Skip to content

Fix snip metadata leaks and TUI corruption - #1600

Merged
kevincodex1 merged 6 commits into
Twigpine:mainfrom
jatmn:tui-corruption
Jun 11, 2026
Merged

kevincodex1 merged 6 commits into
Twigpine:mainfrom
jatmn:tui-corruption

Conversation

@jatmn

@jatmn jatmn commented Jun 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #1578.
Mitigates #1584.

  • replace visible snip [id:...] message tags with internal snip_id=... metadata wrapped in <system-reminder> so snip targets remain available without leaking into user-visible transcript text or model responses
  • keep snip compaction compatible with legacy [id:...] markers while accepting bare/full snip_id=... metadata
  • update SnipTool guidance and tests so pruning old tool output queues related tool interactions without echoing internal ID mechanics
  • clarify the OpenAI shim synthetic assistant boundary from an interruption message to a neutral tool-results marker
  • mitigate Konsole + tmux TUI corruption by disabling the scroll fast path for that environment, preserving bottom-follow behavior, and clearing cached output for culled nodes
  • tighten test isolation around env/session state and GitHub Actions config setup

User / Developer Impact

  • Users should no longer see raw snip IDs or have the assistant discuss them when old conversation/tool output is pruned.
  • Konsole users running inside tmux get a conservative rendering path to avoid garbled scroll output, with OPENCLAUDE_KONSOLE_TMUX_FAST_SCROLL available as an escape hatch.
  • Existing legacy snip markers remain parseable for pending/older conversation state.
  • No provider behavior changed.

Validation

Ran locally on Windows / PowerShell:

  • bun run build
  • bun run smoke
  • $env:ANTHROPIC_API_KEY='test-key'; bun run check
    • 3691 pass, 0 fail
  • $env:ANTHROPIC_API_KEY='test-key'; bun run test:full
    • 3691 pass, 0 fail
  • python -m pytest -q python/tests
    • 44 passed
  • bun run security:pr-scan -- --base upstream/main
    • no suspicious additions

Summary by CodeRabbit

  • Bug Fixes

    • Improved terminal scroll behavior to avoid visual glitches, restore stickiness, and prevent ghost/stale output during navigation.
    • Prevented stale child output when culled and made scroll fast-path safer across environments.
    • Adjusted auto-compact/circuit-breaker threshold logic to reduce unexpected blocking.
  • UX / Messaging

    • Assistant tool-result messages now state "[Tool results received]" for clearer feedback.
    • Snipping uses internal snip metadata and shows simplified, non‑exposing confirmations; prompts updated to prefer system snip_ids.
  • Tests

    • Expanded and updated tests for snip handling, message tagging/normalization, session persistence, compacting, and related behaviors.

Replace visible snip ID tags with internal snip_id metadata and update SnipTool guidance/tests so the model can request pruning without echoing user-visible IDs.

Add compatibility parsing for legacy [id:...] markers, clarify synthetic OpenAI shim tool-result messages, and tighten test cleanup around env/session state.

Mitigate Konsole+tmux rendering corruption by disabling the scroll fast path in that environment while preserving bottom-follow behavior and clearing culled cached output.

Validation: bun run build; bun run smoke; ANTHROPIC_API_KEY=test-key bun run check; ANTHROPIC_API_KEY=test-key bun run test:full; python -m pytest -q python/tests; bun run security:pr-scan -- --base upstream/main.
@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

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: cf80a99c-3fb9-4382-9534-379c273f3136

📥 Commits

Reviewing files that changed from the base of the PR and between 4c06cc8 and 4149196.

📒 Files selected for processing (1)
  • src/query.ts
📜 Recent 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 (3)
**/*.{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/query.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/query.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/query.ts
🔇 Additional comments (1)
src/query.ts (1)

10-10: LGTM!

Also applies to: 825-839


📝 Walkthrough

Walkthrough

Converts visible snip tags to internal snip_id=... metadata (normalizing legacy forms), updates SnipTool prompt/output and tests, changes OpenAI shim marker, adds an env toggle and stickiness fixes for ScrollBox, and tightens several test fixtures to snapshot/restore env/config state.

Changes

Snip ID Tagging Migration to Internal Metadata

Layer / File(s) Summary
Message tagging implementation and semantics
src/utils/messages.ts
appendMessageTagToUserMessage injects <system-reminder>snip_id=<token> markers, preserves tool_result blocks, and uses idempotency checks across string/array content. Comments updated to reflect new behavior.
Short ID normalization for legacy/modern formats
src/services/compact/snipCompact.ts, src/services/compact/snipCompact.test.ts
Add normalizeSnipShortId to canonicalize snip_id=... and legacy [id:...] formats; markForSnip resolves normalized short IDs to UUIDs; tests added for alternative syntaxes and SNIP_NUDGE_TEXT updated.
SnipTool prompt/schema and tests
src/tools/SnipTool/SnipTool.ts, src/tools/SnipTool/prompt.ts, src/tools/SnipTool/SnipTool.test.ts
SnipTool input description and tool-result wording simplified; prompt now instructs model to pass system-generated snip_id=... (raw value); tests updated to avoid exposing internal IDs.
Snip tag tests
src/utils/messages.snipTag.test.ts
Test helpers/assertions updated to expect internal snip_id= markers, validate idempotency, ensure tool_result preservation, and prevent exposure of old [id: markers.

ScrollBox Fast-Path Disable and Stickiness Improvements

Layer / File(s) Summary
Fast-path toggle and at-bottom logic
src/ink/render-node-to-output.ts
Introduce DISABLE_SCROLL_FAST_PATH from env; compute positionallyAtBottom using prevMaxScroll or maxScroll depending on growth/shrink; derive atBottom and sticky restoration from it; require fast-path not disabled for fast path eligibility.
Clear output for culled children
src/ink/render-node-to-output.ts
When preserveCulledCache is false, emit output.clear() for the cached floored rectangle before dropping subtree cache to avoid ghosted content.

OpenAI Shim and Semantic Assistant Marker

Layer / File(s) Summary
Shim marker and tests
src/services/api/openaiShim.ts, src/services/api/openaiShim.test.ts
Synthetic assistant boundary injected on tool→user transitions now uses "[Tool results received]"; tests updated to assert new content and avoid "interrupted"/"user" wording.

Test Infrastructure and Environment Management

Layer / File(s) Summary
SetupGitHubActions test refactor
src/commands/install-github-app/setupGitHubActions.test.ts
Replace initialSetupCount restore with local setupConfig: GlobalConfig; mock src/utils/config.js and route saveGlobalConfig to test updater; initialize counters in beforeEach and assert setupConfig.githubActionSetupCount.
Session persistence test fixture expansion
src/utils/sessionStorage.test.ts
Bring in flushSessionStorage and persistence helpers; snapshot/restore additional env vars and session flag; durability test flushes session storage before validation.
MCP deferred-schema env isolation
src/utils/analyzeContext.mcp.test.ts
Save/restore ENABLE_TOOL_SEARCH and CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS around token-counting invocation via try/finally.
Auto-compact high-context fixture
src/query/autoCompactCooldown.test.ts
Add highContextMessages() helper and use it in three tests to simulate multi-turn assistant context plus a follow-up user message.
Auto-compact circuit breaker threshold logic
src/query.ts
Import getAutoCompactThreshold and change breaker logic to block based on isAboveBreakerThreshold that uses model-specific breaker threshold when the circuit breaker is active/tripped.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • Gitlawb/openclaude#1407: Implements/modifies the History Snip pipeline at the code level, particularly snipCompact/markForSnip and message tagging, so this PR's internal snip_id=... metadata changes integrate directly with snip tool compaction and projection behavior.

Suggested reviewers

  • gnanam1990
  • Vasanthdev2004
  • kevincodex1
🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main changes: fixing snip metadata leaks and TUI corruption, both central to this PR.
Description check ✅ Passed Description includes Summary (what/why), Impact (user/dev), and Validation (testing). Template sections are present and well-populated.
Linked Issues check ✅ Passed All major changes address #1578 (TUI corruption, scroll jumps, rendering stability) and #1584 (snip metadata handling). Snip visibility fixes, scroll fast-path mitigation, and cached output clearing directly resolve the reported issues.
Out of Scope Changes check ✅ Passed Changes are well-scoped to snip metadata replacement, TUI scroll fixes, legacy marker support, and test isolation. Auto-compact circuit-breaker logic refinement relates to stability mentioned in PR objectives.
Risk Surface Disclosed ✅ Passed PR does not touch auth, provider routing, permissions, network behavior, startup/config, MCP/plugins, CI permissions, or release scripts. Changes are localized to internal message mechanics, TUI re...
No Hidden Policy Change ✅ Passed No hidden policy changes detected. PR contains bug fixes (TUI corruption, circuit breaker stability), UX improvements (snip ID hiding), and test cleanup—no trust/permission/routing/telemetry policy...

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

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

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

@jatmn jatmn self-assigned this Jun 11, 2026
@jatmn jatmn linked an issue Jun 11, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/compact/snipCompact.ts`:
- Line 19: Static analysis flagged the regex literals as command-injection risks
but these are false positives; add an inline suppression and brief explanatory
comment above the regex usages to silence SAST. For example, above the
snipMetadataMatch assignment (/\bsnip_id=([a-z0-9]{6})\b/i) and the
/^\[id:...\]$/ usage add a one-line comment like "SAST false positive: regex
literal, not executing user input" plus the project’s suppression token (e.g. //
nosemgrep or // nosec or // eslint-disable-next-line
security/detect-unsafe-regex) so scanners ignore these lines while keeping the
regex literals (snipMetadataMatch and the id regex) unchanged.
🪄 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: 8f4a2128-c2c6-4f97-802b-774eaebfbd2f

📥 Commits

Reviewing files that changed from the base of the PR and between d00b105 and 89918fe.

📒 Files selected for processing (15)
  • docs/windows-aliases-and-launchers.md
  • scripts/windows/openclaude-aliases.ps1
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/ink/render-node-to-output.ts
  • src/services/api/openaiShim.test.ts
  • src/services/api/openaiShim.ts
  • src/services/compact/snipCompact.test.ts
  • src/services/compact/snipCompact.ts
  • src/tools/SnipTool/SnipTool.test.ts
  • src/tools/SnipTool/SnipTool.ts
  • src/tools/SnipTool/prompt.ts
  • src/utils/analyzeContext.mcp.test.ts
  • src/utils/messages.snipTag.test.ts
  • src/utils/messages.ts
  • src/utils/sessionStorage.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/tools/SnipTool/SnipTool.test.ts
  • src/services/compact/snipCompact.test.ts
  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/openaiShim.test.ts
  • src/utils/messages.snipTag.test.ts
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/utils/sessionStorage.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/tools/SnipTool/SnipTool.test.ts
  • src/services/compact/snipCompact.test.ts
  • src/utils/analyzeContext.mcp.test.ts
  • src/tools/SnipTool/prompt.ts
  • src/services/api/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/tools/SnipTool/SnipTool.ts
  • src/utils/messages.snipTag.test.ts
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/utils/sessionStorage.test.ts
  • src/ink/render-node-to-output.ts
  • src/services/compact/snipCompact.ts
  • src/utils/messages.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/tools/SnipTool/SnipTool.test.ts
  • src/services/compact/snipCompact.test.ts
  • src/utils/analyzeContext.mcp.test.ts
  • docs/windows-aliases-and-launchers.md
  • src/tools/SnipTool/prompt.ts
  • src/services/api/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/tools/SnipTool/SnipTool.ts
  • src/utils/messages.snipTag.test.ts
  • scripts/windows/openclaude-aliases.ps1
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/utils/sessionStorage.test.ts
  • src/ink/render-node-to-output.ts
  • src/services/compact/snipCompact.ts
  • src/utils/messages.ts
src/{components/permissions,utils/permissions,hooks/toolPermission,tools,entrypoints/sdk}/**

⚙️ CodeRabbit configuration file

src/{components/permissions,utils/permissions,hooks/toolPermission,tools,entrypoints/sdk}/**: Review permission prompts, auto-allow logic, sandbox behavior, SDK permission schemas, shell/PowerShell execution, and background execution paths as security-sensitive. Block on bypasses, unclear trust boundaries, unsafe path handling, missing user visibility, or changes that broaden allowed behavior without an explicit maintainer decision.

Files:

  • src/tools/SnipTool/SnipTool.test.ts
  • src/tools/SnipTool/prompt.ts
  • src/tools/SnipTool/SnipTool.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/tools/SnipTool/SnipTool.test.ts
  • src/services/compact/snipCompact.test.ts
  • src/utils/analyzeContext.mcp.test.ts
  • src/services/api/openaiShim.test.ts
  • src/utils/messages.snipTag.test.ts
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/utils/sessionStorage.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/tools/SnipTool/SnipTool.test.ts
  • src/services/compact/snipCompact.test.ts
  • src/utils/analyzeContext.mcp.test.ts
  • docs/windows-aliases-and-launchers.md
  • src/tools/SnipTool/prompt.ts
  • src/services/api/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/tools/SnipTool/SnipTool.ts
  • src/utils/messages.snipTag.test.ts
  • scripts/windows/openclaude-aliases.ps1
  • src/commands/install-github-app/setupGitHubActions.test.ts
  • src/utils/sessionStorage.test.ts
  • src/ink/render-node-to-output.ts
  • src/services/compact/snipCompact.ts
  • src/utils/messages.ts
**/*.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update docs when setup, commands, or user-facing behavior changes

