* fix(resume): tolerate malformed legacy attachment records
* test(resume): allow resume hook messages in recovery test
* fix(resume): use validated attachment for skill listing
* fix(status): show active provider route instead of legacy bucket
The /status command collapsed many concrete providers (OpenRouter, Groq,
Ollama, Fireworks AI, etc.) into a single "OpenAI-compatible" label, making
multi-provider setups hard to verify and debug.
When apiProvider resolves to the generic "openai" bucket, /status now uses
route metadata to surface the real active route:
Provider route: OpenRouter
Transport: OpenAI-compatible API
OpenAI base URL: https://openrouter.ai/api/v1
Model: anthropic/claude-sonnet-4.5
Credential: OPENROUTER_API_KEY configured
The legacy "OpenAI-compatible" label and fallback are preserved for unknown
custom base URLs. Dedicated provider buckets (nvidia-nim, minimax, codex,
github, xai, gemini, bedrock, vertex, foundry, firstParty, mistral) already
have accurate labels and are left untouched.
Credential display uses env-var names only (never values). Transport kind and
route label come from the existing descriptor-driven route metadata; no new
hardcoded provider maps or network calls are introduced.
* fix(status): include route status defaults
* fix(status): address route status review findings
* fix(status): cover route secret redaction review
* fix(status): avoid duplicate route resolution
* fix(status): redact base URL query credentials
* fix(status): harden status URL secret redaction
* fix(status): redact route secrets in status text
* test(status): cover fallback URL fragment redaction
* test(status): isolate route status provider imports
* fix(status): redact encoded route secrets
* fix(status): redact encoded query secrets safely
* fix(status): redact nested encoded query secrets
* fix(status): redact encoded secret substrings
* fix(status): redact strict encoded secret variants
* security(status): redact proxy and TLS-sensitive values in /status
Make /status safe to share in public issues and screenshots by ensuring
proxy credentials, mTLS private key/cert paths, CA bundle paths, and
token-bearing URLs are never printed verbatim.
- Proxy URL: wrap with redactUrlForStatus (reuses redactUrlForDisplay
for credential + sensitive query-param masking; additionally strips
the URL fragment, which can carry tokens).
- NODE_EXTRA_CA_CERTS / CLAUDE_CODE_CLIENT_CERT: wrap with
redactPathForStatus, which shortens a leading $HOME to ~ so paths
stay useful without leaking usernames or home directory layout.
- CLAUDE_CODE_CLIENT_KEY: show the literal 'configured' rather than
the path or value of a private key.
Adds two small reusable helpers in src/utils/statusRedaction.ts plus
unit tests, and extends status.test.ts with an integration test that
asserts the full buildAPIProviderProperties output is leak-free when
proxy credentials and mTLS env vars are set.
* fix(status): address status redaction review feedback
* fix(status): redact provider base URL secrets
* fix(status): unify URL status redaction
* feat(cli): add local background sessions
Add local detached background sessions backed by an OpenClaude-owned registry under the resolved config directory.
- implement --bg spawning plus ps, logs, logs -f, kill, and an explicit attach limitation
- harden registry metadata validation, atomic writes, ID/name collision handling, and terminal-name reuse
- precreate child log files with precise ownership cleanup and register metadata only after spawn succeeds
- verify live PIDs against the session command before treating registry entries as running
- wait for process-tree termination and escalate to SIGKILL before marking sessions killed
- skip live local background sessions during --continue transcript selection
- preserve Node heap flags for detached children while avoiding stale launcher relaunch state
- handle -- separators so dash-prefixed prompts remain positional
- document storage, safety model, name reuse, and the current attach limitation
Validation:
- bun test
- bun run typecheck
- bun run smoke
- isolated built-CLI --bg/ps/logs/kill smoke
- CodeRabbit review findings addressed
* test(utils): prevent bg registry mock leakage
Restore complete bg registry and UDS module mocks after conversation recovery tests so Bun's process-global mock.module registry cannot leak partial module exports into later CLI tests.
CI exposed this under Bun 1.3.13 when conversationRecovery.test ran before the bgRegistry and bg CLI test files.
* test(utils): exercise bg registry without global mock
Replace the conversation recovery bgRegistry module mock with real registry metadata backed by a short-lived live child process. This keeps UDS as the only mocked boundary and avoids leaking a mocked registry module into later CLI registry tests under Bun 1.3.13.
* test(utils): isolate background registry state
Stop the conversation recovery test from using process-wide bgRegistry mocks or real child processes by injecting the live-session dependencies directly.
Pin and serialize the bg registry test config directory through the shared env mutation lock so path/cache state cannot leak from neighboring tests under Bun CI ordering.
* test(utils): document Bun mock restoration
Explain why conversation recovery tests re-register full module exports after mock.restore(), matching the CodeRabbit-requested Bun 1.3.13 isolation workaround.
* test(cli): isolate background registry root
Avoid relying on process-wide CLAUDE_CONFIG_DIR state in bgRegistry tests. Use a registry-local test root override so CI file ordering and mocked path modules cannot redirect background session metadata into another test's temp directory.
* test(utils): cover live session fallback paths
Add focused coverage for collectLiveBackgroundSessionIds when UDS discovery fails but registry data remains available, and when registry refresh fails but UDS data remains available.
* fix(cli): harden background session management
Validate persisted and newly-created background session PIDs before exposing them to management commands.
Reserve named live sessions with an atomic registry write, release reservations when sessions become terminal, and cover concurrent duplicate-name attempts.
Split local session management dispatch from background spawning so ps/logs/attach/kill avoid provider startup while --bg still inherits profile routing.
* fix(cli): address background session review findings
Preserve positional prompts when --bg is combined with optional-value flags such as --debug.
Recover stale name reservations whose owner metadata is missing or terminal while preserving in-flight reservations from live creators.
Cover both reviewer findings with focused parser and registry regression tests.
* fix(cli): respect delimiter for background flags
Limit background and print-mode flag detection to arguments before the -- delimiter so flag-shaped prompts remain positional.
Keep optional resume/from-pr flags out of the required-value table and add regressions for delimiter and optional-flag prompt handling.
* refactor(cli): share delimiter argument helper
Move args-before-delimiter handling into the existing dependency-free CLI args utility.
Use a dynamic import from the entrypoint so background flag routing shares the helper without adding top-level module load to version and management fast paths.
* test(cli): cover background entrypoint routing
Export the CLI entrypoint for controlled tests and add isolated importer injection so runtime routing tests do not leak global module mocks.
Replace the delimiter source-layout assertion with execution-level coverage for management commands, real background flags, and flag-shaped prompt text after --.
* fix(cli): preserve background resume selectors
Keep space-separated --resume, -r, and --from-pr values attached when building background child args.
Mark live background sessions stale when PID command identity cannot be read, avoiding termination of reused unrelated PIDs.
* fix(cli): track unknown background session identity
Represent unreadable live PID identity as a non-terminal unknown state so active sessions stay excluded from resume selection.
Refuse to terminate unknown live PIDs because the process command cannot be positively matched to the background session.
* fix(cli): honor background resume selectors
Avoid adding a generated --session-id to non-forked background resume launches so the spawned print-mode child satisfies the existing resume/session-id contract.
Pass --from-pr through headless print mode and resolve PR-linked sessions through the shared conversation recovery path.
Add regression coverage for background resume launch args and PR selector matching.
* fix(cli): treat PR resume as headless resume source
Include --from-pr in print-mode resume guards so PR-linked headless resumes can run without a prompt and share resume-only options.
Skip eager startup hooks for headless PR resumes and add explicit --session-id launch coverage.
* fix(cli): keep background PR resumes live
Resolve non-forked --from-pr background launches to the selected transcript id before writing registry metadata.
Preserve PID identity refresh for PR-resume children by matching the stored invocation when argv does not carry the transcript id.
Add regressions for launch registration and registry refresh.
* test(cli): cover PR resume lookup failures
Add regression coverage for non-forked background --from-pr launches when the selector cannot be resolved.
Verify the launch planner returns the same clear error used by handleBgFlag().
* chore(query): add tool-pairing diagnostics
Add a pure validator for tool_use/tool_result pairing issues and feed phase, query source, model, provider, and agent context into the existing pre-API repair log. Keep ensureToolResultPairing behavior intact while making future repair logs identify missing, orphaned, duplicate tool_use, and duplicate tool_result cases.
* fix(query): complete pairing diagnostics coverage
Address CodeRabbit review by detecting server-side tool use blocks without matching in-message results and by making pairing validation lazy so it only runs after the repair path has actually mutated messages.
* fix(tokens): fallback when provider lacks countTokens
* test(tokens): isolate shim fallback coverage
Avoid process-wide api client mocks in token estimation tests by exercising the count-token dispatch helper directly. Add non-empty tool coverage for the rough fallback path so the local overhead remains covered.
* fix(typecheck): expand cachedMicrocompact stub exports
The cachedMicrocompact module is a feature-gated stub that only exported
3 functions, but microCompact.ts expected 10+ exports including types and
state management functions.
Changes:
- Add missing type exports: CachedMCState, CacheEditsBlock, PinnedCacheEdits, CachedMCConfig
- Add missing function stubs: createCachedMCState, markToolsSentToAPI, resetCachedMCState, registerToolResult, registerToolMessage, getToolResultsToDelete, createCacheEditsBlock
- Add null guard in cachedMicrocompactPath for config
- Add comprehensive tests for stub behavior
Resolves 15 typecheck errors in microCompact.ts:
- TS2694: Namespace has no exported member (10 errors)
- TS2339: Property does not exist (5 errors)
- TS18047: possibly null (2 errors)
Testing:
- bun test src/services/compact/cachedMicrocompact.test.ts: 7/7 pass
- bun test src/services/compact/: 61/61 pass
- bun run smoke: pass
- Typecheck errors: 697 → 682 (-15)
* fix(typecheck): address CodeRabbit review feedback
- Add missing fields to CachedMCConfig type: enabled, supportedModels,
systemPromptSuggestSummaries (used by prompts.ts and claude.ts)
- Replace silent fallback with explicit error throw in cachedMicrocompactPath
to enforce the invariant that isCachedMicrocompactEnabled() === true implies
getCachedMCConfig() !== null, preventing potential recursion in future
non-stub implementations
* test: prevent CI state leaks
* fix: resolve 28 typecheck errors in openaiShim.ts
Add null guards for nullable `reader`, `response`, and `responsesResponse`
variables, and use type assertions to bridge Node vs Web ReadableStream
type mismatches in stream processing helpers.
* fix(typecheck): resolve 17 errors in agentSdkTypes.ts
- Add @ts-expect-error for settingsTypes.generated.js (generated at build time)
- Fix type imports: redirect 5 types from ./sdk/runtimeTypes.js to ./sdk/shared.js
- Remove 11 unused type imports that don't exist (AnyZodRawShape, InferShape, etc.)
* fix(typecheck): resolve 26 errors in openaiShim.ts — nullable guards, ReadableStream types
* fix(typecheck): resolve 23 errors in messages.ts + groupToolUses.ts
MessageWithoutProgress resolved to `never` because all message types are
`any` stubs, making `Exclude<any, any>` = `never`. Widen types and use
boolean wrappers to avoid type-predicate narrowing. Add missing return
in getToolUseID switch statement.
* fix(typecheck): resolve 14 errors in toolExecution.ts — fix never[] inference
* fix(typecheck): resolve type errors in claude.ts
- Cast nested block params to BetaContentBlockParam for SDK type union mismatch
- Add missing CACHE_EDITING_BETA_HEADER constant to betas.ts
- Type-assert getCachedMCConfig() return for supportedModels access
- Add missing imports: getContextWindowForModel, COMPACT_MAX_OUTPUT_TOKENS, getSdkBetas
- Fix model variable reference to use options.model in compact context
- Add optional signature property to ConnectorTextBlock type
* ci: re-trigger checks
* fix: address CodeRabbit review feedback
- Throw error instead of silent return when response body is not readable
- Clamp hybrid context budget to non-negative floor (Math.max(0, ...))
- Remove unused isResult wrapper in messages.ts
* chore(tests): fix flaky and environment-dependent unit tests
- Mock fs.existsSync in geminiAuth tests to prevent real ADC reads
- Isolate runtimeMetadata tests from local environment variables
- Add shared mutation lock to sessionStorage tests to prevent env race conditions
* test: address environment cleanup review
* test(autoCompact): guard temp-dir cleanup against setup-time failures
If beforeEach throws before tempDir is assigned (e.g. lock acquisition or
mkdtempSync fails), afterEach's unconditional rmSync(tempDir) threw a
TypeError and masked the original failure. Type tempDir as string | undefined
and skip removal when unset, mirroring the savedAutoCompactEnabled reset.
Addresses CodeRabbit review on PR #1582.
Co-Authored-By: OpenClaude <openclaude@gitlawb.com>
---------
Co-authored-by: Kevin Codex <kevin@gitlawb.com>
Co-authored-by: OpenClaude <openclaude@gitlawb.com>