Skip to content

Feature/docker/run#1268

Merged
claude-code-best merged 12 commits into
mainfrom
feature/docker/run
Jun 11, 2026
Merged

Feature/docker/run#1268
claude-code-best merged 12 commits into
mainfrom
feature/docker/run

Conversation

@claude-code-best

@claude-code-best claude-code-best commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added goal elapsed-time indicator pill in the footer showing current goal progress and status color.
  • Bug Fixes

    • Clarified invalid tool-input error messages for tool calls.
  • Chores

    • General type-safety and robustness improvements across streaming, state, and UI wiring.
    • Expanded whitelist of environment variables for model/provider configuration.
    • Limited auto-dream consolidation to a maximum number of turns.
    • Added a non-functional goal state stub to support future goal UI.
  • Tests

    • Updated provider-selection and environment-handling tests.

- API 兼容层(openai/grok/gemini): 利用 BetaRawMessageStreamEvent 的
  discriminated union 在 switch/case 中直接属性访问,消除 ~29 个 as any
- ConsoleOAuthFlow: 用 as unknown as Parameters<typeof> 替代 as any
- performanceShim: 用 Record<string, unknown> 和显式类型断言替代 as any
- companionReact/auth: 直接访问已有类型属性消除 as any
- sliceAnsi/textHighlighting: 用 as Char 替代 as any(Token 联合类型收窄)
- ccrClient: 利用 RequestResult 类型收窄直接访问 retryAfterMs
- outputsScanner: 用 TurnStartTime.turnStartTime 属性访问替代双重断言
- plans: 用显式数组类型替代 as any[]
- FeedbackSurvey: 用 in 操作符和 Parameters<typeof> 替代 as any
- messageQueueManager: 用 Record<string, unknown> 替代 as any
- mcp.ts: 用 in 操作符类型守卫替代 as any

precheck 通过: typecheck 零错误 + 5420 测试全部通过 + lint 通过
- AppStateStore: 添加 pipeIpc?: PipeIpcState 可选字段
- PromptInputFooter: 直接访问 s.pipeIpc
- useBackgroundTaskNavigation: 直接访问 s.pipeIpc
- usePipeRouter: 直接访问 store.getState().pipeIpc
- REPL.tsx: 移除 getPipeIpc(s as any) 中的 as any

precheck 通过
Ink Key 类型已包含 wheelDown/wheelUp 属性,直接访问即可。
- toolUse.name: 使用 as unknown as { name: string } 双重断言
- apiErr.error: 使用 as Parameters<typeof formatAPIError>[0] 类型参数
项目级 settings.local.json 的 env 字段在 trust dialog 之前只有
SAFE_ENV_VARS 白名单中的变量会被应用到 process.env。
OPENAI_API_KEY、OPENAI_BASE_URL 等关键变量不在白名单中,
导致容器中通过 settings.local.json 配置 OpenAI 协议时认证失败。
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d18b1905-8ae8-41e7-8ef3-c11db33de9fb

📥 Commits

Reviewing files that changed from the base of the PR and between 551a62a and 0bc1326.

📒 Files selected for processing (2)
  • src/components/PromptInput/PromptInputFooterLeftSide.tsx
  • src/services/goal/goalState.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/PromptInput/PromptInputFooterLeftSide.tsx

📝 Walkthrough

Walkthrough

Tightens TypeScript typing across streaming adapters and utilities, adds optional Pipe IPC to AppState, introduces a periodic goal elapsed footer indicator, expands the SAFE_ENV_VARS allowlist for OpenAI/Grok/Gemini, and limits auto-dream consolidation to 20 turns.

Changes

Type Safety and Platform Support

Layer / File(s) Summary
Pipe IPC state integration
src/state/AppStateStore.ts, src/components/PromptInput/PromptInputFooter.tsx, src/hooks/useBackgroundTaskNavigation.ts, src/hooks/usePipeRouter.ts, src/screens/REPL.tsx
Adds optional pipeIpc?: PipeIpcState to AppState and updates selectors/hooks/components to access it via typed properties instead of any casts.
API streaming type safety
src/services/api/gemini/index.ts, src/services/api/grok/index.ts, src/services/api/openai/index.ts
Imports BetaMessage/BetaUsage, tightens streaming accumulators from any to concrete shapes, replaces untyped event casts with explicit event-field access, and normalizes final content via BetaMessage['content'] casts.
Utility and component type refinements
src/buddy/companionReact.ts, src/cli/transports/ccrClient.ts, src/components/ConsoleOAuthFlow.tsx, src/components/FeedbackSurvey/useFrustrationDetection.ts, src/components/ultraplan/UltraplanChoiceDialog.tsx, src/entrypoints/mcp.ts, src/utils/auth.ts, src/utils/filePersistence/outputsScanner.ts, src/utils/messageQueueManager.ts, src/utils/performanceShim.ts, src/utils/plans.ts, src/utils/sideQuestion.ts, src/utils/sliceAnsi.ts, src/utils/textHighlighting.ts
Removes any casts and applies specific type assertions: message content optional chaining, retry-after field access, OAuth payload typing, API-error detection check, input key properties, validation message stringification, explicit modelType reads, fs.readdir result typing, KAIROS origin checks, performance shim casts, snapshot file typing, and ANSI Char typing.
Goal indicator and environment configuration
src/components/PromptInput/PromptInputFooterLeftSide.tsx, src/utils/managedEnvConstants.ts, src/services/autoDream/autoDream.ts, src/services/goal/goalState.ts
Adds GoalElapsedIndicator with interval refresh and status coloring; conditionally renders it when GOAL is enabled; expands SAFE_ENV_VARS to whitelist OpenAI/Grok/Gemini credentials/config and provider flags; sets maxTurns: 20 for auto-dream consolidation.
Hermetic provider tests
src/utils/model/__tests__/providers.test.ts
Inlines test-local provider selection and base-URL allowlist helpers, expands env-handling in tests, and adds assertions for new provider env flags and truthiness cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

I’m a rabbit tightening types today, 🐇
Swapping any for fields that stay,
Streams speak BetaMessage clear and neat,
Goals tick on the footer’s steady beat,
Env flags set and dreams run fewer turns.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Feature/docker/run' does not clearly describe the actual changes in this PR, which involve type safety improvements and environment variable whitelisting across multiple files. Replace with a descriptive title that captures the main change, such as 'Remove unsafe type casts and improve type safety throughout codebase' or 'Add type-safe field access and expand environment variable whitelisting'.
Docstring Coverage ⚠️ Warning Docstring coverage is 48.28% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/docker/run

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.

@mintlify

mintlify Bot commented Jun 11, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ccb-863780bf 🟢 Ready View Preview Jun 11, 2026, 7:31 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
src/components/PromptInput/PromptInputFooter.tsx (1)

278-281: ⚠️ Potential issue | 🟡 Minor

Type setAppState updaters in PromptInputFooter and remove the {} pipeIpc fallback

  • In src/components/PromptInput/PromptInputFooter.tsx, the three setAppState((prev: any) => { ... }) updaters (routeMode at ~278-281, selectedPipes toggle at ~317-322, selectorOpen close at ~325-328) should use (prev: AppState) to match useSetAppState’s (prev: AppState) => AppState signature.
  • Replace const pIpc = prev.pipeIpc ?? {} with const pIpc = getPipeIpc(prev) (import getPipeIpc from src/utils/pipeTransport.ts alongside the existing pipeTransport imports). PipeIpcState has only required fields, so spreading {} is type-unsound and can produce an incomplete pipeIpc state if pipeIpc is ever missing at update time.
🤖 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/components/PromptInput/PromptInputFooter.tsx` around lines 278 - 281,
Update the three setAppState updaters in PromptInputFooter to type their prev
parameter as (prev: AppState) instead of any and replace the unsafe fallback
const pIpc = prev.pipeIpc ?? {} with const pIpc = getPipeIpc(prev); import
getPipeIpc from src/utils/pipeTransport.ts alongside the existing pipeTransport
imports so you always obtain a complete PipeIpcState; ensure this change is
applied to the updaters that set routeMode, toggle selectedPipes, and close
selectorOpen so the returned AppState conforms to (prev: AppState) => AppState.
🧹 Nitpick comments (3)
src/hooks/usePipeRouter.ts (1)

11-12: ⚡ Quick win

Replace any in type aliases with proper imported types.

The StoreApi and SetAppState type aliases use any for their return and parameter types. Since this file has access to AppState from ../state/AppState.js, consider importing and using the proper types (e.g., AppStateStore type if exported, or properly typing the state parameter as AppState).

This would complete the type safety improvements started at line 40 and align with the PR's objective to eliminate broad any usage.

♻️ Suggested refactor
+import type { AppState } from '../state/AppState.js'
+
-type StoreApi = { getState: () => any }
-type SetAppState = (updater: (prev: any) => any) => void
+type StoreApi = { getState: () => AppState }
+type SetAppState = (updater: (prev: AppState) => AppState) => void

Then update line 89:

-      setAppState((prev: any) => {
+      setAppState((prev: AppState) => {
🤖 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/hooks/usePipeRouter.ts` around lines 11 - 12, Replace the broad any
usages in the type aliases StoreApi and SetAppState by importing and using the
concrete AppState types from ../state/AppState.js (or the exported store type if
available): change StoreApi.getState to return AppState (or AppStateStore) and
change SetAppState to accept an updater whose prev param is typed as AppState;
update the import to bring in AppState (or AppStateStore) and then adjust the
usages of StoreApi and SetAppState (e.g., in the usePipeRouter hook and the
updater passed at the location currently around the updater call) to use these
concrete types.
src/utils/messageQueueManager.ts (1)

371-373: ⚡ Quick win

Remove redundant optional chaining.

The optional chaining ?.kind on line 373 is unnecessary because line 371 already guarantees that origin !== undefined. After confirming origin exists, you can use direct property access.

♻️ Simplified access without optional chaining
   if (
     (feature('KAIROS') || feature('KAIROS_CHANNELS')) &&
     (cmd as Record<string, unknown>).origin !== undefined &&
-    ((cmd as Record<string, unknown>).origin as Record<string, unknown>)
-      ?.kind === 'channel'
+    ((cmd as Record<string, unknown>).origin as Record<string, unknown>)
+      .kind === 'channel'
   )
🤖 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/messageQueueManager.ts` around lines 371 - 373, The conditional
redundantly uses optional chaining on origin's kind; since the earlier check
ensures (cmd as Record<string, unknown>).origin !== undefined, update the
expression in messageQueueManager.ts to access origin.kind directly (remove the
?. from ?.kind) so the condition becomes a direct property comparison
(referencing the same cast of cmd and the origin object used in the current
conditional).
src/utils/filePersistence/outputsScanner.ts (1)

67-74: ⚡ Quick win

Simplify the type annotation by removing the redundant union.

The union type at lines 67-69 is immediately cast away at line 74. Since the cast is necessary anyway (to account for Node version differences in the fs.readdir return type), the union adds no value and makes the code harder to read.

♻️ Simplified type annotation
- let entries:
-   | Awaited<ReturnType<typeof fs.readdir>>
-   | { name: string; isFile(): boolean; isSymbolicLink(): boolean }[]
  try {
-   entries = (await fs.readdir(outputsDir, {
+   const entries = (await fs.readdir(outputsDir, {
      withFileTypes: true,
      recursive: true,
    })) as { name: string; isFile(): boolean; isSymbolicLink(): boolean }[]
🤖 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/filePersistence/outputsScanner.ts` around lines 67 - 74, The
declared variable entries uses an unnecessary union type then immediately casts
the result of fs.readdir to one branch; remove the redundant union and declare
entries with the single target type used in the cast (e.g. the array of
Dirent-like objects), so set entries to the same type you cast to and keep the
await fs.readdir(...) as that type; update references to entries accordingly
(symbols: entries, fs.readdir, outputsDir).
🤖 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/components/PromptInput/PromptInputFooterLeftSide.tsx`:
- Line 178: The color prop is incorrectly asserted to the literal 'ansi:green';
update the return in PromptInputFooterLeftSide to assert color as keyof Theme
(i.e., use color as keyof Theme) instead of 'ansi:green', and if Theme is not
already imported add Theme to the imports from '`@anthropic/ink`'; ensure the Text
component uses color={color as keyof Theme} so the union type ('ansi:green' |
'ansi:yellow' | 'ansi:red' | 'ansi:cyan' | undefined) is correctly typed.
- Around line 140-141: The conditional require for getGoal/getActiveElapsedMs is
being executed inside the component on every render; move that conditional
require to the top-level of the module (following the same pattern used for
coordinatorModule and proactiveModule) so it only runs once at load time, export
or keep the resulting binding in a top-level const (e.g., const { getGoal,
getActiveElapsedMs } = require(...) as typeof import(...);) and update the
component to use those top-level symbols instead of calling require on each
tick.
- Around line 140-142: The require call for ../../services/goal/goalState.js
used to import getGoal and getActiveElapsedMs in PromptInputFooterLeftSide.tsx
is pointing to a non-existent module and will throw MODULE_NOT_FOUND when GOAL
is enabled; fix it by either adding a new module that exports getGoal and
getActiveElapsedMs (matching the expected signatures) under
src/services/goal/goalState.{ts,js} or change the require/import to the correct
existing module that implements those functions (update the require in
PromptInputFooterLeftSide.tsx where getGoal and getActiveElapsedMs are
referenced). Ensure the exported names exactly match getGoal and
getActiveElapsedMs so the current usage continues to work.

In `@src/utils/managedEnvConstants.ts`:
- Around line 166-168: The change incorrectly adds sensitive provider
credentials and endpoints into SAFE_ENV_VARS, contradicting the module's own
security model; update the fix by removing OPENAI_API_KEY, OPENAI_BASE_URL,
GROK_API_KEY, GROK_BASE_URL, XAI_API_KEY, GEMINI_API_KEY, and GEMINI_BASE_URL
from the SAFE_ENV_VARS constant (and any duplicated additions elsewhere around
the file) so they remain classified as dangerous, or alternatively keep them in
SAFE_ENV_VARS only after updating the module documentation to explicitly justify
why third‑party API keys/base URLs are exempt from the trust dialog; locate and
modify the SAFE_ENV_VARS definition and accompanying documentation comments to
ensure consistency between the constant and the security docs.

---

Outside diff comments:
In `@src/components/PromptInput/PromptInputFooter.tsx`:
- Around line 278-281: Update the three setAppState updaters in
PromptInputFooter to type their prev parameter as (prev: AppState) instead of
any and replace the unsafe fallback const pIpc = prev.pipeIpc ?? {} with const
pIpc = getPipeIpc(prev); import getPipeIpc from src/utils/pipeTransport.ts
alongside the existing pipeTransport imports so you always obtain a complete
PipeIpcState; ensure this change is applied to the updaters that set routeMode,
toggle selectedPipes, and close selectorOpen so the returned AppState conforms
to (prev: AppState) => AppState.

---

Nitpick comments:
In `@src/hooks/usePipeRouter.ts`:
- Around line 11-12: Replace the broad any usages in the type aliases StoreApi
and SetAppState by importing and using the concrete AppState types from
../state/AppState.js (or the exported store type if available): change
StoreApi.getState to return AppState (or AppStateStore) and change SetAppState
to accept an updater whose prev param is typed as AppState; update the import to
bring in AppState (or AppStateStore) and then adjust the usages of StoreApi and
SetAppState (e.g., in the usePipeRouter hook and the updater passed at the
location currently around the updater call) to use these concrete types.

In `@src/utils/filePersistence/outputsScanner.ts`:
- Around line 67-74: The declared variable entries uses an unnecessary union
type then immediately casts the result of fs.readdir to one branch; remove the
redundant union and declare entries with the single target type used in the cast
(e.g. the array of Dirent-like objects), so set entries to the same type you
cast to and keep the await fs.readdir(...) as that type; update references to
entries accordingly (symbols: entries, fs.readdir, outputsDir).

In `@src/utils/messageQueueManager.ts`:
- Around line 371-373: The conditional redundantly uses optional chaining on
origin's kind; since the earlier check ensures (cmd as Record<string,
unknown>).origin !== undefined, update the expression in messageQueueManager.ts
to access origin.kind directly (remove the ?. from ?.kind) so the condition
becomes a direct property comparison (referencing the same cast of cmd and the
origin object used in the current conditional).
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8e957fb-c975-4231-b3a7-2b40a1ccb00d

📥 Commits

Reviewing files that changed from the base of the PR and between 83e891d and 7b209ed.

📒 Files selected for processing (33)
  • dist-nosplit/cli.js
  • dist-nosplit/vendor/audio-capture/arm64-darwin/audio-capture.node
  • dist-nosplit/vendor/audio-capture/arm64-linux/audio-capture.node
  • dist-nosplit/vendor/audio-capture/arm64-win32/audio-capture.node
  • dist-nosplit/vendor/audio-capture/x64-darwin/audio-capture.node
  • dist-nosplit/vendor/audio-capture/x64-linux/audio-capture.node
  • dist-nosplit/vendor/audio-capture/x64-win32/audio-capture.node
  • dist-nosplit/vendor/ripgrep/arm64-linux/rg
  • src/buddy/companionReact.ts
  • src/cli/transports/ccrClient.ts
  • src/components/ConsoleOAuthFlow.tsx
  • src/components/FeedbackSurvey/useFrustrationDetection.ts
  • src/components/PromptInput/PromptInputFooter.tsx
  • src/components/PromptInput/PromptInputFooterLeftSide.tsx
  • src/components/ultraplan/UltraplanChoiceDialog.tsx
  • src/entrypoints/mcp.ts
  • src/hooks/useBackgroundTaskNavigation.ts
  • src/hooks/usePipeRouter.ts
  • src/screens/REPL.tsx
  • src/services/api/gemini/index.ts
  • src/services/api/grok/index.ts
  • src/services/api/openai/index.ts
  • src/services/autoDream/autoDream.ts
  • src/state/AppStateStore.ts
  • src/utils/auth.ts
  • src/utils/filePersistence/outputsScanner.ts
  • src/utils/managedEnvConstants.ts
  • src/utils/messageQueueManager.ts
  • src/utils/performanceShim.ts
  • src/utils/plans.ts
  • src/utils/sideQuestion.ts
  • src/utils/sliceAnsi.ts
  • src/utils/textHighlighting.ts

Comment on lines +140 to +141
const { getGoal, getActiveElapsedMs } =
require('../../services/goal/goalState.js') as typeof import('../../services/goal/goalState.js');

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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Move conditional require() to top-level for consistency and efficiency.

The require() call inside the component body runs on every render (every second due to the tick interval). The existing pattern in this file (lines 5-7 for coordinatorModule, lines 51 for proactiveModule) conditionally requires modules at the top level, which evaluates once at module load time.

♻️ Move to top-level conditional require pattern

At the top of the file (after line 52):

 const proactiveModule = feature('PROACTIVE') || feature('KAIROS') ? require('../../proactive/index.js') : null;
 /* eslint-enable `@typescript-eslint/no-require-imports` */
+/* eslint-disable `@typescript-eslint/no-require-imports` */
+const goalModule = feature('GOAL')
+  ? (require('../../services/goal/goalState.js') as typeof import('../../services/goal/goalState.js'))
+  : undefined;
+/* eslint-enable `@typescript-eslint/no-require-imports` */
 const NO_OP_SUBSCRIBE = (_cb: () => void) => () => {};

Then in the component (lines 140-142):

-  const { getGoal, getActiveElapsedMs } =
-    require('../../services/goal/goalState.js') as typeof import('../../services/goal/goalState.js');
-  const goal = getGoal();
+  if (!goalModule) return null;
+  const goal = goalModule.getGoal();
   if (!goal) return null;
 
-  const elapsedMs = getActiveElapsedMs(goal);
+  const elapsedMs = goalModule.getActiveElapsedMs(goal);

And replace the condition at line 432:

-    ...(feature('GOAL') &&
-    (require('../../services/goal/goalState.js') as typeof import('../../services/goal/goalState.js')).getGoal()
+    ...(feature('GOAL') && goalModule?.getGoal()
       ? [<GoalElapsedIndicator key="goal-elapsed" />]
       : []),
🧰 Tools
🪛 GitHub Actions: CI / 0_ci.txt

[error] 141-141: TypeScript (tsc --noEmit) TS2307: Cannot find module '../../services/goal/goalState.js' or its corresponding type declarations.

🪛 GitHub Actions: CI / ci

[error] 141-141: TypeScript (tsc --noEmit) failed: TS2307 Cannot find module '../../services/goal/goalState.js' or its corresponding type declarations.

🤖 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/components/PromptInput/PromptInputFooterLeftSide.tsx` around lines 140 -
141, The conditional require for getGoal/getActiveElapsedMs is being executed
inside the component on every render; move that conditional require to the
top-level of the module (following the same pattern used for coordinatorModule
and proactiveModule) so it only runs once at load time, export or keep the
resulting binding in a top-level const (e.g., const { getGoal,
getActiveElapsedMs } = require(...) as typeof import(...);) and update the
component to use those top-level symbols instead of calling require on each
tick.

Comment thread src/components/PromptInput/PromptInputFooterLeftSide.tsx Outdated
break;
}

return <Text color={color as 'ansi:green'}>goal ({timeStr})</Text>;

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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use as keyof Theme instead of as 'ansi:green' for Ink color prop.

The color variable can be 'ansi:green' | 'ansi:yellow' | 'ansi:red' | 'ansi:cyan' | undefined, but the type assertion forces it to 'ansi:green'. According to coding guidelines for Ink color prop, use as keyof Theme. As per coding guidelines, "Ink color prop must use as keyof Theme rather than as any".

♻️ Fix type assertion
-  return <Text color={color as 'ansi:green'}>goal ({timeStr})</Text>;
+  return <Text color={color as keyof Theme}>goal ({timeStr})</Text>;

If Theme is not imported, add it to the imports from @anthropic/ink:

-import { Box, Text, Link } from '`@anthropic/ink`';
+import { Box, Text, Link, type Theme } from '`@anthropic/ink`';
📝 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.

Suggested change
return <Text color={color as 'ansi:green'}>goal ({timeStr})</Text>;
return <Text color={color as keyof Theme}>goal ({timeStr})</Text>;
🤖 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/components/PromptInput/PromptInputFooterLeftSide.tsx` at line 178, The
color prop is incorrectly asserted to the literal 'ansi:green'; update the
return in PromptInputFooterLeftSide to assert color as keyof Theme (i.e., use
color as keyof Theme) instead of 'ansi:green', and if Theme is not already
imported add Theme to the imports from '`@anthropic/ink`'; ensure the Text
component uses color={color as keyof Theme} so the union type ('ansi:green' |
'ansi:yellow' | 'ansi:red' | 'ansi:cyan' | undefined) is correctly typed.

Source: Coding guidelines

Comment on lines +166 to +168
'OPENAI_API_KEY',
'OPENAI_AUTH_MODE',
'OPENAI_BASE_URL',

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.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Security policy violation: API keys and base URLs marked as safe contradict the security model.

The file's own documentation (lines 134-146) explicitly classifies base URLs and API keys as dangerous:

  • "REDIRECT TO ATTACKER-CONTROLLED SERVER" includes base URLs
  • "SWITCH TO ATTACKER-CONTROLLED PROJECT" includes API keys

Yet this change adds OPENAI_API_KEY, OPENAI_BASE_URL, GROK_API_KEY, GROK_BASE_URL, XAI_API_KEY, GEMINI_API_KEY, and GEMINI_BASE_URL to SAFE_ENV_VARS, which bypasses the trust dialog. An attacker controlling remote managed settings can now:

  1. Set OPENAI_BASE_URL to redirect OpenAI traffic to their server
  2. Set OPENAI_API_KEY to bill usage to their account and exfiltrate prompts
  3. Same for Grok/Gemini providers

This is the exact threat model the trust dialog was designed to prevent. Either these variables must remain dangerous (removed from SAFE_ENV_VARS), or the security documentation must be updated to explain why third-party provider credentials are exempt from the threat model that applies to Anthropic credentials.

Also applies to: 188-189, 195-195, 225-226

🤖 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/managedEnvConstants.ts` around lines 166 - 168, The change
incorrectly adds sensitive provider credentials and endpoints into
SAFE_ENV_VARS, contradicting the module's own security model; update the fix by
removing OPENAI_API_KEY, OPENAI_BASE_URL, GROK_API_KEY, GROK_BASE_URL,
XAI_API_KEY, GEMINI_API_KEY, and GEMINI_BASE_URL from the SAFE_ENV_VARS constant
(and any duplicated additions elsewhere around the file) so they remain
classified as dangerous, or alternatively keep them in SAFE_ENV_VARS only after
updating the module documentation to explicitly justify why third‑party API
keys/base URLs are exempt from the trust dialog; locate and modify the
SAFE_ENV_VARS definition and accompanying documentation comments to ensure
consistency between the constant and the security docs.

