Skip to content

fix: type safety, defensive defaults, and unbounded retry prevention#1553

Open
skyhighbg22-jpg wants to merge 25 commits into
Gitlawb:mainfrom
skyhighbg22-jpg:fix/code-quality-and-defensive-defaults
Open

fix: type safety, defensive defaults, and unbounded retry prevention#1553
skyhighbg22-jpg wants to merge 25 commits into
Gitlawb:mainfrom
skyhighbg22-jpg:fix/code-quality-and-defensive-defaults

Conversation

@skyhighbg22-jpg

@skyhighbg22-jpg skyhighbg22-jpg commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Type safety, defensive defaults, and unbounded retry prevention, plus test-isolation follow-ups. Each commit is a single behavioral change.

Changes

src/QueryEngine.ts

Line Fix
17 Import EXTERNAL_PERMISSION_MODES runtime constant from src/types/permissions.js for the SDK init validation guard
552-561 Validate permissionMode against EXTERNAL_PERMISSION_MODES (not the internal PERMISSION_MODES set, which can include the classifier-only 'auto' mode that is not a valid SDK wire value) — invalid mode strings fall back to 'default' instead of being passed through silently. Fixes the original PR's runtime ReferenceError
942-946 Use splice(0, length, ...messages) instead of length = 0 + push() — atomic array replacement prevents concurrent readers from seeing empty state during snip replay

src/services/api/withRetry.ts