Files:

  • docs/windows-aliases-and-launchers.md
{README.md,CONTRIBUTING.md,docs/**,.github/pull_request_template.md}

⚙️ CodeRabbit configuration file

{README.md,CONTRIBUTING.md,docs/**,.github/pull_request_template.md}: Review docs for accuracy against current code behavior. Flag security or provider claims that overpromise, stale install commands, missing setup caveats, and instructions that could push users toward unsafe credential handling. Keep purely wording-level suggestions non-blocking.

Files:

  • docs/windows-aliases-and-launchers.md
{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/openaiShim.ts
  • src/services/api/openaiShim.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:

  • scripts/windows/openclaude-aliases.ps1
🪛 OpenGrep (1.22.0)
src/services/compact/snipCompact.ts

[ERROR] 19-19: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)


[ERROR] 23-23: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (37)
docs/windows-aliases-and-launchers.md (1)

162-163: LGTM!

scripts/windows/openclaude-aliases.ps1 (1)

206-207: LGTM!

src/commands/install-github-app/setupGitHubActions.test.ts (4)

2-2: LGTM!


28-28: LGTM!


170-174: LGTM!


207-207: LGTM!

Also applies to: 250-250, 278-278

src/utils/sessionStorage.test.ts (3)

18-18: LGTM!

Also applies to: 27-31


173-182: LGTM!

Also applies to: 192-207


580-580: LGTM!

src/utils/analyzeContext.mcp.test.ts (1)

81-134: LGTM!

src/ink/render-node-to-output.ts (5)

52-62: LGTM!


790-798: LGTM!


812-817: LGTM!


940-944: LGTM!


1482-1502: LGTM!

src/utils/messages.ts (6)

200-201: LGTM!


1625-1721: LGTM!

The migration from visible [id:...] tags to internal snip_id=... metadata wrapped in <system-reminder> is correctly implemented:

  1. Tag format aligns with normalizeSnipShortId regex in snipCompact.ts (context snippet 2)
  2. Idempotency check correctly detects existing snip_id=${idToken} markers via substring match
  3. tool_result fallback appends a dedicated text block preserving the tool_result block intact
  4. <system-reminder> wrapping ensures markers are filtered from user-visible exports (context snippet 3)

2048-2051: LGTM!


2214-2215: LGTM!

Also applies to: 2251-2251, 2262-2262


2428-2433: LGTM!


2495-2495: LGTM!

Also applies to: 2519-2520

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

766-773: LGTM!

src/services/api/openaiShim.test.ts (2)

5242-5242: LGTM!


5325-5327: LGTM!

src/utils/messages.snipTag.test.ts (5)

13-15: LGTM!


17-21: LGTM!


24-32: LGTM!


34-73: LGTM!


88-155: LGTM!

src/services/compact/snipCompact.ts (3)

16-28: LGTM!


43-44: LGTM!


57-63: LGTM!

src/tools/SnipTool/SnipTool.ts (2)

13-13: LGTM!


64-66: LGTM!

src/tools/SnipTool/prompt.ts (1)

6-6: LGTM!

src/services/compact/snipCompact.test.ts (1)

289-320: LGTM!

src/tools/SnipTool/SnipTool.test.ts (1)

36-45: LGTM!

Comment thread src/services/compact/snipCompact.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/ink/render-node-to-output.ts (1)

795-804: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Base the bottom-follow branch on maxScroll, not scrollHeight.

This branch detaches sticky follow when the viewport shrinks more than the content does. In that case scrollHeight decreased, so the code takes the "shrank" path, but maxScroll still increased. A user who was exactly at the previous bottom then fails scrollTopBeforeFollow >= maxScroll and stops following after a resize/layout change.

Suggested fix
-        const grew = scrollHeight >= prevScrollHeight
-        // Growth follow must compare against the previous max: a user who was
-        // exactly at bottom before streaming adds a row is now below the new
-        // maxScroll, but should still follow. When content shrinks, use the
-        // current maxScroll to avoid treating virtualization height artifacts
-        // as a real "was at bottom" signal.
-        const positionallyAtBottom = grew
+        const bottomMovedDown = maxScroll >= prevMaxScroll
+        // If the bottom moved down (content growth or viewport shrink), compare
+        // against the previous max so a user who was already at bottom keeps
+        // following. If the bottom moved up, compare against the current max so
+        // shrink/virtualization doesn't falsely re-enable follow.
+        const positionallyAtBottom = bottomMovedDown
           ? scrollTopBeforeFollow >= prevMaxScroll
           : scrollTopBeforeFollow >= maxScroll
🤖 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/ink/render-node-to-output.ts` around lines 795 - 804, The
follow-detachment branch is using scrollHeight comparison (grew = scrollHeight
>= prevScrollHeight) which misclassifies shrinks when maxScroll actually
increased; change the growth test to compare maxScroll against prevMaxScroll
(e.g., grew = maxScroll >= prevMaxScroll) so positionallyAtBottom uses the
correct "previous max" logic; update the logic around positionallyAtBottom and
the comment to reference maxScroll/prevMaxScroll (symbols: grew,
positionallyAtBottom, prevMaxScroll, maxScroll, scrollTopBeforeFollow) so a user
exactly at the prior bottom still follows after layout changes.
🤖 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/openaiShim.ts`:
- Around line 2831-2833: The comment misleadingly states that response is
guaranteed after the try/catch because throwClassifiedTransportError returns
never, yet the code still has a defensive guard `if (!response) continue` inside
the retry loop; update the comment near the `response` usage (and the
surrounding retry loop) to clarify that while `throwClassifiedTransportError` is
typed as never, the `if (!response) continue` check is an intentional defensive
runtime guard for unexpected cases (or remove the incorrect absolute guarantee
claim), referencing the `throwClassifiedTransportError` call and the `response`
variable so future readers understand why the guard remains.
- Line 2879: The local variable responsesResponse currently uses a definite
assignment assertion ("responsesResponse!") which hides control flow; remove the
"!" and either let TypeScript infer the Response type (declare "let
responsesResponse: Response" and ensure all control flows assign it) or declare
"let responsesResponse: Response | undefined" and add a null/undefined check
before any use (or rely on the catch path that calls
throwClassifiedTransportError to exit). Update any subsequent uses of
responsesResponse to handle the possible undefined case or to occur only after
an assignment, referencing the responsesResponse variable in this scope.

---

Outside diff comments:
In `@src/ink/render-node-to-output.ts`:
- Around line 795-804: The follow-detachment branch is using scrollHeight
comparison (grew = scrollHeight >= prevScrollHeight) which misclassifies shrinks
when maxScroll actually increased; change the growth test to compare maxScroll
against prevMaxScroll (e.g., grew = maxScroll >= prevMaxScroll) so
positionallyAtBottom uses the correct "previous max" logic; update the logic
around positionallyAtBottom and the comment to reference maxScroll/prevMaxScroll
(symbols: grew, positionallyAtBottom, prevMaxScroll, maxScroll,
scrollTopBeforeFollow) so a user exactly at the prior bottom still follows after
layout changes.
🪄 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: 68764d67-5d2b-4aba-94ef-97fa35f933c4

📥 Commits

Reviewing files that changed from the base of the PR and between 89918fe and 61c01e7.

📒 Files selected for processing (4)
  • src/ink/render-node-to-output.ts
  • src/services/api/openaiShim.test.ts
  • src/services/api/openaiShim.ts
  • src/utils/messages.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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/services/api/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/ink/render-node-to-output.ts
  • src/utils/messages.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/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/ink/render-node-to-output.ts
  • src/utils/messages.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/openaiShim.ts
  • src/services/api/openaiShim.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/openaiShim.ts
  • src/services/api/openaiShim.test.ts
  • src/ink/render-node-to-output.ts
  • src/utils/messages.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/services/api/openaiShim.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/openaiShim.test.ts
🔇 Additional comments (7)
src/ink/render-node-to-output.ts (1)

52-62: LGTM!

Also applies to: 404-410, 946-955, 1496-1507

src/utils/messages.ts (1)

481-484: LGTM!

Also applies to: 865-871, 885-888, 906-907, 942-943, 960-967, 986-989, 1811-1817, 2868-2869

src/services/api/openaiShim.ts (2)

1059-1061: LGTM!

Also applies to: 1066-1077, 1122-1123, 1135-1142, 1338-1340, 1355-1389


770-774: Confirm: no code relies on the old tool-boundary marker string

  • No occurrences of "[Tool execution interrupted by user]" remain in the codebase.
  • "[Tool results received]" is only referenced in src/services/api/openaiShim.ts and src/services/api/openaiShim.test.ts.
  • src/utils/exportRenderer.tsx’s isSyntheticContent does not special-case either marker string (it filters different synthetic markers / SYNTHETIC_TOOL_RESULT_PLACEHOLDER blocks).
src/services/api/openaiShim.test.ts (3)

1-1: LGTM!

Also applies to: 3-3, 132-132, 259-259, 322-322, 380-380, 416-416, 479-479, 506-506, 546-546, 587-587, 621-621, 655-655, 689-689, 723-723, 768-768, 851-851, 943-943, 978-978, 1025-1025, 1107-1107, 1169-1169, 1214-1214, 1262-1262, 1307-1307, 1398-1398, 1475-1475, 1558-1558, 1639-1639, 1724-1724, 1774-1774, 1848-1848, 1893-1893, 1992-1992, 2068-2068, 2184-2184, 2244-2244, 2294-2294, 2343-2343, 2391-2391, 2644-2644, 2731-2731, 2811-2811, 2885-2885, 2972-2972, 3037-3037, 3099-3099, 3165-3165, 3226-3226, 3293-3293, 3391-3391, 3489-3489, 3565-3565, 3641-3641, 3739-3739, 3815-3815, 3891-3891, 3967-3967, 4036-4036, 4096-4096, 4151-4151, 4212-4212, 4274-4274, 4303-4303, 4356-4356, 4401-4401, 4446-4446, 4465-4488, 4558-4558, 4597-4630, 4655-4715, 4743-4776, 4807-4811, 4842-4844, 4877-4879, 4909-4911, 4934-4940, 4994-4994, 5054-5054, 5116-5116, 5183-5183, 5261-5261, 5298-5298, 5351-5351, 5385-5385, 5417-5417, 5449-5449, 5488-5488, 5555-5555, 5613-5613, 5672-5672, 5738-5738, 5770-5770, 5804-5804, 5871-5871, 5910-5910, 5943-5943, 5991-5991, 6068-6068, 6126-6126, 6199-6199, 6240-6240, 6277-6277, 6329-6329, 6375-6375, 6413-6413, 6449-6449


2198-2201: LGTM!


5328-5330: LGTM!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/ink/render-node-to-output.ts (1)

795-804: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Base the bottom-follow branch on maxScroll, not scrollHeight.

This branch detaches sticky follow when the viewport shrinks more than the content does. In that case scrollHeight decreased, so the code takes the "shrank" path, but maxScroll still increased. A user who was exactly at the previous bottom then fails scrollTopBeforeFollow >= maxScroll and stops following after a resize/layout change.

Suggested fix
-        const grew = scrollHeight >= prevScrollHeight
-        // Growth follow must compare against the previous max: a user who was
-        // exactly at bottom before streaming adds a row is now below the new
-        // maxScroll, but should still follow. When content shrinks, use the
-        // current maxScroll to avoid treating virtualization height artifacts
-        // as a real "was at bottom" signal.
-        const positionallyAtBottom = grew
+        const bottomMovedDown = maxScroll >= prevMaxScroll
+        // If the bottom moved down (content growth or viewport shrink), compare
+        // against the previous max so a user who was already at bottom keeps
+        // following. If the bottom moved up, compare against the current max so
+        // shrink/virtualization doesn't falsely re-enable follow.
+        const positionallyAtBottom = bottomMovedDown
           ? scrollTopBeforeFollow >= prevMaxScroll
           : scrollTopBeforeFollow >= maxScroll
🤖 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/ink/render-node-to-output.ts` around lines 795 - 804, The
follow-detachment branch is using scrollHeight comparison (grew = scrollHeight
>= prevScrollHeight) which misclassifies shrinks when maxScroll actually
increased; change the growth test to compare maxScroll against prevMaxScroll
(e.g., grew = maxScroll >= prevMaxScroll) so positionallyAtBottom uses the
correct "previous max" logic; update the logic around positionallyAtBottom and
the comment to reference maxScroll/prevMaxScroll (symbols: grew,
positionallyAtBottom, prevMaxScroll, maxScroll, scrollTopBeforeFollow) so a user
exactly at the prior bottom still follows after layout changes.
🤖 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/openaiShim.ts`:
- Around line 2831-2833: The comment misleadingly states that response is
guaranteed after the try/catch because throwClassifiedTransportError returns
never, yet the code still has a defensive guard `if (!response) continue` inside
the retry loop; update the comment near the `response` usage (and the
surrounding retry loop) to clarify that while `throwClassifiedTransportError` is
typed as never, the `if (!response) continue` check is an intentional defensive
runtime guard for unexpected cases (or remove the incorrect absolute guarantee
claim), referencing the `throwClassifiedTransportError` call and the `response`
variable so future readers understand why the guard remains.
- Line 2879: The local variable responsesResponse currently uses a definite
assignment assertion ("responsesResponse!") which hides control flow; remove the
"!" and either let TypeScript infer the Response type (declare "let
responsesResponse: Response" and ensure all control flows assign it) or declare
"let responsesResponse: Response | undefined" and add a null/undefined check
before any use (or rely on the catch path that calls
throwClassifiedTransportError to exit). Update any subsequent uses of
responsesResponse to handle the possible undefined case or to occur only after
an assignment, referencing the responsesResponse variable in this scope.

---

Outside diff comments:
In `@src/ink/render-node-to-output.ts`:
- Around line 795-804: The follow-detachment branch is using scrollHeight
comparison (grew = scrollHeight >= prevScrollHeight) which misclassifies shrinks
when maxScroll actually increased; change the growth test to compare maxScroll
against prevMaxScroll (e.g., grew = maxScroll >= prevMaxScroll) so
positionallyAtBottom uses the correct "previous max" logic; update the logic
around positionallyAtBottom and the comment to reference maxScroll/prevMaxScroll
(symbols: grew, positionallyAtBottom, prevMaxScroll, maxScroll,
scrollTopBeforeFollow) so a user exactly at the prior bottom still follows after
layout changes.
🪄 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: 68764d67-5d2b-4aba-94ef-97fa35f933c4

📥 Commits

Reviewing files that changed from the base of the PR and between 89918fe and 61c01e7.

📒 Files selected for processing (4)
  • src/ink/render-node-to-output.ts
  • src/services/api/openaiShim.test.ts
  • src/services/api/openaiShim.ts
  • src/utils/messages.ts
📜 Review details
🔇 Additional comments (7)
src/ink/render-node-to-output.ts (1)

52-62: LGTM!

Also applies to: 404-410, 946-955, 1496-1507

src/utils/messages.ts (1)

481-484: LGTM!

Also applies to: 865-871, 885-888, 906-907, 942-943, 960-967, 986-989, 1811-1817, 2868-2869

src/services/api/openaiShim.ts (2)

1059-1061: LGTM!

Also applies to: 1066-1077, 1122-1123, 1135-1142, 1338-1340, 1355-1389


770-774: Confirm: no code relies on the old tool-boundary marker string

  • No occurrences of "[Tool execution interrupted by user]" remain in the codebase.
  • "[Tool results received]" is only referenced in src/services/api/openaiShim.ts and src/services/api/openaiShim.test.ts.
  • src/utils/exportRenderer.tsx’s isSyntheticContent does not special-case either marker string (it filters different synthetic markers / SYNTHETIC_TOOL_RESULT_PLACEHOLDER blocks).
src/services/api/openaiShim.test.ts (3)

1-1: LGTM!

Also applies to: 3-3, 132-132, 259-259, 322-322, 380-380, 416-416, 479-479, 506-506, 546-546, 587-587, 621-621, 655-655, 689-689, 723-723, 768-768, 851-851, 943-943, 978-978, 1025-1025, 1107-1107, 1169-1169, 1214-1214, 1262-1262, 1307-1307, 1398-1398, 1475-1475, 1558-1558, 1639-1639, 1724-1724, 1774-1774, 1848-1848, 1893-1893, 1992-1992, 2068-2068, 2184-2184, 2244-2244, 2294-2294, 2343-2343, 2391-2391, 2644-2644, 2731-2731, 2811-2811, 2885-2885, 2972-2972, 3037-3037, 3099-3099, 3165-3165, 3226-3226, 3293-3293, 3391-3391, 3489-3489, 3565-3565, 3641-3641, 3739-3739, 3815-3815, 3891-3891, 3967-3967, 4036-4036, 4096-4096, 4151-4151, 4212-4212, 4274-4274, 4303-4303, 4356-4356, 4401-4401, 4446-4446, 4465-4488, 4558-4558, 4597-4630, 4655-4715, 4743-4776, 4807-4811, 4842-4844, 4877-4879, 4909-4911, 4934-4940, 4994-4994, 5054-5054, 5116-5116, 5183-5183, 5261-5261, 5298-5298, 5351-5351, 5385-5385, 5417-5417, 5449-5449, 5488-5488, 5555-5555, 5613-5613, 5672-5672, 5738-5738, 5770-5770, 5804-5804, 5871-5871, 5910-5910, 5943-5943, 5991-5991, 6068-6068, 6126-6126, 6199-6199, 6240-6240, 6277-6277, 6329-6329, 6375-6375, 6413-6413, 6449-6449


2198-2201: LGTM!


5328-5330: LGTM!

🛑 Comments failed to post (2)
src/services/api/openaiShim.ts (2)

2831-2833: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Clarify comment vs runtime guard.

The comment states response is guaranteed after the try/catch because the catch always throws, but the code still checks if (!response) continue. While throwClassifiedTransportError does return never, the defensive guard in a retry loop is reasonable. Consider either removing the comment or noting that the guard is defensive.

🤖 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/openaiShim.ts` around lines 2831 - 2833, The comment
misleadingly states that response is guaranteed after the try/catch because
throwClassifiedTransportError returns never, yet the code still has a defensive
guard `if (!response) continue` inside the retry loop; update the comment near
the `response` usage (and the surrounding retry loop) to clarify that while
`throwClassifiedTransportError` is typed as never, the `if (!response) continue`
check is an intentional defensive runtime guard for unexpected cases (or remove
the incorrect absolute guarantee claim), referencing the
`throwClassifiedTransportError` call and the `response` variable so future
readers understand why the guard remains.

2879-2879: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Remove definite assignment assertion for clarity.

The ! assertion on responsesResponse is technically safe (the catch block throws via throwClassifiedTransportError), but it obscures the control flow. Consider removing it and letting TypeScript infer the type, or use an explicit | undefined type with a proper check.

♻️ Suggested refactor
-        let responsesResponse!: Response
+        let responsesResponse: Response
         try {
           responsesResponse = await fetchWithProxyRetry(responsesUrl, {
🤖 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/openaiShim.ts` at line 2879, The local variable
responsesResponse currently uses a definite assignment assertion
("responsesResponse!") which hides control flow; remove the "!" and either let
TypeScript infer the Response type (declare "let responsesResponse: Response"
and ensure all control flows assign it) or declare "let responsesResponse:
Response | undefined" and add a null/undefined check before any use (or rely on
the catch path that calls throwClassifiedTransportError to exit). Update any
subsequent uses of responsesResponse to handle the possible undefined case or to
occur only after an assignment, referencing the responsesResponse variable in
this scope.

Use usage-bearing high-context fixtures in autoCompactCooldown tests so the cooldown assertions do not depend on process-global threshold overrides surviving full-suite order. Add CodeRabbit-requested SAST suppression comments for snip regex literals.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/compact/snipCompact.ts`:
- Line 19: Update the invalid inline nosemgrep suppressions in
src/services/compact/snipCompact.ts by moving the explanatory text into a
separate comment line and using a proper nosemgrep rule-id on the suppression
line; specifically, for both places where a regex call uses .exec(trimmed)
(locate the .exec(trimmed) usages in the file), replace the single-line "//
nosemgrep: regex literal only; this does not execute user input." with two
lines: one comment containing the explanation ("// Regex literal only; this does
not execute user input.") followed by a pure suppression line using a rule id
(e.g. "// nosemgrep: coderabbit.command-injection.exec-js").
🪄 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: 6beb7b31-e906-444b-bee9-038b2a7b80dd

📥 Commits

Reviewing files that changed from the base of the PR and between 61c01e7 and 52ac043.

📒 Files selected for processing (2)
  • src/query/autoCompactCooldown.test.ts
  • src/services/compact/snipCompact.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/query/autoCompactCooldown.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/query/autoCompactCooldown.test.ts
  • src/services/compact/snipCompact.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/query/autoCompactCooldown.test.ts
  • src/services/compact/snipCompact.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/query/autoCompactCooldown.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/query/autoCompactCooldown.test.ts
  • src/services/compact/snipCompact.ts
🪛 OpenGrep (1.22.0)
src/services/compact/snipCompact.ts

[ERROR] 20-20: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🔇 Additional comments (2)
src/query/autoCompactCooldown.test.ts (2)

75-95: LGTM!


167-167: LGTM!

Also applies to: 222-222, 365-365

Comment thread src/services/compact/snipCompact.ts Outdated
Update the snip regex suppressions to CodeRabbit's requested nosemgrep rule-id form, with the explanatory text kept in a separate comment.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
Set and restore CLAUDE_CODE_AUTO_COMPACT_WINDOW in autoCompactCooldown tests so the high-context fixture lands above the auto-compact threshold but below the hard prompt limit on both local Windows and Linux CI.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/query/autoCompactCooldown.test.ts (1)

78-98: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fixture content is tiny but claims 170k tokens — test fails because token counting re-counts content, not usage metadata.

The highContextMessages() helper sets usage.input_tokens: 170_000, but the actual message content is "previous response" (~15 tokens) + "continue" (~5 tokens). Token counting in production code re-counts the actual content, not historical usage metadata, so the fixture registers as ~100 tokens instead of 170k.

With CLAUDE_CODE_AUTO_COMPACT_WINDOW='200000', the auto-compact threshold is ~153k-163k (80-85% of the effective 192k window). The ~100-token fixture falls far below this threshold, so isAboveAutoCompactThreshold returns false, the blocking check is skipped, and callModel is invoked — causing the test at line 211 to fail.

🛠️ Recommended fix: generate realistic large content

Replace the tiny text with a string large enough to actually represent 170k tokens (roughly 500k+ characters):

 function highContextMessages(): Message[] {
+  // Generate ~170k tokens of content (roughly 500k characters)
+  const largeText = 'A'.repeat(500_000)
   return [
     {
       type: 'assistant',
       message: {
         id: 'msg-high-context',
         role: 'assistant',
-        content: [{ type: 'text', text: 'previous response' }],
+        content: [{ type: 'text', text: largeText }],
         usage: {
           input_tokens: 170_000,
           output_tokens: 1_000,

Alternatively, mock the token counting function to return the expected value, or adjust CLAUDE_CODE_AUTO_COMPACT_WINDOW to a much lower value so the tiny content still exceeds the threshold.

🤖 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/query/autoCompactCooldown.test.ts` around lines 78 - 98, The test fixture
highContextMessages() claims 170k input tokens but its content is tiny, so
production token counting (used by isAboveAutoCompactThreshold and the caller
that may invoke callModel) re-counts and the message doesn't exceed the
auto-compact threshold; fix by making the fixture produce realistic large
content (e.g., replace the short "previous response" text with a generated
string large enough to approximate 170k tokens / ~500k+ characters), or
alternatively adjust the test to stub/mock the token counting function used by
isAboveAutoCompactThreshold or set CLAUDE_CODE_AUTO_COMPACT_WINDOW to a much
smaller value so the fixture legitimately triggers the auto-compact path. Ensure
changes reference highContextMessages, isAboveAutoCompactThreshold, and
callModel when updating the test.
🤖 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/query/autoCompactCooldown.test.ts`:
- Around line 78-98: The test fixture highContextMessages() claims 170k input
tokens but its content is tiny, so production token counting (used by
isAboveAutoCompactThreshold and the caller that may invoke callModel) re-counts
and the message doesn't exceed the auto-compact threshold; fix by making the
fixture produce realistic large content (e.g., replace the short "previous
response" text with a generated string large enough to approximate 170k tokens /
~500k+ characters), or alternatively adjust the test to stub/mock the token
counting function used by isAboveAutoCompactThreshold or set
CLAUDE_CODE_AUTO_COMPACT_WINDOW to a much smaller value so the fixture
legitimately triggers the auto-compact path. Ensure changes reference
highContextMessages, isAboveAutoCompactThreshold, and callModel when updating
the test.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9168f025-fe96-40b5-9026-0893cc4cb88f

📥 Commits

Reviewing files that changed from the base of the PR and between 5c1e63e and 4c06cc8.

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

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Add or update tests when the change affects behavior

Files:

  • src/query/autoCompactCooldown.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/query/autoCompactCooldown.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/query/autoCompactCooldown.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/query/autoCompactCooldown.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/query/autoCompactCooldown.test.ts
🪛 GitHub Actions: PR Checks / 0_smoke-and-tests.txt
src/query/autoCompactCooldown.test.ts

[error] 211-211: Jest assertion failed: expect(callModel).not.toHaveBeenCalled(). Expected number of calls: 0, Received number of calls: 1.

🪛 GitHub Actions: PR Checks / smoke-and-tests
src/query/autoCompactCooldown.test.ts

[error] 211-211: Test assertion failed (Jest). expect(callModel).not.toHaveBeenCalled() expected 0 calls, but received 1.

🔇 Additional comments (1)
src/query/autoCompactCooldown.test.ts (1)

20-21: LGTM!

Also applies to: 36-36

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 11, 2026
Block oversized requests when autocompact reports an active or tripped breaker, even if a later auto-compact config read is stale. This keeps cooldown protection active and stabilizes the CI smoke path.
@jatmn
jatmn marked this pull request as ready for review June 11, 2026 02:49
@kevincodex1
kevincodex1 merged commit 9c74231 into Twigpine:main Jun 11, 2026
3 checks passed
@jatmn
jatmn deleted the tui-corruption branch June 11, 2026 14:33
deagwon97 pushed a commit to deagwon97/openclaude that referenced this pull request Jun 15, 2026
* Fix snip metadata leaks and TUI corruption

Replace visible snip ID tags with internal snip_id metadata and update SnipTool guidance/tests so the model can request pruning without echoing user-visible IDs.

Add compatibility parsing for legacy [id:...] markers, clarify synthetic OpenAI shim tool-result messages, and tighten test cleanup around env/session state.

Mitigate Konsole+tmux rendering corruption by disabling the scroll fast path in that environment while preserving bottom-follow behavior and clearing culled cached output.

Validation: bun run build; bun run smoke; ANTHROPIC_API_KEY=test-key bun run check; ANTHROPIC_API_KEY=test-key bun run test:full; python -m pytest -q python/tests; bun run security:pr-scan -- --base upstream/main.

* Stabilize cooldown smoke test

Use usage-bearing high-context fixtures in autoCompactCooldown tests so the cooldown assertions do not depend on process-global threshold overrides surviving full-suite order. Add CodeRabbit-requested SAST suppression comments for snip regex literals.

* Use rule-id semgrep suppressions

Update the snip regex suppressions to CodeRabbit's requested nosemgrep rule-id form, with the explanatory text kept in a separate comment.

* Pin cooldown test context window

Set and restore CLAUDE_CODE_AUTO_COMPACT_WINDOW in autoCompactCooldown tests so the high-context fixture lands above the auto-compact threshold but below the hard prompt limit on both local Windows and Linux CI.

* Honor autocompact breaker metadata

Block oversized requests when autocompact reports an active or tripped breaker, even if a later auto-compact config read is stale. This keeps cooldown protection active and stabilizes the CI smoke path.
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jun 16, 2026
Cherry-picked from upstream 9c74231. Replace visible snip ID tags
with internal <system-reminder>snip_id=...</system-reminder> metadata
and update SnipTool guidance/tests so the model can request pruning
without echoing user-visible IDs.

Adds compatibility parsing for legacy [id:...] markers, clarifies
synthetic OpenAI shim tool-result messages, tightens test cleanup
around env/session state.

Mitigates Konsole+tmux rendering corruption by disabling the scroll
fast path while preserving bottom-follow behavior and clearing culled
cached output.

OC-specific changes (upstream HEAD files ported verbatim):
- src/utils/messages.ts: full UP HEAD replacement
- src/utils/sessionStorage.test.ts: full UP HEAD replacement
- src/utils/messages.snipTag.test.ts: new file from UP

OC-specific stubs:
- src/utils/sessionStorage.ts: NO-OP recordGoalState stub (OC lacks
  Project.insertGoalState + GoalStateEntry — pending port of PR Twigpine#1293
  session-scoped /goal continuation)
- src/services/api/errors.ts: getVisionNotSupportedErrorMessages +
  getVisionNotSupportedErrorMessage + VISION_NOT_SUPPORTED_MESSAGE_PREFIX
- src/utils/permissions/PermissionMode.ts: isDangerousPermissionMode
  (OC uses 'bypassPermissions' only, not 'fullAccess')

Includes 8 new tests in messages.snipTag.test.ts. 4 goal-related
sessionStorage tests fail (stubbed out, see above).

Also includes UP autoCompactCooldown test changes (1 test fails due
to global fixture ordering — pre-existing flakiness, not port regression).
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.

Garbled text and broken layout in Konsole + tmux since 0.17.1 The interface is so broken...

2 participants