@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

🧹 Nitpick comments (1)
src/utils/model/__tests__/providers.test.ts (1)

71-79: ⚡ Quick win

Consider adding cross-tier precedence tests.

The new OpenAI and Grok tests verify provider selection when their respective env vars are set, but there are no tests verifying that first-tier providers (bedrock/vertex/foundry) take precedence over second-tier providers (openai/grok/gemini) when both are set simultaneously. For example:

test('bedrock takes precedence over openai', () => {
  process.env.CLAUDE_CODE_USE_BEDROCK = '1'
  process.env.CLAUDE_CODE_USE_OPENAI = '1'
  expect(getAPIProvider({})).toBe('bedrock')
})

This would validate the precedence ordering from the implementation.

🤖 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/model/__tests__/providers.test.ts` around lines 71 - 79, Add tests
that assert first-tier provider env vars (CLAUDE_CODE_USE_BEDROCK,
CLAUDE_CODE_USE_VERTEX, CLAUDE_CODE_USE_FOUNDRY) take precedence over
second-tier vars (CLAUDE_CODE_USE_OPENAI, CLAUDE_CODE_USE_GROK,
CLAUDE_CODE_USE_GEMINI) when both are set; update
src/utils/model/__tests__/providers.test.ts to include cases like calling
getAPIProvider({}) with both env vars set and expecting
'bedrock'/'vertex'/'foundry' respectively, and ensure each test clears or resets
other related env vars after running to avoid cross-test pollution.
🤖 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/model/__tests__/providers.test.ts`:
- Line 2: The test import uses a relative path for isEnvTruthy; update the
import in src/utils/model/__tests__/providers.test.ts to use the project alias
(src/*) instead of '../../envUtils.js' so it imports isEnvTruthy from the
aliased module (e.g., import { isEnvTruthy } from 'src/utils/envUtils' or the
correct aliased path used in the repo), ensuring the test references the same
exported symbol name isEnvTruthy.

---

Nitpick comments:
In `@src/utils/model/__tests__/providers.test.ts`:
- Around line 71-79: Add tests that assert first-tier provider env vars
(CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, CLAUDE_CODE_USE_FOUNDRY) take
precedence over second-tier vars (CLAUDE_CODE_USE_OPENAI, CLAUDE_CODE_USE_GROK,
CLAUDE_CODE_USE_GEMINI) when both are set; update
src/utils/model/__tests__/providers.test.ts to include cases like calling
getAPIProvider({}) with both env vars set and expecting
'bedrock'/'vertex'/'foundry' respectively, and ensure each test clears or resets
other related env vars after running to avoid cross-test pollution.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dac4698-1599-466c-a09c-2fea12e913d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6942f53 and 2a1f569.

📒 Files selected for processing (1)
  • src/utils/model/__tests__/providers.test.ts

Comment thread src/utils/model/__tests__/providers.test.ts Outdated
测试不再 import providers.ts(其默认参数触发 getInitialSettings 全链),
改为内联纯函数逻辑,从根源消除 CI 上其他测试 mock.module 污染。

@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

🧹 Nitpick comments (1)
src/utils/model/__tests__/providers.test.ts (1)

171-184: ⚡ Quick win

Consider adding test coverage for full truthy value range.

Once the isEnvTruthy logic is inlined, consider adding tests for the complete set of supported formats:

  • 'yes' and 'on'
  • Case variations: 'TRUE', 'True', 'YES', 'On'
  • Trimmed values: ' true ', ' 1 '

This would ensure production behavior for all supported env var formats is validated.

🤖 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/model/__tests__/providers.test.ts` around lines 171 - 184, Add unit
tests for getAPIProviderTest to cover the full range of env-var truthy formats
supported by isEnvTruthy: add cases setting process.env.CLAUDE_CODE_USE_BEDROCK
to 'yes' and 'on', uppercase/lowercase variants like 'TRUE', 'True', 'YES',
'On', numeric '1', and trimmed values like ' true ' and ' 1 ' to assert they
return 'bedrock', plus negative examples ('false','off','0','') to assert
'firstParty'; place these new cases alongside the existing tests in
providers.test.ts referencing getAPIProviderTest so the inlined isEnvTruthy
behavior is fully validated.
🤖 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/model/__tests__/providers.test.ts`:
- Around line 23-62: getAPIProviderTest currently only treats env values equal
to '1' or 'true' as truthy, causing tests to diverge from production; update
getAPIProviderTest to use the same truthiness logic as isEnvTruthy
(case-insensitive, trimmed match for '1', 'true', 'yes', 'on') or call
isEnvTruthy directly, and apply it for CLAUDE_CODE_USE_BEDROCK,
CLAUDE_CODE_USE_VERTEX, CLAUDE_CODE_USE_FOUNDRY, CLAUDE_CODE_USE_OPENAI,
CLAUDE_CODE_USE_GEMINI, and CLAUDE_CODE_USE_GROK so values like 'yes', 'TRUE',
or ' true ' return the expected provider instead of 'firstParty'.

---

Nitpick comments:
In `@src/utils/model/__tests__/providers.test.ts`:
- Around line 171-184: Add unit tests for getAPIProviderTest to cover the full
range of env-var truthy formats supported by isEnvTruthy: add cases setting
process.env.CLAUDE_CODE_USE_BEDROCK to 'yes' and 'on', uppercase/lowercase
variants like 'TRUE', 'True', 'YES', 'On', numeric '1', and trimmed values like
' true ' and ' 1 ' to assert they return 'bedrock', plus negative examples
('false','off','0','') to assert 'firstParty'; place these new cases alongside
the existing tests in providers.test.ts referencing getAPIProviderTest so the
inlined isEnvTruthy behavior is fully validated.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37a4be71-4a46-4bab-bd0d-18f8afb89eac

📥 Commits

Reviewing files that changed from the base of the PR and between 2a1f569 and 551a62a.

📒 Files selected for processing (1)
  • src/utils/model/__tests__/providers.test.ts

Comment on lines +23 to +62
function getAPIProviderTest(settings: { modelType?: string }): APIProvider {
const modelType = settings.modelType
if (modelType === 'openai') return 'openai'
if (modelType === 'gemini') return 'gemini'
if (modelType === 'grok') return 'grok'

if (
process.env.CLAUDE_CODE_USE_BEDROCK === '1' ||
process.env.CLAUDE_CODE_USE_BEDROCK === 'true'
)
return 'bedrock'
if (
process.env.CLAUDE_CODE_USE_VERTEX === '1' ||
process.env.CLAUDE_CODE_USE_VERTEX === 'true'
)
return 'vertex'
if (
process.env.CLAUDE_CODE_USE_FOUNDRY === '1' ||
process.env.CLAUDE_CODE_USE_FOUNDRY === 'true'
)
return 'foundry'

if (
process.env.CLAUDE_CODE_USE_OPENAI === '1' ||
process.env.CLAUDE_CODE_USE_OPENAI === 'true'
)
return 'openai'
if (
process.env.CLAUDE_CODE_USE_GEMINI === '1' ||
process.env.CLAUDE_CODE_USE_GEMINI === 'true'
)
return 'gemini'
if (
process.env.CLAUDE_CODE_USE_GROK === '1' ||
process.env.CLAUDE_CODE_USE_GROK === 'true'
)
return 'grok'

return 'firstParty'
}

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.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Incomplete truthiness logic diverges from production behavior.

The inlined getAPIProviderTest only checks for exact matches of '1' or 'true', but production's isEnvTruthy (Context snippet 3) accepts '1', 'true', 'yes', 'on' with case-insensitive, trimmed matching. This creates critical test gaps:

  • Setting CLAUDE_CODE_USE_BEDROCK='yes' in production returns 'bedrock', but the test would return 'firstParty'
  • Setting CLAUDE_CODE_USE_BEDROCK='TRUE' or ' true ' would similarly diverge

The tests won't catch bugs when users rely on these supported formats.

🔧 Proposed fix to inline full truthiness logic
+function isEnvTruthy(envVar: string | undefined): boolean {
+  if (!envVar) return false
+  const normalizedValue = envVar.toLowerCase().trim()
+  return ['1', 'true', 'yes', 'on'].includes(normalizedValue)
+}
+
 function getAPIProviderTest(settings: { modelType?: string }): APIProvider {
   const modelType = settings.modelType
   if (modelType === 'openai') return 'openai'
   if (modelType === 'gemini') return 'gemini'
   if (modelType === 'grok') return 'grok'
 
-  if (
-    process.env.CLAUDE_CODE_USE_BEDROCK === '1' ||
-    process.env.CLAUDE_CODE_USE_BEDROCK === 'true'
-  )
-    return 'bedrock'
-  if (
-    process.env.CLAUDE_CODE_USE_VERTEX === '1' ||
-    process.env.CLAUDE_CODE_USE_VERTEX === 'true'
-  )
-    return 'vertex'
-  if (
-    process.env.CLAUDE_CODE_USE_FOUNDRY === '1' ||
-    process.env.CLAUDE_CODE_USE_FOUNDRY === 'true'
-  )
-    return 'foundry'
-
-  if (
-    process.env.CLAUDE_CODE_USE_OPENAI === '1' ||
-    process.env.CLAUDE_CODE_USE_OPENAI === 'true'
-  )
-    return 'openai'
-  if (
-    process.env.CLAUDE_CODE_USE_GEMINI === '1' ||
-    process.env.CLAUDE_CODE_USE_GEMINI === 'true'
-  )
-    return 'gemini'
-  if (
-    process.env.CLAUDE_CODE_USE_GROK === '1' ||
-    process.env.CLAUDE_CODE_USE_GROK === 'true'
-  )
-    return 'grok'
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK)) return 'bedrock'
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX)) return 'vertex'
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY)) return 'foundry'
+
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_OPENAI)) return 'openai'
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI)) return 'gemini'
+  if (isEnvTruthy(process.env.CLAUDE_CODE_USE_GROK)) return 'grok'
 
   return 'firstParty'
 }
🤖 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/model/__tests__/providers.test.ts` around lines 23 - 62,
getAPIProviderTest currently only treats env values equal to '1' or 'true' as
truthy, causing tests to diverge from production; update getAPIProviderTest to
use the same truthiness logic as isEnvTruthy (case-insensitive, trimmed match
for '1', 'true', 'yes', 'on') or call isEnvTruthy directly, and apply it for
CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, CLAUDE_CODE_USE_FOUNDRY,
CLAUDE_CODE_USE_OPENAI, CLAUDE_CODE_USE_GEMINI, and CLAUDE_CODE_USE_GROK so
values like 'yes', 'TRUE', or ' true ' return the expected provider instead of
'firstParty'.

CI 中的 autonomy-lifecycle-user-flow 集成测试会执行 build.ts 打包 CLI。
此前 PromptInputFooterLeftSide.tsx 中 require('../../services/goal/goalState.js')
的路径在源码中不存在,打包器报 Could not resolve,导致 (unnamed) 测试失败。

新增 src/services/goal/goalState.ts 存根模块(getGoal 返回 null,组件不渲染),
让打包器在构建期可以解析该 require 路径。同时把 PromptInputFooterLeftSide.tsx
里两处 as unknown as 内联类型签名换成 as typeof import(...),让类型直接来自
存根模块,避免类型定义重复。
@claude-code-best claude-code-best merged commit e897385 into main Jun 11, 2026
6 of 7 checks passed
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.

1 participant