Line Fix
103 New PERSISTENT_MAX_ATTEMPTS = 100 constant for the persistent-retry cap (renamed from the original PR's PERSISTENT_RETRY_MAX_ATTEMPTS to match the PERSISTENT_* convention)
104-108 Re-export as _PERSISTENT_MAX_ATTEMPTS_FOR_TEST for unit-test assertion only — there is no runtime override seam; the cap is driven by the real isPersistentRetryEnabled() gate
200 Hoist isPersistentRetryEnabled() into a local persistentRetryEnabled const at the top of withRetry() so all call sites see a consistent snapshot within a single retry chain
299, 386, 399, 414 Thread persistentRetryEnabled through shouldRetry() and all retry branches
408-410 Cap persistent retry loop at 100 attempts — prevents unbounded retry (≈8 hours max with exponential backoff and 6-hour reset cap) when the unattended retry path is enabled

src/services/compact/autoCompact.ts

Line Fix
80-83 New MIN_AUTOCOMPACT_FAILURE_COOLDOWN_MS = 10_000 constant — documents the floor and makes it testable
95-99 Add 10_000ms minimum floor for OPENCLAUDE_AUTOCOMPACT_FAILURE_COOLDOWN_MS — prevents misconfiguration from effectively disabling the circuit breaker

src/services/compact/autoCompact.test.ts

Line Fix
250-256 Update 'uses valid positive integer override' test to use 15000 (above floor) and rename to 'uses valid positive integer override above the floor'
258-282 New 'rejects overrides below the minimum cooldown floor' test: verifies 5000 and 9999 are rejected, the floor constant equals 10_000, and the exact floor value 10000 is accepted
482 Update circuit breaker beforeEach override from 5000 to 15000 to respect the new floor
677 Update circuit breaker retry-time expectation from 111_000 to 121_000 (failure at 106_000 + 15_000 cooldown)

src/services/api/withRetry.test.ts

Line Fix
9-15 Switch makeError to the new APIError() constructor so the test errors match the real wire shape and exercise the production canRetry/shouldRetry branches
28 Add CLAUDE_CODE_UNATTENDED_RETRY to the envKeys clear list so the gate isn't poisoned by leaked state from a prior test
78-80 Mock src/utils/sleep.js in importFreshWithRetryModule so the exponential-backoff delays don't slow the suite down
368-403 New 'persistent retry cap' describe block that drives the real persistent retry gate — no runtime override — and proves the loop stops after exactly 101 calls (100 retries) by raising CannotRetryError

package.json

Line Fix
53-56 Enable --feature=UNATTENDED_RETRY on the test, test:full, test:coverage, and test:provider bun test scripts so the persistent retry cap test sees the production gate behavior

src/services/api/client.test.ts

Line Fix
17-50 Extend originalEnv snapshot to include OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, OPENAI_AUTH_HEADER_VALUE, MIMO_API_KEY, VENICE_API_KEY, NVIDIA_API_KEY
80-99 Extend clearEnvForMiniMaxOnlyTest() to clear OPENAI_API_FORMAT, OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, OPENAI_AUTH_HEADER_VALUE, MIMO_API_KEY, VENICE_API_KEY, NVIDIA_API_KEY
116-138 Extend beforeEach to clear MIMO_API_KEY, VENICE_API_KEY, NVIDIA_API_KEY
159-186 Extend afterEach to restoreEnv all the new env vars
203-225 Extend the first test's inline cleanup to clear NVIDIA_API_KEY, XAI_API_KEY, MIMO_API_KEY, VENICE_API_KEY, ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_MODEL so it does not rely solely on the global beforeEach when run in isolation

src/utils/analyzeContext.mcp.test.ts

Line Fix
1 Add afterEach, beforeEach to bun:test imports
8-27 New originalEnv snapshot + beforeEach/afterEach to clear CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS and ENABLE_TOOL_SEARCH so the test observes the production default of tool search enabled regardless of test ordering (mcp.ts leaks the kill switch as a top-level import side effect)

Testing

  • All autoCompact.test.ts cases pass: 23/23 ✓
  • All withRetry.test.ts cases pass: 33/33 ✓
  • All client.test.ts cases pass: 19/19 ✓
  • All analyzeContext.mcp.test.ts cases pass: 2/2 ✓
  • Combined run of all 4 files: 78/78 ✓
  • Broader run of src/services/api/ + src/services/compact/: 634/634 ✓
  • Build passes: bun run build
  • No new typecheck errors introduced (pre-existing errors in unrelated files unchanged)

Notes

  • The persistent retry cap is enforced at the top of the loop after persistentAttempt is incremented on the previous iteration, so the loop runs for exactly 100 retry attempts (giving operation a total of 101 calls — the initial attempt plus 100 retries).
  • The PERSISTENT_MAX_ATTEMPTS constant sits next to the existing PERSISTENT_MAX_BACKOFF_MS / PERSISTENT_RESET_CAP_MS constants and follows the same naming convention.
  • The 10_000ms cooldown floor matches the 5-min test override value used by the autoCompactIfNeeded circuit breaker tests in this file (now 15_000ms = 15s).
  • _PERSISTENT_MAX_ATTEMPTS_FOR_TEST exists solely so unit tests can assert the cap value; the cap itself is driven by isPersistentRetryEnabled() and there is no override seam (tests must enable UNATTENDED_RETRY via bun test --feature=UNATTENDED_RETRY and set CLAUDE_CODE_UNATTENDED_RETRY=1 to exercise the path).

Summary by CodeRabbit

  • New Features
    • Added feature-flagged persistent retry for transient capacity errors, capped at 100 attempts.
  • Bug Fixes
    • Validate external tool permission mode with a safe fallback when misconfigured.
    • Improved snip message replay consistency.
    • Stricter auto-compaction cooldown override validation (format checks + minimum floor).
    • Hardened changelog migration write behavior to tolerate existing cache files and improved retry error reporting.
  • Tests
    • Expanded coverage for persistent retry cap and cooldown boundaries; improved environment isolation in API/MCP-related tests.
  • Chores
    • Enabled the unattended-retry feature flag in Bun test scripts and the release workflow (with concurrency limits).

@skyhighbg22-jpg skyhighbg22-jpg force-pushed the fix/code-quality-and-defensive-defaults branch from 21c2a3c to 4f9da78 Compare June 5, 2026 17:37
QueryEngine.ts:
- Import PERMISSION_MODES runtime constant and validate permissionMode
  before casting in submitMessage — invalid mode strings fall back to
  'default' instead of crashing with ReferenceError: PERMISSION_MODES is
  not defined (fixes the runtime gap from the original PR)
- Use splice(0, length, ...messages) instead of length=0 + push() for
  atomic array replacement in snip replay, so concurrent readers of
  getMessages() never observe an empty state

withRetry.ts:
- Cap persistent retry loop at 100 attempts via PERSISTENT_RETRY_MAX_ATTEMPTS
  constant — prevents unbounded retry (~8 hours max with exponential backoff
  and 6-hour reset cap) when the unattended retry path is enabled

autoCompact.ts:
- Add MIN_AUTOCOMPACT_FAILURE_COOLDOWN_MS = 10_000 floor for
  OPENCLAUDE_AUTOCOMPACT_FAILURE_COOLDOWN_MS override — prevents
  misconfiguration from effectively disabling the circuit breaker

autoCompact.test.ts:
- Update test override from 5000 to 15000 to respect the new 10s minimum floor
- Add test case verifying values below the floor (5000, 9999) are rejected
  and that the floor value (10000) is accepted
- Update circuit breaker retry-time expectation from 111_000 to 121_000
  to account for the new 15s cooldown override
@skyhighbg22-jpg skyhighbg22-jpg force-pushed the fix/code-quality-and-defensive-defaults branch from 4f9da78 to 4d54d5d Compare June 5, 2026 17:38
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c888ba02-e788-4bb7-b385-d3ef06955a9d

📥 Commits

Reviewing files that changed from the base of the PR and between c034103 and d287c2f.

📒 Files selected for processing (2)
  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (13)
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with strict mode and ESM imports

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
{src/commands/**/*.ts,src/services/**/*.ts,src/entrypoints/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use chalk for terminal color in CLI code

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
{src/services/**/*.ts,src/utils/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use execa for child processes

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
{src/integrations/**/*.ts,src/services/**/*.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Test the exact provider/model path you changed when possible for provider modifications

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
**/*.{ts,tsx,js,jsx,py,json,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow the existing code style in the touched files

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/services/api/withRetry.test.ts
**/*.test.{ts,tsx,js}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Test the exact provider/model path you changed when possible

Files:

  • src/services/api/withRetry.test.ts
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Follow TypeScript strict mode and type safety practices by running typecheck before submitting

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/api/withRetry.test.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes fix: skip assertMinVersion for third-party providers #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/api/withRetry.test.ts
  • src/services/api/withRetry.ts
🔇 Additional comments (2)
src/services/api/withRetry.ts (1)

112-112: LGTM!

src/services/api/withRetry.test.ts (1)

541-541: LGTM!

Also applies to: 545-545, 549-549, 564-568


📝 Walkthrough

Walkthrough

This PR tightens validation and bounds (permission mode, autocompact cooldown), adds a capped persistent-retry mode to withRetry (plus tests), expands test environment isolation to prevent credential leakage, enables an unattended-retry test feature flag, and makes migration write errors errno-aware while including error messages in logs.

Changes

Robustness, Error Handling, and Bounds Improvements

Layer / File(s) Summary
Permission mode validation: QueryEngine and useReplBridge
src/QueryEngine.ts, src/hooks/useReplBridge.tsx
Permission mode is validated against EXTERNAL_PERMISSION_MODES before passing to system initialization and bridge payloads; unrecognized modes fall back to 'default'.
QueryEngine: messages snapshot optimization
src/QueryEngine.ts
Snip-boundary message replacement uses a single splice operation instead of clear + push.
withRetry: persistent retry mode and caps
src/services/api/withRetry.ts
Persistent retry mode (computed once per invocation) gates fast-mode and repeated-529 handling, enforces a 100-attempt persistent cap (throws CannotRetryError), and threads the flag into shouldRetry to bypass header/subscriber gating for transient capacity errors.
withRetry: tests and test infrastructure
src/services/api/withRetry.test.ts
APIError construction uses SDK constructor; tests save/restore CLAUDE_CODE_UNATTENDED_RETRY; sleep is mocked for instant retries; new test verifies CannotRetryError after 101 operation calls.
Autocompact: cooldown floor constraint and tests
src/services/compact/autoCompact.ts, src/services/compact/autoCompact.test.ts
Exports MIN_AUTOCOMPACT_FAILURE_COOLDOWN_MS and rejects too-small env overrides; tests cover whitespace-padded overrides, floor boundary behavior, rejection below floor, and updated circuit-breaker timing.
API client tests: environment isolation
src/services/api/client.test.ts
Expanded snapshot/restore and per-test cleanup to include provider/shim credentials (MIMO_API_KEY, VENICE_API_KEY, NVIDIA_API_KEY, XAI_API_KEY, and OPENAI_AUTH_* keys); pre-test cleanup updated for Anthropic test.
MCP tests: environment isolation hooks
src/utils/analyzeContext.mcp.test.ts
Top-level hooks snapshot and restore CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS and ENABLE_TOOL_SEARCH around each test; shared mutation lock management moved to module scope.
Package.json and CI: test feature flags
package.json, .github/workflows/release.yml
--feature=UNATTENDED_RETRY added to Bun test scripts while preserving existing concurrency and coverage settings.
Startup migrations and release notes error handling
src/main.tsx, src/utils/releaseNotes.ts
Migration failure logging now includes the underlying error message; changelog migration tolerates EEXIST for mkdir/writeFile cases and rethrows other errors using errno-aware checks.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested Reviewers

  • jatmn
  • kevincodex1
🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Risk Surface Disclosed ⚠️ Warning PR touches sensitive areas (permissions, provider routing, background execution, release scripts, CI behavior) but the description does not explicitly call out the risk surface or identify any bloc... Add explicit risk surface review to PR description: discuss implications of UNATTENDED_RETRY feature enablement in release tests, permission validation changes, persistent retry cap safety, and provider credential handling.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title precisely reflects the three main objectives: type safety (QueryEngine and withRetry validation), defensive defaults (fallbacks to 'default' mode and minimum cooldown floors), and unbounded retry prevention (persistent retry cap at 100 attempts).
Description check ✅ Passed The description follows the template structure with Summary, Changes (detailed per-file breakdown), Testing (comprehensive pass rates), and Notes (clarifications on design decisions). All required sections are present and substantially completed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hidden Policy Change ✅ Passed All behavioral changes are defensive (type validation, misconfiguration prevention) or properly opt-in/gated. Permission modes unchanged; persistent retry requires dual gates (feature flag + env va...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/api/withRetry.ts`:
- Around line 398-405: Add telemetry when the persistent retry cap is hit: in
the branch that currently throws CannotRetryError when persistent &&
persistentAttempt >= PERSISTENT_RETRY_MAX_ATTEMPTS, emit a telemetry event
(e.g., follow the existing naming pattern like
tengu_api_persistent_retry_cap_reached) including relevant context (error,
retryContext, persistentAttempt, PERSISTENT_RETRY_MAX_BACKOFF_MS,
PERSISTENT_RETRY_MAX_ATTEMPTS) before throwing the CannotRetryError so the team
can monitor how often sessions exhaust the 100-attempt cap and include a comment
clarifying that the "~8 hours" estimate refers only to the exponential backoff
path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 231e17c0-f96f-4154-b394-26fac413f618

📥 Commits

Reviewing files that changed from the base of the PR and between 1204fe2 and 4d54d5d.

📒 Files selected for processing (4)
  • src/QueryEngine.ts
  • src/services/api/withRetry.ts
  • src/services/compact/autoCompact.test.ts
  • src/services/compact/autoCompact.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/api/withRetry.ts
  • src/services/compact/autoCompact.ts
  • src/services/compact/autoCompact.test.ts
  • src/QueryEngine.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/withRetry.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/api/withRetry.ts
  • src/services/compact/autoCompact.ts
  • src/services/compact/autoCompact.test.ts
  • src/QueryEngine.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/compact/autoCompact.test.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-04T22:10:40.834Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
🔇 Additional comments (9)
src/QueryEngine.ts (2)

17-17: LGTM!

Also applies to: 552-557, 563-563


946-950: LGTM!

src/services/api/withRetry.ts (1)

102-102: LGTM!

src/services/compact/autoCompact.ts (2)

84-87: LGTM!


99-103: LGTM!

src/services/compact/autoCompact.test.ts (4)

250-255: LGTM!


257-281: LGTM!


482-482: LGTM!


677-677: LGTM!

Comment thread src/services/api/withRetry.ts Outdated
The new persistent retry cap test in withRetry.test.ts needs the real
UNATTENDED_RETRY feature gate to fire, which requires passing
--feature=UNATTENDED_RETRY on the bun test command line. Enable it
in the standard test, test:full, test:coverage, and test:provider
scripts so the test sees the production gate behavior.
Add a regression test that proves the persistent retry path stops
after PERSISTENT_MAX_ATTEMPTS=100 retryable 429s by driving the real
isPersistentRetryEnabled() gate (no test override seam). Also:

- Switch makeError to the new APIError() constructor so the test
  errors match the real wire shape and exercise the production
  canRetry/shouldRetry branches
- Add CLAUDE_CODE_UNATTENDED_RETRY to the envKeys clear list so the
  gate isn't poisoned by leaked state from a prior test
- Mock src/utils/sleep.js in importFreshWithRetryModule so the
  exponential-backoff delays don't slow the suite down
The 4 failing tests in CI (first-party Anthropic fetch wrapper, env-only
MiniMax routing, OPENAI_MODEL preservation, OpenAI shim options) all sit
at the top of the file and are sensitive to leaked env vars from prior
test files in the same process. Extend the beforeEach, afterEach, and
inline cleanup to clear OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME,
OPENAI_AUTH_HEADER_VALUE, MIMO_API_KEY, VENICE_API_KEY, and
NVIDIA_API_KEY alongside the existing vars, and add ANTHROPIC_API_KEY /
ANTHROPIC_AUTH_TOKEN / ANTHROPIC_MODEL to the first test's inline
cleanup so it does not rely solely on the global beforeEach when run
in isolation.
src/entrypoints/mcp.ts sets CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=true as
a top-level side effect on import. mcp.test.ts imports that file, so the
env var is leaked into the rest of the test process. In
analyzeContext.mcp.test.ts the kill switch forces getToolSearchMode() to
'standard', which makes isToolSearchEnabled() return false, so the
'keeps deferred MCP schemas excluded' test sees isDeferred=false and
returns mcpToolTokens=1000 instead of 0.

Clear the kill switch and ENABLE_TOOL_SEARCH in beforeEach (restoring
the original values in afterEach) so the test observes the production
default of tool search enabled regardless of test ordering.
…etry override to test-only module var

QueryEngine.ts:
- Switch SDK init permissionMode validation from the internal
  PERMISSION_MODES set to EXTERNAL_PERMISSION_MODES. The internal
  set can include the classifier-only 'auto' mode that is not a
  valid wire value for the SDK system/init payload, so emitting
  it would produce an unsupported configuration.

withRetry.ts:
- Rename PERSISTENT_RETRY_MAX_ATTEMPTS to PERSISTENT_MAX_ATTEMPTS
  to match the convention of the other PERSISTENT_* constants and
  re-export it as _PERSISTENT_MAX_ATTEMPTS_FOR_TEST for unit-test
  assertion of the cap value (no runtime override seam).
- Hoist isPersistentRetryEnabled() into a local
  persistentRetryEnabled const at the top of withRetry() so all
  call sites see a consistent snapshot within a single retry
  chain.
- Thread persistentRetryEnabled through shouldRetry() so its
  branch is decided once per chain rather than re-reading the
  feature flag and env var on every attempt.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Restore full-suite client-test isolation
    src/services/api/client.test.ts:117
    The shared setup now clears OPENAI_API_FORMAT, but it still leaves OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, and OPENAI_AUTH_HEADER_VALUE behind unless a test happens to call the MiniMax-only cleanup helper. In the current GitHub smoke-and-tests run, those stale auth overrides bleed into the full suite and make four client.test.ts cases fail with "Could not resolve authentication method" when getAnthropicClient() reaches the Anthropic SDK. Please clear those auth override env vars in the shared setup/affected inline cleanup so the focused file and the full suite run with the same provider state.

  • [P3] Complete CodeRabbit's persistent-retry cap request
    src/services/api/withRetry.ts:403
    CodeRabbit's unresolved thread is still valid here: the new persistent retry cap throws CannotRetryError without emitting a telemetry event, and the adjacent comment still describes 100 attempts as about eight hours even though the reset-delay path can wait up to six hours per retry. Please complete that request by logging a cap-reached event before throwing and clarifying that the eight-hour estimate only applies to the exponential-backoff path.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 6, 2026
@skyhighbg22-jpg skyhighbg22-jpg marked this pull request as draft June 6, 2026 13:22
- Only swallow EEXIST (file already exists) errors in migrateChangelogFromConfig
- Rethrow all other write failures (permissions, disk full, etc.)
- Log migration errors instead of silently ignoring them
- This ensures migration failures are surfaced and will retry on next startup
@skyhighbg22-jpg skyhighbg22-jpg marked this pull request as ready for review June 6, 2026 13:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/releaseNotes.ts (1)

227-242: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Narrow EEXIST suppression to writeFile only

Line 228 (mkdir) can also throw EEXIST for path-collision states. With the current shared catch, that gets treated as success and Line 242 removes cachedChangelog even though migration may not have written the file.

Suggested fix
-  try {
-    await mkdir(dirname(cachePath), { recursive: true })
-    await writeFile(cachePath, config.cachedChangelog, {
-      encoding: 'utf-8',
-      flag: 'wx', // Write only if file doesn't exist
-    })
-  } catch (error) {
-    // File already exists (EEXIST) is fine - skip silently
-    if (getErrnoCode(error) !== 'EEXIST') {
-      throw error
-    }
-  }
+  await mkdir(dirname(cachePath), { recursive: true })
+  try {
+    await writeFile(cachePath, config.cachedChangelog, {
+      encoding: 'utf-8',
+      flag: 'wx', // Write only if file doesn't exist
+    })
+  } catch (error) {
+    // File already exists (EEXIST) is fine - skip silently
+    if (getErrnoCode(error) !== 'EEXIST') {
+      throw error
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/releaseNotes.ts` around lines 227 - 242, The current try/catch
wraps both mkdir and writeFile so an EEXIST from mkdir incorrectly counts as a
successful write; split the operations so mkdir(dirname(cachePath), { recursive:
true }) is awaited outside the writeFile try/catch, then wrap only
writeFile(cachePath, config.cachedChangelog, { encoding: 'utf-8', flag: 'wx' })
in a catch that suppresses only EEXIST (via getErrnoCode(error) === 'EEXIST')
and rethrows otherwise; call saveGlobalConfig(({ cachedChangelog: _, ...rest })
=> rest) only after the writeFile either succeeded or threw EEXIST.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/utils/releaseNotes.ts`:
- Around line 227-242: The current try/catch wraps both mkdir and writeFile so
an EEXIST from mkdir incorrectly counts as a successful write; split the
operations so mkdir(dirname(cachePath), { recursive: true }) is awaited outside
the writeFile try/catch, then wrap only writeFile(cachePath,
config.cachedChangelog, { encoding: 'utf-8', flag: 'wx' }) in a catch that
suppresses only EEXIST (via getErrnoCode(error) === 'EEXIST') and rethrows
otherwise; call saveGlobalConfig(({ cachedChangelog: _, ...rest }) => rest) only
after the writeFile either succeeded or threw EEXIST.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5060761e-d180-4db0-9dd6-f17db2162dc2

📥 Commits

Reviewing files that changed from the base of the PR and between d61b253 and ff28014.

📒 Files selected for processing (2)
  • src/main.tsx
  • src/utils/releaseNotes.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: smoke-and-tests
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/main.tsx
  • src/utils/releaseNotes.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Typecheck TypeScript code before submitting

Files:

  • src/main.tsx
  • src/utils/releaseNotes.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/main.tsx
  • src/utils/releaseNotes.ts
{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}

⚙️ CodeRabbit configuration file

{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}: Review install, launcher, build, packaging, startup, and entrypoint changes for cross-platform compatibility, tracked-source rewrites, env/config precedence, and release safety. Block on changes that can break Windows/macOS/Linux startup or publish unexpected artifacts.

Files:

  • src/main.tsx
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/main.tsx
  • src/utils/releaseNotes.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-04T22:10:40.834Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-06T00:19:44.234Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-06-06T00:19:34.989Z
Learning: PR description must include: what changed and why, user or developer impact, exact checks you ran, linked issue, screenshots for UI/terminal changes, and which provider path was tested
🔇 Additional comments (1)
src/main.tsx (1)

349-355: LGTM!

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 6, 2026
- Ensure mkdir runs before writeFile try/catch
- Only suppress EEXIST from writeFile, not mkdir
- Prevents EEXIST from mkdir incorrectly counting as successful write

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/releaseNotes.ts`:
- Around line 226-228: The mkdir call that ensures the cache directory exists
should suppress EEXIST like the pattern in fsOperations.ts to handle the
Bun/Windows readonly-folder edge case; update the await
mkdir(dirname(cachePath), { recursive: true }) in releaseNotes.ts to catch
errors and ignore only errors with code 'EEXIST' (rethrow other errors) so the
existing-directory case does not trigger the "Changelog migration failed" retry
loop.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0e34a3ec-6c02-4c06-bc41-fe8b3e640dd7

📥 Commits

Reviewing files that changed from the base of the PR and between ff28014 and 2d44e7c.

📒 Files selected for processing (1)
  • src/utils/releaseNotes.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: smoke-and-tests
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/utils/releaseNotes.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Typecheck TypeScript code before submitting

Files:

  • src/utils/releaseNotes.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/releaseNotes.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/utils/releaseNotes.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-04T22:10:40.834Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-06-06T00:19:44.234Z
Learning: Verify that product, trust-model, routing-default, telemetry/network, and permission-policy changes are not hidden inside unrelated cleanup. Flag the PR if the policy decision needs explicit maintainer alignment.
Learnt from: CR
Repo: Gitlawb/openclaude PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2026-06-06T00:19:34.989Z
Learning: PR description must include: what changed and why, user or developer impact, exact checks you ran, linked issue, screenshots for UI/terminal changes, and which provider path was tested
🔇 Additional comments (1)
src/utils/releaseNotes.ts (1)

230-244: LGTM!

Comment thread src/utils/releaseNotes.ts

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary: thanks for the quick follow-ups here. There are still a couple of items to wrap up before this can be considered merge-ready: please address the active CodeRabbit finding and get the failing test path green. Since OpenClaude is moving quickly, it is also possible that rebasing on the latest main will clear some or all of the test failures if they are coming from recent upstream test-order or fixture changes.

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Restore a green full test path before changing the suite flags
    package.json:53
    This PR changes the top-level test, test:full, test:coverage, and test:provider scripts to run the entire suite with --feature=UNATTENDED_RETRY, but the live smoke-and-tests check is now failing in bun run check during bun run test:full. The failed Linux job gets through build and focused type tests, then reports four src/services/api/client.test.ts failures where the Anthropic SDK throws Could not resolve authentication method in the first-party and MiniMax env-only cases. The focused changed tests pass, so the new full-suite execution path is exposing order/feature-flag isolation failures that still need to be cleared. Given how rapidly main is changing, a rebase may be enough if this is already fixed upstream; otherwise, please make the full CI script pass or scope the feature flag so only the persistent-retry test runs under UNATTENDED_RETRY.

  • [P2] Complete CodeRabbit's mkdir EEXIST request
    src/utils/releaseNotes.ts:227
    CodeRabbit's latest changes-requested item is still valid here: mkdir(dirname(cachePath), { recursive: true }) now runs outside the write-file try/catch, so an EEXIST from the directory creation step still escapes as a migration failure even though the requested fix was to suppress only that benign mkdir case and rethrow other errors. Please complete CodeRabbit's request by handling EEXIST around the mkdir call as well, then keep the saveGlobalConfig call gated on successful migration or an already-existing target.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main.tsx (1)

345-350: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Preserve original migration error as cause when wrapping.

You improved message clarity, but wrapping without cause drops causal linkage for diagnostics in some sinks. Keep both message context and cause chain.

Suggested patch
   migrateChangelogFromConfig().catch(error => {
     logError(
       new Error(
         `Changelog migration failed; will retry on next startup: ${errorMessage(error)}`,
+        { cause: error instanceof Error ? error : undefined },
       ),
     )
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main.tsx` around lines 345 - 350, Wrap the original migration error as
the cause when creating the new Error in the migrateChangelogFromConfig().catch
handler so the causal chain is preserved; update the Error construction in the
catch block used with logError to use the Error constructor with an options
object (e.g., new Error(`Changelog migration failed; will retry on next startup:
${errorMessage(error)}`, { cause: error })) so migrateChangelogFromConfig's
original error is available as error.cause while keeping the improved message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/QueryEngine.ts`:
- Around line 949-950: The current replacement uses two operations
(this.mutableMessages.length = 0 followed by
this.mutableMessages.push(...snipResult.messages)) which creates a transient
empty state; change it to a single in-place splice to atomically replace the
contents (e.g., this.mutableMessages.splice(0, this.mutableMessages.length,
...snipResult.messages)) so the array is swapped without ever being empty —
update the code in the QueryEngine method where mutableMessages is being updated
and use splice with snipResult.messages to perform the swap.
- Around line 1469-1472: The length-based computation for executed can drop a
boundary marker when no UUIDs were removed; update the logic in QueryEngine.ts
(the place that builds the returned object with messages: projected and
executed) so that executed is true not only when projected.length !==
store.length + 1 but also when the projected messages include a boundary marker
(e.g., check the boundary flag/type on the relevant message), ensuring
submitMessage() will persist boundary messages even if no removals occurred;
reference the projected array, the store length check, and submitMessage()
behavior when adjusting the executed determination.

---

Outside diff comments:
In `@src/main.tsx`:
- Around line 345-350: Wrap the original migration error as the cause when
creating the new Error in the migrateChangelogFromConfig().catch handler so the
causal chain is preserved; update the Error construction in the catch block used
with logError to use the Error constructor with an options object (e.g., new
Error(`Changelog migration failed; will retry on next startup:
${errorMessage(error)}`, { cause: error })) so migrateChangelogFromConfig's
original error is available as error.cause while keeping the improved message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a8962d5e-baa5-44fc-9ccb-abe65aa5ee18

📥 Commits

Reviewing files that changed from the base of the PR and between 33f9ed9 and aa9f9fd.

📒 Files selected for processing (3)
  • package.json
  • src/QueryEngine.ts
  • src/main.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: smoke-and-tests
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/QueryEngine.ts
  • src/main.tsx
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/QueryEngine.ts
  • src/main.tsx
  • package.json
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/QueryEngine.ts
  • src/main.tsx
  • package.json
{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}

⚙️ CodeRabbit configuration file

{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}: Review install, launcher, build, packaging, startup, and entrypoint changes for cross-platform compatibility, tracked-source rewrites, env/config precedence, and release safety. Block on changes that can break Windows/macOS/Linux startup or publish unexpected artifacts.

Files:

  • src/main.tsx
  • package.json
🔇 Additional comments (3)
package.json (1)

3-3: LGTM!

Also applies to: 23-24, 55-57, 67-67, 80-80, 91-91, 171-171

src/main.tsx (2)

36-37: LGTM!

Also applies to: 106-107, 123-124, 223-226, 264-269, 725-727, 1468-1517, 2730-2731, 2844-2847, 2987-2994, 3175-3175, 4293-4293


944-951: Check --effort xhigh handling end-to-end (and preserve migration error cause)

  • src/main.tsx now accepts --effort xhigh; confirm the full effort pipeline (parsing → persistence → API payload shaping) preserves xhigh when supported and doesn’t silently fall back later. The current search output only shows EffortValue being threaded into handlePromptSubmit, not the xhigh mapping logic itself.
  • When wrapping migration errors in src/main.tsx, preserve the original error as cause to keep stack/cause chains intact for logs.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main.tsx (1)

345-350: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Preserve original migration error as cause when wrapping.

You improved message clarity, but wrapping without cause drops causal linkage for diagnostics in some sinks. Keep both message context and cause chain.

Suggested patch
   migrateChangelogFromConfig().catch(error => {
     logError(
       new Error(
         `Changelog migration failed; will retry on next startup: ${errorMessage(error)}`,
+        { cause: error instanceof Error ? error : undefined },
       ),
     )
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main.tsx` around lines 345 - 350, Wrap the original migration error as
the cause when creating the new Error in the migrateChangelogFromConfig().catch
handler so the causal chain is preserved; update the Error construction in the
catch block used with logError to use the Error constructor with an options
object (e.g., new Error(`Changelog migration failed; will retry on next startup:
${errorMessage(error)}`, { cause: error })) so migrateChangelogFromConfig's
original error is available as error.cause while keeping the improved message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/QueryEngine.ts`:
- Around line 949-950: The current replacement uses two operations
(this.mutableMessages.length = 0 followed by
this.mutableMessages.push(...snipResult.messages)) which creates a transient
empty state; change it to a single in-place splice to atomically replace the
contents (e.g., this.mutableMessages.splice(0, this.mutableMessages.length,
...snipResult.messages)) so the array is swapped without ever being empty —
update the code in the QueryEngine method where mutableMessages is being updated
and use splice with snipResult.messages to perform the swap.
- Around line 1469-1472: The length-based computation for executed can drop a
boundary marker when no UUIDs were removed; update the logic in QueryEngine.ts
(the place that builds the returned object with messages: projected and
executed) so that executed is true not only when projected.length !==
store.length + 1 but also when the projected messages include a boundary marker
(e.g., check the boundary flag/type on the relevant message), ensuring
submitMessage() will persist boundary messages even if no removals occurred;
reference the projected array, the store length check, and submitMessage()
behavior when adjusting the executed determination.

---

Outside diff comments:
In `@src/main.tsx`:
- Around line 345-350: Wrap the original migration error as the cause when
creating the new Error in the migrateChangelogFromConfig().catch handler so the
causal chain is preserved; update the Error construction in the catch block used
with logError to use the Error constructor with an options object (e.g., new
Error(`Changelog migration failed; will retry on next startup:
${errorMessage(error)}`, { cause: error })) so migrateChangelogFromConfig's
original error is available as error.cause while keeping the improved message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a8962d5e-baa5-44fc-9ccb-abe65aa5ee18

📥 Commits

Reviewing files that changed from the base of the PR and between 33f9ed9 and aa9f9fd.

📒 Files selected for processing (3)
  • package.json
  • src/QueryEngine.ts
  • src/main.tsx
📜 Review details
🔇 Additional comments (3)
package.json (1)

3-3: LGTM!

Also applies to: 23-24, 55-57, 67-67, 80-80, 91-91, 171-171

src/main.tsx (2)

36-37: LGTM!

Also applies to: 106-107, 123-124, 223-226, 264-269, 725-727, 1468-1517, 2730-2731, 2844-2847, 2987-2994, 3175-3175, 4293-4293


944-951: Check --effort xhigh handling end-to-end (and preserve migration error cause)

  • src/main.tsx now accepts --effort xhigh; confirm the full effort pipeline (parsing → persistence → API payload shaping) preserves xhigh when supported and doesn’t silently fall back later. The current search output only shows EffortValue being threaded into handlePromptSubmit, not the xhigh mapping logic itself.
  • When wrapping migration errors in src/main.tsx, preserve the original error as cause to keep stack/cause chains intact for logs.
🛑 Comments failed to post (2)
src/QueryEngine.ts (2)

949-950: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace clear+push with atomic splice for snip replay replacement.

This still introduces a transient empty mutableMessages state during replacement. Use one splice to swap contents in-place.

Suggested fix
-              this.mutableMessages.length = 0
-              this.mutableMessages.push(...snipResult.messages)
+              this.mutableMessages.splice(
+                0,
+                this.mutableMessages.length,
+                ...snipResult.messages,
+              )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

              this.mutableMessages.splice(
                0,
                this.mutableMessages.length,
                ...snipResult.messages,
              )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/QueryEngine.ts` around lines 949 - 950, The current replacement uses two
operations (this.mutableMessages.length = 0 followed by
this.mutableMessages.push(...snipResult.messages)) which creates a transient
empty state; change it to a single in-place splice to atomically replace the
contents (e.g., this.mutableMessages.splice(0, this.mutableMessages.length,
...snipResult.messages)) so the array is swapped without ever being empty —
update the code in the QueryEngine method where mutableMessages is being updated
and use splice with snipResult.messages to perform the swap.

1469-1472: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Snip boundary can be dropped when no UUIDs are removed.

executed is derived from length delta, but submitMessage() treats executed === false as “don’t persist boundary” and still breaks. For boundary messages with no removals, the marker is lost, which can break replay/resume consistency.

Suggested fix
             return {
               messages: projected,
-              executed: projected.length !== store.length + 1,
+              // Callback ran for a confirmed snip boundary; always apply result.
+              executed: true,
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

            return {
              messages: projected,
              // Callback ran for a confirmed snip boundary; always apply result.
              executed: true,
            }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/QueryEngine.ts` around lines 1469 - 1472, The length-based computation
for executed can drop a boundary marker when no UUIDs were removed; update the
logic in QueryEngine.ts (the place that builds the returned object with
messages: projected and executed) so that executed is true not only when
projected.length !== store.length + 1 but also when the projected messages
include a boundary marker (e.g., check the boundary flag/type on the relevant
message), ensuring submitMessage() will persist boundary messages even if no
removals occurred; reference the projected array, the store length check, and
submitMessage() behavior when adjusting the executed determination.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Remove the stale retry guard that still calls shouldRetry without the persistent flag
    src/services/api/withRetry.ts:462
    This PR changes shouldRetry to require persistentRetryEnabled, but the old guard remains a few lines later and still calls shouldRetry(error) with one argument. That now fails root typecheck (TS2554: Expected 2 arguments, but got 1) on the changed file, and it also bypasses the new persistent-retry decision that line 429 just made. Please remove the duplicate guard or thread the flag through the remaining call so persistent 429/529 retries are not rejected immediately.

  • [P1] Fix the failing GitHub smoke-and-tests check before merging
    package.json:55
    The current PR head is red on GitHub: smoke-and-tests fails in bun run check during test:full with 5 failures. The new persistent retry cap test only calls the operation once instead of the expected 101 times, and four client.test.ts cases fail because the Anthropic SDK cannot resolve an auth method. Since this PR changes the top-level test scripts to run the whole suite with --feature=UNATTENDED_RETRY, please either keep that feature flag scoped to the retry-cap test path or fix the leaked feature/env/module state so the full CI smoke job is green.

  • [P2] Complete CodeRabbit's mkdir EEXIST request for changelog migration
    src/utils/releaseNotes.ts:227
    CodeRabbit's review thread is still unresolved, and the current patch still calls await mkdir(dirname(cachePath), { recursive: true }) outside the EEXIST-suppressing block. The write path now handles EEXIST, but the directory creation can still throw before the write on the Bun/Windows readonly-folder case the review identified, which leaves startup logging "Changelog migration failed" and retries on every launch even though the directory exists. Please complete that review request by catching mkdir errors here and ignoring only EEXIST, rethrowing everything else.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/utils/analyzeContext.mcp.test.ts (1)

18-21: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Acquire/release the shared mutation lock around all env mutations.

Right now env writes in Line 18-21 happen before lock acquisition, and env restoration in Line 23-31 happens after lock release. That leaves mutation windows unprotected and can reintroduce parallel test flakiness.

Suggested fix (move lock to outer hooks)
 beforeEach(() => {
+  await acquireSharedMutationLock('utils/analyzeContext.mcp.test.ts')
   delete process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS
   delete process.env.ENABLE_TOOL_SEARCH
 })
 
 afterEach(() => {
-  for (const [key, value] of Object.entries(originalEnv)) {
-    if (value === undefined) {
-      delete process.env[key]
-    } else {
-      process.env[key] = value
+  try {
+    for (const [key, value] of Object.entries(originalEnv)) {
+      if (value === undefined) {
+        delete process.env[key]
+      } else {
+        process.env[key] = value
+      }
     }
+  } finally {
+    releaseSharedMutationLock()
   }
 })
 
 describe('countMcpToolTokens', () => {
-  beforeEach(async () => {
-    await acquireSharedMutationLock('utils/analyzeContext.mcp.test.ts')
+  beforeEach(() => {
     process.env.ENABLE_TOOL_SEARCH = 'true'
     delete process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS
     delete process.env.ANTHROPIC_BASE_URL
   })
 
   afterEach(() => {
-    try {
-      for (const [key, value] of Object.entries(savedToolSearchEnv)) {
-        if (value === undefined) {
-          delete process.env[key]
-        } else {
-          process.env[key] = value
-        }
+    for (const [key, value] of Object.entries(savedToolSearchEnv)) {
+      if (value === undefined) {
+        delete process.env[key]
+      } else {
+        process.env[key] = value
       }
-    } finally {
-      releaseSharedMutationLock()
     }
   })

As per coding guidelines, test reviews should block on poor isolation of global/env/config state and async cleanup risks in changed test paths.

Also applies to: 79-84, 86-97, 23-31

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/analyzeContext.mcp.test.ts` around lines 18 - 21, Wrap all
environment variable mutations in the shared mutation lock by acquiring the lock
at the start of the top-level beforeEach and releasing it at the end of the
corresponding afterEach so that delete/set of
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS and
process.env.ENABLE_TOOL_SEARCH (and the restore logic currently in afterEach)
occur while the lock is held; move the lock acquisition to cover the lines in
the beforeEach that mutate env (currently deleting those vars) and move the lock
release to run only after the env restoration logic in afterEach, ensuring all
env writes/readbacks between beforeEach and afterEach are protected.

Source: Coding guidelines

src/services/api/client.test.ts (1)

35-46: ⚠️ Potential issue | 🔴 Critical

Fix TS1117 in src/services/api/client.test.ts: remove duplicate keys in originalEnv
const originalEnv defines OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, and OPENAI_AUTH_HEADER_VALUE twice, triggering TS1117 typecheck/CI failure. Remove one of the duplicate occurrences so each key appears only once.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/api/client.test.ts` around lines 35 - 46, The object originalEnv
in the test contains duplicate keys (OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME,
OPENAI_AUTH_HEADER_VALUE) causing TS1117; edit the originalEnv declaration to
remove the second set of those three duplicated properties so each env key
appears only once (locate the originalEnv constant in
src/services/api/client.test.ts and delete the repeated OPENAI_AUTH_HEADER,
OPENAI_AUTH_SCHEME, and OPENAI_AUTH_HEADER_VALUE entries).

Sources: Coding guidelines, Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/services/api/client.test.ts`:
- Around line 35-46: The object originalEnv in the test contains duplicate keys
(OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, OPENAI_AUTH_HEADER_VALUE) causing
TS1117; edit the originalEnv declaration to remove the second set of those three
duplicated properties so each env key appears only once (locate the originalEnv
constant in src/services/api/client.test.ts and delete the repeated
OPENAI_AUTH_HEADER, OPENAI_AUTH_SCHEME, and OPENAI_AUTH_HEADER_VALUE entries).

In `@src/utils/analyzeContext.mcp.test.ts`:
- Around line 18-21: Wrap all environment variable mutations in the shared
mutation lock by acquiring the lock at the start of the top-level beforeEach and
releasing it at the end of the corresponding afterEach so that delete/set of
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS and
process.env.ENABLE_TOOL_SEARCH (and the restore logic currently in afterEach)
occur while the lock is held; move the lock acquisition to cover the lines in
the beforeEach that mutate env (currently deleting those vars) and move the lock
release to run only after the env restoration logic in afterEach, ensuring all
env writes/readbacks between beforeEach and afterEach are protected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bac08e70-4551-4ae3-8886-c9c99e91540b

📥 Commits

Reviewing files that changed from the base of the PR and between aa9f9fd and ab5a7a7.

📒 Files selected for processing (3)
  • package.json
  • src/services/api/client.test.ts
  • src/utils/analyzeContext.mcp.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • package.json
  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/client.test.ts
{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}

⚙️ CodeRabbit configuration file

{bin/**,scripts/**,package.json,src/setup.ts,src/main.tsx,src/entrypoints/**}: Review install, launcher, build, packaging, startup, and entrypoint changes for cross-platform compatibility, tracked-source rewrites, env/config precedence, and release safety. Block on changes that can break Windows/macOS/Linux startup or publish unexpected artifacts.

Files:

  • package.json
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • package.json
  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/client.test.ts
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/client.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Typecheck TypeScript code before submitting (use bun run typecheck)

Files:

  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/client.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/client.test.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/client.test.ts
🪛 GitHub Actions: PR Checks / 0_typecheck.txt
src/services/api/client.test.ts

[error] 44-46: TypeScript (TS1117): An object literal cannot have multiple properties with the same name.

🪛 GitHub Actions: PR Checks / typecheck
src/services/api/client.test.ts

[error] 44-46: TypeScript (TS1117): An object literal cannot have multiple properties with the same name.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026
@skyhighbg22-jpg skyhighbg22-jpg requested a review from jatmn June 14, 2026 16:10

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the changed paths and found one issue that still needs to be addressed.

Findings

  • [P3] Complete the prior snip-replay description cleanup
    src/QueryEngine.ts:949
    jatmn's prior review item about the stale snip-replay claim is still valid in the current PR description: it says QueryEngine now uses splice(0, length, ...messages) so concurrent readers never observe an empty mutableMessages array, but the current code still leaves the length = 0 followed by push(...snipResult.messages) behavior in place. Since this PR is no longer implementing that atomic replacement, please complete that prior request by removing the stale claim from the description, or include the claimed implementation and tests if it is still intended here.

Restores the atomic array replacement using splice(0, length, ...messages)
instead of length=0 + push(...) that was claimed in commit 4d54d5d but
lost during merge. This ensures concurrent readers of getMessages() never
observe an empty mutableMessages array during snip replay, matching the
compact_boundary behavior.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an issue that needs to be addressed before this is ready.

Findings

  • [P1] Keep release/raw Bun test paths green
    src/services/api/withRetry.test.ts:536
    The new persistent retry test only exercises the production gate when Bun is started with --feature=UNATTENDED_RETRY, and the package scripts were updated to add that flag. However, the release workflow still runs bun test --max-concurrency=1 directly, so this changed test fails on the release path: operation is called once instead of 101 times because feature('UNATTENDED_RETRY') is false. Please either update every raw bun test entry point that runs this file, including .github/workflows/release.yml, or make the test skip/use a feature-enabled runner path so release publishing is not blocked.

@skyhighbg22-jpg skyhighbg22-jpg requested a review from jatmn June 15, 2026 12:34
The persistent retry cap test requires the UNATTENDED_RETRY feature flag
to be enabled. The release workflow was running 'bun test --max-concurrency=1'
without the feature flag, causing the test to fail on the release path.

This aligns the release workflow with the package.json test scripts which
all include --feature=UNATTENDED_RETRY.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.

Findings

  • [P2] Keep documented raw Bun test commands green
    src/services/api/withRetry.test.ts:536
    The release workflow and package scripts now pass --feature=UNATTENDED_RETRY, but the repo still documents raw Bun test entry points for contributors (bun test for the full unit suite and bun test path/to/file.test.ts for focused runs). This new test fails under those documented commands because feature('UNATTENDED_RETRY') remains false, so the retry loop stops after one call instead of the expected 101. Please either make this test skip or adapt itself when the feature flag is unavailable, or update every documented raw/focused Bun test command to include the required feature flag so the documented validation path stays green.

  • [P2] Normalize the REPL bridge system/init permission mode too
    src/hooks/useReplBridge.tsx:310
    The new QueryEngine guard keeps internal permission modes like auto off the SDK system/init wire, but buildSystemInitMessage is also called from the REPL bridge and that path still passes state_0.toolPermissionContext.mode directly. SDKSystemMessageSchema only accepts default, acceptEdits, bypassPermissions, fullAccess, plan, and dontAsk, so an auto-mode REPL bridge session can still emit a schema-invalid permissionMode: "auto" init event to remote clients. Please apply the same external-mode normalization to this caller, or move the normalization into buildSystemInitMessage so both documented call sites stay in sync.

… retry cap

- Remove duplicate OPENAI_AUTH_HEADER/SCHEME/VALUE deletes from
  clearEnvForMiniMaxOnlyTest() (shared beforeEach already clears them)
- Clarify persistent retry cap comment: the ~8h estimate only applies to
  the exponential-backoff path; the reset-delay path (up to
  PERSISTENT_RESET_CAP_MS / 6h per attempt) can take far longer
- Telemetry event at retry cap already present from prior commit
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 16, 2026
@skyhighbg22-jpg skyhighbg22-jpg requested a review from jatmn June 16, 2026 06:21

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.

Findings

  • [P2] Keep documented raw Bun test commands green
    src/services/api/withRetry.test.ts:535
    The release workflow and package scripts now pass --feature=UNATTENDED_RETRY, but the repo still documents raw Bun test entry points for contributors (bun test for the full unit suite and bun test path/to/file.test.ts / bun test ./path/to/test-file.test.ts for focused runs). This new test still fails under that documented path: bun test src/services/api/withRetry.test.ts runs with feature('UNATTENDED_RETRY') === false, so the operation is called once instead of the expected 101 times. Please keep the coverage intact by either updating every documented raw/focused Bun test command to include the required feature flag, or by making the test explicitly assert both modes: the 100-retry cap when the feature is enabled, and the normal non-persistent retry behavior when the feature is unavailable.

  • [P2] Normalize the REPL bridge system/init permission mode too
    src/hooks/useReplBridge.tsx:310
    The new QueryEngine guard keeps internal permission modes like auto off the SDK system/init wire, but the REPL bridge caller still passes state_0.toolPermissionContext.mode directly into buildSystemInitMessage. The SDK PermissionMode wire type only accepts default, acceptEdits, bypassPermissions, fullAccess, plan, and dontAsk, so an auto-mode REPL bridge session can still emit a schema-invalid permissionMode: "auto" init event to remote clients. Please apply the same external-mode normalization to this caller, or move the normalization into buildSystemInitMessage so both documented call sites stay in sync.

…_RETRY

Updated test to account for feature flag behavior in retry logic.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/api/withRetry.test.ts`:
- Around line 565-570: The expectedCalls calculation uses
`_PERSISTENT_MAX_ATTEMPTS_FOR_TEST` which is a constant that always has the
value 100 regardless of feature compilation, causing the condition to always
evaluate true and expectedCalls to always be 101. Replace the constant check
with a call to the actual feature gate function (such as
`isPersistentRetryEnabled()` or the equivalent that checks whether the
UNATTENDED_RETRY feature is compiled and enabled) so the test correctly expects
1 call when the feature is disabled and 101 calls when enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 979214fe-1454-43b7-b809-e624f1a1a0d6

📥 Commits

Reviewing files that changed from the base of the PR and between 38b953c and bac72d6.

📒 Files selected for processing (1)
  • src/services/api/withRetry.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise in code

Files:

  • src/services/api/withRetry.test.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/api/withRetry.test.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}

⚙️ CodeRabbit configuration file

{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.

Files:

  • src/services/api/withRetry.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/api/withRetry.test.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/api/withRetry.test.ts

Comment thread src/services/api/withRetry.test.ts Outdated

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the changed paths and found one issue that still needs to be addressed.

Please do not wait for the maintainer's manual reviews to fix CodeRabbit's findings.

Findings

  • [P2] Complete CodeRabbit's raw-test feature-gate request
    src/services/api/withRetry.test.ts:569
    CodeRabbit's current review thread is still valid: expectedCalls is derived from _PERSISTENT_MAX_ATTEMPTS_FOR_TEST, but that export is the constant 100 regardless of whether Bun was launched with --feature=UNATTENDED_RETRY. Under the documented focused command bun test src/services/api/withRetry.test.ts, feature('UNATTENDED_RETRY') is false, the operation runs once, and the test still expects 101 calls, so the raw contributor path remains red even though the package scripts pass. Please complete that review request by checking the real feature gate, or otherwise explicitly assert both the feature-enabled cap behavior and the feature-disabled one-call behavior.

… test

Refactor withRetry test to include isPersistentRetryEnabled check and update expected calls logic.
…ry test

Refactor runRetries function for clarity.
@skyhighbg22-jpg skyhighbg22-jpg requested a review from jatmn June 17, 2026 13:03

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the changed paths and do not see any remaining actionable issues from my side.

@kevincodex1 LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants