User
/spec-driven-develop src目录下是Claude Code项目的源码,我们现在需要在D:\code\play\stock_ai_rust\claude-code\books新建一 系 列的md文档来构建一个从0到1的完整的Claude Code源码教学指南以供研究者学习。books文 件 夹下文档的命令就是第x章节,xxx。这个教学我们计划是做成中英双语的
Assistant
<thinking> The user wants to execute the Spec-Driven Development workflow for creating a comprehensive Claude Code source code teaching guide. Let me follow the phases as defined.
First, let me check if docs/progress/MASTER.md already exists (cross-conversation continuity check).
The task is:
Source code is in the
srcdirectory (Claude Code project source)Create a series of MD documents in
D:\code\play\stock_ai_rust\claude-code\booksBuild a complete "from 0 to 1" Claude Code source code teaching guide
Documents named as chapters (第x章节,xxx)
Bilingual: Chinese and English
Now I need to check if MASTER.md exists and understand the project structure before starting Phase 0: Intent Recognition & Confirmation. </thinking>
我来启动 Spec-Driven Development 工作流。首先进行跨会话连续性检查,并了解项目结构。
Tool Call: Find D:\code\play\stock_ai_rust\claude-code docs/progress/MASTER.md Status: Completed
No files found
Tool Call: ls "D:/code/play/stock_ai_rust/claude-code/src/" 2>/dev/null | head -30 Status: Completed
Terminal:
QueryEngine.ts
Task.ts
Tool.ts
assistant
bootstrap
bridge
buddy
cli
commands
commands.ts
components
constants
context
context.ts
coordinator
cost-tracker.ts
costHook.ts
dialogLaunchers.tsx
entrypoints
history.ts
hooks
ink
ink.ts
interactiveHelpers.tsx
keybindings
main.tsx
memdir
migrations
moreright
native-tsTool Call: ls "D:/code/play/stock_ai_rust/claude-code/books/" 2>/dev/null || echo "books directory does not exist yet" Status: Completed
Terminal:
(Bash completed with no output)Tool Call: ls "D:/code/play/stock_ai_rust/claude-code/src/" 2>/dev/null Status: Completed
Terminal:
QueryEngine.ts
Task.ts
Tool.ts
assistant
bootstrap
bridge
buddy
cli
commands
commands.ts
components
constants
context
context.ts
coordinator
cost-tracker.ts
costHook.ts
dialogLaunchers.tsx
entrypoints
history.ts
hooks
ink
ink.ts
interactiveHelpers.tsx
keybindings
main.tsx
memdir
migrations
moreright
native-ts
outputStyles
plugins
projectOnboardingState.ts
query
query.ts
remote
replLauncher.tsx
schemas
screens
server
services
setup.ts
skills
state
tasks
tasks.ts
tools
tools.ts
types
upstreamproxy
utils
vim
voiceAssistant
MASTER.md 不存在,这是全新的任务。让我更深入地了解项目结构。
Tool Call: find "D:/code/play/stock_ai_rust/claude-code/src/" -type f -name ".ts" -o -name ".tsx" | wc -l Status: Completed
Terminal:
1884Tool Call: find "D:/code/play/stock_ai_rust/claude-code/src/" -maxdepth 1 -type f ( -name ".ts" -o -name ".tsx" ) | sort Status: Completed
Terminal:
D:/code/play/stock_ai_rust/claude-code/src/QueryEngine.ts
D:/code/play/stock_ai_rust/claude-code/src/Task.ts
D:/code/play/stock_ai_rust/claude-code/src/Tool.ts
D:/code/play/stock_ai_rust/claude-code/src/commands.ts
D:/code/play/stock_ai_rust/claude-code/src/context.ts
D:/code/play/stock_ai_rust/claude-code/src/cost-tracker.ts
D:/code/play/stock_ai_rust/claude-code/src/costHook.ts
D:/code/play/stock_ai_rust/claude-code/src/dialogLaunchers.tsx
D:/code/play/stock_ai_rust/claude-code/src/history.ts
D:/code/play/stock_ai_rust/claude-code/src/ink.ts
D:/code/play/stock_ai_rust/claude-code/src/interactiveHelpers.tsx
D:/code/play/stock_ai_rust/claude-code/src/main.tsx
D:/code/play/stock_ai_rust/claude-code/src/projectOnboardingState.ts
D:/code/play/stock_ai_rust/claude-code/src/query.ts
D:/code/play/stock_ai_rust/claude-code/src/replLauncher.tsx
D:/code/play/stock_ai_rust/claude-code/src/setup.ts
D:/code/play/stock_ai_rust/claude-code/src/tasks.ts
D:/code/play/stock_ai_rust/claude-code/src/tools.tsTool Call: for dir in "D:/code/play/stock_ai_rust/claude-code/src/"/; do echo "$(basename "$dir"): $(find "$dir" -type f ( -name '.ts' -o -name '*.tsx' ) | wc -l) files"; done Status: Completed
Terminal:
assistant: 1 files
bootstrap: 1 files
bridge: 31 files
buddy: 6 files
cli: 19 files
commands: 189 files
components: 389 files
constants: 21 files
context: 9 files
coordinator: 1 files
entrypoints: 8 files
hooks: 104 files
ink: 96 files
keybindings: 14 files
memdir: 8 files
migrations: 11 files
moreright: 1 files
native-ts: 4 files
outputStyles: 1 files
plugins: 2 files
query: 4 files
remote: 4 files
schemas: 1 files
screens: 3 files
server: 3 files
services: 130 files
skills: 20 files
state: 6 files
tasks: 12 files
tools: 184 files
types: 11 files
upstreamproxy: 2 files
utils: 564 files
vim: 5 files
voice: 1 filesAssistant
<thinking> This is a massive codebase with 1884 source files. Now I'm in Phase 0 - I need to understand the user's intent and ask clarifying questions before proceeding.
Let me analyze what we know:
- The source code is Claude Code's source (1884 files)
- User wants to create a teaching guide in
books/directory - Bilingual (Chinese + English)
- Chapter-based structure
I need to ask clarifying questions to confirm the scope and approach. Let me think about what to ask:
Scope: All modules or specific focus areas?
Target audience: Who is this for? Beginners, intermediate, advanced developers?
Depth: Architecture overview level or deep dive into implementation details?
Bilingual format: Separate files per language or mixed in single files?
Chapter organization: By module, by concept, or by learning progression?
These questions will help me understand the exact direction before I start analyzing the codebase and structuring the guide. </thinking>
好的,项目规模相当大 -- 1884 个源文件,分布在 40+ 个模块中。我现在进入 Phase 0: 意图确认。
Phase 0: 意图确认
我对你的需求的初步理解是:
基于 src/ 目录下的 Claude Code 源码,在 books/ 目录下创建一套系统化的、从零到一的源码教学指南,帮助研究者理解 Claude Code 的完整架构与实现。中英双语,按章节组织。
在正式推进之前,我需要确认几个关键问题:
1. 双语格式
- 方案 A:每章一个文件,中英文上下排列(如中文段落后紧跟英文段落)
- 方案 B:每章两个文件,如
第1章-概述.md+Chapter-01-Overview.md - 方案 C:其他你偏好的格式?
2. 目标读者
- 是面向有经验的开发者(熟悉 TypeScript、CLI 工具开发)?
- 还是需要从更基础的层面讲起?
- 研究者主要关心什么 -- 架构设计思想、具体实现细节、还是两者兼顾?
3. 章节深度与覆盖范围
- 是否需要覆盖所有 40+ 个模块,还是聚焦核心模块(如 tools、commands、services、hooks 等关键部分)?
- 每章预期的篇幅大概是什么量级?(比如每章 2000-5000 字,还是更详尽的 10000+ 字?)
4. 章节组织逻辑
- 按"学习路径"组织(从入口到深入,循序渐进)?
- 按"模块划分"组织(每个模块独立一章)?
- 还是按"概念主题"组织(如"工具系统"、"权限模型"、"上下文管理"等)?
5. 代码示例
- 教学中是否需要大量引用源码片段并逐行讲解?
- 还是更侧重于架构图、流程图配合概念性说明?
请告诉我你的偏好,确认后我立刻进入深度分析阶段。
User
- B;2.是面向有经验的开发者,两者兼顾;3. 完整覆盖但是核心详细写,非核心简写;4. 按"学习路径"组织;5. 需要大量引用源码片段并逐行讲解
Assistant
<thinking> The user has confirmed their preferences. Let me summarize:
- Bilingual format: Plan B - separate files per language (e.g.,
第1章-概述.md+Chapter-01-Overview.md) - Target audience: Experienced developers, covering both architecture design and implementation details
- Coverage: Complete coverage, core modules detailed, non-core modules brief
- Organization: Learning path progression
- Code examples: Heavy source code quoting with line-by-line explanation
Now I have a clear task definition. Let me confirm this back to the user and then proceed to Phase 1: Deep Project Analysis.
I've got all the information I need from the user, so I'll move forward with a quick confirmation and then launch Phase 1 to start analyzing the codebase in depth. </thinking>
明确了。任务定义确认如下:
在 books/ 下创建 Claude Code 源码教学指南,每章中英双语各一文件,面向有经验开发者,按学习路径组织,核心模块深入讲解(大量源码引用),非核心模块精简覆盖。
现在进入 Phase 1: 深度项目分析。我将并行启动三个分析 Agent,分别从架构、模块清单、风险与模式三个维度剖析源码。
Tool Call: ToolSearch Status: Completed
Tool: TodoWrite
Assistant
现在并行启动三个分析 Agent。
Tool Call: 分析架构与技术栈 Status: Completed
Now I have a comprehensive picture of the entire codebase. Let me compile the structured analysis document.
Technology Stack
| 技术/工具 | 版本 / 说明 |
|---|---|
| TypeScript | 5.x (strict mode, 所有核心模块) |
| React | 19.x (含 React Compiler 输出,见 App.tsx 的 _c 编译产物) |
| Bun | 运行时 + 打包器 (bun:bundle feature flags 在全局使用) |
| Ink (自研分支) | 完整的 TUI 框架,位于 src/ink/,非 npm 包 |
| @anthropic-ai/sdk | Claude API 客户端,Beta Messages API |
| @modelcontextprotocol/sdk | MCP 服务器/客户端协议 |
| @commander-js/extra-typings | CLI 参数解析 |
| Zod v4 | 运行时类型校验与 Schema 定义 |
| lodash-es | 工具函数 (memoize, mergeWith, uniqBy 等) |
| OpenTelemetry | 遥测/追踪 (sdk-logs, sdk-metrics, sdk-trace-base) |
| GrowthBook | 功能开关与 A/B 测试 |
| chalk | 终端颜色输出 |
| Yoga (wasm) | Ink 布局引擎,CSS Flexbox 实现 (src/ink/layout/yoga.ts) |
Module Inventory
1. 启动与引导层 (Bootstrap Layer)
src/entrypoints/cli.tsx
- 责任:零依赖的快速路径分发器。在加载完整 CLI 之前处理
--version、--daemon-worker、bridge、daemon等特殊子命令,以最小化启动耗时。 - 公开接口:
async function main(): Promise<void> - 内部依赖:动态
import()所有子模块(设计意图是减少模块评估) - 复杂度:中 (大量 if/else 快速路径,但结构清晰)
- 约 250 行
src/entrypoints/init.ts
- 责任:应用核心初始化 — 配置系统启用、环境变量应用、mTLS、遥测初始化、LSP 管理器、策略限制加载。memoize 包裹确保只执行一次。
- 公开接口:
init(),initializeTelemetryAfterTrust() - 外部依赖:OpenTelemetry 系列(懒加载)
- 复杂度:高 (涉及大量异步初始化顺序,且有严格的安全时序要求 — 信任对话框前后分两阶段)
- 约 400 行
src/bootstrap/state.ts
- 责任:全局单例状态仓库。存储会话 ID、当前工作目录、模型配置、遥测计数器、OAuth token 等。模块顶部注释明确警告 "DO NOT ADD MORE STATE HERE"。
- 公开接口:数十个 getter/setter,如
getSessionId(),setCwd(),setInitialMainLoopModel() - 复杂度:高 (状态字段超过 80 个,是全系统最重要的隐式依赖)
- 约 350 行
src/main.tsx
- 责任:主 CLI 入口函数
main()。解析全部 Commander.js 参数,处理所有运行模式(交互式/headless/MCP服务/远程等),组装ToolUseContext,最终调用launchRepl()或runHeadless()。 - 复杂度:Critical (单文件约 4000+ 行,包含应用的全部启动逻辑)
2. 查询处理层 (Query Processing Layer)
src/query.ts
- 责任:
query()函数 — 核心 agentic 循环。异步生成器实现,驱动"发送消息 → 等待 API 响应 → 执行工具 → 追加结果 → 继续循环"的反复过程。处理自动压缩、最大 token 恢复、停止钩子。 - 公开接口:
async function* query(params: QueryParams),QueryParams类型 - 外部依赖:
@anthropic-ai/sdk - 内部依赖:
services/api/claude.ts,services/tools/toolOrchestration.ts,services/compact/,Tool.ts - 复杂度:Critical (无限循环 + 7 个 continue 路径 + 多个特性开关)
- 约 600 行
src/QueryEngine.ts
- 责任:面向 SDK/headless 用户的
query()高层封装。QueryEngine类持有会话状态(消息历史、权限拒绝记录、文件缓存),submitMessage()方法提供逐次提交接口,将内部StreamEvent映射为SDKMessage。 - 公开接口:
class QueryEngine { submitMessage(prompt): AsyncGenerator<SDKMessage> } - 复杂度:高 (处理 SDK 与 REPL 两种消费路径的语义差异)
- 约 500 行
src/services/api/claude.ts
- 责任:直接调用 Anthropic Beta Messages API。组装请求参数(工具定义、betas、缓存控制、thinking 配置),处理流式响应,归一化响应格式。支持 Bedrock、Vertex AI 等替代提供商。
- 复杂度:Critical (包含大量提供商分支逻辑、缓存 scope 管理、多重 beta 参数)
3. 工具系统 (Tool System)
src/Tool.ts
- 责任:工具系统的核心类型定义文件。定义
Tool<Input, Output>接口、ToolUseContext(工具执行的完整上下文依赖注入对象)、ToolPermissionContext、buildTool()工厂函数。 - 公开接口:
Tool接口、ToolUseContext类型、buildTool()、findToolByName()、getEmptyToolPermissionContext() - 复杂度:High (ToolUseContext 有约 40 个可选字段,是系统中最复杂的依赖注入结构)
- 约 550 行
src/tools.ts
- 责任:工具注册表。组装并导出
getTools()函数,根据feature()开关和USER_TYPE环境变量动态决定哪些工具被包含。 - 复杂度:中,约 200 行
src/tools/BashTool/ (15 个文件)
- 责任:执行 shell 命令。包含详尽的权限检查 (
bashPermissions.ts,约 2600 行)、安全验证、sed编辑解析、沙箱控制。 - 复杂度:Critical —
bashPermissions.ts独立超过 2600 行,处理通配符匹配、命令解析、speculative 分类器等
src/tools/AgentTool/ (12 个文件)
- 责任:启动递归子 agent。
runAgent.ts负责创建 fork 上下文、连接 MCP 服务器、调用query()循环,将结果作为工具结果返回父 agent。 - 复杂度:Critical (递归调用形成树状 agent 网络,共享
FileStateCache和ContentReplacementState)
其他重要工具目录:FileEditTool, FileReadTool, FileWriteTool, GlobTool, GrepTool, WebFetchTool, WebSearchTool, LSPTool, MCPTool,每个均遵循 buildTool() 工厂模式。
4. 状态管理层 (State Layer)
src/state/AppStateStore.ts + src/state/store.ts
- 责任:React UI 层的可观察状态。
AppState是一个深度不可变(DeepImmutable)的大型类型,涵盖设置、权限上下文、任务列表、MCP 连接、插件状态等。createStore()实现发布-订阅模式。 - 复杂度:高 (
AppState类型定义超过 200 行)
src/state/onChangeAppState.ts
- 责任:
AppState变化的副作用处理器(持久化、会话写入、节流更新等)
5. UI 层 (TUI Layer)
src/ink/ (约 65 个文件)
- 责任:完整的自研终端 UI 框架。包含自定义 React Reconciler (
reconciler.ts)、基于 Yoga WASM 的 Flexbox 布局引擎 (layout/)、终端输入解析 (termio/)、虚拟滚动、焦点管理、ANSI 渲染。这是对开源 Ink 库的深度定制版本。 - 复杂度:Critical (完整的 React 渲染器实现)
src/screens/REPL.tsx
- 责任:主交互界面。1500+ 行的大型组件,协调消息显示、用户输入、权限对话框、工具进度、背景任务管理。
- 复杂度:Critical
src/components/ (约 150 个 .tsx 文件)
- 责任:所有 UI 组件,包括消息渲染、权限对话框、MCP 管理、主题系统等。
6. 命令系统 (Command System)
src/commands.ts
- 责任:注册和导出所有斜杠命令 (
/commit,/config,/mcp等)。约 60 个静态命令 + 基于 feature flag 的条件命令。 - 复杂度:高 (约 500 行,大量条件导入)
src/commands/ (约 70 个子目录)
- 每个命令为独立模块,分为
prompt(返回提示词)和local(直接执行)两种类型。
7. MCP 集成层 (MCP Integration)
src/services/mcp/ (22 个文件)
- 责任:Model Context Protocol 客户端管理。支持 stdio、SSE、HTTP、WebSocket 四种传输。处理服务器发现、OAuth 认证、权限范围、工具/资源枚举。
- 外部依赖:
@modelcontextprotocol/sdk - 复杂度:高
8. 配置与设置层 (Settings Layer)
src/utils/settings/ (15 个文件)
- 责任:多源设置合并 — 用户级 (
~/.claude/settings.json)、项目级 (.claude/settings.json)、企业级 (MDM/HKCU)、CLI flags、远程托管设置。Zod schema 验证。权限规则解析。 - 复杂度:高
9. 上下文与系统提示 (Context & Prompts)
src/context.ts
- 责任:
getUserContext()和getSystemContext()— 收集 git 状态、CLAUDE.md 文件内容、日期等,注入到每次 API 调用的系统提示中。 - 复杂度:中
src/constants/prompts.ts
- 责任:主系统提示构建器
getSystemPrompt()。
10. 任务调度层 (Task Layer)
src/tasks/ + src/Task.ts
- 责任:背景任务抽象。支持 7 种任务类型:
local_bash,local_agent,remote_agent,in_process_teammate,local_workflow,monitor_mcp,dream。 - 复杂度:高 (跨进程状态同步和权限代理)
11. 服务层 (Services Layer)
src/services/analytics/ — GrowthBook 特性开关 + Statsig + 自研 1P 事件日志 src/services/compact/ — 对话压缩(自动/手动/micro/snip),防止超出 context window src/services/lsp/ — Language Server Protocol 集成 src/services/oauth/ — OAuth 2.0 认证流程
12. Skills / Plugins (扩展系统)
src/skills/ — Markdown 文件驱动的提示词命令,从 ~/.claude/commands/ 和项目级目录加载 src/plugins/ — 结构化插件系统,支持 MCP 服务器、slash 命令、钩子扩展 src/bridge/ — Remote Control Bridge,允许 claude.ai web 控制本地 Claude Code 实例
Architecture
架构模式
这是一个事件驱动的异步生成器管道架构,结合了分层依赖注入。整体不是传统的 MVC 或六边形架构,而是更像一个"响应流水线":
CLI (commander) → main.tsx → query() generator → API → Tool execution → Result
↑ |
└──────────────── 循环 ──────────────────────核心数据流
启动路径:
cli.tsx::main()→ 快速路径分发 → 加载main.tsx::main()→init()→ 解析 CLI 参数 → 构建AppState+ToolUseContext→launchRepl()或 headlessask()交互式会话路径:
launchRepl()→ React + Ink 渲染<App><REPL/></App>→ 用户在PromptInput输入 →REPL.tsx调用QueryEngine.submitMessage()→query()generator →claude.tsAPI 调用 → 流式StreamEvent推回 → 工具调用触发services/tools/toolOrchestration.ts→ 工具结果追加到消息 → 循环继续直到stop_reason === "end_turn"工具执行路径:
tool.checkPermissions()→ 权限对话框(交互模式)或自动决策 →tool.call()→ 返回ToolResult→ 工具结果序列化 → 追加为UserMessage类型的tool_result子 Agent 路径:
AgentTool.call()→runAgent()→ 克隆ToolUseContext(fork) → 独立query()循环 → 结果汇总 → 返回父级CLAUDE.md 注入路径:
context.ts::getUserContext()→ 扫描工作目录到 home 的路径 → 读取 CLAUDE.md 文件 → memoize 缓存 → 每次 API 调用前注入到系统提示
横切关注点
- 权限系统:
ToolPermissionContext(不可变)贯穿整个工具调用链,在bashPermissions.ts和permissions.ts中集中实现 allow/deny/ask 规则匹配 - 遥测/分析:GrowthBook 特性开关 + OpenTelemetry +
logEvent()散布在各处,通过bootstrap/state.ts中的 meter 对象汇聚 - 上下文压缩:
services/compact/在 context window 接近上限时自动触发,通过摘要替代历史消息 - 错误处理:AbortController 信号传播 + try/catch +
gracefulShutdown注册表,工具级别的错误通过is_error: true的tool_result返回给模型 - 多 Agent 协调:Coordinator Mode (
coordinator/coordinatorMode.ts) 通过TeamCreateTool/SendMessageTool管理 worker agent 网络,权限通过leaderPermissionBridge.ts从 worker 代理到 leader 的 UI
设计模式
- Builder/Factory:
buildTool()在Tool.ts中,统一工具构造 - Strategy:MCP 传输协议 (stdio/SSE/HTTP/ws) 通过同一接口替换
- Observer:
store.subscribe()驱动 React 重新渲染 - Generator/Coroutine:
query()和submitMessage()均为AsyncGenerator,实现背压感知的流式消费 - Dependency Injection:
ToolUseContext是一个庞大的上下文对象,通过函数参数在整个工具调用链中传递,避免全局状态
Key Risks
以下风险按严重程度排序,适用于代码理解和教学设计:
1. main.tsx 的认知复杂度 [Critical]src/main.tsx 是单文件 4000+ 行的"上帝函数"。它包含全部 CLI 参数解析、所有运行模式分支、所有前置条件验证。任何人试图理解启动流程都必须通读此文件。建议教学时先画出模式分支树,再逐块深入。
2. ToolUseContext 的隐式契约 [High]ToolUseContext(Tool.ts 约 300 行)有约 40 个可选字段。哪些字段在哪种模式下必须存在没有类型级别的强制保证,仅有注释描述。这造成大量"当 X 存在时才..."的防御性代码,且字段含义经常需要阅读多个调用点才能理解。
3. bootstrap/state.ts 的全局可变状态 [High] 虽然有注释警告不要添加更多状态,但该文件已有 80+ 个 getter/setter。它被系统各层广泛导入,造成隐性时序耦合(例如某些 getter 在 init() 之前调用会返回未初始化值)。测试隔离性差。
4. 自研 Ink 框架的理解成本 [High]src/ink/ 是一个完整的 React 渲染器实现,包含自定义 Reconciler、Yoga WASM 布局引擎、ANSI 渲染管线和终端输入解析器。这约 65 个文件与标准 React 渲染器的实现细节完全不同,教学时需单独讲解。
5. feature() 编译时开关的双重语义 [Medium]bun:bundle 的 feature() 函数同时用于构建时死代码消除和运行时特性开关(部分被 GrowthBook 运行时重写)。阅读代码时很难判断某个 feature block 是否真正在运行时条件执行,还是会被构建工具删除。
6. 查询循环的状态机隐式性 [Medium]query.ts 的 queryLoop() 是一个 while(true) 循环,有 7 个 continue 路径(自动压缩、最大 token 恢复、reactive compact 等)。这些路径的触发条件分散在各条件判断中,没有显式的状态机定义,调试困难。
7. 递归 Agent 的上下文泄漏风险 [Medium]runAgent.ts 的 createSubagentContext() 克隆父 agent 的 ToolUseContext。哪些字段是真正克隆(独立),哪些是共享引用(如 ContentReplacementState)直接影响多 agent 场景的正确性,但这一区别仅通过代码注释传达。
Essential Files
理解该代码库最关键的 15 个文件:
/D:/code/play/stock_ai_rust/claude-code/src/entrypoints/cli.tsx— 真正的程序入口,快速路径路由器,理解启动的第一步/D:/code/play/stock_ai_rust/claude-code/src/main.tsx— 主业务逻辑入口,CLI 参数解析和模式分发的核心 (重点读前 800 行和main()函数)/D:/code/play/stock_ai_rust/claude-code/src/bootstrap/state.ts— 全局状态单例,理解哪些状态是"会话级"的、哪些是"进程级"的/D:/code/play/stock_ai_rust/claude-code/src/entrypoints/init.ts— 初始化顺序文档,安全时序的核心/D:/code/play/stock_ai_rust/claude-code/src/Tool.ts— 工具接口定义,特别是ToolUseContext和Tool<Input, Output>类型,是整个工具系统的基础契约/D:/code/play/stock_ai_rust/claude-code/src/query.ts— agentic 主循环实现,理解"一次 API 调用"的完整生命周期/D:/code/play/stock_ai_rust/claude-code/src/QueryEngine.ts— SDK 接口层,理解 headless 使用模式和会话状态管理/D:/code/play/stock_ai_rust/claude-code/src/services/api/claude.ts— API 调用的最终实现,理解如何组装BetaMessageStreamParams/D:/code/play/stock_ai_rust/claude-code/src/tools.ts— 工具注册表,理解哪些工具在何种条件下启用/D:/code/play/stock_ai_rust/claude-code/src/state/AppStateStore.ts— React UI 状态类型定义,理解 UI 层持有哪些应用状态/D:/code/play/stock_ai_rust/claude-code/src/state/store.ts— 极简的 pub/sub store 实现,理解 UI 响应的基础机制/D:/code/play/stock_ai_rust/claude-code/src/screens/REPL.tsx— 交互式 UI 核心,协调所有 UI 交互(读前 100 行了解导入结构即可)/D:/code/play/stock_ai_rust/claude-code/src/tools/AgentTool/runAgent.ts— 递归子 agent 的启动逻辑,理解 multi-agent 架构/D:/code/play/stock_ai_rust/claude-code/src/context.ts— CLAUDE.md 加载与系统上下文注入,理解"项目感知"的实现/D:/code/play/stock_ai_rust/claude-code/src/utils/settings/types.ts— 设置 Schema 的 Zod 定义,理解settings.json所有可配置项
agentId: af298e26626229529 (use SendMessage with to: 'af298e26626229529' to continue this agent) <usage>total_tokens: 111850 tool_uses: 75 duration_ms: 330781</usage>
Tool Call: 分析模块清单与依赖 Status: Completed
Now I have sufficient information to compile the complete module inventory. Let me produce the final structured output.
Module Inventory: Claude Code src/
Root-Level Files (not in any subdirectory)
These are the system's foundational type contracts and top-level orchestrators.
| File | Responsibility | Size | Complexity |
|---|---|---|---|
src/Tool.ts | Defines the Tool<Input, Output, P> interface — the universal contract every tool must implement. Also defines ToolUseContext, ToolResult, buildTool() factory, and Tools type alias. Every tool in the system is built against this type. | 793 lines | Critical — central interface depended on by all 50+ tools and query.ts |
src/Task.ts | Defines the Task interface (kill lifecycle), TaskType, TaskStatus, TaskStateBase, and ID generation (generateTaskId). Governs all background execution units. | 126 lines | Medium |
src/QueryEngine.ts | The primary headless conversation engine. Implements QueryEngine class with submitMessage() as an async generator yielding SDKMessage. Orchestrates system prompt construction, user input processing, the query() loop, transcript persistence, budget tracking, and SDK result emission. Also exports the functional ask() wrapper. | 1,296 lines | Critical — highest-complexity file in the codebase |
src/commands.ts | The command registry. Imports all ~70 slash commands, assembles them via getCommands() (memoized), manages skill/plugin merging, defines INTERNAL_ONLY_COMMANDS, REMOTE_SAFE_COMMANDS, BRIDGE_SAFE_COMMANDS. | 755 lines | High |
src/query.ts | Low-level agentic loop. Calls the Anthropic API via services/api/claude.ts, runs tools via StreamingToolExecutor, handles auto-compact triggers, token budget checks, stop hooks, and yields typed message events. | ~2000+ lines (file too large to read fully) | Critical |
src/setup.ts | Process-level initialization: loads configs, registers telemetry, wires up MCP connections, sets model strings. Called at startup by entrypoints/cli.tsx. | ~400 lines (est.) | High |
src/context.ts | Likely loads and renders CLAUDE.md context files for injection into the system prompt. | Small | Medium |
src/tools.ts | Assembles the full set of tool instances from src/tools/ sub-directories and returns them as a Tools array. | Small–Medium | Medium |
src/tasks.ts | Registers task type handlers (bash, agent, dream, etc.) so the dispatch system can kill() by type. | Small | Low |
src/ink.ts | Re-exports the customized Ink terminal UI library from src/ink/. | Tiny | Low |
src/cost-tracker.ts | Tracks total API cost, per-model usage, and duration for the current session. | Small | Low |
src/history.ts | Reads/writes session history to transcript files for --resume. | Small | Medium |
src/main.tsx | Application entry point rendered by entrypoints/cli.tsx. Mounts the top-level React tree (AppStateProvider, REPL, or print-mode logic). | Large (789KB, includes compiled React) | Critical |
Subdirectory Modules
CORE — Essential to Understanding Claude Code
src/bootstrap/
Path: src/bootstrap/state.ts Responsibility: The global process-level singleton. Holds session ID, cost counters, model strings, telemetry meters, per-turn timing, scroll state, and many other session-scoped flags (plan mode state, scheduled tasks, invoked skills, etc.). All other modules import getters/setters from here rather than passing state as arguments. The comment "DO NOT ADD MORE STATE HERE" recurs multiple times. Public API: ~100 exported getter/setter functions (getSessionId, getCwdState, addToTotalCostState, registerHookCallbacks, etc.) Size: 1 file, 1,759 lines Internal Deps: src/utils/signal.ts, src/utils/crypto.ts, src/utils/settings/settingsCache.ts, various type imports External Deps: @anthropic-ai/sdk, @opentelemetry/api, lodash-es Complexity: Critical — global mutable singleton; nearly every module in the system depends on it
src/state/
Path: src/state/AppState.tsx, AppStateStore.ts, store.ts, selectors.ts, onChangeAppState.ts, teammateViewHelpers.ts Responsibility: React-layer application state (as opposed to bootstrap's process-level state). AppState contains per-session UI state: toolPermissionContext, in-progress tool use IDs, MCP server connections, task list, swarm worker state, fast mode, TODO list, and the speculation preview system. AppStateStore is a Zustand-like observable store. AppStateProvider is the React context provider. Public API: AppState type, AppStateProvider, AppStoreContext, getDefaultAppState() Size: 6 files, ~800 lines total Internal Deps: src/context/mailbox.ts, src/hooks/useSettingsChange.ts, src/utils/permissions/* External Deps: React Complexity: High — central reactive store; tight coupling with REPL and hooks
src/query/
Path: src/query/config.ts, deps.ts, stopHooks.ts, tokenBudget.ts Responsibility: Supporting modules for src/query.ts. config.ts builds the QueryConfig object passed to each API call. deps.ts defines injectable dependencies (for testability). stopHooks.ts handles post-response hooks. tokenBudget.ts tracks and enforces per-turn token limits. Size: 4 files, ~400 lines Internal Deps: src/bootstrap/state.ts, src/services/api/claude.ts, src/Tool.ts Complexity: Medium
src/entrypoints/
Path: src/entrypoints/cli.tsx, init.ts, mcp.ts, agentSdkTypes.ts, sdk/ Responsibility: Entry points for different invocation modes. cli.tsx is the CLI bootstrap (fast-paths for --version, --dump-system-prompt, Chrome MCP host, etc.). mcp.ts starts Claude as an MCP server exposing tools. agentSdkTypes.ts re-exports the entire public SDK type surface. sdk/ contains the core/control/runtime type split for SDK consumers. Public API: SDKMessage, SDKResultMessage, Options, Query, SDKSession, tool(), createMcpServer() Size: 8 files, ~600 lines Internal Deps: virtually everything (it is the root of the import DAG at runtime) Complexity: High
src/Tool.ts (root-level, see above)
src/QueryEngine.ts (root-level, see above)
src/types/
Path: src/types/command.ts, hooks.ts, ids.ts, logs.ts, permissions.ts, plugin.ts, textInputTypes.ts, message.ts (referenced but in utils), generated/ Responsibility: Shared type definitions that break circular import cycles. command.ts defines the Command union type (local, local-jsx, prompt) and PromptCommand. permissions.ts defines PermissionMode, PermissionResult, PermissionRule. ids.ts defines branded SessionId, AgentId types. hooks.ts defines hook event types. Size: ~10 files, ~800 lines Complexity: Medium — important for understanding the type system architecture
src/screens/
Path: src/screens/REPL.tsx, Doctor.tsx, ResumeConversation.tsx Responsibility: Top-level screen components. REPL.tsx is the interactive terminal session — the most complex UI component. It manages message display, user input, permission dialogs, task panels, teammate views, transcript search, IDE integration, and the full query lifecycle for interactive sessions. Doctor.tsx renders the /doctor diagnostics screen. ResumeConversation.tsx handles session resume flow. Size: 3 files; REPL.tsx alone is estimated at 3000+ lines Internal Deps: almost everything in components/, hooks/, services/, utils/ Complexity: Critical — the interactive REPL is the most complex React component in the system
src/tools/
Path: src/tools/** Responsibility: All tool implementations. Each sub-directory follows the pattern: <ToolName>Tool.ts (core logic), prompt.ts (system prompt description), UI.tsx (result/use message rendering), constants.ts.
Key tools by importance:
| Tool | Purpose | Complexity |
|---|---|---|
AgentTool/ | Spawns sub-agents with their own context. Implements recursive agentic execution, memory snapshots, resume, forking. 22 files. | Critical |
BashTool/ | Executes shell commands. Handles security validation, sandbox detection, sed parsing, permission matching. 18 files. | High |
FileEditTool/ | String-replacement file editing with permission prompts and diff display. | High |
FileReadTool/ | Reads files with image processing and size limits. | Medium |
FileWriteTool/ | Writes/creates files. | Medium |
GrepTool/, GlobTool/ | Ripgrep and glob-based file search. | Low-Medium |
MCPTool/ | Proxy for external MCP server tools. | High |
LSPTool/ | Language server protocol integration. | Medium |
SkillTool/ | Invokes user/plugin skill commands as prompts. | Medium |
NotebookEditTool/ | Jupyter notebook cell editing. | Medium |
TaskCreate/Stop/List/Get/UpdateTool/ | Background task management tools. | Medium |
TodoWriteTool/ | Manages the in-session TODO list. | Low |
ConfigTool/ | Reads/writes settings via the tool interface. | Low |
EnterPlanModeTool/ / ExitPlanModeTool/ | Mode transition tools. | Low |
WebSearchTool/, WebFetchTool/ | Web access tools. | Medium |
AskUserQuestionTool/ | Interactive multi-choice questions. | Medium |
Total: 184 files across ~35 sub-tools Overall Complexity: Critical — tools are the primary action surface of the entire system
src/commands/
Path: src/commands/** Responsibility: Slash command implementations. Each sub-directory is a /command-name command. Commands come in three types: local (runs a function, returns text), local-jsx (renders an Ink UI dialog), prompt (expands to text injected into the model context). The registry in src/commands.ts aggregates them all.
Key commands by category:
- Session management:
clear,compact,resume,session,export,rewind - Configuration:
config,permissions,hooks,mcp,model,theme,vim - Information:
cost,context,doctor,help,status,files,stats - Agent-related:
agents,tasks,plan,branch - Auth/install:
login,logout,install-github-app,install-slack-app - Developer:
bughunter,ant-trace,break-cache(internal only) - Feature-flagged:
bridge,voice,buddy,proactive,workflows
Size: 207 files, ~50 distinct commands Internal Deps: nearly all of utils/, services/, components/ Complexity: Medium individually; High collectively due to volume
src/services/
Path: src/services/** Responsibility: Business-logic service layer. Major sub-areas:
| Sub-module | Purpose | Files | Complexity |
|---|---|---|---|
api/ | Anthropic API client, retry logic, logging, usage tracking, cost calculation | 19 files | High |
mcp/ | MCP server connection management, OAuth, auth, channel notifications | 22 files | High |
compact/ | Context window management: auto-compact, micro-compact, snip, prompt construction | 12 files | High |
analytics/ | GrowthBook feature flags, event logging, Datadog | 9 files | Medium |
lsp/ | Language server process lifecycle, diagnostic registry | 6 files | Medium |
oauth/ | OAuth2 flow for claude.ai authentication | 5 files | Medium |
plugins/ | Plugin installation, CLI commands, operations | 3 files | Medium |
tools/ | Tool execution orchestration: StreamingToolExecutor, toolOrchestration.ts, hooks | 4 files | High |
SessionMemory/ | Session memory extraction and injection | 3 files | Medium |
autoDream/ | Background dream consolidation agent | 4 files | Medium |
skillSearch/ | Semantic skill search/indexing (feature-flagged) | ~3 files | Medium |
Total: 130 files Complexity: High overall
src/hooks/
Path: src/hooks/** Responsibility: React hooks wiring business logic to the REPL UI. All interactive-session behavior lives here: permission handling, command processing, IDE sync, typeahead, vim input, tool progress, notifications, settings changes.
Key hooks:
useCanUseTool.tsx— central permission decision point, called by every tool invocationuseLogMessages.ts— receives and batches messages from the query loop into React stateuseCommandQueue.ts— processes queued slash commandsuseTextInput.ts— manages the prompt input text stateuseTypeahead.tsx— command/file completion suggestionsuseReplBridge.tsx— syncs with the remote bridge (mobile/IDE)toolPermission/— sub-directory with coordinator, interactive, and swarm permission handlers
Size: ~100 files Complexity: High — tight coupling between hooks, AppState, and the query loop
src/ink/
Path: src/ink/** Responsibility: A custom fork/extension of the Ink terminal UI rendering library. Implements a React reconciler targeting the terminal. Contains layout engine (Yoga), ANSI rendering, text wrapping, scroll boxes, click/focus/keyboard events, selection, terminal focus detection, and hyperlinks. Size: ~85 files Internal Deps: native-ts/yoga-layout, native-ts/color-diff External Deps: yoga-layout (via native-ts), React reconciler API Complexity: Critical — foundational terminal rendering infrastructure; understanding it requires knowledge of React's reconciler API
src/context/
Path: src/context/** Responsibility: React context providers for cross-cutting concerns. Includes notifications.tsx (global notification queue), mailbox.tsx (inter-agent message passing), modalContext.tsx (dialog stacking), QueuedMessageContext.tsx (command queue), voice.tsx (voice mode state), stats.tsx, and overlay contexts. Size: 9 files Complexity: Low-Medium
src/components/
Path: src/components/** Responsibility: All terminal UI components. The largest module by file count. Sub-areas include:
messages/— renders each message type in the conversation transcript (AssistantTextMessage, UserPromptMessage, tool use/result messages, etc.)permissions/— all permission dialog UIs (Bash, FileEdit, FileWrite, AskUserQuestion, PowerShell, etc.)PromptInput/— the bottom input bar with mode indicator, suggestions, queued commandsdesign-system/— shared design primitives (Dialog, Tabs, FuzzyPicker, ThemedBox, etc.)agents/— agent creation wizard, agent list/detail/editormcp/— MCP server management UIhooks/— hook configuration UIdiff/— diff display dialogsLogoV2/— welcome screen / feed / channel noticesSpinner/— animated loading indicators- Root-level: App.tsx, Messages.tsx, MessageSelector.tsx, VirtualMessageList.tsx, etc.
Size: 389 files Complexity: High overall; Messages.tsx, VirtualMessageList.tsx, and the permissions sub-tree are individually complex
SUPPORTING — Important but Not Entry Points
src/utils/
Path: src/utils/** Responsibility: The largest module in the codebase — 564 files of utility functions spanning every concern. Major sub-areas:
| Sub-area | Files (est.) | Purpose |
|---|---|---|
bash/ | ~20 | Bash AST parsing, shell command analysis, tab completion specs |
permissions/ | ~20 | Permission rule evaluation, path validation, auto-mode classifier, denial tracking |
plugins/ | ~40 | Plugin loading, marketplace, versioning, reconciliation, policy |
settings/ | ~20 | Settings read/write, validation, MDM policy layer |
swarm/ | ~20 | Multi-agent swarm coordination, teammate spawning, backends (iTerm, Tmux, In-Process) |
computerUse/ | ~15 | Computer use tool host adapter, executor, lock, drain |
model/ | ~15 | Model selection, cost, capability detection, Bedrock/Vertex support |
telemetry/ | ~10 | OTel spans, BigQuery export, session tracing |
hooks/ | ~15 | Hook execution engine (exec bash/HTTP/agent hooks, file watchers, session hooks) |
claudeInChrome/ | ~6 | Chrome extension native host protocol |
deepLink/ | ~6 | Desktop deep link handling |
processUserInput/ | ~4 | Slash command parsing, text prompt processing |
| Misc | ~350 | auth, config, messages, tokens, session storage, git operations, IDE integration, MCP, etc. |
Complexity: High collectively; individual files range from Low to Critical
src/tasks/
Path: src/tasks/** Responsibility: Concrete task runner implementations. Each sub-directory implements a TaskType:
LocalShellTask/— runs shell commands as background tasksLocalAgentTask/— runs an async sub-agent via the AgentTool pipelineInProcessTeammateTask/— runs a full in-process team member (shares the same Node process, different React tree)RemoteAgentTask/— delegates to a remote CCR sessionDreamTask/— runs the autoDream consolidation agentLocalMainSessionTask.ts— represents the primary interactive session as a taskstopTask.ts,types.ts,pillLabel.ts— shared kill/stop logic and UI labels
Size: 12 files Complexity: High — especially InProcessTeammateTask which hosts a full sub-REPL
src/skills/
Path: src/skills/** Responsibility: Loads and manages skill commands. loadSkillsDir.ts scans .claude/skills/ for Markdown skill files. bundledSkills.ts registers built-in skills (batch, debug, loop, remember, verify, etc.). mcpSkillBuilders.ts creates skill commands from MCP prompts. Size: ~20 files Complexity: Medium
src/bridge/
Path: src/bridge/** Responsibility: The Remote Control Bridge — enables a mobile/web client (Claude iOS app, Claude.ai) to control a local terminal session. Includes JWT authentication, session creation, WebSocket/SSE messaging, polling configuration, flush gates, inbound message/attachment routing, and the REPL bridge integration. Size: 33 files Complexity: High — complex asynchronous protocol with multiple transport layers
src/cli/
Path: src/cli/** Responsibility: CLI-specific I/O and transport layer. print.ts handles --print mode output. structuredIO.ts implements structured JSON output for SDK consumers. remoteIO.ts handles remote session I/O. transports/ contains SSETransport, WebSocketTransport, HybridTransport, SerialBatchEventUploader for streaming events to clients. Size: ~15 files Complexity: Medium
src/constants/
Path: src/constants/** Responsibility: Hard-coded application constants: API limits, beta header names, product strings, OAuth config, XML tag names, tool limits, system prompt sections. Size: ~20 files Complexity: Low
src/memdir/
Path: src/memdir/** Responsibility: Memory directory management. Scans .claude/memory/ for per-project memory files, finds relevant memories for injection, tracks memory age, handles team memory paths. Size: 8 files Complexity: Medium
src/keybindings/
Path: src/keybindings/** Responsibility: Customizable keyboard shortcut system. Parses user binding files, resolves conflicts, provides a useKeybinding hook, validates shortcuts against reserved system shortcuts. Size: 14 files Complexity: Medium
src/coordinator/
Path: src/coordinator/coordinatorMode.ts Responsibility: Injects coordinator-mode context into the system prompt's userContext section when Claude is running as a swarm coordinator node. Size: 1 file Complexity: Low
src/schemas/
Path: src/schemas/hooks.ts Responsibility: Zod schema for the hooks configuration format (PreToolUse, PostToolUse, PostSampling, etc.). Size: 1 file Complexity: Low
PERIPHERAL — Supporting or Feature-Specific
src/buddy/
Path: src/buddy/** Responsibility: "Buddy" companion mascot feature (feature-flagged). Animated sprite, companion prompts, notification hook. Size: 6 files Complexity: Low; purely cosmetic feature
src/plugins/
Path: src/plugins/builtinPlugins.ts, bundled/index.ts Responsibility: Registers built-in (bundled) plugins such as the memory plugin. Provides getBuiltinPluginSkillCommands() consumed by src/commands.ts. Size: 2 files Complexity: Low
src/remote/
Path: src/remote/** Responsibility: Remote session management for --remote mode. RemoteSessionManager.ts handles WebSocket connections to a CCR (Claude Code Remote) host. sdkMessageAdapter.ts converts internal messages to the SDK wire format. Size: 4 files Complexity: Medium
src/server/
Path: src/server/** Responsibility: Direct Connect server — allows Claude Desktop or other local clients to connect to the CLI session via a Unix domain socket without going through the bridge. Size: 3 files Complexity: Medium
src/migrations/
Path: src/migrations/** Responsibility: One-time data migrations for settings/config files (e.g., renaming model settings, migrating OAuth fields, updating default values). Size: 11 files Complexity: Low
src/vim/
Path: src/vim/** Responsibility: Vim mode implementation for the prompt input. Defines vi motions, operators, text objects, and state machine transitions. Size: 5 files Complexity: Medium
src/voice/
Path: src/voice/voiceModeEnabled.ts Responsibility: Single utility file checking whether voice mode is feature-flagged on. Size: 1 file Complexity: Low
src/outputStyles/
Path: src/outputStyles/loadOutputStylesDir.ts Responsibility: Loads custom output style definitions from disk (user-defined rendering overrides for tool results). Size: 1 file Complexity: Low
src/native-ts/
Path: src/native-ts/** Responsibility: Pure TypeScript ports of native C++ libraries used to avoid native bindings in browser/portable builds. Contains yoga-layout (CSS flexbox layout engine used by Ink) and color-diff (color difference for ANSI diff rendering) and file-index (file search index). Size: 4 files Complexity: High internally (these are ports of complex algorithms) but Low for understanding Claude Code's architecture
src/moreright/
Path: src/moreright/useMoreRight.tsx Responsibility: A single React hook for detecting when content has overflowed to the right in a terminal row (used for scroll indicators). Size: 1 file Complexity: Low
src/assistant/
Path: src/assistant/sessionHistory.ts Responsibility: Fetches remote session event history pages for the Kairos/assistant feature (cloud-stored conversation history). Uses paginated API calls. Size: 1 file, 88 lines Complexity: Low
src/upstreamproxy/
Path: src/upstreamproxy/** Responsibility: Upstream HTTP proxy support — relays outgoing API requests through a configured proxy server (for enterprise firewall traversal). Size: 2 files Complexity: Low
Summary Table
| Module | Path | Files | Complexity | Core/Peripheral |
|---|---|---|---|---|
| Tool contract | src/Tool.ts | 1 | Critical | CORE |
| QueryEngine | src/QueryEngine.ts | 1 | Critical | CORE |
| query loop | src/query.ts + src/query/ | 5 | Critical | CORE |
| bootstrap/state | src/bootstrap/ | 1 | Critical | CORE |
| tools | src/tools/ | 184 | Critical | CORE |
| commands | src/commands/ + src/commands.ts | 208 | High | CORE |
| screens/REPL | src/screens/ | 3 | Critical | CORE |
| ink | src/ink/ | 85 | Critical | CORE |
| components | src/components/ | 389 | High | CORE |
| hooks | src/hooks/ | ~100 | High | CORE |
| state | src/state/ | 6 | High | CORE |
| services | src/services/ | 130 | High | CORE |
| utils | src/utils/ | 564 | High | CORE (utility) |
| entrypoints | src/entrypoints/ | 8 | High | CORE |
| types | src/types/ | ~10 | Medium | CORE |
| tasks | src/tasks/ | 12 | High | SUPPORTING |
| skills | src/skills/ | 20 | Medium | SUPPORTING |
| bridge | src/bridge/ | 33 | High | SUPPORTING |
| cli | src/cli/ | 15 | Medium | SUPPORTING |
| memdir | src/memdir/ | 8 | Medium | SUPPORTING |
| keybindings | src/keybindings/ | 14 | Medium | SUPPORTING |
| constants | src/constants/ | 20 | Low | SUPPORTING |
| context | src/context/ | 9 | Medium | SUPPORTING |
| coordinator | src/coordinator/ | 1 | Low | PERIPHERAL |
| schemas | src/schemas/ | 1 | Low | PERIPHERAL |
| buddy | src/buddy/ | 6 | Low | PERIPHERAL |
| plugins | src/plugins/ | 2 | Low | PERIPHERAL |
| remote | src/remote/ | 4 | Medium | PERIPHERAL |
| server | src/server/ | 3 | Medium | PERIPHERAL |
| migrations | src/migrations/ | 11 | Low | PERIPHERAL |
| vim | src/vim/ | 5 | Medium | PERIPHERAL |
| voice | src/voice/ | 1 | Low | PERIPHERAL |
| outputStyles | src/outputStyles/ | 1 | Low | PERIPHERAL |
| native-ts | src/native-ts/ | 4 | Low (interface) | PERIPHERAL |
| moreright | src/moreright/ | 1 | Low | PERIPHERAL |
| assistant | src/assistant/ | 1 | Low | PERIPHERAL |
| upstreamproxy | src/upstreamproxy/ | 2 | Low | PERIPHERAL |
Essential Files for Teaching This Codebase
The 15 most important files to understand the system's architecture and data flow:
D:/code/play/stock_ai_rust/claude-code/src/Tool.ts— defines theTool<Input, Output, P>type contract andToolUseContext; everything else plugs into this interfaceD:/code/play/stock_ai_rust/claude-code/src/QueryEngine.ts— the full headless conversation lifecycle in one classD:/code/play/stock_ai_rust/claude-code/src/query.ts— the inner agentic loop: API calls, streaming, tool execution, compactionD:/code/play/stock_ai_rust/claude-code/src/bootstrap/state.ts— the global singleton; understanding what state lives here explains many seemingly "magic" behaviorsD:/code/play/stock_ai_rust/claude-code/src/commands.ts— command registry assembly and the skill/plugin composition modelD:/code/play/stock_ai_rust/claude-code/src/Task.ts— background task type systemD:/code/play/stock_ai_rust/claude-code/src/state/AppStateStore.ts— theAppStatetype definition (React-layer state)D:/code/play/stock_ai_rust/claude-code/src/screens/REPL.tsx— the interactive session orchestratorD:/code/play/stock_ai_rust/claude-code/src/tools/AgentTool/AgentTool.tsx— recursive sub-agent invocationD:/code/play/stock_ai_rust/claude-code/src/tools/BashTool/BashTool.tsx— the most security-sensitive toolD:/code/play/stock_ai_rust/claude-code/src/hooks/useCanUseTool.tsx— central permission decision pointD:/code/play/stock_ai_rust/claude-code/src/services/api/claude.ts— Anthropic API streaming clientD:/code/play/stock_ai_rust/claude-code/src/services/compact/autoCompact.ts— context window management logicD:/code/play/stock_ai_rust/claude-code/src/entrypoints/agentSdkTypes.ts— public SDK type surfaceD:/code/play/stock_ai_rust/claude-code/src/types/command.ts— theCommandunion type that unifies all slash commands
Key Architectural Notes
The system follows a layered architecture:
Entrypoint layer (entrypoints/cli.tsx) bootstraps the process and either mounts the React/Ink REPL tree or enters headless SDK mode.
Conversation engine layer (QueryEngine.ts, query.ts) owns the turn-loop: builds system prompts, calls the API, runs tools via StreamingToolExecutor, handles compaction, and yields SDKMessage events.
Tool layer (tools/, Tool.ts) implements every action Claude can take. Each tool is a self-contained module with a call() function, permission check, Zod input schema, and React rendering methods.
State layer (bootstrap/state.ts for process globals, state/AppState for React UI state) is intentionally split: bootstrap is a flat module-level singleton to avoid circular imports; AppState is a Zustand-like observable store for the React tree.
Rendering layer (ink/, components/, screens/) turns the message stream into terminal output using a custom React reconciler targeting ANSI escape codes.
The ToolUseContext object (defined in Tool.ts, constructed in QueryEngine.ts) is the primary data bus: it carries the permission context, app state accessors, abort controller, file cache, message history, and all callback hooks. Understanding its shape is essential to understanding how any part of the system coordinates with any other part.
agentId: a58be4b4971bec15b (use SendMessage with to: 'a58be4b4971bec15b' to continue this agent) <usage>total_tokens: 136595 tool_uses: 56 duration_ms: 310798</usage>
Tool Call: 分析代码模式与风险 Status: Completed
Now I have enough information to produce a comprehensive analysis. Let me compile the findings:
Technology Stack
| 技术 | 版本/说明 |
|---|---|
| TypeScript | 5.x,使用 strict 模式,广泛使用高级类型特性 |
| React | 19.x,使用 React Compiler (react/compiler-runtime),useSyncExternalStore |
| Bun | 运行时 + 打包,使用 bun:bundle 的 feature() 做 DCE(死代码消除) |
| Zod | v4,用于 tool 的输入 schema 定义与运行时校验 |
| @anthropic-ai/sdk | API 客户端,提供 ToolUseBlockParam、ToolResultBlockParam 等类型 |
| @modelcontextprotocol/sdk | MCP 协议集成 |
| lodash-es | memoize 等工具函数 |
| Ink | React 的终端渲染引擎(用于 TUI) |
| 语言 | TypeScript + 少量 JavaScript(旧工具 + 条件加载) |
Module Inventory
核心抽象层
src/Tool.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\Tool.ts 职责:定义整个系统最核心的类型契约。Tool<Input, Output, P> 是一个拥有 ~25 个方法的接口类型,涵盖执行(call)、权限检查(checkPermissions)、输入校验(validateInput)、UI 渲染(renderToolResultMessage、renderToolUseMessage)等全生命周期。buildTool() 是工厂函数,为可选方法注入安全默认值。 公开表面:Tool<>, ToolDef<>, ToolUseContext, ToolPermissionContext, buildTool(), findToolByName(), toolMatchesName() 外部依赖:@anthropic-ai/sdk, @modelcontextprotocol/sdk, zod/v4 规模:793 行,单文件 复杂度:Critical — 整个 tool 系统的合同定义,ToolUseContext 本身有 40+ 个字段
src/Task.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\Task.ts 职责:定义后台任务的类型体系。TaskType(7 种:local_bash/local_agent/remote_agent/in_process_teammate/local_workflow/monitor_mcp/dream)、TaskStatus(5 种状态机)、TaskHandle、TaskStateBase。包含任务 ID 生成逻辑(前缀 + 8 位随机 base36)。 规模:126 行 复杂度:Low
src/QueryEngine.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\QueryEngine.ts 职责:SDK/headless 模式下的会话状态机。QueryEngine 类封装单个对话的全生命周期;submitMessage() 是一个 AsyncGenerator,产出 SDKMessage 流。ask() 是其 one-shot 便捷包装。 公开表面:QueryEngine, QueryEngineConfig, ask() 内部依赖:query.ts, Tool.ts, commands.ts, 大量 utils/ 规模:1296 行,单文件 复杂度:Critical — 单函数 submitMessage() 约 900 行,含复杂的消息分发 switch、多重 budget 检查、transcript 持久化、snip compaction 逻辑
命令系统
src/commands.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\commands.ts 职责:命令注册表。静态注册 70+ 个内置命令,通过 bun:bundle 的 feature() 做条件加载(PROACTIVE、KAIROS、BRIDGE_MODE 等特性门控),动态加载 skills/plugins/workflows。getCommands() 是主入口,结果按 cwd 做 memoize。 公开表面:getCommands(), findCommand(), REMOTE_SAFE_COMMANDS, BRIDGE_SAFE_COMMANDS, meetsAvailabilityRequirement() 规模:755 行 复杂度:High — 多层 memoize + 动态 require + feature flag 条件分支
src/types/command.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\types\command.ts 职责:Command 的判别联合类型定义。三种变体:PromptCommand(展开为模型提示词)、LocalCommand(本地文本命令)、LocalJSXCommand(渲染 Ink UI)。每种通过 type 字段区分。 复杂度:Medium — 类型本身清晰,但 LocalJSXCommand 的 lazy load() 模式需要理解
Tool 实现层
src/tools/(目录) 包含 20+ 个工具,每个工具均为独立子目录,通常包含:
XxxTool.ts(x)— 核心实现,通过buildTool()导出prompt.ts— 模型可见的工具描述文本UI.tsx— Ink/React 渲染组件(渲染 tool use 和 tool result 消息)
典型工具:BashTool(最复杂,~400 行主文件 + 10 个辅助模块)、FileReadTool、FileEditTool、AgentTool(递归子 agent)、MCPTool(MCP 协议代理)
src/tools/AgentTool/runAgent.ts 复杂度:High — 实现递归 agent 调用,处理 MCP 连接、子上下文克隆、前台任务协调
权限系统
src/types/permissions.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\types\permissions.ts 职责:权限类型的唯一来源。定义 5 种 PermissionMode、PermissionBehavior(allow/deny/ask)、PermissionResult(含 passthrough 扩展)、PermissionDecisionReason(9 种原因的判别联合)、YoloClassifierResult(AI 分类器的详细结果)。 规模:442 行(纯类型,无运行时依赖) 复杂度:High — 权限决策路径非常复杂,PermissionDecisionReason 的 9 个变体记录了每种决策来源
src/hooks/useCanUseTool.tsx 路径:D:\code\play\stock_ai_rust\claude-code\src\hooks\useCanUseTool.tsx 职责:权限决策的主入口 hook。按顺序走:hasPermissionsToUseTool(规则检查)→ allow(直接通过)/ deny(直接拒绝)/ ask(触发 handleCoordinatorPermission → handleSwarmWorkerPermission → 投机分类器竞速 → handleInteractivePermission)。 复杂度:Critical — 多层异步竞争,含 Promise.race 与 2 秒 timeout,是文件中最难理解的逻辑
状态管理
src/state/store.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\state\store.ts 职责:极简的 Zustand 风格外部 store,35 行。createStore<T>() 返回 { getState, setState, subscribe } 三元组。setState 使用 Object.is 做 bail-out。 复杂度:Low — 模式非常简洁,是理解 store 的最佳起点
src/state/AppStateStore.ts 路径:D:\code\play\stock_ai_rust\claude-code\src\state\AppStateStore.ts 职责:AppState 的类型定义,包含整个应用的可变状态(150+ 个字段),用 DeepImmutable<{...}> 包装,强制所有消费者进行 immutable 更新。 复杂度:High — 状态字段数量极多,每次 setState 需要整个 spread
src/state/AppState.tsx(注意:已是 React Compiler 编译后的产物) 路径:D:\code\play\stock_ai_rust\claude-code\src\state\AppState.tsx 职责:React Context Provider + useAppState(selector) / useSetAppState() hooks。使用 useSyncExternalStore 将外部 store 接入 React 渲染树。 关键设计:AppStateProvider 持有 store 引用保持稳定(不触发 Provider 重渲染),消费者通过 selector 订阅特定切片。
Skills 与 Plugins
src/skills/loadSkillsDir.ts 职责:从文件系统的 .claude/skills/ 目录扫描 Markdown 文件,解析 frontmatter,生成 Command 对象。支持 YAML frontmatter(whenToUse、paths、hooks、model、effort 等)。动态 skill 注册使用 createSignal() 模式。 复杂度:High — 大量文件系统操作 + frontmatter 解析 + gitignore 过滤
src/plugins/builtinPlugins.ts 职责:内置插件的注册点。
服务层(src/services/)
按子模块分类:
api/claude.ts— Anthropic API 调用核心mcp/client.ts— MCP 协议客户端compact/compact.ts— 对话压缩(context compaction)analytics/— 事件追踪(GrowthBook + Datadog)lsp/— LSP 语言服务器集成oauth/— OAuth 认证流程
Architecture
架构模式:事件驱动 + 层次化管道(Event-driven Layered Pipeline)
整体不是标准的 MVC 或分层架构,而是围绕"消息流"构建的管道:
用户输入
↓ processUserInput() — 解析斜杠命令 / 工具调用 / 纯文本
↓ query() — API 调用循环,产出 AsyncGenerator<Message>
↓ QueryEngine.submitMessage() — 消费 generator,分发 SDKMessage
↓ Tool.call() — 各工具实际执行
↓ canUseTool() — 权限检查(可能展示 UI 对话框)
↓ AppState.setState() — 状态更新,触发 React 重渲染数据流关键路径:
- 用户在 REPL 输入 →
processUserInput解析为消息数组 - 消息送入
query()→ 触发 Anthropic API 调用(streaming) - API 返回
tool_use块 → 查找对应Tool→ 调用canUseTool()进行权限决策 - 权限通过 → 调用
tool.call()→ 产出ToolResult - Tool result 转换为
user消息(tool_result内容块)→ 继续 API 循环 - 最终
assistant消息(stop_reason: end_turn)→ 循环结束
跨切面关注点:
- 权限检查:
ToolPermissionContext贯穿整个工具调用链,通过ToolUseContext传递 - 日志/追踪:
logEvent()散布在工具调用、权限决策、命令执行各处 - 特性门控:
feature('FLAG_NAME')从bun:bundle导入,编译期做 DCE,运行期配合 GrowthBook 动态配置 - 错误处理:每个工具
call()包在try-catch中,失败返回ToolResultBlockParam含错误文本 - 任务并发:
AppState.tasks维护后台任务字典,LocalShellTask提供前台/后台切换
设计模式:
- Builder 模式:
buildTool(def)— 合并默认值,生成完整Tool对象 - Strategy 模式:权限处理的三路 handler(
handleCoordinatorPermission/handleSwarmWorkerPermission/handleInteractivePermission),根据上下文选择策略 - Generator 模式:
query()和QueryEngine.submitMessage()均为AsyncGenerator,天然支持 streaming 消费 - Observer 模式:
store.subscribe()+useSyncExternalStore— 外部 store 通知 React 渲染 - Command 模式:
Command类型的PromptCommand/LocalCommand/LocalJSXCommand三变体 - Decorator 模式:
wrappedCanUseTool在QueryEngine中包装原始canUseTool,追加权限拒绝记录
Key Risks
风险 1 — ToolUseContext 字段膨胀(严重度:High)src/Tool.ts 中 ToolUseContext 有 40+ 个字段,其中大量是可选的(?:)。这说明上下文并非始终完整,不同执行路径(REPL vs SDK vs 子 agent)提供不同的字段子集。任何新 tool 实现者都需要理解哪些字段在哪些模式下存在,风险极高。缓解建议:对必要字段建立文档矩阵,或拆分为不同的上下文类型。
风险 2 — QueryEngine.submitMessage() 单函数约 900 行(严重度:High)src/QueryEngine.ts 第 209-1156 行是单个 async generator 函数,内含 transcript 持久化、budget 检查、snip compaction、消息分发、结构化输出追踪等多个完全不同的关注点。圈复杂度极高,理解与修改都需要极高认知负担。
风险 3 — 编译后的 .tsx 文件(严重度:Medium)src/state/AppState.tsx 和 src/hooks/useCanUseTool.tsx 是 React Compiler 处理后的产物,包含 _c() 缓存槽和 $[] 数组操作,完全不是人类正常编写的 React 代码。文件末尾还有 base64 编码的 source map。直接阅读这两个文件来理解逻辑极为困难,应当优先阅读 source map 还原后的内容(已嵌入文件末尾注释)。
风险 4 — 特性门控的 require() 破坏静态分析(严重度:Medium)commands.ts 和 QueryEngine.ts 中大量使用 feature('FLAG') ? require('./module') : null 模式,导致 IDE 的"查找引用"和 TypeScript 的类型检查在这些路径上部分失效。具体条件依赖运行时 GrowthBook 配置,开发者无法从代码中直接推断哪些特性处于激活状态。
风险 5 — PermissionDecisionReason 的 9 路判别联合(严重度:Medium)src/types/permissions.ts 中 PermissionDecisionReason 枚举了 9 种权限决策原因(rule、mode、hook、classifier、asyncAgent、sandboxOverride、workingDir、safetyCheck、other),加上 useCanUseTool.tsx 中的多层异步竞争(coordinator → swarm → 投机分类器 2 秒 race → 交互对话框),理解完整的权限决策树需要同时追踪多个文件。
风险 6 — AppState 字段过多(严重度:Medium)AppStateStore.ts 中的 AppState 单个对象包含 150+ 个字段,从 toolPermissionContext 到 replBridgeConnectUrl 再到 speculation 状态,耦合了 UI、业务逻辑、网络连接状态。DeepImmutable<> 包装保证了不可变性,但 setState(prev => ({...prev, field: newValue})) 模式在字段众多时极易遗漏或误更新。
Essential Files
理解这个代码库最关键的 15 个文件:
D:\code\play\stock_ai_rust\claude-code\src\Tool.ts— 整个工具系统的类型合同,必读D:\code\play\stock_ai_rust\claude-code\src\QueryEngine.ts— SDK 会话状态机,理解 headless 执行路径D:\code\play\stock_ai_rust\claude-code\src\query.ts— 核心 API 调用循环(AsyncGenerator),工具执行编排D:\code\play\stock_ai_rust\claude-code\src\types\command.ts—Command判别联合,三种命令类型的合同D:\code\play\stock_ai_rust\claude-code\src\types\permissions.ts— 权限类型完整定义,包括PermissionDecisionReason9 路分支D:\code\play\stock_ai_rust\claude-code\src\state\store.ts— 35 行的 Zustand 风格 store,状态系统基础D:\code\play\stock_ai_rust\claude-code\src\state\AppStateStore.ts—AppState的完整类型定义(150+ 字段)D:\code\play\stock_ai_rust\claude-code\src\hooks\useCanUseTool.tsx— 权限决策主入口,包含多层异步竞争逻辑(注意:是编译后产物,阅读 source map)D:\code\play\stock_ai_rust\claude-code\src\commands.ts— 命令注册表,展示 feature-flag DCE 模式D:\code\play\stock_ai_rust\claude-code\src\Task.ts— 后台任务类型体系,7 种任务类型D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx— 最复杂工具的完整实现,展示buildTool()用法D:\code\play\stock_ai_rust\claude-code\src\tools\AgentTool\runAgent.ts— 递归子 agent 调用,展示createSubagentContextD:\code\play\stock_ai_rust\claude-code\src\skills\loadSkillsDir.ts— skill 动态加载,frontmatter 解析,Command生成D:\code\play\stock_ai_rust\claude-code\src\types\hooks.ts— Hook 系统类型(HookCallback、HookResult、9 种 hook 事件hookEventName)D:\code\play\stock_ai_rust\claude-code\src\utils\processUserInput\processUserInput.ts— 用户输入到消息数组的转换入口
agentId: ade735896441ace7e (use SendMessage with to: 'ade735896441ace7e' to continue this agent) <usage>total_tokens: 140911 tool_uses: 41 duration_ms: 230836</usage>
Tool Call: Find D:\code\play\stock_ai_rust\claude-code **/* Status: Completed
.git\description .git\hooks\applypatch-msg.sample .git\hooks\commit-msg.sample .git\hooks\fsmonitor-watchman.sample .git\hooks\post-update.sample .git\hooks\pre-applypatch.sample .git\hooks\pre-commit.sample .git\hooks\pre-merge-commit.sample .git\hooks\pre-push.sample .git\hooks\pre-rebase.sample .git\hooks\pre-receive.sample .git\hooks\prepare-commit-msg.sample .git\hooks\push-to-checkout.sample .git\hooks\sendemail-validate.sample .git\hooks\update.sample .git\objects\pack\pack-5cdf543681ba51cff3a1583e6adbc2f76a485785.pack .git\objects\pack\pack-5cdf543681ba51cff3a1583e6adbc2f76a485785.idx .git\objects\pack\pack-5cdf543681ba51cff3a1583e6adbc2f76a485785.rev .git\packed-refs .git\HEAD .git\logs\refs\remotes\origin\HEAD .git\refs\remotes\origin\HEAD .git\logs\HEAD .git\logs\refs\heads\main .git\refs\heads\main .git\config src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code\src **/* Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\main.tsx Status: Failed
File content (789.7KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/** Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src Status: Failed
EISDIR: illegal operation on a directory, read 'D:\code\play\stock_ai_rust\claude-code\src'Tool Call: Read src Status: Failed
EISDIR: illegal operation on a directory, read 'D:\code\play\stock_ai_rust\claude-code\src'Tool Call: Find D:\code\play\stock_ai_rust\claude-code\src **/* Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\main.tsx (1 - 150) Status: Completed
1→// These side-effects must run before all other imports:
2→// 1. profileCheckpoint marks entry before heavy module evaluation begins
3→// 2. startMdmRawRead fires MDM subprocesses (plutil/reg query) so they run in
4→// parallel with the remaining ~135ms of imports below
5→// 3. startKeychainPrefetch fires both macOS keychain reads (OAuth + legacy API
6→// key) in parallel — isRemoteManagedSettingsEligible() otherwise reads them
7→// sequentially via sync spawn inside applySafeConfigEnvironmentVariables()
8→// (~65ms on every macOS startup)
9→import { profileCheckpoint, profileReport } from './utils/startupProfiler.js';
10→
11→// eslint-disable-next-line custom-rules/no-top-level-side-effects
12→profileCheckpoint('main_tsx_entry');
13→import { startMdmRawRead } from './utils/settings/mdm/rawRead.js';
14→
15→// eslint-disable-next-line custom-rules/no-top-level-side-effects
16→startMdmRawRead();
17→import { ensureKeychainPrefetchCompleted, startKeychainPrefetch } from './utils/secureStorage/keychainPrefetch.js';
18→
19→// eslint-disable-next-line custom-rules/no-top-level-side-effects
20→startKeychainPrefetch();
21→import { feature } from 'bun:bundle';
22→import { Command as CommanderCommand, InvalidArgumentError, Option } from '@commander-js/extra-typings';
23→import chalk from 'chalk';
24→import { readFileSync } from 'fs';
25→import mapValues from 'lodash-es/mapValues.js';
26→import pickBy from 'lodash-es/pickBy.js';
27→import uniqBy from 'lodash-es/uniqBy.js';
28→import React from 'react';
29→import { getOauthConfig } from './constants/oauth.js';
30→import { getRemoteSessionUrl } from './constants/product.js';
31→import { getSystemContext, getUserContext } from './context.js';
32→import { init, initializeTelemetryAfterTrust } from './entrypoints/init.js';
33→import { addToHistory } from './history.js';
34→import type { Root } from './ink.js';
35→import { launchRepl } from './replLauncher.js';
36→import { hasGrowthBookEnvOverride, initializeGrowthBook, refreshGrowthBookAfterAuthChange } from './services/analytics/growthbook.js';
37→import { fetchBootstrapData } from './services/api/bootstrap.js';
38→import { type DownloadResult, downloadSessionFiles, type FilesApiConfig, parseFileSpecs } from './services/api/filesApi.js';
39→import { prefetchPassesEligibility } from './services/api/referral.js';
40→import { prefetchOfficialMcpUrls } from './services/mcp/officialRegistry.js';
41→import type { McpSdkServerConfig, McpServerConfig, ScopedMcpServerConfig } from './services/mcp/types.js';
42→import { isPolicyAllowed, loadPolicyLimits, refreshPolicyLimits, waitForPolicyLimitsToLoad } from './services/policyLimits/index.js';
43→import { loadRemoteManagedSettings, refreshRemoteManagedSettings } from './services/remoteManagedSettings/index.js';
44→import type { ToolInputJSONSchema } from './Tool.js';
45→import { createSyntheticOutputTool, isSyntheticOutputToolEnabled } from './tools/SyntheticOutputTool/SyntheticOutputTool.js';
46→import { getTools } from './tools.js';
47→import { canUserConfigureAdvisor, getInitialAdvisorSetting, isAdvisorEnabled, isValidAdvisorModel, modelSupportsAdvisor } from './utils/advisor.js';
48→import { isAgentSwarmsEnabled } from './utils/agentSwarmsEnabled.js';
49→import { count, uniq } from './utils/array.js';
50→import { installAsciicastRecorder } from './utils/asciicast.js';
51→import { getSubscriptionType, isClaudeAISubscriber, prefetchAwsCredentialsAndBedRockInfoIfSafe, prefetchGcpCredentialsIfSafe, validateForceLoginOrg } from './utils/auth.js';
52→import { checkHasTrustDialogAccepted, getGlobalConfig, getRemoteControlAtStartup, isAutoUpdaterDisabled, saveGlobalConfig } from './utils/config.js';
53→import { seedEarlyInput, stopCapturingEarlyInput } from './utils/earlyInput.js';
54→import { getInitialEffortSetting, parseEffortValue } from './utils/effort.js';
55→import { getInitialFastModeSetting, isFastModeEnabled, prefetchFastModeStatus, resolveFastModeStatusFromCache } from './utils/fastMode.js';
56→import { applyConfigEnvironmentVariables } from './utils/managedEnv.js';
57→import { createSystemMessage, createUserMessage } from './utils/messages.js';
58→import { getPlatform } from './utils/platform.js';
59→import { getBaseRenderOptions } from './utils/renderOptions.js';
60→import { getSessionIngressAuthToken } from './utils/sessionIngressAuth.js';
61→import { settingsChangeDetector } from './utils/settings/changeDetector.js';
62→import { skillChangeDetector } from './utils/skills/skillChangeDetector.js';
63→import { jsonParse, writeFileSync_DEPRECATED } from './utils/slowOperations.js';
64→import { computeInitialTeamContext } from './utils/swarm/reconnection.js';
65→import { initializeWarningHandler } from './utils/warningHandler.js';
66→import { isWorktreeModeEnabled } from './utils/worktreeModeEnabled.js';
67→
68→// Lazy require to avoid circular dependency: teammate.ts -> AppState.tsx -> ... -> main.tsx
69→/* eslint-disable @typescript-eslint/no-require-imports */
70→const getTeammateUtils = () => require('./utils/teammate.js') as typeof import('./utils/teammate.js');
71→const getTeammatePromptAddendum = () => require('./utils/swarm/teammatePromptAddendum.js') as typeof import('./utils/swarm/teammatePromptAddendum.js');
72→const getTeammateModeSnapshot = () => require('./utils/swarm/backends/teammateModeSnapshot.js') as typeof import('./utils/swarm/backends/teammateModeSnapshot.js');
73→/* eslint-enable @typescript-eslint/no-require-imports */
74→// Dead code elimination: conditional import for COORDINATOR_MODE
75→/* eslint-disable @typescript-eslint/no-require-imports */
76→const coordinatorModeModule = feature('COORDINATOR_MODE') ? require('./coordinator/coordinatorMode.js') as typeof import('./coordinator/coordinatorMode.js') : null;
77→/* eslint-enable @typescript-eslint/no-require-imports */
78→// Dead code elimination: conditional import for KAIROS (assistant mode)
79→/* eslint-disable @typescript-eslint/no-require-imports */
80→const assistantModule = feature('KAIROS') ? require('./assistant/index.js') as typeof import('./assistant/index.js') : null;
81→const kairosGate = feature('KAIROS') ? require('./assistant/gate.js') as typeof import('./assistant/gate.js') : null;
82→import { relative, resolve } from 'path';
83→import { isAnalyticsDisabled } from 'src/services/analytics/config.js';
84→import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js';
85→import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from 'src/services/analytics/index.js';
86→import { initializeAnalyticsGates } from 'src/services/analytics/sink.js';
87→import { getOriginalCwd, setAdditionalDirectoriesForClaudeMd, setIsRemoteMode, setMainLoopModelOverride, setMainThreadAgentType, setTeleportedSessionInfo } from './bootstrap/state.js';
88→import { filterCommandsForRemoteMode, getCommands } from './commands.js';
89→import type { StatsStore } from './context/stats.js';
90→import { launchAssistantInstallWizard, launchAssistantSessionChooser, launchInvalidSettingsDialog, launchResumeChooser, launchSnapshotUpdateDialog, launchTeleportRepoMismatchDialog, launchTeleportResumeWrapper } from './dialogLaunchers.js';
91→import { SHOW_CURSOR } from './ink/termio/dec.js';
92→import { exitWithError, exitWithMessage, getRenderContext, renderAndRun, showSetupScreens } from './interactiveHelpers.js';
93→import { initBuiltinPlugins } from './plugins/bundled/index.js';
94→/* eslint-enable @typescript-eslint/no-require-imports */
95→import { checkQuotaStatus } from './services/claudeAiLimits.js';
96→import { getMcpToolsCommandsAndResources, prefetchAllMcpResources } from './services/mcp/client.js';
97→import { VALID_INSTALLABLE_SCOPES, VALID_UPDATE_SCOPES } from './services/plugins/pluginCliCommands.js';
98→import { initBundledSkills } from './skills/bundled/index.js';
99→import type { AgentColorName } from './tools/AgentTool/agentColorManager.js';
100→import { getActiveAgentsFromList, getAgentDefinitionsWithOverrides, isBuiltInAgent, isCustomAgent, parseAgentsFromJson } from './tools/AgentTool/loadAgentsDir.js';
101→import type { LogOption } from './types/logs.js';
102→import type { Message as MessageType } from './types/message.js';
103→import { assertMinVersion } from './utils/autoUpdater.js';
104→import { CLAUDE_IN_CHROME_SKILL_HINT, CLAUDE_IN_CHROME_SKILL_HINT_WITH_WEBBROWSER } from './utils/claudeInChrome/prompt.js';
105→import { setupClaudeInChrome, shouldAutoEnableClaudeInChrome, shouldEnableClaudeInChrome } from './utils/claudeInChrome/setup.js';
106→import { getContextWindowForModel } from './utils/context.js';
107→import { loadConversationForResume } from './utils/conversationRecovery.js';
108→import { buildDeepLinkBanner } from './utils/deepLink/banner.js';
109→import { hasNodeOption, isBareMode, isEnvTruthy, isInProtectedNamespace } from './utils/envUtils.js';
110→import { refreshExampleCommands } from './utils/exampleCommands.js';
111→import type { FpsMetrics } from './utils/fpsTracker.js';
112→import { getWorktreePaths } from './utils/getWorktreePaths.js';
113→import { findGitRoot, getBranch, getIsGit, getWorktreeCount } from './utils/git.js';
114→import { getGhAuthStatus } from './utils/github/ghAuthStatus.js';
115→import { safeParseJSON } from './utils/json.js';
116→import { logError } from './utils/log.js';
117→import { getModelDeprecationWarning } from './utils/model/deprecation.js';
118→import { getDefaultMainLoopModel, getUserSpecifiedModelSetting, normalizeModelStringForAPI, parseUserSpecifiedModel } from './utils/model/model.js';
119→import { ensureModelStringsInitialized } from './utils/model/modelStrings.js';
120→import { PERMISSION_MODES } from './utils/permissions/PermissionMode.js';
121→import { checkAndDisableBypassPermissions, getAutoModeEnabledStateIfCached, initializeToolPermissionContext, initialPermissionModeFromCLI, isDefaultPermissionModeAuto, parseToolListFromCLI, removeDangerousPermissions, stripDangerousPermissionsForAutoMode, verifyAutoModeGateAccess } from './utils/permissions/permissionSetup.js';
122→import { cleanupOrphanedPluginVersionsInBackground } from './utils/plugins/cacheUtils.js';
123→import { initializeVersionedPlugins } from './utils/plugins/installedPluginsManager.js';
124→import { getManagedPluginNames } from './utils/plugins/managedPlugins.js';
125→import { getGlobExclusionsForPluginCache } from './utils/plugins/orphanedPluginFilter.js';
126→import { getPluginSeedDirs } from './utils/plugins/pluginDirectories.js';
127→import { countFilesRoundedRg } from './utils/ripgrep.js';
128→import { processSessionStartHooks, processSetupHooks } from './utils/sessionStart.js';
129→import { cacheSessionTitle, getSessionIdFromLog, loadTranscriptFromFile, saveAgentSetting, saveMode, searchSessionsByCustomTitle, sessionIdExists } from './utils/sessionStorage.js';
130→import { ensureMdmSettingsLoaded } from './utils/settings/mdm/settings.js';
131→import { getInitialSettings, getManagedSettingsKeysForLogging, getSettingsForSource, getSettingsWithErrors } from './utils/settings/settings.js';
132→import { resetSettingsCache } from './utils/settings/settingsCache.js';
133→import type { ValidationError } from './utils/settings/validation.js';
134→import { DEFAULT_TASKS_MODE_TASK_LIST_ID, TASK_STATUSES } from './utils/tasks.js';
135→import { logPluginLoadErrors, logPluginsEnabledForSession } from './utils/telemetry/pluginTelemetry.js';
136→import { logSkillsLoaded } from './utils/telemetry/skillLoadedEvent.js';
137→import { generateTempFilePath } from './utils/tempfile.js';
138→import { validateUuid } from './utils/uuid.js';
139→// Plugin startup checks are now handled non-blockingly in REPL.tsx
140→
141→import { registerMcpAddCommand } from 'src/commands/mcp/addCommand.js';
142→import { registerMcpXaaIdpCommand } from 'src/commands/mcp/xaaIdpCommand.js';
143→import { logPermissionContextForAnts } from 'src/services/internalLogging.js';
144→import { fetchClaudeAIMcpConfigsIfEligible } from 'src/services/mcp/claudeai.js';
145→import { clearServerCache } from 'src/services/mcp/client.js';
146→import { areMcpConfigsAllowedWithEnterpriseMcpConfig, dedupClaudeAiMcpServers, doesEnterpriseMcpConfigExist, filterMcpServersByPolicy, getClaudeCodeMcpConfigs, getMcpServerSignature, parseMcpConfig, parseMcpConfigFromFilePath } from 'src/services/mcp/config.js';
147→import { excludeCommandsByServer, excludeResourcesByServer } from 'src/services/mcp/utils.js';
148→import { isXaaEnabled } from 'src/services/mcp/xaaIdpLogin.js';
149→import { getRelevantTips } from 'src/services/tips/tipRegistry.js';
150→import { logContextMetrics } from 'src/utils/api.js';Tool Call: Find D:\code\play\stock_ai_rust\claude-code\src **/* Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/** Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\CompanionSprite.tsx src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\buddy\useBuddyNotification.tsx src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\mcp.tsx src\cli\handlers\plugins.ts src\cli\handlers\util.tsx src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/*.{ts,tsx,js} Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\commands.ts src\context.ts src\cost-tracker.ts src\costHook.ts src\dialogLaunchers.tsx src\history.ts src\ink.ts src\interactiveHelpers.tsx src\main.tsx src\projectOnboardingState.ts src\query.ts src\replLauncher.tsx src\setup.ts src\tasks.ts src\tools.ts
Tool Call: Read src\main.tsx (150 - 299) Status: Completed
150→import { logContextMetrics } from 'src/utils/api.js';
151→import { CLAUDE_IN_CHROME_MCP_SERVER_NAME, isClaudeInChromeMCPServer } from 'src/utils/claudeInChrome/common.js';
152→import { registerCleanup } from 'src/utils/cleanupRegistry.js';
153→import { eagerParseCliFlag } from 'src/utils/cliArgs.js';
154→import { createEmptyAttributionState } from 'src/utils/commitAttribution.js';
155→import { countConcurrentSessions, registerSession, updateSessionName } from 'src/utils/concurrentSessions.js';
156→import { getCwd } from 'src/utils/cwd.js';
157→import { logForDebugging, setHasFormattedOutput } from 'src/utils/debug.js';
158→import { errorMessage, getErrnoCode, isENOENT, TeleportOperationError, toError } from 'src/utils/errors.js';
159→import { getFsImplementation, safeResolvePath } from 'src/utils/fsOperations.js';
160→import { gracefulShutdown, gracefulShutdownSync } from 'src/utils/gracefulShutdown.js';
161→import { setAllHookEventsEnabled } from 'src/utils/hooks/hookEvents.js';
162→import { refreshModelCapabilities } from 'src/utils/model/modelCapabilities.js';
163→import { peekForStdinData, writeToStderr } from 'src/utils/process.js';
164→import { setCwd } from 'src/utils/Shell.js';
165→import { type ProcessedResume, processResumedConversation } from 'src/utils/sessionRestore.js';
166→import { parseSettingSourcesFlag } from 'src/utils/settings/constants.js';
167→import { plural } from 'src/utils/stringUtils.js';
168→import { type ChannelEntry, getInitialMainLoopModel, getIsNonInteractiveSession, getSdkBetas, getSessionId, getUserMsgOptIn, setAllowedChannels, setAllowedSettingSources, setChromeFlagOverride, setClientType, setCwdState, setDirectConnectServerUrl, setFlagSettingsPath, setInitialMainLoopModel, setInlinePlugins, setIsInteractive, setKairosActive, setOriginalCwd, setQuestionPreviewFormat, setSdkBetas, setSessionBypassPermissionsMode, setSessionPersistenceDisabled, setSessionSource, setUserMsgOptIn, switchSession } from './bootstrap/state.js';
169→
170→/* eslint-disable @typescript-eslint/no-require-imports */
171→const autoModeStateModule = feature('TRANSCRIPT_CLASSIFIER') ? require('./utils/permissions/autoModeState.js') as typeof import('./utils/permissions/autoModeState.js') : null;
172→
173→// TeleportRepoMismatchDialog, TeleportResumeWrapper dynamically imported at call sites
174→import { migrateAutoUpdatesToSettings } from './migrations/migrateAutoUpdatesToSettings.js';
175→import { migrateBypassPermissionsAcceptedToSettings } from './migrations/migrateBypassPermissionsAcceptedToSettings.js';
176→import { migrateEnableAllProjectMcpServersToSettings } from './migrations/migrateEnableAllProjectMcpServersToSettings.js';
177→import { migrateFennecToOpus } from './migrations/migrateFennecToOpus.js';
178→import { migrateLegacyOpusToCurrent } from './migrations/migrateLegacyOpusToCurrent.js';
179→import { migrateOpusToOpus1m } from './migrations/migrateOpusToOpus1m.js';
180→import { migrateReplBridgeEnabledToRemoteControlAtStartup } from './migrations/migrateReplBridgeEnabledToRemoteControlAtStartup.js';
181→import { migrateSonnet1mToSonnet45 } from './migrations/migrateSonnet1mToSonnet45.js';
182→import { migrateSonnet45ToSonnet46 } from './migrations/migrateSonnet45ToSonnet46.js';
183→import { resetAutoModeOptInForDefaultOffer } from './migrations/resetAutoModeOptInForDefaultOffer.js';
184→import { resetProToOpusDefault } from './migrations/resetProToOpusDefault.js';
185→import { createRemoteSessionConfig } from './remote/RemoteSessionManager.js';
186→/* eslint-enable @typescript-eslint/no-require-imports */
187→// teleportWithProgress dynamically imported at call site
188→import { createDirectConnectSession, DirectConnectError } from './server/createDirectConnectSession.js';
189→import { initializeLspServerManager } from './services/lsp/manager.js';
190→import { shouldEnablePromptSuggestion } from './services/PromptSuggestion/promptSuggestion.js';
191→import { type AppState, getDefaultAppState, IDLE_SPECULATION_STATE } from './state/AppStateStore.js';
192→import { onChangeAppState } from './state/onChangeAppState.js';
193→import { createStore } from './state/store.js';
194→import { asSessionId } from './types/ids.js';
195→import { filterAllowedSdkBetas } from './utils/betas.js';
196→import { isInBundledMode, isRunningWithBun } from './utils/bundledMode.js';
197→import { logForDiagnosticsNoPII } from './utils/diagLogs.js';
198→import { filterExistingPaths, getKnownPathsForRepo } from './utils/githubRepoPathMapping.js';
199→import { clearPluginCache, loadAllPluginsCacheOnly } from './utils/plugins/pluginLoader.js';
200→import { migrateChangelogFromConfig } from './utils/releaseNotes.js';
201→import { SandboxManager } from './utils/sandbox/sandbox-adapter.js';
202→import { fetchSession, prepareApiRequest } from './utils/teleport/api.js';
203→import { checkOutTeleportedSessionBranch, processMessagesForTeleportResume, teleportToRemoteWithErrorHandling, validateGitState, validateSessionRepository } from './utils/teleport.js';
204→import { shouldEnableThinkingByDefault, type ThinkingConfig } from './utils/thinking.js';
205→import { initUser, resetUserCache } from './utils/user.js';
206→import { getTmuxInstallInstructions, isTmuxAvailable, parsePRReference } from './utils/worktree.js';
207→
208→// eslint-disable-next-line custom-rules/no-top-level-side-effects
209→profileCheckpoint('main_tsx_imports_loaded');
210→
211→/**
212→ * Log managed settings keys to Statsig for analytics.
213→ * This is called after init() completes to ensure settings are loaded
214→ * and environment variables are applied before model resolution.
215→ */
216→function logManagedSettings(): void {
217→ try {
218→ const policySettings = getSettingsForSource('policySettings');
219→ if (policySettings) {
220→ const allKeys = getManagedSettingsKeysForLogging(policySettings);
221→ logEvent('tengu_managed_settings_loaded', {
222→ keyCount: allKeys.length,
223→ keys: allKeys.join(',') as unknown as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
224→ });
225→ }
226→ } catch {
227→ // Silently ignore errors - this is just for analytics
228→ }
229→}
230→
231→// Check if running in debug/inspection mode
232→function isBeingDebugged() {
233→ const isBun = isRunningWithBun();
234→
235→ // Check for inspect flags in process arguments (including all variants)
236→ const hasInspectArg = process.execArgv.some(arg => {
237→ if (isBun) {
238→ // Note: Bun has an issue with single-file executables where application arguments
239→ // from process.argv leak into process.execArgv (similar to https://github.com/oven-sh/bun/issues/11673)
240→ // This breaks use of --debug mode if we omit this branch
241→ // We're fine to skip that check, because Bun doesn't support Node.js legacy --debug or --debug-brk flags
242→ return /--inspect(-brk)?/.test(arg);
243→ } else {
244→ // In Node.js, check for both --inspect and legacy --debug flags
245→ return /--inspect(-brk)?|--debug(-brk)?/.test(arg);
246→ }
247→ });
248→
249→ // Check if NODE_OPTIONS contains inspect flags
250→ const hasInspectEnv = process.env.NODE_OPTIONS && /--inspect(-brk)?|--debug(-brk)?/.test(process.env.NODE_OPTIONS);
251→
252→ // Check if inspector is available and active (indicates debugging)
253→ try {
254→ // Dynamic import would be better but is async - use global object instead
255→ // eslint-disable-next-line @typescript-eslint/no-explicit-any
256→ const inspector = (global as any).require('inspector');
257→ const hasInspectorUrl = !!inspector.url();
258→ return hasInspectorUrl || hasInspectArg || hasInspectEnv;
259→ } catch {
260→ // Ignore error and fall back to argument detection
261→ return hasInspectArg || hasInspectEnv;
262→ }
263→}
264→
265→// Exit if we detect node debugging or inspection
266→if ("external" !== 'ant' && isBeingDebugged()) {
267→ // Use process.exit directly here since we're in the top-level code before imports
268→ // and gracefulShutdown is not yet available
269→ // eslint-disable-next-line custom-rules/no-top-level-side-effects
270→ process.exit(1);
271→}
272→
273→/**
274→ * Per-session skill/plugin telemetry. Called from both the interactive path
275→ * and the headless -p path (before runHeadless) — both go through
276→ * main.tsx but branch before the interactive startup path, so it needs two
277→ * call sites here rather than one here + one in QueryEngine.
278→ */
279→function logSessionTelemetry(): void {
280→ const model = parseUserSpecifiedModel(getInitialMainLoopModel() ?? getDefaultMainLoopModel());
281→ void logSkillsLoaded(getCwd(), getContextWindowForModel(model, getSdkBetas()));
282→ void loadAllPluginsCacheOnly().then(({
283→ enabled,
284→ errors
285→ }) => {
286→ const managedNames = getManagedPluginNames();
287→ logPluginsEnabledForSession(enabled, managedNames, getPluginSeedDirs());
288→ logPluginLoadErrors(errors, managedNames);
289→ }).catch(err => logError(err));
290→}
291→function getCertEnvVarTelemetry(): Record<string, boolean> {
292→ const result: Record<string, boolean> = {};
293→ if (process.env.NODE_EXTRA_CA_CERTS) {
294→ result.has_node_extra_ca_certs = true;
295→ }
296→ if (process.env.CLAUDE_CODE_CLIENT_CERT) {
297→ result.has_client_cert = true;
298→ }
299→ if (hasNodeOption('--use-system-ca')) {Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/**/*.ts Status: Completed
src\QueryEngine.ts src\Task.ts src\Tool.ts src\assistant\sessionHistory.ts src\bootstrap\state.ts src\bridge\bridgeApi.ts src\bridge\bridgeConfig.ts src\bridge\bridgeDebug.ts src\bridge\bridgeEnabled.ts src\bridge\bridgeMain.ts src\bridge\bridgeMessaging.ts src\bridge\bridgePermissionCallbacks.ts src\bridge\bridgePointer.ts src\bridge\bridgeStatusUtil.ts src\bridge\bridgeUI.ts src\bridge\capacityWake.ts src\bridge\codeSessionApi.ts src\bridge\createSession.ts src\bridge\debugUtils.ts src\bridge\envLessBridgeConfig.ts src\bridge\flushGate.ts src\bridge\inboundAttachments.ts src\bridge\inboundMessages.ts src\bridge\initReplBridge.ts src\bridge\jwtUtils.ts src\bridge\pollConfig.ts src\bridge\pollConfigDefaults.ts src\bridge\remoteBridgeCore.ts src\bridge\replBridge.ts src\bridge\replBridgeHandle.ts src\bridge\replBridgeTransport.ts src\bridge\sessionIdCompat.ts src\bridge\sessionRunner.ts src\bridge\trustedDevice.ts src\bridge\types.ts src\bridge\workSecret.ts src\buddy\companion.ts src\buddy\prompt.ts src\buddy\sprites.ts src\buddy\types.ts src\cli\exit.ts src\cli\handlers\agents.ts src\cli\handlers\auth.ts src\cli\handlers\autoMode.ts src\cli\handlers\plugins.ts src\cli\ndjsonSafeStringify.ts src\cli\print.ts src\cli\remoteIO.ts src\cli\structuredIO.ts src\cli\transports\HybridTransport.ts src\cli\transports\SerialBatchEventUploader.ts src\cli\transports\SSETransport.ts src\cli\transports\WebSocketTransport.ts src\cli\transports\WorkerStateUploader.ts src\cli\transports\ccrClient.ts src\cli\transports\transportUtils.ts src\cli\update.ts src\commands.ts src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\index.ts src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\bridge-kick.ts src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\index.ts src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\index.ts src\commands\copy\index.ts src\commands\cost\cost.ts src\commands\cost\index.ts src\commands\createMovedToPluginCommand.ts src\commands\desktop\index.ts src\commands\diff\index.ts src\commands\doctor\index.ts src\commands\effort\index.ts src\commands\exit\index.ts src\commands\export\index.ts src\commands\extra-usage\extra-usage-core.ts src\commands\extra-usage\extra-usage-noninteractive.ts src\commands\extra-usage\index.ts src\commands\fast\index.ts src\commands\feedback\index.ts src\commands\files\files.ts src\commands\files\index.ts src\commands\heapdump\heapdump.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code *.json Status: Completed
No files found
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/**/*.tsx Status: Completed
src\buddy\CompanionSprite.tsx src\buddy\useBuddyNotification.tsx src\cli\handlers\mcp.tsx src\cli\handlers\util.tsx src\commands\add-dir\add-dir.tsx src\commands\agents\agents.tsx src\commands\bridge\bridge.tsx src\commands\btw\btw.tsx src\commands\chrome\chrome.tsx src\commands\config\config.tsx src\commands\context\context.tsx src\commands\copy\copy.tsx src\commands\desktop\desktop.tsx src\commands\diff\diff.tsx src\commands\doctor\doctor.tsx src\commands\effort\effort.tsx src\commands\exit\exit.tsx src\commands\export\export.tsx src\commands\extra-usage\extra-usage.tsx src\commands\fast\fast.tsx src\commands\feedback\feedback.tsx src\commands\help\help.tsx src\commands\hooks\hooks.tsx src\commands\ide\ide.tsx src\commands\install-github-app\ApiKeyStep.tsx src\commands\install-github-app\CheckExistingSecretStep.tsx src\commands\install-github-app\CheckGitHubStep.tsx src\commands\install-github-app\ChooseRepoStep.tsx src\commands\install-github-app\CreatingStep.tsx src\commands\install-github-app\ErrorStep.tsx src\commands\install-github-app\ExistingWorkflowStep.tsx src\commands\install-github-app\InstallAppStep.tsx src\commands\install-github-app\OAuthFlowStep.tsx src\commands\install-github-app\SuccessStep.tsx src\commands\install-github-app\WarningsStep.tsx src\commands\install-github-app\install-github-app.tsx src\commands\install.tsx src\commands\login\login.tsx src\commands\logout\logout.tsx src\commands\mcp\mcp.tsx src\commands\memory\memory.tsx src\commands\mobile\mobile.tsx src\commands\model\model.tsx src\commands\output-style\output-style.tsx src\commands\passes\passes.tsx src\commands\permissions\permissions.tsx src\commands\plan\plan.tsx src\commands\plugin\AddMarketplace.tsx src\commands\plugin\BrowseMarketplace.tsx src\commands\plugin\DiscoverPlugins.tsx src\commands\plugin\ManageMarketplaces.tsx src\commands\plugin\ManagePlugins.tsx src\commands\plugin\PluginErrors.tsx src\commands\plugin\PluginOptionsDialog.tsx src\commands\plugin\PluginOptionsFlow.tsx src\commands\plugin\PluginSettings.tsx src\commands\plugin\PluginTrustWarning.tsx src\commands\plugin\index.tsx src\commands\plugin\plugin.tsx src\commands\plugin\UnifiedInstalledCell.tsx src\commands\plugin\ValidatePlugin.tsx src\commands\plugin\pluginDetailsHelpers.tsx src\commands\privacy-settings\privacy-settings.tsx src\commands\rate-limit-options\rate-limit-options.tsx src\commands\remote-env\remote-env.tsx src\commands\remote-setup\remote-setup.tsx src\commands\resume\resume.tsx src\commands\review\UltrareviewOverageDialog.tsx src\commands\review\ultrareviewCommand.tsx src\commands\sandbox-toggle\sandbox-toggle.tsx src\commands\session\session.tsx src\commands\skills\skills.tsx src\commands\stats\stats.tsx src\commands\status\status.tsx src\commands\statusline.tsx src\commands\tag\tag.tsx src\commands\tasks\tasks.tsx src\commands\terminalSetup\terminalSetup.tsx src\commands\theme\theme.tsx src\commands\thinkback\thinkback.tsx src\commands\ultraplan.tsx src\commands\upgrade\upgrade.tsx src\commands\usage\usage.tsx src\components\AgentProgressLine.tsx src\components\App.tsx src\components\ApproveApiKey.tsx src\components\AutoModeOptInDialog.tsx src\components\AutoUpdater.tsx src\components\AutoUpdaterWrapper.tsx src\components\AwsAuthStatusBox.tsx src\components\BaseTextInput.tsx src\components\BashModeProgress.tsx src\components\BridgeDialog.tsx src\components\BypassPermissionsModeDialog.tsx src\components\ChannelDowngradeDialog.tsx src\components\ClaudeCodeHint\PluginHintMenu.tsx src\components\ClaudeInChromeOnboarding.tsx src\components\ClaudeMdExternalIncludesDialog.tsx src\components\ClickableImageRef.tsx src\components\CompactSummary.tsx (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/commands/**/*.{ts,tsx,js} Status: Completed
src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts src\commands\cost\cost.ts src\commands\cost\index.ts src\commands\createMovedToPluginCommand.ts src\commands\ctx_viz\index.js src\commands\debug-tool-call\index.js src\commands\desktop\desktop.tsx src\commands\desktop\index.ts src\commands\diff\diff.tsx src\commands\diff\index.ts src\commands\doctor\doctor.tsx src\commands\doctor\index.ts src\commands\effort\effort.tsx src\commands\effort\index.ts src\commands\env\index.js src\commands\exit\exit.tsx src\commands\exit\index.ts src\commands\export\export.tsx src\commands\export\index.ts src\commands\extra-usage\extra-usage-core.ts src\commands\extra-usage\extra-usage-noninteractive.ts src\commands\extra-usage\extra-usage.tsx src\commands\extra-usage\index.ts src\commands\fast\fast.tsx src\commands\fast\index.ts src\commands\feedback\feedback.tsx src\commands\feedback\index.ts src\commands\files\files.ts src\commands\files\index.ts src\commands\good-claude\index.js src\commands\heapdump\heapdump.ts src\commands\heapdump\index.ts src\commands\help\help.tsx src\commands\help\index.ts src\commands\hooks\hooks.tsx src\commands\hooks\index.ts src\commands\ide\ide.tsx src\commands\ide\index.ts src\commands\init-verifiers.ts src\commands\init.ts src\commands\insights.ts src\commands\install-github-app\ApiKeyStep.tsx src\commands\install-github-app\CheckExistingSecretStep.tsx src\commands\install-github-app\CheckGitHubStep.tsx src\commands\install-github-app\ChooseRepoStep.tsx src\commands\install-github-app\CreatingStep.tsx src\commands\install-github-app\ErrorStep.tsx src\commands\install-github-app\ExistingWorkflowStep.tsx src\commands\install-github-app\InstallAppStep.tsx src\commands\install-github-app\OAuthFlowStep.tsx src\commands\install-github-app\SuccessStep.tsx src\commands\install-github-app\WarningsStep.tsx src\commands\install-github-app\index.ts src\commands\install-github-app\install-github-app.tsx src\commands\install-github-app\setupGitHubActions.ts src\commands\install-slack-app\index.ts src\commands\install-slack-app\install-slack-app.ts src\commands\install.tsx src\commands\issue\index.js src\commands\keybindings\index.ts src\commands\keybindings\keybindings.ts src\commands\login\index.ts src\commands\login\login.tsx (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/**/*.{ts,tsx} Status: Completed
src\tools\AgentTool\AgentTool.tsx src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\UI.tsx src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\built-in\claudeCodeGuideAgent.ts src\tools\AgentTool\built-in\exploreAgent.ts src\tools\AgentTool\built-in\generalPurposeAgent.ts src\tools\AgentTool\built-in\planAgent.ts src\tools\AgentTool\built-in\statuslineSetup.ts src\tools\AgentTool\built-in\verificationAgent.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\runAgent.ts src\tools\AskUserQuestionTool\AskUserQuestionTool.tsx src\tools\AskUserQuestionTool\prompt.ts src\tools\BashTool\BashTool.tsx src\tools\BashTool\BashToolResultMessage.tsx src\tools\BashTool\UI.tsx src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts src\tools\BriefTool\BriefTool.ts src\tools\BriefTool\attachments.ts src\tools\BriefTool\prompt.ts src\tools\BriefTool\UI.tsx src\tools\BriefTool\upload.ts src\tools\ConfigTool\ConfigTool.ts src\tools\ConfigTool\constants.ts src\tools\ConfigTool\prompt.ts src\tools\ConfigTool\supportedSettings.ts src\tools\ConfigTool\UI.tsx src\tools\EnterPlanModeTool\constants.ts src\tools\EnterPlanModeTool\EnterPlanModeTool.ts src\tools\EnterPlanModeTool\prompt.ts src\tools\EnterPlanModeTool\UI.tsx src\tools\EnterWorktreeTool\constants.ts src\tools\EnterWorktreeTool\EnterWorktreeTool.ts src\tools\EnterWorktreeTool\prompt.ts src\tools\EnterWorktreeTool\UI.tsx src\tools\ExitPlanModeTool\constants.ts src\tools\ExitPlanModeTool\ExitPlanModeV2Tool.ts src\tools\ExitPlanModeTool\prompt.ts src\tools\ExitPlanModeTool\UI.tsx src\tools\ExitWorktreeTool\constants.ts src\tools\ExitWorktreeTool\ExitWorktreeTool.ts src\tools\ExitWorktreeTool\prompt.ts src\tools\ExitWorktreeTool\UI.tsx src\tools\FileEditTool\FileEditTool.ts src\tools\FileEditTool\constants.ts src\tools\FileEditTool\prompt.ts src\tools\FileEditTool\UI.tsx src\tools\FileEditTool\types.ts src\tools\FileEditTool\utils.ts src\tools\FileReadTool\FileReadTool.ts src\tools\FileReadTool\imageProcessor.ts src\tools\FileReadTool\limits.ts src\tools\FileReadTool\prompt.ts src\tools\FileReadTool\UI.tsx src\tools\FileWriteTool\FileWriteTool.ts src\tools\FileWriteTool\prompt.ts src\tools\FileWriteTool\UI.tsx src\tools\GlobTool\GlobTool.ts src\tools\GlobTool\prompt.ts src\tools\GlobTool\UI.tsx src\tools\GrepTool\GrepTool.ts src\tools\GrepTool\UI.tsx src\tools\GrepTool\prompt.ts src\tools\LSPTool\LSPTool.ts src\tools\LSPTool\UI.tsx src\tools\LSPTool\formatters.ts src\tools\LSPTool\prompt.ts src\tools\LSPTool\schemas.ts src\tools\LSPTool\symbolContext.ts src\tools\ListMcpResourcesTool\ListMcpResourcesTool.ts src\tools\ListMcpResourcesTool\prompt.ts src\tools\ListMcpResourcesTool\UI.tsx src\tools\MCPTool\MCPTool.ts src\tools\MCPTool\classifyForCollapse.ts src\tools\MCPTool\prompt.ts src\tools\MCPTool\UI.tsx src\tools\McpAuthTool\McpAuthTool.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\Tool.ts Status: Completed
1→import type {
2→ ToolResultBlockParam,
3→ ToolUseBlockParam,
4→} from '@anthropic-ai/sdk/resources/index.mjs'
5→import type {
6→ ElicitRequestURLParams,
7→ ElicitResult,
8→} from '@modelcontextprotocol/sdk/types.js'
9→import type { UUID } from 'crypto'
10→import type { z } from 'zod/v4'
11→import type { Command } from './commands.js'
12→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
13→import type { ThinkingConfig } from './utils/thinking.js'
14→
15→export type ToolInputJSONSchema = {
16→ [x: string]: unknown
17→ type: 'object'
18→ properties?: {
19→ [x: string]: unknown
20→ }
21→}
22→
23→import type { Notification } from './context/notifications.js'
24→import type {
25→ MCPServerConnection,
26→ ServerResource,
27→} from './services/mcp/types.js'
28→import type {
29→ AgentDefinition,
30→ AgentDefinitionsResult,
31→} from './tools/AgentTool/loadAgentsDir.js'
32→import type {
33→ AssistantMessage,
34→ AttachmentMessage,
35→ Message,
36→ ProgressMessage,
37→ SystemLocalCommandMessage,
38→ SystemMessage,
39→ UserMessage,
40→} from './types/message.js'
41→// Import permission types from centralized location to break import cycles
42→// Import PermissionResult from centralized location to break import cycles
43→import type {
44→ AdditionalWorkingDirectory,
45→ PermissionMode,
46→ PermissionResult,
47→} from './types/permissions.js'
48→// Import tool progress types from centralized location to break import cycles
49→import type {
50→ AgentToolProgress,
51→ BashProgress,
52→ MCPProgress,
53→ REPLToolProgress,
54→ SkillToolProgress,
55→ TaskOutputProgress,
56→ ToolProgressData,
57→ WebSearchProgress,
58→} from './types/tools.js'
59→import type { FileStateCache } from './utils/fileStateCache.js'
60→import type { DenialTrackingState } from './utils/permissions/denialTracking.js'
61→import type { SystemPrompt } from './utils/systemPromptType.js'
62→import type { ContentReplacementState } from './utils/toolResultStorage.js'
63→
64→// Re-export progress types for backwards compatibility
65→export type {
66→ AgentToolProgress,
67→ BashProgress,
68→ MCPProgress,
69→ REPLToolProgress,
70→ SkillToolProgress,
71→ TaskOutputProgress,
72→ WebSearchProgress,
73→}
74→
75→import type { SpinnerMode } from './components/Spinner.js'
76→import type { QuerySource } from './constants/querySource.js'
77→import type { SDKStatus } from './entrypoints/agentSdkTypes.js'
78→import type { AppState } from './state/AppState.js'
79→import type {
80→ HookProgress,
81→ PromptRequest,
82→ PromptResponse,
83→} from './types/hooks.js'
84→import type { AgentId } from './types/ids.js'
85→import type { DeepImmutable } from './types/utils.js'
86→import type { AttributionState } from './utils/commitAttribution.js'
87→import type { FileHistoryState } from './utils/fileHistory.js'
88→import type { Theme, ThemeName } from './utils/theme.js'
89→
90→export type QueryChainTracking = {
91→ chainId: string
92→ depth: number
93→}
94→
95→export type ValidationResult =
96→ | { result: true }
97→ | {
98→ result: false
99→ message: string
100→ errorCode: number
101→ }
102→
103→export type SetToolJSXFn = (
104→ args: {
105→ jsx: React.ReactNode | null
106→ shouldHidePromptInput: boolean
107→ shouldContinueAnimation?: true
108→ showSpinner?: boolean
109→ isLocalJSXCommand?: boolean
110→ isImmediate?: boolean
111→ /** Set to true to clear a local JSX command (e.g., from its onDone callback) */
112→ clearLocalJSX?: boolean
113→ } | null,
114→) => void
115→
116→// Import tool permission types from centralized location to break import cycles
117→import type { ToolPermissionRulesBySource } from './types/permissions.js'
118→
119→// Re-export for backwards compatibility
120→export type { ToolPermissionRulesBySource }
121→
122→// Apply DeepImmutable to the imported type
123→export type ToolPermissionContext = DeepImmutable<{
124→ mode: PermissionMode
125→ additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
126→ alwaysAllowRules: ToolPermissionRulesBySource
127→ alwaysDenyRules: ToolPermissionRulesBySource
128→ alwaysAskRules: ToolPermissionRulesBySource
129→ isBypassPermissionsModeAvailable: boolean
130→ isAutoModeAvailable?: boolean
131→ strippedDangerousRules?: ToolPermissionRulesBySource
132→ /** When true, permission prompts are auto-denied (e.g., background agents that can't show UI) */
133→ shouldAvoidPermissionPrompts?: boolean
134→ /** When true, automated checks (classifier, hooks) are awaited before showing the permission dialog (coordinator workers) */
135→ awaitAutomatedChecksBeforeDialog?: boolean
136→ /** Stores the permission mode before model-initiated plan mode entry, so it can be restored on exit */
137→ prePlanMode?: PermissionMode
138→}>
139→
140→export const getEmptyToolPermissionContext: () => ToolPermissionContext =
141→ () => ({
142→ mode: 'default',
143→ additionalWorkingDirectories: new Map(),
144→ alwaysAllowRules: {},
145→ alwaysDenyRules: {},
146→ alwaysAskRules: {},
147→ isBypassPermissionsModeAvailable: false,
148→ })
149→
150→export type CompactProgressEvent =
151→ | {
152→ type: 'hooks_start'
153→ hookType: 'pre_compact' | 'post_compact' | 'session_start'
154→ }
155→ | { type: 'compact_start' }
156→ | { type: 'compact_end' }
157→
158→export type ToolUseContext = {
159→ options: {
160→ commands: Command[]
161→ debug: boolean
162→ mainLoopModel: string
163→ tools: Tools
164→ verbose: boolean
165→ thinkingConfig: ThinkingConfig
166→ mcpClients: MCPServerConnection[]
167→ mcpResources: Record<string, ServerResource[]>
168→ isNonInteractiveSession: boolean
169→ agentDefinitions: AgentDefinitionsResult
170→ maxBudgetUsd?: number
171→ /** Custom system prompt that replaces the default system prompt */
172→ customSystemPrompt?: string
173→ /** Additional system prompt appended after the main system prompt */
174→ appendSystemPrompt?: string
175→ /** Override querySource for analytics tracking */
176→ querySource?: QuerySource
177→ /** Optional callback to get the latest tools (e.g., after MCP servers connect mid-query) */
178→ refreshTools?: () => Tools
179→ }
180→ abortController: AbortController
181→ readFileState: FileStateCache
182→ getAppState(): AppState
183→ setAppState(f: (prev: AppState) => AppState): void
184→ /**
185→ * Always-shared setAppState for session-scoped infrastructure (background
186→ * tasks, session hooks). Unlike setAppState, which is no-op for async agents
187→ * (see createSubagentContext), this always reaches the root store so agents
188→ * at any nesting depth can register/clean up infrastructure that outlives
189→ * a single turn. Only set by createSubagentContext; main-thread contexts
190→ * fall back to setAppState.
191→ */
192→ setAppStateForTasks?: (f: (prev: AppState) => AppState) => void
193→ /**
194→ * Optional handler for URL elicitations triggered by tool call errors (-32042).
195→ * In print/SDK mode, this delegates to structuredIO.handleElicitation.
196→ * In REPL mode, this is undefined and the queue-based UI path is used.
197→ */
198→ handleElicitation?: (
199→ serverName: string,
200→ params: ElicitRequestURLParams,
201→ signal: AbortSignal,
202→ ) => Promise<ElicitResult>
203→ setToolJSX?: SetToolJSXFn
204→ addNotification?: (notif: Notification) => void
205→ /** Append a UI-only system message to the REPL message list. Stripped at the
206→ * normalizeMessagesForAPI boundary — the Exclude<> makes that type-enforced. */
207→ appendSystemMessage?: (
208→ msg: Exclude<SystemMessage, SystemLocalCommandMessage>,
209→ ) => void
210→ /** Send an OS-level notification (iTerm2, Kitty, Ghostty, bell, etc.) */
211→ sendOSNotification?: (opts: {
212→ message: string
213→ notificationType: string
214→ }) => void
215→ nestedMemoryAttachmentTriggers?: Set<string>
216→ /**
217→ * CLAUDE.md paths already injected as nested_memory attachments this
218→ * session. Dedup for memoryFilesToAttachments — readFileState is an LRU
219→ * that evicts entries in busy sessions, so its .has() check alone can
220→ * re-inject the same CLAUDE.md dozens of times.
221→ */
222→ loadedNestedMemoryPaths?: Set<string>
223→ dynamicSkillDirTriggers?: Set<string>
224→ /** Skill names surfaced via skill_discovery this session. Telemetry only (feeds was_discovered). */
225→ discoveredSkillNames?: Set<string>
226→ userModified?: boolean
227→ setInProgressToolUseIDs: (f: (prev: Set<string>) => Set<string>) => void
228→ /** Only wired in interactive (REPL) contexts; SDK/QueryEngine don't set this. */
229→ setHasInterruptibleToolInProgress?: (v: boolean) => void
230→ setResponseLength: (f: (prev: number) => number) => void
231→ /** Ant-only: push a new API metrics entry for OTPS tracking.
232→ * Called by subagent streaming when a new API request starts. */
233→ pushApiMetricsEntry?: (ttftMs: number) => void
234→ setStreamMode?: (mode: SpinnerMode) => void
235→ onCompactProgress?: (event: CompactProgressEvent) => void
236→ setSDKStatus?: (status: SDKStatus) => void
237→ openMessageSelector?: () => void
238→ updateFileHistoryState: (
239→ updater: (prev: FileHistoryState) => FileHistoryState,
240→ ) => void
241→ updateAttributionState: (
242→ updater: (prev: AttributionState) => AttributionState,
243→ ) => void
244→ setConversationId?: (id: UUID) => void
245→ agentId?: AgentId // Only set for subagents; use getSessionId() for session ID. Hooks use this to distinguish subagent calls.
246→ agentType?: string // Subagent type name. For the main thread's --agent type, hooks fall back to getMainThreadAgentType().
247→ /** When true, canUseTool must always be called even when hooks auto-approve.
248→ * Used by speculation for overlay file path rewriting. */
249→ requireCanUseTool?: boolean
250→ messages: Message[]
251→ fileReadingLimits?: {
252→ maxTokens?: number
253→ maxSizeBytes?: number
254→ }
255→ globLimits?: {
256→ maxResults?: number
257→ }
258→ toolDecisions?: Map<
259→ string,
260→ {
261→ source: string
262→ decision: 'accept' | 'reject'
263→ timestamp: number
264→ }
265→ >
266→ queryTracking?: QueryChainTracking
267→ /** Callback factory for requesting interactive prompts from the user.
268→ * Returns a prompt callback bound to the given source name.
269→ * Only available in interactive (REPL) contexts. */
270→ requestPrompt?: (
271→ sourceName: string,
272→ toolInputSummary?: string | null,
273→ ) => (request: PromptRequest) => Promise<PromptResponse>
274→ toolUseId?: string
275→ criticalSystemReminder_EXPERIMENTAL?: string
276→ /** When true, preserve toolUseResult on messages even for subagents.
277→ * Used by in-process teammates whose transcripts are viewable by the user. */
278→ preserveToolUseResults?: boolean
279→ /** Local denial tracking state for async subagents whose setAppState is a
280→ * no-op. Without this, the denial counter never accumulates and the
281→ * fallback-to-prompting threshold is never reached. Mutable — the
282→ * permissions code updates it in place. */
283→ localDenialTracking?: DenialTrackingState
284→ /**
285→ * Per-conversation-thread content replacement state for the tool result
286→ * budget. When present, query.ts applies the aggregate tool result budget.
287→ * Main thread: REPL provisions once (never resets — stale UUID keys
288→ * are inert). Subagents: createSubagentContext clones the parent's state
289→ * by default (cache-sharing forks need identical decisions), or
290→ * resumeAgentBackground threads one reconstructed from sidechain records.
291→ */
292→ contentReplacementState?: ContentReplacementState
293→ /**
294→ * Parent's rendered system prompt bytes, frozen at turn start.
295→ * Used by fork subagents to share the parent's prompt cache — re-calling
296→ * getSystemPrompt() at fork-spawn time can diverge (GrowthBook cold→warm)
297→ * and bust the cache. See forkSubagent.ts.
298→ */
299→ renderedSystemPrompt?: SystemPrompt
300→}
301→
302→// Re-export ToolProgressData from centralized location
303→export type { ToolProgressData }
304→
305→export type Progress = ToolProgressData | HookProgress
306→
307→export type ToolProgress<P extends ToolProgressData> = {
308→ toolUseID: string
309→ data: P
310→}
311→
312→export function filterToolProgressMessages(
313→ progressMessagesForMessage: ProgressMessage[],
314→): ProgressMessage<ToolProgressData>[] {
315→ return progressMessagesForMessage.filter(
316→ (msg): msg is ProgressMessage<ToolProgressData> =>
317→ msg.data?.type !== 'hook_progress',
318→ )
319→}
320→
321→export type ToolResult<T> = {
322→ data: T
323→ newMessages?: (
324→ | UserMessage
325→ | AssistantMessage
326→ | AttachmentMessage
327→ | SystemMessage
328→ )[]
329→ // contextModifier is only honored for tools that aren't concurrency safe.
330→ contextModifier?: (context: ToolUseContext) => ToolUseContext
331→ /** MCP protocol metadata (structuredContent, _meta) to pass through to SDK consumers */
332→ mcpMeta?: {
333→ _meta?: Record<string, unknown>
334→ structuredContent?: Record<string, unknown>
335→ }
336→}
337→
338→export type ToolCallProgress<P extends ToolProgressData = ToolProgressData> = (
339→ progress: ToolProgress<P>,
340→) => void
341→
342→// Type for any schema that outputs an object with string keys
343→export type AnyObject = z.ZodType<{ [key: string]: unknown }>
344→
345→/**
346→ * Checks if a tool matches the given name (primary name or alias).
347→ */
348→export function toolMatchesName(
349→ tool: { name: string; aliases?: string[] },
350→ name: string,
351→): boolean {
352→ return tool.name === name || (tool.aliases?.includes(name) ?? false)
353→}
354→
355→/**
356→ * Finds a tool by name or alias from a list of tools.
357→ */
358→export function findToolByName(tools: Tools, name: string): Tool | undefined {
359→ return tools.find(t => toolMatchesName(t, name))
360→}
361→
362→export type Tool<
363→ Input extends AnyObject = AnyObject,
364→ Output = unknown,
365→ P extends ToolProgressData = ToolProgressData,
366→> = {
367→ /**
368→ * Optional aliases for backwards compatibility when a tool is renamed.
369→ * The tool can be looked up by any of these names in addition to its primary name.
370→ */
371→ aliases?: string[]
372→ /**
373→ * One-line capability phrase used by ToolSearch for keyword matching.
374→ * Helps the model find this tool via keyword search when it's deferred.
375→ * 3–10 words, no trailing period.
376→ * Prefer terms not already in the tool name (e.g. 'jupyter' for NotebookEdit).
377→ */
378→ searchHint?: string
379→ call(
380→ args: z.infer<Input>,
381→ context: ToolUseContext,
382→ canUseTool: CanUseToolFn,
383→ parentMessage: AssistantMessage,
384→ onProgress?: ToolCallProgress<P>,
385→ ): Promise<ToolResult<Output>>
386→ description(
387→ input: z.infer<Input>,
388→ options: {
389→ isNonInteractiveSession: boolean
390→ toolPermissionContext: ToolPermissionContext
391→ tools: Tools
392→ },
393→ ): Promise<string>
394→ readonly inputSchema: Input
395→ // Type for MCP tools that can specify their input schema directly in JSON Schema format
396→ // rather than converting from Zod schema
397→ readonly inputJSONSchema?: ToolInputJSONSchema
398→ // Optional because TungstenTool doesn't define this. TODO: Make it required.
399→ // When we do that, we can also go through and make this a bit more type-safe.
400→ outputSchema?: z.ZodType<unknown>
401→ inputsEquivalent?(a: z.infer<Input>, b: z.infer<Input>): boolean
402→ isConcurrencySafe(input: z.infer<Input>): boolean
403→ isEnabled(): boolean
404→ isReadOnly(input: z.infer<Input>): boolean
405→ /** Defaults to false. Only set when the tool performs irreversible operations (delete, overwrite, send). */
406→ isDestructive?(input: z.infer<Input>): boolean
407→ /**
408→ * What should happen when the user submits a new message while this tool
409→ * is running.
410→ *
411→ * - `'cancel'` — stop the tool and discard its result
412→ * - `'block'` — keep running; the new message waits
413→ *
414→ * Defaults to `'block'` when not implemented.
415→ */
416→ interruptBehavior?(): 'cancel' | 'block'
417→ /**
418→ * Returns information about whether this tool use is a search or read operation
419→ * that should be collapsed into a condensed display in the UI. Examples include
420→ * file searching (Grep, Glob), file reading (Read), and bash commands like find,
421→ * grep, wc, etc.
422→ *
423→ * Returns an object indicating whether the operation is a search or read operation:
424→ * - `isSearch: true` for search operations (grep, find, glob patterns)
425→ * - `isRead: true` for read operations (cat, head, tail, file read)
426→ * - `isList: true` for directory-listing operations (ls, tree, du)
427→ * - All can be false if the operation shouldn't be collapsed
428→ */
429→ isSearchOrReadCommand?(input: z.infer<Input>): {
430→ isSearch: boolean
431→ isRead: boolean
432→ isList?: boolean
433→ }
434→ isOpenWorld?(input: z.infer<Input>): boolean
435→ requiresUserInteraction?(): boolean
436→ isMcp?: boolean
437→ isLsp?: boolean
438→ /**
439→ * When true, this tool is deferred (sent with defer_loading: true) and requires
440→ * ToolSearch to be used before it can be called.
441→ */
442→ readonly shouldDefer?: boolean
443→ /**
444→ * When true, this tool is never deferred — its full schema appears in the
445→ * initial prompt even when ToolSearch is enabled. For MCP tools, set via
446→ * `_meta['anthropic/alwaysLoad']`. Use for tools the model must see on
447→ * turn 1 without a ToolSearch round-trip.
448→ */
449→ readonly alwaysLoad?: boolean
450→ /**
451→ * For MCP tools: the server and tool names as received from the MCP server (unnormalized).
452→ * Present on all MCP tools regardless of whether `name` is prefixed (mcp__server__tool)
453→ * or unprefixed (CLAUDE_AGENT_SDK_MCP_NO_PREFIX mode).
454→ */
455→ mcpInfo?: { serverName: string; toolName: string }
456→ readonly name: string
457→ /**
458→ * Maximum size in characters for tool result before it gets persisted to disk.
459→ * When exceeded, the result is saved to a file and Claude receives a preview
460→ * with the file path instead of the full content.
461→ *
462→ * Set to Infinity for tools whose output must never be persisted (e.g. Read,
463→ * where persisting creates a circular Read→file→Read loop and the tool
464→ * already self-bounds via its own limits).
465→ */
466→ maxResultSizeChars: number
467→ /**
468→ * When true, enables strict mode for this tool, which causes the API to
469→ * more strictly adhere to tool instructions and parameter schemas.
470→ * Only applied when the tengu_tool_pear is enabled.
471→ */
472→ readonly strict?: boolean
473→
474→ /**
475→ * Called on copies of tool_use input before observers see it (SDK stream,
476→ * transcript, canUseTool, PreToolUse/PostToolUse hooks). Mutate in place
477→ * to add legacy/derived fields. Must be idempotent. The original API-bound
478→ * input is never mutated (preserves prompt cache). Not re-applied when a
479→ * hook/permission returns a fresh updatedInput — those own their shape.
480→ */
481→ backfillObservableInput?(input: Record<string, unknown>): void
482→
483→ /**
484→ * Determines if this tool is allowed to run with this input in the current context.
485→ * It informs the model of why the tool use failed, and does not directly display any UI.
486→ * @param input
487→ * @param context
488→ */
489→ validateInput?(
490→ input: z.infer<Input>,
491→ context: ToolUseContext,
492→ ): Promise<ValidationResult>
493→
494→ /**
495→ * Determines if the user is asked for permission. Only called after validateInput() passes.
496→ * General permission logic is in permissions.ts. This method contains tool-specific logic.
497→ * @param input
498→ * @param context
499→ */
500→ checkPermissions(
501→ input: z.infer<Input>,
502→ context: ToolUseContext,
503→ ): Promise<PermissionResult>
504→
505→ // Optional method for tools that operate on a file path
506→ getPath?(input: z.infer<Input>): string
507→
508→ /**
509→ * Prepare a matcher for hook `if` conditions (permission-rule patterns like
510→ * "git *" from "Bash(git *)"). Called once per hook-input pair; any
511→ * expensive parsing happens here. Returns a closure that is called per
512→ * hook pattern. If not implemented, only tool-name-level matching works.
513→ */
514→ preparePermissionMatcher?(
515→ input: z.infer<Input>,
516→ ): Promise<(pattern: string) => boolean>
517→
518→ prompt(options: {
519→ getToolPermissionContext: () => Promise<ToolPermissionContext>
520→ tools: Tools
521→ agents: AgentDefinition[]
522→ allowedAgentTypes?: string[]
523→ }): Promise<string>
524→ userFacingName(input: Partial<z.infer<Input>> | undefined): string
525→ userFacingNameBackgroundColor?(
526→ input: Partial<z.infer<Input>> | undefined,
527→ ): keyof Theme | undefined
528→ /**
529→ * Transparent wrappers (e.g. REPL) delegate all rendering to their progress
530→ * handler, which emits native-looking blocks for each inner tool call.
531→ * The wrapper itself shows nothing.
532→ */
533→ isTransparentWrapper?(): boolean
534→ /**
535→ * Returns a short string summary of this tool use for display in compact views.
536→ * @param input The tool input
537→ * @returns A short string summary, or null to not display
538→ */
539→ getToolUseSummary?(input: Partial<z.infer<Input>> | undefined): string | null
540→ /**
541→ * Returns a human-readable present-tense activity description for spinner display.
542→ * Example: "Reading src/foo.ts", "Running bun test", "Searching for pattern"
543→ * @param input The tool input
544→ * @returns Activity description string, or null to fall back to tool name
545→ */
546→ getActivityDescription?(
547→ input: Partial<z.infer<Input>> | undefined,
548→ ): string | null
549→ /**
550→ * Returns a compact representation of this tool use for the auto-mode
551→ * security classifier. Examples: `ls -la` for Bash, `/tmp/x: new content`
552→ * for Edit. Return '' to skip this tool in the classifier transcript
553→ * (e.g. tools with no security relevance). May return an object to avoid
554→ * double-encoding when the caller JSON-wraps the value.
555→ */
556→ toAutoClassifierInput(input: z.infer<Input>): unknown
557→ mapToolResultToToolResultBlockParam(
558→ content: Output,
559→ toolUseID: string,
560→ ): ToolResultBlockParam
561→ /**
562→ * Optional. When omitted, the tool result renders nothing (same as returning
563→ * null). Omit for tools whose results are surfaced elsewhere (e.g., TodoWrite
564→ * updates the todo panel, not the transcript).
565→ */
566→ renderToolResultMessage?(
567→ content: Output,
568→ progressMessagesForMessage: ProgressMessage<P>[],
569→ options: {
570→ style?: 'condensed'
571→ theme: ThemeName
572→ tools: Tools
573→ verbose: boolean
574→ isTranscriptMode?: boolean
575→ isBriefOnly?: boolean
576→ /** Original tool_use input, when available. Useful for compact result
577→ * summaries that reference what was requested (e.g. "Sent to #foo"). */
578→ input?: unknown
579→ },
580→ ): React.ReactNode
581→ /**
582→ * Flattened text of what renderToolResultMessage shows IN TRANSCRIPT
583→ * MODE (verbose=true, isTranscriptMode=true). For transcript search
584→ * indexing: the index counts occurrences in this string, the highlight
585→ * overlay scans the actual screen buffer. For count ≡ highlight, this
586→ * must return the text that ends up visible — not the model-facing
587→ * serialization from mapToolResultToToolResultBlockParam (which adds
588→ * system-reminders, persisted-output wrappers).
589→ *
590→ * Chrome can be skipped (under-count is fine). "Found 3 files in 12ms"
591→ * isn't worth indexing. Phantoms are not fine — text that's claimed
592→ * here but doesn't render is a count≠highlight bug.
593→ *
594→ * Optional: omitted → field-name heuristic in transcriptSearch.ts.
595→ * Drift caught by test/utils/transcriptSearch.renderFidelity.test.tsx
596→ * which renders sample outputs and flags text that's indexed-but-not-
597→ * rendered (phantom) or rendered-but-not-indexed (under-count warning).
598→ */
599→ extractSearchText?(out: Output): string
600→ /**
601→ * Render the tool use message. Note that `input` is partial because we render
602→ * the message as soon as possible, possibly before tool parameters have fully
603→ * streamed in.
604→ */
605→ renderToolUseMessage(
606→ input: Partial<z.infer<Input>>,
607→ options: { theme: ThemeName; verbose: boolean; commands?: Command[] },
608→ ): React.ReactNode
609→ /**
610→ * Returns true when the non-verbose rendering of this output is truncated
611→ * (i.e., clicking to expand would reveal more content). Gates
612→ * click-to-expand in fullscreen — only messages where verbose actually
613→ * shows more get a hover/click affordance. Unset means never truncated.
614→ */
615→ isResultTruncated?(output: Output): boolean
616→ /**
617→ * Renders an optional tag to display after the tool use message.
618→ * Used for additional metadata like timeout, model, resume ID, etc.
619→ * Returns null to not display anything.
620→ */
621→ renderToolUseTag?(input: Partial<z.infer<Input>>): React.ReactNode
622→ /**
623→ * Optional. When omitted, no progress UI is shown while the tool runs.
624→ */
625→ renderToolUseProgressMessage?(
626→ progressMessagesForMessage: ProgressMessage<P>[],
627→ options: {
628→ tools: Tools
629→ verbose: boolean
630→ terminalSize?: { columns: number; rows: number }
631→ inProgressToolCallCount?: number
632→ isTranscriptMode?: boolean
633→ },
634→ ): React.ReactNode
635→ renderToolUseQueuedMessage?(): React.ReactNode
636→ /**
637→ * Optional. When omitted, falls back to <FallbackToolUseRejectedMessage />.
638→ * Only define this for tools that need custom rejection UI (e.g., file edits
639→ * that show the rejected diff).
640→ */
641→ renderToolUseRejectedMessage?(
642→ input: z.infer<Input>,
643→ options: {
644→ columns: number
645→ messages: Message[]
646→ style?: 'condensed'
647→ theme: ThemeName
648→ tools: Tools
649→ verbose: boolean
650→ progressMessagesForMessage: ProgressMessage<P>[]
651→ isTranscriptMode?: boolean
652→ },
653→ ): React.ReactNode
654→ /**
655→ * Optional. When omitted, falls back to <FallbackToolUseErrorMessage />.
656→ * Only define this for tools that need custom error UI (e.g., search tools
657→ * that show "File not found" instead of the raw error).
658→ */
659→ renderToolUseErrorMessage?(
660→ result: ToolResultBlockParam['content'],
661→ options: {
662→ progressMessagesForMessage: ProgressMessage<P>[]
663→ tools: Tools
664→ verbose: boolean
665→ isTranscriptMode?: boolean
666→ },
667→ ): React.ReactNode
668→
669→ /**
670→ * Renders multiple parallel instances of this tool as a group.
671→ * @returns React node to render, or null to fall back to individual rendering
672→ */
673→ /**
674→ * Renders multiple tool uses as a group (non-verbose mode only).
675→ * In verbose mode, individual tool uses render at their original positions.
676→ * @returns React node to render, or null to fall back to individual rendering
677→ */
678→ renderGroupedToolUse?(
679→ toolUses: Array<{
680→ param: ToolUseBlockParam
681→ isResolved: boolean
682→ isError: boolean
683→ isInProgress: boolean
684→ progressMessages: ProgressMessage<P>[]
685→ result?: {
686→ param: ToolResultBlockParam
687→ output: unknown
688→ }
689→ }>,
690→ options: {
691→ shouldAnimate: boolean
692→ tools: Tools
693→ },
694→ ): React.ReactNode | null
695→}
696→
697→/**
698→ * A collection of tools. Use this type instead of `Tool[]` to make it easier
699→ * to track where tool sets are assembled, passed, and filtered across the codebase.
700→ */
701→export type Tools = readonly Tool[]
702→
703→/**
704→ * Methods that `buildTool` supplies a default for. A `ToolDef` may omit these;
705→ * the resulting `Tool` always has them.
706→ */
707→type DefaultableToolKeys =
708→ | 'isEnabled'
709→ | 'isConcurrencySafe'
710→ | 'isReadOnly'
711→ | 'isDestructive'
712→ | 'checkPermissions'
713→ | 'toAutoClassifierInput'
714→ | 'userFacingName'
715→
716→/**
717→ * Tool definition accepted by `buildTool`. Same shape as `Tool` but with the
718→ * defaultable methods optional — `buildTool` fills them in so callers always
719→ * see a complete `Tool`.
720→ */
721→export type ToolDef<
722→ Input extends AnyObject = AnyObject,
723→ Output = unknown,
724→ P extends ToolProgressData = ToolProgressData,
725→> = Omit<Tool<Input, Output, P>, DefaultableToolKeys> &
726→ Partial<Pick<Tool<Input, Output, P>, DefaultableToolKeys>>
727→
728→/**
729→ * Type-level spread mirroring `{ ...TOOL_DEFAULTS, ...def }`. For each
730→ * defaultable key: if D provides it (required), D's type wins; if D omits
731→ * it or has it optional (inherited from Partial<> in the constraint), the
732→ * default fills in. All other keys come from D verbatim — preserving arity,
733→ * optional presence, and literal types exactly as `satisfies Tool` did.
734→ */
735→type BuiltTool<D> = Omit<D, DefaultableToolKeys> & {
736→ [K in DefaultableToolKeys]-?: K extends keyof D
737→ ? undefined extends D[K]
738→ ? ToolDefaults[K]
739→ : D[K]
740→ : ToolDefaults[K]
741→}
742→
743→/**
744→ * Build a complete `Tool` from a partial definition, filling in safe defaults
745→ * for the commonly-stubbed methods. All tool exports should go through this so
746→ * that defaults live in one place and callers never need `?.() ?? default`.
747→ *
748→ * Defaults (fail-closed where it matters):
749→ * - `isEnabled` → `true`
750→ * - `isConcurrencySafe` → `false` (assume not safe)
751→ * - `isReadOnly` → `false` (assume writes)
752→ * - `isDestructive` → `false`
753→ * - `checkPermissions` → `{ behavior: 'allow', updatedInput }` (defer to general permission system)
754→ * - `toAutoClassifierInput` → `''` (skip classifier — security-relevant tools must override)
755→ * - `userFacingName` → `name`
756→ */
757→const TOOL_DEFAULTS = {
758→ isEnabled: () => true,
759→ isConcurrencySafe: (_input?: unknown) => false,
760→ isReadOnly: (_input?: unknown) => false,
761→ isDestructive: (_input?: unknown) => false,
762→ checkPermissions: (
763→ input: { [key: string]: unknown },
764→ _ctx?: ToolUseContext,
765→ ): Promise<PermissionResult> =>
766→ Promise.resolve({ behavior: 'allow', updatedInput: input }),
767→ toAutoClassifierInput: (_input?: unknown) => '',
768→ userFacingName: (_input?: unknown) => '',
769→}
770→
771→// The defaults type is the ACTUAL shape of TOOL_DEFAULTS (optional params so
772→// both 0-arg and full-arg call sites type-check — stubs varied in arity and
773→// tests relied on that), not the interface's strict signatures.
774→type ToolDefaults = typeof TOOL_DEFAULTS
775→
776→// D infers the concrete object-literal type from the call site. The
777→// constraint provides contextual typing for method parameters; `any` in
778→// constraint position is structural and never leaks into the return type.
779→// BuiltTool<D> mirrors runtime `{...TOOL_DEFAULTS, ...def}` at the type level.
780→// eslint-disable-next-line @typescript-eslint/no-explicit-any
781→type AnyToolDef = ToolDef<any, any, any>
782→
783→export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
784→ // The runtime spread is straightforward; the `as` bridges the gap between
785→ // the structural-any constraint and the precise BuiltTool<D> return. The
786→ // type semantics are proven by the 0-error typecheck across all 60+ tools.
787→ return {
788→ ...TOOL_DEFAULTS,
789→ userFacingName: () => def.name,
790→ ...def,
791→ } as BuiltTool<D>
792→}
793→Tool Call: Find D:\code\play\stock_ai_rust\claude-code\src *.json Status: Completed
No files found
Tool Call: Read src\Task.ts Status: Completed
1→import { randomBytes } from 'crypto'
2→import type { AppState } from './state/AppState.js'
3→import type { AgentId } from './types/ids.js'
4→import { getTaskOutputPath } from './utils/task/diskOutput.js'
5→
6→export type TaskType =
7→ | 'local_bash'
8→ | 'local_agent'
9→ | 'remote_agent'
10→ | 'in_process_teammate'
11→ | 'local_workflow'
12→ | 'monitor_mcp'
13→ | 'dream'
14→
15→export type TaskStatus =
16→ | 'pending'
17→ | 'running'
18→ | 'completed'
19→ | 'failed'
20→ | 'killed'
21→
22→/**
23→ * True when a task is in a terminal state and will not transition further.
24→ * Used to guard against injecting messages into dead teammates, evicting
25→ * finished tasks from AppState, and orphan-cleanup paths.
26→ */
27→export function isTerminalTaskStatus(status: TaskStatus): boolean {
28→ return status === 'completed' || status === 'failed' || status === 'killed'
29→}
30→
31→export type TaskHandle = {
32→ taskId: string
33→ cleanup?: () => void
34→}
35→
36→export type SetAppState = (f: (prev: AppState) => AppState) => void
37→
38→export type TaskContext = {
39→ abortController: AbortController
40→ getAppState: () => AppState
41→ setAppState: SetAppState
42→}
43→
44→// Base fields shared by all task states
45→export type TaskStateBase = {
46→ id: string
47→ type: TaskType
48→ status: TaskStatus
49→ description: string
50→ toolUseId?: string
51→ startTime: number
52→ endTime?: number
53→ totalPausedMs?: number
54→ outputFile: string
55→ outputOffset: number
56→ notified: boolean
57→}
58→
59→export type LocalShellSpawnInput = {
60→ command: string
61→ description: string
62→ timeout?: number
63→ toolUseId?: string
64→ agentId?: AgentId
65→ /** UI display variant: description-as-label, dialog title, status bar pill. */
66→ kind?: 'bash' | 'monitor'
67→}
68→
69→// What getTaskByType dispatches for: kill. spawn/render were never
70→// called polymorphically (removed in #22546). All six kill implementations
71→// use only setAppState — getAppState/abortController were dead weight.
72→export type Task = {
73→ name: string
74→ type: TaskType
75→ kill(taskId: string, setAppState: SetAppState): Promise<void>
76→}
77→
78→// Task ID prefixes
79→const TASK_ID_PREFIXES: Record<string, string> = {
80→ local_bash: 'b', // Keep as 'b' for backward compatibility
81→ local_agent: 'a',
82→ remote_agent: 'r',
83→ in_process_teammate: 't',
84→ local_workflow: 'w',
85→ monitor_mcp: 'm',
86→ dream: 'd',
87→}
88→
89→// Get task ID prefix
90→function getTaskIdPrefix(type: TaskType): string {
91→ return TASK_ID_PREFIXES[type] ?? 'x'
92→}
93→
94→// Case-insensitive-safe alphabet (digits + lowercase) for task IDs.
95→// 36^8 ≈ 2.8 trillion combinations, sufficient to resist brute-force symlink attacks.
96→const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
97→
98→export function generateTaskId(type: TaskType): string {
99→ const prefix = getTaskIdPrefix(type)
100→ const bytes = randomBytes(8)
101→ let id = prefix
102→ for (let i = 0; i < 8; i++) {
103→ id += TASK_ID_ALPHABET[bytes[i]! % TASK_ID_ALPHABET.length]
104→ }
105→ return id
106→}
107→
108→export function createTaskStateBase(
109→ id: string,
110→ type: TaskType,
111→ description: string,
112→ toolUseId?: string,
113→): TaskStateBase {
114→ return {
115→ id,
116→ type,
117→ status: 'pending',
118→ description,
119→ toolUseId,
120→ startTime: Date.now(),
121→ outputFile: getTaskOutputPath(id),
122→ outputOffset: 0,
123→ notified: false,
124→ }
125→}
126→Tool Call: Read src\QueryEngine.ts Status: Completed
1→import { feature } from 'bun:bundle'
2→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
3→import { randomUUID } from 'crypto'
4→import last from 'lodash-es/last.js'
5→import {
6→ getSessionId,
7→ isSessionPersistenceDisabled,
8→} from 'src/bootstrap/state.js'
9→import type {
10→ PermissionMode,
11→ SDKCompactBoundaryMessage,
12→ SDKMessage,
13→ SDKPermissionDenial,
14→ SDKStatus,
15→ SDKUserMessageReplay,
16→} from 'src/entrypoints/agentSdkTypes.js'
17→import { accumulateUsage, updateUsage } from 'src/services/api/claude.js'
18→import type { NonNullableUsage } from 'src/services/api/logging.js'
19→import { EMPTY_USAGE } from 'src/services/api/logging.js'
20→import stripAnsi from 'strip-ansi'
21→import type { Command } from './commands.js'
22→import { getSlashCommandToolSkills } from './commands.js'
23→import {
24→ LOCAL_COMMAND_STDERR_TAG,
25→ LOCAL_COMMAND_STDOUT_TAG,
26→} from './constants/xml.js'
27→import {
28→ getModelUsage,
29→ getTotalAPIDuration,
30→ getTotalCost,
31→} from './cost-tracker.js'
32→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
33→import { loadMemoryPrompt } from './memdir/memdir.js'
34→import { hasAutoMemPathOverride } from './memdir/paths.js'
35→import { query } from './query.js'
36→import { categorizeRetryableAPIError } from './services/api/errors.js'
37→import type { MCPServerConnection } from './services/mcp/types.js'
38→import type { AppState } from './state/AppState.js'
39→import { type Tools, type ToolUseContext, toolMatchesName } from './Tool.js'
40→import type { AgentDefinition } from './tools/AgentTool/loadAgentsDir.js'
41→import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js'
42→import type { Message } from './types/message.js'
43→import type { OrphanedPermission } from './types/textInputTypes.js'
44→import { createAbortController } from './utils/abortController.js'
45→import type { AttributionState } from './utils/commitAttribution.js'
46→import { getGlobalConfig } from './utils/config.js'
47→import { getCwd } from './utils/cwd.js'
48→import { isBareMode, isEnvTruthy } from './utils/envUtils.js'
49→import { getFastModeState } from './utils/fastMode.js'
50→import {
51→ type FileHistoryState,
52→ fileHistoryEnabled,
53→ fileHistoryMakeSnapshot,
54→} from './utils/fileHistory.js'
55→import {
56→ cloneFileStateCache,
57→ type FileStateCache,
58→} from './utils/fileStateCache.js'
59→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
60→import { registerStructuredOutputEnforcement } from './utils/hooks/hookHelpers.js'
61→import { getInMemoryErrors } from './utils/log.js'
62→import { countToolCalls, SYNTHETIC_MESSAGES } from './utils/messages.js'
63→import {
64→ getMainLoopModel,
65→ parseUserSpecifiedModel,
66→} from './utils/model/model.js'
67→import { loadAllPluginsCacheOnly } from './utils/plugins/pluginLoader.js'
68→import {
69→ type ProcessUserInputContext,
70→ processUserInput,
71→} from './utils/processUserInput/processUserInput.js'
72→import { fetchSystemPromptParts } from './utils/queryContext.js'
73→import { setCwd } from './utils/Shell.js'
74→import {
75→ flushSessionStorage,
76→ recordTranscript,
77→} from './utils/sessionStorage.js'
78→import { asSystemPrompt } from './utils/systemPromptType.js'
79→import { resolveThemeSetting } from './utils/systemTheme.js'
80→import {
81→ shouldEnableThinkingByDefault,
82→ type ThinkingConfig,
83→} from './utils/thinking.js'
84→
85→// Lazy: MessageSelector.tsx pulls React/ink; only needed for message filtering at query time
86→/* eslint-disable @typescript-eslint/no-require-imports */
87→const messageSelector =
88→ (): typeof import('src/components/MessageSelector.js') =>
89→ require('src/components/MessageSelector.js')
90→
91→import {
92→ localCommandOutputToSDKAssistantMessage,
93→ toSDKCompactMetadata,
94→} from './utils/messages/mappers.js'
95→import {
96→ buildSystemInitMessage,
97→ sdkCompatToolName,
98→} from './utils/messages/systemInit.js'
99→import {
100→ getScratchpadDir,
101→ isScratchpadEnabled,
102→} from './utils/permissions/filesystem.js'
103→/* eslint-enable @typescript-eslint/no-require-imports */
104→import {
105→ handleOrphanedPermission,
106→ isResultSuccessful,
107→ normalizeMessage,
108→} from './utils/queryHelpers.js'
109→
110→// Dead code elimination: conditional import for coordinator mode
111→/* eslint-disable @typescript-eslint/no-require-imports */
112→const getCoordinatorUserContext: (
113→ mcpClients: ReadonlyArray<{ name: string }>,
114→ scratchpadDir?: string,
115→) => { [k: string]: string } = feature('COORDINATOR_MODE')
116→ ? require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
117→ : () => ({})
118→/* eslint-enable @typescript-eslint/no-require-imports */
119→
120→// Dead code elimination: conditional import for snip compaction
121→/* eslint-disable @typescript-eslint/no-require-imports */
122→const snipModule = feature('HISTORY_SNIP')
123→ ? (require('./services/compact/snipCompact.js') as typeof import('./services/compact/snipCompact.js'))
124→ : null
125→const snipProjection = feature('HISTORY_SNIP')
126→ ? (require('./services/compact/snipProjection.js') as typeof import('./services/compact/snipProjection.js'))
127→ : null
128→/* eslint-enable @typescript-eslint/no-require-imports */
129→
130→export type QueryEngineConfig = {
131→ cwd: string
132→ tools: Tools
133→ commands: Command[]
134→ mcpClients: MCPServerConnection[]
135→ agents: AgentDefinition[]
136→ canUseTool: CanUseToolFn
137→ getAppState: () => AppState
138→ setAppState: (f: (prev: AppState) => AppState) => void
139→ initialMessages?: Message[]
140→ readFileCache: FileStateCache
141→ customSystemPrompt?: string
142→ appendSystemPrompt?: string
143→ userSpecifiedModel?: string
144→ fallbackModel?: string
145→ thinkingConfig?: ThinkingConfig
146→ maxTurns?: number
147→ maxBudgetUsd?: number
148→ taskBudget?: { total: number }
149→ jsonSchema?: Record<string, unknown>
150→ verbose?: boolean
151→ replayUserMessages?: boolean
152→ /** Handler for URL elicitations triggered by MCP tool -32042 errors. */
153→ handleElicitation?: ToolUseContext['handleElicitation']
154→ includePartialMessages?: boolean
155→ setSDKStatus?: (status: SDKStatus) => void
156→ abortController?: AbortController
157→ orphanedPermission?: OrphanedPermission
158→ /**
159→ * Snip-boundary handler: receives each yielded system message plus the
160→ * current mutableMessages store. Returns undefined if the message is not a
161→ * snip boundary; otherwise returns the replayed snip result. Injected by
162→ * ask() when HISTORY_SNIP is enabled so feature-gated strings stay inside
163→ * the gated module (keeps QueryEngine free of excluded strings and testable
164→ * despite feature() returning false under bun test). SDK-only: the REPL
165→ * keeps full history for UI scrollback and projects on demand via
166→ * projectSnippedView; QueryEngine truncates here to bound memory in long
167→ * headless sessions (no UI to preserve).
168→ */
169→ snipReplay?: (
170→ yieldedSystemMsg: Message,
171→ store: Message[],
172→ ) => { messages: Message[]; executed: boolean } | undefined
173→}
174→
175→/**
176→ * QueryEngine owns the query lifecycle and session state for a conversation.
177→ * It extracts the core logic from ask() into a standalone class that can be
178→ * used by both the headless/SDK path and (in a future phase) the REPL.
179→ *
180→ * One QueryEngine per conversation. Each submitMessage() call starts a new
181→ * turn within the same conversation. State (messages, file cache, usage, etc.)
182→ * persists across turns.
183→ */
184→export class QueryEngine {
185→ private config: QueryEngineConfig
186→ private mutableMessages: Message[]
187→ private abortController: AbortController
188→ private permissionDenials: SDKPermissionDenial[]
189→ private totalUsage: NonNullableUsage
190→ private hasHandledOrphanedPermission = false
191→ private readFileState: FileStateCache
192→ // Turn-scoped skill discovery tracking (feeds was_discovered on
193→ // tengu_skill_tool_invocation). Must persist across the two
194→ // processUserInputContext rebuilds inside submitMessage, but is cleared
195→ // at the start of each submitMessage to avoid unbounded growth across
196→ // many turns in SDK mode.
197→ private discoveredSkillNames = new Set<string>()
198→ private loadedNestedMemoryPaths = new Set<string>()
199→
200→ constructor(config: QueryEngineConfig) {
201→ this.config = config
202→ this.mutableMessages = config.initialMessages ?? []
203→ this.abortController = config.abortController ?? createAbortController()
204→ this.permissionDenials = []
205→ this.readFileState = config.readFileCache
206→ this.totalUsage = EMPTY_USAGE
207→ }
208→
209→ async *submitMessage(
210→ prompt: string | ContentBlockParam[],
211→ options?: { uuid?: string; isMeta?: boolean },
212→ ): AsyncGenerator<SDKMessage, void, unknown> {
213→ const {
214→ cwd,
215→ commands,
216→ tools,
217→ mcpClients,
218→ verbose = false,
219→ thinkingConfig,
220→ maxTurns,
221→ maxBudgetUsd,
222→ taskBudget,
223→ canUseTool,
224→ customSystemPrompt,
225→ appendSystemPrompt,
226→ userSpecifiedModel,
227→ fallbackModel,
228→ jsonSchema,
229→ getAppState,
230→ setAppState,
231→ replayUserMessages = false,
232→ includePartialMessages = false,
233→ agents = [],
234→ setSDKStatus,
235→ orphanedPermission,
236→ } = this.config
237→
238→ this.discoveredSkillNames.clear()
239→ setCwd(cwd)
240→ const persistSession = !isSessionPersistenceDisabled()
241→ const startTime = Date.now()
242→
243→ // Wrap canUseTool to track permission denials
244→ const wrappedCanUseTool: CanUseToolFn = async (
245→ tool,
246→ input,
247→ toolUseContext,
248→ assistantMessage,
249→ toolUseID,
250→ forceDecision,
251→ ) => {
252→ const result = await canUseTool(
253→ tool,
254→ input,
255→ toolUseContext,
256→ assistantMessage,
257→ toolUseID,
258→ forceDecision,
259→ )
260→
261→ // Track denials for SDK reporting
262→ if (result.behavior !== 'allow') {
263→ this.permissionDenials.push({
264→ tool_name: sdkCompatToolName(tool.name),
265→ tool_use_id: toolUseID,
266→ tool_input: input,
267→ })
268→ }
269→
270→ return result
271→ }
272→
273→ const initialAppState = getAppState()
274→ const initialMainLoopModel = userSpecifiedModel
275→ ? parseUserSpecifiedModel(userSpecifiedModel)
276→ : getMainLoopModel()
277→
278→ const initialThinkingConfig: ThinkingConfig = thinkingConfig
279→ ? thinkingConfig
280→ : shouldEnableThinkingByDefault() !== false
281→ ? { type: 'adaptive' }
282→ : { type: 'disabled' }
283→
284→ headlessProfilerCheckpoint('before_getSystemPrompt')
285→ // Narrow once so TS tracks the type through the conditionals below.
286→ const customPrompt =
287→ typeof customSystemPrompt === 'string' ? customSystemPrompt : undefined
288→ const {
289→ defaultSystemPrompt,
290→ userContext: baseUserContext,
291→ systemContext,
292→ } = await fetchSystemPromptParts({
293→ tools,
294→ mainLoopModel: initialMainLoopModel,
295→ additionalWorkingDirectories: Array.from(
296→ initialAppState.toolPermissionContext.additionalWorkingDirectories.keys(),
297→ ),
298→ mcpClients,
299→ customSystemPrompt: customPrompt,
300→ })
301→ headlessProfilerCheckpoint('after_getSystemPrompt')
302→ const userContext = {
303→ ...baseUserContext,
304→ ...getCoordinatorUserContext(
305→ mcpClients,
306→ isScratchpadEnabled() ? getScratchpadDir() : undefined,
307→ ),
308→ }
309→
310→ // When an SDK caller provides a custom system prompt AND has set
311→ // CLAUDE_COWORK_MEMORY_PATH_OVERRIDE, inject the memory-mechanics prompt.
312→ // The env var is an explicit opt-in signal — the caller has wired up
313→ // a memory directory and needs Claude to know how to use it (which
314→ // Write/Edit tools to call, MEMORY.md filename, loading semantics).
315→ // The caller can layer their own policy text via appendSystemPrompt.
316→ const memoryMechanicsPrompt =
317→ customPrompt !== undefined && hasAutoMemPathOverride()
318→ ? await loadMemoryPrompt()
319→ : null
320→
321→ const systemPrompt = asSystemPrompt([
322→ ...(customPrompt !== undefined ? [customPrompt] : defaultSystemPrompt),
323→ ...(memoryMechanicsPrompt ? [memoryMechanicsPrompt] : []),
324→ ...(appendSystemPrompt ? [appendSystemPrompt] : []),
325→ ])
326→
327→ // Register function hook for structured output enforcement
328→ const hasStructuredOutputTool = tools.some(t =>
329→ toolMatchesName(t, SYNTHETIC_OUTPUT_TOOL_NAME),
330→ )
331→ if (jsonSchema && hasStructuredOutputTool) {
332→ registerStructuredOutputEnforcement(setAppState, getSessionId())
333→ }
334→
335→ let processUserInputContext: ProcessUserInputContext = {
336→ messages: this.mutableMessages,
337→ // Slash commands that mutate the message array (e.g. /force-snip)
338→ // call setMessages(fn). In interactive mode this writes back to
339→ // AppState; in print mode we write back to mutableMessages so the
340→ // rest of the query loop (push at :389, snapshot at :392) sees
341→ // the result. The second processUserInputContext below (after
342→ // slash-command processing) keeps the no-op — nothing else calls
343→ // setMessages past that point.
344→ setMessages: fn => {
345→ this.mutableMessages = fn(this.mutableMessages)
346→ },
347→ onChangeAPIKey: () => {},
348→ handleElicitation: this.config.handleElicitation,
349→ options: {
350→ commands,
351→ debug: false, // we use stdout, so don't want to clobber it
352→ tools,
353→ verbose,
354→ mainLoopModel: initialMainLoopModel,
355→ thinkingConfig: initialThinkingConfig,
356→ mcpClients,
357→ mcpResources: {},
358→ ideInstallationStatus: null,
359→ isNonInteractiveSession: true,
360→ customSystemPrompt,
361→ appendSystemPrompt,
362→ agentDefinitions: { activeAgents: agents, allAgents: [] },
363→ theme: resolveThemeSetting(getGlobalConfig().theme),
364→ maxBudgetUsd,
365→ },
366→ getAppState,
367→ setAppState,
368→ abortController: this.abortController,
369→ readFileState: this.readFileState,
370→ nestedMemoryAttachmentTriggers: new Set<string>(),
371→ loadedNestedMemoryPaths: this.loadedNestedMemoryPaths,
372→ dynamicSkillDirTriggers: new Set<string>(),
373→ discoveredSkillNames: this.discoveredSkillNames,
374→ setInProgressToolUseIDs: () => {},
375→ setResponseLength: () => {},
376→ updateFileHistoryState: (
377→ updater: (prev: FileHistoryState) => FileHistoryState,
378→ ) => {
379→ setAppState(prev => {
380→ const updated = updater(prev.fileHistory)
381→ if (updated === prev.fileHistory) return prev
382→ return { ...prev, fileHistory: updated }
383→ })
384→ },
385→ updateAttributionState: (
386→ updater: (prev: AttributionState) => AttributionState,
387→ ) => {
388→ setAppState(prev => {
389→ const updated = updater(prev.attribution)
390→ if (updated === prev.attribution) return prev
391→ return { ...prev, attribution: updated }
392→ })
393→ },
394→ setSDKStatus,
395→ }
396→
397→ // Handle orphaned permission (only once per engine lifetime)
398→ if (orphanedPermission && !this.hasHandledOrphanedPermission) {
399→ this.hasHandledOrphanedPermission = true
400→ for await (const message of handleOrphanedPermission(
401→ orphanedPermission,
402→ tools,
403→ this.mutableMessages,
404→ processUserInputContext,
405→ )) {
406→ yield message
407→ }
408→ }
409→
410→ const {
411→ messages: messagesFromUserInput,
412→ shouldQuery,
413→ allowedTools,
414→ model: modelFromUserInput,
415→ resultText,
416→ } = await processUserInput({
417→ input: prompt,
418→ mode: 'prompt',
419→ setToolJSX: () => {},
420→ context: {
421→ ...processUserInputContext,
422→ messages: this.mutableMessages,
423→ },
424→ messages: this.mutableMessages,
425→ uuid: options?.uuid,
426→ isMeta: options?.isMeta,
427→ querySource: 'sdk',
428→ })
429→
430→ // Push new messages, including user input and any attachments
431→ this.mutableMessages.push(...messagesFromUserInput)
432→
433→ // Update params to reflect updates from processing /slash commands
434→ const messages = [...this.mutableMessages]
435→
436→ // Persist the user's message(s) to transcript BEFORE entering the query
437→ // loop. The for-await below only calls recordTranscript when ask() yields
438→ // an assistant/user/compact_boundary message — which doesn't happen until
439→ // the API responds. If the process is killed before that (e.g. user clicks
440→ // Stop in cowork seconds after send), the transcript is left with only
441→ // queue-operation entries; getLastSessionLog filters those out, returns
442→ // null, and --resume fails with "No conversation found". Writing now makes
443→ // the transcript resumable from the point the user message was accepted,
444→ // even if no API response ever arrives.
445→ //
446→ // --bare / SIMPLE: fire-and-forget. Scripted calls don't --resume after
447→ // kill-mid-request. The await is ~4ms on SSD, ~30ms under disk contention
448→ // — the single largest controllable critical-path cost after module eval.
449→ // Transcript is still written (for post-hoc debugging); just not blocking.
450→ if (persistSession && messagesFromUserInput.length > 0) {
451→ const transcriptPromise = recordTranscript(messages)
452→ if (isBareMode()) {
453→ void transcriptPromise
454→ } else {
455→ await transcriptPromise
456→ if (
457→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
458→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
459→ ) {
460→ await flushSessionStorage()
461→ }
462→ }
463→ }
464→
465→ // Filter messages that should be acknowledged after transcript
466→ const replayableMessages = messagesFromUserInput.filter(
467→ msg =>
468→ (msg.type === 'user' &&
469→ !msg.isMeta && // Skip synthetic caveat messages
470→ !msg.toolUseResult && // Skip tool results (they'll be acked from query)
471→ messageSelector().selectableUserMessagesFilter(msg)) || // Skip non-user-authored messages (task notifications, etc.)
472→ (msg.type === 'system' && msg.subtype === 'compact_boundary'), // Always ack compact boundaries
473→ )
474→ const messagesToAck = replayUserMessages ? replayableMessages : []
475→
476→ // Update the ToolPermissionContext based on user input processing (as necessary)
477→ setAppState(prev => ({
478→ ...prev,
479→ toolPermissionContext: {
480→ ...prev.toolPermissionContext,
481→ alwaysAllowRules: {
482→ ...prev.toolPermissionContext.alwaysAllowRules,
483→ command: allowedTools,
484→ },
485→ },
486→ }))
487→
488→ const mainLoopModel = modelFromUserInput ?? initialMainLoopModel
489→
490→ // Recreate after processing the prompt to pick up updated messages and
491→ // model (from slash commands).
492→ processUserInputContext = {
493→ messages,
494→ setMessages: () => {},
495→ onChangeAPIKey: () => {},
496→ handleElicitation: this.config.handleElicitation,
497→ options: {
498→ commands,
499→ debug: false,
500→ tools,
501→ verbose,
502→ mainLoopModel,
503→ thinkingConfig: initialThinkingConfig,
504→ mcpClients,
505→ mcpResources: {},
506→ ideInstallationStatus: null,
507→ isNonInteractiveSession: true,
508→ customSystemPrompt,
509→ appendSystemPrompt,
510→ theme: resolveThemeSetting(getGlobalConfig().theme),
511→ agentDefinitions: { activeAgents: agents, allAgents: [] },
512→ maxBudgetUsd,
513→ },
514→ getAppState,
515→ setAppState,
516→ abortController: this.abortController,
517→ readFileState: this.readFileState,
518→ nestedMemoryAttachmentTriggers: new Set<string>(),
519→ loadedNestedMemoryPaths: this.loadedNestedMemoryPaths,
520→ dynamicSkillDirTriggers: new Set<string>(),
521→ discoveredSkillNames: this.discoveredSkillNames,
522→ setInProgressToolUseIDs: () => {},
523→ setResponseLength: () => {},
524→ updateFileHistoryState: processUserInputContext.updateFileHistoryState,
525→ updateAttributionState: processUserInputContext.updateAttributionState,
526→ setSDKStatus,
527→ }
528→
529→ headlessProfilerCheckpoint('before_skills_plugins')
530→ // Cache-only: headless/SDK/CCR startup must not block on network for
531→ // ref-tracked plugins. CCR populates the cache via CLAUDE_CODE_SYNC_PLUGIN_INSTALL
532→ // (headlessPluginInstall) or CLAUDE_CODE_PLUGIN_SEED_DIR before this runs;
533→ // SDK callers that need fresh source can call /reload-plugins.
534→ const [skills, { enabled: enabledPlugins }] = await Promise.all([
535→ getSlashCommandToolSkills(getCwd()),
536→ loadAllPluginsCacheOnly(),
537→ ])
538→ headlessProfilerCheckpoint('after_skills_plugins')
539→
540→ yield buildSystemInitMessage({
541→ tools,
542→ mcpClients,
543→ model: mainLoopModel,
544→ permissionMode: initialAppState.toolPermissionContext
545→ .mode as PermissionMode, // TODO: avoid the cast
546→ commands,
547→ agents,
548→ skills,
549→ plugins: enabledPlugins,
550→ fastMode: initialAppState.fastMode,
551→ })
552→
553→ // Record when system message is yielded for headless latency tracking
554→ headlessProfilerCheckpoint('system_message_yielded')
555→
556→ if (!shouldQuery) {
557→ // Return the results of local slash commands.
558→ // Use messagesFromUserInput (not replayableMessages) for command output
559→ // because selectableUserMessagesFilter excludes local-command-stdout tags.
560→ for (const msg of messagesFromUserInput) {
561→ if (
562→ msg.type === 'user' &&
563→ typeof msg.message.content === 'string' &&
564→ (msg.message.content.includes(`<${LOCAL_COMMAND_STDOUT_TAG}>`) ||
565→ msg.message.content.includes(`<${LOCAL_COMMAND_STDERR_TAG}>`) ||
566→ msg.isCompactSummary)
567→ ) {
568→ yield {
569→ type: 'user',
570→ message: {
571→ ...msg.message,
572→ content: stripAnsi(msg.message.content),
573→ },
574→ session_id: getSessionId(),
575→ parent_tool_use_id: null,
576→ uuid: msg.uuid,
577→ timestamp: msg.timestamp,
578→ isReplay: !msg.isCompactSummary,
579→ isSynthetic: msg.isMeta || msg.isVisibleInTranscriptOnly,
580→ } as SDKUserMessageReplay
581→ }
582→
583→ // Local command output — yield as a synthetic assistant message so
584→ // RC renders it as assistant-style text rather than a user bubble.
585→ // Emitted as assistant (not the dedicated SDKLocalCommandOutputMessage
586→ // system subtype) so mobile clients + session-ingress can parse it.
587→ if (
588→ msg.type === 'system' &&
589→ msg.subtype === 'local_command' &&
590→ typeof msg.content === 'string' &&
591→ (msg.content.includes(`<${LOCAL_COMMAND_STDOUT_TAG}>`) ||
592→ msg.content.includes(`<${LOCAL_COMMAND_STDERR_TAG}>`))
593→ ) {
594→ yield localCommandOutputToSDKAssistantMessage(msg.content, msg.uuid)
595→ }
596→
597→ if (msg.type === 'system' && msg.subtype === 'compact_boundary') {
598→ yield {
599→ type: 'system',
600→ subtype: 'compact_boundary' as const,
601→ session_id: getSessionId(),
602→ uuid: msg.uuid,
603→ compact_metadata: toSDKCompactMetadata(msg.compactMetadata),
604→ } as SDKCompactBoundaryMessage
605→ }
606→ }
607→
608→ if (persistSession) {
609→ await recordTranscript(messages)
610→ if (
611→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
612→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
613→ ) {
614→ await flushSessionStorage()
615→ }
616→ }
617→
618→ yield {
619→ type: 'result',
620→ subtype: 'success',
621→ is_error: false,
622→ duration_ms: Date.now() - startTime,
623→ duration_api_ms: getTotalAPIDuration(),
624→ num_turns: messages.length - 1,
625→ result: resultText ?? '',
626→ stop_reason: null,
627→ session_id: getSessionId(),
628→ total_cost_usd: getTotalCost(),
629→ usage: this.totalUsage,
630→ modelUsage: getModelUsage(),
631→ permission_denials: this.permissionDenials,
632→ fast_mode_state: getFastModeState(
633→ mainLoopModel,
634→ initialAppState.fastMode,
635→ ),
636→ uuid: randomUUID(),
637→ }
638→ return
639→ }
640→
641→ if (fileHistoryEnabled() && persistSession) {
642→ messagesFromUserInput
643→ .filter(messageSelector().selectableUserMessagesFilter)
644→ .forEach(message => {
645→ void fileHistoryMakeSnapshot(
646→ (updater: (prev: FileHistoryState) => FileHistoryState) => {
647→ setAppState(prev => ({
648→ ...prev,
649→ fileHistory: updater(prev.fileHistory),
650→ }))
651→ },
652→ message.uuid,
653→ )
654→ })
655→ }
656→
657→ // Track current message usage (reset on each message_start)
658→ let currentMessageUsage: NonNullableUsage = EMPTY_USAGE
659→ let turnCount = 1
660→ let hasAcknowledgedInitialMessages = false
661→ // Track structured output from StructuredOutput tool calls
662→ let structuredOutputFromTool: unknown
663→ // Track the last stop_reason from assistant messages
664→ let lastStopReason: string | null = null
665→ // Reference-based watermark so error_during_execution's errors[] is
666→ // turn-scoped. A length-based index breaks when the 100-entry ring buffer
667→ // shift()s during the turn — the index slides. If this entry is rotated
668→ // out, lastIndexOf returns -1 and we include everything (safe fallback).
669→ const errorLogWatermark = getInMemoryErrors().at(-1)
670→ // Snapshot count before this query for delta-based retry limiting
671→ const initialStructuredOutputCalls = jsonSchema
672→ ? countToolCalls(this.mutableMessages, SYNTHETIC_OUTPUT_TOOL_NAME)
673→ : 0
674→
675→ for await (const message of query({
676→ messages,
677→ systemPrompt,
678→ userContext,
679→ systemContext,
680→ canUseTool: wrappedCanUseTool,
681→ toolUseContext: processUserInputContext,
682→ fallbackModel,
683→ querySource: 'sdk',
684→ maxTurns,
685→ taskBudget,
686→ })) {
687→ // Record assistant, user, and compact boundary messages
688→ if (
689→ message.type === 'assistant' ||
690→ message.type === 'user' ||
691→ (message.type === 'system' && message.subtype === 'compact_boundary')
692→ ) {
693→ // Before writing a compact boundary, flush any in-memory-only
694→ // messages up through the preservedSegment tail. Attachments and
695→ // progress are now recorded inline (their switch cases below), but
696→ // this flush still matters for the preservedSegment tail walk.
697→ // If the SDK subprocess restarts before then (claude-desktop kills
698→ // between turns), tailUuid points to a never-written message →
699→ // applyPreservedSegmentRelinks fails its tail→head walk → returns
700→ // without pruning → resume loads full pre-compact history.
701→ if (
702→ persistSession &&
703→ message.type === 'system' &&
704→ message.subtype === 'compact_boundary'
705→ ) {
706→ const tailUuid = message.compactMetadata?.preservedSegment?.tailUuid
707→ if (tailUuid) {
708→ const tailIdx = this.mutableMessages.findLastIndex(
709→ m => m.uuid === tailUuid,
710→ )
711→ if (tailIdx !== -1) {
712→ await recordTranscript(this.mutableMessages.slice(0, tailIdx + 1))
713→ }
714→ }
715→ }
716→ messages.push(message)
717→ if (persistSession) {
718→ // Fire-and-forget for assistant messages. claude.ts yields one
719→ // assistant message per content block, then mutates the last
720→ // one's message.usage/stop_reason on message_delta — relying on
721→ // the write queue's 100ms lazy jsonStringify. Awaiting here
722→ // blocks ask()'s generator, so message_delta can't run until
723→ // every block is consumed; the drain timer (started at block 1)
724→ // elapses first. Interactive CC doesn't hit this because
725→ // useLogMessages.ts fire-and-forgets. enqueueWrite is
726→ // order-preserving so fire-and-forget here is safe.
727→ if (message.type === 'assistant') {
728→ void recordTranscript(messages)
729→ } else {
730→ await recordTranscript(messages)
731→ }
732→ }
733→
734→ // Acknowledge initial user messages after first transcript recording
735→ if (!hasAcknowledgedInitialMessages && messagesToAck.length > 0) {
736→ hasAcknowledgedInitialMessages = true
737→ for (const msgToAck of messagesToAck) {
738→ if (msgToAck.type === 'user') {
739→ yield {
740→ type: 'user',
741→ message: msgToAck.message,
742→ session_id: getSessionId(),
743→ parent_tool_use_id: null,
744→ uuid: msgToAck.uuid,
745→ timestamp: msgToAck.timestamp,
746→ isReplay: true,
747→ } as SDKUserMessageReplay
748→ }
749→ }
750→ }
751→ }
752→
753→ if (message.type === 'user') {
754→ turnCount++
755→ }
756→
757→ switch (message.type) {
758→ case 'tombstone':
759→ // Tombstone messages are control signals for removing messages, skip them
760→ break
761→ case 'assistant':
762→ // Capture stop_reason if already set (synthetic messages). For
763→ // streamed responses, this is null at content_block_stop time;
764→ // the real value arrives via message_delta (handled below).
765→ if (message.message.stop_reason != null) {
766→ lastStopReason = message.message.stop_reason
767→ }
768→ this.mutableMessages.push(message)
769→ yield* normalizeMessage(message)
770→ break
771→ case 'progress':
772→ this.mutableMessages.push(message)
773→ // Record inline so the dedup loop in the next ask() call sees it
774→ // as already-recorded. Without this, deferred progress interleaves
775→ // with already-recorded tool_results in mutableMessages, and the
776→ // dedup walk freezes startingParentUuid at the wrong message —
777→ // forking the chain and orphaning the conversation on resume.
778→ if (persistSession) {
779→ messages.push(message)
780→ void recordTranscript(messages)
781→ }
782→ yield* normalizeMessage(message)
783→ break
784→ case 'user':
785→ this.mutableMessages.push(message)
786→ yield* normalizeMessage(message)
787→ break
788→ case 'stream_event':
789→ if (message.event.type === 'message_start') {
790→ // Reset current message usage for new message
791→ currentMessageUsage = EMPTY_USAGE
792→ currentMessageUsage = updateUsage(
793→ currentMessageUsage,
794→ message.event.message.usage,
795→ )
796→ }
797→ if (message.event.type === 'message_delta') {
798→ currentMessageUsage = updateUsage(
799→ currentMessageUsage,
800→ message.event.usage,
801→ )
802→ // Capture stop_reason from message_delta. The assistant message
803→ // is yielded at content_block_stop with stop_reason=null; the
804→ // real value only arrives here (see claude.ts message_delta
805→ // handler). Without this, result.stop_reason is always null.
806→ if (message.event.delta.stop_reason != null) {
807→ lastStopReason = message.event.delta.stop_reason
808→ }
809→ }
810→ if (message.event.type === 'message_stop') {
811→ // Accumulate current message usage into total
812→ this.totalUsage = accumulateUsage(
813→ this.totalUsage,
814→ currentMessageUsage,
815→ )
816→ }
817→
818→ if (includePartialMessages) {
819→ yield {
820→ type: 'stream_event' as const,
821→ event: message.event,
822→ session_id: getSessionId(),
823→ parent_tool_use_id: null,
824→ uuid: randomUUID(),
825→ }
826→ }
827→
828→ break
829→ case 'attachment':
830→ this.mutableMessages.push(message)
831→ // Record inline (same reason as progress above).
832→ if (persistSession) {
833→ messages.push(message)
834→ void recordTranscript(messages)
835→ }
836→
837→ // Extract structured output from StructuredOutput tool calls
838→ if (message.attachment.type === 'structured_output') {
839→ structuredOutputFromTool = message.attachment.data
840→ }
841→ // Handle max turns reached signal from query.ts
842→ else if (message.attachment.type === 'max_turns_reached') {
843→ if (persistSession) {
844→ if (
845→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
846→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
847→ ) {
848→ await flushSessionStorage()
849→ }
850→ }
851→ yield {
852→ type: 'result',
853→ subtype: 'error_max_turns',
854→ duration_ms: Date.now() - startTime,
855→ duration_api_ms: getTotalAPIDuration(),
856→ is_error: true,
857→ num_turns: message.attachment.turnCount,
858→ stop_reason: lastStopReason,
859→ session_id: getSessionId(),
860→ total_cost_usd: getTotalCost(),
861→ usage: this.totalUsage,
862→ modelUsage: getModelUsage(),
863→ permission_denials: this.permissionDenials,
864→ fast_mode_state: getFastModeState(
865→ mainLoopModel,
866→ initialAppState.fastMode,
867→ ),
868→ uuid: randomUUID(),
869→ errors: [
870→ `Reached maximum number of turns (${message.attachment.maxTurns})`,
871→ ],
872→ }
873→ return
874→ }
875→ // Yield queued_command attachments as SDK user message replays
876→ else if (
877→ replayUserMessages &&
878→ message.attachment.type === 'queued_command'
879→ ) {
880→ yield {
881→ type: 'user',
882→ message: {
883→ role: 'user' as const,
884→ content: message.attachment.prompt,
885→ },
886→ session_id: getSessionId(),
887→ parent_tool_use_id: null,
888→ uuid: message.attachment.source_uuid || message.uuid,
889→ timestamp: message.timestamp,
890→ isReplay: true,
891→ } as SDKUserMessageReplay
892→ }
893→ break
894→ case 'stream_request_start':
895→ // Don't yield stream request start messages
896→ break
897→ case 'system': {
898→ // Snip boundary: replay on our store to remove zombie messages and
899→ // stale markers. The yielded boundary is a signal, not data to push —
900→ // the replay produces its own equivalent boundary. Without this,
901→ // markers persist and re-trigger on every turn, and mutableMessages
902→ // never shrinks (memory leak in long SDK sessions). The subtype
903→ // check lives inside the injected callback so feature-gated strings
904→ // stay out of this file (excluded-strings check).
905→ const snipResult = this.config.snipReplay?.(
906→ message,
907→ this.mutableMessages,
908→ )
909→ if (snipResult !== undefined) {
910→ if (snipResult.executed) {
911→ this.mutableMessages.length = 0
912→ this.mutableMessages.push(...snipResult.messages)
913→ }
914→ break
915→ }
916→ this.mutableMessages.push(message)
917→ // Yield compact boundary messages to SDK
918→ if (
919→ message.subtype === 'compact_boundary' &&
920→ message.compactMetadata
921→ ) {
922→ // Release pre-compaction messages for GC. The boundary was just
923→ // pushed so it's the last element. query.ts already uses
924→ // getMessagesAfterCompactBoundary() internally, so only
925→ // post-boundary messages are needed going forward.
926→ const mutableBoundaryIdx = this.mutableMessages.length - 1
927→ if (mutableBoundaryIdx > 0) {
928→ this.mutableMessages.splice(0, mutableBoundaryIdx)
929→ }
930→ const localBoundaryIdx = messages.length - 1
931→ if (localBoundaryIdx > 0) {
932→ messages.splice(0, localBoundaryIdx)
933→ }
934→
935→ yield {
936→ type: 'system',
937→ subtype: 'compact_boundary' as const,
938→ session_id: getSessionId(),
939→ uuid: message.uuid,
940→ compact_metadata: toSDKCompactMetadata(message.compactMetadata),
941→ }
942→ }
943→ if (message.subtype === 'api_error') {
944→ yield {
945→ type: 'system',
946→ subtype: 'api_retry' as const,
947→ attempt: message.retryAttempt,
948→ max_retries: message.maxRetries,
949→ retry_delay_ms: message.retryInMs,
950→ error_status: message.error.status ?? null,
951→ error: categorizeRetryableAPIError(message.error),
952→ session_id: getSessionId(),
953→ uuid: message.uuid,
954→ }
955→ }
956→ // Don't yield other system messages in headless mode
957→ break
958→ }
959→ case 'tool_use_summary':
960→ // Yield tool use summary messages to SDK
961→ yield {
962→ type: 'tool_use_summary' as const,
963→ summary: message.summary,
964→ preceding_tool_use_ids: message.precedingToolUseIds,
965→ session_id: getSessionId(),
966→ uuid: message.uuid,
967→ }
968→ break
969→ }
970→
971→ // Check if USD budget has been exceeded
972→ if (maxBudgetUsd !== undefined && getTotalCost() >= maxBudgetUsd) {
973→ if (persistSession) {
974→ if (
975→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
976→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
977→ ) {
978→ await flushSessionStorage()
979→ }
980→ }
981→ yield {
982→ type: 'result',
983→ subtype: 'error_max_budget_usd',
984→ duration_ms: Date.now() - startTime,
985→ duration_api_ms: getTotalAPIDuration(),
986→ is_error: true,
987→ num_turns: turnCount,
988→ stop_reason: lastStopReason,
989→ session_id: getSessionId(),
990→ total_cost_usd: getTotalCost(),
991→ usage: this.totalUsage,
992→ modelUsage: getModelUsage(),
993→ permission_denials: this.permissionDenials,
994→ fast_mode_state: getFastModeState(
995→ mainLoopModel,
996→ initialAppState.fastMode,
997→ ),
998→ uuid: randomUUID(),
999→ errors: [`Reached maximum budget ($${maxBudgetUsd})`],
1000→ }
1001→ return
1002→ }
1003→
1004→ // Check if structured output retry limit exceeded (only on user messages)
1005→ if (message.type === 'user' && jsonSchema) {
1006→ const currentCalls = countToolCalls(
1007→ this.mutableMessages,
1008→ SYNTHETIC_OUTPUT_TOOL_NAME,
1009→ )
1010→ const callsThisQuery = currentCalls - initialStructuredOutputCalls
1011→ const maxRetries = parseInt(
1012→ process.env.MAX_STRUCTURED_OUTPUT_RETRIES || '5',
1013→ 10,
1014→ )
1015→ if (callsThisQuery >= maxRetries) {
1016→ if (persistSession) {
1017→ if (
1018→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
1019→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
1020→ ) {
1021→ await flushSessionStorage()
1022→ }
1023→ }
1024→ yield {
1025→ type: 'result',
1026→ subtype: 'error_max_structured_output_retries',
1027→ duration_ms: Date.now() - startTime,
1028→ duration_api_ms: getTotalAPIDuration(),
1029→ is_error: true,
1030→ num_turns: turnCount,
1031→ stop_reason: lastStopReason,
1032→ session_id: getSessionId(),
1033→ total_cost_usd: getTotalCost(),
1034→ usage: this.totalUsage,
1035→ modelUsage: getModelUsage(),
1036→ permission_denials: this.permissionDenials,
1037→ fast_mode_state: getFastModeState(
1038→ mainLoopModel,
1039→ initialAppState.fastMode,
1040→ ),
1041→ uuid: randomUUID(),
1042→ errors: [
1043→ `Failed to provide valid structured output after ${maxRetries} attempts`,
1044→ ],
1045→ }
1046→ return
1047→ }
1048→ }
1049→ }
1050→
1051→ // Stop hooks yield progress/attachment messages AFTER the assistant
1052→ // response (via yield* handleStopHooks in query.ts). Since #23537 pushes
1053→ // those to `messages` inline, last(messages) can be a progress/attachment
1054→ // instead of the assistant — which makes textResult extraction below
1055→ // return '' and -p mode emit a blank line. Allowlist to assistant|user:
1056→ // isResultSuccessful handles both (user with all tool_result blocks is a
1057→ // valid successful terminal state).
1058→ const result = messages.findLast(
1059→ m => m.type === 'assistant' || m.type === 'user',
1060→ )
1061→ // Capture for the error_during_execution diagnostic — isResultSuccessful
1062→ // is a type predicate (message is Message), so inside the false branch
1063→ // `result` narrows to never and these accesses don't typecheck.
1064→ const edeResultType = result?.type ?? 'undefined'
1065→ const edeLastContentType =
1066→ result?.type === 'assistant'
1067→ ? (last(result.message.content)?.type ?? 'none')
1068→ : 'n/a'
1069→
1070→ // Flush buffered transcript writes before yielding result.
1071→ // The desktop app kills the CLI process immediately after receiving the
1072→ // result message, so any unflushed writes would be lost.
1073→ if (persistSession) {
1074→ if (
1075→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
1076→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
1077→ ) {
1078→ await flushSessionStorage()
1079→ }
1080→ }
1081→
1082→ if (!isResultSuccessful(result, lastStopReason)) {
1083→ yield {
1084→ type: 'result',
1085→ subtype: 'error_during_execution',
1086→ duration_ms: Date.now() - startTime,
1087→ duration_api_ms: getTotalAPIDuration(),
1088→ is_error: true,
1089→ num_turns: turnCount,
1090→ stop_reason: lastStopReason,
1091→ session_id: getSessionId(),
1092→ total_cost_usd: getTotalCost(),
1093→ usage: this.totalUsage,
1094→ modelUsage: getModelUsage(),
1095→ permission_denials: this.permissionDenials,
1096→ fast_mode_state: getFastModeState(
1097→ mainLoopModel,
1098→ initialAppState.fastMode,
1099→ ),
1100→ uuid: randomUUID(),
1101→ // Diagnostic prefix: these are what isResultSuccessful() checks — if
1102→ // the result type isn't assistant-with-text/thinking or user-with-
1103→ // tool_result, and stop_reason isn't end_turn, that's why this fired.
1104→ // errors[] is turn-scoped via the watermark; previously it dumped the
1105→ // entire process's logError buffer (ripgrep timeouts, ENOENT, etc).
1106→ errors: (() => {
1107→ const all = getInMemoryErrors()
1108→ const start = errorLogWatermark
1109→ ? all.lastIndexOf(errorLogWatermark) + 1
1110→ : 0
1111→ return [
1112→ `[ede_diagnostic] result_type=${edeResultType} last_content_type=${edeLastContentType} stop_reason=${lastStopReason}`,
1113→ ...all.slice(start).map(_ => _.error),
1114→ ]
1115→ })(),
1116→ }
1117→ return
1118→ }
1119→
1120→ // Extract the text result based on message type
1121→ let textResult = ''
1122→ let isApiError = false
1123→
1124→ if (result.type === 'assistant') {
1125→ const lastContent = last(result.message.content)
1126→ if (
1127→ lastContent?.type === 'text' &&
1128→ !SYNTHETIC_MESSAGES.has(lastContent.text)
1129→ ) {
1130→ textResult = lastContent.text
1131→ }
1132→ isApiError = Boolean(result.isApiErrorMessage)
1133→ }
1134→
1135→ yield {
1136→ type: 'result',
1137→ subtype: 'success',
1138→ is_error: isApiError,
1139→ duration_ms: Date.now() - startTime,
1140→ duration_api_ms: getTotalAPIDuration(),
1141→ num_turns: turnCount,
1142→ result: textResult,
1143→ stop_reason: lastStopReason,
1144→ session_id: getSessionId(),
1145→ total_cost_usd: getTotalCost(),
1146→ usage: this.totalUsage,
1147→ modelUsage: getModelUsage(),
1148→ permission_denials: this.permissionDenials,
1149→ structured_output: structuredOutputFromTool,
1150→ fast_mode_state: getFastModeState(
1151→ mainLoopModel,
1152→ initialAppState.fastMode,
1153→ ),
1154→ uuid: randomUUID(),
1155→ }
1156→ }
1157→
1158→ interrupt(): void {
1159→ this.abortController.abort()
1160→ }
1161→
1162→ getMessages(): readonly Message[] {
1163→ return this.mutableMessages
1164→ }
1165→
1166→ getReadFileState(): FileStateCache {
1167→ return this.readFileState
1168→ }
1169→
1170→ getSessionId(): string {
1171→ return getSessionId()
1172→ }
1173→
1174→ setModel(model: string): void {
1175→ this.config.userSpecifiedModel = model
1176→ }
1177→}
1178→
1179→/**
1180→ * Sends a single prompt to the Claude API and returns the response.
1181→ * Assumes that claude is being used non-interactively -- will not
1182→ * ask the user for permissions or further input.
1183→ *
1184→ * Convenience wrapper around QueryEngine for one-shot usage.
1185→ */
1186→export async function* ask({
1187→ commands,
1188→ prompt,
1189→ promptUuid,
1190→ isMeta,
1191→ cwd,
1192→ tools,
1193→ mcpClients,
1194→ verbose = false,
1195→ thinkingConfig,
1196→ maxTurns,
1197→ maxBudgetUsd,
1198→ taskBudget,
1199→ canUseTool,
1200→ mutableMessages = [],
1201→ getReadFileCache,
1202→ setReadFileCache,
1203→ customSystemPrompt,
1204→ appendSystemPrompt,
1205→ userSpecifiedModel,
1206→ fallbackModel,
1207→ jsonSchema,
1208→ getAppState,
1209→ setAppState,
1210→ abortController,
1211→ replayUserMessages = false,
1212→ includePartialMessages = false,
1213→ handleElicitation,
1214→ agents = [],
1215→ setSDKStatus,
1216→ orphanedPermission,
1217→}: {
1218→ commands: Command[]
1219→ prompt: string | Array<ContentBlockParam>
1220→ promptUuid?: string
1221→ isMeta?: boolean
1222→ cwd: string
1223→ tools: Tools
1224→ verbose?: boolean
1225→ mcpClients: MCPServerConnection[]
1226→ thinkingConfig?: ThinkingConfig
1227→ maxTurns?: number
1228→ maxBudgetUsd?: number
1229→ taskBudget?: { total: number }
1230→ canUseTool: CanUseToolFn
1231→ mutableMessages?: Message[]
1232→ customSystemPrompt?: string
1233→ appendSystemPrompt?: string
1234→ userSpecifiedModel?: string
1235→ fallbackModel?: string
1236→ jsonSchema?: Record<string, unknown>
1237→ getAppState: () => AppState
1238→ setAppState: (f: (prev: AppState) => AppState) => void
1239→ getReadFileCache: () => FileStateCache
1240→ setReadFileCache: (cache: FileStateCache) => void
1241→ abortController?: AbortController
1242→ replayUserMessages?: boolean
1243→ includePartialMessages?: boolean
1244→ handleElicitation?: ToolUseContext['handleElicitation']
1245→ agents?: AgentDefinition[]
1246→ setSDKStatus?: (status: SDKStatus) => void
1247→ orphanedPermission?: OrphanedPermission
1248→}): AsyncGenerator<SDKMessage, void, unknown> {
1249→ const engine = new QueryEngine({
1250→ cwd,
1251→ tools,
1252→ commands,
1253→ mcpClients,
1254→ agents,
1255→ canUseTool,
1256→ getAppState,
1257→ setAppState,
1258→ initialMessages: mutableMessages,
1259→ readFileCache: cloneFileStateCache(getReadFileCache()),
1260→ customSystemPrompt,
1261→ appendSystemPrompt,
1262→ userSpecifiedModel,
1263→ fallbackModel,
1264→ thinkingConfig,
1265→ maxTurns,
1266→ maxBudgetUsd,
1267→ taskBudget,
1268→ jsonSchema,
1269→ verbose,
1270→ handleElicitation,
1271→ replayUserMessages,
1272→ includePartialMessages,
1273→ setSDKStatus,
1274→ abortController,
1275→ orphanedPermission,
1276→ ...(feature('HISTORY_SNIP')
1277→ ? {
1278→ snipReplay: (yielded: Message, store: Message[]) => {
1279→ if (!snipProjection!.isSnipBoundaryMessage(yielded))
1280→ return undefined
1281→ return snipModule!.snipCompactIfNeeded(store, { force: true })
1282→ },
1283→ }
1284→ : {}),
1285→ })
1286→
1287→ try {
1288→ yield* engine.submitMessage(prompt, {
1289→ uuid: promptUuid,
1290→ isMeta,
1291→ })
1292→ } finally {
1293→ setReadFileCache(engine.getReadFileState())
1294→ }
1295→}
1296→Tool Call: Read src\Tool.ts (1 - 100) Status: Completed
1→import type {
2→ ToolResultBlockParam,
3→ ToolUseBlockParam,
4→} from '@anthropic-ai/sdk/resources/index.mjs'
5→import type {
6→ ElicitRequestURLParams,
7→ ElicitResult,
8→} from '@modelcontextprotocol/sdk/types.js'
9→import type { UUID } from 'crypto'
10→import type { z } from 'zod/v4'
11→import type { Command } from './commands.js'
12→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
13→import type { ThinkingConfig } from './utils/thinking.js'
14→
15→export type ToolInputJSONSchema = {
16→ [x: string]: unknown
17→ type: 'object'
18→ properties?: {
19→ [x: string]: unknown
20→ }
21→}
22→
23→import type { Notification } from './context/notifications.js'
24→import type {
25→ MCPServerConnection,
26→ ServerResource,
27→} from './services/mcp/types.js'
28→import type {
29→ AgentDefinition,
30→ AgentDefinitionsResult,
31→} from './tools/AgentTool/loadAgentsDir.js'
32→import type {
33→ AssistantMessage,
34→ AttachmentMessage,
35→ Message,
36→ ProgressMessage,
37→ SystemLocalCommandMessage,
38→ SystemMessage,
39→ UserMessage,
40→} from './types/message.js'
41→// Import permission types from centralized location to break import cycles
42→// Import PermissionResult from centralized location to break import cycles
43→import type {
44→ AdditionalWorkingDirectory,
45→ PermissionMode,
46→ PermissionResult,
47→} from './types/permissions.js'
48→// Import tool progress types from centralized location to break import cycles
49→import type {
50→ AgentToolProgress,
51→ BashProgress,
52→ MCPProgress,
53→ REPLToolProgress,
54→ SkillToolProgress,
55→ TaskOutputProgress,
56→ ToolProgressData,
57→ WebSearchProgress,
58→} from './types/tools.js'
59→import type { FileStateCache } from './utils/fileStateCache.js'
60→import type { DenialTrackingState } from './utils/permissions/denialTracking.js'
61→import type { SystemPrompt } from './utils/systemPromptType.js'
62→import type { ContentReplacementState } from './utils/toolResultStorage.js'
63→
64→// Re-export progress types for backwards compatibility
65→export type {
66→ AgentToolProgress,
67→ BashProgress,
68→ MCPProgress,
69→ REPLToolProgress,
70→ SkillToolProgress,
71→ TaskOutputProgress,
72→ WebSearchProgress,
73→}
74→
75→import type { SpinnerMode } from './components/Spinner.js'
76→import type { QuerySource } from './constants/querySource.js'
77→import type { SDKStatus } from './entrypoints/agentSdkTypes.js'
78→import type { AppState } from './state/AppState.js'
79→import type {
80→ HookProgress,
81→ PromptRequest,
82→ PromptResponse,
83→} from './types/hooks.js'
84→import type { AgentId } from './types/ids.js'
85→import type { DeepImmutable } from './types/utils.js'
86→import type { AttributionState } from './utils/commitAttribution.js'
87→import type { FileHistoryState } from './utils/fileHistory.js'
88→import type { Theme, ThemeName } from './utils/theme.js'
89→
90→export type QueryChainTracking = {
91→ chainId: string
92→ depth: number
93→}
94→
95→export type ValidationResult =
96→ | { result: true }
97→ | {
98→ result: false
99→ message: string
100→ errorCode: numberTool Call: Read src\Task.ts (1 - 100) Status: Completed
1→import { randomBytes } from 'crypto'
2→import type { AppState } from './state/AppState.js'
3→import type { AgentId } from './types/ids.js'
4→import { getTaskOutputPath } from './utils/task/diskOutput.js'
5→
6→export type TaskType =
7→ | 'local_bash'
8→ | 'local_agent'
9→ | 'remote_agent'
10→ | 'in_process_teammate'
11→ | 'local_workflow'
12→ | 'monitor_mcp'
13→ | 'dream'
14→
15→export type TaskStatus =
16→ | 'pending'
17→ | 'running'
18→ | 'completed'
19→ | 'failed'
20→ | 'killed'
21→
22→/**
23→ * True when a task is in a terminal state and will not transition further.
24→ * Used to guard against injecting messages into dead teammates, evicting
25→ * finished tasks from AppState, and orphan-cleanup paths.
26→ */
27→export function isTerminalTaskStatus(status: TaskStatus): boolean {
28→ return status === 'completed' || status === 'failed' || status === 'killed'
29→}
30→
31→export type TaskHandle = {
32→ taskId: string
33→ cleanup?: () => void
34→}
35→
36→export type SetAppState = (f: (prev: AppState) => AppState) => void
37→
38→export type TaskContext = {
39→ abortController: AbortController
40→ getAppState: () => AppState
41→ setAppState: SetAppState
42→}
43→
44→// Base fields shared by all task states
45→export type TaskStateBase = {
46→ id: string
47→ type: TaskType
48→ status: TaskStatus
49→ description: string
50→ toolUseId?: string
51→ startTime: number
52→ endTime?: number
53→ totalPausedMs?: number
54→ outputFile: string
55→ outputOffset: number
56→ notified: boolean
57→}
58→
59→export type LocalShellSpawnInput = {
60→ command: string
61→ description: string
62→ timeout?: number
63→ toolUseId?: string
64→ agentId?: AgentId
65→ /** UI display variant: description-as-label, dialog title, status bar pill. */
66→ kind?: 'bash' | 'monitor'
67→}
68→
69→// What getTaskByType dispatches for: kill. spawn/render were never
70→// called polymorphically (removed in #22546). All six kill implementations
71→// use only setAppState — getAppState/abortController were dead weight.
72→export type Task = {
73→ name: string
74→ type: TaskType
75→ kill(taskId: string, setAppState: SetAppState): Promise<void>
76→}
77→
78→// Task ID prefixes
79→const TASK_ID_PREFIXES: Record<string, string> = {
80→ local_bash: 'b', // Keep as 'b' for backward compatibility
81→ local_agent: 'a',
82→ remote_agent: 'r',
83→ in_process_teammate: 't',
84→ local_workflow: 'w',
85→ monitor_mcp: 'm',
86→ dream: 'd',
87→}
88→
89→// Get task ID prefix
90→function getTaskIdPrefix(type: TaskType): string {
91→ return TASK_ID_PREFIXES[type] ?? 'x'
92→}
93→
94→// Case-insensitive-safe alphabet (digits + lowercase) for task IDs.
95→// 36^8 ≈ 2.8 trillion combinations, sufficient to resist brute-force symlink attacks.
96→const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
97→
98→export function generateTaskId(type: TaskType): string {
99→ const prefix = getTaskIdPrefix(type)
100→ const bytes = randomBytes(8)Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/**/*.{ts,tsx} Status: Completed
src\tools\AgentTool\AgentTool.tsx src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\UI.tsx src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\built-in\claudeCodeGuideAgent.ts src\tools\AgentTool\built-in\exploreAgent.ts src\tools\AgentTool\built-in\generalPurposeAgent.ts src\tools\AgentTool\built-in\planAgent.ts src\tools\AgentTool\built-in\statuslineSetup.ts src\tools\AgentTool\built-in\verificationAgent.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\runAgent.ts src\tools\AskUserQuestionTool\AskUserQuestionTool.tsx src\tools\AskUserQuestionTool\prompt.ts src\tools\BashTool\BashTool.tsx src\tools\BashTool\BashToolResultMessage.tsx src\tools\BashTool\UI.tsx src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts src\tools\BriefTool\BriefTool.ts src\tools\BriefTool\attachments.ts src\tools\BriefTool\prompt.ts src\tools\BriefTool\UI.tsx src\tools\BriefTool\upload.ts src\tools\ConfigTool\ConfigTool.ts src\tools\ConfigTool\constants.ts src\tools\ConfigTool\prompt.ts src\tools\ConfigTool\supportedSettings.ts src\tools\ConfigTool\UI.tsx src\tools\EnterPlanModeTool\constants.ts src\tools\EnterPlanModeTool\EnterPlanModeTool.ts src\tools\EnterPlanModeTool\prompt.ts src\tools\EnterPlanModeTool\UI.tsx src\tools\EnterWorktreeTool\constants.ts src\tools\EnterWorktreeTool\EnterWorktreeTool.ts src\tools\EnterWorktreeTool\prompt.ts src\tools\EnterWorktreeTool\UI.tsx src\tools\ExitPlanModeTool\constants.ts src\tools\ExitPlanModeTool\ExitPlanModeV2Tool.ts src\tools\ExitPlanModeTool\prompt.ts src\tools\ExitPlanModeTool\UI.tsx src\tools\ExitWorktreeTool\constants.ts src\tools\ExitWorktreeTool\ExitWorktreeTool.ts src\tools\ExitWorktreeTool\prompt.ts src\tools\ExitWorktreeTool\UI.tsx src\tools\FileEditTool\FileEditTool.ts src\tools\FileEditTool\constants.ts src\tools\FileEditTool\prompt.ts src\tools\FileEditTool\UI.tsx src\tools\FileEditTool\types.ts src\tools\FileEditTool\utils.ts src\tools\FileReadTool\FileReadTool.ts src\tools\FileReadTool\imageProcessor.ts src\tools\FileReadTool\limits.ts src\tools\FileReadTool\prompt.ts src\tools\FileReadTool\UI.tsx src\tools\FileWriteTool\FileWriteTool.ts src\tools\FileWriteTool\prompt.ts src\tools\FileWriteTool\UI.tsx src\tools\GlobTool\GlobTool.ts src\tools\GlobTool\prompt.ts src\tools\GlobTool\UI.tsx src\tools\GrepTool\GrepTool.ts src\tools\GrepTool\UI.tsx src\tools\GrepTool\prompt.ts src\tools\LSPTool\LSPTool.ts src\tools\LSPTool\UI.tsx src\tools\LSPTool\formatters.ts src\tools\LSPTool\prompt.ts src\tools\LSPTool\schemas.ts src\tools\LSPTool\symbolContext.ts src\tools\ListMcpResourcesTool\ListMcpResourcesTool.ts src\tools\ListMcpResourcesTool\prompt.ts src\tools\ListMcpResourcesTool\UI.tsx src\tools\MCPTool\MCPTool.ts src\tools\MCPTool\classifyForCollapse.ts src\tools\MCPTool\prompt.ts src\tools\MCPTool\UI.tsx src\tools\McpAuthTool\McpAuthTool.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/components/**/*.{ts,tsx} Status: Completed
src\components\AgentProgressLine.tsx src\components\App.tsx src\components\ApproveApiKey.tsx src\components\AutoModeOptInDialog.tsx src\components\AutoUpdater.tsx src\components\AutoUpdaterWrapper.tsx src\components\AwsAuthStatusBox.tsx src\components\BaseTextInput.tsx src\components\BashModeProgress.tsx src\components\BridgeDialog.tsx src\components\BypassPermissionsModeDialog.tsx src\components\ChannelDowngradeDialog.tsx src\components\ClaudeCodeHint\PluginHintMenu.tsx src\components\ClaudeInChromeOnboarding.tsx src\components\ClaudeMdExternalIncludesDialog.tsx src\components\ClickableImageRef.tsx src\components\CompactSummary.tsx src\components\ConfigurableShortcutHint.tsx src\components\ConsoleOAuthFlow.tsx src\components\ContextSuggestions.tsx src\components\ContextVisualization.tsx src\components\CoordinatorAgentStatus.tsx src\components\CostThresholdDialog.tsx src\components\CtrlOToExpand.tsx src\components\CustomSelect\index.ts src\components\CustomSelect\option-map.ts src\components\CustomSelect\SelectMulti.tsx src\components\CustomSelect\select-input-option.tsx src\components\CustomSelect\select-option.tsx src\components\CustomSelect\select.tsx src\components\CustomSelect\use-multi-select-state.ts src\components\CustomSelect\use-select-input.ts src\components\CustomSelect\use-select-navigation.ts src\components\CustomSelect\use-select-state.ts src\components\DesktopHandoff.tsx src\components\DesktopUpsell\DesktopUpsellStartup.tsx src\components\DevBar.tsx src\components\DevChannelsDialog.tsx src\components\DiagnosticsDisplay.tsx src\components\EffortCallout.tsx src\components\EffortIndicator.ts src\components\ExitFlow.tsx src\components\ExportDialog.tsx src\components\FallbackToolUseErrorMessage.tsx src\components\FallbackToolUseRejectedMessage.tsx src\components\FastIcon.tsx src\components\Feedback.tsx src\components\FeedbackSurvey\FeedbackSurvey.tsx src\components\FeedbackSurvey\FeedbackSurveyView.tsx src\components\FeedbackSurvey\submitTranscriptShare.ts src\components\FeedbackSurvey\TranscriptSharePrompt.tsx src\components\FeedbackSurvey\useDebouncedDigitInput.ts src\components\FeedbackSurvey\useFeedbackSurvey.tsx src\components\FeedbackSurvey\useMemorySurvey.tsx src\components\FeedbackSurvey\usePostCompactSurvey.tsx src\components\FeedbackSurvey\useSurveyState.tsx src\components\FileEditToolDiff.tsx src\components\FileEditToolUpdatedMessage.tsx src\components\FileEditToolUseRejectedMessage.tsx src\components\FilePathLink.tsx src\components\FullscreenLayout.tsx src\components\GlobalSearchDialog.tsx src\components\HelpV2\Commands.tsx src\components\HelpV2\General.tsx src\components\HelpV2\HelpV2.tsx src\components\HighlightedCode.tsx src\components\HighlightedCode\Fallback.tsx src\components\HistorySearchDialog.tsx src\components\IdeAutoConnectDialog.tsx src\components\IdeOnboardingDialog.tsx src\components\IdeStatusIndicator.tsx src\components\IdleReturnDialog.tsx src\components\InterruptedByUser.tsx src\components\InvalidConfigDialog.tsx src\components\InvalidSettingsDialog.tsx src\components\KeybindingWarnings.tsx src\components\LanguagePicker.tsx src\components\LogoV2\AnimatedAsterisk.tsx src\components\LogoV2\AnimatedClawd.tsx src\components\LogSelector.tsx src\components\LogoV2\ChannelsNotice.tsx src\components\LogoV2\Clawd.tsx src\components\LogoV2\CondensedLogo.tsx src\components\LogoV2\EmergencyTip.tsx src\components\LogoV2\Feed.tsx src\components\LogoV2\FeedColumn.tsx src\components\LogoV2\GuestPassesUpsell.tsx src\components\LogoV2\LogoV2.tsx src\components\LogoV2\Opus1mMergeNotice.tsx src\components\LogoV2\OverageCreditUpsell.tsx src\components\LogoV2\VoiceModeNotice.tsx src\components\LogoV2\WelcomeV2.tsx src\components\LogoV2\feedConfigs.tsx src\components\LspRecommendation\LspRecommendationMenu.tsx src\components\MCPServerApprovalDialog.tsx src\components\MCPServerDesktopImportDialog.tsx src\components\MCPServerDialogCopy.tsx src\components\MCPServerMultiselectDialog.tsx src\components\ManagedSettingsSecurityDialog\ManagedSettingsSecurityDialog.tsx src\components\ManagedSettingsSecurityDialog\utils.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\QueryEngine.ts (1 - 120) Status: Completed
1→import { feature } from 'bun:bundle'
2→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
3→import { randomUUID } from 'crypto'
4→import last from 'lodash-es/last.js'
5→import {
6→ getSessionId,
7→ isSessionPersistenceDisabled,
8→} from 'src/bootstrap/state.js'
9→import type {
10→ PermissionMode,
11→ SDKCompactBoundaryMessage,
12→ SDKMessage,
13→ SDKPermissionDenial,
14→ SDKStatus,
15→ SDKUserMessageReplay,
16→} from 'src/entrypoints/agentSdkTypes.js'
17→import { accumulateUsage, updateUsage } from 'src/services/api/claude.js'
18→import type { NonNullableUsage } from 'src/services/api/logging.js'
19→import { EMPTY_USAGE } from 'src/services/api/logging.js'
20→import stripAnsi from 'strip-ansi'
21→import type { Command } from './commands.js'
22→import { getSlashCommandToolSkills } from './commands.js'
23→import {
24→ LOCAL_COMMAND_STDERR_TAG,
25→ LOCAL_COMMAND_STDOUT_TAG,
26→} from './constants/xml.js'
27→import {
28→ getModelUsage,
29→ getTotalAPIDuration,
30→ getTotalCost,
31→} from './cost-tracker.js'
32→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
33→import { loadMemoryPrompt } from './memdir/memdir.js'
34→import { hasAutoMemPathOverride } from './memdir/paths.js'
35→import { query } from './query.js'
36→import { categorizeRetryableAPIError } from './services/api/errors.js'
37→import type { MCPServerConnection } from './services/mcp/types.js'
38→import type { AppState } from './state/AppState.js'
39→import { type Tools, type ToolUseContext, toolMatchesName } from './Tool.js'
40→import type { AgentDefinition } from './tools/AgentTool/loadAgentsDir.js'
41→import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js'
42→import type { Message } from './types/message.js'
43→import type { OrphanedPermission } from './types/textInputTypes.js'
44→import { createAbortController } from './utils/abortController.js'
45→import type { AttributionState } from './utils/commitAttribution.js'
46→import { getGlobalConfig } from './utils/config.js'
47→import { getCwd } from './utils/cwd.js'
48→import { isBareMode, isEnvTruthy } from './utils/envUtils.js'
49→import { getFastModeState } from './utils/fastMode.js'
50→import {
51→ type FileHistoryState,
52→ fileHistoryEnabled,
53→ fileHistoryMakeSnapshot,
54→} from './utils/fileHistory.js'
55→import {
56→ cloneFileStateCache,
57→ type FileStateCache,
58→} from './utils/fileStateCache.js'
59→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
60→import { registerStructuredOutputEnforcement } from './utils/hooks/hookHelpers.js'
61→import { getInMemoryErrors } from './utils/log.js'
62→import { countToolCalls, SYNTHETIC_MESSAGES } from './utils/messages.js'
63→import {
64→ getMainLoopModel,
65→ parseUserSpecifiedModel,
66→} from './utils/model/model.js'
67→import { loadAllPluginsCacheOnly } from './utils/plugins/pluginLoader.js'
68→import {
69→ type ProcessUserInputContext,
70→ processUserInput,
71→} from './utils/processUserInput/processUserInput.js'
72→import { fetchSystemPromptParts } from './utils/queryContext.js'
73→import { setCwd } from './utils/Shell.js'
74→import {
75→ flushSessionStorage,
76→ recordTranscript,
77→} from './utils/sessionStorage.js'
78→import { asSystemPrompt } from './utils/systemPromptType.js'
79→import { resolveThemeSetting } from './utils/systemTheme.js'
80→import {
81→ shouldEnableThinkingByDefault,
82→ type ThinkingConfig,
83→} from './utils/thinking.js'
84→
85→// Lazy: MessageSelector.tsx pulls React/ink; only needed for message filtering at query time
86→/* eslint-disable @typescript-eslint/no-require-imports */
87→const messageSelector =
88→ (): typeof import('src/components/MessageSelector.js') =>
89→ require('src/components/MessageSelector.js')
90→
91→import {
92→ localCommandOutputToSDKAssistantMessage,
93→ toSDKCompactMetadata,
94→} from './utils/messages/mappers.js'
95→import {
96→ buildSystemInitMessage,
97→ sdkCompatToolName,
98→} from './utils/messages/systemInit.js'
99→import {
100→ getScratchpadDir,
101→ isScratchpadEnabled,
102→} from './utils/permissions/filesystem.js'
103→/* eslint-enable @typescript-eslint/no-require-imports */
104→import {
105→ handleOrphanedPermission,
106→ isResultSuccessful,
107→ normalizeMessage,
108→} from './utils/queryHelpers.js'
109→
110→// Dead code elimination: conditional import for coordinator mode
111→/* eslint-disable @typescript-eslint/no-require-imports */
112→const getCoordinatorUserContext: (
113→ mcpClients: ReadonlyArray<{ name: string }>,
114→ scratchpadDir?: string,
115→) => { [k: string]: string } = feature('COORDINATOR_MODE')
116→ ? require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
117→ : () => ({})
118→/* eslint-enable @typescript-eslint/no-require-imports */
119→
120→// Dead code elimination: conditional import for snip compactionTool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/**/* Status: Completed
src\tools\AgentTool\AgentTool.tsx src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\UI.tsx src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\built-in\claudeCodeGuideAgent.ts src\tools\AgentTool\built-in\exploreAgent.ts src\tools\AgentTool\built-in\generalPurposeAgent.ts src\tools\AgentTool\built-in\planAgent.ts src\tools\AgentTool\built-in\statuslineSetup.ts src\tools\AgentTool\built-in\verificationAgent.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\runAgent.ts src\tools\AskUserQuestionTool\AskUserQuestionTool.tsx src\tools\AskUserQuestionTool\prompt.ts src\tools\BashTool\BashTool.tsx src\tools\BashTool\BashToolResultMessage.tsx src\tools\BashTool\UI.tsx src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts src\tools\BriefTool\BriefTool.ts src\tools\BriefTool\attachments.ts src\tools\BriefTool\prompt.ts src\tools\BriefTool\UI.tsx src\tools\BriefTool\upload.ts src\tools\ConfigTool\ConfigTool.ts src\tools\ConfigTool\constants.ts src\tools\ConfigTool\prompt.ts src\tools\ConfigTool\supportedSettings.ts src\tools\ConfigTool\UI.tsx src\tools\EnterPlanModeTool\constants.ts src\tools\EnterPlanModeTool\EnterPlanModeTool.ts src\tools\EnterPlanModeTool\prompt.ts src\tools\EnterPlanModeTool\UI.tsx src\tools\EnterWorktreeTool\constants.ts src\tools\EnterWorktreeTool\EnterWorktreeTool.ts src\tools\EnterWorktreeTool\prompt.ts src\tools\EnterWorktreeTool\UI.tsx src\tools\ExitPlanModeTool\constants.ts src\tools\ExitPlanModeTool\ExitPlanModeV2Tool.ts src\tools\ExitPlanModeTool\prompt.ts src\tools\ExitPlanModeTool\UI.tsx src\tools\ExitWorktreeTool\constants.ts src\tools\ExitWorktreeTool\ExitWorktreeTool.ts src\tools\ExitWorktreeTool\prompt.ts src\tools\ExitWorktreeTool\UI.tsx src\tools\FileEditTool\FileEditTool.ts src\tools\FileEditTool\constants.ts src\tools\FileEditTool\prompt.ts src\tools\FileEditTool\UI.tsx src\tools\FileEditTool\types.ts src\tools\FileEditTool\utils.ts src\tools\FileReadTool\FileReadTool.ts src\tools\FileReadTool\imageProcessor.ts src\tools\FileReadTool\limits.ts src\tools\FileReadTool\prompt.ts src\tools\FileReadTool\UI.tsx src\tools\FileWriteTool\FileWriteTool.ts src\tools\FileWriteTool\prompt.ts src\tools\FileWriteTool\UI.tsx src\tools\GlobTool\GlobTool.ts src\tools\GlobTool\prompt.ts src\tools\GlobTool\UI.tsx src\tools\GrepTool\GrepTool.ts src\tools\GrepTool\UI.tsx src\tools\GrepTool\prompt.ts src\tools\LSPTool\LSPTool.ts src\tools\LSPTool\UI.tsx src\tools\LSPTool\formatters.ts src\tools\LSPTool\prompt.ts src\tools\LSPTool\schemas.ts src\tools\LSPTool\symbolContext.ts src\tools\ListMcpResourcesTool\ListMcpResourcesTool.ts src\tools\ListMcpResourcesTool\prompt.ts src\tools\ListMcpResourcesTool\UI.tsx src\tools\MCPTool\MCPTool.ts src\tools\MCPTool\classifyForCollapse.ts src\tools\MCPTool\prompt.ts src\tools\MCPTool\UI.tsx src\tools\McpAuthTool\McpAuthTool.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\commands.ts Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import addDir from './commands/add-dir/index.js'
3→import autofixPr from './commands/autofix-pr/index.js'
4→import backfillSessions from './commands/backfill-sessions/index.js'
5→import btw from './commands/btw/index.js'
6→import goodClaude from './commands/good-claude/index.js'
7→import issue from './commands/issue/index.js'
8→import feedback from './commands/feedback/index.js'
9→import clear from './commands/clear/index.js'
10→import color from './commands/color/index.js'
11→import commit from './commands/commit.js'
12→import copy from './commands/copy/index.js'
13→import desktop from './commands/desktop/index.js'
14→import commitPushPr from './commands/commit-push-pr.js'
15→import compact from './commands/compact/index.js'
16→import config from './commands/config/index.js'
17→import { context, contextNonInteractive } from './commands/context/index.js'
18→import cost from './commands/cost/index.js'
19→import diff from './commands/diff/index.js'
20→import ctx_viz from './commands/ctx_viz/index.js'
21→import doctor from './commands/doctor/index.js'
22→import memory from './commands/memory/index.js'
23→import help from './commands/help/index.js'
24→import ide from './commands/ide/index.js'
25→import init from './commands/init.js'
26→import initVerifiers from './commands/init-verifiers.js'
27→import keybindings from './commands/keybindings/index.js'
28→import login from './commands/login/index.js'
29→import logout from './commands/logout/index.js'
30→import installGitHubApp from './commands/install-github-app/index.js'
31→import installSlackApp from './commands/install-slack-app/index.js'
32→import breakCache from './commands/break-cache/index.js'
33→import mcp from './commands/mcp/index.js'
34→import mobile from './commands/mobile/index.js'
35→import onboarding from './commands/onboarding/index.js'
36→import pr_comments from './commands/pr_comments/index.js'
37→import releaseNotes from './commands/release-notes/index.js'
38→import rename from './commands/rename/index.js'
39→import resume from './commands/resume/index.js'
40→import review, { ultrareview } from './commands/review.js'
41→import session from './commands/session/index.js'
42→import share from './commands/share/index.js'
43→import skills from './commands/skills/index.js'
44→import status from './commands/status/index.js'
45→import tasks from './commands/tasks/index.js'
46→import teleport from './commands/teleport/index.js'
47→/* eslint-disable @typescript-eslint/no-require-imports */
48→const agentsPlatform =
49→ process.env.USER_TYPE === 'ant'
50→ ? require('./commands/agents-platform/index.js').default
51→ : null
52→/* eslint-enable @typescript-eslint/no-require-imports */
53→import securityReview from './commands/security-review.js'
54→import bughunter from './commands/bughunter/index.js'
55→import terminalSetup from './commands/terminalSetup/index.js'
56→import usage from './commands/usage/index.js'
57→import theme from './commands/theme/index.js'
58→import vim from './commands/vim/index.js'
59→import { feature } from 'bun:bundle'
60→// Dead code elimination: conditional imports
61→/* eslint-disable @typescript-eslint/no-require-imports */
62→const proactive =
63→ feature('PROACTIVE') || feature('KAIROS')
64→ ? require('./commands/proactive.js').default
65→ : null
66→const briefCommand =
67→ feature('KAIROS') || feature('KAIROS_BRIEF')
68→ ? require('./commands/brief.js').default
69→ : null
70→const assistantCommand = feature('KAIROS')
71→ ? require('./commands/assistant/index.js').default
72→ : null
73→const bridge = feature('BRIDGE_MODE')
74→ ? require('./commands/bridge/index.js').default
75→ : null
76→const remoteControlServerCommand =
77→ feature('DAEMON') && feature('BRIDGE_MODE')
78→ ? require('./commands/remoteControlServer/index.js').default
79→ : null
80→const voiceCommand = feature('VOICE_MODE')
81→ ? require('./commands/voice/index.js').default
82→ : null
83→const forceSnip = feature('HISTORY_SNIP')
84→ ? require('./commands/force-snip.js').default
85→ : null
86→const workflowsCmd = feature('WORKFLOW_SCRIPTS')
87→ ? (
88→ require('./commands/workflows/index.js') as typeof import('./commands/workflows/index.js')
89→ ).default
90→ : null
91→const webCmd = feature('CCR_REMOTE_SETUP')
92→ ? (
93→ require('./commands/remote-setup/index.js') as typeof import('./commands/remote-setup/index.js')
94→ ).default
95→ : null
96→const clearSkillIndexCache = feature('EXPERIMENTAL_SKILL_SEARCH')
97→ ? (
98→ require('./services/skillSearch/localSearch.js') as typeof import('./services/skillSearch/localSearch.js')
99→ ).clearSkillIndexCache
100→ : null
101→const subscribePr = feature('KAIROS_GITHUB_WEBHOOKS')
102→ ? require('./commands/subscribe-pr.js').default
103→ : null
104→const ultraplan = feature('ULTRAPLAN')
105→ ? require('./commands/ultraplan.js').default
106→ : null
107→const torch = feature('TORCH') ? require('./commands/torch.js').default : null
108→const peersCmd = feature('UDS_INBOX')
109→ ? (
110→ require('./commands/peers/index.js') as typeof import('./commands/peers/index.js')
111→ ).default
112→ : null
113→const forkCmd = feature('FORK_SUBAGENT')
114→ ? (
115→ require('./commands/fork/index.js') as typeof import('./commands/fork/index.js')
116→ ).default
117→ : null
118→const buddy = feature('BUDDY')
119→ ? (
120→ require('./commands/buddy/index.js') as typeof import('./commands/buddy/index.js')
121→ ).default
122→ : null
123→/* eslint-enable @typescript-eslint/no-require-imports */
124→import thinkback from './commands/thinkback/index.js'
125→import thinkbackPlay from './commands/thinkback-play/index.js'
126→import permissions from './commands/permissions/index.js'
127→import plan from './commands/plan/index.js'
128→import fast from './commands/fast/index.js'
129→import passes from './commands/passes/index.js'
130→import privacySettings from './commands/privacy-settings/index.js'
131→import hooks from './commands/hooks/index.js'
132→import files from './commands/files/index.js'
133→import branch from './commands/branch/index.js'
134→import agents from './commands/agents/index.js'
135→import plugin from './commands/plugin/index.js'
136→import reloadPlugins from './commands/reload-plugins/index.js'
137→import rewind from './commands/rewind/index.js'
138→import heapDump from './commands/heapdump/index.js'
139→import mockLimits from './commands/mock-limits/index.js'
140→import bridgeKick from './commands/bridge-kick.js'
141→import version from './commands/version.js'
142→import summary from './commands/summary/index.js'
143→import {
144→ resetLimits,
145→ resetLimitsNonInteractive,
146→} from './commands/reset-limits/index.js'
147→import antTrace from './commands/ant-trace/index.js'
148→import perfIssue from './commands/perf-issue/index.js'
149→import sandboxToggle from './commands/sandbox-toggle/index.js'
150→import chrome from './commands/chrome/index.js'
151→import stickers from './commands/stickers/index.js'
152→import advisor from './commands/advisor.js'
153→import { logError } from './utils/log.js'
154→import { toError } from './utils/errors.js'
155→import { logForDebugging } from './utils/debug.js'
156→import {
157→ getSkillDirCommands,
158→ clearSkillCaches,
159→ getDynamicSkills,
160→} from './skills/loadSkillsDir.js'
161→import { getBundledSkills } from './skills/bundledSkills.js'
162→import { getBuiltinPluginSkillCommands } from './plugins/builtinPlugins.js'
163→import {
164→ getPluginCommands,
165→ clearPluginCommandCache,
166→ getPluginSkills,
167→ clearPluginSkillsCache,
168→} from './utils/plugins/loadPluginCommands.js'
169→import memoize from 'lodash-es/memoize.js'
170→import { isUsing3PServices, isClaudeAISubscriber } from './utils/auth.js'
171→import { isFirstPartyAnthropicBaseUrl } from './utils/model/providers.js'
172→import env from './commands/env/index.js'
173→import exit from './commands/exit/index.js'
174→import exportCommand from './commands/export/index.js'
175→import model from './commands/model/index.js'
176→import tag from './commands/tag/index.js'
177→import outputStyle from './commands/output-style/index.js'
178→import remoteEnv from './commands/remote-env/index.js'
179→import upgrade from './commands/upgrade/index.js'
180→import {
181→ extraUsage,
182→ extraUsageNonInteractive,
183→} from './commands/extra-usage/index.js'
184→import rateLimitOptions from './commands/rate-limit-options/index.js'
185→import statusline from './commands/statusline.js'
186→import effort from './commands/effort/index.js'
187→import stats from './commands/stats/index.js'
188→// insights.ts is 113KB (3200 lines, includes diffLines/html rendering). Lazy
189→// shim defers the heavy module until /insights is actually invoked.
190→const usageReport: Command = {
191→ type: 'prompt',
192→ name: 'insights',
193→ description: 'Generate a report analyzing your Claude Code sessions',
194→ contentLength: 0,
195→ progressMessage: 'analyzing your sessions',
196→ source: 'builtin',
197→ async getPromptForCommand(args, context) {
198→ const real = (await import('./commands/insights.js')).default
199→ if (real.type !== 'prompt') throw new Error('unreachable')
200→ return real.getPromptForCommand(args, context)
201→ },
202→}
203→import oauthRefresh from './commands/oauth-refresh/index.js'
204→import debugToolCall from './commands/debug-tool-call/index.js'
205→import { getSettingSourceName } from './utils/settings/constants.js'
206→import {
207→ type Command,
208→ getCommandName,
209→ isCommandEnabled,
210→} from './types/command.js'
211→
212→// Re-export types from the centralized location
213→export type {
214→ Command,
215→ CommandBase,
216→ CommandResultDisplay,
217→ LocalCommandResult,
218→ LocalJSXCommandContext,
219→ PromptCommand,
220→ ResumeEntrypoint,
221→} from './types/command.js'
222→export { getCommandName, isCommandEnabled } from './types/command.js'
223→
224→// Commands that get eliminated from the external build
225→export const INTERNAL_ONLY_COMMANDS = [
226→ backfillSessions,
227→ breakCache,
228→ bughunter,
229→ commit,
230→ commitPushPr,
231→ ctx_viz,
232→ goodClaude,
233→ issue,
234→ initVerifiers,
235→ ...(forceSnip ? [forceSnip] : []),
236→ mockLimits,
237→ bridgeKick,
238→ version,
239→ ...(ultraplan ? [ultraplan] : []),
240→ ...(subscribePr ? [subscribePr] : []),
241→ resetLimits,
242→ resetLimitsNonInteractive,
243→ onboarding,
244→ share,
245→ summary,
246→ teleport,
247→ antTrace,
248→ perfIssue,
249→ env,
250→ oauthRefresh,
251→ debugToolCall,
252→ agentsPlatform,
253→ autofixPr,
254→].filter(Boolean)
255→
256→// Declared as a function so that we don't run this until getCommands is called,
257→// since underlying functions read from config, which can't be read at module initialization time
258→const COMMANDS = memoize((): Command[] => [
259→ addDir,
260→ advisor,
261→ agents,
262→ branch,
263→ btw,
264→ chrome,
265→ clear,
266→ color,
267→ compact,
268→ config,
269→ copy,
270→ desktop,
271→ context,
272→ contextNonInteractive,
273→ cost,
274→ diff,
275→ doctor,
276→ effort,
277→ exit,
278→ fast,
279→ files,
280→ heapDump,
281→ help,
282→ ide,
283→ init,
284→ keybindings,
285→ installGitHubApp,
286→ installSlackApp,
287→ mcp,
288→ memory,
289→ mobile,
290→ model,
291→ outputStyle,
292→ remoteEnv,
293→ plugin,
294→ pr_comments,
295→ releaseNotes,
296→ reloadPlugins,
297→ rename,
298→ resume,
299→ session,
300→ skills,
301→ stats,
302→ status,
303→ statusline,
304→ stickers,
305→ tag,
306→ theme,
307→ feedback,
308→ review,
309→ ultrareview,
310→ rewind,
311→ securityReview,
312→ terminalSetup,
313→ upgrade,
314→ extraUsage,
315→ extraUsageNonInteractive,
316→ rateLimitOptions,
317→ usage,
318→ usageReport,
319→ vim,
320→ ...(webCmd ? [webCmd] : []),
321→ ...(forkCmd ? [forkCmd] : []),
322→ ...(buddy ? [buddy] : []),
323→ ...(proactive ? [proactive] : []),
324→ ...(briefCommand ? [briefCommand] : []),
325→ ...(assistantCommand ? [assistantCommand] : []),
326→ ...(bridge ? [bridge] : []),
327→ ...(remoteControlServerCommand ? [remoteControlServerCommand] : []),
328→ ...(voiceCommand ? [voiceCommand] : []),
329→ thinkback,
330→ thinkbackPlay,
331→ permissions,
332→ plan,
333→ privacySettings,
334→ hooks,
335→ exportCommand,
336→ sandboxToggle,
337→ ...(!isUsing3PServices() ? [logout, login()] : []),
338→ passes,
339→ ...(peersCmd ? [peersCmd] : []),
340→ tasks,
341→ ...(workflowsCmd ? [workflowsCmd] : []),
342→ ...(torch ? [torch] : []),
343→ ...(process.env.USER_TYPE === 'ant' && !process.env.IS_DEMO
344→ ? INTERNAL_ONLY_COMMANDS
345→ : []),
346→])
347→
348→export const builtInCommandNames = memoize(
349→ (): Set<string> =>
350→ new Set(COMMANDS().flatMap(_ => [_.name, ...(_.aliases ?? [])])),
351→)
352→
353→async function getSkills(cwd: string): Promise<{
354→ skillDirCommands: Command[]
355→ pluginSkills: Command[]
356→ bundledSkills: Command[]
357→ builtinPluginSkills: Command[]
358→}> {
359→ try {
360→ const [skillDirCommands, pluginSkills] = await Promise.all([
361→ getSkillDirCommands(cwd).catch(err => {
362→ logError(toError(err))
363→ logForDebugging(
364→ 'Skill directory commands failed to load, continuing without them',
365→ )
366→ return []
367→ }),
368→ getPluginSkills().catch(err => {
369→ logError(toError(err))
370→ logForDebugging('Plugin skills failed to load, continuing without them')
371→ return []
372→ }),
373→ ])
374→ // Bundled skills are registered synchronously at startup
375→ const bundledSkills = getBundledSkills()
376→ // Built-in plugin skills come from enabled built-in plugins
377→ const builtinPluginSkills = getBuiltinPluginSkillCommands()
378→ logForDebugging(
379→ `getSkills returning: ${skillDirCommands.length} skill dir commands, ${pluginSkills.length} plugin skills, ${bundledSkills.length} bundled skills, ${builtinPluginSkills.length} builtin plugin skills`,
380→ )
381→ return {
382→ skillDirCommands,
383→ pluginSkills,
384→ bundledSkills,
385→ builtinPluginSkills,
386→ }
387→ } catch (err) {
388→ // This should never happen since we catch at the Promise level, but defensive
389→ logError(toError(err))
390→ logForDebugging('Unexpected error in getSkills, returning empty')
391→ return {
392→ skillDirCommands: [],
393→ pluginSkills: [],
394→ bundledSkills: [],
395→ builtinPluginSkills: [],
396→ }
397→ }
398→}
399→
400→/* eslint-disable @typescript-eslint/no-require-imports */
401→const getWorkflowCommands = feature('WORKFLOW_SCRIPTS')
402→ ? (
403→ require('./tools/WorkflowTool/createWorkflowCommand.js') as typeof import('./tools/WorkflowTool/createWorkflowCommand.js')
404→ ).getWorkflowCommands
405→ : null
406→/* eslint-enable @typescript-eslint/no-require-imports */
407→
408→/**
409→ * Filters commands by their declared `availability` (auth/provider requirement).
410→ * Commands without `availability` are treated as universal.
411→ * This runs before `isEnabled()` so that provider-gated commands are hidden
412→ * regardless of feature-flag state.
413→ *
414→ * Not memoized — auth state can change mid-session (e.g. after /login),
415→ * so this must be re-evaluated on every getCommands() call.
416→ */
417→export function meetsAvailabilityRequirement(cmd: Command): boolean {
418→ if (!cmd.availability) return true
419→ for (const a of cmd.availability) {
420→ switch (a) {
421→ case 'claude-ai':
422→ if (isClaudeAISubscriber()) return true
423→ break
424→ case 'console':
425→ // Console API key user = direct 1P API customer (not 3P, not claude.ai).
426→ // Excludes 3P (Bedrock/Vertex/Foundry) who don't set ANTHROPIC_BASE_URL
427→ // and gateway users who proxy through a custom base URL.
428→ if (
429→ !isClaudeAISubscriber() &&
430→ !isUsing3PServices() &&
431→ isFirstPartyAnthropicBaseUrl()
432→ )
433→ return true
434→ break
435→ default: {
436→ const _exhaustive: never = a
437→ void _exhaustive
438→ break
439→ }
440→ }
441→ }
442→ return false
443→}
444→
445→/**
446→ * Loads all command sources (skills, plugins, workflows). Memoized by cwd
447→ * because loading is expensive (disk I/O, dynamic imports).
448→ */
449→const loadAllCommands = memoize(async (cwd: string): Promise<Command[]> => {
450→ const [
451→ { skillDirCommands, pluginSkills, bundledSkills, builtinPluginSkills },
452→ pluginCommands,
453→ workflowCommands,
454→ ] = await Promise.all([
455→ getSkills(cwd),
456→ getPluginCommands(),
457→ getWorkflowCommands ? getWorkflowCommands(cwd) : Promise.resolve([]),
458→ ])
459→
460→ return [
461→ ...bundledSkills,
462→ ...builtinPluginSkills,
463→ ...skillDirCommands,
464→ ...workflowCommands,
465→ ...pluginCommands,
466→ ...pluginSkills,
467→ ...COMMANDS(),
468→ ]
469→})
470→
471→/**
472→ * Returns commands available to the current user. The expensive loading is
473→ * memoized, but availability and isEnabled checks run fresh every call so
474→ * auth changes (e.g. /login) take effect immediately.
475→ */
476→export async function getCommands(cwd: string): Promise<Command[]> {
477→ const allCommands = await loadAllCommands(cwd)
478→
479→ // Get dynamic skills discovered during file operations
480→ const dynamicSkills = getDynamicSkills()
481→
482→ // Build base commands without dynamic skills
483→ const baseCommands = allCommands.filter(
484→ _ => meetsAvailabilityRequirement(_) && isCommandEnabled(_),
485→ )
486→
487→ if (dynamicSkills.length === 0) {
488→ return baseCommands
489→ }
490→
491→ // Dedupe dynamic skills - only add if not already present
492→ const baseCommandNames = new Set(baseCommands.map(c => c.name))
493→ const uniqueDynamicSkills = dynamicSkills.filter(
494→ s =>
495→ !baseCommandNames.has(s.name) &&
496→ meetsAvailabilityRequirement(s) &&
497→ isCommandEnabled(s),
498→ )
499→
500→ if (uniqueDynamicSkills.length === 0) {
501→ return baseCommands
502→ }
503→
504→ // Insert dynamic skills after plugin skills but before built-in commands
505→ const builtInNames = new Set(COMMANDS().map(c => c.name))
506→ const insertIndex = baseCommands.findIndex(c => builtInNames.has(c.name))
507→
508→ if (insertIndex === -1) {
509→ return [...baseCommands, ...uniqueDynamicSkills]
510→ }
511→
512→ return [
513→ ...baseCommands.slice(0, insertIndex),
514→ ...uniqueDynamicSkills,
515→ ...baseCommands.slice(insertIndex),
516→ ]
517→}
518→
519→/**
520→ * Clears only the memoization caches for commands, WITHOUT clearing skill caches.
521→ * Use this when dynamic skills are added to invalidate cached command lists.
522→ */
523→export function clearCommandMemoizationCaches(): void {
524→ loadAllCommands.cache?.clear?.()
525→ getSkillToolCommands.cache?.clear?.()
526→ getSlashCommandToolSkills.cache?.clear?.()
527→ // getSkillIndex in skillSearch/localSearch.ts is a separate memoization layer
528→ // built ON TOP of getSkillToolCommands/getCommands. Clearing only the inner
529→ // caches is a no-op for the outer — lodash memoize returns the cached result
530→ // without ever reaching the cleared inners. Must clear it explicitly.
531→ clearSkillIndexCache?.()
532→}
533→
534→export function clearCommandsCache(): void {
535→ clearCommandMemoizationCaches()
536→ clearPluginCommandCache()
537→ clearPluginSkillsCache()
538→ clearSkillCaches()
539→}
540→
541→/**
542→ * Filter AppState.mcp.commands to MCP-provided skills (prompt-type,
543→ * model-invocable, loaded from MCP). These live outside getCommands() so
544→ * callers that need MCP skills in their skill index thread them through
545→ * separately.
546→ */
547→export function getMcpSkillCommands(
548→ mcpCommands: readonly Command[],
549→): readonly Command[] {
550→ if (feature('MCP_SKILLS')) {
551→ return mcpCommands.filter(
552→ cmd =>
553→ cmd.type === 'prompt' &&
554→ cmd.loadedFrom === 'mcp' &&
555→ !cmd.disableModelInvocation,
556→ )
557→ }
558→ return []
559→}
560→
561→// SkillTool shows ALL prompt-based commands that the model can invoke
562→// This includes both skills (from /skills/) and commands (from /commands/)
563→export const getSkillToolCommands = memoize(
564→ async (cwd: string): Promise<Command[]> => {
565→ const allCommands = await getCommands(cwd)
566→ return allCommands.filter(
567→ cmd =>
568→ cmd.type === 'prompt' &&
569→ !cmd.disableModelInvocation &&
570→ cmd.source !== 'builtin' &&
571→ // Always include skills from /skills/ dirs, bundled skills, and legacy /commands/ entries
572→ // (they all get an auto-derived description from the first line if frontmatter is missing).
573→ // Plugin/MCP commands still require an explicit description to appear in the listing.
574→ (cmd.loadedFrom === 'bundled' ||
575→ cmd.loadedFrom === 'skills' ||
576→ cmd.loadedFrom === 'commands_DEPRECATED' ||
577→ cmd.hasUserSpecifiedDescription ||
578→ cmd.whenToUse),
579→ )
580→ },
581→)
582→
583→// Filters commands to include only skills. Skills are commands that provide
584→// specialized capabilities for the model to use. They are identified by
585→// loadedFrom being 'skills', 'plugin', or 'bundled', or having disableModelInvocation set.
586→export const getSlashCommandToolSkills = memoize(
587→ async (cwd: string): Promise<Command[]> => {
588→ try {
589→ const allCommands = await getCommands(cwd)
590→ return allCommands.filter(
591→ cmd =>
592→ cmd.type === 'prompt' &&
593→ cmd.source !== 'builtin' &&
594→ (cmd.hasUserSpecifiedDescription || cmd.whenToUse) &&
595→ (cmd.loadedFrom === 'skills' ||
596→ cmd.loadedFrom === 'plugin' ||
597→ cmd.loadedFrom === 'bundled' ||
598→ cmd.disableModelInvocation),
599→ )
600→ } catch (error) {
601→ logError(toError(error))
602→ // Return empty array rather than throwing - skills are non-critical
603→ // This prevents skill loading failures from breaking the entire system
604→ logForDebugging('Returning empty skills array due to load failure')
605→ return []
606→ }
607→ },
608→)
609→
610→/**
611→ * Commands that are safe to use in remote mode (--remote).
612→ * These only affect local TUI state and don't depend on local filesystem,
613→ * git, shell, IDE, MCP, or other local execution context.
614→ *
615→ * Used in two places:
616→ * 1. Pre-filtering commands in main.tsx before REPL renders (prevents race with CCR init)
617→ * 2. Preserving local-only commands in REPL's handleRemoteInit after CCR filters
618→ */
619→export const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([
620→ session, // Shows QR code / URL for remote session
621→ exit, // Exit the TUI
622→ clear, // Clear screen
623→ help, // Show help
624→ theme, // Change terminal theme
625→ color, // Change agent color
626→ vim, // Toggle vim mode
627→ cost, // Show session cost (local cost tracking)
628→ usage, // Show usage info
629→ copy, // Copy last message
630→ btw, // Quick note
631→ feedback, // Send feedback
632→ plan, // Plan mode toggle
633→ keybindings, // Keybinding management
634→ statusline, // Status line toggle
635→ stickers, // Stickers
636→ mobile, // Mobile QR code
637→])
638→
639→/**
640→ * Builtin commands of type 'local' that ARE safe to execute when received
641→ * over the Remote Control bridge. These produce text output that streams
642→ * back to the mobile/web client and have no terminal-only side effects.
643→ *
644→ * 'local-jsx' commands are blocked by type (they render Ink UI) and
645→ * 'prompt' commands are allowed by type (they expand to text sent to the
646→ * model) — this set only gates 'local' commands.
647→ *
648→ * When adding a new 'local' command that should work from mobile, add it
649→ * here. Default is blocked.
650→ */
651→export const BRIDGE_SAFE_COMMANDS: Set<Command> = new Set(
652→ [
653→ compact, // Shrink context — useful mid-session from a phone
654→ clear, // Wipe transcript
655→ cost, // Show session cost
656→ summary, // Summarize conversation
657→ releaseNotes, // Show changelog
658→ files, // List tracked files
659→ ].filter((c): c is Command => c !== null),
660→)
661→
662→/**
663→ * Whether a slash command is safe to execute when its input arrived over the
664→ * Remote Control bridge (mobile/web client).
665→ *
666→ * PR #19134 blanket-blocked all slash commands from bridge inbound because
667→ * `/model` from iOS was popping the local Ink picker. This predicate relaxes
668→ * that with an explicit allowlist: 'prompt' commands (skills) expand to text
669→ * and are safe by construction; 'local' commands need an explicit opt-in via
670→ * BRIDGE_SAFE_COMMANDS; 'local-jsx' commands render Ink UI and stay blocked.
671→ */
672→export function isBridgeSafeCommand(cmd: Command): boolean {
673→ if (cmd.type === 'local-jsx') return false
674→ if (cmd.type === 'prompt') return true
675→ return BRIDGE_SAFE_COMMANDS.has(cmd)
676→}
677→
678→/**
679→ * Filter commands to only include those safe for remote mode.
680→ * Used to pre-filter commands when rendering the REPL in --remote mode,
681→ * preventing local-only commands from being briefly available before
682→ * the CCR init message arrives.
683→ */
684→export function filterCommandsForRemoteMode(commands: Command[]): Command[] {
685→ return commands.filter(cmd => REMOTE_SAFE_COMMANDS.has(cmd))
686→}
687→
688→export function findCommand(
689→ commandName: string,
690→ commands: Command[],
691→): Command | undefined {
692→ return commands.find(
693→ _ =>
694→ _.name === commandName ||
695→ getCommandName(_) === commandName ||
696→ _.aliases?.includes(commandName),
697→ )
698→}
699→
700→export function hasCommand(commandName: string, commands: Command[]): boolean {
701→ return findCommand(commandName, commands) !== undefined
702→}
703→
704→export function getCommand(commandName: string, commands: Command[]): Command {
705→ const command = findCommand(commandName, commands)
706→ if (!command) {
707→ throw ReferenceError(
708→ `Command ${commandName} not found. Available commands: ${commands
709→ .map(_ => {
710→ const name = getCommandName(_)
711→ return _.aliases ? `${name} (aliases: ${_.aliases.join(', ')})` : name
712→ })
713→ .sort((a, b) => a.localeCompare(b))
714→ .join(', ')}`,
715→ )
716→ }
717→
718→ return command
719→}
720→
721→/**
722→ * Formats a command's description with its source annotation for user-facing UI.
723→ * Use this in typeahead, help screens, and other places where users need to see
724→ * where a command comes from.
725→ *
726→ * For model-facing prompts (like SkillTool), use cmd.description directly.
727→ */
728→export function formatDescriptionWithSource(cmd: Command): string {
729→ if (cmd.type !== 'prompt') {
730→ return cmd.description
731→ }
732→
733→ if (cmd.kind === 'workflow') {
734→ return `${cmd.description} (workflow)`
735→ }
736→
737→ if (cmd.source === 'plugin') {
738→ const pluginName = cmd.pluginInfo?.pluginManifest.name
739→ if (pluginName) {
740→ return `(${pluginName}) ${cmd.description}`
741→ }
742→ return `${cmd.description} (plugin)`
743→ }
744→
745→ if (cmd.source === 'builtin' || cmd.source === 'mcp') {
746→ return cmd.description
747→ }
748→
749→ if (cmd.source === 'bundled') {
750→ return `${cmd.description} (bundled)`
751→ }
752→
753→ return `${cmd.description} (${getSettingSourceName(cmd.source)})`
754→}
755→Tool Call: Read src\bootstrap\state.ts (1 - 120) Status: Completed
1→import type { BetaMessageStreamParams } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
2→import type { Attributes, Meter, MetricOptions } from '@opentelemetry/api'
3→import type { logs } from '@opentelemetry/api-logs'
4→import type { LoggerProvider } from '@opentelemetry/sdk-logs'
5→import type { MeterProvider } from '@opentelemetry/sdk-metrics'
6→import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'
7→import { realpathSync } from 'fs'
8→import sumBy from 'lodash-es/sumBy.js'
9→import { cwd } from 'process'
10→import type { HookEvent, ModelUsage } from 'src/entrypoints/agentSdkTypes.js'
11→import type { AgentColorName } from 'src/tools/AgentTool/agentColorManager.js'
12→import type { HookCallbackMatcher } from 'src/types/hooks.js'
13→// Indirection for browser-sdk build (package.json "browser" field swaps
14→// crypto.ts for crypto.browser.ts). Pure leaf re-export of node:crypto —
15→// zero circular-dep risk. Path-alias import bypasses bootstrap-isolation
16→// (rule only checks ./ and / prefixes); explicit disable documents intent.
17→// eslint-disable-next-line custom-rules/bootstrap-isolation
18→import { randomUUID } from 'src/utils/crypto.js'
19→import type { ModelSetting } from 'src/utils/model/model.js'
20→import type { ModelStrings } from 'src/utils/model/modelStrings.js'
21→import type { SettingSource } from 'src/utils/settings/constants.js'
22→import { resetSettingsCache } from 'src/utils/settings/settingsCache.js'
23→import type { PluginHookMatcher } from 'src/utils/settings/types.js'
24→import { createSignal } from 'src/utils/signal.js'
25→
26→// Union type for registered hooks - can be SDK callbacks or native plugin hooks
27→type RegisteredHookMatcher = HookCallbackMatcher | PluginHookMatcher
28→
29→import type { SessionId } from 'src/types/ids.js'
30→
31→// DO NOT ADD MORE STATE HERE - BE JUDICIOUS WITH GLOBAL STATE
32→
33→// dev: true on entries that came via --dangerously-load-development-channels.
34→// The allowlist gate checks this per-entry (not the session-wide
35→// hasDevChannels bit) so passing both flags doesn't let the dev dialog's
36→// acceptance leak allowlist-bypass to the --channels entries.
37→export type ChannelEntry =
38→ | { kind: 'plugin'; name: string; marketplace: string; dev?: boolean }
39→ | { kind: 'server'; name: string; dev?: boolean }
40→
41→export type AttributedCounter = {
42→ add(value: number, additionalAttributes?: Attributes): void
43→}
44→
45→type State = {
46→ originalCwd: string
47→ // Stable project root - set once at startup (including by --worktree flag),
48→ // never updated by mid-session EnterWorktreeTool.
49→ // Use for project identity (history, skills, sessions) not file operations.
50→ projectRoot: string
51→ totalCostUSD: number
52→ totalAPIDuration: number
53→ totalAPIDurationWithoutRetries: number
54→ totalToolDuration: number
55→ turnHookDurationMs: number
56→ turnToolDurationMs: number
57→ turnClassifierDurationMs: number
58→ turnToolCount: number
59→ turnHookCount: number
60→ turnClassifierCount: number
61→ startTime: number
62→ lastInteractionTime: number
63→ totalLinesAdded: number
64→ totalLinesRemoved: number
65→ hasUnknownModelCost: boolean
66→ cwd: string
67→ modelUsage: { [modelName: string]: ModelUsage }
68→ mainLoopModelOverride: ModelSetting | undefined
69→ initialMainLoopModel: ModelSetting
70→ modelStrings: ModelStrings | null
71→ isInteractive: boolean
72→ kairosActive: boolean
73→ // When true, ensureToolResultPairing throws on mismatch instead of
74→ // repairing with synthetic placeholders. HFI opts in at startup so
75→ // trajectories fail fast rather than conditioning the model on fake
76→ // tool_results.
77→ strictToolResultPairing: boolean
78→ sdkAgentProgressSummariesEnabled: boolean
79→ userMsgOptIn: boolean
80→ clientType: string
81→ sessionSource: string | undefined
82→ questionPreviewFormat: 'markdown' | 'html' | undefined
83→ flagSettingsPath: string | undefined
84→ flagSettingsInline: Record<string, unknown> | null
85→ allowedSettingSources: SettingSource[]
86→ sessionIngressToken: string | null | undefined
87→ oauthTokenFromFd: string | null | undefined
88→ apiKeyFromFd: string | null | undefined
89→ // Telemetry state
90→ meter: Meter | null
91→ sessionCounter: AttributedCounter | null
92→ locCounter: AttributedCounter | null
93→ prCounter: AttributedCounter | null
94→ commitCounter: AttributedCounter | null
95→ costCounter: AttributedCounter | null
96→ tokenCounter: AttributedCounter | null
97→ codeEditToolDecisionCounter: AttributedCounter | null
98→ activeTimeCounter: AttributedCounter | null
99→ statsStore: { observe(name: string, value: number): void } | null
100→ sessionId: SessionId
101→ // Parent session ID for tracking session lineage (e.g., plan mode -> implementation)
102→ parentSessionId: SessionId | undefined
103→ // Logger state
104→ loggerProvider: LoggerProvider | null
105→ eventLogger: ReturnType<typeof logs.getLogger> | null
106→ // Meter provider state
107→ meterProvider: MeterProvider | null
108→ // Tracer provider state
109→ tracerProvider: BasicTracerProvider | null
110→ // Agent color state
111→ agentColorMap: Map<string, AgentColorName>
112→ agentColorIndex: number
113→ // Last API request for bug reports
114→ lastAPIRequest: Omit<BetaMessageStreamParams, 'messages'> | null
115→ // Messages from the last API request (ant-only; reference, not clone).
116→ // Captures the exact post-compaction, CLAUDE.md-injected message set sent
117→ // to the API so /share's serialized_conversation.json reflects reality.
118→ lastAPIRequestMessages: BetaMessageStreamParams['messages'] | null
119→ // Last auto-mode classifier request(s) for /share transcript
120→ lastClassifierRequests: unknown[] | nullTool Call: Read src\commands.ts (1 - 80) Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import addDir from './commands/add-dir/index.js'
3→import autofixPr from './commands/autofix-pr/index.js'
4→import backfillSessions from './commands/backfill-sessions/index.js'
5→import btw from './commands/btw/index.js'
6→import goodClaude from './commands/good-claude/index.js'
7→import issue from './commands/issue/index.js'
8→import feedback from './commands/feedback/index.js'
9→import clear from './commands/clear/index.js'
10→import color from './commands/color/index.js'
11→import commit from './commands/commit.js'
12→import copy from './commands/copy/index.js'
13→import desktop from './commands/desktop/index.js'
14→import commitPushPr from './commands/commit-push-pr.js'
15→import compact from './commands/compact/index.js'
16→import config from './commands/config/index.js'
17→import { context, contextNonInteractive } from './commands/context/index.js'
18→import cost from './commands/cost/index.js'
19→import diff from './commands/diff/index.js'
20→import ctx_viz from './commands/ctx_viz/index.js'
21→import doctor from './commands/doctor/index.js'
22→import memory from './commands/memory/index.js'
23→import help from './commands/help/index.js'
24→import ide from './commands/ide/index.js'
25→import init from './commands/init.js'
26→import initVerifiers from './commands/init-verifiers.js'
27→import keybindings from './commands/keybindings/index.js'
28→import login from './commands/login/index.js'
29→import logout from './commands/logout/index.js'
30→import installGitHubApp from './commands/install-github-app/index.js'
31→import installSlackApp from './commands/install-slack-app/index.js'
32→import breakCache from './commands/break-cache/index.js'
33→import mcp from './commands/mcp/index.js'
34→import mobile from './commands/mobile/index.js'
35→import onboarding from './commands/onboarding/index.js'
36→import pr_comments from './commands/pr_comments/index.js'
37→import releaseNotes from './commands/release-notes/index.js'
38→import rename from './commands/rename/index.js'
39→import resume from './commands/resume/index.js'
40→import review, { ultrareview } from './commands/review.js'
41→import session from './commands/session/index.js'
42→import share from './commands/share/index.js'
43→import skills from './commands/skills/index.js'
44→import status from './commands/status/index.js'
45→import tasks from './commands/tasks/index.js'
46→import teleport from './commands/teleport/index.js'
47→/* eslint-disable @typescript-eslint/no-require-imports */
48→const agentsPlatform =
49→ process.env.USER_TYPE === 'ant'
50→ ? require('./commands/agents-platform/index.js').default
51→ : null
52→/* eslint-enable @typescript-eslint/no-require-imports */
53→import securityReview from './commands/security-review.js'
54→import bughunter from './commands/bughunter/index.js'
55→import terminalSetup from './commands/terminalSetup/index.js'
56→import usage from './commands/usage/index.js'
57→import theme from './commands/theme/index.js'
58→import vim from './commands/vim/index.js'
59→import { feature } from 'bun:bundle'
60→// Dead code elimination: conditional imports
61→/* eslint-disable @typescript-eslint/no-require-imports */
62→const proactive =
63→ feature('PROACTIVE') || feature('KAIROS')
64→ ? require('./commands/proactive.js').default
65→ : null
66→const briefCommand =
67→ feature('KAIROS') || feature('KAIROS_BRIEF')
68→ ? require('./commands/brief.js').default
69→ : null
70→const assistantCommand = feature('KAIROS')
71→ ? require('./commands/assistant/index.js').default
72→ : null
73→const bridge = feature('BRIDGE_MODE')
74→ ? require('./commands/bridge/index.js').default
75→ : null
76→const remoteControlServerCommand =
77→ feature('DAEMON') && feature('BRIDGE_MODE')
78→ ? require('./commands/remoteControlServer/index.js').default
79→ : null
80→const voiceCommand = feature('VOICE_MODE')Tool Call: Read src\main.tsx Status: Failed
File content (789.7KB) exceeds maximum allowed size (256KB). Use offset and limit parameters to read specific portions of the file, or search for specific content instead of reading the whole file.Tool Call: Read src\commands.ts (80 - 199) Status: Completed
80→const voiceCommand = feature('VOICE_MODE')
81→ ? require('./commands/voice/index.js').default
82→ : null
83→const forceSnip = feature('HISTORY_SNIP')
84→ ? require('./commands/force-snip.js').default
85→ : null
86→const workflowsCmd = feature('WORKFLOW_SCRIPTS')
87→ ? (
88→ require('./commands/workflows/index.js') as typeof import('./commands/workflows/index.js')
89→ ).default
90→ : null
91→const webCmd = feature('CCR_REMOTE_SETUP')
92→ ? (
93→ require('./commands/remote-setup/index.js') as typeof import('./commands/remote-setup/index.js')
94→ ).default
95→ : null
96→const clearSkillIndexCache = feature('EXPERIMENTAL_SKILL_SEARCH')
97→ ? (
98→ require('./services/skillSearch/localSearch.js') as typeof import('./services/skillSearch/localSearch.js')
99→ ).clearSkillIndexCache
100→ : null
101→const subscribePr = feature('KAIROS_GITHUB_WEBHOOKS')
102→ ? require('./commands/subscribe-pr.js').default
103→ : null
104→const ultraplan = feature('ULTRAPLAN')
105→ ? require('./commands/ultraplan.js').default
106→ : null
107→const torch = feature('TORCH') ? require('./commands/torch.js').default : null
108→const peersCmd = feature('UDS_INBOX')
109→ ? (
110→ require('./commands/peers/index.js') as typeof import('./commands/peers/index.js')
111→ ).default
112→ : null
113→const forkCmd = feature('FORK_SUBAGENT')
114→ ? (
115→ require('./commands/fork/index.js') as typeof import('./commands/fork/index.js')
116→ ).default
117→ : null
118→const buddy = feature('BUDDY')
119→ ? (
120→ require('./commands/buddy/index.js') as typeof import('./commands/buddy/index.js')
121→ ).default
122→ : null
123→/* eslint-enable @typescript-eslint/no-require-imports */
124→import thinkback from './commands/thinkback/index.js'
125→import thinkbackPlay from './commands/thinkback-play/index.js'
126→import permissions from './commands/permissions/index.js'
127→import plan from './commands/plan/index.js'
128→import fast from './commands/fast/index.js'
129→import passes from './commands/passes/index.js'
130→import privacySettings from './commands/privacy-settings/index.js'
131→import hooks from './commands/hooks/index.js'
132→import files from './commands/files/index.js'
133→import branch from './commands/branch/index.js'
134→import agents from './commands/agents/index.js'
135→import plugin from './commands/plugin/index.js'
136→import reloadPlugins from './commands/reload-plugins/index.js'
137→import rewind from './commands/rewind/index.js'
138→import heapDump from './commands/heapdump/index.js'
139→import mockLimits from './commands/mock-limits/index.js'
140→import bridgeKick from './commands/bridge-kick.js'
141→import version from './commands/version.js'
142→import summary from './commands/summary/index.js'
143→import {
144→ resetLimits,
145→ resetLimitsNonInteractive,
146→} from './commands/reset-limits/index.js'
147→import antTrace from './commands/ant-trace/index.js'
148→import perfIssue from './commands/perf-issue/index.js'
149→import sandboxToggle from './commands/sandbox-toggle/index.js'
150→import chrome from './commands/chrome/index.js'
151→import stickers from './commands/stickers/index.js'
152→import advisor from './commands/advisor.js'
153→import { logError } from './utils/log.js'
154→import { toError } from './utils/errors.js'
155→import { logForDebugging } from './utils/debug.js'
156→import {
157→ getSkillDirCommands,
158→ clearSkillCaches,
159→ getDynamicSkills,
160→} from './skills/loadSkillsDir.js'
161→import { getBundledSkills } from './skills/bundledSkills.js'
162→import { getBuiltinPluginSkillCommands } from './plugins/builtinPlugins.js'
163→import {
164→ getPluginCommands,
165→ clearPluginCommandCache,
166→ getPluginSkills,
167→ clearPluginSkillsCache,
168→} from './utils/plugins/loadPluginCommands.js'
169→import memoize from 'lodash-es/memoize.js'
170→import { isUsing3PServices, isClaudeAISubscriber } from './utils/auth.js'
171→import { isFirstPartyAnthropicBaseUrl } from './utils/model/providers.js'
172→import env from './commands/env/index.js'
173→import exit from './commands/exit/index.js'
174→import exportCommand from './commands/export/index.js'
175→import model from './commands/model/index.js'
176→import tag from './commands/tag/index.js'
177→import outputStyle from './commands/output-style/index.js'
178→import remoteEnv from './commands/remote-env/index.js'
179→import upgrade from './commands/upgrade/index.js'
180→import {
181→ extraUsage,
182→ extraUsageNonInteractive,
183→} from './commands/extra-usage/index.js'
184→import rateLimitOptions from './commands/rate-limit-options/index.js'
185→import statusline from './commands/statusline.js'
186→import effort from './commands/effort/index.js'
187→import stats from './commands/stats/index.js'
188→// insights.ts is 113KB (3200 lines, includes diffLines/html rendering). Lazy
189→// shim defers the heavy module until /insights is actually invoked.
190→const usageReport: Command = {
191→ type: 'prompt',
192→ name: 'insights',
193→ description: 'Generate a report analyzing your Claude Code sessions',
194→ contentLength: 0,
195→ progressMessage: 'analyzing your sessions',
196→ source: 'builtin',
197→ async getPromptForCommand(args, context) {
198→ const real = (await import('./commands/insights.js')).default
199→ if (real.type !== 'prompt') throw new Error('unreachable')Tool Call: Read src\Tool.ts Status: Completed
1→import type {
2→ ToolResultBlockParam,
3→ ToolUseBlockParam,
4→} from '@anthropic-ai/sdk/resources/index.mjs'
5→import type {
6→ ElicitRequestURLParams,
7→ ElicitResult,
8→} from '@modelcontextprotocol/sdk/types.js'
9→import type { UUID } from 'crypto'
10→import type { z } from 'zod/v4'
11→import type { Command } from './commands.js'
12→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
13→import type { ThinkingConfig } from './utils/thinking.js'
14→
15→export type ToolInputJSONSchema = {
16→ [x: string]: unknown
17→ type: 'object'
18→ properties?: {
19→ [x: string]: unknown
20→ }
21→}
22→
23→import type { Notification } from './context/notifications.js'
24→import type {
25→ MCPServerConnection,
26→ ServerResource,
27→} from './services/mcp/types.js'
28→import type {
29→ AgentDefinition,
30→ AgentDefinitionsResult,
31→} from './tools/AgentTool/loadAgentsDir.js'
32→import type {
33→ AssistantMessage,
34→ AttachmentMessage,
35→ Message,
36→ ProgressMessage,
37→ SystemLocalCommandMessage,
38→ SystemMessage,
39→ UserMessage,
40→} from './types/message.js'
41→// Import permission types from centralized location to break import cycles
42→// Import PermissionResult from centralized location to break import cycles
43→import type {
44→ AdditionalWorkingDirectory,
45→ PermissionMode,
46→ PermissionResult,
47→} from './types/permissions.js'
48→// Import tool progress types from centralized location to break import cycles
49→import type {
50→ AgentToolProgress,
51→ BashProgress,
52→ MCPProgress,
53→ REPLToolProgress,
54→ SkillToolProgress,
55→ TaskOutputProgress,
56→ ToolProgressData,
57→ WebSearchProgress,
58→} from './types/tools.js'
59→import type { FileStateCache } from './utils/fileStateCache.js'
60→import type { DenialTrackingState } from './utils/permissions/denialTracking.js'
61→import type { SystemPrompt } from './utils/systemPromptType.js'
62→import type { ContentReplacementState } from './utils/toolResultStorage.js'
63→
64→// Re-export progress types for backwards compatibility
65→export type {
66→ AgentToolProgress,
67→ BashProgress,
68→ MCPProgress,
69→ REPLToolProgress,
70→ SkillToolProgress,
71→ TaskOutputProgress,
72→ WebSearchProgress,
73→}
74→
75→import type { SpinnerMode } from './components/Spinner.js'
76→import type { QuerySource } from './constants/querySource.js'
77→import type { SDKStatus } from './entrypoints/agentSdkTypes.js'
78→import type { AppState } from './state/AppState.js'
79→import type {
80→ HookProgress,
81→ PromptRequest,
82→ PromptResponse,
83→} from './types/hooks.js'
84→import type { AgentId } from './types/ids.js'
85→import type { DeepImmutable } from './types/utils.js'
86→import type { AttributionState } from './utils/commitAttribution.js'
87→import type { FileHistoryState } from './utils/fileHistory.js'
88→import type { Theme, ThemeName } from './utils/theme.js'
89→
90→export type QueryChainTracking = {
91→ chainId: string
92→ depth: number
93→}
94→
95→export type ValidationResult =
96→ | { result: true }
97→ | {
98→ result: false
99→ message: string
100→ errorCode: number
101→ }
102→
103→export type SetToolJSXFn = (
104→ args: {
105→ jsx: React.ReactNode | null
106→ shouldHidePromptInput: boolean
107→ shouldContinueAnimation?: true
108→ showSpinner?: boolean
109→ isLocalJSXCommand?: boolean
110→ isImmediate?: boolean
111→ /** Set to true to clear a local JSX command (e.g., from its onDone callback) */
112→ clearLocalJSX?: boolean
113→ } | null,
114→) => void
115→
116→// Import tool permission types from centralized location to break import cycles
117→import type { ToolPermissionRulesBySource } from './types/permissions.js'
118→
119→// Re-export for backwards compatibility
120→export type { ToolPermissionRulesBySource }
121→
122→// Apply DeepImmutable to the imported type
123→export type ToolPermissionContext = DeepImmutable<{
124→ mode: PermissionMode
125→ additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
126→ alwaysAllowRules: ToolPermissionRulesBySource
127→ alwaysDenyRules: ToolPermissionRulesBySource
128→ alwaysAskRules: ToolPermissionRulesBySource
129→ isBypassPermissionsModeAvailable: boolean
130→ isAutoModeAvailable?: boolean
131→ strippedDangerousRules?: ToolPermissionRulesBySource
132→ /** When true, permission prompts are auto-denied (e.g., background agents that can't show UI) */
133→ shouldAvoidPermissionPrompts?: boolean
134→ /** When true, automated checks (classifier, hooks) are awaited before showing the permission dialog (coordinator workers) */
135→ awaitAutomatedChecksBeforeDialog?: boolean
136→ /** Stores the permission mode before model-initiated plan mode entry, so it can be restored on exit */
137→ prePlanMode?: PermissionMode
138→}>
139→
140→export const getEmptyToolPermissionContext: () => ToolPermissionContext =
141→ () => ({
142→ mode: 'default',
143→ additionalWorkingDirectories: new Map(),
144→ alwaysAllowRules: {},
145→ alwaysDenyRules: {},
146→ alwaysAskRules: {},
147→ isBypassPermissionsModeAvailable: false,
148→ })
149→
150→export type CompactProgressEvent =
151→ | {
152→ type: 'hooks_start'
153→ hookType: 'pre_compact' | 'post_compact' | 'session_start'
154→ }
155→ | { type: 'compact_start' }
156→ | { type: 'compact_end' }
157→
158→export type ToolUseContext = {
159→ options: {
160→ commands: Command[]
161→ debug: boolean
162→ mainLoopModel: string
163→ tools: Tools
164→ verbose: boolean
165→ thinkingConfig: ThinkingConfig
166→ mcpClients: MCPServerConnection[]
167→ mcpResources: Record<string, ServerResource[]>
168→ isNonInteractiveSession: boolean
169→ agentDefinitions: AgentDefinitionsResult
170→ maxBudgetUsd?: number
171→ /** Custom system prompt that replaces the default system prompt */
172→ customSystemPrompt?: string
173→ /** Additional system prompt appended after the main system prompt */
174→ appendSystemPrompt?: string
175→ /** Override querySource for analytics tracking */
176→ querySource?: QuerySource
177→ /** Optional callback to get the latest tools (e.g., after MCP servers connect mid-query) */
178→ refreshTools?: () => Tools
179→ }
180→ abortController: AbortController
181→ readFileState: FileStateCache
182→ getAppState(): AppState
183→ setAppState(f: (prev: AppState) => AppState): void
184→ /**
185→ * Always-shared setAppState for session-scoped infrastructure (background
186→ * tasks, session hooks). Unlike setAppState, which is no-op for async agents
187→ * (see createSubagentContext), this always reaches the root store so agents
188→ * at any nesting depth can register/clean up infrastructure that outlives
189→ * a single turn. Only set by createSubagentContext; main-thread contexts
190→ * fall back to setAppState.
191→ */
192→ setAppStateForTasks?: (f: (prev: AppState) => AppState) => void
193→ /**
194→ * Optional handler for URL elicitations triggered by tool call errors (-32042).
195→ * In print/SDK mode, this delegates to structuredIO.handleElicitation.
196→ * In REPL mode, this is undefined and the queue-based UI path is used.
197→ */
198→ handleElicitation?: (
199→ serverName: string,
200→ params: ElicitRequestURLParams,
201→ signal: AbortSignal,
202→ ) => Promise<ElicitResult>
203→ setToolJSX?: SetToolJSXFn
204→ addNotification?: (notif: Notification) => void
205→ /** Append a UI-only system message to the REPL message list. Stripped at the
206→ * normalizeMessagesForAPI boundary — the Exclude<> makes that type-enforced. */
207→ appendSystemMessage?: (
208→ msg: Exclude<SystemMessage, SystemLocalCommandMessage>,
209→ ) => void
210→ /** Send an OS-level notification (iTerm2, Kitty, Ghostty, bell, etc.) */
211→ sendOSNotification?: (opts: {
212→ message: string
213→ notificationType: string
214→ }) => void
215→ nestedMemoryAttachmentTriggers?: Set<string>
216→ /**
217→ * CLAUDE.md paths already injected as nested_memory attachments this
218→ * session. Dedup for memoryFilesToAttachments — readFileState is an LRU
219→ * that evicts entries in busy sessions, so its .has() check alone can
220→ * re-inject the same CLAUDE.md dozens of times.
221→ */
222→ loadedNestedMemoryPaths?: Set<string>
223→ dynamicSkillDirTriggers?: Set<string>
224→ /** Skill names surfaced via skill_discovery this session. Telemetry only (feeds was_discovered). */
225→ discoveredSkillNames?: Set<string>
226→ userModified?: boolean
227→ setInProgressToolUseIDs: (f: (prev: Set<string>) => Set<string>) => void
228→ /** Only wired in interactive (REPL) contexts; SDK/QueryEngine don't set this. */
229→ setHasInterruptibleToolInProgress?: (v: boolean) => void
230→ setResponseLength: (f: (prev: number) => number) => void
231→ /** Ant-only: push a new API metrics entry for OTPS tracking.
232→ * Called by subagent streaming when a new API request starts. */
233→ pushApiMetricsEntry?: (ttftMs: number) => void
234→ setStreamMode?: (mode: SpinnerMode) => void
235→ onCompactProgress?: (event: CompactProgressEvent) => void
236→ setSDKStatus?: (status: SDKStatus) => void
237→ openMessageSelector?: () => void
238→ updateFileHistoryState: (
239→ updater: (prev: FileHistoryState) => FileHistoryState,
240→ ) => void
241→ updateAttributionState: (
242→ updater: (prev: AttributionState) => AttributionState,
243→ ) => void
244→ setConversationId?: (id: UUID) => void
245→ agentId?: AgentId // Only set for subagents; use getSessionId() for session ID. Hooks use this to distinguish subagent calls.
246→ agentType?: string // Subagent type name. For the main thread's --agent type, hooks fall back to getMainThreadAgentType().
247→ /** When true, canUseTool must always be called even when hooks auto-approve.
248→ * Used by speculation for overlay file path rewriting. */
249→ requireCanUseTool?: boolean
250→ messages: Message[]
251→ fileReadingLimits?: {
252→ maxTokens?: number
253→ maxSizeBytes?: number
254→ }
255→ globLimits?: {
256→ maxResults?: number
257→ }
258→ toolDecisions?: Map<
259→ string,
260→ {
261→ source: string
262→ decision: 'accept' | 'reject'
263→ timestamp: number
264→ }
265→ >
266→ queryTracking?: QueryChainTracking
267→ /** Callback factory for requesting interactive prompts from the user.
268→ * Returns a prompt callback bound to the given source name.
269→ * Only available in interactive (REPL) contexts. */
270→ requestPrompt?: (
271→ sourceName: string,
272→ toolInputSummary?: string | null,
273→ ) => (request: PromptRequest) => Promise<PromptResponse>
274→ toolUseId?: string
275→ criticalSystemReminder_EXPERIMENTAL?: string
276→ /** When true, preserve toolUseResult on messages even for subagents.
277→ * Used by in-process teammates whose transcripts are viewable by the user. */
278→ preserveToolUseResults?: boolean
279→ /** Local denial tracking state for async subagents whose setAppState is a
280→ * no-op. Without this, the denial counter never accumulates and the
281→ * fallback-to-prompting threshold is never reached. Mutable — the
282→ * permissions code updates it in place. */
283→ localDenialTracking?: DenialTrackingState
284→ /**
285→ * Per-conversation-thread content replacement state for the tool result
286→ * budget. When present, query.ts applies the aggregate tool result budget.
287→ * Main thread: REPL provisions once (never resets — stale UUID keys
288→ * are inert). Subagents: createSubagentContext clones the parent's state
289→ * by default (cache-sharing forks need identical decisions), or
290→ * resumeAgentBackground threads one reconstructed from sidechain records.
291→ */
292→ contentReplacementState?: ContentReplacementState
293→ /**
294→ * Parent's rendered system prompt bytes, frozen at turn start.
295→ * Used by fork subagents to share the parent's prompt cache — re-calling
296→ * getSystemPrompt() at fork-spawn time can diverge (GrowthBook cold→warm)
297→ * and bust the cache. See forkSubagent.ts.
298→ */
299→ renderedSystemPrompt?: SystemPrompt
300→}
301→
302→// Re-export ToolProgressData from centralized location
303→export type { ToolProgressData }
304→
305→export type Progress = ToolProgressData | HookProgress
306→
307→export type ToolProgress<P extends ToolProgressData> = {
308→ toolUseID: string
309→ data: P
310→}
311→
312→export function filterToolProgressMessages(
313→ progressMessagesForMessage: ProgressMessage[],
314→): ProgressMessage<ToolProgressData>[] {
315→ return progressMessagesForMessage.filter(
316→ (msg): msg is ProgressMessage<ToolProgressData> =>
317→ msg.data?.type !== 'hook_progress',
318→ )
319→}
320→
321→export type ToolResult<T> = {
322→ data: T
323→ newMessages?: (
324→ | UserMessage
325→ | AssistantMessage
326→ | AttachmentMessage
327→ | SystemMessage
328→ )[]
329→ // contextModifier is only honored for tools that aren't concurrency safe.
330→ contextModifier?: (context: ToolUseContext) => ToolUseContext
331→ /** MCP protocol metadata (structuredContent, _meta) to pass through to SDK consumers */
332→ mcpMeta?: {
333→ _meta?: Record<string, unknown>
334→ structuredContent?: Record<string, unknown>
335→ }
336→}
337→
338→export type ToolCallProgress<P extends ToolProgressData = ToolProgressData> = (
339→ progress: ToolProgress<P>,
340→) => void
341→
342→// Type for any schema that outputs an object with string keys
343→export type AnyObject = z.ZodType<{ [key: string]: unknown }>
344→
345→/**
346→ * Checks if a tool matches the given name (primary name or alias).
347→ */
348→export function toolMatchesName(
349→ tool: { name: string; aliases?: string[] },
350→ name: string,
351→): boolean {
352→ return tool.name === name || (tool.aliases?.includes(name) ?? false)
353→}
354→
355→/**
356→ * Finds a tool by name or alias from a list of tools.
357→ */
358→export function findToolByName(tools: Tools, name: string): Tool | undefined {
359→ return tools.find(t => toolMatchesName(t, name))
360→}
361→
362→export type Tool<
363→ Input extends AnyObject = AnyObject,
364→ Output = unknown,
365→ P extends ToolProgressData = ToolProgressData,
366→> = {
367→ /**
368→ * Optional aliases for backwards compatibility when a tool is renamed.
369→ * The tool can be looked up by any of these names in addition to its primary name.
370→ */
371→ aliases?: string[]
372→ /**
373→ * One-line capability phrase used by ToolSearch for keyword matching.
374→ * Helps the model find this tool via keyword search when it's deferred.
375→ * 3–10 words, no trailing period.
376→ * Prefer terms not already in the tool name (e.g. 'jupyter' for NotebookEdit).
377→ */
378→ searchHint?: string
379→ call(
380→ args: z.infer<Input>,
381→ context: ToolUseContext,
382→ canUseTool: CanUseToolFn,
383→ parentMessage: AssistantMessage,
384→ onProgress?: ToolCallProgress<P>,
385→ ): Promise<ToolResult<Output>>
386→ description(
387→ input: z.infer<Input>,
388→ options: {
389→ isNonInteractiveSession: boolean
390→ toolPermissionContext: ToolPermissionContext
391→ tools: Tools
392→ },
393→ ): Promise<string>
394→ readonly inputSchema: Input
395→ // Type for MCP tools that can specify their input schema directly in JSON Schema format
396→ // rather than converting from Zod schema
397→ readonly inputJSONSchema?: ToolInputJSONSchema
398→ // Optional because TungstenTool doesn't define this. TODO: Make it required.
399→ // When we do that, we can also go through and make this a bit more type-safe.
400→ outputSchema?: z.ZodType<unknown>
401→ inputsEquivalent?(a: z.infer<Input>, b: z.infer<Input>): boolean
402→ isConcurrencySafe(input: z.infer<Input>): boolean
403→ isEnabled(): boolean
404→ isReadOnly(input: z.infer<Input>): boolean
405→ /** Defaults to false. Only set when the tool performs irreversible operations (delete, overwrite, send). */
406→ isDestructive?(input: z.infer<Input>): boolean
407→ /**
408→ * What should happen when the user submits a new message while this tool
409→ * is running.
410→ *
411→ * - `'cancel'` — stop the tool and discard its result
412→ * - `'block'` — keep running; the new message waits
413→ *
414→ * Defaults to `'block'` when not implemented.
415→ */
416→ interruptBehavior?(): 'cancel' | 'block'
417→ /**
418→ * Returns information about whether this tool use is a search or read operation
419→ * that should be collapsed into a condensed display in the UI. Examples include
420→ * file searching (Grep, Glob), file reading (Read), and bash commands like find,
421→ * grep, wc, etc.
422→ *
423→ * Returns an object indicating whether the operation is a search or read operation:
424→ * - `isSearch: true` for search operations (grep, find, glob patterns)
425→ * - `isRead: true` for read operations (cat, head, tail, file read)
426→ * - `isList: true` for directory-listing operations (ls, tree, du)
427→ * - All can be false if the operation shouldn't be collapsed
428→ */
429→ isSearchOrReadCommand?(input: z.infer<Input>): {
430→ isSearch: boolean
431→ isRead: boolean
432→ isList?: boolean
433→ }
434→ isOpenWorld?(input: z.infer<Input>): boolean
435→ requiresUserInteraction?(): boolean
436→ isMcp?: boolean
437→ isLsp?: boolean
438→ /**
439→ * When true, this tool is deferred (sent with defer_loading: true) and requires
440→ * ToolSearch to be used before it can be called.
441→ */
442→ readonly shouldDefer?: boolean
443→ /**
444→ * When true, this tool is never deferred — its full schema appears in the
445→ * initial prompt even when ToolSearch is enabled. For MCP tools, set via
446→ * `_meta['anthropic/alwaysLoad']`. Use for tools the model must see on
447→ * turn 1 without a ToolSearch round-trip.
448→ */
449→ readonly alwaysLoad?: boolean
450→ /**
451→ * For MCP tools: the server and tool names as received from the MCP server (unnormalized).
452→ * Present on all MCP tools regardless of whether `name` is prefixed (mcp__server__tool)
453→ * or unprefixed (CLAUDE_AGENT_SDK_MCP_NO_PREFIX mode).
454→ */
455→ mcpInfo?: { serverName: string; toolName: string }
456→ readonly name: string
457→ /**
458→ * Maximum size in characters for tool result before it gets persisted to disk.
459→ * When exceeded, the result is saved to a file and Claude receives a preview
460→ * with the file path instead of the full content.
461→ *
462→ * Set to Infinity for tools whose output must never be persisted (e.g. Read,
463→ * where persisting creates a circular Read→file→Read loop and the tool
464→ * already self-bounds via its own limits).
465→ */
466→ maxResultSizeChars: number
467→ /**
468→ * When true, enables strict mode for this tool, which causes the API to
469→ * more strictly adhere to tool instructions and parameter schemas.
470→ * Only applied when the tengu_tool_pear is enabled.
471→ */
472→ readonly strict?: boolean
473→
474→ /**
475→ * Called on copies of tool_use input before observers see it (SDK stream,
476→ * transcript, canUseTool, PreToolUse/PostToolUse hooks). Mutate in place
477→ * to add legacy/derived fields. Must be idempotent. The original API-bound
478→ * input is never mutated (preserves prompt cache). Not re-applied when a
479→ * hook/permission returns a fresh updatedInput — those own their shape.
480→ */
481→ backfillObservableInput?(input: Record<string, unknown>): void
482→
483→ /**
484→ * Determines if this tool is allowed to run with this input in the current context.
485→ * It informs the model of why the tool use failed, and does not directly display any UI.
486→ * @param input
487→ * @param context
488→ */
489→ validateInput?(
490→ input: z.infer<Input>,
491→ context: ToolUseContext,
492→ ): Promise<ValidationResult>
493→
494→ /**
495→ * Determines if the user is asked for permission. Only called after validateInput() passes.
496→ * General permission logic is in permissions.ts. This method contains tool-specific logic.
497→ * @param input
498→ * @param context
499→ */
500→ checkPermissions(
501→ input: z.infer<Input>,
502→ context: ToolUseContext,
503→ ): Promise<PermissionResult>
504→
505→ // Optional method for tools that operate on a file path
506→ getPath?(input: z.infer<Input>): string
507→
508→ /**
509→ * Prepare a matcher for hook `if` conditions (permission-rule patterns like
510→ * "git *" from "Bash(git *)"). Called once per hook-input pair; any
511→ * expensive parsing happens here. Returns a closure that is called per
512→ * hook pattern. If not implemented, only tool-name-level matching works.
513→ */
514→ preparePermissionMatcher?(
515→ input: z.infer<Input>,
516→ ): Promise<(pattern: string) => boolean>
517→
518→ prompt(options: {
519→ getToolPermissionContext: () => Promise<ToolPermissionContext>
520→ tools: Tools
521→ agents: AgentDefinition[]
522→ allowedAgentTypes?: string[]
523→ }): Promise<string>
524→ userFacingName(input: Partial<z.infer<Input>> | undefined): string
525→ userFacingNameBackgroundColor?(
526→ input: Partial<z.infer<Input>> | undefined,
527→ ): keyof Theme | undefined
528→ /**
529→ * Transparent wrappers (e.g. REPL) delegate all rendering to their progress
530→ * handler, which emits native-looking blocks for each inner tool call.
531→ * The wrapper itself shows nothing.
532→ */
533→ isTransparentWrapper?(): boolean
534→ /**
535→ * Returns a short string summary of this tool use for display in compact views.
536→ * @param input The tool input
537→ * @returns A short string summary, or null to not display
538→ */
539→ getToolUseSummary?(input: Partial<z.infer<Input>> | undefined): string | null
540→ /**
541→ * Returns a human-readable present-tense activity description for spinner display.
542→ * Example: "Reading src/foo.ts", "Running bun test", "Searching for pattern"
543→ * @param input The tool input
544→ * @returns Activity description string, or null to fall back to tool name
545→ */
546→ getActivityDescription?(
547→ input: Partial<z.infer<Input>> | undefined,
548→ ): string | null
549→ /**
550→ * Returns a compact representation of this tool use for the auto-mode
551→ * security classifier. Examples: `ls -la` for Bash, `/tmp/x: new content`
552→ * for Edit. Return '' to skip this tool in the classifier transcript
553→ * (e.g. tools with no security relevance). May return an object to avoid
554→ * double-encoding when the caller JSON-wraps the value.
555→ */
556→ toAutoClassifierInput(input: z.infer<Input>): unknown
557→ mapToolResultToToolResultBlockParam(
558→ content: Output,
559→ toolUseID: string,
560→ ): ToolResultBlockParam
561→ /**
562→ * Optional. When omitted, the tool result renders nothing (same as returning
563→ * null). Omit for tools whose results are surfaced elsewhere (e.g., TodoWrite
564→ * updates the todo panel, not the transcript).
565→ */
566→ renderToolResultMessage?(
567→ content: Output,
568→ progressMessagesForMessage: ProgressMessage<P>[],
569→ options: {
570→ style?: 'condensed'
571→ theme: ThemeName
572→ tools: Tools
573→ verbose: boolean
574→ isTranscriptMode?: boolean
575→ isBriefOnly?: boolean
576→ /** Original tool_use input, when available. Useful for compact result
577→ * summaries that reference what was requested (e.g. "Sent to #foo"). */
578→ input?: unknown
579→ },
580→ ): React.ReactNode
581→ /**
582→ * Flattened text of what renderToolResultMessage shows IN TRANSCRIPT
583→ * MODE (verbose=true, isTranscriptMode=true). For transcript search
584→ * indexing: the index counts occurrences in this string, the highlight
585→ * overlay scans the actual screen buffer. For count ≡ highlight, this
586→ * must return the text that ends up visible — not the model-facing
587→ * serialization from mapToolResultToToolResultBlockParam (which adds
588→ * system-reminders, persisted-output wrappers).
589→ *
590→ * Chrome can be skipped (under-count is fine). "Found 3 files in 12ms"
591→ * isn't worth indexing. Phantoms are not fine — text that's claimed
592→ * here but doesn't render is a count≠highlight bug.
593→ *
594→ * Optional: omitted → field-name heuristic in transcriptSearch.ts.
595→ * Drift caught by test/utils/transcriptSearch.renderFidelity.test.tsx
596→ * which renders sample outputs and flags text that's indexed-but-not-
597→ * rendered (phantom) or rendered-but-not-indexed (under-count warning).
598→ */
599→ extractSearchText?(out: Output): string
600→ /**
601→ * Render the tool use message. Note that `input` is partial because we render
602→ * the message as soon as possible, possibly before tool parameters have fully
603→ * streamed in.
604→ */
605→ renderToolUseMessage(
606→ input: Partial<z.infer<Input>>,
607→ options: { theme: ThemeName; verbose: boolean; commands?: Command[] },
608→ ): React.ReactNode
609→ /**
610→ * Returns true when the non-verbose rendering of this output is truncated
611→ * (i.e., clicking to expand would reveal more content). Gates
612→ * click-to-expand in fullscreen — only messages where verbose actually
613→ * shows more get a hover/click affordance. Unset means never truncated.
614→ */
615→ isResultTruncated?(output: Output): boolean
616→ /**
617→ * Renders an optional tag to display after the tool use message.
618→ * Used for additional metadata like timeout, model, resume ID, etc.
619→ * Returns null to not display anything.
620→ */
621→ renderToolUseTag?(input: Partial<z.infer<Input>>): React.ReactNode
622→ /**
623→ * Optional. When omitted, no progress UI is shown while the tool runs.
624→ */
625→ renderToolUseProgressMessage?(
626→ progressMessagesForMessage: ProgressMessage<P>[],
627→ options: {
628→ tools: Tools
629→ verbose: boolean
630→ terminalSize?: { columns: number; rows: number }
631→ inProgressToolCallCount?: number
632→ isTranscriptMode?: boolean
633→ },
634→ ): React.ReactNode
635→ renderToolUseQueuedMessage?(): React.ReactNode
636→ /**
637→ * Optional. When omitted, falls back to <FallbackToolUseRejectedMessage />.
638→ * Only define this for tools that need custom rejection UI (e.g., file edits
639→ * that show the rejected diff).
640→ */
641→ renderToolUseRejectedMessage?(
642→ input: z.infer<Input>,
643→ options: {
644→ columns: number
645→ messages: Message[]
646→ style?: 'condensed'
647→ theme: ThemeName
648→ tools: Tools
649→ verbose: boolean
650→ progressMessagesForMessage: ProgressMessage<P>[]
651→ isTranscriptMode?: boolean
652→ },
653→ ): React.ReactNode
654→ /**
655→ * Optional. When omitted, falls back to <FallbackToolUseErrorMessage />.
656→ * Only define this for tools that need custom error UI (e.g., search tools
657→ * that show "File not found" instead of the raw error).
658→ */
659→ renderToolUseErrorMessage?(
660→ result: ToolResultBlockParam['content'],
661→ options: {
662→ progressMessagesForMessage: ProgressMessage<P>[]
663→ tools: Tools
664→ verbose: boolean
665→ isTranscriptMode?: boolean
666→ },
667→ ): React.ReactNode
668→
669→ /**
670→ * Renders multiple parallel instances of this tool as a group.
671→ * @returns React node to render, or null to fall back to individual rendering
672→ */
673→ /**
674→ * Renders multiple tool uses as a group (non-verbose mode only).
675→ * In verbose mode, individual tool uses render at their original positions.
676→ * @returns React node to render, or null to fall back to individual rendering
677→ */
678→ renderGroupedToolUse?(
679→ toolUses: Array<{
680→ param: ToolUseBlockParam
681→ isResolved: boolean
682→ isError: boolean
683→ isInProgress: boolean
684→ progressMessages: ProgressMessage<P>[]
685→ result?: {
686→ param: ToolResultBlockParam
687→ output: unknown
688→ }
689→ }>,
690→ options: {
691→ shouldAnimate: boolean
692→ tools: Tools
693→ },
694→ ): React.ReactNode | null
695→}
696→
697→/**
698→ * A collection of tools. Use this type instead of `Tool[]` to make it easier
699→ * to track where tool sets are assembled, passed, and filtered across the codebase.
700→ */
701→export type Tools = readonly Tool[]
702→
703→/**
704→ * Methods that `buildTool` supplies a default for. A `ToolDef` may omit these;
705→ * the resulting `Tool` always has them.
706→ */
707→type DefaultableToolKeys =
708→ | 'isEnabled'
709→ | 'isConcurrencySafe'
710→ | 'isReadOnly'
711→ | 'isDestructive'
712→ | 'checkPermissions'
713→ | 'toAutoClassifierInput'
714→ | 'userFacingName'
715→
716→/**
717→ * Tool definition accepted by `buildTool`. Same shape as `Tool` but with the
718→ * defaultable methods optional — `buildTool` fills them in so callers always
719→ * see a complete `Tool`.
720→ */
721→export type ToolDef<
722→ Input extends AnyObject = AnyObject,
723→ Output = unknown,
724→ P extends ToolProgressData = ToolProgressData,
725→> = Omit<Tool<Input, Output, P>, DefaultableToolKeys> &
726→ Partial<Pick<Tool<Input, Output, P>, DefaultableToolKeys>>
727→
728→/**
729→ * Type-level spread mirroring `{ ...TOOL_DEFAULTS, ...def }`. For each
730→ * defaultable key: if D provides it (required), D's type wins; if D omits
731→ * it or has it optional (inherited from Partial<> in the constraint), the
732→ * default fills in. All other keys come from D verbatim — preserving arity,
733→ * optional presence, and literal types exactly as `satisfies Tool` did.
734→ */
735→type BuiltTool<D> = Omit<D, DefaultableToolKeys> & {
736→ [K in DefaultableToolKeys]-?: K extends keyof D
737→ ? undefined extends D[K]
738→ ? ToolDefaults[K]
739→ : D[K]
740→ : ToolDefaults[K]
741→}
742→
743→/**
744→ * Build a complete `Tool` from a partial definition, filling in safe defaults
745→ * for the commonly-stubbed methods. All tool exports should go through this so
746→ * that defaults live in one place and callers never need `?.() ?? default`.
747→ *
748→ * Defaults (fail-closed where it matters):
749→ * - `isEnabled` → `true`
750→ * - `isConcurrencySafe` → `false` (assume not safe)
751→ * - `isReadOnly` → `false` (assume writes)
752→ * - `isDestructive` → `false`
753→ * - `checkPermissions` → `{ behavior: 'allow', updatedInput }` (defer to general permission system)
754→ * - `toAutoClassifierInput` → `''` (skip classifier — security-relevant tools must override)
755→ * - `userFacingName` → `name`
756→ */
757→const TOOL_DEFAULTS = {
758→ isEnabled: () => true,
759→ isConcurrencySafe: (_input?: unknown) => false,
760→ isReadOnly: (_input?: unknown) => false,
761→ isDestructive: (_input?: unknown) => false,
762→ checkPermissions: (
763→ input: { [key: string]: unknown },
764→ _ctx?: ToolUseContext,
765→ ): Promise<PermissionResult> =>
766→ Promise.resolve({ behavior: 'allow', updatedInput: input }),
767→ toAutoClassifierInput: (_input?: unknown) => '',
768→ userFacingName: (_input?: unknown) => '',
769→}
770→
771→// The defaults type is the ACTUAL shape of TOOL_DEFAULTS (optional params so
772→// both 0-arg and full-arg call sites type-check — stubs varied in arity and
773→// tests relied on that), not the interface's strict signatures.
774→type ToolDefaults = typeof TOOL_DEFAULTS
775→
776→// D infers the concrete object-literal type from the call site. The
777→// constraint provides contextual typing for method parameters; `any` in
778→// constraint position is structural and never leaks into the return type.
779→// BuiltTool<D> mirrors runtime `{...TOOL_DEFAULTS, ...def}` at the type level.
780→// eslint-disable-next-line @typescript-eslint/no-explicit-any
781→type AnyToolDef = ToolDef<any, any, any>
782→
783→export function buildTool<D extends AnyToolDef>(def: D): BuiltTool<D> {
784→ // The runtime spread is straightforward; the `as` bridges the gap between
785→ // the structural-any constraint and the precise BuiltTool<D> return. The
786→ // type semantics are proven by the 0-error typecheck across all 60+ tools.
787→ return {
788→ ...TOOL_DEFAULTS,
789→ userFacingName: () => def.name,
790→ ...def,
791→ } as BuiltTool<D>
792→}
793→Tool Call: Read src\types Status: Failed
EISDIR: illegal operation on a directory, read 'D:\code\play\stock_ai_rust\claude-code\src\types'Tool Call: Read src\query.ts (1 - 100) Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import type {
3→ ToolResultBlockParam,
4→ ToolUseBlock,
5→} from '@anthropic-ai/sdk/resources/index.mjs'
6→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
7→import { FallbackTriggeredError } from './services/api/withRetry.js'
8→import {
9→ calculateTokenWarningState,
10→ isAutoCompactEnabled,
11→ type AutoCompactTrackingState,
12→} from './services/compact/autoCompact.js'
13→import { buildPostCompactMessages } from './services/compact/compact.js'
14→/* eslint-disable @typescript-eslint/no-require-imports */
15→const reactiveCompact = feature('REACTIVE_COMPACT')
16→ ? (require('./services/compact/reactiveCompact.js') as typeof import('./services/compact/reactiveCompact.js'))
17→ : null
18→const contextCollapse = feature('CONTEXT_COLLAPSE')
19→ ? (require('./services/contextCollapse/index.js') as typeof import('./services/contextCollapse/index.js'))
20→ : null
21→/* eslint-enable @typescript-eslint/no-require-imports */
22→import {
23→ logEvent,
24→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
25→} from 'src/services/analytics/index.js'
26→import { ImageSizeError } from './utils/imageValidation.js'
27→import { ImageResizeError } from './utils/imageResizer.js'
28→import { findToolByName, type ToolUseContext } from './Tool.js'
29→import { asSystemPrompt, type SystemPrompt } from './utils/systemPromptType.js'
30→import type {
31→ AssistantMessage,
32→ AttachmentMessage,
33→ Message,
34→ RequestStartEvent,
35→ StreamEvent,
36→ ToolUseSummaryMessage,
37→ UserMessage,
38→ TombstoneMessage,
39→} from './types/message.js'
40→import { logError } from './utils/log.js'
41→import {
42→ PROMPT_TOO_LONG_ERROR_MESSAGE,
43→ isPromptTooLongMessage,
44→} from './services/api/errors.js'
45→import { logAntError, logForDebugging } from './utils/debug.js'
46→import {
47→ createUserMessage,
48→ createUserInterruptionMessage,
49→ normalizeMessagesForAPI,
50→ createSystemMessage,
51→ createAssistantAPIErrorMessage,
52→ getMessagesAfterCompactBoundary,
53→ createToolUseSummaryMessage,
54→ createMicrocompactBoundaryMessage,
55→ stripSignatureBlocks,
56→} from './utils/messages.js'
57→import { generateToolUseSummary } from './services/toolUseSummary/toolUseSummaryGenerator.js'
58→import { prependUserContext, appendSystemContext } from './utils/api.js'
59→import {
60→ createAttachmentMessage,
61→ filterDuplicateMemoryAttachments,
62→ getAttachmentMessages,
63→ startRelevantMemoryPrefetch,
64→} from './utils/attachments.js'
65→/* eslint-disable @typescript-eslint/no-require-imports */
66→const skillPrefetch = feature('EXPERIMENTAL_SKILL_SEARCH')
67→ ? (require('./services/skillSearch/prefetch.js') as typeof import('./services/skillSearch/prefetch.js'))
68→ : null
69→const jobClassifier = feature('TEMPLATES')
70→ ? (require('./jobs/classifier.js') as typeof import('./jobs/classifier.js'))
71→ : null
72→/* eslint-enable @typescript-eslint/no-require-imports */
73→import {
74→ remove as removeFromQueue,
75→ getCommandsByMaxPriority,
76→ isSlashCommand,
77→} from './utils/messageQueueManager.js'
78→import { notifyCommandLifecycle } from './utils/commandLifecycle.js'
79→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
80→import {
81→ getRuntimeMainLoopModel,
82→ renderModelName,
83→} from './utils/model/model.js'
84→import {
85→ doesMostRecentAssistantMessageExceed200k,
86→ finalContextTokensFromLastResponse,
87→ tokenCountWithEstimation,
88→} from './utils/tokens.js'
89→import { ESCALATED_MAX_TOKENS } from './utils/context.js'
90→import { getFeatureValue_CACHED_MAY_BE_STALE } from './services/analytics/growthbook.js'
91→import { SLEEP_TOOL_NAME } from './tools/SleepTool/prompt.js'
92→import { executePostSamplingHooks } from './utils/hooks/postSamplingHooks.js'
93→import { executeStopFailureHooks } from './utils/hooks.js'
94→import type { QuerySource } from './constants/querySource.js'
95→import { createDumpPromptsFetch } from './services/api/dumpPrompts.js'
96→import { StreamingToolExecutor } from './services/tools/StreamingToolExecutor.js'
97→import { queryCheckpoint } from './utils/queryProfiler.js'
98→import { runTools } from './services/tools/toolOrchestration.js'
99→import { applyToolResultBudget } from './utils/toolResultStorage.js'
100→import { recordContentReplacement } from './utils/sessionStorage.js'Tool Call: Read src\Task.ts Status: Completed
1→import { randomBytes } from 'crypto'
2→import type { AppState } from './state/AppState.js'
3→import type { AgentId } from './types/ids.js'
4→import { getTaskOutputPath } from './utils/task/diskOutput.js'
5→
6→export type TaskType =
7→ | 'local_bash'
8→ | 'local_agent'
9→ | 'remote_agent'
10→ | 'in_process_teammate'
11→ | 'local_workflow'
12→ | 'monitor_mcp'
13→ | 'dream'
14→
15→export type TaskStatus =
16→ | 'pending'
17→ | 'running'
18→ | 'completed'
19→ | 'failed'
20→ | 'killed'
21→
22→/**
23→ * True when a task is in a terminal state and will not transition further.
24→ * Used to guard against injecting messages into dead teammates, evicting
25→ * finished tasks from AppState, and orphan-cleanup paths.
26→ */
27→export function isTerminalTaskStatus(status: TaskStatus): boolean {
28→ return status === 'completed' || status === 'failed' || status === 'killed'
29→}
30→
31→export type TaskHandle = {
32→ taskId: string
33→ cleanup?: () => void
34→}
35→
36→export type SetAppState = (f: (prev: AppState) => AppState) => void
37→
38→export type TaskContext = {
39→ abortController: AbortController
40→ getAppState: () => AppState
41→ setAppState: SetAppState
42→}
43→
44→// Base fields shared by all task states
45→export type TaskStateBase = {
46→ id: string
47→ type: TaskType
48→ status: TaskStatus
49→ description: string
50→ toolUseId?: string
51→ startTime: number
52→ endTime?: number
53→ totalPausedMs?: number
54→ outputFile: string
55→ outputOffset: number
56→ notified: boolean
57→}
58→
59→export type LocalShellSpawnInput = {
60→ command: string
61→ description: string
62→ timeout?: number
63→ toolUseId?: string
64→ agentId?: AgentId
65→ /** UI display variant: description-as-label, dialog title, status bar pill. */
66→ kind?: 'bash' | 'monitor'
67→}
68→
69→// What getTaskByType dispatches for: kill. spawn/render were never
70→// called polymorphically (removed in #22546). All six kill implementations
71→// use only setAppState — getAppState/abortController were dead weight.
72→export type Task = {
73→ name: string
74→ type: TaskType
75→ kill(taskId: string, setAppState: SetAppState): Promise<void>
76→}
77→
78→// Task ID prefixes
79→const TASK_ID_PREFIXES: Record<string, string> = {
80→ local_bash: 'b', // Keep as 'b' for backward compatibility
81→ local_agent: 'a',
82→ remote_agent: 'r',
83→ in_process_teammate: 't',
84→ local_workflow: 'w',
85→ monitor_mcp: 'm',
86→ dream: 'd',
87→}
88→
89→// Get task ID prefix
90→function getTaskIdPrefix(type: TaskType): string {
91→ return TASK_ID_PREFIXES[type] ?? 'x'
92→}
93→
94→// Case-insensitive-safe alphabet (digits + lowercase) for task IDs.
95→// 36^8 ≈ 2.8 trillion combinations, sufficient to resist brute-force symlink attacks.
96→const TASK_ID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
97→
98→export function generateTaskId(type: TaskType): string {
99→ const prefix = getTaskIdPrefix(type)
100→ const bytes = randomBytes(8)
101→ let id = prefix
102→ for (let i = 0; i < 8; i++) {
103→ id += TASK_ID_ALPHABET[bytes[i]! % TASK_ID_ALPHABET.length]
104→ }
105→ return id
106→}
107→
108→export function createTaskStateBase(
109→ id: string,
110→ type: TaskType,
111→ description: string,
112→ toolUseId?: string,
113→): TaskStateBase {
114→ return {
115→ id,
116→ type,
117→ status: 'pending',
118→ description,
119→ toolUseId,
120→ startTime: Date.now(),
121→ outputFile: getTaskOutputPath(id),
122→ outputOffset: 0,
123→ notified: false,
124→ }
125→}
126→Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/**/* Status: Completed
src\types\command.ts src\types\generated\events_mono\claude_code\v1\claude_code_internal_event.ts src\types\generated\events_mono\common\v1\auth.ts src\types\generated\events_mono\growthbook\v1\growthbook_experiment_event.ts src\types\generated\google\protobuf\timestamp.ts src\types\hooks.ts src\types\ids.ts src\types\logs.ts src\types\permissions.ts src\types\plugin.ts src\types\textInputTypes.ts
Tool Call: Read src\types\command.ts Status: Completed
1→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
2→import type { UUID } from 'crypto'
3→import type { CanUseToolFn } from '../hooks/useCanUseTool.js'
4→import type { CompactionResult } from '../services/compact/compact.js'
5→import type { ScopedMcpServerConfig } from '../services/mcp/types.js'
6→import type { ToolUseContext } from '../Tool.js'
7→import type { EffortValue } from '../utils/effort.js'
8→import type { IDEExtensionInstallationStatus, IdeType } from '../utils/ide.js'
9→import type { SettingSource } from '../utils/settings/constants.js'
10→import type { HooksSettings } from '../utils/settings/types.js'
11→import type { ThemeName } from '../utils/theme.js'
12→import type { LogOption } from './logs.js'
13→import type { Message } from './message.js'
14→import type { PluginManifest } from './plugin.js'
15→
16→export type LocalCommandResult =
17→ | { type: 'text'; value: string }
18→ | {
19→ type: 'compact'
20→ compactionResult: CompactionResult
21→ displayText?: string
22→ }
23→ | { type: 'skip' } // Skip messages
24→
25→export type PromptCommand = {
26→ type: 'prompt'
27→ progressMessage: string
28→ contentLength: number // Length of command content in characters (used for token estimation)
29→ argNames?: string[]
30→ allowedTools?: string[]
31→ model?: string
32→ source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
33→ pluginInfo?: {
34→ pluginManifest: PluginManifest
35→ repository: string
36→ }
37→ disableNonInteractive?: boolean
38→ // Hooks to register when this skill is invoked
39→ hooks?: HooksSettings
40→ // Base directory for skill resources (used to set CLAUDE_PLUGIN_ROOT environment variable for skill hooks)
41→ skillRoot?: string
42→ // Execution context: 'inline' (default) or 'fork' (run as sub-agent)
43→ // 'inline' = skill content expands into the current conversation
44→ // 'fork' = skill runs in a sub-agent with separate context and token budget
45→ context?: 'inline' | 'fork'
46→ // Agent type to use when forked (e.g., 'Bash', 'general-purpose')
47→ // Only applicable when context is 'fork'
48→ agent?: string
49→ effort?: EffortValue
50→ // Glob patterns for file paths this skill applies to
51→ // When set, the skill is only visible after the model touches matching files
52→ paths?: string[]
53→ getPromptForCommand(
54→ args: string,
55→ context: ToolUseContext,
56→ ): Promise<ContentBlockParam[]>
57→}
58→
59→/**
60→ * The call signature for a local command implementation.
61→ */
62→export type LocalCommandCall = (
63→ args: string,
64→ context: LocalJSXCommandContext,
65→) => Promise<LocalCommandResult>
66→
67→/**
68→ * Module shape returned by load() for lazy-loaded local commands.
69→ */
70→export type LocalCommandModule = {
71→ call: LocalCommandCall
72→}
73→
74→type LocalCommand = {
75→ type: 'local'
76→ supportsNonInteractive: boolean
77→ load: () => Promise<LocalCommandModule>
78→}
79→
80→export type LocalJSXCommandContext = ToolUseContext & {
81→ canUseTool?: CanUseToolFn
82→ setMessages: (updater: (prev: Message[]) => Message[]) => void
83→ options: {
84→ dynamicMcpConfig?: Record<string, ScopedMcpServerConfig>
85→ ideInstallationStatus: IDEExtensionInstallationStatus | null
86→ theme: ThemeName
87→ }
88→ onChangeAPIKey: () => void
89→ onChangeDynamicMcpConfig?: (
90→ config: Record<string, ScopedMcpServerConfig>,
91→ ) => void
92→ onInstallIDEExtension?: (ide: IdeType) => void
93→ resume?: (
94→ sessionId: UUID,
95→ log: LogOption,
96→ entrypoint: ResumeEntrypoint,
97→ ) => Promise<void>
98→}
99→
100→export type ResumeEntrypoint =
101→ | 'cli_flag'
102→ | 'slash_command_picker'
103→ | 'slash_command_session_id'
104→ | 'slash_command_title'
105→ | 'fork'
106→
107→export type CommandResultDisplay = 'skip' | 'system' | 'user'
108→
109→/**
110→ * Callback when a command completes.
111→ * @param result - Optional user-visible message to display
112→ * @param options - Optional configuration for command completion
113→ * @param options.display - How to display the result: 'skip' | 'system' | 'user' (default)
114→ * @param options.shouldQuery - If true, send messages to the model after command completes
115→ * @param options.metaMessages - Additional messages to insert as isMeta (model-visible but hidden)
116→ */
117→export type LocalJSXCommandOnDone = (
118→ result?: string,
119→ options?: {
120→ display?: CommandResultDisplay
121→ shouldQuery?: boolean
122→ metaMessages?: string[]
123→ nextInput?: string
124→ submitNextInput?: boolean
125→ },
126→) => void
127→
128→/**
129→ * The call signature for a local JSX command implementation.
130→ */
131→export type LocalJSXCommandCall = (
132→ onDone: LocalJSXCommandOnDone,
133→ context: ToolUseContext & LocalJSXCommandContext,
134→ args: string,
135→) => Promise<React.ReactNode>
136→
137→/**
138→ * Module shape returned by load() for lazy-loaded commands.
139→ */
140→export type LocalJSXCommandModule = {
141→ call: LocalJSXCommandCall
142→}
143→
144→type LocalJSXCommand = {
145→ type: 'local-jsx'
146→ /**
147→ * Lazy-load the command implementation.
148→ * Returns a module with a call() function.
149→ * This defers loading heavy dependencies until the command is invoked.
150→ */
151→ load: () => Promise<LocalJSXCommandModule>
152→}
153→
154→/**
155→ * Declares which auth/provider environments a command is available in.
156→ *
157→ * This is separate from `isEnabled()`:
158→ * - `availability` = who can use this (auth/provider requirement, static)
159→ * - `isEnabled()` = is this turned on right now (GrowthBook, platform, env vars)
160→ *
161→ * Commands without `availability` are available everywhere.
162→ * Commands with `availability` are only shown if the user matches at least one
163→ * of the listed auth types. See meetsAvailabilityRequirement() in commands.ts.
164→ *
165→ * Example: `availability: ['claude-ai', 'console']` shows the command to
166→ * claude.ai subscribers and direct Console API key users (api.anthropic.com),
167→ * but hides it from Bedrock/Vertex/Foundry users and custom base URL users.
168→ */
169→export type CommandAvailability =
170→ // claude.ai OAuth subscriber (Pro/Max/Team/Enterprise via claude.ai)
171→ | 'claude-ai'
172→ // Console API key user (direct api.anthropic.com, not via claude.ai OAuth)
173→ | 'console'
174→
175→export type CommandBase = {
176→ availability?: CommandAvailability[]
177→ description: string
178→ hasUserSpecifiedDescription?: boolean
179→ /** Defaults to true. Only set when the command has conditional enablement (feature flags, env checks, etc). */
180→ isEnabled?: () => boolean
181→ /** Defaults to false. Only set when the command should be hidden from typeahead/help. */
182→ isHidden?: boolean
183→ name: string
184→ aliases?: string[]
185→ isMcp?: boolean
186→ argumentHint?: string // Hint text for command arguments (displayed in gray after command)
187→ whenToUse?: string // From the "Skill" spec. Detailed usage scenarios for when to use this command
188→ version?: string // Version of the command/skill
189→ disableModelInvocation?: boolean // Whether to disable this command from being invoked by models
190→ userInvocable?: boolean // Whether users can invoke this skill by typing /skill-name
191→ loadedFrom?:
192→ | 'commands_DEPRECATED'
193→ | 'skills'
194→ | 'plugin'
195→ | 'managed'
196→ | 'bundled'
197→ | 'mcp' // Where the command was loaded from
198→ kind?: 'workflow' // Distinguishes workflow-backed commands (badged in autocomplete)
199→ immediate?: boolean // If true, command executes immediately without waiting for a stop point (bypasses queue)
200→ isSensitive?: boolean // If true, args are redacted from the conversation history
201→ /** Defaults to `name`. Only override when the displayed name differs (e.g. plugin prefix stripping). */
202→ userFacingName?: () => string
203→}
204→
205→export type Command = CommandBase &
206→ (PromptCommand | LocalCommand | LocalJSXCommand)
207→
208→/** Resolves the user-visible name, falling back to `cmd.name` when not overridden. */
209→export function getCommandName(cmd: CommandBase): string {
210→ return cmd.userFacingName?.() ?? cmd.name
211→}
212→
213→/** Resolves whether the command is enabled, defaulting to true. */
214→export function isCommandEnabled(cmd: CommandBase): boolean {
215→ return cmd.isEnabled?.() ?? true
216→}
217→Tool Call: Read src\query.ts (100 - 199) Status: Completed
100→import { recordContentReplacement } from './utils/sessionStorage.js'
101→import { handleStopHooks } from './query/stopHooks.js'
102→import { buildQueryConfig } from './query/config.js'
103→import { productionDeps, type QueryDeps } from './query/deps.js'
104→import type { Terminal, Continue } from './query/transitions.js'
105→import { feature } from 'bun:bundle'
106→import {
107→ getCurrentTurnTokenBudget,
108→ getTurnOutputTokens,
109→ incrementBudgetContinuationCount,
110→} from './bootstrap/state.js'
111→import { createBudgetTracker, checkTokenBudget } from './query/tokenBudget.js'
112→import { count } from './utils/array.js'
113→
114→/* eslint-disable @typescript-eslint/no-require-imports */
115→const snipModule = feature('HISTORY_SNIP')
116→ ? (require('./services/compact/snipCompact.js') as typeof import('./services/compact/snipCompact.js'))
117→ : null
118→const taskSummaryModule = feature('BG_SESSIONS')
119→ ? (require('./utils/taskSummary.js') as typeof import('./utils/taskSummary.js'))
120→ : null
121→/* eslint-enable @typescript-eslint/no-require-imports */
122→
123→function* yieldMissingToolResultBlocks(
124→ assistantMessages: AssistantMessage[],
125→ errorMessage: string,
126→) {
127→ for (const assistantMessage of assistantMessages) {
128→ // Extract all tool use blocks from this assistant message
129→ const toolUseBlocks = assistantMessage.message.content.filter(
130→ content => content.type === 'tool_use',
131→ ) as ToolUseBlock[]
132→
133→ // Emit an interruption message for each tool use
134→ for (const toolUse of toolUseBlocks) {
135→ yield createUserMessage({
136→ content: [
137→ {
138→ type: 'tool_result',
139→ content: errorMessage,
140→ is_error: true,
141→ tool_use_id: toolUse.id,
142→ },
143→ ],
144→ toolUseResult: errorMessage,
145→ sourceToolAssistantUUID: assistantMessage.uuid,
146→ })
147→ }
148→ }
149→}
150→
151→/**
152→ * The rules of thinking are lengthy and fortuitous. They require plenty of thinking
153→ * of most long duration and deep meditation for a wizard to wrap one's noggin around.
154→ *
155→ * The rules follow:
156→ * 1. A message that contains a thinking or redacted_thinking block must be part of a query whose max_thinking_length > 0
157→ * 2. A thinking block may not be the last message in a block
158→ * 3. Thinking blocks must be preserved for the duration of an assistant trajectory (a single turn, or if that turn includes a tool_use block then also its subsequent tool_result and the following assistant message)
159→ *
160→ * Heed these rules well, young wizard. For they are the rules of thinking, and
161→ * the rules of thinking are the rules of the universe. If ye does not heed these
162→ * rules, ye will be punished with an entire day of debugging and hair pulling.
163→ */
164→const MAX_OUTPUT_TOKENS_RECOVERY_LIMIT = 3
165→
166→/**
167→ * Is this a max_output_tokens error message? If so, the streaming loop should
168→ * withhold it from SDK callers until we know whether the recovery loop can
169→ * continue. Yielding early leaks an intermediate error to SDK callers (e.g.
170→ * cowork/desktop) that terminate the session on any `error` field — the
171→ * recovery loop keeps running but nobody is listening.
172→ *
173→ * Mirrors reactiveCompact.isWithheldPromptTooLong.
174→ */
175→function isWithheldMaxOutputTokens(
176→ msg: Message | StreamEvent | undefined,
177→): msg is AssistantMessage {
178→ return msg?.type === 'assistant' && msg.apiError === 'max_output_tokens'
179→}
180→
181→export type QueryParams = {
182→ messages: Message[]
183→ systemPrompt: SystemPrompt
184→ userContext: { [k: string]: string }
185→ systemContext: { [k: string]: string }
186→ canUseTool: CanUseToolFn
187→ toolUseContext: ToolUseContext
188→ fallbackModel?: string
189→ querySource: QuerySource
190→ maxOutputTokensOverride?: number
191→ maxTurns?: number
192→ skipCacheWrite?: boolean
193→ // API task_budget (output_config.task_budget, beta task-budgets-2026-03-13).
194→ // Distinct from the tokenBudget +500k auto-continue feature. `total` is the
195→ // budget for the whole agentic turn; `remaining` is computed per iteration
196→ // from cumulative API usage. See configureTaskBudgetParams in claude.ts.
197→ taskBudget?: { total: number }
198→ deps?: QueryDeps
199→}Tool Call: Read src\types\permissions.ts Status: Completed
1→/**
2→ * Pure permission type definitions extracted to break import cycles.
3→ *
4→ * This file contains only type definitions and constants with no runtime dependencies.
5→ * Implementation files remain in src/utils/permissions/ but can now import from here
6→ * to avoid circular dependencies.
7→ */
8→
9→import { feature } from 'bun:bundle'
10→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
11→
12→// ============================================================================
13→// Permission Modes
14→// ============================================================================
15→
16→export const EXTERNAL_PERMISSION_MODES = [
17→ 'acceptEdits',
18→ 'bypassPermissions',
19→ 'default',
20→ 'dontAsk',
21→ 'plan',
22→] as const
23→
24→export type ExternalPermissionMode = (typeof EXTERNAL_PERMISSION_MODES)[number]
25→
26→// Exhaustive mode union for typechecking. The user-addressable runtime set
27→// is INTERNAL_PERMISSION_MODES below.
28→export type InternalPermissionMode = ExternalPermissionMode | 'auto' | 'bubble'
29→export type PermissionMode = InternalPermissionMode
30→
31→// Runtime validation set: modes that are user-addressable (settings.json
32→// defaultMode, --permission-mode CLI flag, conversation recovery).
33→export const INTERNAL_PERMISSION_MODES = [
34→ ...EXTERNAL_PERMISSION_MODES,
35→ ...(feature('TRANSCRIPT_CLASSIFIER') ? (['auto'] as const) : ([] as const)),
36→] as const satisfies readonly PermissionMode[]
37→
38→export const PERMISSION_MODES = INTERNAL_PERMISSION_MODES
39→
40→// ============================================================================
41→// Permission Behaviors
42→// ============================================================================
43→
44→export type PermissionBehavior = 'allow' | 'deny' | 'ask'
45→
46→// ============================================================================
47→// Permission Rules
48→// ============================================================================
49→
50→/**
51→ * Where a permission rule originated from.
52→ * Includes all SettingSource values plus additional rule-specific sources.
53→ */
54→export type PermissionRuleSource =
55→ | 'userSettings'
56→ | 'projectSettings'
57→ | 'localSettings'
58→ | 'flagSettings'
59→ | 'policySettings'
60→ | 'cliArg'
61→ | 'command'
62→ | 'session'
63→
64→/**
65→ * The value of a permission rule - specifies which tool and optional content
66→ */
67→export type PermissionRuleValue = {
68→ toolName: string
69→ ruleContent?: string
70→}
71→
72→/**
73→ * A permission rule with its source and behavior
74→ */
75→export type PermissionRule = {
76→ source: PermissionRuleSource
77→ ruleBehavior: PermissionBehavior
78→ ruleValue: PermissionRuleValue
79→}
80→
81→// ============================================================================
82→// Permission Updates
83→// ============================================================================
84→
85→/**
86→ * Where a permission update should be persisted
87→ */
88→export type PermissionUpdateDestination =
89→ | 'userSettings'
90→ | 'projectSettings'
91→ | 'localSettings'
92→ | 'session'
93→ | 'cliArg'
94→
95→/**
96→ * Update operations for permission configuration
97→ */
98→export type PermissionUpdate =
99→ | {
100→ type: 'addRules'
101→ destination: PermissionUpdateDestination
102→ rules: PermissionRuleValue[]
103→ behavior: PermissionBehavior
104→ }
105→ | {
106→ type: 'replaceRules'
107→ destination: PermissionUpdateDestination
108→ rules: PermissionRuleValue[]
109→ behavior: PermissionBehavior
110→ }
111→ | {
112→ type: 'removeRules'
113→ destination: PermissionUpdateDestination
114→ rules: PermissionRuleValue[]
115→ behavior: PermissionBehavior
116→ }
117→ | {
118→ type: 'setMode'
119→ destination: PermissionUpdateDestination
120→ mode: ExternalPermissionMode
121→ }
122→ | {
123→ type: 'addDirectories'
124→ destination: PermissionUpdateDestination
125→ directories: string[]
126→ }
127→ | {
128→ type: 'removeDirectories'
129→ destination: PermissionUpdateDestination
130→ directories: string[]
131→ }
132→
133→/**
134→ * Source of an additional working directory permission.
135→ * Note: This is currently the same as PermissionRuleSource but kept as a
136→ * separate type for semantic clarity and potential future divergence.
137→ */
138→export type WorkingDirectorySource = PermissionRuleSource
139→
140→/**
141→ * An additional directory included in permission scope
142→ */
143→export type AdditionalWorkingDirectory = {
144→ path: string
145→ source: WorkingDirectorySource
146→}
147→
148→// ============================================================================
149→// Permission Decisions & Results
150→// ============================================================================
151→
152→/**
153→ * Minimal command shape for permission metadata.
154→ * This is intentionally a subset of the full Command type to avoid import cycles.
155→ * Only includes properties needed by permission-related components.
156→ */
157→export type PermissionCommandMetadata = {
158→ name: string
159→ description?: string
160→ // Allow additional properties for forward compatibility
161→ [key: string]: unknown
162→}
163→
164→/**
165→ * Metadata attached to permission decisions
166→ */
167→export type PermissionMetadata =
168→ | { command: PermissionCommandMetadata }
169→ | undefined
170→
171→/**
172→ * Result when permission is granted
173→ */
174→export type PermissionAllowDecision<
175→ Input extends { [key: string]: unknown } = { [key: string]: unknown },
176→> = {
177→ behavior: 'allow'
178→ updatedInput?: Input
179→ userModified?: boolean
180→ decisionReason?: PermissionDecisionReason
181→ toolUseID?: string
182→ acceptFeedback?: string
183→ contentBlocks?: ContentBlockParam[]
184→}
185→
186→/**
187→ * Metadata for a pending classifier check that will run asynchronously.
188→ * Used to enable non-blocking allow classifier evaluation.
189→ */
190→export type PendingClassifierCheck = {
191→ command: string
192→ cwd: string
193→ descriptions: string[]
194→}
195→
196→/**
197→ * Result when user should be prompted
198→ */
199→export type PermissionAskDecision<
200→ Input extends { [key: string]: unknown } = { [key: string]: unknown },
201→> = {
202→ behavior: 'ask'
203→ message: string
204→ updatedInput?: Input
205→ decisionReason?: PermissionDecisionReason
206→ suggestions?: PermissionUpdate[]
207→ blockedPath?: string
208→ metadata?: PermissionMetadata
209→ /**
210→ * If true, this ask decision was triggered by a bashCommandIsSafe_DEPRECATED security check
211→ * for patterns that splitCommand_DEPRECATED could misparse (e.g. line continuations, shell-quote
212→ * transformations). Used by bashToolHasPermission to block early before splitCommand_DEPRECATED
213→ * transforms the command. Not set for simple newline compound commands.
214→ */
215→ isBashSecurityCheckForMisparsing?: boolean
216→ /**
217→ * If set, an allow classifier check should be run asynchronously.
218→ * The classifier may auto-approve the permission before the user responds.
219→ */
220→ pendingClassifierCheck?: PendingClassifierCheck
221→ /**
222→ * Optional content blocks (e.g., images) to include alongside the rejection
223→ * message in the tool result. Used when users paste images as feedback.
224→ */
225→ contentBlocks?: ContentBlockParam[]
226→}
227→
228→/**
229→ * Result when permission is denied
230→ */
231→export type PermissionDenyDecision = {
232→ behavior: 'deny'
233→ message: string
234→ decisionReason: PermissionDecisionReason
235→ toolUseID?: string
236→}
237→
238→/**
239→ * A permission decision - allow, ask, or deny
240→ */
241→export type PermissionDecision<
242→ Input extends { [key: string]: unknown } = { [key: string]: unknown },
243→> =
244→ | PermissionAllowDecision<Input>
245→ | PermissionAskDecision<Input>
246→ | PermissionDenyDecision
247→
248→/**
249→ * Permission result with additional passthrough option
250→ */
251→export type PermissionResult<
252→ Input extends { [key: string]: unknown } = { [key: string]: unknown },
253→> =
254→ | PermissionDecision<Input>
255→ | {
256→ behavior: 'passthrough'
257→ message: string
258→ decisionReason?: PermissionDecision<Input>['decisionReason']
259→ suggestions?: PermissionUpdate[]
260→ blockedPath?: string
261→ /**
262→ * If set, an allow classifier check should be run asynchronously.
263→ * The classifier may auto-approve the permission before the user responds.
264→ */
265→ pendingClassifierCheck?: PendingClassifierCheck
266→ }
267→
268→/**
269→ * Explanation of why a permission decision was made
270→ */
271→export type PermissionDecisionReason =
272→ | {
273→ type: 'rule'
274→ rule: PermissionRule
275→ }
276→ | {
277→ type: 'mode'
278→ mode: PermissionMode
279→ }
280→ | {
281→ type: 'subcommandResults'
282→ reasons: Map<string, PermissionResult>
283→ }
284→ | {
285→ type: 'permissionPromptTool'
286→ permissionPromptToolName: string
287→ toolResult: unknown
288→ }
289→ | {
290→ type: 'hook'
291→ hookName: string
292→ hookSource?: string
293→ reason?: string
294→ }
295→ | {
296→ type: 'asyncAgent'
297→ reason: string
298→ }
299→ | {
300→ type: 'sandboxOverride'
301→ reason: 'excludedCommand' | 'dangerouslyDisableSandbox'
302→ }
303→ | {
304→ type: 'classifier'
305→ classifier: string
306→ reason: string
307→ }
308→ | {
309→ type: 'workingDir'
310→ reason: string
311→ }
312→ | {
313→ type: 'safetyCheck'
314→ reason: string
315→ // When true, auto mode lets the classifier evaluate this instead of
316→ // forcing a prompt. True for sensitive-file paths (.claude/, .git/,
317→ // shell configs) — the classifier can see context and decide. False
318→ // for Windows path bypass attempts and cross-machine bridge messages.
319→ classifierApprovable: boolean
320→ }
321→ | {
322→ type: 'other'
323→ reason: string
324→ }
325→
326→// ============================================================================
327→// Bash Classifier Types
328→// ============================================================================
329→
330→export type ClassifierResult = {
331→ matches: boolean
332→ matchedDescription?: string
333→ confidence: 'high' | 'medium' | 'low'
334→ reason: string
335→}
336→
337→export type ClassifierBehavior = 'deny' | 'ask' | 'allow'
338→
339→export type ClassifierUsage = {
340→ inputTokens: number
341→ outputTokens: number
342→ cacheReadInputTokens: number
343→ cacheCreationInputTokens: number
344→}
345→
346→export type YoloClassifierResult = {
347→ thinking?: string
348→ shouldBlock: boolean
349→ reason: string
350→ unavailable?: boolean
351→ /**
352→ * API returned "prompt is too long" — the classifier transcript exceeded
353→ * the context window. Deterministic (same transcript → same error), so
354→ * callers should fall back to normal prompting rather than retry/fail-closed.
355→ */
356→ transcriptTooLong?: boolean
357→ /** The model used for this classifier call */
358→ model: string
359→ /** Token usage from the classifier API call (for overhead telemetry) */
360→ usage?: ClassifierUsage
361→ /** Duration of the classifier API call in ms */
362→ durationMs?: number
363→ /** Character lengths of the prompt components sent to the classifier */
364→ promptLengths?: {
365→ systemPrompt: number
366→ toolCalls: number
367→ userPrompts: number
368→ }
369→ /** Path where error prompts were dumped (only set when unavailable due to API error) */
370→ errorDumpPath?: string
371→ /** Which classifier stage produced the final decision (2-stage XML only) */
372→ stage?: 'fast' | 'thinking'
373→ /** Token usage from stage 1 (fast) when stage 2 was also run */
374→ stage1Usage?: ClassifierUsage
375→ /** Duration of stage 1 in ms when stage 2 was also run */
376→ stage1DurationMs?: number
377→ /**
378→ * API request_id (req_xxx) for stage 1. Enables joining to server-side
379→ * api_usage logs for cache-miss / routing attribution. Also used for the
380→ * legacy 1-stage (tool_use) classifier — the single request goes here.
381→ */
382→ stage1RequestId?: string
383→ /**
384→ * API message id (msg_xxx) for stage 1. Enables joining the
385→ * tengu_auto_mode_decision analytics event to the classifier's actual
386→ * prompt/completion in post-analysis.
387→ */
388→ stage1MsgId?: string
389→ /** Token usage from stage 2 (thinking) when stage 2 was run */
390→ stage2Usage?: ClassifierUsage
391→ /** Duration of stage 2 in ms when stage 2 was run */
392→ stage2DurationMs?: number
393→ /** API request_id for stage 2 (set whenever stage 2 ran) */
394→ stage2RequestId?: string
395→ /** API message id (msg_xxx) for stage 2 (set whenever stage 2 ran) */
396→ stage2MsgId?: string
397→}
398→
399→// ============================================================================
400→// Permission Explainer Types
401→// ============================================================================
402→
403→export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH'
404→
405→export type PermissionExplanation = {
406→ riskLevel: RiskLevel
407→ explanation: string
408→ reasoning: string
409→ risk: string
410→}
411→
412→// ============================================================================
413→// Tool Permission Context
414→// ============================================================================
415→
416→/**
417→ * Mapping of permission rules by their source
418→ */
419→export type ToolPermissionRulesBySource = {
420→ [T in PermissionRuleSource]?: string[]
421→}
422→
423→/**
424→ * Context needed for permission checking in tools
425→ * Note: Uses a simplified DeepImmutable approximation for this types-only file
426→ */
427→export type ToolPermissionContext = {
428→ readonly mode: PermissionMode
429→ readonly additionalWorkingDirectories: ReadonlyMap<
430→ string,
431→ AdditionalWorkingDirectory
432→ >
433→ readonly alwaysAllowRules: ToolPermissionRulesBySource
434→ readonly alwaysDenyRules: ToolPermissionRulesBySource
435→ readonly alwaysAskRules: ToolPermissionRulesBySource
436→ readonly isBypassPermissionsModeAvailable: boolean
437→ readonly strippedDangerousRules?: ToolPermissionRulesBySource
438→ readonly shouldAvoidPermissionPrompts?: boolean
439→ readonly awaitAutomatedChecksBeforeDialog?: boolean
440→ readonly prePlanMode?: PermissionMode
441→}
442→Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/entrypoints/* Status: Completed
src\entrypoints\agentSdkTypes.ts src\entrypoints\cli.tsx src\entrypoints\init.ts src\entrypoints\mcp.ts src\entrypoints\sandboxTypes.ts
Tool Call: Read src\QueryEngine.ts Status: Completed
1→import { feature } from 'bun:bundle'
2→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.mjs'
3→import { randomUUID } from 'crypto'
4→import last from 'lodash-es/last.js'
5→import {
6→ getSessionId,
7→ isSessionPersistenceDisabled,
8→} from 'src/bootstrap/state.js'
9→import type {
10→ PermissionMode,
11→ SDKCompactBoundaryMessage,
12→ SDKMessage,
13→ SDKPermissionDenial,
14→ SDKStatus,
15→ SDKUserMessageReplay,
16→} from 'src/entrypoints/agentSdkTypes.js'
17→import { accumulateUsage, updateUsage } from 'src/services/api/claude.js'
18→import type { NonNullableUsage } from 'src/services/api/logging.js'
19→import { EMPTY_USAGE } from 'src/services/api/logging.js'
20→import stripAnsi from 'strip-ansi'
21→import type { Command } from './commands.js'
22→import { getSlashCommandToolSkills } from './commands.js'
23→import {
24→ LOCAL_COMMAND_STDERR_TAG,
25→ LOCAL_COMMAND_STDOUT_TAG,
26→} from './constants/xml.js'
27→import {
28→ getModelUsage,
29→ getTotalAPIDuration,
30→ getTotalCost,
31→} from './cost-tracker.js'
32→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
33→import { loadMemoryPrompt } from './memdir/memdir.js'
34→import { hasAutoMemPathOverride } from './memdir/paths.js'
35→import { query } from './query.js'
36→import { categorizeRetryableAPIError } from './services/api/errors.js'
37→import type { MCPServerConnection } from './services/mcp/types.js'
38→import type { AppState } from './state/AppState.js'
39→import { type Tools, type ToolUseContext, toolMatchesName } from './Tool.js'
40→import type { AgentDefinition } from './tools/AgentTool/loadAgentsDir.js'
41→import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js'
42→import type { Message } from './types/message.js'
43→import type { OrphanedPermission } from './types/textInputTypes.js'
44→import { createAbortController } from './utils/abortController.js'
45→import type { AttributionState } from './utils/commitAttribution.js'
46→import { getGlobalConfig } from './utils/config.js'
47→import { getCwd } from './utils/cwd.js'
48→import { isBareMode, isEnvTruthy } from './utils/envUtils.js'
49→import { getFastModeState } from './utils/fastMode.js'
50→import {
51→ type FileHistoryState,
52→ fileHistoryEnabled,
53→ fileHistoryMakeSnapshot,
54→} from './utils/fileHistory.js'
55→import {
56→ cloneFileStateCache,
57→ type FileStateCache,
58→} from './utils/fileStateCache.js'
59→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
60→import { registerStructuredOutputEnforcement } from './utils/hooks/hookHelpers.js'
61→import { getInMemoryErrors } from './utils/log.js'
62→import { countToolCalls, SYNTHETIC_MESSAGES } from './utils/messages.js'
63→import {
64→ getMainLoopModel,
65→ parseUserSpecifiedModel,
66→} from './utils/model/model.js'
67→import { loadAllPluginsCacheOnly } from './utils/plugins/pluginLoader.js'
68→import {
69→ type ProcessUserInputContext,
70→ processUserInput,
71→} from './utils/processUserInput/processUserInput.js'
72→import { fetchSystemPromptParts } from './utils/queryContext.js'
73→import { setCwd } from './utils/Shell.js'
74→import {
75→ flushSessionStorage,
76→ recordTranscript,
77→} from './utils/sessionStorage.js'
78→import { asSystemPrompt } from './utils/systemPromptType.js'
79→import { resolveThemeSetting } from './utils/systemTheme.js'
80→import {
81→ shouldEnableThinkingByDefault,
82→ type ThinkingConfig,
83→} from './utils/thinking.js'
84→
85→// Lazy: MessageSelector.tsx pulls React/ink; only needed for message filtering at query time
86→/* eslint-disable @typescript-eslint/no-require-imports */
87→const messageSelector =
88→ (): typeof import('src/components/MessageSelector.js') =>
89→ require('src/components/MessageSelector.js')
90→
91→import {
92→ localCommandOutputToSDKAssistantMessage,
93→ toSDKCompactMetadata,
94→} from './utils/messages/mappers.js'
95→import {
96→ buildSystemInitMessage,
97→ sdkCompatToolName,
98→} from './utils/messages/systemInit.js'
99→import {
100→ getScratchpadDir,
101→ isScratchpadEnabled,
102→} from './utils/permissions/filesystem.js'
103→/* eslint-enable @typescript-eslint/no-require-imports */
104→import {
105→ handleOrphanedPermission,
106→ isResultSuccessful,
107→ normalizeMessage,
108→} from './utils/queryHelpers.js'
109→
110→// Dead code elimination: conditional import for coordinator mode
111→/* eslint-disable @typescript-eslint/no-require-imports */
112→const getCoordinatorUserContext: (
113→ mcpClients: ReadonlyArray<{ name: string }>,
114→ scratchpadDir?: string,
115→) => { [k: string]: string } = feature('COORDINATOR_MODE')
116→ ? require('./coordinator/coordinatorMode.js').getCoordinatorUserContext
117→ : () => ({})
118→/* eslint-enable @typescript-eslint/no-require-imports */
119→
120→// Dead code elimination: conditional import for snip compaction
121→/* eslint-disable @typescript-eslint/no-require-imports */
122→const snipModule = feature('HISTORY_SNIP')
123→ ? (require('./services/compact/snipCompact.js') as typeof import('./services/compact/snipCompact.js'))
124→ : null
125→const snipProjection = feature('HISTORY_SNIP')
126→ ? (require('./services/compact/snipProjection.js') as typeof import('./services/compact/snipProjection.js'))
127→ : null
128→/* eslint-enable @typescript-eslint/no-require-imports */
129→
130→export type QueryEngineConfig = {
131→ cwd: string
132→ tools: Tools
133→ commands: Command[]
134→ mcpClients: MCPServerConnection[]
135→ agents: AgentDefinition[]
136→ canUseTool: CanUseToolFn
137→ getAppState: () => AppState
138→ setAppState: (f: (prev: AppState) => AppState) => void
139→ initialMessages?: Message[]
140→ readFileCache: FileStateCache
141→ customSystemPrompt?: string
142→ appendSystemPrompt?: string
143→ userSpecifiedModel?: string
144→ fallbackModel?: string
145→ thinkingConfig?: ThinkingConfig
146→ maxTurns?: number
147→ maxBudgetUsd?: number
148→ taskBudget?: { total: number }
149→ jsonSchema?: Record<string, unknown>
150→ verbose?: boolean
151→ replayUserMessages?: boolean
152→ /** Handler for URL elicitations triggered by MCP tool -32042 errors. */
153→ handleElicitation?: ToolUseContext['handleElicitation']
154→ includePartialMessages?: boolean
155→ setSDKStatus?: (status: SDKStatus) => void
156→ abortController?: AbortController
157→ orphanedPermission?: OrphanedPermission
158→ /**
159→ * Snip-boundary handler: receives each yielded system message plus the
160→ * current mutableMessages store. Returns undefined if the message is not a
161→ * snip boundary; otherwise returns the replayed snip result. Injected by
162→ * ask() when HISTORY_SNIP is enabled so feature-gated strings stay inside
163→ * the gated module (keeps QueryEngine free of excluded strings and testable
164→ * despite feature() returning false under bun test). SDK-only: the REPL
165→ * keeps full history for UI scrollback and projects on demand via
166→ * projectSnippedView; QueryEngine truncates here to bound memory in long
167→ * headless sessions (no UI to preserve).
168→ */
169→ snipReplay?: (
170→ yieldedSystemMsg: Message,
171→ store: Message[],
172→ ) => { messages: Message[]; executed: boolean } | undefined
173→}
174→
175→/**
176→ * QueryEngine owns the query lifecycle and session state for a conversation.
177→ * It extracts the core logic from ask() into a standalone class that can be
178→ * used by both the headless/SDK path and (in a future phase) the REPL.
179→ *
180→ * One QueryEngine per conversation. Each submitMessage() call starts a new
181→ * turn within the same conversation. State (messages, file cache, usage, etc.)
182→ * persists across turns.
183→ */
184→export class QueryEngine {
185→ private config: QueryEngineConfig
186→ private mutableMessages: Message[]
187→ private abortController: AbortController
188→ private permissionDenials: SDKPermissionDenial[]
189→ private totalUsage: NonNullableUsage
190→ private hasHandledOrphanedPermission = false
191→ private readFileState: FileStateCache
192→ // Turn-scoped skill discovery tracking (feeds was_discovered on
193→ // tengu_skill_tool_invocation). Must persist across the two
194→ // processUserInputContext rebuilds inside submitMessage, but is cleared
195→ // at the start of each submitMessage to avoid unbounded growth across
196→ // many turns in SDK mode.
197→ private discoveredSkillNames = new Set<string>()
198→ private loadedNestedMemoryPaths = new Set<string>()
199→
200→ constructor(config: QueryEngineConfig) {
201→ this.config = config
202→ this.mutableMessages = config.initialMessages ?? []
203→ this.abortController = config.abortController ?? createAbortController()
204→ this.permissionDenials = []
205→ this.readFileState = config.readFileCache
206→ this.totalUsage = EMPTY_USAGE
207→ }
208→
209→ async *submitMessage(
210→ prompt: string | ContentBlockParam[],
211→ options?: { uuid?: string; isMeta?: boolean },
212→ ): AsyncGenerator<SDKMessage, void, unknown> {
213→ const {
214→ cwd,
215→ commands,
216→ tools,
217→ mcpClients,
218→ verbose = false,
219→ thinkingConfig,
220→ maxTurns,
221→ maxBudgetUsd,
222→ taskBudget,
223→ canUseTool,
224→ customSystemPrompt,
225→ appendSystemPrompt,
226→ userSpecifiedModel,
227→ fallbackModel,
228→ jsonSchema,
229→ getAppState,
230→ setAppState,
231→ replayUserMessages = false,
232→ includePartialMessages = false,
233→ agents = [],
234→ setSDKStatus,
235→ orphanedPermission,
236→ } = this.config
237→
238→ this.discoveredSkillNames.clear()
239→ setCwd(cwd)
240→ const persistSession = !isSessionPersistenceDisabled()
241→ const startTime = Date.now()
242→
243→ // Wrap canUseTool to track permission denials
244→ const wrappedCanUseTool: CanUseToolFn = async (
245→ tool,
246→ input,
247→ toolUseContext,
248→ assistantMessage,
249→ toolUseID,
250→ forceDecision,
251→ ) => {
252→ const result = await canUseTool(
253→ tool,
254→ input,
255→ toolUseContext,
256→ assistantMessage,
257→ toolUseID,
258→ forceDecision,
259→ )
260→
261→ // Track denials for SDK reporting
262→ if (result.behavior !== 'allow') {
263→ this.permissionDenials.push({
264→ tool_name: sdkCompatToolName(tool.name),
265→ tool_use_id: toolUseID,
266→ tool_input: input,
267→ })
268→ }
269→
270→ return result
271→ }
272→
273→ const initialAppState = getAppState()
274→ const initialMainLoopModel = userSpecifiedModel
275→ ? parseUserSpecifiedModel(userSpecifiedModel)
276→ : getMainLoopModel()
277→
278→ const initialThinkingConfig: ThinkingConfig = thinkingConfig
279→ ? thinkingConfig
280→ : shouldEnableThinkingByDefault() !== false
281→ ? { type: 'adaptive' }
282→ : { type: 'disabled' }
283→
284→ headlessProfilerCheckpoint('before_getSystemPrompt')
285→ // Narrow once so TS tracks the type through the conditionals below.
286→ const customPrompt =
287→ typeof customSystemPrompt === 'string' ? customSystemPrompt : undefined
288→ const {
289→ defaultSystemPrompt,
290→ userContext: baseUserContext,
291→ systemContext,
292→ } = await fetchSystemPromptParts({
293→ tools,
294→ mainLoopModel: initialMainLoopModel,
295→ additionalWorkingDirectories: Array.from(
296→ initialAppState.toolPermissionContext.additionalWorkingDirectories.keys(),
297→ ),
298→ mcpClients,
299→ customSystemPrompt: customPrompt,
300→ })
301→ headlessProfilerCheckpoint('after_getSystemPrompt')
302→ const userContext = {
303→ ...baseUserContext,
304→ ...getCoordinatorUserContext(
305→ mcpClients,
306→ isScratchpadEnabled() ? getScratchpadDir() : undefined,
307→ ),
308→ }
309→
310→ // When an SDK caller provides a custom system prompt AND has set
311→ // CLAUDE_COWORK_MEMORY_PATH_OVERRIDE, inject the memory-mechanics prompt.
312→ // The env var is an explicit opt-in signal — the caller has wired up
313→ // a memory directory and needs Claude to know how to use it (which
314→ // Write/Edit tools to call, MEMORY.md filename, loading semantics).
315→ // The caller can layer their own policy text via appendSystemPrompt.
316→ const memoryMechanicsPrompt =
317→ customPrompt !== undefined && hasAutoMemPathOverride()
318→ ? await loadMemoryPrompt()
319→ : null
320→
321→ const systemPrompt = asSystemPrompt([
322→ ...(customPrompt !== undefined ? [customPrompt] : defaultSystemPrompt),
323→ ...(memoryMechanicsPrompt ? [memoryMechanicsPrompt] : []),
324→ ...(appendSystemPrompt ? [appendSystemPrompt] : []),
325→ ])
326→
327→ // Register function hook for structured output enforcement
328→ const hasStructuredOutputTool = tools.some(t =>
329→ toolMatchesName(t, SYNTHETIC_OUTPUT_TOOL_NAME),
330→ )
331→ if (jsonSchema && hasStructuredOutputTool) {
332→ registerStructuredOutputEnforcement(setAppState, getSessionId())
333→ }
334→
335→ let processUserInputContext: ProcessUserInputContext = {
336→ messages: this.mutableMessages,
337→ // Slash commands that mutate the message array (e.g. /force-snip)
338→ // call setMessages(fn). In interactive mode this writes back to
339→ // AppState; in print mode we write back to mutableMessages so the
340→ // rest of the query loop (push at :389, snapshot at :392) sees
341→ // the result. The second processUserInputContext below (after
342→ // slash-command processing) keeps the no-op — nothing else calls
343→ // setMessages past that point.
344→ setMessages: fn => {
345→ this.mutableMessages = fn(this.mutableMessages)
346→ },
347→ onChangeAPIKey: () => {},
348→ handleElicitation: this.config.handleElicitation,
349→ options: {
350→ commands,
351→ debug: false, // we use stdout, so don't want to clobber it
352→ tools,
353→ verbose,
354→ mainLoopModel: initialMainLoopModel,
355→ thinkingConfig: initialThinkingConfig,
356→ mcpClients,
357→ mcpResources: {},
358→ ideInstallationStatus: null,
359→ isNonInteractiveSession: true,
360→ customSystemPrompt,
361→ appendSystemPrompt,
362→ agentDefinitions: { activeAgents: agents, allAgents: [] },
363→ theme: resolveThemeSetting(getGlobalConfig().theme),
364→ maxBudgetUsd,
365→ },
366→ getAppState,
367→ setAppState,
368→ abortController: this.abortController,
369→ readFileState: this.readFileState,
370→ nestedMemoryAttachmentTriggers: new Set<string>(),
371→ loadedNestedMemoryPaths: this.loadedNestedMemoryPaths,
372→ dynamicSkillDirTriggers: new Set<string>(),
373→ discoveredSkillNames: this.discoveredSkillNames,
374→ setInProgressToolUseIDs: () => {},
375→ setResponseLength: () => {},
376→ updateFileHistoryState: (
377→ updater: (prev: FileHistoryState) => FileHistoryState,
378→ ) => {
379→ setAppState(prev => {
380→ const updated = updater(prev.fileHistory)
381→ if (updated === prev.fileHistory) return prev
382→ return { ...prev, fileHistory: updated }
383→ })
384→ },
385→ updateAttributionState: (
386→ updater: (prev: AttributionState) => AttributionState,
387→ ) => {
388→ setAppState(prev => {
389→ const updated = updater(prev.attribution)
390→ if (updated === prev.attribution) return prev
391→ return { ...prev, attribution: updated }
392→ })
393→ },
394→ setSDKStatus,
395→ }
396→
397→ // Handle orphaned permission (only once per engine lifetime)
398→ if (orphanedPermission && !this.hasHandledOrphanedPermission) {
399→ this.hasHandledOrphanedPermission = true
400→ for await (const message of handleOrphanedPermission(
401→ orphanedPermission,
402→ tools,
403→ this.mutableMessages,
404→ processUserInputContext,
405→ )) {
406→ yield message
407→ }
408→ }
409→
410→ const {
411→ messages: messagesFromUserInput,
412→ shouldQuery,
413→ allowedTools,
414→ model: modelFromUserInput,
415→ resultText,
416→ } = await processUserInput({
417→ input: prompt,
418→ mode: 'prompt',
419→ setToolJSX: () => {},
420→ context: {
421→ ...processUserInputContext,
422→ messages: this.mutableMessages,
423→ },
424→ messages: this.mutableMessages,
425→ uuid: options?.uuid,
426→ isMeta: options?.isMeta,
427→ querySource: 'sdk',
428→ })
429→
430→ // Push new messages, including user input and any attachments
431→ this.mutableMessages.push(...messagesFromUserInput)
432→
433→ // Update params to reflect updates from processing /slash commands
434→ const messages = [...this.mutableMessages]
435→
436→ // Persist the user's message(s) to transcript BEFORE entering the query
437→ // loop. The for-await below only calls recordTranscript when ask() yields
438→ // an assistant/user/compact_boundary message — which doesn't happen until
439→ // the API responds. If the process is killed before that (e.g. user clicks
440→ // Stop in cowork seconds after send), the transcript is left with only
441→ // queue-operation entries; getLastSessionLog filters those out, returns
442→ // null, and --resume fails with "No conversation found". Writing now makes
443→ // the transcript resumable from the point the user message was accepted,
444→ // even if no API response ever arrives.
445→ //
446→ // --bare / SIMPLE: fire-and-forget. Scripted calls don't --resume after
447→ // kill-mid-request. The await is ~4ms on SSD, ~30ms under disk contention
448→ // — the single largest controllable critical-path cost after module eval.
449→ // Transcript is still written (for post-hoc debugging); just not blocking.
450→ if (persistSession && messagesFromUserInput.length > 0) {
451→ const transcriptPromise = recordTranscript(messages)
452→ if (isBareMode()) {
453→ void transcriptPromise
454→ } else {
455→ await transcriptPromise
456→ if (
457→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
458→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
459→ ) {
460→ await flushSessionStorage()
461→ }
462→ }
463→ }
464→
465→ // Filter messages that should be acknowledged after transcript
466→ const replayableMessages = messagesFromUserInput.filter(
467→ msg =>
468→ (msg.type === 'user' &&
469→ !msg.isMeta && // Skip synthetic caveat messages
470→ !msg.toolUseResult && // Skip tool results (they'll be acked from query)
471→ messageSelector().selectableUserMessagesFilter(msg)) || // Skip non-user-authored messages (task notifications, etc.)
472→ (msg.type === 'system' && msg.subtype === 'compact_boundary'), // Always ack compact boundaries
473→ )
474→ const messagesToAck = replayUserMessages ? replayableMessages : []
475→
476→ // Update the ToolPermissionContext based on user input processing (as necessary)
477→ setAppState(prev => ({
478→ ...prev,
479→ toolPermissionContext: {
480→ ...prev.toolPermissionContext,
481→ alwaysAllowRules: {
482→ ...prev.toolPermissionContext.alwaysAllowRules,
483→ command: allowedTools,
484→ },
485→ },
486→ }))
487→
488→ const mainLoopModel = modelFromUserInput ?? initialMainLoopModel
489→
490→ // Recreate after processing the prompt to pick up updated messages and
491→ // model (from slash commands).
492→ processUserInputContext = {
493→ messages,
494→ setMessages: () => {},
495→ onChangeAPIKey: () => {},
496→ handleElicitation: this.config.handleElicitation,
497→ options: {
498→ commands,
499→ debug: false,
500→ tools,
501→ verbose,
502→ mainLoopModel,
503→ thinkingConfig: initialThinkingConfig,
504→ mcpClients,
505→ mcpResources: {},
506→ ideInstallationStatus: null,
507→ isNonInteractiveSession: true,
508→ customSystemPrompt,
509→ appendSystemPrompt,
510→ theme: resolveThemeSetting(getGlobalConfig().theme),
511→ agentDefinitions: { activeAgents: agents, allAgents: [] },
512→ maxBudgetUsd,
513→ },
514→ getAppState,
515→ setAppState,
516→ abortController: this.abortController,
517→ readFileState: this.readFileState,
518→ nestedMemoryAttachmentTriggers: new Set<string>(),
519→ loadedNestedMemoryPaths: this.loadedNestedMemoryPaths,
520→ dynamicSkillDirTriggers: new Set<string>(),
521→ discoveredSkillNames: this.discoveredSkillNames,
522→ setInProgressToolUseIDs: () => {},
523→ setResponseLength: () => {},
524→ updateFileHistoryState: processUserInputContext.updateFileHistoryState,
525→ updateAttributionState: processUserInputContext.updateAttributionState,
526→ setSDKStatus,
527→ }
528→
529→ headlessProfilerCheckpoint('before_skills_plugins')
530→ // Cache-only: headless/SDK/CCR startup must not block on network for
531→ // ref-tracked plugins. CCR populates the cache via CLAUDE_CODE_SYNC_PLUGIN_INSTALL
532→ // (headlessPluginInstall) or CLAUDE_CODE_PLUGIN_SEED_DIR before this runs;
533→ // SDK callers that need fresh source can call /reload-plugins.
534→ const [skills, { enabled: enabledPlugins }] = await Promise.all([
535→ getSlashCommandToolSkills(getCwd()),
536→ loadAllPluginsCacheOnly(),
537→ ])
538→ headlessProfilerCheckpoint('after_skills_plugins')
539→
540→ yield buildSystemInitMessage({
541→ tools,
542→ mcpClients,
543→ model: mainLoopModel,
544→ permissionMode: initialAppState.toolPermissionContext
545→ .mode as PermissionMode, // TODO: avoid the cast
546→ commands,
547→ agents,
548→ skills,
549→ plugins: enabledPlugins,
550→ fastMode: initialAppState.fastMode,
551→ })
552→
553→ // Record when system message is yielded for headless latency tracking
554→ headlessProfilerCheckpoint('system_message_yielded')
555→
556→ if (!shouldQuery) {
557→ // Return the results of local slash commands.
558→ // Use messagesFromUserInput (not replayableMessages) for command output
559→ // because selectableUserMessagesFilter excludes local-command-stdout tags.
560→ for (const msg of messagesFromUserInput) {
561→ if (
562→ msg.type === 'user' &&
563→ typeof msg.message.content === 'string' &&
564→ (msg.message.content.includes(`<${LOCAL_COMMAND_STDOUT_TAG}>`) ||
565→ msg.message.content.includes(`<${LOCAL_COMMAND_STDERR_TAG}>`) ||
566→ msg.isCompactSummary)
567→ ) {
568→ yield {
569→ type: 'user',
570→ message: {
571→ ...msg.message,
572→ content: stripAnsi(msg.message.content),
573→ },
574→ session_id: getSessionId(),
575→ parent_tool_use_id: null,
576→ uuid: msg.uuid,
577→ timestamp: msg.timestamp,
578→ isReplay: !msg.isCompactSummary,
579→ isSynthetic: msg.isMeta || msg.isVisibleInTranscriptOnly,
580→ } as SDKUserMessageReplay
581→ }
582→
583→ // Local command output — yield as a synthetic assistant message so
584→ // RC renders it as assistant-style text rather than a user bubble.
585→ // Emitted as assistant (not the dedicated SDKLocalCommandOutputMessage
586→ // system subtype) so mobile clients + session-ingress can parse it.
587→ if (
588→ msg.type === 'system' &&
589→ msg.subtype === 'local_command' &&
590→ typeof msg.content === 'string' &&
591→ (msg.content.includes(`<${LOCAL_COMMAND_STDOUT_TAG}>`) ||
592→ msg.content.includes(`<${LOCAL_COMMAND_STDERR_TAG}>`))
593→ ) {
594→ yield localCommandOutputToSDKAssistantMessage(msg.content, msg.uuid)
595→ }
596→
597→ if (msg.type === 'system' && msg.subtype === 'compact_boundary') {
598→ yield {
599→ type: 'system',
600→ subtype: 'compact_boundary' as const,
601→ session_id: getSessionId(),
602→ uuid: msg.uuid,
603→ compact_metadata: toSDKCompactMetadata(msg.compactMetadata),
604→ } as SDKCompactBoundaryMessage
605→ }
606→ }
607→
608→ if (persistSession) {
609→ await recordTranscript(messages)
610→ if (
611→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
612→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
613→ ) {
614→ await flushSessionStorage()
615→ }
616→ }
617→
618→ yield {
619→ type: 'result',
620→ subtype: 'success',
621→ is_error: false,
622→ duration_ms: Date.now() - startTime,
623→ duration_api_ms: getTotalAPIDuration(),
624→ num_turns: messages.length - 1,
625→ result: resultText ?? '',
626→ stop_reason: null,
627→ session_id: getSessionId(),
628→ total_cost_usd: getTotalCost(),
629→ usage: this.totalUsage,
630→ modelUsage: getModelUsage(),
631→ permission_denials: this.permissionDenials,
632→ fast_mode_state: getFastModeState(
633→ mainLoopModel,
634→ initialAppState.fastMode,
635→ ),
636→ uuid: randomUUID(),
637→ }
638→ return
639→ }
640→
641→ if (fileHistoryEnabled() && persistSession) {
642→ messagesFromUserInput
643→ .filter(messageSelector().selectableUserMessagesFilter)
644→ .forEach(message => {
645→ void fileHistoryMakeSnapshot(
646→ (updater: (prev: FileHistoryState) => FileHistoryState) => {
647→ setAppState(prev => ({
648→ ...prev,
649→ fileHistory: updater(prev.fileHistory),
650→ }))
651→ },
652→ message.uuid,
653→ )
654→ })
655→ }
656→
657→ // Track current message usage (reset on each message_start)
658→ let currentMessageUsage: NonNullableUsage = EMPTY_USAGE
659→ let turnCount = 1
660→ let hasAcknowledgedInitialMessages = false
661→ // Track structured output from StructuredOutput tool calls
662→ let structuredOutputFromTool: unknown
663→ // Track the last stop_reason from assistant messages
664→ let lastStopReason: string | null = null
665→ // Reference-based watermark so error_during_execution's errors[] is
666→ // turn-scoped. A length-based index breaks when the 100-entry ring buffer
667→ // shift()s during the turn — the index slides. If this entry is rotated
668→ // out, lastIndexOf returns -1 and we include everything (safe fallback).
669→ const errorLogWatermark = getInMemoryErrors().at(-1)
670→ // Snapshot count before this query for delta-based retry limiting
671→ const initialStructuredOutputCalls = jsonSchema
672→ ? countToolCalls(this.mutableMessages, SYNTHETIC_OUTPUT_TOOL_NAME)
673→ : 0
674→
675→ for await (const message of query({
676→ messages,
677→ systemPrompt,
678→ userContext,
679→ systemContext,
680→ canUseTool: wrappedCanUseTool,
681→ toolUseContext: processUserInputContext,
682→ fallbackModel,
683→ querySource: 'sdk',
684→ maxTurns,
685→ taskBudget,
686→ })) {
687→ // Record assistant, user, and compact boundary messages
688→ if (
689→ message.type === 'assistant' ||
690→ message.type === 'user' ||
691→ (message.type === 'system' && message.subtype === 'compact_boundary')
692→ ) {
693→ // Before writing a compact boundary, flush any in-memory-only
694→ // messages up through the preservedSegment tail. Attachments and
695→ // progress are now recorded inline (their switch cases below), but
696→ // this flush still matters for the preservedSegment tail walk.
697→ // If the SDK subprocess restarts before then (claude-desktop kills
698→ // between turns), tailUuid points to a never-written message →
699→ // applyPreservedSegmentRelinks fails its tail→head walk → returns
700→ // without pruning → resume loads full pre-compact history.
701→ if (
702→ persistSession &&
703→ message.type === 'system' &&
704→ message.subtype === 'compact_boundary'
705→ ) {
706→ const tailUuid = message.compactMetadata?.preservedSegment?.tailUuid
707→ if (tailUuid) {
708→ const tailIdx = this.mutableMessages.findLastIndex(
709→ m => m.uuid === tailUuid,
710→ )
711→ if (tailIdx !== -1) {
712→ await recordTranscript(this.mutableMessages.slice(0, tailIdx + 1))
713→ }
714→ }
715→ }
716→ messages.push(message)
717→ if (persistSession) {
718→ // Fire-and-forget for assistant messages. claude.ts yields one
719→ // assistant message per content block, then mutates the last
720→ // one's message.usage/stop_reason on message_delta — relying on
721→ // the write queue's 100ms lazy jsonStringify. Awaiting here
722→ // blocks ask()'s generator, so message_delta can't run until
723→ // every block is consumed; the drain timer (started at block 1)
724→ // elapses first. Interactive CC doesn't hit this because
725→ // useLogMessages.ts fire-and-forgets. enqueueWrite is
726→ // order-preserving so fire-and-forget here is safe.
727→ if (message.type === 'assistant') {
728→ void recordTranscript(messages)
729→ } else {
730→ await recordTranscript(messages)
731→ }
732→ }
733→
734→ // Acknowledge initial user messages after first transcript recording
735→ if (!hasAcknowledgedInitialMessages && messagesToAck.length > 0) {
736→ hasAcknowledgedInitialMessages = true
737→ for (const msgToAck of messagesToAck) {
738→ if (msgToAck.type === 'user') {
739→ yield {
740→ type: 'user',
741→ message: msgToAck.message,
742→ session_id: getSessionId(),
743→ parent_tool_use_id: null,
744→ uuid: msgToAck.uuid,
745→ timestamp: msgToAck.timestamp,
746→ isReplay: true,
747→ } as SDKUserMessageReplay
748→ }
749→ }
750→ }
751→ }
752→
753→ if (message.type === 'user') {
754→ turnCount++
755→ }
756→
757→ switch (message.type) {
758→ case 'tombstone':
759→ // Tombstone messages are control signals for removing messages, skip them
760→ break
761→ case 'assistant':
762→ // Capture stop_reason if already set (synthetic messages). For
763→ // streamed responses, this is null at content_block_stop time;
764→ // the real value arrives via message_delta (handled below).
765→ if (message.message.stop_reason != null) {
766→ lastStopReason = message.message.stop_reason
767→ }
768→ this.mutableMessages.push(message)
769→ yield* normalizeMessage(message)
770→ break
771→ case 'progress':
772→ this.mutableMessages.push(message)
773→ // Record inline so the dedup loop in the next ask() call sees it
774→ // as already-recorded. Without this, deferred progress interleaves
775→ // with already-recorded tool_results in mutableMessages, and the
776→ // dedup walk freezes startingParentUuid at the wrong message —
777→ // forking the chain and orphaning the conversation on resume.
778→ if (persistSession) {
779→ messages.push(message)
780→ void recordTranscript(messages)
781→ }
782→ yield* normalizeMessage(message)
783→ break
784→ case 'user':
785→ this.mutableMessages.push(message)
786→ yield* normalizeMessage(message)
787→ break
788→ case 'stream_event':
789→ if (message.event.type === 'message_start') {
790→ // Reset current message usage for new message
791→ currentMessageUsage = EMPTY_USAGE
792→ currentMessageUsage = updateUsage(
793→ currentMessageUsage,
794→ message.event.message.usage,
795→ )
796→ }
797→ if (message.event.type === 'message_delta') {
798→ currentMessageUsage = updateUsage(
799→ currentMessageUsage,
800→ message.event.usage,
801→ )
802→ // Capture stop_reason from message_delta. The assistant message
803→ // is yielded at content_block_stop with stop_reason=null; the
804→ // real value only arrives here (see claude.ts message_delta
805→ // handler). Without this, result.stop_reason is always null.
806→ if (message.event.delta.stop_reason != null) {
807→ lastStopReason = message.event.delta.stop_reason
808→ }
809→ }
810→ if (message.event.type === 'message_stop') {
811→ // Accumulate current message usage into total
812→ this.totalUsage = accumulateUsage(
813→ this.totalUsage,
814→ currentMessageUsage,
815→ )
816→ }
817→
818→ if (includePartialMessages) {
819→ yield {
820→ type: 'stream_event' as const,
821→ event: message.event,
822→ session_id: getSessionId(),
823→ parent_tool_use_id: null,
824→ uuid: randomUUID(),
825→ }
826→ }
827→
828→ break
829→ case 'attachment':
830→ this.mutableMessages.push(message)
831→ // Record inline (same reason as progress above).
832→ if (persistSession) {
833→ messages.push(message)
834→ void recordTranscript(messages)
835→ }
836→
837→ // Extract structured output from StructuredOutput tool calls
838→ if (message.attachment.type === 'structured_output') {
839→ structuredOutputFromTool = message.attachment.data
840→ }
841→ // Handle max turns reached signal from query.ts
842→ else if (message.attachment.type === 'max_turns_reached') {
843→ if (persistSession) {
844→ if (
845→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
846→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
847→ ) {
848→ await flushSessionStorage()
849→ }
850→ }
851→ yield {
852→ type: 'result',
853→ subtype: 'error_max_turns',
854→ duration_ms: Date.now() - startTime,
855→ duration_api_ms: getTotalAPIDuration(),
856→ is_error: true,
857→ num_turns: message.attachment.turnCount,
858→ stop_reason: lastStopReason,
859→ session_id: getSessionId(),
860→ total_cost_usd: getTotalCost(),
861→ usage: this.totalUsage,
862→ modelUsage: getModelUsage(),
863→ permission_denials: this.permissionDenials,
864→ fast_mode_state: getFastModeState(
865→ mainLoopModel,
866→ initialAppState.fastMode,
867→ ),
868→ uuid: randomUUID(),
869→ errors: [
870→ `Reached maximum number of turns (${message.attachment.maxTurns})`,
871→ ],
872→ }
873→ return
874→ }
875→ // Yield queued_command attachments as SDK user message replays
876→ else if (
877→ replayUserMessages &&
878→ message.attachment.type === 'queued_command'
879→ ) {
880→ yield {
881→ type: 'user',
882→ message: {
883→ role: 'user' as const,
884→ content: message.attachment.prompt,
885→ },
886→ session_id: getSessionId(),
887→ parent_tool_use_id: null,
888→ uuid: message.attachment.source_uuid || message.uuid,
889→ timestamp: message.timestamp,
890→ isReplay: true,
891→ } as SDKUserMessageReplay
892→ }
893→ break
894→ case 'stream_request_start':
895→ // Don't yield stream request start messages
896→ break
897→ case 'system': {
898→ // Snip boundary: replay on our store to remove zombie messages and
899→ // stale markers. The yielded boundary is a signal, not data to push —
900→ // the replay produces its own equivalent boundary. Without this,
901→ // markers persist and re-trigger on every turn, and mutableMessages
902→ // never shrinks (memory leak in long SDK sessions). The subtype
903→ // check lives inside the injected callback so feature-gated strings
904→ // stay out of this file (excluded-strings check).
905→ const snipResult = this.config.snipReplay?.(
906→ message,
907→ this.mutableMessages,
908→ )
909→ if (snipResult !== undefined) {
910→ if (snipResult.executed) {
911→ this.mutableMessages.length = 0
912→ this.mutableMessages.push(...snipResult.messages)
913→ }
914→ break
915→ }
916→ this.mutableMessages.push(message)
917→ // Yield compact boundary messages to SDK
918→ if (
919→ message.subtype === 'compact_boundary' &&
920→ message.compactMetadata
921→ ) {
922→ // Release pre-compaction messages for GC. The boundary was just
923→ // pushed so it's the last element. query.ts already uses
924→ // getMessagesAfterCompactBoundary() internally, so only
925→ // post-boundary messages are needed going forward.
926→ const mutableBoundaryIdx = this.mutableMessages.length - 1
927→ if (mutableBoundaryIdx > 0) {
928→ this.mutableMessages.splice(0, mutableBoundaryIdx)
929→ }
930→ const localBoundaryIdx = messages.length - 1
931→ if (localBoundaryIdx > 0) {
932→ messages.splice(0, localBoundaryIdx)
933→ }
934→
935→ yield {
936→ type: 'system',
937→ subtype: 'compact_boundary' as const,
938→ session_id: getSessionId(),
939→ uuid: message.uuid,
940→ compact_metadata: toSDKCompactMetadata(message.compactMetadata),
941→ }
942→ }
943→ if (message.subtype === 'api_error') {
944→ yield {
945→ type: 'system',
946→ subtype: 'api_retry' as const,
947→ attempt: message.retryAttempt,
948→ max_retries: message.maxRetries,
949→ retry_delay_ms: message.retryInMs,
950→ error_status: message.error.status ?? null,
951→ error: categorizeRetryableAPIError(message.error),
952→ session_id: getSessionId(),
953→ uuid: message.uuid,
954→ }
955→ }
956→ // Don't yield other system messages in headless mode
957→ break
958→ }
959→ case 'tool_use_summary':
960→ // Yield tool use summary messages to SDK
961→ yield {
962→ type: 'tool_use_summary' as const,
963→ summary: message.summary,
964→ preceding_tool_use_ids: message.precedingToolUseIds,
965→ session_id: getSessionId(),
966→ uuid: message.uuid,
967→ }
968→ break
969→ }
970→
971→ // Check if USD budget has been exceeded
972→ if (maxBudgetUsd !== undefined && getTotalCost() >= maxBudgetUsd) {
973→ if (persistSession) {
974→ if (
975→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
976→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
977→ ) {
978→ await flushSessionStorage()
979→ }
980→ }
981→ yield {
982→ type: 'result',
983→ subtype: 'error_max_budget_usd',
984→ duration_ms: Date.now() - startTime,
985→ duration_api_ms: getTotalAPIDuration(),
986→ is_error: true,
987→ num_turns: turnCount,
988→ stop_reason: lastStopReason,
989→ session_id: getSessionId(),
990→ total_cost_usd: getTotalCost(),
991→ usage: this.totalUsage,
992→ modelUsage: getModelUsage(),
993→ permission_denials: this.permissionDenials,
994→ fast_mode_state: getFastModeState(
995→ mainLoopModel,
996→ initialAppState.fastMode,
997→ ),
998→ uuid: randomUUID(),
999→ errors: [`Reached maximum budget ($${maxBudgetUsd})`],
1000→ }
1001→ return
1002→ }
1003→
1004→ // Check if structured output retry limit exceeded (only on user messages)
1005→ if (message.type === 'user' && jsonSchema) {
1006→ const currentCalls = countToolCalls(
1007→ this.mutableMessages,
1008→ SYNTHETIC_OUTPUT_TOOL_NAME,
1009→ )
1010→ const callsThisQuery = currentCalls - initialStructuredOutputCalls
1011→ const maxRetries = parseInt(
1012→ process.env.MAX_STRUCTURED_OUTPUT_RETRIES || '5',
1013→ 10,
1014→ )
1015→ if (callsThisQuery >= maxRetries) {
1016→ if (persistSession) {
1017→ if (
1018→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
1019→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
1020→ ) {
1021→ await flushSessionStorage()
1022→ }
1023→ }
1024→ yield {
1025→ type: 'result',
1026→ subtype: 'error_max_structured_output_retries',
1027→ duration_ms: Date.now() - startTime,
1028→ duration_api_ms: getTotalAPIDuration(),
1029→ is_error: true,
1030→ num_turns: turnCount,
1031→ stop_reason: lastStopReason,
1032→ session_id: getSessionId(),
1033→ total_cost_usd: getTotalCost(),
1034→ usage: this.totalUsage,
1035→ modelUsage: getModelUsage(),
1036→ permission_denials: this.permissionDenials,
1037→ fast_mode_state: getFastModeState(
1038→ mainLoopModel,
1039→ initialAppState.fastMode,
1040→ ),
1041→ uuid: randomUUID(),
1042→ errors: [
1043→ `Failed to provide valid structured output after ${maxRetries} attempts`,
1044→ ],
1045→ }
1046→ return
1047→ }
1048→ }
1049→ }
1050→
1051→ // Stop hooks yield progress/attachment messages AFTER the assistant
1052→ // response (via yield* handleStopHooks in query.ts). Since #23537 pushes
1053→ // those to `messages` inline, last(messages) can be a progress/attachment
1054→ // instead of the assistant — which makes textResult extraction below
1055→ // return '' and -p mode emit a blank line. Allowlist to assistant|user:
1056→ // isResultSuccessful handles both (user with all tool_result blocks is a
1057→ // valid successful terminal state).
1058→ const result = messages.findLast(
1059→ m => m.type === 'assistant' || m.type === 'user',
1060→ )
1061→ // Capture for the error_during_execution diagnostic — isResultSuccessful
1062→ // is a type predicate (message is Message), so inside the false branch
1063→ // `result` narrows to never and these accesses don't typecheck.
1064→ const edeResultType = result?.type ?? 'undefined'
1065→ const edeLastContentType =
1066→ result?.type === 'assistant'
1067→ ? (last(result.message.content)?.type ?? 'none')
1068→ : 'n/a'
1069→
1070→ // Flush buffered transcript writes before yielding result.
1071→ // The desktop app kills the CLI process immediately after receiving the
1072→ // result message, so any unflushed writes would be lost.
1073→ if (persistSession) {
1074→ if (
1075→ isEnvTruthy(process.env.CLAUDE_CODE_EAGER_FLUSH) ||
1076→ isEnvTruthy(process.env.CLAUDE_CODE_IS_COWORK)
1077→ ) {
1078→ await flushSessionStorage()
1079→ }
1080→ }
1081→
1082→ if (!isResultSuccessful(result, lastStopReason)) {
1083→ yield {
1084→ type: 'result',
1085→ subtype: 'error_during_execution',
1086→ duration_ms: Date.now() - startTime,
1087→ duration_api_ms: getTotalAPIDuration(),
1088→ is_error: true,
1089→ num_turns: turnCount,
1090→ stop_reason: lastStopReason,
1091→ session_id: getSessionId(),
1092→ total_cost_usd: getTotalCost(),
1093→ usage: this.totalUsage,
1094→ modelUsage: getModelUsage(),
1095→ permission_denials: this.permissionDenials,
1096→ fast_mode_state: getFastModeState(
1097→ mainLoopModel,
1098→ initialAppState.fastMode,
1099→ ),
1100→ uuid: randomUUID(),
1101→ // Diagnostic prefix: these are what isResultSuccessful() checks — if
1102→ // the result type isn't assistant-with-text/thinking or user-with-
1103→ // tool_result, and stop_reason isn't end_turn, that's why this fired.
1104→ // errors[] is turn-scoped via the watermark; previously it dumped the
1105→ // entire process's logError buffer (ripgrep timeouts, ENOENT, etc).
1106→ errors: (() => {
1107→ const all = getInMemoryErrors()
1108→ const start = errorLogWatermark
1109→ ? all.lastIndexOf(errorLogWatermark) + 1
1110→ : 0
1111→ return [
1112→ `[ede_diagnostic] result_type=${edeResultType} last_content_type=${edeLastContentType} stop_reason=${lastStopReason}`,
1113→ ...all.slice(start).map(_ => _.error),
1114→ ]
1115→ })(),
1116→ }
1117→ return
1118→ }
1119→
1120→ // Extract the text result based on message type
1121→ let textResult = ''
1122→ let isApiError = false
1123→
1124→ if (result.type === 'assistant') {
1125→ const lastContent = last(result.message.content)
1126→ if (
1127→ lastContent?.type === 'text' &&
1128→ !SYNTHETIC_MESSAGES.has(lastContent.text)
1129→ ) {
1130→ textResult = lastContent.text
1131→ }
1132→ isApiError = Boolean(result.isApiErrorMessage)
1133→ }
1134→
1135→ yield {
1136→ type: 'result',
1137→ subtype: 'success',
1138→ is_error: isApiError,
1139→ duration_ms: Date.now() - startTime,
1140→ duration_api_ms: getTotalAPIDuration(),
1141→ num_turns: turnCount,
1142→ result: textResult,
1143→ stop_reason: lastStopReason,
1144→ session_id: getSessionId(),
1145→ total_cost_usd: getTotalCost(),
1146→ usage: this.totalUsage,
1147→ modelUsage: getModelUsage(),
1148→ permission_denials: this.permissionDenials,
1149→ structured_output: structuredOutputFromTool,
1150→ fast_mode_state: getFastModeState(
1151→ mainLoopModel,
1152→ initialAppState.fastMode,
1153→ ),
1154→ uuid: randomUUID(),
1155→ }
1156→ }
1157→
1158→ interrupt(): void {
1159→ this.abortController.abort()
1160→ }
1161→
1162→ getMessages(): readonly Message[] {
1163→ return this.mutableMessages
1164→ }
1165→
1166→ getReadFileState(): FileStateCache {
1167→ return this.readFileState
1168→ }
1169→
1170→ getSessionId(): string {
1171→ return getSessionId()
1172→ }
1173→
1174→ setModel(model: string): void {
1175→ this.config.userSpecifiedModel = model
1176→ }
1177→}
1178→
1179→/**
1180→ * Sends a single prompt to the Claude API and returns the response.
1181→ * Assumes that claude is being used non-interactively -- will not
1182→ * ask the user for permissions or further input.
1183→ *
1184→ * Convenience wrapper around QueryEngine for one-shot usage.
1185→ */
1186→export async function* ask({
1187→ commands,
1188→ prompt,
1189→ promptUuid,
1190→ isMeta,
1191→ cwd,
1192→ tools,
1193→ mcpClients,
1194→ verbose = false,
1195→ thinkingConfig,
1196→ maxTurns,
1197→ maxBudgetUsd,
1198→ taskBudget,
1199→ canUseTool,
1200→ mutableMessages = [],
1201→ getReadFileCache,
1202→ setReadFileCache,
1203→ customSystemPrompt,
1204→ appendSystemPrompt,
1205→ userSpecifiedModel,
1206→ fallbackModel,
1207→ jsonSchema,
1208→ getAppState,
1209→ setAppState,
1210→ abortController,
1211→ replayUserMessages = false,
1212→ includePartialMessages = false,
1213→ handleElicitation,
1214→ agents = [],
1215→ setSDKStatus,
1216→ orphanedPermission,
1217→}: {
1218→ commands: Command[]
1219→ prompt: string | Array<ContentBlockParam>
1220→ promptUuid?: string
1221→ isMeta?: boolean
1222→ cwd: string
1223→ tools: Tools
1224→ verbose?: boolean
1225→ mcpClients: MCPServerConnection[]
1226→ thinkingConfig?: ThinkingConfig
1227→ maxTurns?: number
1228→ maxBudgetUsd?: number
1229→ taskBudget?: { total: number }
1230→ canUseTool: CanUseToolFn
1231→ mutableMessages?: Message[]
1232→ customSystemPrompt?: string
1233→ appendSystemPrompt?: string
1234→ userSpecifiedModel?: string
1235→ fallbackModel?: string
1236→ jsonSchema?: Record<string, unknown>
1237→ getAppState: () => AppState
1238→ setAppState: (f: (prev: AppState) => AppState) => void
1239→ getReadFileCache: () => FileStateCache
1240→ setReadFileCache: (cache: FileStateCache) => void
1241→ abortController?: AbortController
1242→ replayUserMessages?: boolean
1243→ includePartialMessages?: boolean
1244→ handleElicitation?: ToolUseContext['handleElicitation']
1245→ agents?: AgentDefinition[]
1246→ setSDKStatus?: (status: SDKStatus) => void
1247→ orphanedPermission?: OrphanedPermission
1248→}): AsyncGenerator<SDKMessage, void, unknown> {
1249→ const engine = new QueryEngine({
1250→ cwd,
1251→ tools,
1252→ commands,
1253→ mcpClients,
1254→ agents,
1255→ canUseTool,
1256→ getAppState,
1257→ setAppState,
1258→ initialMessages: mutableMessages,
1259→ readFileCache: cloneFileStateCache(getReadFileCache()),
1260→ customSystemPrompt,
1261→ appendSystemPrompt,
1262→ userSpecifiedModel,
1263→ fallbackModel,
1264→ thinkingConfig,
1265→ maxTurns,
1266→ maxBudgetUsd,
1267→ taskBudget,
1268→ jsonSchema,
1269→ verbose,
1270→ handleElicitation,
1271→ replayUserMessages,
1272→ includePartialMessages,
1273→ setSDKStatus,
1274→ abortController,
1275→ orphanedPermission,
1276→ ...(feature('HISTORY_SNIP')
1277→ ? {
1278→ snipReplay: (yielded: Message, store: Message[]) => {
1279→ if (!snipProjection!.isSnipBoundaryMessage(yielded))
1280→ return undefined
1281→ return snipModule!.snipCompactIfNeeded(store, { force: true })
1282→ },
1283→ }
1284→ : {}),
1285→ })
1286→
1287→ try {
1288→ yield* engine.submitMessage(prompt, {
1289→ uuid: promptUuid,
1290→ isMeta,
1291→ })
1292→ } finally {
1293→ setReadFileCache(engine.getReadFileState())
1294→ }
1295→}
1296→Tool Call: Read src\commands.ts Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import addDir from './commands/add-dir/index.js'
3→import autofixPr from './commands/autofix-pr/index.js'
4→import backfillSessions from './commands/backfill-sessions/index.js'
5→import btw from './commands/btw/index.js'
6→import goodClaude from './commands/good-claude/index.js'
7→import issue from './commands/issue/index.js'
8→import feedback from './commands/feedback/index.js'
9→import clear from './commands/clear/index.js'
10→import color from './commands/color/index.js'
11→import commit from './commands/commit.js'
12→import copy from './commands/copy/index.js'
13→import desktop from './commands/desktop/index.js'
14→import commitPushPr from './commands/commit-push-pr.js'
15→import compact from './commands/compact/index.js'
16→import config from './commands/config/index.js'
17→import { context, contextNonInteractive } from './commands/context/index.js'
18→import cost from './commands/cost/index.js'
19→import diff from './commands/diff/index.js'
20→import ctx_viz from './commands/ctx_viz/index.js'
21→import doctor from './commands/doctor/index.js'
22→import memory from './commands/memory/index.js'
23→import help from './commands/help/index.js'
24→import ide from './commands/ide/index.js'
25→import init from './commands/init.js'
26→import initVerifiers from './commands/init-verifiers.js'
27→import keybindings from './commands/keybindings/index.js'
28→import login from './commands/login/index.js'
29→import logout from './commands/logout/index.js'
30→import installGitHubApp from './commands/install-github-app/index.js'
31→import installSlackApp from './commands/install-slack-app/index.js'
32→import breakCache from './commands/break-cache/index.js'
33→import mcp from './commands/mcp/index.js'
34→import mobile from './commands/mobile/index.js'
35→import onboarding from './commands/onboarding/index.js'
36→import pr_comments from './commands/pr_comments/index.js'
37→import releaseNotes from './commands/release-notes/index.js'
38→import rename from './commands/rename/index.js'
39→import resume from './commands/resume/index.js'
40→import review, { ultrareview } from './commands/review.js'
41→import session from './commands/session/index.js'
42→import share from './commands/share/index.js'
43→import skills from './commands/skills/index.js'
44→import status from './commands/status/index.js'
45→import tasks from './commands/tasks/index.js'
46→import teleport from './commands/teleport/index.js'
47→/* eslint-disable @typescript-eslint/no-require-imports */
48→const agentsPlatform =
49→ process.env.USER_TYPE === 'ant'
50→ ? require('./commands/agents-platform/index.js').default
51→ : null
52→/* eslint-enable @typescript-eslint/no-require-imports */
53→import securityReview from './commands/security-review.js'
54→import bughunter from './commands/bughunter/index.js'
55→import terminalSetup from './commands/terminalSetup/index.js'
56→import usage from './commands/usage/index.js'
57→import theme from './commands/theme/index.js'
58→import vim from './commands/vim/index.js'
59→import { feature } from 'bun:bundle'
60→// Dead code elimination: conditional imports
61→/* eslint-disable @typescript-eslint/no-require-imports */
62→const proactive =
63→ feature('PROACTIVE') || feature('KAIROS')
64→ ? require('./commands/proactive.js').default
65→ : null
66→const briefCommand =
67→ feature('KAIROS') || feature('KAIROS_BRIEF')
68→ ? require('./commands/brief.js').default
69→ : null
70→const assistantCommand = feature('KAIROS')
71→ ? require('./commands/assistant/index.js').default
72→ : null
73→const bridge = feature('BRIDGE_MODE')
74→ ? require('./commands/bridge/index.js').default
75→ : null
76→const remoteControlServerCommand =
77→ feature('DAEMON') && feature('BRIDGE_MODE')
78→ ? require('./commands/remoteControlServer/index.js').default
79→ : null
80→const voiceCommand = feature('VOICE_MODE')
81→ ? require('./commands/voice/index.js').default
82→ : null
83→const forceSnip = feature('HISTORY_SNIP')
84→ ? require('./commands/force-snip.js').default
85→ : null
86→const workflowsCmd = feature('WORKFLOW_SCRIPTS')
87→ ? (
88→ require('./commands/workflows/index.js') as typeof import('./commands/workflows/index.js')
89→ ).default
90→ : null
91→const webCmd = feature('CCR_REMOTE_SETUP')
92→ ? (
93→ require('./commands/remote-setup/index.js') as typeof import('./commands/remote-setup/index.js')
94→ ).default
95→ : null
96→const clearSkillIndexCache = feature('EXPERIMENTAL_SKILL_SEARCH')
97→ ? (
98→ require('./services/skillSearch/localSearch.js') as typeof import('./services/skillSearch/localSearch.js')
99→ ).clearSkillIndexCache
100→ : null
101→const subscribePr = feature('KAIROS_GITHUB_WEBHOOKS')
102→ ? require('./commands/subscribe-pr.js').default
103→ : null
104→const ultraplan = feature('ULTRAPLAN')
105→ ? require('./commands/ultraplan.js').default
106→ : null
107→const torch = feature('TORCH') ? require('./commands/torch.js').default : null
108→const peersCmd = feature('UDS_INBOX')
109→ ? (
110→ require('./commands/peers/index.js') as typeof import('./commands/peers/index.js')
111→ ).default
112→ : null
113→const forkCmd = feature('FORK_SUBAGENT')
114→ ? (
115→ require('./commands/fork/index.js') as typeof import('./commands/fork/index.js')
116→ ).default
117→ : null
118→const buddy = feature('BUDDY')
119→ ? (
120→ require('./commands/buddy/index.js') as typeof import('./commands/buddy/index.js')
121→ ).default
122→ : null
123→/* eslint-enable @typescript-eslint/no-require-imports */
124→import thinkback from './commands/thinkback/index.js'
125→import thinkbackPlay from './commands/thinkback-play/index.js'
126→import permissions from './commands/permissions/index.js'
127→import plan from './commands/plan/index.js'
128→import fast from './commands/fast/index.js'
129→import passes from './commands/passes/index.js'
130→import privacySettings from './commands/privacy-settings/index.js'
131→import hooks from './commands/hooks/index.js'
132→import files from './commands/files/index.js'
133→import branch from './commands/branch/index.js'
134→import agents from './commands/agents/index.js'
135→import plugin from './commands/plugin/index.js'
136→import reloadPlugins from './commands/reload-plugins/index.js'
137→import rewind from './commands/rewind/index.js'
138→import heapDump from './commands/heapdump/index.js'
139→import mockLimits from './commands/mock-limits/index.js'
140→import bridgeKick from './commands/bridge-kick.js'
141→import version from './commands/version.js'
142→import summary from './commands/summary/index.js'
143→import {
144→ resetLimits,
145→ resetLimitsNonInteractive,
146→} from './commands/reset-limits/index.js'
147→import antTrace from './commands/ant-trace/index.js'
148→import perfIssue from './commands/perf-issue/index.js'
149→import sandboxToggle from './commands/sandbox-toggle/index.js'
150→import chrome from './commands/chrome/index.js'
151→import stickers from './commands/stickers/index.js'
152→import advisor from './commands/advisor.js'
153→import { logError } from './utils/log.js'
154→import { toError } from './utils/errors.js'
155→import { logForDebugging } from './utils/debug.js'
156→import {
157→ getSkillDirCommands,
158→ clearSkillCaches,
159→ getDynamicSkills,
160→} from './skills/loadSkillsDir.js'
161→import { getBundledSkills } from './skills/bundledSkills.js'
162→import { getBuiltinPluginSkillCommands } from './plugins/builtinPlugins.js'
163→import {
164→ getPluginCommands,
165→ clearPluginCommandCache,
166→ getPluginSkills,
167→ clearPluginSkillsCache,
168→} from './utils/plugins/loadPluginCommands.js'
169→import memoize from 'lodash-es/memoize.js'
170→import { isUsing3PServices, isClaudeAISubscriber } from './utils/auth.js'
171→import { isFirstPartyAnthropicBaseUrl } from './utils/model/providers.js'
172→import env from './commands/env/index.js'
173→import exit from './commands/exit/index.js'
174→import exportCommand from './commands/export/index.js'
175→import model from './commands/model/index.js'
176→import tag from './commands/tag/index.js'
177→import outputStyle from './commands/output-style/index.js'
178→import remoteEnv from './commands/remote-env/index.js'
179→import upgrade from './commands/upgrade/index.js'
180→import {
181→ extraUsage,
182→ extraUsageNonInteractive,
183→} from './commands/extra-usage/index.js'
184→import rateLimitOptions from './commands/rate-limit-options/index.js'
185→import statusline from './commands/statusline.js'
186→import effort from './commands/effort/index.js'
187→import stats from './commands/stats/index.js'
188→// insights.ts is 113KB (3200 lines, includes diffLines/html rendering). Lazy
189→// shim defers the heavy module until /insights is actually invoked.
190→const usageReport: Command = {
191→ type: 'prompt',
192→ name: 'insights',
193→ description: 'Generate a report analyzing your Claude Code sessions',
194→ contentLength: 0,
195→ progressMessage: 'analyzing your sessions',
196→ source: 'builtin',
197→ async getPromptForCommand(args, context) {
198→ const real = (await import('./commands/insights.js')).default
199→ if (real.type !== 'prompt') throw new Error('unreachable')
200→ return real.getPromptForCommand(args, context)
201→ },
202→}
203→import oauthRefresh from './commands/oauth-refresh/index.js'
204→import debugToolCall from './commands/debug-tool-call/index.js'
205→import { getSettingSourceName } from './utils/settings/constants.js'
206→import {
207→ type Command,
208→ getCommandName,
209→ isCommandEnabled,
210→} from './types/command.js'
211→
212→// Re-export types from the centralized location
213→export type {
214→ Command,
215→ CommandBase,
216→ CommandResultDisplay,
217→ LocalCommandResult,
218→ LocalJSXCommandContext,
219→ PromptCommand,
220→ ResumeEntrypoint,
221→} from './types/command.js'
222→export { getCommandName, isCommandEnabled } from './types/command.js'
223→
224→// Commands that get eliminated from the external build
225→export const INTERNAL_ONLY_COMMANDS = [
226→ backfillSessions,
227→ breakCache,
228→ bughunter,
229→ commit,
230→ commitPushPr,
231→ ctx_viz,
232→ goodClaude,
233→ issue,
234→ initVerifiers,
235→ ...(forceSnip ? [forceSnip] : []),
236→ mockLimits,
237→ bridgeKick,
238→ version,
239→ ...(ultraplan ? [ultraplan] : []),
240→ ...(subscribePr ? [subscribePr] : []),
241→ resetLimits,
242→ resetLimitsNonInteractive,
243→ onboarding,
244→ share,
245→ summary,
246→ teleport,
247→ antTrace,
248→ perfIssue,
249→ env,
250→ oauthRefresh,
251→ debugToolCall,
252→ agentsPlatform,
253→ autofixPr,
254→].filter(Boolean)
255→
256→// Declared as a function so that we don't run this until getCommands is called,
257→// since underlying functions read from config, which can't be read at module initialization time
258→const COMMANDS = memoize((): Command[] => [
259→ addDir,
260→ advisor,
261→ agents,
262→ branch,
263→ btw,
264→ chrome,
265→ clear,
266→ color,
267→ compact,
268→ config,
269→ copy,
270→ desktop,
271→ context,
272→ contextNonInteractive,
273→ cost,
274→ diff,
275→ doctor,
276→ effort,
277→ exit,
278→ fast,
279→ files,
280→ heapDump,
281→ help,
282→ ide,
283→ init,
284→ keybindings,
285→ installGitHubApp,
286→ installSlackApp,
287→ mcp,
288→ memory,
289→ mobile,
290→ model,
291→ outputStyle,
292→ remoteEnv,
293→ plugin,
294→ pr_comments,
295→ releaseNotes,
296→ reloadPlugins,
297→ rename,
298→ resume,
299→ session,
300→ skills,
301→ stats,
302→ status,
303→ statusline,
304→ stickers,
305→ tag,
306→ theme,
307→ feedback,
308→ review,
309→ ultrareview,
310→ rewind,
311→ securityReview,
312→ terminalSetup,
313→ upgrade,
314→ extraUsage,
315→ extraUsageNonInteractive,
316→ rateLimitOptions,
317→ usage,
318→ usageReport,
319→ vim,
320→ ...(webCmd ? [webCmd] : []),
321→ ...(forkCmd ? [forkCmd] : []),
322→ ...(buddy ? [buddy] : []),
323→ ...(proactive ? [proactive] : []),
324→ ...(briefCommand ? [briefCommand] : []),
325→ ...(assistantCommand ? [assistantCommand] : []),
326→ ...(bridge ? [bridge] : []),
327→ ...(remoteControlServerCommand ? [remoteControlServerCommand] : []),
328→ ...(voiceCommand ? [voiceCommand] : []),
329→ thinkback,
330→ thinkbackPlay,
331→ permissions,
332→ plan,
333→ privacySettings,
334→ hooks,
335→ exportCommand,
336→ sandboxToggle,
337→ ...(!isUsing3PServices() ? [logout, login()] : []),
338→ passes,
339→ ...(peersCmd ? [peersCmd] : []),
340→ tasks,
341→ ...(workflowsCmd ? [workflowsCmd] : []),
342→ ...(torch ? [torch] : []),
343→ ...(process.env.USER_TYPE === 'ant' && !process.env.IS_DEMO
344→ ? INTERNAL_ONLY_COMMANDS
345→ : []),
346→])
347→
348→export const builtInCommandNames = memoize(
349→ (): Set<string> =>
350→ new Set(COMMANDS().flatMap(_ => [_.name, ...(_.aliases ?? [])])),
351→)
352→
353→async function getSkills(cwd: string): Promise<{
354→ skillDirCommands: Command[]
355→ pluginSkills: Command[]
356→ bundledSkills: Command[]
357→ builtinPluginSkills: Command[]
358→}> {
359→ try {
360→ const [skillDirCommands, pluginSkills] = await Promise.all([
361→ getSkillDirCommands(cwd).catch(err => {
362→ logError(toError(err))
363→ logForDebugging(
364→ 'Skill directory commands failed to load, continuing without them',
365→ )
366→ return []
367→ }),
368→ getPluginSkills().catch(err => {
369→ logError(toError(err))
370→ logForDebugging('Plugin skills failed to load, continuing without them')
371→ return []
372→ }),
373→ ])
374→ // Bundled skills are registered synchronously at startup
375→ const bundledSkills = getBundledSkills()
376→ // Built-in plugin skills come from enabled built-in plugins
377→ const builtinPluginSkills = getBuiltinPluginSkillCommands()
378→ logForDebugging(
379→ `getSkills returning: ${skillDirCommands.length} skill dir commands, ${pluginSkills.length} plugin skills, ${bundledSkills.length} bundled skills, ${builtinPluginSkills.length} builtin plugin skills`,
380→ )
381→ return {
382→ skillDirCommands,
383→ pluginSkills,
384→ bundledSkills,
385→ builtinPluginSkills,
386→ }
387→ } catch (err) {
388→ // This should never happen since we catch at the Promise level, but defensive
389→ logError(toError(err))
390→ logForDebugging('Unexpected error in getSkills, returning empty')
391→ return {
392→ skillDirCommands: [],
393→ pluginSkills: [],
394→ bundledSkills: [],
395→ builtinPluginSkills: [],
396→ }
397→ }
398→}
399→
400→/* eslint-disable @typescript-eslint/no-require-imports */
401→const getWorkflowCommands = feature('WORKFLOW_SCRIPTS')
402→ ? (
403→ require('./tools/WorkflowTool/createWorkflowCommand.js') as typeof import('./tools/WorkflowTool/createWorkflowCommand.js')
404→ ).getWorkflowCommands
405→ : null
406→/* eslint-enable @typescript-eslint/no-require-imports */
407→
408→/**
409→ * Filters commands by their declared `availability` (auth/provider requirement).
410→ * Commands without `availability` are treated as universal.
411→ * This runs before `isEnabled()` so that provider-gated commands are hidden
412→ * regardless of feature-flag state.
413→ *
414→ * Not memoized — auth state can change mid-session (e.g. after /login),
415→ * so this must be re-evaluated on every getCommands() call.
416→ */
417→export function meetsAvailabilityRequirement(cmd: Command): boolean {
418→ if (!cmd.availability) return true
419→ for (const a of cmd.availability) {
420→ switch (a) {
421→ case 'claude-ai':
422→ if (isClaudeAISubscriber()) return true
423→ break
424→ case 'console':
425→ // Console API key user = direct 1P API customer (not 3P, not claude.ai).
426→ // Excludes 3P (Bedrock/Vertex/Foundry) who don't set ANTHROPIC_BASE_URL
427→ // and gateway users who proxy through a custom base URL.
428→ if (
429→ !isClaudeAISubscriber() &&
430→ !isUsing3PServices() &&
431→ isFirstPartyAnthropicBaseUrl()
432→ )
433→ return true
434→ break
435→ default: {
436→ const _exhaustive: never = a
437→ void _exhaustive
438→ break
439→ }
440→ }
441→ }
442→ return false
443→}
444→
445→/**
446→ * Loads all command sources (skills, plugins, workflows). Memoized by cwd
447→ * because loading is expensive (disk I/O, dynamic imports).
448→ */
449→const loadAllCommands = memoize(async (cwd: string): Promise<Command[]> => {
450→ const [
451→ { skillDirCommands, pluginSkills, bundledSkills, builtinPluginSkills },
452→ pluginCommands,
453→ workflowCommands,
454→ ] = await Promise.all([
455→ getSkills(cwd),
456→ getPluginCommands(),
457→ getWorkflowCommands ? getWorkflowCommands(cwd) : Promise.resolve([]),
458→ ])
459→
460→ return [
461→ ...bundledSkills,
462→ ...builtinPluginSkills,
463→ ...skillDirCommands,
464→ ...workflowCommands,
465→ ...pluginCommands,
466→ ...pluginSkills,
467→ ...COMMANDS(),
468→ ]
469→})
470→
471→/**
472→ * Returns commands available to the current user. The expensive loading is
473→ * memoized, but availability and isEnabled checks run fresh every call so
474→ * auth changes (e.g. /login) take effect immediately.
475→ */
476→export async function getCommands(cwd: string): Promise<Command[]> {
477→ const allCommands = await loadAllCommands(cwd)
478→
479→ // Get dynamic skills discovered during file operations
480→ const dynamicSkills = getDynamicSkills()
481→
482→ // Build base commands without dynamic skills
483→ const baseCommands = allCommands.filter(
484→ _ => meetsAvailabilityRequirement(_) && isCommandEnabled(_),
485→ )
486→
487→ if (dynamicSkills.length === 0) {
488→ return baseCommands
489→ }
490→
491→ // Dedupe dynamic skills - only add if not already present
492→ const baseCommandNames = new Set(baseCommands.map(c => c.name))
493→ const uniqueDynamicSkills = dynamicSkills.filter(
494→ s =>
495→ !baseCommandNames.has(s.name) &&
496→ meetsAvailabilityRequirement(s) &&
497→ isCommandEnabled(s),
498→ )
499→
500→ if (uniqueDynamicSkills.length === 0) {
501→ return baseCommands
502→ }
503→
504→ // Insert dynamic skills after plugin skills but before built-in commands
505→ const builtInNames = new Set(COMMANDS().map(c => c.name))
506→ const insertIndex = baseCommands.findIndex(c => builtInNames.has(c.name))
507→
508→ if (insertIndex === -1) {
509→ return [...baseCommands, ...uniqueDynamicSkills]
510→ }
511→
512→ return [
513→ ...baseCommands.slice(0, insertIndex),
514→ ...uniqueDynamicSkills,
515→ ...baseCommands.slice(insertIndex),
516→ ]
517→}
518→
519→/**
520→ * Clears only the memoization caches for commands, WITHOUT clearing skill caches.
521→ * Use this when dynamic skills are added to invalidate cached command lists.
522→ */
523→export function clearCommandMemoizationCaches(): void {
524→ loadAllCommands.cache?.clear?.()
525→ getSkillToolCommands.cache?.clear?.()
526→ getSlashCommandToolSkills.cache?.clear?.()
527→ // getSkillIndex in skillSearch/localSearch.ts is a separate memoization layer
528→ // built ON TOP of getSkillToolCommands/getCommands. Clearing only the inner
529→ // caches is a no-op for the outer — lodash memoize returns the cached result
530→ // without ever reaching the cleared inners. Must clear it explicitly.
531→ clearSkillIndexCache?.()
532→}
533→
534→export function clearCommandsCache(): void {
535→ clearCommandMemoizationCaches()
536→ clearPluginCommandCache()
537→ clearPluginSkillsCache()
538→ clearSkillCaches()
539→}
540→
541→/**
542→ * Filter AppState.mcp.commands to MCP-provided skills (prompt-type,
543→ * model-invocable, loaded from MCP). These live outside getCommands() so
544→ * callers that need MCP skills in their skill index thread them through
545→ * separately.
546→ */
547→export function getMcpSkillCommands(
548→ mcpCommands: readonly Command[],
549→): readonly Command[] {
550→ if (feature('MCP_SKILLS')) {
551→ return mcpCommands.filter(
552→ cmd =>
553→ cmd.type === 'prompt' &&
554→ cmd.loadedFrom === 'mcp' &&
555→ !cmd.disableModelInvocation,
556→ )
557→ }
558→ return []
559→}
560→
561→// SkillTool shows ALL prompt-based commands that the model can invoke
562→// This includes both skills (from /skills/) and commands (from /commands/)
563→export const getSkillToolCommands = memoize(
564→ async (cwd: string): Promise<Command[]> => {
565→ const allCommands = await getCommands(cwd)
566→ return allCommands.filter(
567→ cmd =>
568→ cmd.type === 'prompt' &&
569→ !cmd.disableModelInvocation &&
570→ cmd.source !== 'builtin' &&
571→ // Always include skills from /skills/ dirs, bundled skills, and legacy /commands/ entries
572→ // (they all get an auto-derived description from the first line if frontmatter is missing).
573→ // Plugin/MCP commands still require an explicit description to appear in the listing.
574→ (cmd.loadedFrom === 'bundled' ||
575→ cmd.loadedFrom === 'skills' ||
576→ cmd.loadedFrom === 'commands_DEPRECATED' ||
577→ cmd.hasUserSpecifiedDescription ||
578→ cmd.whenToUse),
579→ )
580→ },
581→)
582→
583→// Filters commands to include only skills. Skills are commands that provide
584→// specialized capabilities for the model to use. They are identified by
585→// loadedFrom being 'skills', 'plugin', or 'bundled', or having disableModelInvocation set.
586→export const getSlashCommandToolSkills = memoize(
587→ async (cwd: string): Promise<Command[]> => {
588→ try {
589→ const allCommands = await getCommands(cwd)
590→ return allCommands.filter(
591→ cmd =>
592→ cmd.type === 'prompt' &&
593→ cmd.source !== 'builtin' &&
594→ (cmd.hasUserSpecifiedDescription || cmd.whenToUse) &&
595→ (cmd.loadedFrom === 'skills' ||
596→ cmd.loadedFrom === 'plugin' ||
597→ cmd.loadedFrom === 'bundled' ||
598→ cmd.disableModelInvocation),
599→ )
600→ } catch (error) {
601→ logError(toError(error))
602→ // Return empty array rather than throwing - skills are non-critical
603→ // This prevents skill loading failures from breaking the entire system
604→ logForDebugging('Returning empty skills array due to load failure')
605→ return []
606→ }
607→ },
608→)
609→
610→/**
611→ * Commands that are safe to use in remote mode (--remote).
612→ * These only affect local TUI state and don't depend on local filesystem,
613→ * git, shell, IDE, MCP, or other local execution context.
614→ *
615→ * Used in two places:
616→ * 1. Pre-filtering commands in main.tsx before REPL renders (prevents race with CCR init)
617→ * 2. Preserving local-only commands in REPL's handleRemoteInit after CCR filters
618→ */
619→export const REMOTE_SAFE_COMMANDS: Set<Command> = new Set([
620→ session, // Shows QR code / URL for remote session
621→ exit, // Exit the TUI
622→ clear, // Clear screen
623→ help, // Show help
624→ theme, // Change terminal theme
625→ color, // Change agent color
626→ vim, // Toggle vim mode
627→ cost, // Show session cost (local cost tracking)
628→ usage, // Show usage info
629→ copy, // Copy last message
630→ btw, // Quick note
631→ feedback, // Send feedback
632→ plan, // Plan mode toggle
633→ keybindings, // Keybinding management
634→ statusline, // Status line toggle
635→ stickers, // Stickers
636→ mobile, // Mobile QR code
637→])
638→
639→/**
640→ * Builtin commands of type 'local' that ARE safe to execute when received
641→ * over the Remote Control bridge. These produce text output that streams
642→ * back to the mobile/web client and have no terminal-only side effects.
643→ *
644→ * 'local-jsx' commands are blocked by type (they render Ink UI) and
645→ * 'prompt' commands are allowed by type (they expand to text sent to the
646→ * model) — this set only gates 'local' commands.
647→ *
648→ * When adding a new 'local' command that should work from mobile, add it
649→ * here. Default is blocked.
650→ */
651→export const BRIDGE_SAFE_COMMANDS: Set<Command> = new Set(
652→ [
653→ compact, // Shrink context — useful mid-session from a phone
654→ clear, // Wipe transcript
655→ cost, // Show session cost
656→ summary, // Summarize conversation
657→ releaseNotes, // Show changelog
658→ files, // List tracked files
659→ ].filter((c): c is Command => c !== null),
660→)
661→
662→/**
663→ * Whether a slash command is safe to execute when its input arrived over the
664→ * Remote Control bridge (mobile/web client).
665→ *
666→ * PR #19134 blanket-blocked all slash commands from bridge inbound because
667→ * `/model` from iOS was popping the local Ink picker. This predicate relaxes
668→ * that with an explicit allowlist: 'prompt' commands (skills) expand to text
669→ * and are safe by construction; 'local' commands need an explicit opt-in via
670→ * BRIDGE_SAFE_COMMANDS; 'local-jsx' commands render Ink UI and stay blocked.
671→ */
672→export function isBridgeSafeCommand(cmd: Command): boolean {
673→ if (cmd.type === 'local-jsx') return false
674→ if (cmd.type === 'prompt') return true
675→ return BRIDGE_SAFE_COMMANDS.has(cmd)
676→}
677→
678→/**
679→ * Filter commands to only include those safe for remote mode.
680→ * Used to pre-filter commands when rendering the REPL in --remote mode,
681→ * preventing local-only commands from being briefly available before
682→ * the CCR init message arrives.
683→ */
684→export function filterCommandsForRemoteMode(commands: Command[]): Command[] {
685→ return commands.filter(cmd => REMOTE_SAFE_COMMANDS.has(cmd))
686→}
687→
688→export function findCommand(
689→ commandName: string,
690→ commands: Command[],
691→): Command | undefined {
692→ return commands.find(
693→ _ =>
694→ _.name === commandName ||
695→ getCommandName(_) === commandName ||
696→ _.aliases?.includes(commandName),
697→ )
698→}
699→
700→export function hasCommand(commandName: string, commands: Command[]): boolean {
701→ return findCommand(commandName, commands) !== undefined
702→}
703→
704→export function getCommand(commandName: string, commands: Command[]): Command {
705→ const command = findCommand(commandName, commands)
706→ if (!command) {
707→ throw ReferenceError(
708→ `Command ${commandName} not found. Available commands: ${commands
709→ .map(_ => {
710→ const name = getCommandName(_)
711→ return _.aliases ? `${name} (aliases: ${_.aliases.join(', ')})` : name
712→ })
713→ .sort((a, b) => a.localeCompare(b))
714→ .join(', ')}`,
715→ )
716→ }
717→
718→ return command
719→}
720→
721→/**
722→ * Formats a command's description with its source annotation for user-facing UI.
723→ * Use this in typeahead, help screens, and other places where users need to see
724→ * where a command comes from.
725→ *
726→ * For model-facing prompts (like SkillTool), use cmd.description directly.
727→ */
728→export function formatDescriptionWithSource(cmd: Command): string {
729→ if (cmd.type !== 'prompt') {
730→ return cmd.description
731→ }
732→
733→ if (cmd.kind === 'workflow') {
734→ return `${cmd.description} (workflow)`
735→ }
736→
737→ if (cmd.source === 'plugin') {
738→ const pluginName = cmd.pluginInfo?.pluginManifest.name
739→ if (pluginName) {
740→ return `(${pluginName}) ${cmd.description}`
741→ }
742→ return `${cmd.description} (plugin)`
743→ }
744→
745→ if (cmd.source === 'builtin' || cmd.source === 'mcp') {
746→ return cmd.description
747→ }
748→
749→ if (cmd.source === 'bundled') {
750→ return `${cmd.description} (bundled)`
751→ }
752→
753→ return `${cmd.description} (${getSettingSourceName(cmd.source)})`
754→}
755→Tool Call: Read src\entrypoints\cli.tsx (1 - 100) Status: Completed
1→import { feature } from 'bun:bundle';
2→
3→// Bugfix for corepack auto-pinning, which adds yarnpkg to peoples' package.jsons
4→// eslint-disable-next-line custom-rules/no-top-level-side-effects
5→process.env.COREPACK_ENABLE_AUTO_PIN = '0';
6→
7→// Set max heap size for child processes in CCR environments (containers have 16GB)
8→// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level, custom-rules/safe-env-boolean-check
9→if (process.env.CLAUDE_CODE_REMOTE === 'true') {
10→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
11→ const existing = process.env.NODE_OPTIONS || '';
12→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
13→ process.env.NODE_OPTIONS = existing ? `${existing} --max-old-space-size=8192` : '--max-old-space-size=8192';
14→}
15→
16→// Harness-science L0 ablation baseline. Inlined here (not init.ts) because
17→// BashTool/AgentTool/PowerShellTool capture DISABLE_BACKGROUND_TASKS into
18→// module-level consts at import time — init() runs too late. feature() gate
19→// DCEs this entire block from external builds.
20→// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
21→if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) {
22→ for (const k of ['CLAUDE_CODE_SIMPLE', 'CLAUDE_CODE_DISABLE_THINKING', 'DISABLE_INTERLEAVED_THINKING', 'DISABLE_COMPACT', 'DISABLE_AUTO_COMPACT', 'CLAUDE_CODE_DISABLE_AUTO_MEMORY', 'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS']) {
23→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
24→ process.env[k] ??= '1';
25→ }
26→}
27→
28→/**
29→ * Bootstrap entrypoint - checks for special flags before loading the full CLI.
30→ * All imports are dynamic to minimize module evaluation for fast paths.
31→ * Fast-path for --version has zero imports beyond this file.
32→ */
33→async function main(): Promise<void> {
34→ const args = process.argv.slice(2);
35→
36→ // Fast-path for --version/-v: zero module loading needed
37→ if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
38→ // MACRO.VERSION is inlined at build time
39→ // biome-ignore lint/suspicious/noConsole:: intentional console output
40→ console.log(`${MACRO.VERSION} (Claude Code)`);
41→ return;
42→ }
43→
44→ // For all other paths, load the startup profiler
45→ const {
46→ profileCheckpoint
47→ } = await import('../utils/startupProfiler.js');
48→ profileCheckpoint('cli_entry');
49→
50→ // Fast-path for --dump-system-prompt: output the rendered system prompt and exit.
51→ // Used by prompt sensitivity evals to extract the system prompt at a specific commit.
52→ // Ant-only: eliminated from external builds via feature flag.
53→ if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') {
54→ profileCheckpoint('cli_dump_system_prompt_path');
55→ const {
56→ enableConfigs
57→ } = await import('../utils/config.js');
58→ enableConfigs();
59→ const {
60→ getMainLoopModel
61→ } = await import('../utils/model/model.js');
62→ const modelIdx = args.indexOf('--model');
63→ const model = modelIdx !== -1 && args[modelIdx + 1] || getMainLoopModel();
64→ const {
65→ getSystemPrompt
66→ } = await import('../constants/prompts.js');
67→ const prompt = await getSystemPrompt([], model);
68→ // biome-ignore lint/suspicious/noConsole:: intentional console output
69→ console.log(prompt.join('\n'));
70→ return;
71→ }
72→ if (process.argv[2] === '--claude-in-chrome-mcp') {
73→ profileCheckpoint('cli_claude_in_chrome_mcp_path');
74→ const {
75→ runClaudeInChromeMcpServer
76→ } = await import('../utils/claudeInChrome/mcpServer.js');
77→ await runClaudeInChromeMcpServer();
78→ return;
79→ } else if (process.argv[2] === '--chrome-native-host') {
80→ profileCheckpoint('cli_chrome_native_host_path');
81→ const {
82→ runChromeNativeHost
83→ } = await import('../utils/claudeInChrome/chromeNativeHost.js');
84→ await runChromeNativeHost();
85→ return;
86→ } else if (feature('CHICAGO_MCP') && process.argv[2] === '--computer-use-mcp') {
87→ profileCheckpoint('cli_computer_use_mcp_path');
88→ const {
89→ runComputerUseMcpServer
90→ } = await import('../utils/computerUse/mcpServer.js');
91→ await runComputerUseMcpServer();
92→ return;
93→ }
94→
95→ // Fast-path for `--daemon-worker=<kind>` (internal — supervisor spawns this).
96→ // Must come before the daemon subcommand check: spawned per-worker, so
97→ // perf-sensitive. No enableConfigs(), no analytics sinks at this layer —
98→ // workers are lean. If a worker kind needs configs/auth (assistant will),
99→ // it calls them inside its run() fn.
100→ if (feature('DAEMON') && args[0] === '--daemon-worker') {Tool Call: Read src\state\AppState.ts Status: Failed
File does not exist. Note: your current working directory is D:\code\play\stock_ai_rust\claude-code. Did you mean AppState.tsx?Tool Call: Read src\entrypoints\init.ts (1 - 100) Status: Completed
1→import { profileCheckpoint } from '../utils/startupProfiler.js'
2→import '../bootstrap/state.js'
3→import '../utils/config.js'
4→import type { Attributes, MetricOptions } from '@opentelemetry/api'
5→import memoize from 'lodash-es/memoize.js'
6→import { getIsNonInteractiveSession } from 'src/bootstrap/state.js'
7→import type { AttributedCounter } from '../bootstrap/state.js'
8→import { getSessionCounter, setMeter } from '../bootstrap/state.js'
9→import { shutdownLspServerManager } from '../services/lsp/manager.js'
10→import { populateOAuthAccountInfoIfNeeded } from '../services/oauth/client.js'
11→import {
12→ initializePolicyLimitsLoadingPromise,
13→ isPolicyLimitsEligible,
14→} from '../services/policyLimits/index.js'
15→import {
16→ initializeRemoteManagedSettingsLoadingPromise,
17→ isEligibleForRemoteManagedSettings,
18→ waitForRemoteManagedSettingsToLoad,
19→} from '../services/remoteManagedSettings/index.js'
20→import { preconnectAnthropicApi } from '../utils/apiPreconnect.js'
21→import { applyExtraCACertsFromConfig } from '../utils/caCertsConfig.js'
22→import { registerCleanup } from '../utils/cleanupRegistry.js'
23→import { enableConfigs, recordFirstStartTime } from '../utils/config.js'
24→import { logForDebugging } from '../utils/debug.js'
25→import { detectCurrentRepository } from '../utils/detectRepository.js'
26→import { logForDiagnosticsNoPII } from '../utils/diagLogs.js'
27→import { initJetBrainsDetection } from '../utils/envDynamic.js'
28→import { isEnvTruthy } from '../utils/envUtils.js'
29→import { ConfigParseError, errorMessage } from '../utils/errors.js'
30→// showInvalidConfigDialog is dynamically imported in the error path to avoid loading React at init
31→import {
32→ gracefulShutdownSync,
33→ setupGracefulShutdown,
34→} from '../utils/gracefulShutdown.js'
35→import {
36→ applyConfigEnvironmentVariables,
37→ applySafeConfigEnvironmentVariables,
38→} from '../utils/managedEnv.js'
39→import { configureGlobalMTLS } from '../utils/mtls.js'
40→import {
41→ ensureScratchpadDir,
42→ isScratchpadEnabled,
43→} from '../utils/permissions/filesystem.js'
44→// initializeTelemetry is loaded lazily via import() in setMeterState() to defer
45→// ~400KB of OpenTelemetry + protobuf modules until telemetry is actually initialized.
46→// gRPC exporters (~700KB via @grpc/grpc-js) are further lazy-loaded within instrumentation.ts.
47→import { configureGlobalAgents } from '../utils/proxy.js'
48→import { isBetaTracingEnabled } from '../utils/telemetry/betaSessionTracing.js'
49→import { getTelemetryAttributes } from '../utils/telemetryAttributes.js'
50→import { setShellIfWindows } from '../utils/windowsPaths.js'
51→
52→// initialize1PEventLogging is dynamically imported to defer OpenTelemetry sdk-logs/resources
53→
54→// Track if telemetry has been initialized to prevent double initialization
55→let telemetryInitialized = false
56→
57→export const init = memoize(async (): Promise<void> => {
58→ const initStartTime = Date.now()
59→ logForDiagnosticsNoPII('info', 'init_started')
60→ profileCheckpoint('init_function_start')
61→
62→ // Validate configs are valid and enable configuration system
63→ try {
64→ const configsStart = Date.now()
65→ enableConfigs()
66→ logForDiagnosticsNoPII('info', 'init_configs_enabled', {
67→ duration_ms: Date.now() - configsStart,
68→ })
69→ profileCheckpoint('init_configs_enabled')
70→
71→ // Apply only safe environment variables before trust dialog
72→ // Full environment variables are applied after trust is established
73→ const envVarsStart = Date.now()
74→ applySafeConfigEnvironmentVariables()
75→
76→ // Apply NODE_EXTRA_CA_CERTS from settings.json to process.env early,
77→ // before any TLS connections. Bun caches the TLS cert store at boot
78→ // via BoringSSL, so this must happen before the first TLS handshake.
79→ applyExtraCACertsFromConfig()
80→
81→ logForDiagnosticsNoPII('info', 'init_safe_env_vars_applied', {
82→ duration_ms: Date.now() - envVarsStart,
83→ })
84→ profileCheckpoint('init_safe_env_vars_applied')
85→
86→ // Make sure things get flushed on exit
87→ setupGracefulShutdown()
88→ profileCheckpoint('init_after_graceful_shutdown')
89→
90→ // Initialize 1P event logging (no security concerns, but deferred to avoid
91→ // loading OpenTelemetry sdk-logs at startup). growthbook.js is already in
92→ // the module cache by this point (firstPartyEventLogger imports it), so the
93→ // second dynamic import adds no load cost.
94→ void Promise.all([
95→ import('../services/analytics/firstPartyEventLogger.js'),
96→ import('../services/analytics/growthbook.js'),
97→ ]).then(([fp, gb]) => {
98→ fp.initialize1PEventLogging()
99→ // Rebuild the logger provider if tengu_1p_event_batch_config changes
100→ // mid-session. Change detection (isEqual) is inside the handler soTool Call: Find D:\code\play\stock_ai_rust\claude-code src/hooks/**/* Status: Completed
src\hooks\fileSuggestions.ts src\hooks\notifs\useAutoModeUnavailableNotification.ts src\hooks\notifs\useCanSwitchToExistingSubscription.tsx src\hooks\notifs\useDeprecationWarningNotification.tsx src\hooks\notifs\useFastModeNotification.tsx src\hooks\notifs\useIDEStatusIndicator.tsx src\hooks\notifs\useInstallMessages.tsx src\hooks\notifs\useLspInitializationNotification.tsx src\hooks\notifs\useMcpConnectivityStatus.tsx src\hooks\notifs\useModelMigrationNotifications.tsx src\hooks\notifs\useNpmDeprecationNotification.tsx src\hooks\notifs\usePluginAutoupdateNotification.tsx src\hooks\notifs\usePluginInstallationStatus.tsx src\hooks\notifs\useRateLimitWarningNotification.tsx src\hooks\notifs\useSettingsErrors.tsx src\hooks\notifs\useStartupNotification.ts src\hooks\notifs\useTeammateShutdownNotification.ts src\hooks\renderPlaceholder.ts src\hooks\toolPermission\PermissionContext.ts src\hooks\toolPermission\handlers\coordinatorHandler.ts src\hooks\toolPermission\handlers\interactiveHandler.ts src\hooks\toolPermission\handlers\swarmWorkerHandler.ts src\hooks\toolPermission\permissionLogging.ts src\hooks\unifiedSuggestions.ts src\hooks\useAfterFirstRender.ts src\hooks\useApiKeyVerification.ts src\hooks\useArrowKeyHistory.tsx src\hooks\useAssistantHistory.ts src\hooks\useAwaySummary.ts src\hooks\useBackgroundTaskNavigation.ts src\hooks\useBlink.ts src\hooks\useCancelRequest.ts src\hooks\useCanUseTool.tsx src\hooks\useChromeExtensionNotification.tsx src\hooks\useClaudeCodeHintRecommendation.tsx src\hooks\useClipboardImageHint.ts src\hooks\useCommandKeybindings.tsx src\hooks\useCommandQueue.ts src\hooks\useCopyOnSelect.ts src\hooks\useDeferredHookMessages.ts src\hooks\useDiffData.ts src\hooks\useDiffInIDE.ts src\hooks\useDirectConnect.ts src\hooks\useDoublePress.ts src\hooks\useDynamicConfig.ts src\hooks\useElapsedTime.ts src\hooks\useExitOnCtrlCD.ts src\hooks\useExitOnCtrlCDWithKeybindings.ts src\hooks\useFileHistorySnapshotInit.ts src\hooks\useGlobalKeybindings.tsx src\hooks\useHistorySearch.ts src\hooks\useIdeAtMentioned.ts src\hooks\useIdeConnectionStatus.ts src\hooks\useIDEIntegration.tsx src\hooks\useIdeLogging.ts src\hooks\useIdeSelection.ts src\hooks\useInboxPoller.ts src\hooks\useInputBuffer.ts src\hooks\useIssueFlagBanner.ts src\hooks\useLogMessages.ts src\hooks\useLspPluginRecommendation.tsx src\hooks\useMailboxBridge.ts src\hooks\useMainLoopModel.ts src\hooks\useManagePlugins.ts src\hooks\useMemoryUsage.ts src\hooks\useMergedClients.ts src\hooks\useMergedCommands.ts src\hooks\useMergedTools.ts src\hooks\useMinDisplayTime.ts src\hooks\useNotifyAfterTimeout.ts src\hooks\useOfficialMarketplaceNotification.tsx src\hooks\usePasteHandler.ts src\hooks\usePluginRecommendationBase.tsx src\hooks\usePrStatus.ts src\hooks\usePromptsFromClaudeInChrome.tsx src\hooks\usePromptSuggestion.ts src\hooks\useQueueProcessor.ts src\hooks\useRemoteSession.ts src\hooks\useReplBridge.tsx src\hooks\useSSHSession.ts src\hooks\useScheduledTasks.ts src\hooks\useSearchInput.ts src\hooks\useSessionBackgrounding.ts src\hooks\useSettings.ts src\hooks\useSettingsChange.ts src\hooks\useSkillImprovementSurvey.ts src\hooks\useSkillsChange.ts src\hooks\useSwarmInitialization.ts src\hooks\useSwarmPermissionPoller.ts src\hooks\useTaskListWatcher.ts src\hooks\useTasksV2.ts src\hooks\useTeammateViewAutoExit.ts src\hooks\useTeleportResume.tsx src\hooks\useTerminalSize.ts src\hooks\useTextInput.ts src\hooks\useTimeout.ts src\hooks\useTurnDiffs.ts src\hooks\useTypeahead.tsx src\hooks\useUpdateNotification.ts src\hooks\useVimInput.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\entrypoints\cli.tsx (100 - 199) Status: Completed
100→ if (feature('DAEMON') && args[0] === '--daemon-worker') {
101→ const {
102→ runDaemonWorker
103→ } = await import('../daemon/workerRegistry.js');
104→ await runDaemonWorker(args[1]);
105→ return;
106→ }
107→
108→ // Fast-path for `claude remote-control` (also accepts legacy `claude remote` / `claude sync` / `claude bridge`):
109→ // serve local machine as bridge environment.
110→ // feature() must stay inline for build-time dead code elimination;
111→ // isBridgeEnabled() checks the runtime GrowthBook gate.
112→ if (feature('BRIDGE_MODE') && (args[0] === 'remote-control' || args[0] === 'rc' || args[0] === 'remote' || args[0] === 'sync' || args[0] === 'bridge')) {
113→ profileCheckpoint('cli_bridge_path');
114→ const {
115→ enableConfigs
116→ } = await import('../utils/config.js');
117→ enableConfigs();
118→ const {
119→ getBridgeDisabledReason,
120→ checkBridgeMinVersion
121→ } = await import('../bridge/bridgeEnabled.js');
122→ const {
123→ BRIDGE_LOGIN_ERROR
124→ } = await import('../bridge/types.js');
125→ const {
126→ bridgeMain
127→ } = await import('../bridge/bridgeMain.js');
128→ const {
129→ exitWithError
130→ } = await import('../utils/process.js');
131→
132→ // Auth check must come before the GrowthBook gate check — without auth,
133→ // GrowthBook has no user context and would return a stale/default false.
134→ // getBridgeDisabledReason awaits GB init, so the returned value is fresh
135→ // (not the stale disk cache), but init still needs auth headers to work.
136→ const {
137→ getClaudeAIOAuthTokens
138→ } = await import('../utils/auth.js');
139→ if (!getClaudeAIOAuthTokens()?.accessToken) {
140→ exitWithError(BRIDGE_LOGIN_ERROR);
141→ }
142→ const disabledReason = await getBridgeDisabledReason();
143→ if (disabledReason) {
144→ exitWithError(`Error: ${disabledReason}`);
145→ }
146→ const versionError = checkBridgeMinVersion();
147→ if (versionError) {
148→ exitWithError(versionError);
149→ }
150→
151→ // Bridge is a remote control feature - check policy limits
152→ const {
153→ waitForPolicyLimitsToLoad,
154→ isPolicyAllowed
155→ } = await import('../services/policyLimits/index.js');
156→ await waitForPolicyLimitsToLoad();
157→ if (!isPolicyAllowed('allow_remote_control')) {
158→ exitWithError("Error: Remote Control is disabled by your organization's policy.");
159→ }
160→ await bridgeMain(args.slice(1));
161→ return;
162→ }
163→
164→ // Fast-path for `claude daemon [subcommand]`: long-running supervisor.
165→ if (feature('DAEMON') && args[0] === 'daemon') {
166→ profileCheckpoint('cli_daemon_path');
167→ const {
168→ enableConfigs
169→ } = await import('../utils/config.js');
170→ enableConfigs();
171→ const {
172→ initSinks
173→ } = await import('../utils/sinks.js');
174→ initSinks();
175→ const {
176→ daemonMain
177→ } = await import('../daemon/main.js');
178→ await daemonMain(args.slice(1));
179→ return;
180→ }
181→
182→ // Fast-path for `claude ps|logs|attach|kill` and `--bg`/`--background`.
183→ // Session management against the ~/.claude/sessions/ registry. Flag
184→ // literals are inlined so bg.js only loads when actually dispatching.
185→ if (feature('BG_SESSIONS') && (args[0] === 'ps' || args[0] === 'logs' || args[0] === 'attach' || args[0] === 'kill' || args.includes('--bg') || args.includes('--background'))) {
186→ profileCheckpoint('cli_bg_path');
187→ const {
188→ enableConfigs
189→ } = await import('../utils/config.js');
190→ enableConfigs();
191→ const bg = await import('../cli/bg.js');
192→ switch (args[0]) {
193→ case 'ps':
194→ await bg.psHandler(args.slice(1));
195→ break;
196→ case 'logs':
197→ await bg.logsHandler(args[1]);
198→ break;
199→ case 'attach':Tool Call: Read src\state\AppState.tsx Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→import { feature } from 'bun:bundle';
3→import React, { useContext, useEffect, useEffectEvent, useState, useSyncExternalStore } from 'react';
4→import { MailboxProvider } from '../context/mailbox.js';
5→import { useSettingsChange } from '../hooks/useSettingsChange.js';
6→import { logForDebugging } from '../utils/debug.js';
7→import { createDisabledBypassPermissionsContext, isBypassPermissionsModeDisabled } from '../utils/permissions/permissionSetup.js';
8→import { applySettingsChange } from '../utils/settings/applySettingsChange.js';
9→import type { SettingSource } from '../utils/settings/constants.js';
10→import { createStore } from './store.js';
11→
12→// DCE: voice context is ant-only. External builds get a passthrough.
13→/* eslint-disable @typescript-eslint/no-require-imports */
14→const VoiceProvider: (props: {
15→ children: React.ReactNode;
16→}) => React.ReactNode = feature('VOICE_MODE') ? require('../context/voice.js').VoiceProvider : ({
17→ children
18→}) => children;
19→
20→/* eslint-enable @typescript-eslint/no-require-imports */
21→import { type AppState, type AppStateStore, getDefaultAppState } from './AppStateStore.js';
22→
23→// TODO: Remove these re-exports once all callers import directly from
24→// ./AppStateStore.js. Kept for back-compat during migration so .ts callers
25→// can incrementally move off the .tsx import and stop pulling React.
26→export { type AppState, type AppStateStore, type CompletionBoundary, getDefaultAppState, IDLE_SPECULATION_STATE, type SpeculationResult, type SpeculationState } from './AppStateStore.js';
27→export const AppStoreContext = React.createContext<AppStateStore | null>(null);
28→type Props = {
29→ children: React.ReactNode;
30→ initialState?: AppState;
31→ onChangeAppState?: (args: {
32→ newState: AppState;
33→ oldState: AppState;
34→ }) => void;
35→};
36→const HasAppStateContext = React.createContext<boolean>(false);
37→export function AppStateProvider(t0) {
38→ const $ = _c(13);
39→ const {
40→ children,
41→ initialState,
42→ onChangeAppState
43→ } = t0;
44→ const hasAppStateContext = useContext(HasAppStateContext);
45→ if (hasAppStateContext) {
46→ throw new Error("AppStateProvider can not be nested within another AppStateProvider");
47→ }
48→ let t1;
49→ if ($[0] !== initialState || $[1] !== onChangeAppState) {
50→ t1 = () => createStore(initialState ?? getDefaultAppState(), onChangeAppState);
51→ $[0] = initialState;
52→ $[1] = onChangeAppState;
53→ $[2] = t1;
54→ } else {
55→ t1 = $[2];
56→ }
57→ const [store] = useState(t1);
58→ let t2;
59→ if ($[3] !== store) {
60→ t2 = () => {
61→ const {
62→ toolPermissionContext
63→ } = store.getState();
64→ if (toolPermissionContext.isBypassPermissionsModeAvailable && isBypassPermissionsModeDisabled()) {
65→ logForDebugging("Disabling bypass permissions mode on mount (remote settings loaded before mount)");
66→ store.setState(_temp);
67→ }
68→ };
69→ $[3] = store;
70→ $[4] = t2;
71→ } else {
72→ t2 = $[4];
73→ }
74→ let t3;
75→ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
76→ t3 = [];
77→ $[5] = t3;
78→ } else {
79→ t3 = $[5];
80→ }
81→ useEffect(t2, t3);
82→ let t4;
83→ if ($[6] !== store.setState) {
84→ t4 = source => applySettingsChange(source, store.setState);
85→ $[6] = store.setState;
86→ $[7] = t4;
87→ } else {
88→ t4 = $[7];
89→ }
90→ const onSettingsChange = useEffectEvent(t4);
91→ useSettingsChange(onSettingsChange);
92→ let t5;
93→ if ($[8] !== children) {
94→ t5 = <MailboxProvider><VoiceProvider>{children}</VoiceProvider></MailboxProvider>;
95→ $[8] = children;
96→ $[9] = t5;
97→ } else {
98→ t5 = $[9];
99→ }
100→ let t6;
101→ if ($[10] !== store || $[11] !== t5) {
102→ t6 = <HasAppStateContext.Provider value={true}><AppStoreContext.Provider value={store}>{t5}</AppStoreContext.Provider></HasAppStateContext.Provider>;
103→ $[10] = store;
104→ $[11] = t5;
105→ $[12] = t6;
106→ } else {
107→ t6 = $[12];
108→ }
109→ return t6;
110→}
111→function _temp(prev) {
112→ return {
113→ ...prev,
114→ toolPermissionContext: createDisabledBypassPermissionsContext(prev.toolPermissionContext)
115→ };
116→}
117→function useAppStore(): AppStateStore {
118→ // eslint-disable-next-line react-hooks/rules-of-hooks
119→ const store = useContext(AppStoreContext);
120→ if (!store) {
121→ throw new ReferenceError('useAppState/useSetAppState cannot be called outside of an <AppStateProvider />');
122→ }
123→ return store;
124→}
125→
126→/**
127→ * Subscribe to a slice of AppState. Only re-renders when the selected value
128→ * changes (compared via Object.is).
129→ *
130→ * For multiple independent fields, call the hook multiple times:
131→ * ```
132→ * const verbose = useAppState(s => s.verbose)
133→ * const model = useAppState(s => s.mainLoopModel)
134→ * ```
135→ *
136→ * Do NOT return new objects from the selector -- Object.is will always see
137→ * them as changed. Instead, select an existing sub-object reference:
138→ * ```
139→ * const { text, promptId } = useAppState(s => s.promptSuggestion) // good
140→ * ```
141→ */
142→export function useAppState(selector) {
143→ const $ = _c(3);
144→ const store = useAppStore();
145→ let t0;
146→ if ($[0] !== selector || $[1] !== store) {
147→ t0 = () => {
148→ const state = store.getState();
149→ const selected = selector(state);
150→ if (false && state === selected) {
151→ throw new Error(`Your selector in \`useAppState(${selector.toString()})\` returned the original state, which is not allowed. You must instead return a property for optimised rendering.`);
152→ }
153→ return selected;
154→ };
155→ $[0] = selector;
156→ $[1] = store;
157→ $[2] = t0;
158→ } else {
159→ t0 = $[2];
160→ }
161→ const get = t0;
162→ return useSyncExternalStore(store.subscribe, get, get);
163→}
164→
165→/**
166→ * Get the setAppState updater without subscribing to any state.
167→ * Returns a stable reference that never changes -- components using only
168→ * this hook will never re-render from state changes.
169→ */
170→export function useSetAppState() {
171→ return useAppStore().setState;
172→}
173→
174→/**
175→ * Get the store directly (for passing getState/setState to non-React code).
176→ */
177→export function useAppStateStore() {
178→ return useAppStore();
179→}
180→const NOOP_SUBSCRIBE = () => () => {};
181→
182→/**
183→ * Safe version of useAppState that returns undefined if called outside of AppStateProvider.
184→ * Useful for components that may be rendered in contexts where AppStateProvider isn't available.
185→ */
186→export function useAppStateMaybeOutsideOfProvider(selector) {
187→ const $ = _c(3);
188→ const store = useContext(AppStoreContext);
189→ let t0;
190→ if ($[0] !== selector || $[1] !== store) {
191→ t0 = () => store ? selector(store.getState()) : undefined;
192→ $[0] = selector;
193→ $[1] = store;
194→ $[2] = t0;
195→ } else {
196→ t0 = $[2];
197→ }
198→ return useSyncExternalStore(store ? store.subscribe : NOOP_SUBSCRIBE, t0);
199→}
200→//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmZWF0dXJlIiwiUmVhY3QiLCJ1c2VDb250ZXh0IiwidXNlRWZmZWN0IiwidXNlRWZmZWN0RXZlbnQiLCJ1c2VTdGF0ZSIsInVzZVN5bmNFeHRlcm5hbFN0b3JlIiwiTWFpbGJveFByb3ZpZGVyIiwidXNlU2V0dGluZ3NDaGFuZ2UiLCJsb2dGb3JEZWJ1Z2dpbmciLCJjcmVhdGVEaXNhYmxlZEJ5cGFzc1Blcm1pc3Npb25zQ29udGV4dCIsImlzQnlwYXNzUGVybWlzc2lvbnNNb2RlRGlzYWJsZWQiLCJhcHBseVNldHRpbmdzQ2hhbmdlIiwiU2V0dGluZ1NvdXJjZSIsImNyZWF0ZVN0b3JlIiwiVm9pY2VQcm92aWRlciIsInByb3BzIiwiY2hpbGRyZW4iLCJSZWFjdE5vZGUiLCJyZXF1aXJlIiwiQXBwU3RhdGUiLCJBcHBTdGF0ZVN0b3JlIiwiZ2V0RGVmYXVsdEFwcFN0YXRlIiwiQ29tcGxldGlvbkJvdW5kYXJ5IiwiSURMRV9TUEVDVUxBVElPTl9TVEFURSIsIlNwZWN1bGF0aW9uUmVzdWx0IiwiU3BlY3VsYXRpb25TdGF0ZSIsIkFwcFN0b3JlQ29udGV4dCIsImNyZWF0ZUNvbnRleHQiLCJQcm9wcyIsImluaXRpYWxTdGF0ZSIsIm9uQ2hhbmdlQXBwU3RhdGUiLCJhcmdzIiwibmV3U3RhdGUiLCJvbGRTdGF0ZSIsIkhhc0FwcFN0YXRlQ29udGV4dCIsIkFwcFN0YXRlUHJvdmlkZXIiLCJ0MCIsIiQiLCJfYyIsImhhc0FwcFN0YXRlQ29udGV4dCIsIkVycm9yIiwidDEiLCJzdG9yZSIsInQyIiwidG9vbFBlcm1pc3Npb25Db250ZXh0IiwiZ2V0U3RhdGUiLCJpc0J5cGFzc1Blcm1pc3Npb25zTW9kZUF2YWlsYWJsZSIsInNldFN0YXRlIiwiX3RlbXAiLCJ0MyIsIlN5bWJvbCIsImZvciIsInQ0Iiwic291cmNlIiwib25TZXR0aW5nc0NoYW5nZSIsInQ1IiwidDYiLCJwcmV2IiwidXNlQXBwU3RvcmUiLCJSZWZlcmVuY2VFcnJvciIsInVzZUFwcFN0YXRlIiwic2VsZWN0b3IiLCJzdGF0ZSIsInNlbGVjdGVkIiwidG9TdHJpbmciLCJnZXQiLCJzdWJzY3JpYmUiLCJ1c2VTZXRBcHBTdGF0ZSIsInVzZUFwcFN0YXRlU3RvcmUiLCJOT09QX1NVQlNDUklCRSIsInVzZUFwcFN0YXRlTWF5YmVPdXRzaWRlT2ZQcm92aWRlciIsInVuZGVmaW5lZCJdLCJzb3VyY2VzIjpbIkFwcFN0YXRlLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmZWF0dXJlIH0gZnJvbSAnYnVuOmJ1bmRsZSdcbmltcG9ydCBSZWFjdCwge1xuICB1c2VDb250ZXh0LFxuICB1c2VFZmZlY3QsXG4gIHVzZUVmZmVjdEV2ZW50LFxuICB1c2VTdGF0ZSxcbiAgdXNlU3luY0V4dGVybmFsU3RvcmUsXG59IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgTWFpbGJveFByb3ZpZGVyIH0gZnJvbSAnLi4vY29udGV4dC9tYWlsYm94LmpzJ1xuaW1wb3J0IHsgdXNlU2V0dGluZ3NDaGFuZ2UgfSBmcm9tICcuLi9ob29rcy91c2VTZXR0aW5nc0NoYW5nZS5qcydcbmltcG9ydCB7IGxvZ0ZvckRlYnVnZ2luZyB9IGZyb20gJy4uL3V0aWxzL2RlYnVnLmpzJ1xuaW1wb3J0IHtcbiAgY3JlYXRlRGlzYWJsZWRCeXBhc3NQZXJtaXNzaW9uc0NvbnRleHQsXG4gIGlzQnlwYXNzUGVybWlzc2lvbnNNb2RlRGlzYWJsZWQsXG59IGZyb20gJy4uL3V0aWxzL3Blcm1pc3Npb25zL3Blcm1pc3Npb25TZXR1cC5qcydcbmltcG9ydCB7IGFwcGx5U2V0dGluZ3NDaGFuZ2UgfSBmcm9tICcuLi91dGlscy9zZXR0aW5ncy9hcHBseVNldHRpbmdzQ2hhbmdlLmpzJ1xuaW1wb3J0IHR5cGUgeyBTZXR0aW5nU291cmNlIH0gZnJvbSAnLi4vdXRpbHMvc2V0dGluZ3MvY29uc3RhbnRzLmpzJ1xuaW1wb3J0IHsgY3JlYXRlU3RvcmUgfSBmcm9tICcuL3N0b3JlLmpzJ1xuXG4vLyBEQ0U6IHZvaWNlIGNvbnRleHQgaXMgYW50LW9ubHkuIEV4dGVybmFsIGJ1aWxkcyBnZXQgYSBwYXNzdGhyb3VnaC5cbi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHMgKi9cbmNvbnN0IFZvaWNlUHJvdmlkZXI6IChwcm9wczogeyBjaGlsZHJlbjogUmVhY3QuUmVhY3ROb2RlIH0pID0+IFJlYWN0LlJlYWN0Tm9kZSA9XG4gIGZlYXR1cmUoJ1ZPSUNFX01PREUnKVxuICAgID8gcmVxdWlyZSgnLi4vY29udGV4dC92b2ljZS5qcycpLlZvaWNlUHJvdmlkZXJcbiAgICA6ICh7IGNoaWxkcmVuIH0pID0+IGNoaWxkcmVuXG5cbi8qIGVzbGludC1lbmFibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cyAqL1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBTdGF0ZSxcbiAgdHlwZSBBcHBTdGF0ZVN0b3JlLFxuICBnZXREZWZhdWx0QXBwU3RhdGUsXG59IGZyb20gJy4vQXBwU3RhdGVTdG9yZS5qcydcblxuLy8gVE9ETzogUmVtb3ZlIHRoZXNlIHJlLWV4cG9ydHMgb25jZSBhbGwgY2FsbGVycyBpbXBvcnQgZGlyZWN0bHkgZnJvbVxuLy8gLi9BcHBTdGF0ZVN0b3JlLmpzLiBLZXB0IGZvciBiYWNrLWNvbXBhdCBkdXJpbmcgbWlncmF0aW9uIHNvIC50cyBjYWxsZXJzXG4vLyBjYW4gaW5jcmVtZW50YWxseSBtb3ZlIG9mZiB0aGUgLnRzeCBpbXBvcnQgYW5kIHN0b3AgcHVsbGluZyBSZWFjdC5cbmV4cG9ydCB7XG4gIHR5cGUgQXBwU3RhdGUsXG4gIHR5cGUgQXBwU3RhdGVTdG9yZSxcbiAgdHlwZSBDb21wbGV0aW9uQm91bmRhcnksXG4gIGdldERlZmF1bHRBcHBTdGF0ZSxcbiAgSURMRV9TUEVDVUxBVElPTl9TVEFURSxcbiAgdHlwZSBTcGVjdWxhdGlvblJlc3VsdCxcbiAgdHlwZSBTcGVjdWxhdGlvblN0YXRlLFxufSBmcm9tICcuL0FwcFN0YXRlU3RvcmUuanMnXG5cbmV4cG9ydCBjb25zdCBBcHBTdG9yZUNvbnRleHQgPSBSZWFjdC5jcmVhdGVDb250ZXh0PEFwcFN0YXRlU3RvcmUgfCBudWxsPihudWxsKVxuXG50eXBlIFByb3BzID0ge1xuICBjaGlsZHJlbjogUmVhY3QuUmVhY3ROb2RlXG4gIGluaXRpYWxTdGF0ZT86IEFwcFN0YXRlXG4gIG9uQ2hhbmdlQXBwU3RhdGU/OiAoYXJnczogeyBuZXdTdGF0ZTogQXBwU3RhdGU7IG9sZFN0YXRlOiBBcHBTdGF0ZSB9KSA9PiB2b2lkXG59XG5cbmNvbnN0IEhhc0FwcFN0YXRlQ29udGV4dCA9IFJlYWN0LmNyZWF0ZUNvbnRleHQ8Ym9vbGVhbj4oZmFsc2UpXG5cbmV4cG9ydCBmdW5jdGlvbiBBcHBTdGF0ZVByb3ZpZGVyKHtcbiAgY2hpbGRyZW4sXG4gIGluaXRpYWxTdGF0ZSxcbiAgb25DaGFuZ2VBcHBTdGF0ZSxcbn06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgLy8gRG9uJ3QgYWxsb3cgbmVzdGVkIEFwcFN0YXRlUHJvdmlkZXJzLlxuICBjb25zdCBoYXNBcHBTdGF0ZUNvbnRleHQgPSB1c2VDb250ZXh0KEhhc0FwcFN0YXRlQ29udGV4dClcbiAgaWYgKGhhc0FwcFN0YXRlQ29udGV4dCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdBcHBTdGF0ZVByb3ZpZGVyIGNhbiBub3QgYmUgbmVzdGVkIHdpdGhpbiBhbm90aGVyIEFwcFN0YXRlUHJvdmlkZXInLFxuICAgIClcbiAgfVxuXG4gIC8vIFN0b3JlIGlzIGNyZWF0ZWQgb25jZSBhbmQgbmV2ZXIgY2hhbmdlcyAtLSBzdGFibGUgY29udGV4dCB2YWx1ZSBtZWFuc1xuICAvLyB0aGUgcHJvdmlkZXIgbmV2ZXIgdHJpZ2dlcnMgcmUtcmVuZGVycy4gQ29uc3VtZXJzIHN1YnNjcmliZSB0byBzbGljZXNcbiAgLy8gdmlhIHVzZVN5bmNFeHRlcm5hbFN0b3JlIGluIHVzZUFwcFN0YXRlKHNlbGVjdG9yKS5cbiAgY29uc3QgW3N0b3JlXSA9IHVzZVN0YXRlKCgpID0+XG4gICAgY3JlYXRlU3RvcmU8QXBwU3RhdGU+KFxuICAgICAgaW5pdGlhbFN0YXRlID8/IGdldERlZmF1bHRBcHBTdGF0ZSgpLFxuICAgICAgb25DaGFuZ2VBcHBTdGF0ZSxcbiAgICApLFxuICApXG5cbiAgLy8gQ2hlY2sgb24gbW91bnQgaWYgYnlwYXNzIG1vZGUgc2hvdWxkIGJlIGRpc2FibGVkXG4gIC8vIFRoaXMgaGFuZGxlcyB0aGUgcmFjZSBjb25kaXRpb24gd2hlcmUgcmVtb3RlIHNldHRpbmdzIGxvYWQgQkVGT1JFIHRoaXMgY29tcG9uZW50IG1vdW50cyxcbiAgLy8gbWVhbmluZyB0aGUgc2V0dGluZ3MgY2hhbmdlIG5vdGlmaWNhdGlvbiB3YXMgc2VudCB3aGVuIG5vIGxpc3RlbmVycyB3ZXJlIHN1YnNjcmliZWQuXG4gIC8vIE9uIHN1YnNlcXVlbnQgc2Vzc2lvbnMsIHRoZSBjYWNoZWQgcmVtb3RlLXNldHRpbmdzLmpzb24gaXMgcmVhZCBkdXJpbmcgaW5pdGlhbCBzZXR1cCxcbiAgLy8gYnV0IG9uIHRoZSBmaXJzdCBzZXNzaW9uIHRoZSByZW1vdGUgZmV0Y2ggbWF5IGNvbXBsZXRlIGJlZm9yZSBSZWFjdCBtb3VudHMuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgY29uc3QgeyB0b29sUGVybWlzc2lvbkNvbnRleHQgfSA9IHN0b3JlLmdldFN0YXRlKClcbiAgICBpZiAoXG4gICAgICB0b29sUGVybWlzc2lvbkNvbnRleHQuaXNCeXBhc3NQZXJtaXNzaW9uc01vZGVBdmFpbGFibGUgJiZcbiAgICAgIGlzQnlwYXNzUGVybWlzc2lvbnNNb2RlRGlzYWJsZWQoKVxuICAgICkge1xuICAgICAgbG9nRm9yRGVidWdnaW5nKFxuICAgICAgICAnRGlzYWJsaW5nIGJ5cGFzcyBwZXJtaXNzaW9ucyBtb2RlIG9uIG1vdW50IChyZW1vdGUgc2V0dGluZ3MgbG9hZGVkIGJlZm9yZSBtb3VudCknLFxuICAgICAgKVxuICAgICAgc3RvcmUuc2V0U3RhdGUocHJldiA9PiAoe1xuICAgICAgICAuLi5wcmV2LFxuICAgICAgICB0b29sUGVybWlzc2lvbkNvbnRleHQ6IGNyZWF0ZURpc2FibGVkQnlwYXNzUGVybWlzc2lvbnNDb250ZXh0KFxuICAgICAgICAgIHByZXYudG9vbFBlcm1pc3Npb25Db250ZXh0LFxuICAgICAgICApLFxuICAgICAgfSkpXG4gICAgfVxuICAgIC8vIGJpb21lLWlnbm9yZSBsaW50L2NvcnJlY3RuZXNzL3VzZUV4aGF1c3RpdmVEZXBlbmRlbmNpZXM6IGludGVudGlvbmFsIG1vdW50LW9ubHkgZWZmZWN0XG4gIH0sIFtdKVxuXG4gIC8vIExpc3RlbiBmb3IgZXh0ZXJuYWwgc2V0dGluZ3MgY2hhbmdlcyBhbmQgc3luYyB0byBBcHBTdGF0ZS5cbiAgLy8gVGhpcyBlbnN1cmVzIGZpbGUgd2F0Y2hlciBjaGFuZ2VzIHByb3BhZ2F0ZSB0aHJvdWdoIHRoZSBhcHAgLS1cbiAgLy8gc2hhcmVkIHdpdGggdGhlIGhlYWRsZXNzL1NESyBwYXRoIHZpYSBhcHBseVNldHRpbmdzQ2hhbmdlLlxuICBjb25zdCBvblNldHRpbmdzQ2hhbmdlID0gdXNlRWZmZWN0RXZlbnQoKHNvdXJjZTogU2V0dGluZ1NvdXJjZSkgPT5cbiAgICBhcHBseVNldHRpbmdzQ2hhbmdlKHNvdXJjZSwgc3RvcmUuc2V0U3RhdGUpLFxuICApXG4gIHVzZVNldHRpbmdzQ2hhbmdlKG9uU2V0dGluZ3NDaGFuZ2UpXG5cbiAgcmV0dXJuIChcbiAgICA8SGFzQXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyIHZhbHVlPXt0cnVlfT5cbiAgICAgIDxBcHBTdG9yZUNvbnRleHQuUHJvdmlkZXIgdmFsdWU9e3N0b3JlfT5cbiAgICAgICAgPE1haWxib3hQcm92aWRlcj5cbiAgICAgICAgICA8Vm9pY2VQcm92aWRlcj57Y2hpbGRyZW59PC9Wb2ljZVByb3ZpZGVyPlxuICAgICAgICA8L01haWxib3hQcm92aWRlcj5cbiAgICAgIDwvQXBwU3RvcmVDb250ZXh0LlByb3ZpZGVyPlxuICAgIDwvSGFzQXBwU3RhdGVDb250ZXh0LlByb3ZpZGVyPlxuICApXG59XG5cbmZ1bmN0aW9uIHVzZUFwcFN0b3JlKCk6IEFwcFN0YXRlU3RvcmUge1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3QtaG9va3MvcnVsZXMtb2YtaG9va3NcbiAgY29uc3Qgc3RvcmUgPSB1c2VDb250ZXh0KEFwcFN0b3JlQ29udGV4dClcbiAgaWYgKCFzdG9yZSkge1xuICAgIHRocm93IG5ldyBSZWZlcmVuY2VFcnJvcihcbiAgICAgICd1c2VBcHBTdGF0ZS91c2VTZXRBcHBTdGF0ZSBjYW5ub3QgYmUgY2FsbGVkIG91dHNpZGUgb2YgYW4gPEFwcFN0YXRlUHJvdmlkZXIgLz4nLFxuICAgIClcbiAgfVxuICByZXR1cm4gc3RvcmVcbn1cblxuLyoqXG4gKiBTdWJzY3JpYmUgdG8gYSBzbGljZSBvZiBBcHBTdGF0ZS4gT25seSByZS1yZW5kZXJzIHdoZW4gdGhlIHNlbGVjdGVkIHZhbHVlXG4gKiBjaGFuZ2VzIChjb21wYXJlZCB2aWEgT2JqZWN0LmlzKS5cbiAqXG4gKiBGb3IgbXVsdGlwbGUgaW5kZXBlbmRlbnQgZmllbGRzLCBjYWxsIHRoZSBob29rIG11bHRpcGxlIHRpbWVzOlxuICogYGBgXG4gKiBjb25zdCB2ZXJib3NlID0gdXNlQXBwU3RhdGUocyA9PiBzLnZlcmJvc2UpXG4gKiBjb25zdCBtb2RlbCA9IHVzZUFwcFN0YXRlKHMgPT4gcy5tYWluTG9vcE1vZGVsKVxuICogYGBgXG4gKlxuICogRG8gTk9UIHJldHVybiBuZXcgb2JqZWN0cyBmcm9tIHRoZSBzZWxlY3RvciAtLSBPYmplY3QuaXMgd2lsbCBhbHdheXMgc2VlXG4gKiB0aGVtIGFzIGNoYW5nZWQuIEluc3RlYWQsIHNlbGVjdCBhbiBleGlzdGluZyBzdWItb2JqZWN0IHJlZmVyZW5jZTpcbiAqIGBgYFxuICogY29uc3QgeyB0ZXh0LCBwcm9tcHRJZCB9ID0gdXNlQXBwU3RhdGUocyA9PiBzLnByb21wdFN1Z2dlc3Rpb24pIC8vIGdvb2RcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlQXBwU3RhdGU8VD4oc2VsZWN0b3I6IChzdGF0ZTogQXBwU3RhdGUpID0+IFQpOiBUIHtcbiAgY29uc3Qgc3RvcmUgPSB1c2VBcHBTdG9yZSgpXG5cbiAgY29uc3QgZ2V0ID0gKCkgPT4ge1xuICAgIGNvbnN0IHN0YXRlID0gc3RvcmUuZ2V0U3RhdGUoKVxuICAgIGNvbnN0IHNlbGVjdGVkID0gc2VsZWN0b3Ioc3RhdGUpXG5cbiAgICBpZiAoXCJleHRlcm5hbFwiID09PSAnYW50JyAmJiBzdGF0ZSA9PT0gc2VsZWN0ZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYFlvdXIgc2VsZWN0b3IgaW4gXFxgdXNlQXBwU3RhdGUoJHtzZWxlY3Rvci50b1N0cmluZygpfSlcXGAgcmV0dXJuZWQgdGhlIG9yaWdpbmFsIHN0YXRlLCB3aGljaCBpcyBub3QgYWxsb3dlZC4gWW91IG11c3QgaW5zdGVhZCByZXR1cm4gYSBwcm9wZXJ0eSBmb3Igb3B0aW1pc2VkIHJlbmRlcmluZy5gLFxuICAgICAgKVxuICAgIH1cblxuICAgIHJldHVybiBzZWxlY3RlZFxuICB9XG5cbiAgcmV0dXJuIHVzZVN5bmNFeHRlcm5hbFN0b3JlKHN0b3JlLnN1YnNjcmliZSwgZ2V0LCBnZXQpXG59XG5cbi8qKlxuICogR2V0IHRoZSBzZXRBcHBTdGF0ZSB1cGRhdGVyIHdpdGhvdXQgc3Vic2NyaWJpbmcgdG8gYW55IHN0YXRlLlxuICogUmV0dXJucyBhIHN0YWJsZSByZWZlcmVuY2UgdGhhdCBuZXZlciBjaGFuZ2VzIC0tIGNvbXBvbmVudHMgdXNpbmcgb25seVxuICogdGhpcyBob29rIHdpbGwgbmV2ZXIgcmUtcmVuZGVyIGZyb20gc3RhdGUgY2hhbmdlcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVNldEFwcFN0YXRlKCk6IChcbiAgdXBkYXRlcjogKHByZXY6IEFwcFN0YXRlKSA9PiBBcHBTdGF0ZSxcbikgPT4gdm9pZCB7XG4gIHJldHVybiB1c2VBcHBTdG9yZSgpLnNldFN0YXRlXG59XG5cbi8qKlxuICogR2V0IHRoZSBzdG9yZSBkaXJlY3RseSAoZm9yIHBhc3NpbmcgZ2V0U3RhdGUvc2V0U3RhdGUgdG8gbm9uLVJlYWN0IGNvZGUpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlQXBwU3RhdGVTdG9yZSgpOiBBcHBTdGF0ZVN0b3JlIHtcbiAgcmV0dXJuIHVzZUFwcFN0b3JlKClcbn1cblxuY29uc3QgTk9PUF9TVUJTQ1JJQkUgPSAoKSA9PiAoKSA9PiB7fVxuXG4vKipcbiAqIFNhZmUgdmVyc2lvbiBvZiB1c2VBcHBTdGF0ZSB0aGF0IHJldHVybnMgdW5kZWZpbmVkIGlmIGNhbGxlZCBvdXRzaWRlIG9mIEFwcFN0YXRlUHJvdmlkZXIuXG4gKiBVc2VmdWwgZm9yIGNvbXBvbmVudHMgdGhhdCBtYXkgYmUgcmVuZGVyZWQgaW4gY29udGV4dHMgd2hlcmUgQXBwU3RhdGVQcm92aWRlciBpc24ndCBhdmFpbGFibGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VBcHBTdGF0ZU1heWJlT3V0c2lkZU9mUHJvdmlkZXI8VD4oXG4gIHNlbGVjdG9yOiAoc3RhdGU6IEFwcFN0YXRlKSA9PiBULFxuKTogVCB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHN0b3JlID0gdXNlQ29udGV4dChBcHBTdG9yZUNvbnRleHQpXG4gIHJldHVybiB1c2VTeW5jRXh0ZXJuYWxTdG9yZShzdG9yZSA/IHN0b3JlLnN1YnNjcmliZSA6IE5PT1BfU1VCU0NSSUJFLCAoKSA9PlxuICAgIHN0b3JlID8gc2VsZWN0b3Ioc3RvcmUuZ2V0U3RhdGUoKSkgOiB1bmRlZmluZWQsXG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IjtBQUFBLFNBQVNBLE9BQU8sUUFBUSxZQUFZO0FBQ3BDLE9BQU9DLEtBQUssSUFDVkMsVUFBVSxFQUNWQyxTQUFTLEVBQ1RDLGNBQWMsRUFDZEMsUUFBUSxFQUNSQyxvQkFBb0IsUUFDZixPQUFPO0FBQ2QsU0FBU0MsZUFBZSxRQUFRLHVCQUF1QjtBQUN2RCxTQUFTQyxpQkFBaUIsUUFBUSwrQkFBK0I7QUFDakUsU0FBU0MsZUFBZSxRQUFRLG1CQUFtQjtBQUNuRCxTQUNFQyxzQ0FBc0MsRUFDdENDLCtCQUErQixRQUMxQix5Q0FBeUM7QUFDaEQsU0FBU0MsbUJBQW1CLFFBQVEsMENBQTBDO0FBQzlFLGNBQWNDLGFBQWEsUUFBUSxnQ0FBZ0M7QUFDbkUsU0FBU0MsV0FBVyxRQUFRLFlBQVk7O0FBRXhDO0FBQ0E7QUFDQSxNQUFNQyxhQUFhLEVBQUUsQ0FBQ0MsS0FBSyxFQUFFO0VBQUVDLFFBQVEsRUFBRWhCLEtBQUssQ0FBQ2lCLFNBQVM7QUFBQyxDQUFDLEVBQUUsR0FBR2pCLEtBQUssQ0FBQ2lCLFNBQVMsR0FDNUVsQixPQUFPLENBQUMsWUFBWSxDQUFDLEdBQ2pCbUIsT0FBTyxDQUFDLHFCQUFxQixDQUFDLENBQUNKLGFBQWEsR0FDNUMsQ0FBQztFQUFFRTtBQUFTLENBQUMsS0FBS0EsUUFBUTs7QUFFaEM7QUFDQSxTQUNFLEtBQUtHLFFBQVEsRUFDYixLQUFLQyxhQUFhLEVBQ2xCQyxrQkFBa0IsUUFDYixvQkFBb0I7O0FBRTNCO0FBQ0E7QUFDQTtBQUNBLFNBQ0UsS0FBS0YsUUFBUSxFQUNiLEtBQUtDLGFBQWEsRUFDbEIsS0FBS0Usa0JBQWtCLEVBQ3ZCRCxrQkFBa0IsRUFDbEJFLHNCQUFzQixFQUN0QixLQUFLQyxpQkFBaUIsRUFDdEIsS0FBS0MsZ0JBQWdCLFFBQ2hCLG9CQUFvQjtBQUUzQixPQUFPLE1BQU1DLGVBQWUsR0FBRzFCLEtBQUssQ0FBQzJCLGFBQWEsQ0FBQ1AsYUFBYSxHQUFHLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQztBQUU5RSxLQUFLUSxLQUFLLEdBQUc7RUFDWFosUUFBUSxFQUFFaEIsS0FBSyxDQUFDaUIsU0FBUztFQUN6QlksWUFBWSxDQUFDLEVBQUVWLFFBQVE7RUFDdkJXLGdCQUFnQixDQUFDLEVBQUUsQ0FBQ0MsSUFBSSxFQUFFO0lBQUVDLFFBQVEsRUFBRWIsUUFBUTtJQUFFYyxRQUFRLEVBQUVkLFFBQVE7RUFBQyxDQUFDLEVBQUUsR0FBRyxJQUFJO0FBQy9FLENBQUM7QUFFRCxNQUFNZSxrQkFBa0IsR0FBR2xDLEtBQUssQ0FBQzJCLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFFOUQsT0FBTyxTQUFBUSxpQkFBQUMsRUFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUEwQjtJQUFBdEIsUUFBQTtJQUFBYSxZQUFBO0lBQUFDO0VBQUEsSUFBQU0sRUFJekI7RUFFTixNQUFBRyxrQkFBQSxHQUEyQnRDLFVBQVUsQ0FBQ2lDLGtCQUFrQixDQUFDO0VBQ3pELElBQUlLLGtCQUFrQjtJQUNwQixNQUFNLElBQUlDLEtBQUssQ0FDYixvRUFDRixDQUFDO0VBQUE7RUFDRixJQUFBQyxFQUFBO0VBQUEsSUFBQUosQ0FBQSxRQUFBUixZQUFBLElBQUFRLENBQUEsUUFBQVAsZ0JBQUE7SUFLd0JXLEVBQUEsR0FBQUEsQ0FBQSxLQUN2QjVCLFdBQVcsQ0FDVGdCLFlBQW9DLElBQXBCUixrQkFBa0IsQ0FBQyxDQUFDLEVBQ3BDUyxnQkFDRixDQUFDO0lBQUFPLENBQUEsTUFBQVIsWUFBQTtJQUFBUSxDQUFBLE1BQUFQLGdCQUFBO0lBQUFPLENBQUEsTUFBQUksRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQUosQ0FBQTtFQUFBO0VBSkgsT0FBQUssS0FBQSxJQUFnQnRDLFFBQVEsQ0FBQ3FDLEVBS3pCLENBQUM7RUFBQSxJQUFBRSxFQUFBO0VBQUEsSUFBQU4sQ0FBQSxRQUFBSyxLQUFBO0lBT1NDLEVBQUEsR0FBQUEsQ0FBQTtNQUNSO1FBQUFDO01BQUEsSUFBa0NGLEtBQUssQ0FBQUcsUUFBUyxDQUFDLENBQUM7TUFDbEQsSUFDRUQscUJBQXFCLENBQUFFLGdDQUNZLElBQWpDcEMsK0JBQStCLENBQUMsQ0FBQztRQUVqQ0YsZUFBZSxDQUNiLGtGQUNGLENBQUM7UUFDRGtDLEtBQUssQ0FBQUssUUFBUyxDQUFDQyxLQUtiLENBQUM7TUFBQTtJQUNKLENBRUY7SUFBQVgsQ0FBQSxNQUFBSyxLQUFBO0lBQUFMLENBQUEsTUFBQU0sRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQU4sQ0FBQTtFQUFBO0VBQUEsSUFBQVksRUFBQTtFQUFBLElBQUFaLENBQUEsUUFBQWEsTUFBQSxDQUFBQyxHQUFBO0lBQUVGLEVBQUEsS0FBRTtJQUFBWixDQUFBLE1BQUFZLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFaLENBQUE7RUFBQTtFQWpCTG5DLFNBQVMsQ0FBQ3lDLEVBaUJULEVBQUVNLEVBQUUsQ0FBQztFQUFBLElBQUFHLEVBQUE7RUFBQSxJQUFBZixDQUFBLFFBQUFLLEtBQUEsQ0FBQUssUUFBQTtJQUtrQ0ssRUFBQSxHQUFBQyxNQUFBLElBQ3RDMUMsbUJBQW1CLENBQUMwQyxNQUFNLEVBQUVYLEtBQUssQ0FBQUssUUFBUyxDQUFDO0lBQUFWLENBQUEsTUFBQUssS0FBQSxDQUFBSyxRQUFBO0lBQUFWLENBQUEsTUFBQWUsRUFBQTtFQUFBO0lBQUFBLEVBQUEsR0FBQWYsQ0FBQTtFQUFBO0VBRDdDLE1BQUFpQixnQkFBQSxHQUF5Qm5ELGNBQWMsQ0FBQ2lELEVBRXhDLENBQUM7RUFDRDdDLGlCQUFpQixDQUFDK0MsZ0JBQWdCLENBQUM7RUFBQSxJQUFBQyxFQUFBO0VBQUEsSUFBQWxCLENBQUEsUUFBQXJCLFFBQUE7SUFLN0J1QyxFQUFBLElBQUMsZUFBZSxDQUNkLENBQUMsYUFBYSxDQUFFdkMsU0FBTyxDQUFFLEVBQXhCLGFBQWEsQ0FDaEIsRUFGQyxlQUFlLENBRUU7SUFBQXFCLENBQUEsTUFBQXJCLFFBQUE7SUFBQXFCLENBQUEsTUFBQWtCLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFsQixDQUFBO0VBQUE7RUFBQSxJQUFBbUIsRUFBQTtFQUFBLElBQUFuQixDQUFBLFNBQUFLLEtBQUEsSUFBQUwsQ0FBQSxTQUFBa0IsRUFBQTtJQUp0QkMsRUFBQSxnQ0FBb0MsS0FBSSxDQUFKLEtBQUcsQ0FBQyxDQUN0QywwQkFBaUNkLEtBQUssQ0FBTEEsTUFBSSxDQUFDLENBQ3BDLENBQUFhLEVBRWlCLENBQ25CLDJCQUNGLDhCQUE4QjtJQUFBbEIsQ0FBQSxPQUFBSyxLQUFBO0lBQUFMLENBQUEsT0FBQWtCLEVBQUE7SUFBQWxCLENBQUEsT0FBQW1CLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFuQixDQUFBO0VBQUE7RUFBQSxPQU45Qm1CLEVBTThCO0FBQUE7QUE5RDNCLFNBQUFSLE1BQUFTLElBQUE7RUFBQSxPQXFDdUI7SUFBQSxHQUNuQkEsSUFBSTtJQUFBYixxQkFBQSxFQUNnQm5DLHNDQUFzQyxDQUMzRGdELElBQUksQ0FBQWIscUJBQ047RUFDRixDQUFDO0FBQUE7QUF3QlAsU0FBU2MsV0FBV0EsQ0FBQSxDQUFFLEVBQUV0QyxhQUFhLENBQUM7RUFDcEM7RUFDQSxNQUFNc0IsS0FBSyxHQUFHekMsVUFBVSxDQUFDeUIsZUFBZSxDQUFDO0VBQ3pDLElBQUksQ0FBQ2dCLEtBQUssRUFBRTtJQUNWLE1BQU0sSUFBSWlCLGNBQWMsQ0FDdEIsZ0ZBQ0YsQ0FBQztFQUNIO0VBQ0EsT0FBT2pCLEtBQUs7QUFDZDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU8sU0FBQWtCLFlBQUFDLFFBQUE7RUFBQSxNQUFBeEIsQ0FBQSxHQUFBQyxFQUFBO0VBQ0wsTUFBQUksS0FBQSxHQUFjZ0IsV0FBVyxDQUFDLENBQUM7RUFBQSxJQUFBdEIsRUFBQTtFQUFBLElBQUFDLENBQUEsUUFBQXdCLFFBQUEsSUFBQXhCLENBQUEsUUFBQUssS0FBQTtJQUVmTixFQUFBLEdBQUFBLENBQUE7TUFDVixNQUFBMEIsS0FBQSxHQUFjcEIsS0FBSyxDQUFBRyxRQUFTLENBQUMsQ0FBQztNQUM5QixNQUFBa0IsUUFBQSxHQUFpQkYsUUFBUSxDQUFDQyxLQUFLLENBQUM7TUFFaEMsSUFBSSxLQUEwQyxJQUFsQkEsS0FBSyxLQUFLQyxRQUFRO1FBQzVDLE1BQU0sSUFBSXZCLEtBQUssQ0FDYixrQ0FBa0NxQixRQUFRLENBQUFHLFFBQVMsQ0FBQyxDQUFDLG9IQUN2RCxDQUFDO01BQUE7TUFDRixPQUVNRCxRQUFRO0lBQUEsQ0FDaEI7SUFBQTFCLENBQUEsTUFBQXdCLFFBQUE7SUFBQXhCLENBQUEsTUFBQUssS0FBQTtJQUFBTCxDQUFBLE1BQUFELEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFDLENBQUE7RUFBQTtFQVhELE1BQUE0QixHQUFBLEdBQVk3QixFQVdYO0VBQUEsT0FFTS9CLG9CQUFvQixDQUFDcUMsS0FBSyxDQUFBd0IsU0FBVSxFQUFFRCxHQUFHLEVBQUVBLEdBQUcsQ0FBQztBQUFBOztBQUd4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFBRSxlQUFBO0VBQUEsT0FHRVQsV0FBVyxDQUFDLENBQUMsQ0FBQVgsUUFBUztBQUFBOztBQUcvQjtBQUNBO0FBQ0E7QUFDQSxPQUFPLFNBQUFxQixpQkFBQTtFQUFBLE9BQ0VWLFdBQVcsQ0FBQyxDQUFDO0FBQUE7QUFHdEIsTUFBTVcsY0FBYyxHQUFHQSxDQUFBLEtBQU0sTUFBTSxDQUFDLENBQUM7O0FBRXJDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFBQyxrQ0FBQVQsUUFBQTtFQUFBLE1BQUF4QixDQUFBLEdBQUFDLEVBQUE7RUFHTCxNQUFBSSxLQUFBLEdBQWN6QyxVQUFVLENBQUN5QixlQUFlLENBQUM7RUFBQSxJQUFBVSxFQUFBO0VBQUEsSUFBQUMsQ0FBQSxRQUFBd0IsUUFBQSxJQUFBeEIsQ0FBQSxRQUFBSyxLQUFBO0lBQzZCTixFQUFBLEdBQUFBLENBQUEsS0FDcEVNLEtBQUssR0FBR21CLFFBQVEsQ0FBQ25CLEtBQUssQ0FBQUcsUUFBUyxDQUFDLENBQWEsQ0FBQyxHQUE5QzBCLFNBQThDO0lBQUFsQyxDQUFBLE1BQUF3QixRQUFBO0lBQUF4QixDQUFBLE1BQUFLLEtBQUE7SUFBQUwsQ0FBQSxNQUFBRCxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBQyxDQUFBO0VBQUE7RUFBQSxPQUR6Q2hDLG9CQUFvQixDQUFDcUMsS0FBSyxHQUFHQSxLQUFLLENBQUF3QixTQUEyQixHQUF4Q0csY0FBd0MsRUFBRWpDLEVBRXRFLENBQUM7QUFBQSIsImlnbm9yZUxpc3QiOltdfQ==Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/coordinator/* Status: Completed
src\coordinator\coordinatorMode.ts
Tool Call: Read src\hooks\useCanUseTool.tsx Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→import { feature } from 'bun:bundle';
3→import { APIUserAbortError } from '@anthropic-ai/sdk';
4→import * as React from 'react';
5→import { useCallback } from 'react';
6→import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from 'src/services/analytics/index.js';
7→import { sanitizeToolNameForAnalytics } from 'src/services/analytics/metadata.js';
8→import type { ToolUseConfirm } from '../components/permissions/PermissionRequest.js';
9→import { Text } from '../ink.js';
10→import type { ToolPermissionContext, Tool as ToolType, ToolUseContext } from '../Tool.js';
11→import { consumeSpeculativeClassifierCheck, peekSpeculativeClassifierCheck } from '../tools/BashTool/bashPermissions.js';
12→import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js';
13→import type { AssistantMessage } from '../types/message.js';
14→import { recordAutoModeDenial } from '../utils/autoModeDenials.js';
15→import { clearClassifierChecking, setClassifierApproval, setYoloClassifierApproval } from '../utils/classifierApprovals.js';
16→import { logForDebugging } from '../utils/debug.js';
17→import { AbortError } from '../utils/errors.js';
18→import { logError } from '../utils/log.js';
19→import type { PermissionDecision } from '../utils/permissions/PermissionResult.js';
20→import { hasPermissionsToUseTool } from '../utils/permissions/permissions.js';
21→import { jsonStringify } from '../utils/slowOperations.js';
22→import { handleCoordinatorPermission } from './toolPermission/handlers/coordinatorHandler.js';
23→import { handleInteractivePermission } from './toolPermission/handlers/interactiveHandler.js';
24→import { handleSwarmWorkerPermission } from './toolPermission/handlers/swarmWorkerHandler.js';
25→import { createPermissionContext, createPermissionQueueOps } from './toolPermission/PermissionContext.js';
26→import { logPermissionDecision } from './toolPermission/permissionLogging.js';
27→export type CanUseToolFn<Input extends Record<string, unknown> = Record<string, unknown>> = (tool: ToolType, input: Input, toolUseContext: ToolUseContext, assistantMessage: AssistantMessage, toolUseID: string, forceDecision?: PermissionDecision<Input>) => Promise<PermissionDecision<Input>>;
28→function useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext) {
29→ const $ = _c(3);
30→ let t0;
31→ if ($[0] !== setToolPermissionContext || $[1] !== setToolUseConfirmQueue) {
32→ t0 = async (tool, input, toolUseContext, assistantMessage, toolUseID, forceDecision) => new Promise(resolve => {
33→ const ctx = createPermissionContext(tool, input, toolUseContext, assistantMessage, toolUseID, setToolPermissionContext, createPermissionQueueOps(setToolUseConfirmQueue));
34→ if (ctx.resolveIfAborted(resolve)) {
35→ return;
36→ }
37→ const decisionPromise = forceDecision !== undefined ? Promise.resolve(forceDecision) : hasPermissionsToUseTool(tool, input, toolUseContext, assistantMessage, toolUseID);
38→ return decisionPromise.then(async result => {
39→ if (result.behavior === "allow") {
40→ if (ctx.resolveIfAborted(resolve)) {
41→ return;
42→ }
43→ if (feature("TRANSCRIPT_CLASSIFIER") && result.decisionReason?.type === "classifier" && result.decisionReason.classifier === "auto-mode") {
44→ setYoloClassifierApproval(toolUseID, result.decisionReason.reason);
45→ }
46→ ctx.logDecision({
47→ decision: "accept",
48→ source: "config"
49→ });
50→ resolve(ctx.buildAllow(result.updatedInput ?? input, {
51→ decisionReason: result.decisionReason
52→ }));
53→ return;
54→ }
55→ const appState = toolUseContext.getAppState();
56→ const description = await tool.description(input as never, {
57→ isNonInteractiveSession: toolUseContext.options.isNonInteractiveSession,
58→ toolPermissionContext: appState.toolPermissionContext,
59→ tools: toolUseContext.options.tools
60→ });
61→ if (ctx.resolveIfAborted(resolve)) {
62→ return;
63→ }
64→ switch (result.behavior) {
65→ case "deny":
66→ {
67→ logPermissionDecision({
68→ tool,
69→ input,
70→ toolUseContext,
71→ messageId: ctx.messageId,
72→ toolUseID
73→ }, {
74→ decision: "reject",
75→ source: "config"
76→ });
77→ if (feature("TRANSCRIPT_CLASSIFIER") && result.decisionReason?.type === "classifier" && result.decisionReason.classifier === "auto-mode") {
78→ recordAutoModeDenial({
79→ toolName: tool.name,
80→ display: description,
81→ reason: result.decisionReason.reason ?? "",
82→ timestamp: Date.now()
83→ });
84→ toolUseContext.addNotification?.({
85→ key: "auto-mode-denied",
86→ priority: "immediate",
87→ jsx: <><Text color="error">{tool.userFacingName(input).toLowerCase()} denied by auto mode</Text><Text dimColor={true}> · /permissions</Text></>
88→ });
89→ }
90→ resolve(result);
91→ return;
92→ }
93→ case "ask":
94→ {
95→ if (appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog) {
96→ const coordinatorDecision = await handleCoordinatorPermission({
97→ ctx,
98→ ...(feature("BASH_CLASSIFIER") ? {
99→ pendingClassifierCheck: result.pendingClassifierCheck
100→ } : {}),
101→ updatedInput: result.updatedInput,
102→ suggestions: result.suggestions,
103→ permissionMode: appState.toolPermissionContext.mode
104→ });
105→ if (coordinatorDecision) {
106→ resolve(coordinatorDecision);
107→ return;
108→ }
109→ }
110→ if (ctx.resolveIfAborted(resolve)) {
111→ return;
112→ }
113→ const swarmDecision = await handleSwarmWorkerPermission({
114→ ctx,
115→ description,
116→ ...(feature("BASH_CLASSIFIER") ? {
117→ pendingClassifierCheck: result.pendingClassifierCheck
118→ } : {}),
119→ updatedInput: result.updatedInput,
120→ suggestions: result.suggestions
121→ });
122→ if (swarmDecision) {
123→ resolve(swarmDecision);
124→ return;
125→ }
126→ if (feature("BASH_CLASSIFIER") && result.pendingClassifierCheck && tool.name === BASH_TOOL_NAME && !appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog) {
127→ const speculativePromise = peekSpeculativeClassifierCheck((input as {
128→ command: string;
129→ }).command);
130→ if (speculativePromise) {
131→ const raceResult = await Promise.race([speculativePromise.then(_temp), new Promise(_temp2)]);
132→ if (ctx.resolveIfAborted(resolve)) {
133→ return;
134→ }
135→ if (raceResult.type === "result" && raceResult.result.matches && raceResult.result.confidence === "high" && feature("BASH_CLASSIFIER")) {
136→ consumeSpeculativeClassifierCheck((input as {
137→ command: string;
138→ }).command);
139→ const matchedRule = raceResult.result.matchedDescription ?? undefined;
140→ if (matchedRule) {
141→ setClassifierApproval(toolUseID, matchedRule);
142→ }
143→ ctx.logDecision({
144→ decision: "accept",
145→ source: {
146→ type: "classifier"
147→ }
148→ });
149→ resolve(ctx.buildAllow(result.updatedInput ?? input as Record<string, unknown>, {
150→ decisionReason: {
151→ type: "classifier" as const,
152→ classifier: "bash_allow" as const,
153→ reason: `Allowed by prompt rule: "${raceResult.result.matchedDescription}"`
154→ }
155→ }));
156→ return;
157→ }
158→ }
159→ }
160→ handleInteractivePermission({
161→ ctx,
162→ description,
163→ result,
164→ awaitAutomatedChecksBeforeDialog: appState.toolPermissionContext.awaitAutomatedChecksBeforeDialog,
165→ bridgeCallbacks: feature("BRIDGE_MODE") ? appState.replBridgePermissionCallbacks : undefined,
166→ channelCallbacks: feature("KAIROS") || feature("KAIROS_CHANNELS") ? appState.channelPermissionCallbacks : undefined
167→ }, resolve);
168→ return;
169→ }
170→ }
171→ }).catch(error => {
172→ if (error instanceof AbortError || error instanceof APIUserAbortError) {
173→ logForDebugging(`Permission check threw ${error.constructor.name} for tool=${tool.name}: ${error.message}`);
174→ ctx.logCancelled();
175→ resolve(ctx.cancelAndAbort(undefined, true));
176→ } else {
177→ logError(error);
178→ resolve(ctx.cancelAndAbort(undefined, true));
179→ }
180→ }).finally(() => {
181→ clearClassifierChecking(toolUseID);
182→ });
183→ });
184→ $[0] = setToolPermissionContext;
185→ $[1] = setToolUseConfirmQueue;
186→ $[2] = t0;
187→ } else {
188→ t0 = $[2];
189→ }
190→ return t0;
191→}
192→function _temp2(res) {
193→ return setTimeout(res, 2000, {
194→ type: "timeout" as const
195→ });
196→}
197→function _temp(r) {
198→ return {
199→ type: "result" as const,
200→ result: r
201→ };
202→}
203→export default useCanUseTool;
204→//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmZWF0dXJlIiwiQVBJVXNlckFib3J0RXJyb3IiLCJSZWFjdCIsInVzZUNhbGxiYWNrIiwiQW5hbHl0aWNzTWV0YWRhdGFfSV9WRVJJRklFRF9USElTX0lTX05PVF9DT0RFX09SX0ZJTEVQQVRIUyIsImxvZ0V2ZW50Iiwic2FuaXRpemVUb29sTmFtZUZvckFuYWx5dGljcyIsIlRvb2xVc2VDb25maXJtIiwiVGV4dCIsIlRvb2xQZXJtaXNzaW9uQ29udGV4dCIsIlRvb2wiLCJUb29sVHlwZSIsIlRvb2xVc2VDb250ZXh0IiwiY29uc3VtZVNwZWN1bGF0aXZlQ2xhc3NpZmllckNoZWNrIiwicGVla1NwZWN1bGF0aXZlQ2xhc3NpZmllckNoZWNrIiwiQkFTSF9UT09MX05BTUUiLCJBc3Npc3RhbnRNZXNzYWdlIiwicmVjb3JkQXV0b01vZGVEZW5pYWwiLCJjbGVhckNsYXNzaWZpZXJDaGVja2luZyIsInNldENsYXNzaWZpZXJBcHByb3ZhbCIsInNldFlvbG9DbGFzc2lmaWVyQXBwcm92YWwiLCJsb2dGb3JEZWJ1Z2dpbmciLCJBYm9ydEVycm9yIiwibG9nRXJyb3IiLCJQZXJtaXNzaW9uRGVjaXNpb24iLCJoYXNQZXJtaXNzaW9uc1RvVXNlVG9vbCIsImpzb25TdHJpbmdpZnkiLCJoYW5kbGVDb29yZGluYXRvclBlcm1pc3Npb24iLCJoYW5kbGVJbnRlcmFjdGl2ZVBlcm1pc3Npb24iLCJoYW5kbGVTd2FybVdvcmtlclBlcm1pc3Npb24iLCJjcmVhdGVQZXJtaXNzaW9uQ29udGV4dCIsImNyZWF0ZVBlcm1pc3Npb25RdWV1ZU9wcyIsImxvZ1Blcm1pc3Npb25EZWNpc2lvbiIsIkNhblVzZVRvb2xGbiIsIlJlY29yZCIsInRvb2wiLCJpbnB1dCIsIklucHV0IiwidG9vbFVzZUNvbnRleHQiLCJhc3Npc3RhbnRNZXNzYWdlIiwidG9vbFVzZUlEIiwiZm9yY2VEZWNpc2lvbiIsIlByb21pc2UiLCJ1c2VDYW5Vc2VUb29sIiwic2V0VG9vbFVzZUNvbmZpcm1RdWV1ZSIsInNldFRvb2xQZXJtaXNzaW9uQ29udGV4dCIsIiQiLCJfYyIsInQwIiwicmVzb2x2ZSIsImN0eCIsInJlc29sdmVJZkFib3J0ZWQiLCJkZWNpc2lvblByb21pc2UiLCJ1bmRlZmluZWQiLCJ0aGVuIiwicmVzdWx0IiwiYmVoYXZpb3IiLCJkZWNpc2lvblJlYXNvbiIsInR5cGUiLCJjbGFzc2lmaWVyIiwicmVhc29uIiwibG9nRGVjaXNpb24iLCJkZWNpc2lvbiIsInNvdXJjZSIsImJ1aWxkQWxsb3ciLCJ1cGRhdGVkSW5wdXQiLCJhcHBTdGF0ZSIsImdldEFwcFN0YXRlIiwiZGVzY3JpcHRpb24iLCJpc05vbkludGVyYWN0aXZlU2Vzc2lvbiIsIm9wdGlvbnMiLCJ0b29sUGVybWlzc2lvbkNvbnRleHQiLCJ0b29scyIsIm1lc3NhZ2VJZCIsInRvb2xOYW1lIiwibmFtZSIsImRpc3BsYXkiLCJ0aW1lc3RhbXAiLCJEYXRlIiwibm93IiwiYWRkTm90aWZpY2F0aW9uIiwia2V5IiwicHJpb3JpdHkiLCJqc3giLCJ1c2VyRmFjaW5nTmFtZSIsInRvTG93ZXJDYXNlIiwiYXdhaXRBdXRvbWF0ZWRDaGVja3NCZWZvcmVEaWFsb2ciLCJjb29yZGluYXRvckRlY2lzaW9uIiwicGVuZGluZ0NsYXNzaWZpZXJDaGVjayIsInN1Z2dlc3Rpb25zIiwicGVybWlzc2lvbk1vZGUiLCJtb2RlIiwic3dhcm1EZWNpc2lvbiIsInNwZWN1bGF0aXZlUHJvbWlzZSIsImNvbW1hbmQiLCJyYWNlUmVzdWx0IiwicmFjZSIsIl90ZW1wIiwiX3RlbXAyIiwibWF0Y2hlcyIsImNvbmZpZGVuY2UiLCJtYXRjaGVkUnVsZSIsIm1hdGNoZWREZXNjcmlwdGlvbiIsImNvbnN0IiwiYnJpZGdlQ2FsbGJhY2tzIiwicmVwbEJyaWRnZVBlcm1pc3Npb25DYWxsYmFja3MiLCJjaGFubmVsQ2FsbGJhY2tzIiwiY2hhbm5lbFBlcm1pc3Npb25DYWxsYmFja3MiLCJjYXRjaCIsImVycm9yIiwiY29uc3RydWN0b3IiLCJtZXNzYWdlIiwibG9nQ2FuY2VsbGVkIiwiY2FuY2VsQW5kQWJvcnQiLCJmaW5hbGx5IiwicmVzIiwic2V0VGltZW91dCIsInIiXSwic291cmNlcyI6WyJ1c2VDYW5Vc2VUb29sLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmZWF0dXJlIH0gZnJvbSAnYnVuOmJ1bmRsZSdcbmltcG9ydCB7IEFQSVVzZXJBYm9ydEVycm9yIH0gZnJvbSAnQGFudGhyb3BpYy1haS9zZGsnXG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IHVzZUNhbGxiYWNrIH0gZnJvbSAncmVhY3QnXG5pbXBvcnQge1xuICB0eXBlIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gIGxvZ0V2ZW50LFxufSBmcm9tICdzcmMvc2VydmljZXMvYW5hbHl0aWNzL2luZGV4LmpzJ1xuaW1wb3J0IHsgc2FuaXRpemVUb29sTmFtZUZvckFuYWx5dGljcyB9IGZyb20gJ3NyYy9zZXJ2aWNlcy9hbmFseXRpY3MvbWV0YWRhdGEuanMnXG5pbXBvcnQgdHlwZSB7IFRvb2xVc2VDb25maXJtIH0gZnJvbSAnLi4vY29tcG9uZW50cy9wZXJtaXNzaW9ucy9QZXJtaXNzaW9uUmVxdWVzdC5qcydcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5pbXBvcnQgdHlwZSB7XG4gIFRvb2xQZXJtaXNzaW9uQ29udGV4dCxcbiAgVG9vbCBhcyBUb29sVHlwZSxcbiAgVG9vbFVzZUNvbnRleHQsXG59IGZyb20gJy4uL1Rvb2wuanMnXG5pbXBvcnQge1xuICBjb25zdW1lU3BlY3VsYXRpdmVDbGFzc2lmaWVyQ2hlY2ssXG4gIHBlZWtTcGVjdWxhdGl2ZUNsYXNzaWZpZXJDaGVjayxcbn0gZnJvbSAnLi4vdG9vbHMvQmFzaFRvb2wvYmFzaFBlcm1pc3Npb25zLmpzJ1xuaW1wb3J0IHsgQkFTSF9UT09MX05BTUUgfSBmcm9tICcuLi90b29scy9CYXNoVG9vbC90b29sTmFtZS5qcydcbmltcG9ydCB0eXBlIHsgQXNzaXN0YW50TWVzc2FnZSB9IGZyb20gJy4uL3R5cGVzL21lc3NhZ2UuanMnXG5pbXBvcnQgeyByZWNvcmRBdXRvTW9kZURlbmlhbCB9IGZyb20gJy4uL3V0aWxzL2F1dG9Nb2RlRGVuaWFscy5qcydcbmltcG9ydCB7XG4gIGNsZWFyQ2xhc3NpZmllckNoZWNraW5nLFxuICBzZXRDbGFzc2lmaWVyQXBwcm92YWwsXG4gIHNldFlvbG9DbGFzc2lmaWVyQXBwcm92YWwsXG59IGZyb20gJy4uL3V0aWxzL2NsYXNzaWZpZXJBcHByb3ZhbHMuanMnXG5pbXBvcnQgeyBsb2dGb3JEZWJ1Z2dpbmcgfSBmcm9tICcuLi91dGlscy9kZWJ1Zy5qcydcbmltcG9ydCB7IEFib3J0RXJyb3IgfSBmcm9tICcuLi91dGlscy9lcnJvcnMuanMnXG5pbXBvcnQgeyBsb2dFcnJvciB9IGZyb20gJy4uL3V0aWxzL2xvZy5qcydcbmltcG9ydCB0eXBlIHsgUGVybWlzc2lvbkRlY2lzaW9uIH0gZnJvbSAnLi4vdXRpbHMvcGVybWlzc2lvbnMvUGVybWlzc2lvblJlc3VsdC5qcydcbmltcG9ydCB7IGhhc1Blcm1pc3Npb25zVG9Vc2VUb29sIH0gZnJvbSAnLi4vdXRpbHMvcGVybWlzc2lvbnMvcGVybWlzc2lvbnMuanMnXG5pbXBvcnQgeyBqc29uU3RyaW5naWZ5IH0gZnJvbSAnLi4vdXRpbHMvc2xvd09wZXJhdGlvbnMuanMnXG5pbXBvcnQgeyBoYW5kbGVDb29yZGluYXRvclBlcm1pc3Npb24gfSBmcm9tICcuL3Rvb2xQZXJtaXNzaW9uL2hhbmRsZXJzL2Nvb3JkaW5hdG9ySGFuZGxlci5qcydcbmltcG9ydCB7IGhhbmRsZUludGVyYWN0aXZlUGVybWlzc2lvbiB9IGZyb20gJy4vdG9vbFBlcm1pc3Npb24vaGFuZGxlcnMvaW50ZXJhY3RpdmVIYW5kbGVyLmpzJ1xuaW1wb3J0IHsgaGFuZGxlU3dhcm1Xb3JrZXJQZXJtaXNzaW9uIH0gZnJvbSAnLi90b29sUGVybWlzc2lvbi9oYW5kbGVycy9zd2FybVdvcmtlckhhbmRsZXIuanMnXG5pbXBvcnQge1xuICBjcmVhdGVQZXJtaXNzaW9uQ29udGV4dCxcbiAgY3JlYXRlUGVybWlzc2lvblF1ZXVlT3BzLFxufSBmcm9tICcuL3Rvb2xQZXJtaXNzaW9uL1Blcm1pc3Npb25Db250ZXh0LmpzJ1xuaW1wb3J0IHsgbG9nUGVybWlzc2lvbkRlY2lzaW9uIH0gZnJvbSAnLi90b29sUGVybWlzc2lvbi9wZXJtaXNzaW9uTG9nZ2luZy5qcydcblxuZXhwb3J0IHR5cGUgQ2FuVXNlVG9vbEZuPFxuICBJbnB1dCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0gUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4+ID0gKFxuICB0b29sOiBUb29sVHlwZSxcbiAgaW5wdXQ6IElucHV0LFxuICB0b29sVXNlQ29udGV4dDogVG9vbFVzZUNvbnRleHQsXG4gIGFzc2lzdGFudE1lc3NhZ2U6IEFzc2lzdGFudE1lc3NhZ2UsXG4gIHRvb2xVc2VJRDogc3RyaW5nLFxuICBmb3JjZURlY2lzaW9uPzogUGVybWlzc2lvbkRlY2lzaW9uPElucHV0PixcbikgPT4gUHJvbWlzZTxQZXJtaXNzaW9uRGVjaXNpb248SW5wdXQ+PlxuXG5mdW5jdGlvbiB1c2VDYW5Vc2VUb29sKFxuICBzZXRUb29sVXNlQ29uZmlybVF1ZXVlOiBSZWFjdC5EaXNwYXRjaDxcbiAgICBSZWFjdC5TZXRTdGF0ZUFjdGlvbjxUb29sVXNlQ29uZmlybVtdPlxuICA+LFxuICBzZXRUb29sUGVybWlzc2lvbkNvbnRleHQ6IChjb250ZXh0OiBUb29sUGVybWlzc2lvbkNvbnRleHQpID0+IHZvaWQsXG4pOiBDYW5Vc2VUb29sRm4ge1xuICByZXR1cm4gdXNlQ2FsbGJhY2s8Q2FuVXNlVG9vbEZuPihcbiAgICBhc3luYyAoXG4gICAgICB0b29sLFxuICAgICAgaW5wdXQsXG4gICAgICB0b29sVXNlQ29udGV4dCxcbiAgICAgIGFzc2lzdGFudE1lc3NhZ2UsXG4gICAgICB0b29sVXNlSUQsXG4gICAgICBmb3JjZURlY2lzaW9uLFxuICAgICkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgICBjb25zdCBjdHggPSBjcmVhdGVQZXJtaXNzaW9uQ29udGV4dChcbiAgICAgICAgICB0b29sLFxuICAgICAgICAgIGlucHV0LFxuICAgICAgICAgIHRvb2xVc2VDb250ZXh0LFxuICAgICAgICAgIGFzc2lzdGFudE1lc3NhZ2UsXG4gICAgICAgICAgdG9vbFVzZUlELFxuICAgICAgICAgIHNldFRvb2xQZXJtaXNzaW9uQ29udGV4dCxcbiAgICAgICAgICBjcmVhdGVQZXJtaXNzaW9uUXVldWVPcHMoc2V0VG9vbFVzZUNvbmZpcm1RdWV1ZSksXG4gICAgICAgIClcblxuICAgICAgICBpZiAoY3R4LnJlc29sdmVJZkFib3J0ZWQocmVzb2x2ZSkpIHJldHVyblxuXG4gICAgICAgIGNvbnN0IGRlY2lzaW9uUHJvbWlzZSA9XG4gICAgICAgICAgZm9yY2VEZWNpc2lvbiAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgICA/IFByb21pc2UucmVzb2x2ZShmb3JjZURlY2lzaW9uKVxuICAgICAgICAgICAgOiBoYXNQZXJtaXNzaW9uc1RvVXNlVG9vbChcbiAgICAgICAgICAgICAgICB0b29sLFxuICAgICAgICAgICAgICAgIGlucHV0LFxuICAgICAgICAgICAgICAgIHRvb2xVc2VDb250ZXh0LFxuICAgICAgICAgICAgICAgIGFzc2lzdGFudE1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgdG9vbFVzZUlELFxuICAgICAgICAgICAgICApXG5cbiAgICAgICAgcmV0dXJuIGRlY2lzaW9uUHJvbWlzZVxuICAgICAgICAgIC50aGVuKGFzeW5jIHJlc3VsdCA9PiB7XG4gICAgICAgICAgICAvLyBbQU5ULU9OTFldIExvZyBhbGwgdG9vbCBwZXJtaXNzaW9uIGRlY2lzaW9ucyB3aXRoIHRvb2wgbmFtZSBhbmQgYXJnc1xuICAgICAgICAgICAgaWYgKFwiZXh0ZXJuYWxcIiA9PT0gJ2FudCcpIHtcbiAgICAgICAgICAgICAgbG9nRXZlbnQoJ3Rlbmd1X2ludGVybmFsX3Rvb2xfcGVybWlzc2lvbl9kZWNpc2lvbicsIHtcbiAgICAgICAgICAgICAgICB0b29sTmFtZTogc2FuaXRpemVUb29sTmFtZUZvckFuYWx5dGljcyh0b29sLm5hbWUpLFxuICAgICAgICAgICAgICAgIGJlaGF2aW9yOlxuICAgICAgICAgICAgICAgICAgcmVzdWx0LmJlaGF2aW9yIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICAgICAgICAgICAgLy8gTm90ZTogaW5wdXQgY29udGFpbnMgY29kZS9maWxlcGF0aHMsIG9ubHkgbG9nIGZvciBhbnRzXG4gICAgICAgICAgICAgICAgaW5wdXQ6IGpzb25TdHJpbmdpZnkoXG4gICAgICAgICAgICAgICAgICBpbnB1dCxcbiAgICAgICAgICAgICAgICApIGFzIEFuYWx5dGljc01ldGFkYXRhX0lfVkVSSUZJRURfVEhJU19JU19OT1RfQ09ERV9PUl9GSUxFUEFUSFMsXG4gICAgICAgICAgICAgICAgbWVzc2FnZUlEOlxuICAgICAgICAgICAgICAgICAgY3R4Lm1lc3NhZ2VJZCBhcyBBbmFseXRpY3NNZXRhZGF0YV9JX1ZFUklGSUVEX1RISVNfSVNfTk9UX0NPREVfT1JfRklMRVBBVEhTLFxuICAgICAgICAgICAgICAgIGlzTWNwOiB0b29sLmlzTWNwID8/IGZhbHNlLFxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBIYXMgcGVybWlzc2lvbnMgdG8gdXNlIHRvb2wsIGdyYW50ZWQgaW4gY29uZmlnXG4gICAgICAgICAgICBpZiAocmVzdWx0LmJlaGF2aW9yID09PSAnYWxsb3cnKSB7XG4gICAgICAgICAgICAgIGlmIChjdHgucmVzb2x2ZUlmQWJvcnRlZChyZXNvbHZlKSkgcmV0dXJuXG4gICAgICAgICAgICAgIC8vIFRyYWNrIGF1dG8gbW9kZSBjbGFzc2lmaWVyIGFwcHJvdmFscyBmb3IgVUkgZGlzcGxheVxuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgZmVhdHVyZSgnVFJBTlNDUklQVF9DTEFTU0lGSUVSJykgJiZcbiAgICAgICAgICAgICAgICByZXN1bHQuZGVjaXNpb25SZWFzb24/LnR5cGUgPT09ICdjbGFzc2lmaWVyJyAmJlxuICAgICAgICAgICAgICAgIHJlc3VsdC5kZWNpc2lvblJlYXNvbi5jbGFzc2lmaWVyID09PSAnYXV0by1tb2RlJ1xuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICBzZXRZb2xvQ2xhc3NpZmllckFwcHJvdmFsKFxuICAgICAgICAgICAgICAgICAgdG9vbFVzZUlELFxuICAgICAgICAgICAgICAgICAgcmVzdWx0LmRlY2lzaW9uUmVhc29uLnJlYXNvbixcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBjdHgubG9nRGVjaXNpb24oeyBkZWNpc2lvbjogJ2FjY2VwdCcsIHNvdXJjZTogJ2NvbmZpZycgfSlcblxuICAgICAgICAgICAgICByZXNvbHZlKFxuICAgICAgICAgICAgICAgIGN0eC5idWlsZEFsbG93KHJlc3VsdC51cGRhdGVkSW5wdXQgPz8gaW5wdXQsIHtcbiAgICAgICAgICAgICAgICAgIGRlY2lzaW9uUmVhc29uOiByZXN1bHQuZGVjaXNpb25SZWFzb24sXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IGFwcFN0YXRlID0gdG9vbFVzZUNvbnRleHQuZ2V0QXBwU3RhdGUoKVxuICAgICAgICAgICAgY29uc3QgZGVzY3JpcHRpb24gPSBhd2FpdCB0b29sLmRlc2NyaXB0aW9uKGlucHV0IGFzIG5ldmVyLCB7XG4gICAgICAgICAgICAgIGlzTm9uSW50ZXJhY3RpdmVTZXNzaW9uOlxuICAgICAgICAgICAgICAgIHRvb2xVc2VDb250ZXh0Lm9wdGlvbnMuaXNOb25JbnRlcmFjdGl2ZVNlc3Npb24sXG4gICAgICAgICAgICAgIHRvb2xQZXJtaXNzaW9uQ29udGV4dDogYXBwU3RhdGUudG9vbFBlcm1pc3Npb25Db250ZXh0LFxuICAgICAgICAgICAgICB0b29sczogdG9vbFVzZUNvbnRleHQub3B0aW9ucy50b29scyxcbiAgICAgICAgICAgIH0pXG5cbiAgICAgICAgICAgIGlmIChjdHgucmVzb2x2ZUlmQWJvcnRlZChyZXNvbHZlKSkgcmV0dXJuXG5cbiAgICAgICAgICAgIC8vIERvZXMgbm90IGhhdmUgcGVybWlzc2lvbnMgdG8gdXNlIHRvb2wsIGNoZWNrIHRoZSBiZWhhdmlvclxuICAgICAgICAgICAgc3dpdGNoIChyZXN1bHQuYmVoYXZpb3IpIHtcbiAgICAgICAgICAgICAgY2FzZSAnZGVueSc6IHtcbiAgICAgICAgICAgICAgICBsb2dQZXJtaXNzaW9uRGVjaXNpb24oXG4gICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHRvb2wsXG4gICAgICAgICAgICAgICAgICAgIGlucHV0LFxuICAgICAgICAgICAgICAgICAgICB0b29sVXNlQ29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZUlkOiBjdHgubWVzc2FnZUlkLFxuICAgICAgICAgICAgICAgICAgICB0b29sVXNlSUQsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgeyBkZWNpc2lvbjogJ3JlamVjdCcsIHNvdXJjZTogJ2NvbmZpZycgfSxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgZmVhdHVyZSgnVFJBTlNDUklQVF9DTEFTU0lGSUVSJykgJiZcbiAgICAgICAgICAgICAgICAgIHJlc3VsdC5kZWNpc2lvblJlYXNvbj8udHlwZSA9PT0gJ2NsYXNzaWZpZXInICYmXG4gICAgICAgICAgICAgICAgICByZXN1bHQuZGVjaXNpb25SZWFzb24uY2xhc3NpZmllciA9PT0gJ2F1dG8tbW9kZSdcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgIHJlY29yZEF1dG9Nb2RlRGVuaWFsKHtcbiAgICAgICAgICAgICAgICAgICAgdG9vbE5hbWU6IHRvb2wubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogZGVzY3JpcHRpb24sXG4gICAgICAgICAgICAgICAgICAgIHJlYXNvbjogcmVzdWx0LmRlY2lzaW9uUmVhc29uLnJlYXNvbiA/PyAnJyxcbiAgICAgICAgICAgICAgICAgICAgdGltZXN0YW1wOiBEYXRlLm5vdygpLFxuICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgIHRvb2xVc2VDb250ZXh0LmFkZE5vdGlmaWNhdGlvbj8uKHtcbiAgICAgICAgICAgICAgICAgICAga2V5OiAnYXV0by1tb2RlLWRlbmllZCcsXG4gICAgICAgICAgICAgICAgICAgIHByaW9yaXR5OiAnaW1tZWRpYXRlJyxcbiAgICAgICAgICAgICAgICAgICAganN4OiAoXG4gICAgICAgICAgICAgICAgICAgICAgPD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxUZXh0IGNvbG9yPVwiZXJyb3JcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAge3Rvb2wudXNlckZhY2luZ05hbWUoaW5wdXQpLnRvTG93ZXJDYXNlKCl9IGRlbmllZCBieVxuICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRvIG1vZGVcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvVGV4dD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxUZXh0IGRpbUNvbG9yPiDCtyAvcGVybWlzc2lvbnM8L1RleHQ+XG4gICAgICAgICAgICAgICAgICAgICAgPC8+XG4gICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXNvbHZlKHJlc3VsdClcbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGNhc2UgJ2Fzayc6IHtcbiAgICAgICAgICAgICAgICAvLyBGb3IgY29vcmRpbmF0b3Igd29ya2VycywgYXdhaXQgYXV0b21hdGVkIGNoZWNrcyBiZWZvcmUgc2hvd2luZyBkaWFsb2cuXG4gICAgICAgICAgICAgICAgLy8gQmFja2dyb3VuZCB3b3JrZXJzIHNob3VsZCBvbmx5IGludGVycnVwdCB0aGUgdXNlciB3aGVuIGF1dG9tYXRlZCBjaGVja3MgY2FuJ3QgZGVjaWRlLlxuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgIGFwcFN0YXRlLnRvb2xQZXJtaXNzaW9uQ29udGV4dFxuICAgICAgICAgICAgICAgICAgICAuYXdhaXRBdXRvbWF0ZWRDaGVja3NCZWZvcmVEaWFsb2dcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IGNvb3JkaW5hdG9yRGVjaXNpb24gPSBhd2FpdCBoYW5kbGVDb29yZGluYXRvclBlcm1pc3Npb24oXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICBjdHgsXG4gICAgICAgICAgICAgICAgICAgICAgLi4uKGZlYXR1cmUoJ0JBU0hfQ0xBU1NJRklFUicpXG4gICAgICAgICAgICAgICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZW5kaW5nQ2xhc3NpZmllckNoZWNrOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnBlbmRpbmdDbGFzc2lmaWVyQ2hlY2ssXG4gICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZWRJbnB1dDogcmVzdWx0LnVwZGF0ZWRJbnB1dCxcbiAgICAgICAgICAgICAgICAgICAgICBzdWdnZXN0aW9uczogcmVzdWx0LnN1Z2dlc3Rpb25zLFxuICAgICAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb25Nb2RlOiBhcHBTdGF0ZS50b29sUGVybWlzc2lvbkNvbnRleHQubW9kZSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgIGlmIChjb29yZGluYXRvckRlY2lzaW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoY29vcmRpbmF0b3JEZWNpc2lvbilcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAvLyBudWxsIG1lYW5zIG5laXRoZXIgYXV0b21hdGVkIGNoZWNrIHJlc29sdmVkIC0tIGZhbGwgdGhyb3VnaCB0byBkaWFsb2cgYmVsb3cuXG4gICAgICAgICAgICAgICAgICAvLyBIb29rcyBhbHJlYWR5IHJhbiwgY2xhc3NpZmllciBhbHJlYWR5IGNvbnN1bWVkLlxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEFmdGVyIGF3YWl0aW5nIGF1dG9tYXRlZCBjaGVja3MsIHZlcmlmeSB0aGUgcmVxdWVzdCB3YXNuJ3QgYWJvcnRlZFxuICAgICAgICAgICAgICAgIC8vIHdoaWxlIHdlIHdlcmUgd2FpdGluZy4gV2l0aG91dCB0aGlzIGNoZWNrLCBhIHN0YWxlIGRpYWxvZyBjb3VsZCBhcHBlYXIuXG4gICAgICAgICAgICAgICAgaWYgKGN0eC5yZXNvbHZlSWZBYm9ydGVkKHJlc29sdmUpKSByZXR1cm5cblxuICAgICAgICAgICAgICAgIC8vIEZvciBzd2FybSB3b3JrZXJzLCB0cnkgY2xhc3NpZmllciBhdXRvLWFwcHJvdmFsIHRoZW5cbiAgICAgICAgICAgICAgICAvLyBmb3J3YXJkIHBlcm1pc3Npb24gcmVxdWVzdHMgdG8gdGhlIGxlYWRlciB2aWEgbWFpbGJveC5cbiAgICAgICAgICAgICAgICBjb25zdCBzd2FybURlY2lzaW9uID0gYXdhaXQgaGFuZGxlU3dhcm1Xb3JrZXJQZXJtaXNzaW9uKHtcbiAgICAgICAgICAgICAgICAgIGN0eCxcbiAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uLFxuICAgICAgICAgICAgICAgICAgLi4uKGZlYXR1cmUoJ0JBU0hfQ0xBU1NJRklFUicpXG4gICAgICAgICAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcGVuZGluZ0NsYXNzaWZpZXJDaGVjazogcmVzdWx0LnBlbmRpbmdDbGFzc2lmaWVyQ2hlY2ssXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICA6IHt9KSxcbiAgICAgICAgICAgICAgICAgIHVwZGF0ZWRJbnB1dDogcmVzdWx0LnVwZGF0ZWRJbnB1dCxcbiAgICAgICAgICAgICAgICAgIHN1Z2dlc3Rpb25zOiByZXN1bHQuc3VnZ2VzdGlvbnMsXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICBpZiAoc3dhcm1EZWNpc2lvbikge1xuICAgICAgICAgICAgICAgICAgcmVzb2x2ZShzd2FybURlY2lzaW9uKVxuICAgICAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gR3JhY2UgcGVyaW9kOiB3YWl0IHVwIHRvIDJzIGZvciBzcGVjdWxhdGl2ZSBjbGFzc2lmaWVyXG4gICAgICAgICAgICAgICAgLy8gdG8gcmVzb2x2ZSBiZWZvcmUgc2hvd2luZyB0aGUgZGlhbG9nIChtYWluIGFnZW50IG9ubHkpXG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgZmVhdHVyZSgnQkFTSF9DTEFTU0lGSUVSJykgJiZcbiAgICAgICAgICAgICAgICAgIHJlc3VsdC5wZW5kaW5nQ2xhc3NpZmllckNoZWNrICYmXG4gICAgICAgICAgICAgICAgICB0b29sLm5hbWUgPT09IEJBU0hfVE9PTF9OQU1FICYmXG4gICAgICAgICAgICAgICAgICAhYXBwU3RhdGUudG9vbFBlcm1pc3Npb25Db250ZXh0XG4gICAgICAgICAgICAgICAgICAgIC5hd2FpdEF1dG9tYXRlZENoZWNrc0JlZm9yZURpYWxvZ1xuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgY29uc3Qgc3BlY3VsYXRpdmVQcm9taXNlID0gcGVla1NwZWN1bGF0aXZlQ2xhc3NpZmllckNoZWNrKFxuICAgICAgICAgICAgICAgICAgICAoaW5wdXQgYXMgeyBjb21tYW5kOiBzdHJpbmcgfSkuY29tbWFuZCxcbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgIGlmIChzcGVjdWxhdGl2ZVByb21pc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmFjZVJlc3VsdCA9IGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgICAgICAgICAgICAgICAgICAgc3BlY3VsYXRpdmVQcm9taXNlLnRoZW4ociA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3Jlc3VsdCcgYXMgY29uc3QsXG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQ6IHIsXG4gICAgICAgICAgICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgICAgICAgICAgIG5ldyBQcm9taXNlPHsgdHlwZTogJ3RpbWVvdXQnIH0+KHJlcyA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXJlc3RyaWN0ZWQtc3ludGF4IC0tIHJlc29sdmVzIHdpdGggYSB2YWx1ZSwgbm90IHZvaWRcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQocmVzLCAyMDAwLCB7IHR5cGU6ICd0aW1lb3V0JyBhcyBjb25zdCB9KSxcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICBdKVxuXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdHgucmVzb2x2ZUlmQWJvcnRlZChyZXNvbHZlKSkgcmV0dXJuXG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgIHJhY2VSZXN1bHQudHlwZSA9PT0gJ3Jlc3VsdCcgJiZcbiAgICAgICAgICAgICAgICAgICAgICByYWNlUmVzdWx0LnJlc3VsdC5tYXRjaGVzICYmXG4gICAgICAgICAgICAgICAgICAgICAgcmFjZVJlc3VsdC5yZXN1bHQuY29uZmlkZW5jZSA9PT0gJ2hpZ2gnICYmXG4gICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZSgnQkFTSF9DTEFTU0lGSUVSJylcbiAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gQ2xhc3NpZmllciBhcHByb3ZlZCB3aXRoaW4gZ3JhY2UgcGVyaW9kIOKAlCBza2lwIGRpYWxvZ1xuICAgICAgICAgICAgICAgICAgICAgIHZvaWQgY29uc3VtZVNwZWN1bGF0aXZlQ2xhc3NpZmllckNoZWNrKFxuICAgICAgICAgICAgICAgICAgICAgICAgKGlucHV0IGFzIHsgY29tbWFuZDogc3RyaW5nIH0pLmNvbW1hbmQsXG4gICAgICAgICAgICAgICAgICAgICAgKVxuXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgbWF0Y2hlZFJ1bGUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgcmFjZVJlc3VsdC5yZXN1bHQubWF0Y2hlZERlc2NyaXB0aW9uID8/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgICAgICAgIGlmIChtYXRjaGVkUnVsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0Q2xhc3NpZmllckFwcHJvdmFsKHRvb2xVc2VJRCwgbWF0Y2hlZFJ1bGUpXG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgY3R4LmxvZ0RlY2lzaW9uKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlY2lzaW9uOiAnYWNjZXB0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZTogeyB0eXBlOiAnY2xhc3NpZmllcicgfSxcbiAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAgIHJlc29sdmUoXG4gICAgICAgICAgICAgICAgICAgICAgICBjdHguYnVpbGRBbGxvdyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnVwZGF0ZWRJbnB1dCA/P1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChpbnB1dCBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiksXG4gICAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpc2lvblJlYXNvbjoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ2NsYXNzaWZpZXInIGFzIGNvbnN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NpZmllcjogJ2Jhc2hfYWxsb3cnIGFzIGNvbnN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uOiBgQWxsb3dlZCBieSBwcm9tcHQgcnVsZTogXCIke3JhY2VSZXN1bHQucmVzdWx0Lm1hdGNoZWREZXNjcmlwdGlvbn1cImAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIFRpbWVvdXQgb3Igbm8gbWF0Y2gg4oCUIGZhbGwgdGhyb3VnaCB0byBzaG93IGRpYWxvZ1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFNob3cgZGlhbG9nIGFuZCBzdGFydCBob29rcy9jbGFzc2lmaWVyIGluIGJhY2tncm91bmRcbiAgICAgICAgICAgICAgICBoYW5kbGVJbnRlcmFjdGl2ZVBlcm1pc3Npb24oXG4gICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGN0eCxcbiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24sXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCxcbiAgICAgICAgICAgICAgICAgICAgYXdhaXRBdXRvbWF0ZWRDaGVja3NCZWZvcmVEaWFsb2c6XG4gICAgICAgICAgICAgICAgICAgICAgYXBwU3RhdGUudG9vbFBlcm1pc3Npb25Db250ZXh0XG4gICAgICAgICAgICAgICAgICAgICAgICAuYXdhaXRBdXRvbWF0ZWRDaGVja3NCZWZvcmVEaWFsb2csXG4gICAgICAgICAgICAgICAgICAgIGJyaWRnZUNhbGxiYWNrczogZmVhdHVyZSgnQlJJREdFX01PREUnKVxuICAgICAgICAgICAgICAgICAgICAgID8gYXBwU3RhdGUucmVwbEJyaWRnZVBlcm1pc3Npb25DYWxsYmFja3NcbiAgICAgICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgY2hhbm5lbENhbGxiYWNrczpcbiAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlKCdLQUlST1MnKSB8fCBmZWF0dXJlKCdLQUlST1NfQ0hBTk5FTFMnKVxuICAgICAgICAgICAgICAgICAgICAgICAgPyBhcHBTdGF0ZS5jaGFubmVsUGVybWlzc2lvbkNhbGxiYWNrc1xuICAgICAgICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgcmVzb2x2ZSxcbiAgICAgICAgICAgICAgICApXG5cbiAgICAgICAgICAgICAgICByZXR1cm5cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pXG4gICAgICAgICAgLmNhdGNoKGVycm9yID0+IHtcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBBYm9ydEVycm9yIHx8XG4gICAgICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgQVBJVXNlckFib3J0RXJyb3JcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICBsb2dGb3JEZWJ1Z2dpbmcoXG4gICAgICAgICAgICAgICAgYFBlcm1pc3Npb24gY2hlY2sgdGhyZXcgJHtlcnJvci5jb25zdHJ1Y3Rvci5uYW1lfSBmb3IgdG9vbD0ke3Rvb2wubmFtZX06ICR7ZXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIGN0eC5sb2dDYW5jZWxsZWQoKVxuICAgICAgICAgICAgICByZXNvbHZlKGN0eC5jYW5jZWxBbmRBYm9ydCh1bmRlZmluZWQsIHRydWUpKVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgbG9nRXJyb3IoZXJyb3IpXG4gICAgICAgICAgICAgIHJlc29sdmUoY3R4LmNhbmNlbEFuZEFib3J0KHVuZGVmaW5lZCwgdHJ1ZSkpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICBjbGVhckNsYXNzaWZpZXJDaGVja2luZyh0b29sVXNlSUQpXG4gICAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfSxcbiAgICBbc2V0VG9vbFVzZUNvbmZpcm1RdWV1ZSwgc2V0VG9vbFBlcm1pc3Npb25Db250ZXh0XSxcbiAgKVxufVxuXG5leHBvcnQgZGVmYXVsdCB1c2VDYW5Vc2VUb29sXG4iXSwibWFwcGluZ3MiOiI7QUFBQSxTQUFTQSxPQUFPLFFBQVEsWUFBWTtBQUNwQyxTQUFTQyxpQkFBaUIsUUFBUSxtQkFBbUI7QUFDckQsT0FBTyxLQUFLQyxLQUFLLE1BQU0sT0FBTztBQUM5QixTQUFTQyxXQUFXLFFBQVEsT0FBTztBQUNuQyxTQUNFLEtBQUtDLDBEQUEwRCxFQUMvREMsUUFBUSxRQUNILGlDQUFpQztBQUN4QyxTQUFTQyw0QkFBNEIsUUFBUSxvQ0FBb0M7QUFDakYsY0FBY0MsY0FBYyxRQUFRLGdEQUFnRDtBQUNwRixTQUFTQyxJQUFJLFFBQVEsV0FBVztBQUNoQyxjQUNFQyxxQkFBcUIsRUFDckJDLElBQUksSUFBSUMsUUFBUSxFQUNoQkMsY0FBYyxRQUNULFlBQVk7QUFDbkIsU0FDRUMsaUNBQWlDLEVBQ2pDQyw4QkFBOEIsUUFDekIsc0NBQXNDO0FBQzdDLFNBQVNDLGNBQWMsUUFBUSwrQkFBK0I7QUFDOUQsY0FBY0MsZ0JBQWdCLFFBQVEscUJBQXFCO0FBQzNELFNBQVNDLG9CQUFvQixRQUFRLDZCQUE2QjtBQUNsRSxTQUNFQyx1QkFBdUIsRUFDdkJDLHFCQUFxQixFQUNyQkMseUJBQXlCLFFBQ3BCLGlDQUFpQztBQUN4QyxTQUFTQyxlQUFlLFFBQVEsbUJBQW1CO0FBQ25ELFNBQVNDLFVBQVUsUUFBUSxvQkFBb0I7QUFDL0MsU0FBU0MsUUFBUSxRQUFRLGlCQUFpQjtBQUMxQyxjQUFjQyxrQkFBa0IsUUFBUSwwQ0FBMEM7QUFDbEYsU0FBU0MsdUJBQXVCLFFBQVEscUNBQXFDO0FBQzdFLFNBQVNDLGFBQWEsUUFBUSw0QkFBNEI7QUFDMUQsU0FBU0MsMkJBQTJCLFFBQVEsaURBQWlEO0FBQzdGLFNBQVNDLDJCQUEyQixRQUFRLGlEQUFpRDtBQUM3RixTQUFTQywyQkFBMkIsUUFBUSxpREFBaUQ7QUFDN0YsU0FDRUMsdUJBQXVCLEVBQ3ZCQyx3QkFBd0IsUUFDbkIsdUNBQXVDO0FBQzlDLFNBQVNDLHFCQUFxQixRQUFRLHVDQUF1QztBQUU3RSxPQUFPLEtBQUtDLFlBQVksQ0FDdEIsY0FBY0MsTUFBTSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBR0EsTUFBTSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FDaEUsR0FBRyxDQUNGQyxJQUFJLEVBQUV4QixRQUFRLEVBQ2R5QixLQUFLLEVBQUVDLEtBQUssRUFDWkMsY0FBYyxFQUFFMUIsY0FBYyxFQUM5QjJCLGdCQUFnQixFQUFFdkIsZ0JBQWdCLEVBQ2xDd0IsU0FBUyxFQUFFLE1BQU0sRUFDakJDLGFBQXlDLENBQTNCLEVBQUVqQixrQkFBa0IsQ0FBQ2EsS0FBSyxDQUFDLEVBQ3pDLEdBQUdLLE9BQU8sQ0FBQ2xCLGtCQUFrQixDQUFDYSxLQUFLLENBQUMsQ0FBQztBQUV2QyxTQUFBTSxjQUFBQyxzQkFBQSxFQUFBQyx3QkFBQTtFQUFBLE1BQUFDLENBQUEsR0FBQUMsRUFBQTtFQUFBLElBQUFDLEVBQUE7RUFBQSxJQUFBRixDQUFBLFFBQUFELHdCQUFBLElBQUFDLENBQUEsUUFBQUYsc0JBQUE7SUFPSUksRUFBQSxTQUFBQSxDQUFBYixJQUFBLEVBQUFDLEtBQUEsRUFBQUUsY0FBQSxFQUFBQyxnQkFBQSxFQUFBQyxTQUFBLEVBQUFDLGFBQUEsS0FRUyxJQUFJQyxPQUFPLENBQUNPLE9BQUE7TUFDakIsTUFBQUMsR0FBQSxHQUFZcEIsdUJBQXVCLENBQ2pDSyxJQUFJLEVBQ0pDLEtBQUssRUFDTEUsY0FBYyxFQUNkQyxnQkFBZ0IsRUFDaEJDLFNBQVMsRUFDVEssd0JBQXdCLEVBQ3hCZCx3QkFBd0IsQ0FBQ2Esc0JBQXNCLENBQ2pELENBQUM7TUFFRCxJQUFJTSxHQUFHLENBQUFDLGdCQUFpQixDQUFDRixPQUFPLENBQUM7UUFBQTtNQUFBO01BRWpDLE1BQUFHLGVBQUEsR0FDRVgsYUFBYSxLQUFLWSxTQVFiLEdBUERYLE9BQU8sQ0FBQU8sT0FBUSxDQUFDUixhQU9oQixDQUFDLEdBTkRoQix1QkFBdUIsQ0FDckJVLElBQUksRUFDSkMsS0FBSyxFQUNMRSxjQUFjLEVBQ2RDLGdCQUFnQixFQUNoQkMsU0FDRixDQUFDO01BQUEsT0FFQVksZUFBZSxDQUFBRSxJQUNmLENBQUMsTUFBQUMsTUFBQTtRQWtCSixJQUFJQSxNQUFNLENBQUFDLFFBQVMsS0FBSyxPQUFPO1VBQzdCLElBQUlOLEdBQUcsQ0FBQUMsZ0JBQWlCLENBQUNGLE9BQU8sQ0FBQztZQUFBO1VBQUE7VUFFakMsSUFDRWpELE9BQU8sQ0FBQyx1QkFDbUMsQ0FBQyxJQUE1Q3VELE1BQU0sQ0FBQUUsY0FBcUIsRUFBQUMsSUFBQSxLQUFLLFlBQ2dCLElBQWhESCxNQUFNLENBQUFFLGNBQWUsQ0FBQUUsVUFBVyxLQUFLLFdBQVc7WUFFaER2Qyx5QkFBeUIsQ0FDdkJvQixTQUFTLEVBQ1RlLE1BQU0sQ0FBQUUsY0FBZSxDQUFBRyxNQUN2QixDQUFDO1VBQUE7VUFHSFYsR0FBRyxDQUFBVyxXQUFZLENBQUM7WUFBQUMsUUFBQSxFQUFZLFFBQVE7WUFBQUMsTUFBQSxFQUFVO1VBQVMsQ0FBQyxDQUFDO1VBRXpEZCxPQUFPLENBQ0xDLEdBQUcsQ0FBQWMsVUFBVyxDQUFDVCxNQUFNLENBQUFVLFlBQXNCLElBQTVCN0IsS0FBNEIsRUFBRTtZQUFBcUIsY0FBQSxFQUMzQkYsTUFBTSxDQUFBRTtVQUN4QixDQUFDLENBQ0gsQ0FBQztVQUFBO1FBQUE7UUFJSCxNQUFBUyxRQUFBLEdBQWlCNUIsY0FBYyxDQUFBNkIsV0FBWSxDQUFDLENBQUM7UUFDN0MsTUFBQUMsV0FBQSxHQUFvQixNQUFNakMsSUFBSSxDQUFBaUMsV0FBWSxDQUFDaEMsS0FBSyxJQUFJLEtBQUssRUFBRTtVQUFBaUMsdUJBQUEsRUFFdkQvQixjQUFjLENBQUFnQyxPQUFRLENBQUFELHVCQUF3QjtVQUFBRSxxQkFBQSxFQUN6QkwsUUFBUSxDQUFBSyxxQkFBc0I7VUFBQUMsS0FBQSxFQUM5Q2xDLGNBQWMsQ0FBQWdDLE9BQVEsQ0FBQUU7UUFDL0IsQ0FBQyxDQUFDO1FBRUYsSUFBSXRCLEdBQUcsQ0FBQUMsZ0JBQWlCLENBQUNGLE9BQU8sQ0FBQztVQUFBO1FBQUE7UUFHakMsUUFBUU0sTUFBTSxDQUFBQyxRQUFTO1VBQUEsS0FDaEIsTUFBTTtZQUFBO2NBQ1R4QixxQkFBcUIsQ0FDbkI7Z0JBQUFHLElBQUE7Z0JBQUFDLEtBQUE7Z0JBQUFFLGNBQUE7Z0JBQUFtQyxTQUFBLEVBSWF2QixHQUFHLENBQUF1QixTQUFVO2dCQUFBakM7Y0FFMUIsQ0FBQyxFQUNEO2dCQUFBc0IsUUFBQSxFQUFZLFFBQVE7Z0JBQUFDLE1BQUEsRUFBVTtjQUFTLENBQ3pDLENBQUM7Y0FDRCxJQUNFL0QsT0FBTyxDQUFDLHVCQUNtQyxDQUFDLElBQTVDdUQsTUFBTSxDQUFBRSxjQUFxQixFQUFBQyxJQUFBLEtBQUssWUFDZ0IsSUFBaERILE1BQU0sQ0FBQUUsY0FBZSxDQUFBRSxVQUFXLEtBQUssV0FBVztnQkFFaEQxQyxvQkFBb0IsQ0FBQztrQkFBQXlELFFBQUEsRUFDVHZDLElBQUksQ0FBQXdDLElBQUs7a0JBQUFDLE9BQUEsRUFDVlIsV0FBVztrQkFBQVIsTUFBQSxFQUNaTCxNQUFNLENBQUFFLGNBQWUsQ0FBQUcsTUFBYSxJQUFsQyxFQUFrQztrQkFBQWlCLFNBQUEsRUFDL0JDLElBQUksQ0FBQUMsR0FBSSxDQUFDO2dCQUN0QixDQUFDLENBQUM7Z0JBQ0Z6QyxjQUFjLENBQUEwQyxlQVlaLEdBWitCO2tCQUFBQyxHQUFBLEVBQzFCLGtCQUFrQjtrQkFBQUMsUUFBQSxFQUNiLFdBQVc7a0JBQUFDLEdBQUEsRUFFbkIsRUFDRSxDQUFDLElBQUksQ0FBTyxLQUFPLENBQVAsT0FBTyxDQUNoQixDQUFBaEQsSUFBSSxDQUFBaUQsY0FBZSxDQUFDaEQsS0FBSyxDQUFDLENBQUFpRCxXQUFZLENBQUMsRUFBRSxvQkFFNUMsRUFIQyxJQUFJLENBSUwsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFSLEtBQU8sQ0FBQyxDQUFDLGVBQWUsRUFBN0IsSUFBSSxDQUFnQztnQkFHM0MsQ0FBQyxDQUFDO2NBQUE7Y0FFSnBDLE9BQU8sQ0FBQ00sTUFBTSxDQUFDO2NBQUE7WUFBQTtVQUFBLEtBSVosS0FBSztZQUFBO2NBR1IsSUFDRVcsUUFBUSxDQUFBSyxxQkFBc0IsQ0FBQWUsZ0NBQ0s7Z0JBRW5DLE1BQUFDLG1CQUFBLEdBQTRCLE1BQU01RCwyQkFBMkIsQ0FDM0Q7a0JBQUF1QixHQUFBO2tCQUFBLElBRU1sRCxPQUFPLENBQUMsaUJBS1AsQ0FBQyxHQUxGO29CQUFBd0Ysc0JBQUEsRUFHSWpDLE1BQU0sQ0FBQWlDO2tCQUVULENBQUMsR0FMRixDQUtDLENBQUM7a0JBQUF2QixZQUFBLEVBQ1FWLE1BQU0sQ0FBQVUsWUFBYTtrQkFBQXdCLFdBQUEsRUFDcEJsQyxNQUFNLENBQUFrQyxXQUFZO2tCQUFBQyxjQUFBLEVBQ2Z4QixRQUFRLENBQUFLLHFCQUFzQixDQUFBb0I7Z0JBQ2hELENBQ0YsQ0FBQztnQkFDRCxJQUFJSixtQkFBbUI7a0JBQ3JCdEMsT0FBTyxDQUFDc0MsbUJBQW1CLENBQUM7a0JBQUE7Z0JBQUE7Y0FFN0I7Y0FPSCxJQUFJckMsR0FBRyxDQUFBQyxnQkFBaUIsQ0FBQ0YsT0FBTyxDQUFDO2dCQUFBO2NBQUE7Y0FJakMsTUFBQTJDLGFBQUEsR0FBc0IsTUFBTS9ELDJCQUEyQixDQUFDO2dCQUFBcUIsR0FBQTtnQkFBQWtCLFdBQUE7Z0JBQUEsSUFHbERwRSxPQUFPLENBQUMsaUJBSVAsQ0FBQyxHQUpGO2tCQUFBd0Ysc0JBQUEsRUFFMEJqQyxNQUFNLENBQUFpQztnQkFFL0IsQ0FBQyxHQUpGLENBSUMsQ0FBQztnQkFBQXZCLFlBQUEsRUFDUVYsTUFBTSxDQUFBVSxZQUFhO2dCQUFBd0IsV0FBQSxFQUNwQmxDLE1BQU0sQ0FBQWtDO2NBQ3JCLENBQUMsQ0FBQztjQUNGLElBQUlHLGFBQWE7Z0JBQ2YzQyxPQUFPLENBQUMyQyxhQUFhLENBQUM7Z0JBQUE7Y0FBQTtjQU14QixJQUNFNUYsT0FBTyxDQUFDLGlCQUNvQixDQUFDLElBQTdCdUQsTUFBTSxDQUFBaUMsc0JBQ3NCLElBQTVCckQsSUFBSSxDQUFBd0MsSUFBSyxLQUFLNUQsY0FFcUIsSUFKbkMsQ0FHQ21ELFFBQVEsQ0FBQUsscUJBQXNCLENBQUFlLGdDQUNJO2dCQUVuQyxNQUFBTyxrQkFBQSxHQUEyQi9FLDhCQUE4QixDQUN2RCxDQUFDc0IsS0FBSyxJQUFJO2tCQUFFMEQsT0FBTyxFQUFFLE1BQU07Z0JBQUMsQ0FBQyxFQUFBQSxPQUMvQixDQUFDO2dCQUNELElBQUlELGtCQUFrQjtrQkFDcEIsTUFBQUUsVUFBQSxHQUFtQixNQUFNckQsT0FBTyxDQUFBc0QsSUFBSyxDQUFDLENBQ3BDSCxrQkFBa0IsQ0FBQXZDLElBQUssQ0FBQzJDLEtBR3RCLENBQUMsRUFDSCxJQUFJdkQsT0FBTyxDQUFzQndELE1BR2pDLENBQUMsQ0FDRixDQUFDO2tCQUVGLElBQUloRCxHQUFHLENBQUFDLGdCQUFpQixDQUFDRixPQUFPLENBQUM7b0JBQUE7a0JBQUE7a0JBRWpDLElBQ0U4QyxVQUFVLENBQUFyQyxJQUFLLEtBQUssUUFDSyxJQUF6QnFDLFVBQVUsQ0FBQXhDLE1BQU8sQ0FBQTRDLE9BQ3NCLElBQXZDSixVQUFVLENBQUF4QyxNQUFPLENBQUE2QyxVQUFXLEtBQUssTUFDUCxJQUExQnBHLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztvQkFHckJhLGlDQUFpQyxDQUNwQyxDQUFDdUIsS0FBSyxJQUFJO3NCQUFFMEQsT0FBTyxFQUFFLE1BQU07b0JBQUMsQ0FBQyxFQUFBQSxPQUMvQixDQUFDO29CQUVELE1BQUFPLFdBQUEsR0FDRU4sVUFBVSxDQUFBeEMsTUFBTyxDQUFBK0Msa0JBQWdDLElBQWpEakQsU0FBaUQ7b0JBQ25ELElBQUlnRCxXQUFXO3NCQUNibEYscUJBQXFCLENBQUNxQixTQUFTLEVBQUU2RCxXQUFXLENBQUM7b0JBQUE7b0JBRy9DbkQsR0FBRyxDQUFBVyxXQUFZLENBQUM7c0JBQUFDLFFBQUEsRUFDSixRQUFRO3NCQUFBQyxNQUFBLEVBQ1Y7d0JBQUFMLElBQUEsRUFBUTtzQkFBYTtvQkFDL0IsQ0FBQyxDQUFDO29CQUNGVCxPQUFPLENBQ0xDLEdBQUcsQ0FBQWMsVUFBVyxDQUNaVCxNQUFNLENBQUFVLFlBQzhCLElBQWpDN0IsS0FBSyxJQUFJRixNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBRSxFQUNwQztzQkFBQXVCLGNBQUEsRUFDa0I7d0JBQUFDLElBQUEsRUFDUixZQUFZLElBQUk2QyxLQUFLO3dCQUFBNUMsVUFBQSxFQUNmLFlBQVksSUFBSTRDLEtBQUs7d0JBQUEzQyxNQUFBLEVBQ3pCLDRCQUE0Qm1DLFVBQVUsQ0FBQXhDLE1BQU8sQ0FBQStDLGtCQUFtQjtzQkFDMUU7b0JBQ0YsQ0FDRixDQUNGLENBQUM7b0JBQUE7a0JBQUE7Z0JBRUY7Y0FFRjtjQUlIMUUsMkJBQTJCLENBQ3pCO2dCQUFBc0IsR0FBQTtnQkFBQWtCLFdBQUE7Z0JBQUFiLE1BQUE7Z0JBQUErQixnQ0FBQSxFQUtJcEIsUUFBUSxDQUFBSyxxQkFBc0IsQ0FBQWUsZ0NBQ0s7Z0JBQUFrQixlQUFBLEVBQ3BCeEcsT0FBTyxDQUFDLGFBRWIsQ0FBQyxHQURUa0UsUUFBUSxDQUFBdUMsNkJBQ0MsR0FGSXBELFNBRUo7Z0JBQUFxRCxnQkFBQSxFQUVYMUcsT0FBTyxDQUFDLFFBQXNDLENBQUMsSUFBMUJBLE9BQU8sQ0FBQyxpQkFBaUIsQ0FFakMsR0FEVGtFLFFBQVEsQ0FBQXlDLDBCQUNDLEdBRmJ0RDtjQUdKLENBQUMsRUFDREosT0FDRixDQUFDO2NBQUE7WUFBQTtRQUlMO01BQUMsQ0FDRixDQUFDLENBQUEyRCxLQUNJLENBQUNDLEtBQUE7UUFDTCxJQUNFQSxLQUFLLFlBQVl2RixVQUNpQixJQUFsQ3VGLEtBQUssWUFBWTVHLGlCQUFpQjtVQUVsQ29CLGVBQWUsQ0FDYiwwQkFBMEJ3RixLQUFLLENBQUFDLFdBQVksQ0FBQW5DLElBQUssYUFBYXhDLElBQUksQ0FBQXdDLElBQUssS0FBS2tDLEtBQUssQ0FBQUUsT0FBUSxFQUMxRixDQUFDO1VBQ0Q3RCxHQUFHLENBQUE4RCxZQUFhLENBQUMsQ0FBQztVQUNsQi9ELE9BQU8sQ0FBQ0MsR0FBRyxDQUFBK0QsY0FBZSxDQUFDNUQsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQUE7VUFFNUM5QixRQUFRLENBQUNzRixLQUFLLENBQUM7VUFDZjVELE9BQU8sQ0FBQ0MsR0FBRyxDQUFBK0QsY0FBZSxDQUFDNUQsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQUE7TUFDN0MsQ0FDRixDQUFDLENBQUE2RCxPQUNNLENBQUM7UUFDUGhHLHVCQUF1QixDQUFDc0IsU0FBUyxDQUFDO01BQUEsQ0FDbkMsQ0FBQztJQUFBLENBQ0wsQ0FDRjtJQUFBTSxDQUFBLE1BQUFELHdCQUFBO0lBQUFDLENBQUEsTUFBQUYsc0JBQUE7SUFBQUUsQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxPQWhTSUUsRUFrU047QUFBQTtBQXhTSCxTQUFBa0QsT0FBQWlCLEdBQUE7RUFBQSxPQTZNd0JDLFVBQVUsQ0FBQ0QsR0FBRyxFQUFFLElBQUksRUFBRTtJQUFBekQsSUFBQSxFQUFRLFNBQVMsSUFBSTZDO0VBQU0sQ0FBQyxDQUFDO0FBQUE7QUE3TTNFLFNBQUFOLE1BQUFvQixDQUFBO0VBQUEsT0F1TW9EO0lBQUEzRCxJQUFBLEVBQ3RCLFFBQVEsSUFBSTZDLEtBQUs7SUFBQWhELE1BQUEsRUFDZjhEO0VBQ1YsQ0FBQztBQUFBO0FBaUd2QixlQUFlMUUsYUFBYSIsImlnbm9yZUxpc3QiOltdfQ==Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/* Status: Completed
src\tools\utils.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/**/*.ts Status: Completed
src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\built-in\claudeCodeGuideAgent.ts src\tools\AgentTool\built-in\exploreAgent.ts src\tools\AgentTool\built-in\generalPurposeAgent.ts src\tools\AgentTool\built-in\planAgent.ts src\tools\AgentTool\built-in\statuslineSetup.ts src\tools\AgentTool\built-in\verificationAgent.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\runAgent.ts src\tools\AskUserQuestionTool\prompt.ts src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts src\tools\BriefTool\BriefTool.ts src\tools\BriefTool\attachments.ts src\tools\BriefTool\prompt.ts src\tools\BriefTool\upload.ts src\tools\ConfigTool\ConfigTool.ts src\tools\ConfigTool\constants.ts src\tools\ConfigTool\prompt.ts src\tools\ConfigTool\supportedSettings.ts src\tools\EnterPlanModeTool\constants.ts src\tools\EnterPlanModeTool\EnterPlanModeTool.ts src\tools\EnterPlanModeTool\prompt.ts src\tools\EnterWorktreeTool\constants.ts src\tools\EnterWorktreeTool\EnterWorktreeTool.ts src\tools\EnterWorktreeTool\prompt.ts src\tools\ExitPlanModeTool\constants.ts src\tools\ExitPlanModeTool\ExitPlanModeV2Tool.ts src\tools\ExitPlanModeTool\prompt.ts src\tools\ExitWorktreeTool\constants.ts src\tools\ExitWorktreeTool\ExitWorktreeTool.ts src\tools\ExitWorktreeTool\prompt.ts src\tools\FileEditTool\FileEditTool.ts src\tools\FileEditTool\constants.ts src\tools\FileEditTool\prompt.ts src\tools\FileEditTool\types.ts src\tools\FileEditTool\utils.ts src\tools\FileReadTool\FileReadTool.ts src\tools\FileReadTool\imageProcessor.ts src\tools\FileReadTool\limits.ts src\tools\FileReadTool\prompt.ts src\tools\FileWriteTool\FileWriteTool.ts src\tools\FileWriteTool\prompt.ts src\tools\GlobTool\GlobTool.ts src\tools\GlobTool\prompt.ts src\tools\GrepTool\GrepTool.ts src\tools\GrepTool\prompt.ts src\tools\LSPTool\LSPTool.ts src\tools\LSPTool\formatters.ts src\tools\LSPTool\prompt.ts src\tools\LSPTool\schemas.ts src\tools\LSPTool\symbolContext.ts src\tools\ListMcpResourcesTool\ListMcpResourcesTool.ts src\tools\ListMcpResourcesTool\prompt.ts src\tools\MCPTool\MCPTool.ts src\tools\MCPTool\classifyForCollapse.ts src\tools\MCPTool\prompt.ts src\tools\McpAuthTool\McpAuthTool.ts src\tools\NotebookEditTool\NotebookEditTool.ts src\tools\NotebookEditTool\constants.ts src\tools\NotebookEditTool\prompt.ts src\tools\PowerShellTool\clmTypes.ts src\tools\PowerShellTool\commandSemantics.ts src\tools\PowerShellTool\commonParameters.ts src\tools\PowerShellTool\destructiveCommandWarning.ts src\tools\PowerShellTool\gitSafety.ts src\tools\PowerShellTool\modeValidation.ts src\tools\PowerShellTool\pathValidation.ts src\tools\PowerShellTool\powershellPermissions.ts src\tools\PowerShellTool\powershellSecurity.ts src\tools\PowerShellTool\prompt.ts src\tools\PowerShellTool\readOnlyValidation.ts src\tools\PowerShellTool\toolName.ts src\tools\REPLTool\constants.ts src\tools\ReadMcpResourceTool\ReadMcpResourceTool.ts src\tools\REPLTool\primitiveTools.ts src\tools\ReadMcpResourceTool\prompt.ts src\tools\RemoteTriggerTool\prompt.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\coordinator\coordinatorMode.ts (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle'
2→import { ASYNC_AGENT_ALLOWED_TOOLS } from '../constants/tools.js'
3→import { checkStatsigFeatureGate_CACHED_MAY_BE_STALE } from '../services/analytics/growthbook.js'
4→import {
5→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
6→ logEvent,
7→} from '../services/analytics/index.js'
8→import { AGENT_TOOL_NAME } from '../tools/AgentTool/constants.js'
9→import { BASH_TOOL_NAME } from '../tools/BashTool/toolName.js'
10→import { FILE_EDIT_TOOL_NAME } from '../tools/FileEditTool/constants.js'
11→import { FILE_READ_TOOL_NAME } from '../tools/FileReadTool/prompt.js'
12→import { SEND_MESSAGE_TOOL_NAME } from '../tools/SendMessageTool/constants.js'
13→import { SYNTHETIC_OUTPUT_TOOL_NAME } from '../tools/SyntheticOutputTool/SyntheticOutputTool.js'
14→import { TASK_STOP_TOOL_NAME } from '../tools/TaskStopTool/prompt.js'
15→import { TEAM_CREATE_TOOL_NAME } from '../tools/TeamCreateTool/constants.js'
16→import { TEAM_DELETE_TOOL_NAME } from '../tools/TeamDeleteTool/constants.js'
17→import { isEnvTruthy } from '../utils/envUtils.js'
18→
19→// Checks the same gate as isScratchpadEnabled() in
20→// utils/permissions/filesystem.ts. Duplicated here because importing
21→// filesystem.ts creates a circular dependency (filesystem -> permissions
22→// -> ... -> coordinatorMode). The actual scratchpad path is passed in via
23→// getCoordinatorUserContext's scratchpadDir parameter (dependency injection
24→// from QueryEngine.ts, which lives higher in the dep graph).
25→function isScratchpadGateEnabled(): boolean {
26→ return checkStatsigFeatureGate_CACHED_MAY_BE_STALE('tengu_scratch')
27→}
28→
29→const INTERNAL_WORKER_TOOLS = new Set([
30→ TEAM_CREATE_TOOL_NAME,
31→ TEAM_DELETE_TOOL_NAME,
32→ SEND_MESSAGE_TOOL_NAME,
33→ SYNTHETIC_OUTPUT_TOOL_NAME,
34→])
35→
36→export function isCoordinatorMode(): boolean {
37→ if (feature('COORDINATOR_MODE')) {
38→ return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
39→ }
40→ return false
41→}
42→
43→/**
44→ * Checks if the current coordinator mode matches the session's stored mode.
45→ * If mismatched, flips the environment variable so isCoordinatorMode() returns
46→ * the correct value for the resumed session. Returns a warning message if
47→ * the mode was switched, or undefined if no switch was needed.
48→ */
49→export function matchSessionMode(
50→ sessionMode: 'coordinator' | 'normal' | undefined,
51→): string | undefined {
52→ // No stored mode (old session before mode tracking) — do nothing
53→ if (!sessionMode) {
54→ return undefined
55→ }
56→
57→ const currentIsCoordinator = isCoordinatorMode()
58→ const sessionIsCoordinator = sessionMode === 'coordinator'
59→
60→ if (currentIsCoordinator === sessionIsCoordinator) {
61→ return undefined
62→ }
63→
64→ // Flip the env var — isCoordinatorMode() reads it live, no caching
65→ if (sessionIsCoordinator) {
66→ process.env.CLAUDE_CODE_COORDINATOR_MODE = '1'
67→ } else {
68→ delete process.env.CLAUDE_CODE_COORDINATOR_MODE
69→ }
70→
71→ logEvent('tengu_coordinator_mode_switched', {
72→ to: sessionMode as unknown as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
73→ })
74→
75→ return sessionIsCoordinator
76→ ? 'Entered coordinator mode to match resumed session.'
77→ : 'Exited coordinator mode to match resumed session.'
78→}
79→
80→export function getCoordinatorUserContext(Tool Call: Read src\state\AppStateStore.js (1 - 120) Status: Failed
File does not exist. Note: your current working directory is D:\code\play\stock_ai_rust\claude-code. Did you mean AppStateStore.ts?Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/services/**/* Status: Completed
src\services\AgentSummary\agentSummary.ts src\services\MagicDocs\magicDocs.ts src\services\MagicDocs\prompts.ts src\services\PromptSuggestion\promptSuggestion.ts src\services\PromptSuggestion\speculation.ts src\services\SessionMemory\prompts.ts src\services\SessionMemory\sessionMemory.ts src\services\analytics\config.ts src\services\SessionMemory\sessionMemoryUtils.ts src\services\analytics\datadog.ts src\services\analytics\firstPartyEventLogger.ts src\services\analytics\firstPartyEventLoggingExporter.ts src\services\analytics\growthbook.ts src\services\analytics\index.ts src\services\analytics\metadata.ts src\services\analytics\sink.ts src\services\analytics\sinkKillswitch.ts src\services\api\adminRequests.ts src\services\api\bootstrap.ts src\services\api\claude.ts src\services\api\client.ts src\services\api\dumpPrompts.ts src\services\api\emptyUsage.ts src\services\api\errorUtils.ts src\services\api\errors.ts src\services\api\filesApi.ts src\services\api\firstTokenDate.ts src\services\api\grove.ts src\services\api\logging.ts src\services\api\metricsOptOut.ts src\services\api\overageCreditGrant.ts src\services\api\promptCacheBreakDetection.ts src\services\api\referral.ts src\services\api\sessionIngress.ts src\services\api\ultrareviewQuota.ts src\services\api\usage.ts src\services\api\withRetry.ts src\services\autoDream\autoDream.ts src\services\autoDream\config.ts src\services\autoDream\consolidationLock.ts src\services\autoDream\consolidationPrompt.ts src\services\awaySummary.ts src\services\claudeAiLimits.ts src\services\claudeAiLimitsHook.ts src\services\compact\apiMicrocompact.ts src\services\compact\autoCompact.ts src\services\compact\compact.ts src\services\compact\compactWarningHook.ts src\services\compact\compactWarningState.ts src\services\compact\grouping.ts src\services\compact\microCompact.ts src\services\compact\postCompactCleanup.ts src\services\compact\prompt.ts src\services\compact\sessionMemoryCompact.ts src\services\compact\timeBasedMCConfig.ts src\services\diagnosticTracking.ts src\services\extractMemories\extractMemories.ts src\services\extractMemories\prompts.ts src\services\internalLogging.ts src\services\lsp\LSPClient.ts src\services\lsp\LSPDiagnosticRegistry.ts src\services\lsp\LSPServerInstance.ts src\services\lsp\config.ts src\services\lsp\LSPServerManager.ts src\services\lsp\manager.ts src\services\lsp\passiveFeedback.ts src\services\mcp\InProcessTransport.ts src\services\mcp\MCPConnectionManager.tsx src\services\mcp\SdkControlTransport.ts src\services\mcp\auth.ts src\services\mcp\channelAllowlist.ts src\services\mcp\channelNotification.ts src\services\mcp\channelPermissions.ts src\services\mcp\claudeai.ts src\services\mcp\client.ts src\services\mcp\config.ts src\services\mcp\elicitationHandler.ts src\services\mcp\envExpansion.ts src\services\mcp\headersHelper.ts src\services\mcp\mcpStringUtils.ts src\services\mcp\normalization.ts src\services\mcp\oauthPort.ts src\services\mcp\officialRegistry.ts src\services\mcp\types.ts src\services\mcp\useManageMCPConnections.ts src\services\mcp\utils.ts src\services\mcp\vscodeSdkMcp.ts src\services\mcp\xaa.ts src\services\mcp\xaaIdpLogin.ts src\services\mcpServerApproval.tsx src\services\mockRateLimits.ts src\services\notifier.ts src\services\oauth\auth-code-listener.ts src\services\oauth\client.ts src\services\oauth\crypto.ts src\services\oauth\getOauthProfile.ts src\services\oauth\index.ts src\services\plugins\pluginCliCommands.ts src\services\plugins\PluginInstallationManager.ts src\services\plugins\pluginOperations.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\assistant\sessionHistory.ts Status: Completed
1→import axios from 'axios'
2→import { getOauthConfig } from '../constants/oauth.js'
3→import type { SDKMessage } from '../entrypoints/agentSdkTypes.js'
4→import { logForDebugging } from '../utils/debug.js'
5→import { getOAuthHeaders, prepareApiRequest } from '../utils/teleport/api.js'
6→
7→export const HISTORY_PAGE_SIZE = 100
8→
9→export type HistoryPage = {
10→ /** Chronological order within the page. */
11→ events: SDKMessage[]
12→ /** Oldest event ID in this page → before_id cursor for next-older page. */
13→ firstId: string | null
14→ /** true = older events exist. */
15→ hasMore: boolean
16→}
17→
18→type SessionEventsResponse = {
19→ data: SDKMessage[]
20→ has_more: boolean
21→ first_id: string | null
22→ last_id: string | null
23→}
24→
25→export type HistoryAuthCtx = {
26→ baseUrl: string
27→ headers: Record<string, string>
28→}
29→
30→/** Prepare auth + headers + base URL once, reuse across pages. */
31→export async function createHistoryAuthCtx(
32→ sessionId: string,
33→): Promise<HistoryAuthCtx> {
34→ const { accessToken, orgUUID } = await prepareApiRequest()
35→ return {
36→ baseUrl: `${getOauthConfig().BASE_API_URL}/v1/sessions/${sessionId}/events`,
37→ headers: {
38→ ...getOAuthHeaders(accessToken),
39→ 'anthropic-beta': 'ccr-byoc-2025-07-29',
40→ 'x-organization-uuid': orgUUID,
41→ },
42→ }
43→}
44→
45→async function fetchPage(
46→ ctx: HistoryAuthCtx,
47→ params: Record<string, string | number | boolean>,
48→ label: string,
49→): Promise<HistoryPage | null> {
50→ const resp = await axios
51→ .get<SessionEventsResponse>(ctx.baseUrl, {
52→ headers: ctx.headers,
53→ params,
54→ timeout: 15000,
55→ validateStatus: () => true,
56→ })
57→ .catch(() => null)
58→ if (!resp || resp.status !== 200) {
59→ logForDebugging(`[${label}] HTTP ${resp?.status ?? 'error'}`)
60→ return null
61→ }
62→ return {
63→ events: Array.isArray(resp.data.data) ? resp.data.data : [],
64→ firstId: resp.data.first_id,
65→ hasMore: resp.data.has_more,
66→ }
67→}
68→
69→/**
70→ * Newest page: last `limit` events, chronological, via anchor_to_latest.
71→ * has_more=true means older events exist.
72→ */
73→export async function fetchLatestEvents(
74→ ctx: HistoryAuthCtx,
75→ limit = HISTORY_PAGE_SIZE,
76→): Promise<HistoryPage | null> {
77→ return fetchPage(ctx, { limit, anchor_to_latest: true }, 'fetchLatestEvents')
78→}
79→
80→/** Older page: events immediately before `beforeId` cursor. */
81→export async function fetchOlderEvents(
82→ ctx: HistoryAuthCtx,
83→ beforeId: string,
84→ limit = HISTORY_PAGE_SIZE,
85→): Promise<HistoryPage | null> {
86→ return fetchPage(ctx, { limit, before_id: beforeId }, 'fetchOlderEvents')
87→}
88→Tool Call: Read src\bootstrap\state.ts Status: Completed
1→import type { BetaMessageStreamParams } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
2→import type { Attributes, Meter, MetricOptions } from '@opentelemetry/api'
3→import type { logs } from '@opentelemetry/api-logs'
4→import type { LoggerProvider } from '@opentelemetry/sdk-logs'
5→import type { MeterProvider } from '@opentelemetry/sdk-metrics'
6→import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'
7→import { realpathSync } from 'fs'
8→import sumBy from 'lodash-es/sumBy.js'
9→import { cwd } from 'process'
10→import type { HookEvent, ModelUsage } from 'src/entrypoints/agentSdkTypes.js'
11→import type { AgentColorName } from 'src/tools/AgentTool/agentColorManager.js'
12→import type { HookCallbackMatcher } from 'src/types/hooks.js'
13→// Indirection for browser-sdk build (package.json "browser" field swaps
14→// crypto.ts for crypto.browser.ts). Pure leaf re-export of node:crypto —
15→// zero circular-dep risk. Path-alias import bypasses bootstrap-isolation
16→// (rule only checks ./ and / prefixes); explicit disable documents intent.
17→// eslint-disable-next-line custom-rules/bootstrap-isolation
18→import { randomUUID } from 'src/utils/crypto.js'
19→import type { ModelSetting } from 'src/utils/model/model.js'
20→import type { ModelStrings } from 'src/utils/model/modelStrings.js'
21→import type { SettingSource } from 'src/utils/settings/constants.js'
22→import { resetSettingsCache } from 'src/utils/settings/settingsCache.js'
23→import type { PluginHookMatcher } from 'src/utils/settings/types.js'
24→import { createSignal } from 'src/utils/signal.js'
25→
26→// Union type for registered hooks - can be SDK callbacks or native plugin hooks
27→type RegisteredHookMatcher = HookCallbackMatcher | PluginHookMatcher
28→
29→import type { SessionId } from 'src/types/ids.js'
30→
31→// DO NOT ADD MORE STATE HERE - BE JUDICIOUS WITH GLOBAL STATE
32→
33→// dev: true on entries that came via --dangerously-load-development-channels.
34→// The allowlist gate checks this per-entry (not the session-wide
35→// hasDevChannels bit) so passing both flags doesn't let the dev dialog's
36→// acceptance leak allowlist-bypass to the --channels entries.
37→export type ChannelEntry =
38→ | { kind: 'plugin'; name: string; marketplace: string; dev?: boolean }
39→ | { kind: 'server'; name: string; dev?: boolean }
40→
41→export type AttributedCounter = {
42→ add(value: number, additionalAttributes?: Attributes): void
43→}
44→
45→type State = {
46→ originalCwd: string
47→ // Stable project root - set once at startup (including by --worktree flag),
48→ // never updated by mid-session EnterWorktreeTool.
49→ // Use for project identity (history, skills, sessions) not file operations.
50→ projectRoot: string
51→ totalCostUSD: number
52→ totalAPIDuration: number
53→ totalAPIDurationWithoutRetries: number
54→ totalToolDuration: number
55→ turnHookDurationMs: number
56→ turnToolDurationMs: number
57→ turnClassifierDurationMs: number
58→ turnToolCount: number
59→ turnHookCount: number
60→ turnClassifierCount: number
61→ startTime: number
62→ lastInteractionTime: number
63→ totalLinesAdded: number
64→ totalLinesRemoved: number
65→ hasUnknownModelCost: boolean
66→ cwd: string
67→ modelUsage: { [modelName: string]: ModelUsage }
68→ mainLoopModelOverride: ModelSetting | undefined
69→ initialMainLoopModel: ModelSetting
70→ modelStrings: ModelStrings | null
71→ isInteractive: boolean
72→ kairosActive: boolean
73→ // When true, ensureToolResultPairing throws on mismatch instead of
74→ // repairing with synthetic placeholders. HFI opts in at startup so
75→ // trajectories fail fast rather than conditioning the model on fake
76→ // tool_results.
77→ strictToolResultPairing: boolean
78→ sdkAgentProgressSummariesEnabled: boolean
79→ userMsgOptIn: boolean
80→ clientType: string
81→ sessionSource: string | undefined
82→ questionPreviewFormat: 'markdown' | 'html' | undefined
83→ flagSettingsPath: string | undefined
84→ flagSettingsInline: Record<string, unknown> | null
85→ allowedSettingSources: SettingSource[]
86→ sessionIngressToken: string | null | undefined
87→ oauthTokenFromFd: string | null | undefined
88→ apiKeyFromFd: string | null | undefined
89→ // Telemetry state
90→ meter: Meter | null
91→ sessionCounter: AttributedCounter | null
92→ locCounter: AttributedCounter | null
93→ prCounter: AttributedCounter | null
94→ commitCounter: AttributedCounter | null
95→ costCounter: AttributedCounter | null
96→ tokenCounter: AttributedCounter | null
97→ codeEditToolDecisionCounter: AttributedCounter | null
98→ activeTimeCounter: AttributedCounter | null
99→ statsStore: { observe(name: string, value: number): void } | null
100→ sessionId: SessionId
101→ // Parent session ID for tracking session lineage (e.g., plan mode -> implementation)
102→ parentSessionId: SessionId | undefined
103→ // Logger state
104→ loggerProvider: LoggerProvider | null
105→ eventLogger: ReturnType<typeof logs.getLogger> | null
106→ // Meter provider state
107→ meterProvider: MeterProvider | null
108→ // Tracer provider state
109→ tracerProvider: BasicTracerProvider | null
110→ // Agent color state
111→ agentColorMap: Map<string, AgentColorName>
112→ agentColorIndex: number
113→ // Last API request for bug reports
114→ lastAPIRequest: Omit<BetaMessageStreamParams, 'messages'> | null
115→ // Messages from the last API request (ant-only; reference, not clone).
116→ // Captures the exact post-compaction, CLAUDE.md-injected message set sent
117→ // to the API so /share's serialized_conversation.json reflects reality.
118→ lastAPIRequestMessages: BetaMessageStreamParams['messages'] | null
119→ // Last auto-mode classifier request(s) for /share transcript
120→ lastClassifierRequests: unknown[] | null
121→ // CLAUDE.md content cached by context.ts for the auto-mode classifier.
122→ // Breaks the yoloClassifier → claudemd → filesystem → permissions cycle.
123→ cachedClaudeMdContent: string | null
124→ // In-memory error log for recent errors
125→ inMemoryErrorLog: Array<{ error: string; timestamp: string }>
126→ // Session-only plugins from --plugin-dir flag
127→ inlinePlugins: Array<string>
128→ // Explicit --chrome / --no-chrome flag value (undefined = not set on CLI)
129→ chromeFlagOverride: boolean | undefined
130→ // Use cowork_plugins directory instead of plugins (--cowork flag or env var)
131→ useCoworkPlugins: boolean
132→ // Session-only bypass permissions mode flag (not persisted)
133→ sessionBypassPermissionsMode: boolean
134→ // Session-only flag gating the .claude/scheduled_tasks.json watcher
135→ // (useScheduledTasks). Set by cronScheduler.start() when the JSON has
136→ // entries, or by CronCreateTool. Not persisted.
137→ scheduledTasksEnabled: boolean
138→ // Session-only cron tasks created via CronCreate with durable: false.
139→ // Fire on schedule like file-backed tasks but are never written to
140→ // .claude/scheduled_tasks.json — they die with the process. Typed via
141→ // SessionCronTask below (not importing from cronTasks.ts keeps
142→ // bootstrap a leaf of the import DAG).
143→ sessionCronTasks: SessionCronTask[]
144→ // Teams created this session via TeamCreate. cleanupSessionTeams()
145→ // removes these on gracefulShutdown so subagent-created teams don't
146→ // persist on disk forever (gh-32730). TeamDelete removes entries to
147→ // avoid double-cleanup. Lives here (not teamHelpers.ts) so
148→ // resetStateForTests() clears it between tests.
149→ sessionCreatedTeams: Set<string>
150→ // Session-only trust flag for home directory (not persisted to disk)
151→ // When running from home dir, trust dialog is shown but not saved to disk.
152→ // This flag allows features requiring trust to work during the session.
153→ sessionTrustAccepted: boolean
154→ // Session-only flag to disable session persistence to disk
155→ sessionPersistenceDisabled: boolean
156→ // Track if user has exited plan mode in this session (for re-entry guidance)
157→ hasExitedPlanMode: boolean
158→ // Track if we need to show the plan mode exit attachment (one-time notification)
159→ needsPlanModeExitAttachment: boolean
160→ // Track if we need to show the auto mode exit attachment (one-time notification)
161→ needsAutoModeExitAttachment: boolean
162→ // Track if LSP plugin recommendation has been shown this session (only show once)
163→ lspRecommendationShownThisSession: boolean
164→ // SDK init event state - jsonSchema for structured output
165→ initJsonSchema: Record<string, unknown> | null
166→ // Registered hooks - SDK callbacks and plugin native hooks
167→ registeredHooks: Partial<Record<HookEvent, RegisteredHookMatcher[]>> | null
168→ // Cache for plan slugs: sessionId -> wordSlug
169→ planSlugCache: Map<string, string>
170→ // Track teleported session for reliability logging
171→ teleportedSessionInfo: {
172→ isTeleported: boolean
173→ hasLoggedFirstMessage: boolean
174→ sessionId: string | null
175→ } | null
176→ // Track invoked skills for preservation across compaction
177→ // Keys are composite: `${agentId ?? ''}:${skillName}` to prevent cross-agent overwrites
178→ invokedSkills: Map<
179→ string,
180→ {
181→ skillName: string
182→ skillPath: string
183→ content: string
184→ invokedAt: number
185→ agentId: string | null
186→ }
187→ >
188→ // Track slow operations for dev bar display (ant-only)
189→ slowOperations: Array<{
190→ operation: string
191→ durationMs: number
192→ timestamp: number
193→ }>
194→ // SDK-provided betas (e.g., context-1m-2025-08-07)
195→ sdkBetas: string[] | undefined
196→ // Main thread agent type (from --agent flag or settings)
197→ mainThreadAgentType: string | undefined
198→ // Remote mode (--remote flag)
199→ isRemoteMode: boolean
200→ // Direct connect server URL (for display in header)
201→ directConnectServerUrl: string | undefined
202→ // System prompt section cache state
203→ systemPromptSectionCache: Map<string, string | null>
204→ // Last date emitted to the model (for detecting midnight date changes)
205→ lastEmittedDate: string | null
206→ // Additional directories from --add-dir flag (for CLAUDE.md loading)
207→ additionalDirectoriesForClaudeMd: string[]
208→ // Channel server allowlist from --channels flag (servers whose channel
209→ // notifications should register this session). Parsed once in main.tsx —
210→ // the tag decides trust model: 'plugin' → marketplace verification +
211→ // allowlist, 'server' → allowlist always fails (schema is plugin-only).
212→ // Either kind needs entry.dev to bypass allowlist.
213→ allowedChannels: ChannelEntry[]
214→ // True if any entry in allowedChannels came from
215→ // --dangerously-load-development-channels (so ChannelsNotice can name the
216→ // right flag in policy-blocked messages)
217→ hasDevChannels: boolean
218→ // Dir containing the session's `.jsonl`; null = derive from originalCwd.
219→ sessionProjectDir: string | null
220→ // Cached prompt cache 1h TTL allowlist from GrowthBook (session-stable)
221→ promptCache1hAllowlist: string[] | null
222→ // Cached 1h TTL user eligibility (session-stable). Latched on first
223→ // evaluation so mid-session overage flips don't change the cache_control
224→ // TTL, which would bust the server-side prompt cache.
225→ promptCache1hEligible: boolean | null
226→ // Sticky-on latch for AFK_MODE_BETA_HEADER. Once auto mode is first
227→ // activated, keep sending the header for the rest of the session so
228→ // Shift+Tab toggles don't bust the ~50-70K token prompt cache.
229→ afkModeHeaderLatched: boolean | null
230→ // Sticky-on latch for FAST_MODE_BETA_HEADER. Once fast mode is first
231→ // enabled, keep sending the header so cooldown enter/exit doesn't
232→ // double-bust the prompt cache. The `speed` body param stays dynamic.
233→ fastModeHeaderLatched: boolean | null
234→ // Sticky-on latch for the cache-editing beta header. Once cached
235→ // microcompact is first enabled, keep sending the header so mid-session
236→ // GrowthBook/settings toggles don't bust the prompt cache.
237→ cacheEditingHeaderLatched: boolean | null
238→ // Sticky-on latch for clearing thinking from prior tool loops. Triggered
239→ // when >1h since last API call (confirmed cache miss — no cache-hit
240→ // benefit to keeping thinking). Once latched, stays on so the newly-warmed
241→ // thinking-cleared cache isn't busted by flipping back to keep:'all'.
242→ thinkingClearLatched: boolean | null
243→ // Current prompt ID (UUID) correlating a user prompt with subsequent OTel events
244→ promptId: string | null
245→ // Last API requestId for the main conversation chain (not subagents).
246→ // Updated after each successful API response for main-session queries.
247→ // Read at shutdown to send cache eviction hints to inference.
248→ lastMainRequestId: string | undefined
249→ // Timestamp (Date.now()) of the last successful API call completion.
250→ // Used to compute timeSinceLastApiCallMs in tengu_api_success for
251→ // correlating cache misses with idle time (cache TTL is ~5min).
252→ lastApiCompletionTimestamp: number | null
253→ // Set to true after compaction (auto or manual /compact). Consumed by
254→ // logAPISuccess to tag the first post-compaction API call so we can
255→ // distinguish compaction-induced cache misses from TTL expiry.
256→ pendingPostCompaction: boolean
257→}
258→
259→// ALSO HERE - THINK THRICE BEFORE MODIFYING
260→function getInitialState(): State {
261→ // Resolve symlinks in cwd to match behavior of shell.ts setCwd
262→ // This ensures consistency with how paths are sanitized for session storage
263→ let resolvedCwd = ''
264→ if (
265→ typeof process !== 'undefined' &&
266→ typeof process.cwd === 'function' &&
267→ typeof realpathSync === 'function'
268→ ) {
269→ const rawCwd = cwd()
270→ try {
271→ resolvedCwd = realpathSync(rawCwd).normalize('NFC')
272→ } catch {
273→ // File Provider EPERM on CloudStorage mounts (lstat per path component).
274→ resolvedCwd = rawCwd.normalize('NFC')
275→ }
276→ }
277→ const state: State = {
278→ originalCwd: resolvedCwd,
279→ projectRoot: resolvedCwd,
280→ totalCostUSD: 0,
281→ totalAPIDuration: 0,
282→ totalAPIDurationWithoutRetries: 0,
283→ totalToolDuration: 0,
284→ turnHookDurationMs: 0,
285→ turnToolDurationMs: 0,
286→ turnClassifierDurationMs: 0,
287→ turnToolCount: 0,
288→ turnHookCount: 0,
289→ turnClassifierCount: 0,
290→ startTime: Date.now(),
291→ lastInteractionTime: Date.now(),
292→ totalLinesAdded: 0,
293→ totalLinesRemoved: 0,
294→ hasUnknownModelCost: false,
295→ cwd: resolvedCwd,
296→ modelUsage: {},
297→ mainLoopModelOverride: undefined,
298→ initialMainLoopModel: null,
299→ modelStrings: null,
300→ isInteractive: false,
301→ kairosActive: false,
302→ strictToolResultPairing: false,
303→ sdkAgentProgressSummariesEnabled: false,
304→ userMsgOptIn: false,
305→ clientType: 'cli',
306→ sessionSource: undefined,
307→ questionPreviewFormat: undefined,
308→ sessionIngressToken: undefined,
309→ oauthTokenFromFd: undefined,
310→ apiKeyFromFd: undefined,
311→ flagSettingsPath: undefined,
312→ flagSettingsInline: null,
313→ allowedSettingSources: [
314→ 'userSettings',
315→ 'projectSettings',
316→ 'localSettings',
317→ 'flagSettings',
318→ 'policySettings',
319→ ],
320→ // Telemetry state
321→ meter: null,
322→ sessionCounter: null,
323→ locCounter: null,
324→ prCounter: null,
325→ commitCounter: null,
326→ costCounter: null,
327→ tokenCounter: null,
328→ codeEditToolDecisionCounter: null,
329→ activeTimeCounter: null,
330→ statsStore: null,
331→ sessionId: randomUUID() as SessionId,
332→ parentSessionId: undefined,
333→ // Logger state
334→ loggerProvider: null,
335→ eventLogger: null,
336→ // Meter provider state
337→ meterProvider: null,
338→ tracerProvider: null,
339→ // Agent color state
340→ agentColorMap: new Map(),
341→ agentColorIndex: 0,
342→ // Last API request for bug reports
343→ lastAPIRequest: null,
344→ lastAPIRequestMessages: null,
345→ // Last auto-mode classifier request(s) for /share transcript
346→ lastClassifierRequests: null,
347→ cachedClaudeMdContent: null,
348→ // In-memory error log for recent errors
349→ inMemoryErrorLog: [],
350→ // Session-only plugins from --plugin-dir flag
351→ inlinePlugins: [],
352→ // Explicit --chrome / --no-chrome flag value (undefined = not set on CLI)
353→ chromeFlagOverride: undefined,
354→ // Use cowork_plugins directory instead of plugins
355→ useCoworkPlugins: false,
356→ // Session-only bypass permissions mode flag (not persisted)
357→ sessionBypassPermissionsMode: false,
358→ // Scheduled tasks disabled until flag or dialog enables them
359→ scheduledTasksEnabled: false,
360→ sessionCronTasks: [],
361→ sessionCreatedTeams: new Set(),
362→ // Session-only trust flag (not persisted to disk)
363→ sessionTrustAccepted: false,
364→ // Session-only flag to disable session persistence to disk
365→ sessionPersistenceDisabled: false,
366→ // Track if user has exited plan mode in this session
367→ hasExitedPlanMode: false,
368→ // Track if we need to show the plan mode exit attachment
369→ needsPlanModeExitAttachment: false,
370→ // Track if we need to show the auto mode exit attachment
371→ needsAutoModeExitAttachment: false,
372→ // Track if LSP plugin recommendation has been shown this session
373→ lspRecommendationShownThisSession: false,
374→ // SDK init event state
375→ initJsonSchema: null,
376→ registeredHooks: null,
377→ // Cache for plan slugs
378→ planSlugCache: new Map(),
379→ // Track teleported session for reliability logging
380→ teleportedSessionInfo: null,
381→ // Track invoked skills for preservation across compaction
382→ invokedSkills: new Map(),
383→ // Track slow operations for dev bar display
384→ slowOperations: [],
385→ // SDK-provided betas
386→ sdkBetas: undefined,
387→ // Main thread agent type
388→ mainThreadAgentType: undefined,
389→ // Remote mode
390→ isRemoteMode: false,
391→ ...(process.env.USER_TYPE === 'ant'
392→ ? {
393→ replBridgeActive: false,
394→ }
395→ : {}),
396→ // Direct connect server URL
397→ directConnectServerUrl: undefined,
398→ // System prompt section cache state
399→ systemPromptSectionCache: new Map(),
400→ // Last date emitted to the model
401→ lastEmittedDate: null,
402→ // Additional directories from --add-dir flag (for CLAUDE.md loading)
403→ additionalDirectoriesForClaudeMd: [],
404→ // Channel server allowlist from --channels flag
405→ allowedChannels: [],
406→ hasDevChannels: false,
407→ // Session project dir (null = derive from originalCwd)
408→ sessionProjectDir: null,
409→ // Prompt cache 1h allowlist (null = not yet fetched from GrowthBook)
410→ promptCache1hAllowlist: null,
411→ // Prompt cache 1h eligibility (null = not yet evaluated)
412→ promptCache1hEligible: null,
413→ // Beta header latches (null = not yet triggered)
414→ afkModeHeaderLatched: null,
415→ fastModeHeaderLatched: null,
416→ cacheEditingHeaderLatched: null,
417→ thinkingClearLatched: null,
418→ // Current prompt ID
419→ promptId: null,
420→ lastMainRequestId: undefined,
421→ lastApiCompletionTimestamp: null,
422→ pendingPostCompaction: false,
423→ }
424→
425→ return state
426→}
427→
428→// AND ESPECIALLY HERE
429→const STATE: State = getInitialState()
430→
431→export function getSessionId(): SessionId {
432→ return STATE.sessionId
433→}
434→
435→export function regenerateSessionId(
436→ options: { setCurrentAsParent?: boolean } = {},
437→): SessionId {
438→ if (options.setCurrentAsParent) {
439→ STATE.parentSessionId = STATE.sessionId
440→ }
441→ // Drop the outgoing session's plan-slug entry so the Map doesn't
442→ // accumulate stale keys. Callers that need to carry the slug across
443→ // (REPL.tsx clearContext) read it before calling clearConversation.
444→ STATE.planSlugCache.delete(STATE.sessionId)
445→ // Regenerated sessions live in the current project: reset projectDir to
446→ // null so getTranscriptPath() derives from originalCwd.
447→ STATE.sessionId = randomUUID() as SessionId
448→ STATE.sessionProjectDir = null
449→ return STATE.sessionId
450→}
451→
452→export function getParentSessionId(): SessionId | undefined {
453→ return STATE.parentSessionId
454→}
455→
456→/**
457→ * Atomically switch the active session. `sessionId` and `sessionProjectDir`
458→ * always change together — there is no separate setter for either, so they
459→ * cannot drift out of sync (CC-34).
460→ *
461→ * @param projectDir — directory containing `<sessionId>.jsonl`. Omit (or
462→ * pass `null`) for sessions in the current project — the path will derive
463→ * from originalCwd at read time. Pass `dirname(transcriptPath)` when the
464→ * session lives in a different project directory (git worktrees,
465→ * cross-project resume). Every call resets the project dir; it never
466→ * carries over from the previous session.
467→ */
468→export function switchSession(
469→ sessionId: SessionId,
470→ projectDir: string | null = null,
471→): void {
472→ // Drop the outgoing session's plan-slug entry so the Map stays bounded
473→ // across repeated /resume. Only the current session's slug is ever read
474→ // (plans.ts getPlanSlug defaults to getSessionId()).
475→ STATE.planSlugCache.delete(STATE.sessionId)
476→ STATE.sessionId = sessionId
477→ STATE.sessionProjectDir = projectDir
478→ sessionSwitched.emit(sessionId)
479→}
480→
481→const sessionSwitched = createSignal<[id: SessionId]>()
482→
483→/**
484→ * Register a callback that fires when switchSession changes the active
485→ * sessionId. bootstrap can't import listeners directly (DAG leaf), so
486→ * callers register themselves. concurrentSessions.ts uses this to keep the
487→ * PID file's sessionId in sync with --resume.
488→ */
489→export const onSessionSwitch = sessionSwitched.subscribe
490→
491→/**
492→ * Project directory the current session's transcript lives in, or `null` if
493→ * the session was created in the current project (common case — derive from
494→ * originalCwd). See `switchSession()`.
495→ */
496→export function getSessionProjectDir(): string | null {
497→ return STATE.sessionProjectDir
498→}
499→
500→export function getOriginalCwd(): string {
501→ return STATE.originalCwd
502→}
503→
504→/**
505→ * Get the stable project root directory.
506→ * Unlike getOriginalCwd(), this is never updated by mid-session EnterWorktreeTool
507→ * (so skills/history stay stable when entering a throwaway worktree).
508→ * It IS set at startup by --worktree, since that worktree is the session's project.
509→ * Use for project identity (history, skills, sessions) not file operations.
510→ */
511→export function getProjectRoot(): string {
512→ return STATE.projectRoot
513→}
514→
515→export function setOriginalCwd(cwd: string): void {
516→ STATE.originalCwd = cwd.normalize('NFC')
517→}
518→
519→/**
520→ * Only for --worktree startup flag. Mid-session EnterWorktreeTool must NOT
521→ * call this — skills/history should stay anchored to where the session started.
522→ */
523→export function setProjectRoot(cwd: string): void {
524→ STATE.projectRoot = cwd.normalize('NFC')
525→}
526→
527→export function getCwdState(): string {
528→ return STATE.cwd
529→}
530→
531→export function setCwdState(cwd: string): void {
532→ STATE.cwd = cwd.normalize('NFC')
533→}
534→
535→export function getDirectConnectServerUrl(): string | undefined {
536→ return STATE.directConnectServerUrl
537→}
538→
539→export function setDirectConnectServerUrl(url: string): void {
540→ STATE.directConnectServerUrl = url
541→}
542→
543→export function addToTotalDurationState(
544→ duration: number,
545→ durationWithoutRetries: number,
546→): void {
547→ STATE.totalAPIDuration += duration
548→ STATE.totalAPIDurationWithoutRetries += durationWithoutRetries
549→}
550→
551→export function resetTotalDurationStateAndCost_FOR_TESTS_ONLY(): void {
552→ STATE.totalAPIDuration = 0
553→ STATE.totalAPIDurationWithoutRetries = 0
554→ STATE.totalCostUSD = 0
555→}
556→
557→export function addToTotalCostState(
558→ cost: number,
559→ modelUsage: ModelUsage,
560→ model: string,
561→): void {
562→ STATE.modelUsage[model] = modelUsage
563→ STATE.totalCostUSD += cost
564→}
565→
566→export function getTotalCostUSD(): number {
567→ return STATE.totalCostUSD
568→}
569→
570→export function getTotalAPIDuration(): number {
571→ return STATE.totalAPIDuration
572→}
573→
574→export function getTotalDuration(): number {
575→ return Date.now() - STATE.startTime
576→}
577→
578→export function getTotalAPIDurationWithoutRetries(): number {
579→ return STATE.totalAPIDurationWithoutRetries
580→}
581→
582→export function getTotalToolDuration(): number {
583→ return STATE.totalToolDuration
584→}
585→
586→export function addToToolDuration(duration: number): void {
587→ STATE.totalToolDuration += duration
588→ STATE.turnToolDurationMs += duration
589→ STATE.turnToolCount++
590→}
591→
592→export function getTurnHookDurationMs(): number {
593→ return STATE.turnHookDurationMs
594→}
595→
596→export function addToTurnHookDuration(duration: number): void {
597→ STATE.turnHookDurationMs += duration
598→ STATE.turnHookCount++
599→}
600→
601→export function resetTurnHookDuration(): void {
602→ STATE.turnHookDurationMs = 0
603→ STATE.turnHookCount = 0
604→}
605→
606→export function getTurnHookCount(): number {
607→ return STATE.turnHookCount
608→}
609→
610→export function getTurnToolDurationMs(): number {
611→ return STATE.turnToolDurationMs
612→}
613→
614→export function resetTurnToolDuration(): void {
615→ STATE.turnToolDurationMs = 0
616→ STATE.turnToolCount = 0
617→}
618→
619→export function getTurnToolCount(): number {
620→ return STATE.turnToolCount
621→}
622→
623→export function getTurnClassifierDurationMs(): number {
624→ return STATE.turnClassifierDurationMs
625→}
626→
627→export function addToTurnClassifierDuration(duration: number): void {
628→ STATE.turnClassifierDurationMs += duration
629→ STATE.turnClassifierCount++
630→}
631→
632→export function resetTurnClassifierDuration(): void {
633→ STATE.turnClassifierDurationMs = 0
634→ STATE.turnClassifierCount = 0
635→}
636→
637→export function getTurnClassifierCount(): number {
638→ return STATE.turnClassifierCount
639→}
640→
641→export function getStatsStore(): {
642→ observe(name: string, value: number): void
643→} | null {
644→ return STATE.statsStore
645→}
646→
647→export function setStatsStore(
648→ store: { observe(name: string, value: number): void } | null,
649→): void {
650→ STATE.statsStore = store
651→}
652→
653→/**
654→ * Marks that an interaction occurred.
655→ *
656→ * By default the actual Date.now() call is deferred until the next Ink render
657→ * frame (via flushInteractionTime()) so we avoid calling Date.now() on every
658→ * single keypress.
659→ *
660→ * Pass `immediate = true` when calling from React useEffect callbacks or
661→ * other code that runs *after* the Ink render cycle has already flushed.
662→ * Without it the timestamp stays stale until the next render, which may never
663→ * come if the user is idle (e.g. permission dialog waiting for input).
664→ */
665→let interactionTimeDirty = false
666→
667→export function updateLastInteractionTime(immediate?: boolean): void {
668→ if (immediate) {
669→ flushInteractionTime_inner()
670→ } else {
671→ interactionTimeDirty = true
672→ }
673→}
674→
675→/**
676→ * If an interaction was recorded since the last flush, update the timestamp
677→ * now. Called by Ink before each render cycle so we batch many keypresses into
678→ * a single Date.now() call.
679→ */
680→export function flushInteractionTime(): void {
681→ if (interactionTimeDirty) {
682→ flushInteractionTime_inner()
683→ }
684→}
685→
686→function flushInteractionTime_inner(): void {
687→ STATE.lastInteractionTime = Date.now()
688→ interactionTimeDirty = false
689→}
690→
691→export function addToTotalLinesChanged(added: number, removed: number): void {
692→ STATE.totalLinesAdded += added
693→ STATE.totalLinesRemoved += removed
694→}
695→
696→export function getTotalLinesAdded(): number {
697→ return STATE.totalLinesAdded
698→}
699→
700→export function getTotalLinesRemoved(): number {
701→ return STATE.totalLinesRemoved
702→}
703→
704→export function getTotalInputTokens(): number {
705→ return sumBy(Object.values(STATE.modelUsage), 'inputTokens')
706→}
707→
708→export function getTotalOutputTokens(): number {
709→ return sumBy(Object.values(STATE.modelUsage), 'outputTokens')
710→}
711→
712→export function getTotalCacheReadInputTokens(): number {
713→ return sumBy(Object.values(STATE.modelUsage), 'cacheReadInputTokens')
714→}
715→
716→export function getTotalCacheCreationInputTokens(): number {
717→ return sumBy(Object.values(STATE.modelUsage), 'cacheCreationInputTokens')
718→}
719→
720→export function getTotalWebSearchRequests(): number {
721→ return sumBy(Object.values(STATE.modelUsage), 'webSearchRequests')
722→}
723→
724→let outputTokensAtTurnStart = 0
725→let currentTurnTokenBudget: number | null = null
726→export function getTurnOutputTokens(): number {
727→ return getTotalOutputTokens() - outputTokensAtTurnStart
728→}
729→export function getCurrentTurnTokenBudget(): number | null {
730→ return currentTurnTokenBudget
731→}
732→let budgetContinuationCount = 0
733→export function snapshotOutputTokensForTurn(budget: number | null): void {
734→ outputTokensAtTurnStart = getTotalOutputTokens()
735→ currentTurnTokenBudget = budget
736→ budgetContinuationCount = 0
737→}
738→export function getBudgetContinuationCount(): number {
739→ return budgetContinuationCount
740→}
741→export function incrementBudgetContinuationCount(): void {
742→ budgetContinuationCount++
743→}
744→
745→export function setHasUnknownModelCost(): void {
746→ STATE.hasUnknownModelCost = true
747→}
748→
749→export function hasUnknownModelCost(): boolean {
750→ return STATE.hasUnknownModelCost
751→}
752→
753→export function getLastMainRequestId(): string | undefined {
754→ return STATE.lastMainRequestId
755→}
756→
757→export function setLastMainRequestId(requestId: string): void {
758→ STATE.lastMainRequestId = requestId
759→}
760→
761→export function getLastApiCompletionTimestamp(): number | null {
762→ return STATE.lastApiCompletionTimestamp
763→}
764→
765→export function setLastApiCompletionTimestamp(timestamp: number): void {
766→ STATE.lastApiCompletionTimestamp = timestamp
767→}
768→
769→/** Mark that a compaction just occurred. The next API success event will
770→ * include isPostCompaction=true, then the flag auto-resets. */
771→export function markPostCompaction(): void {
772→ STATE.pendingPostCompaction = true
773→}
774→
775→/** Consume the post-compaction flag. Returns true once after compaction,
776→ * then returns false until the next compaction. */
777→export function consumePostCompaction(): boolean {
778→ const was = STATE.pendingPostCompaction
779→ STATE.pendingPostCompaction = false
780→ return was
781→}
782→
783→export function getLastInteractionTime(): number {
784→ return STATE.lastInteractionTime
785→}
786→
787→// Scroll drain suspension — background intervals check this before doing work
788→// so they don't compete with scroll frames for the event loop. Set by
789→// ScrollBox scrollBy/scrollTo, cleared SCROLL_DRAIN_IDLE_MS after the last
790→// scroll event. Module-scope (not in STATE) — ephemeral hot-path flag, no
791→// test-reset needed since the debounce timer self-clears.
792→let scrollDraining = false
793→let scrollDrainTimer: ReturnType<typeof setTimeout> | undefined
794→const SCROLL_DRAIN_IDLE_MS = 150
795→
796→/** Mark that a scroll event just happened. Background intervals gate on
797→ * getIsScrollDraining() and skip their work until the debounce clears. */
798→export function markScrollActivity(): void {
799→ scrollDraining = true
800→ if (scrollDrainTimer) clearTimeout(scrollDrainTimer)
801→ scrollDrainTimer = setTimeout(() => {
802→ scrollDraining = false
803→ scrollDrainTimer = undefined
804→ }, SCROLL_DRAIN_IDLE_MS)
805→ scrollDrainTimer.unref?.()
806→}
807→
808→/** True while scroll is actively draining (within 150ms of last event).
809→ * Intervals should early-return when this is set — the work picks up next
810→ * tick after scroll settles. */
811→export function getIsScrollDraining(): boolean {
812→ return scrollDraining
813→}
814→
815→/** Await this before expensive one-shot work (network, subprocess) that could
816→ * coincide with scroll. Resolves immediately if not scrolling; otherwise
817→ * polls at the idle interval until the flag clears. */
818→export async function waitForScrollIdle(): Promise<void> {
819→ while (scrollDraining) {
820→ // bootstrap-isolation forbids importing sleep() from src/utils/
821→ // eslint-disable-next-line no-restricted-syntax
822→ await new Promise(r => setTimeout(r, SCROLL_DRAIN_IDLE_MS).unref?.())
823→ }
824→}
825→
826→export function getModelUsage(): { [modelName: string]: ModelUsage } {
827→ return STATE.modelUsage
828→}
829→
830→export function getUsageForModel(model: string): ModelUsage | undefined {
831→ return STATE.modelUsage[model]
832→}
833→
834→/**
835→ * Gets the model override set from the --model CLI flag or after the user
836→ * updates their configured model.
837→ */
838→export function getMainLoopModelOverride(): ModelSetting | undefined {
839→ return STATE.mainLoopModelOverride
840→}
841→
842→export function getInitialMainLoopModel(): ModelSetting {
843→ return STATE.initialMainLoopModel
844→}
845→
846→export function setMainLoopModelOverride(
847→ model: ModelSetting | undefined,
848→): void {
849→ STATE.mainLoopModelOverride = model
850→}
851→
852→export function setInitialMainLoopModel(model: ModelSetting): void {
853→ STATE.initialMainLoopModel = model
854→}
855→
856→export function getSdkBetas(): string[] | undefined {
857→ return STATE.sdkBetas
858→}
859→
860→export function setSdkBetas(betas: string[] | undefined): void {
861→ STATE.sdkBetas = betas
862→}
863→
864→export function resetCostState(): void {
865→ STATE.totalCostUSD = 0
866→ STATE.totalAPIDuration = 0
867→ STATE.totalAPIDurationWithoutRetries = 0
868→ STATE.totalToolDuration = 0
869→ STATE.startTime = Date.now()
870→ STATE.totalLinesAdded = 0
871→ STATE.totalLinesRemoved = 0
872→ STATE.hasUnknownModelCost = false
873→ STATE.modelUsage = {}
874→ STATE.promptId = null
875→}
876→
877→/**
878→ * Sets cost state values for session restore.
879→ * Called by restoreCostStateForSession in cost-tracker.ts.
880→ */
881→export function setCostStateForRestore({
882→ totalCostUSD,
883→ totalAPIDuration,
884→ totalAPIDurationWithoutRetries,
885→ totalToolDuration,
886→ totalLinesAdded,
887→ totalLinesRemoved,
888→ lastDuration,
889→ modelUsage,
890→}: {
891→ totalCostUSD: number
892→ totalAPIDuration: number
893→ totalAPIDurationWithoutRetries: number
894→ totalToolDuration: number
895→ totalLinesAdded: number
896→ totalLinesRemoved: number
897→ lastDuration: number | undefined
898→ modelUsage: { [modelName: string]: ModelUsage } | undefined
899→}): void {
900→ STATE.totalCostUSD = totalCostUSD
901→ STATE.totalAPIDuration = totalAPIDuration
902→ STATE.totalAPIDurationWithoutRetries = totalAPIDurationWithoutRetries
903→ STATE.totalToolDuration = totalToolDuration
904→ STATE.totalLinesAdded = totalLinesAdded
905→ STATE.totalLinesRemoved = totalLinesRemoved
906→
907→ // Restore per-model usage breakdown
908→ if (modelUsage) {
909→ STATE.modelUsage = modelUsage
910→ }
911→
912→ // Adjust startTime to make wall duration accumulate
913→ if (lastDuration) {
914→ STATE.startTime = Date.now() - lastDuration
915→ }
916→}
917→
918→// Only used in tests
919→export function resetStateForTests(): void {
920→ if (process.env.NODE_ENV !== 'test') {
921→ throw new Error('resetStateForTests can only be called in tests')
922→ }
923→ Object.entries(getInitialState()).forEach(([key, value]) => {
924→ STATE[key as keyof State] = value as never
925→ })
926→ outputTokensAtTurnStart = 0
927→ currentTurnTokenBudget = null
928→ budgetContinuationCount = 0
929→ sessionSwitched.clear()
930→}
931→
932→// You shouldn't use this directly. See src/utils/model/modelStrings.ts::getModelStrings()
933→export function getModelStrings(): ModelStrings | null {
934→ return STATE.modelStrings
935→}
936→
937→// You shouldn't use this directly. See src/utils/model/modelStrings.ts
938→export function setModelStrings(modelStrings: ModelStrings): void {
939→ STATE.modelStrings = modelStrings
940→}
941→
942→// Test utility function to reset model strings for re-initialization.
943→// Separate from setModelStrings because we only want to accept 'null' in tests.
944→export function resetModelStringsForTestingOnly() {
945→ STATE.modelStrings = null
946→}
947→
948→export function setMeter(
949→ meter: Meter,
950→ createCounter: (name: string, options: MetricOptions) => AttributedCounter,
951→): void {
952→ STATE.meter = meter
953→
954→ // Initialize all counters using the provided factory
955→ STATE.sessionCounter = createCounter('claude_code.session.count', {
956→ description: 'Count of CLI sessions started',
957→ })
958→ STATE.locCounter = createCounter('claude_code.lines_of_code.count', {
959→ description:
960→ "Count of lines of code modified, with the 'type' attribute indicating whether lines were added or removed",
961→ })
962→ STATE.prCounter = createCounter('claude_code.pull_request.count', {
963→ description: 'Number of pull requests created',
964→ })
965→ STATE.commitCounter = createCounter('claude_code.commit.count', {
966→ description: 'Number of git commits created',
967→ })
968→ STATE.costCounter = createCounter('claude_code.cost.usage', {
969→ description: 'Cost of the Claude Code session',
970→ unit: 'USD',
971→ })
972→ STATE.tokenCounter = createCounter('claude_code.token.usage', {
973→ description: 'Number of tokens used',
974→ unit: 'tokens',
975→ })
976→ STATE.codeEditToolDecisionCounter = createCounter(
977→ 'claude_code.code_edit_tool.decision',
978→ {
979→ description:
980→ 'Count of code editing tool permission decisions (accept/reject) for Edit, Write, and NotebookEdit tools',
981→ },
982→ )
983→ STATE.activeTimeCounter = createCounter('claude_code.active_time.total', {
984→ description: 'Total active time in seconds',
985→ unit: 's',
986→ })
987→}
988→
989→export function getMeter(): Meter | null {
990→ return STATE.meter
991→}
992→
993→export function getSessionCounter(): AttributedCounter | null {
994→ return STATE.sessionCounter
995→}
996→
997→export function getLocCounter(): AttributedCounter | null {
998→ return STATE.locCounter
999→}
1000→
1001→export function getPrCounter(): AttributedCounter | null {
1002→ return STATE.prCounter
1003→}
1004→
1005→export function getCommitCounter(): AttributedCounter | null {
1006→ return STATE.commitCounter
1007→}
1008→
1009→export function getCostCounter(): AttributedCounter | null {
1010→ return STATE.costCounter
1011→}
1012→
1013→export function getTokenCounter(): AttributedCounter | null {
1014→ return STATE.tokenCounter
1015→}
1016→
1017→export function getCodeEditToolDecisionCounter(): AttributedCounter | null {
1018→ return STATE.codeEditToolDecisionCounter
1019→}
1020→
1021→export function getActiveTimeCounter(): AttributedCounter | null {
1022→ return STATE.activeTimeCounter
1023→}
1024→
1025→export function getLoggerProvider(): LoggerProvider | null {
1026→ return STATE.loggerProvider
1027→}
1028→
1029→export function setLoggerProvider(provider: LoggerProvider | null): void {
1030→ STATE.loggerProvider = provider
1031→}
1032→
1033→export function getEventLogger(): ReturnType<typeof logs.getLogger> | null {
1034→ return STATE.eventLogger
1035→}
1036→
1037→export function setEventLogger(
1038→ logger: ReturnType<typeof logs.getLogger> | null,
1039→): void {
1040→ STATE.eventLogger = logger
1041→}
1042→
1043→export function getMeterProvider(): MeterProvider | null {
1044→ return STATE.meterProvider
1045→}
1046→
1047→export function setMeterProvider(provider: MeterProvider | null): void {
1048→ STATE.meterProvider = provider
1049→}
1050→export function getTracerProvider(): BasicTracerProvider | null {
1051→ return STATE.tracerProvider
1052→}
1053→export function setTracerProvider(provider: BasicTracerProvider | null): void {
1054→ STATE.tracerProvider = provider
1055→}
1056→
1057→export function getIsNonInteractiveSession(): boolean {
1058→ return !STATE.isInteractive
1059→}
1060→
1061→export function getIsInteractive(): boolean {
1062→ return STATE.isInteractive
1063→}
1064→
1065→export function setIsInteractive(value: boolean): void {
1066→ STATE.isInteractive = value
1067→}
1068→
1069→export function getClientType(): string {
1070→ return STATE.clientType
1071→}
1072→
1073→export function setClientType(type: string): void {
1074→ STATE.clientType = type
1075→}
1076→
1077→export function getSdkAgentProgressSummariesEnabled(): boolean {
1078→ return STATE.sdkAgentProgressSummariesEnabled
1079→}
1080→
1081→export function setSdkAgentProgressSummariesEnabled(value: boolean): void {
1082→ STATE.sdkAgentProgressSummariesEnabled = value
1083→}
1084→
1085→export function getKairosActive(): boolean {
1086→ return STATE.kairosActive
1087→}
1088→
1089→export function setKairosActive(value: boolean): void {
1090→ STATE.kairosActive = value
1091→}
1092→
1093→export function getStrictToolResultPairing(): boolean {
1094→ return STATE.strictToolResultPairing
1095→}
1096→
1097→export function setStrictToolResultPairing(value: boolean): void {
1098→ STATE.strictToolResultPairing = value
1099→}
1100→
1101→// Field name 'userMsgOptIn' avoids excluded-string substrings ('BriefTool',
1102→// 'SendUserMessage' — case-insensitive). All callers are inside feature()
1103→// guards so these accessors don't need their own (matches getKairosActive).
1104→export function getUserMsgOptIn(): boolean {
1105→ return STATE.userMsgOptIn
1106→}
1107→
1108→export function setUserMsgOptIn(value: boolean): void {
1109→ STATE.userMsgOptIn = value
1110→}
1111→
1112→export function getSessionSource(): string | undefined {
1113→ return STATE.sessionSource
1114→}
1115→
1116→export function setSessionSource(source: string): void {
1117→ STATE.sessionSource = source
1118→}
1119→
1120→export function getQuestionPreviewFormat(): 'markdown' | 'html' | undefined {
1121→ return STATE.questionPreviewFormat
1122→}
1123→
1124→export function setQuestionPreviewFormat(format: 'markdown' | 'html'): void {
1125→ STATE.questionPreviewFormat = format
1126→}
1127→
1128→export function getAgentColorMap(): Map<string, AgentColorName> {
1129→ return STATE.agentColorMap
1130→}
1131→
1132→export function getFlagSettingsPath(): string | undefined {
1133→ return STATE.flagSettingsPath
1134→}
1135→
1136→export function setFlagSettingsPath(path: string | undefined): void {
1137→ STATE.flagSettingsPath = path
1138→}
1139→
1140→export function getFlagSettingsInline(): Record<string, unknown> | null {
1141→ return STATE.flagSettingsInline
1142→}
1143→
1144→export function setFlagSettingsInline(
1145→ settings: Record<string, unknown> | null,
1146→): void {
1147→ STATE.flagSettingsInline = settings
1148→}
1149→
1150→export function getSessionIngressToken(): string | null | undefined {
1151→ return STATE.sessionIngressToken
1152→}
1153→
1154→export function setSessionIngressToken(token: string | null): void {
1155→ STATE.sessionIngressToken = token
1156→}
1157→
1158→export function getOauthTokenFromFd(): string | null | undefined {
1159→ return STATE.oauthTokenFromFd
1160→}
1161→
1162→export function setOauthTokenFromFd(token: string | null): void {
1163→ STATE.oauthTokenFromFd = token
1164→}
1165→
1166→export function getApiKeyFromFd(): string | null | undefined {
1167→ return STATE.apiKeyFromFd
1168→}
1169→
1170→export function setApiKeyFromFd(key: string | null): void {
1171→ STATE.apiKeyFromFd = key
1172→}
1173→
1174→export function setLastAPIRequest(
1175→ params: Omit<BetaMessageStreamParams, 'messages'> | null,
1176→): void {
1177→ STATE.lastAPIRequest = params
1178→}
1179→
1180→export function getLastAPIRequest(): Omit<
1181→ BetaMessageStreamParams,
1182→ 'messages'
1183→> | null {
1184→ return STATE.lastAPIRequest
1185→}
1186→
1187→export function setLastAPIRequestMessages(
1188→ messages: BetaMessageStreamParams['messages'] | null,
1189→): void {
1190→ STATE.lastAPIRequestMessages = messages
1191→}
1192→
1193→export function getLastAPIRequestMessages():
1194→ | BetaMessageStreamParams['messages']
1195→ | null {
1196→ return STATE.lastAPIRequestMessages
1197→}
1198→
1199→export function setLastClassifierRequests(requests: unknown[] | null): void {
1200→ STATE.lastClassifierRequests = requests
1201→}
1202→
1203→export function getLastClassifierRequests(): unknown[] | null {
1204→ return STATE.lastClassifierRequests
1205→}
1206→
1207→export function setCachedClaudeMdContent(content: string | null): void {
1208→ STATE.cachedClaudeMdContent = content
1209→}
1210→
1211→export function getCachedClaudeMdContent(): string | null {
1212→ return STATE.cachedClaudeMdContent
1213→}
1214→
1215→export function addToInMemoryErrorLog(errorInfo: {
1216→ error: string
1217→ timestamp: string
1218→}): void {
1219→ const MAX_IN_MEMORY_ERRORS = 100
1220→ if (STATE.inMemoryErrorLog.length >= MAX_IN_MEMORY_ERRORS) {
1221→ STATE.inMemoryErrorLog.shift() // Remove oldest error
1222→ }
1223→ STATE.inMemoryErrorLog.push(errorInfo)
1224→}
1225→
1226→export function getAllowedSettingSources(): SettingSource[] {
1227→ return STATE.allowedSettingSources
1228→}
1229→
1230→export function setAllowedSettingSources(sources: SettingSource[]): void {
1231→ STATE.allowedSettingSources = sources
1232→}
1233→
1234→export function preferThirdPartyAuthentication(): boolean {
1235→ // IDE extension should behave as 1P for authentication reasons.
1236→ return getIsNonInteractiveSession() && STATE.clientType !== 'claude-vscode'
1237→}
1238→
1239→export function setInlinePlugins(plugins: Array<string>): void {
1240→ STATE.inlinePlugins = plugins
1241→}
1242→
1243→export function getInlinePlugins(): Array<string> {
1244→ return STATE.inlinePlugins
1245→}
1246→
1247→export function setChromeFlagOverride(value: boolean | undefined): void {
1248→ STATE.chromeFlagOverride = value
1249→}
1250→
1251→export function getChromeFlagOverride(): boolean | undefined {
1252→ return STATE.chromeFlagOverride
1253→}
1254→
1255→export function setUseCoworkPlugins(value: boolean): void {
1256→ STATE.useCoworkPlugins = value
1257→ resetSettingsCache()
1258→}
1259→
1260→export function getUseCoworkPlugins(): boolean {
1261→ return STATE.useCoworkPlugins
1262→}
1263→
1264→export function setSessionBypassPermissionsMode(enabled: boolean): void {
1265→ STATE.sessionBypassPermissionsMode = enabled
1266→}
1267→
1268→export function getSessionBypassPermissionsMode(): boolean {
1269→ return STATE.sessionBypassPermissionsMode
1270→}
1271→
1272→export function setScheduledTasksEnabled(enabled: boolean): void {
1273→ STATE.scheduledTasksEnabled = enabled
1274→}
1275→
1276→export function getScheduledTasksEnabled(): boolean {
1277→ return STATE.scheduledTasksEnabled
1278→}
1279→
1280→export type SessionCronTask = {
1281→ id: string
1282→ cron: string
1283→ prompt: string
1284→ createdAt: number
1285→ recurring?: boolean
1286→ /**
1287→ * When set, the task was created by an in-process teammate (not the team lead).
1288→ * The scheduler routes fires to that teammate's pendingUserMessages queue
1289→ * instead of the main REPL command queue. Session-only — never written to disk.
1290→ */
1291→ agentId?: string
1292→}
1293→
1294→export function getSessionCronTasks(): SessionCronTask[] {
1295→ return STATE.sessionCronTasks
1296→}
1297→
1298→export function addSessionCronTask(task: SessionCronTask): void {
1299→ STATE.sessionCronTasks.push(task)
1300→}
1301→
1302→/**
1303→ * Returns the number of tasks actually removed. Callers use this to skip
1304→ * downstream work (e.g. the disk read in removeCronTasks) when all ids
1305→ * were accounted for here.
1306→ */
1307→export function removeSessionCronTasks(ids: readonly string[]): number {
1308→ if (ids.length === 0) return 0
1309→ const idSet = new Set(ids)
1310→ const remaining = STATE.sessionCronTasks.filter(t => !idSet.has(t.id))
1311→ const removed = STATE.sessionCronTasks.length - remaining.length
1312→ if (removed === 0) return 0
1313→ STATE.sessionCronTasks = remaining
1314→ return removed
1315→}
1316→
1317→export function setSessionTrustAccepted(accepted: boolean): void {
1318→ STATE.sessionTrustAccepted = accepted
1319→}
1320→
1321→export function getSessionTrustAccepted(): boolean {
1322→ return STATE.sessionTrustAccepted
1323→}
1324→
1325→export function setSessionPersistenceDisabled(disabled: boolean): void {
1326→ STATE.sessionPersistenceDisabled = disabled
1327→}
1328→
1329→export function isSessionPersistenceDisabled(): boolean {
1330→ return STATE.sessionPersistenceDisabled
1331→}
1332→
1333→export function hasExitedPlanModeInSession(): boolean {
1334→ return STATE.hasExitedPlanMode
1335→}
1336→
1337→export function setHasExitedPlanMode(value: boolean): void {
1338→ STATE.hasExitedPlanMode = value
1339→}
1340→
1341→export function needsPlanModeExitAttachment(): boolean {
1342→ return STATE.needsPlanModeExitAttachment
1343→}
1344→
1345→export function setNeedsPlanModeExitAttachment(value: boolean): void {
1346→ STATE.needsPlanModeExitAttachment = value
1347→}
1348→
1349→export function handlePlanModeTransition(
1350→ fromMode: string,
1351→ toMode: string,
1352→): void {
1353→ // If switching TO plan mode, clear any pending exit attachment
1354→ // This prevents sending both plan_mode and plan_mode_exit when user toggles quickly
1355→ if (toMode === 'plan' && fromMode !== 'plan') {
1356→ STATE.needsPlanModeExitAttachment = false
1357→ }
1358→
1359→ // If switching out of plan mode, trigger the plan_mode_exit attachment
1360→ if (fromMode === 'plan' && toMode !== 'plan') {
1361→ STATE.needsPlanModeExitAttachment = true
1362→ }
1363→}
1364→
1365→export function needsAutoModeExitAttachment(): boolean {
1366→ return STATE.needsAutoModeExitAttachment
1367→}
1368→
1369→export function setNeedsAutoModeExitAttachment(value: boolean): void {
1370→ STATE.needsAutoModeExitAttachment = value
1371→}
1372→
1373→export function handleAutoModeTransition(
1374→ fromMode: string,
1375→ toMode: string,
1376→): void {
1377→ // Auto↔plan transitions are handled by prepareContextForPlanMode (auto may
1378→ // stay active through plan if opted in) and ExitPlanMode (restores mode).
1379→ // Skip both directions so this function only handles direct auto transitions.
1380→ if (
1381→ (fromMode === 'auto' && toMode === 'plan') ||
1382→ (fromMode === 'plan' && toMode === 'auto')
1383→ ) {
1384→ return
1385→ }
1386→ const fromIsAuto = fromMode === 'auto'
1387→ const toIsAuto = toMode === 'auto'
1388→
1389→ // If switching TO auto mode, clear any pending exit attachment
1390→ // This prevents sending both auto_mode and auto_mode_exit when user toggles quickly
1391→ if (toIsAuto && !fromIsAuto) {
1392→ STATE.needsAutoModeExitAttachment = false
1393→ }
1394→
1395→ // If switching out of auto mode, trigger the auto_mode_exit attachment
1396→ if (fromIsAuto && !toIsAuto) {
1397→ STATE.needsAutoModeExitAttachment = true
1398→ }
1399→}
1400→
1401→// LSP plugin recommendation session tracking
1402→export function hasShownLspRecommendationThisSession(): boolean {
1403→ return STATE.lspRecommendationShownThisSession
1404→}
1405→
1406→export function setLspRecommendationShownThisSession(value: boolean): void {
1407→ STATE.lspRecommendationShownThisSession = value
1408→}
1409→
1410→// SDK init event state
1411→export function setInitJsonSchema(schema: Record<string, unknown>): void {
1412→ STATE.initJsonSchema = schema
1413→}
1414→
1415→export function getInitJsonSchema(): Record<string, unknown> | null {
1416→ return STATE.initJsonSchema
1417→}
1418→
1419→export function registerHookCallbacks(
1420→ hooks: Partial<Record<HookEvent, RegisteredHookMatcher[]>>,
1421→): void {
1422→ if (!STATE.registeredHooks) {
1423→ STATE.registeredHooks = {}
1424→ }
1425→
1426→ // `registerHookCallbacks` may be called multiple times, so we need to merge (not overwrite)
1427→ for (const [event, matchers] of Object.entries(hooks)) {
1428→ const eventKey = event as HookEvent
1429→ if (!STATE.registeredHooks[eventKey]) {
1430→ STATE.registeredHooks[eventKey] = []
1431→ }
1432→ STATE.registeredHooks[eventKey]!.push(...matchers)
1433→ }
1434→}
1435→
1436→export function getRegisteredHooks(): Partial<
1437→ Record<HookEvent, RegisteredHookMatcher[]>
1438→> | null {
1439→ return STATE.registeredHooks
1440→}
1441→
1442→export function clearRegisteredHooks(): void {
1443→ STATE.registeredHooks = null
1444→}
1445→
1446→export function clearRegisteredPluginHooks(): void {
1447→ if (!STATE.registeredHooks) {
1448→ return
1449→ }
1450→
1451→ const filtered: Partial<Record<HookEvent, RegisteredHookMatcher[]>> = {}
1452→ for (const [event, matchers] of Object.entries(STATE.registeredHooks)) {
1453→ // Keep only callback hooks (those without pluginRoot)
1454→ const callbackHooks = matchers.filter(m => !('pluginRoot' in m))
1455→ if (callbackHooks.length > 0) {
1456→ filtered[event as HookEvent] = callbackHooks
1457→ }
1458→ }
1459→
1460→ STATE.registeredHooks = Object.keys(filtered).length > 0 ? filtered : null
1461→}
1462→
1463→export function resetSdkInitState(): void {
1464→ STATE.initJsonSchema = null
1465→ STATE.registeredHooks = null
1466→}
1467→
1468→export function getPlanSlugCache(): Map<string, string> {
1469→ return STATE.planSlugCache
1470→}
1471→
1472→export function getSessionCreatedTeams(): Set<string> {
1473→ return STATE.sessionCreatedTeams
1474→}
1475→
1476→// Teleported session tracking for reliability logging
1477→export function setTeleportedSessionInfo(info: {
1478→ sessionId: string | null
1479→}): void {
1480→ STATE.teleportedSessionInfo = {
1481→ isTeleported: true,
1482→ hasLoggedFirstMessage: false,
1483→ sessionId: info.sessionId,
1484→ }
1485→}
1486→
1487→export function getTeleportedSessionInfo(): {
1488→ isTeleported: boolean
1489→ hasLoggedFirstMessage: boolean
1490→ sessionId: string | null
1491→} | null {
1492→ return STATE.teleportedSessionInfo
1493→}
1494→
1495→export function markFirstTeleportMessageLogged(): void {
1496→ if (STATE.teleportedSessionInfo) {
1497→ STATE.teleportedSessionInfo.hasLoggedFirstMessage = true
1498→ }
1499→}
1500→
1501→// Invoked skills tracking for preservation across compaction
1502→export type InvokedSkillInfo = {
1503→ skillName: string
1504→ skillPath: string
1505→ content: string
1506→ invokedAt: number
1507→ agentId: string | null
1508→}
1509→
1510→export function addInvokedSkill(
1511→ skillName: string,
1512→ skillPath: string,
1513→ content: string,
1514→ agentId: string | null = null,
1515→): void {
1516→ const key = `${agentId ?? ''}:${skillName}`
1517→ STATE.invokedSkills.set(key, {
1518→ skillName,
1519→ skillPath,
1520→ content,
1521→ invokedAt: Date.now(),
1522→ agentId,
1523→ })
1524→}
1525→
1526→export function getInvokedSkills(): Map<string, InvokedSkillInfo> {
1527→ return STATE.invokedSkills
1528→}
1529→
1530→export function getInvokedSkillsForAgent(
1531→ agentId: string | undefined | null,
1532→): Map<string, InvokedSkillInfo> {
1533→ const normalizedId = agentId ?? null
1534→ const filtered = new Map<string, InvokedSkillInfo>()
1535→ for (const [key, skill] of STATE.invokedSkills) {
1536→ if (skill.agentId === normalizedId) {
1537→ filtered.set(key, skill)
1538→ }
1539→ }
1540→ return filtered
1541→}
1542→
1543→export function clearInvokedSkills(
1544→ preservedAgentIds?: ReadonlySet<string>,
1545→): void {
1546→ if (!preservedAgentIds || preservedAgentIds.size === 0) {
1547→ STATE.invokedSkills.clear()
1548→ return
1549→ }
1550→ for (const [key, skill] of STATE.invokedSkills) {
1551→ if (skill.agentId === null || !preservedAgentIds.has(skill.agentId)) {
1552→ STATE.invokedSkills.delete(key)
1553→ }
1554→ }
1555→}
1556→
1557→export function clearInvokedSkillsForAgent(agentId: string): void {
1558→ for (const [key, skill] of STATE.invokedSkills) {
1559→ if (skill.agentId === agentId) {
1560→ STATE.invokedSkills.delete(key)
1561→ }
1562→ }
1563→}
1564→
1565→// Slow operations tracking for dev bar
1566→const MAX_SLOW_OPERATIONS = 10
1567→const SLOW_OPERATION_TTL_MS = 10000
1568→
1569→export function addSlowOperation(operation: string, durationMs: number): void {
1570→ if (process.env.USER_TYPE !== 'ant') return
1571→ // Skip tracking for editor sessions (user editing a prompt file in $EDITOR)
1572→ // These are intentionally slow since the user is drafting text
1573→ if (operation.includes('exec') && operation.includes('claude-prompt-')) {
1574→ return
1575→ }
1576→ const now = Date.now()
1577→ // Remove stale operations
1578→ STATE.slowOperations = STATE.slowOperations.filter(
1579→ op => now - op.timestamp < SLOW_OPERATION_TTL_MS,
1580→ )
1581→ // Add new operation
1582→ STATE.slowOperations.push({ operation, durationMs, timestamp: now })
1583→ // Keep only the most recent operations
1584→ if (STATE.slowOperations.length > MAX_SLOW_OPERATIONS) {
1585→ STATE.slowOperations = STATE.slowOperations.slice(-MAX_SLOW_OPERATIONS)
1586→ }
1587→}
1588→
1589→const EMPTY_SLOW_OPERATIONS: ReadonlyArray<{
1590→ operation: string
1591→ durationMs: number
1592→ timestamp: number
1593→}> = []
1594→
1595→export function getSlowOperations(): ReadonlyArray<{
1596→ operation: string
1597→ durationMs: number
1598→ timestamp: number
1599→}> {
1600→ // Most common case: nothing tracked. Return a stable reference so the
1601→ // caller's setState() can bail via Object.is instead of re-rendering at 2fps.
1602→ if (STATE.slowOperations.length === 0) {
1603→ return EMPTY_SLOW_OPERATIONS
1604→ }
1605→ const now = Date.now()
1606→ // Only allocate a new array when something actually expired; otherwise keep
1607→ // the reference stable across polls while ops are still fresh.
1608→ if (
1609→ STATE.slowOperations.some(op => now - op.timestamp >= SLOW_OPERATION_TTL_MS)
1610→ ) {
1611→ STATE.slowOperations = STATE.slowOperations.filter(
1612→ op => now - op.timestamp < SLOW_OPERATION_TTL_MS,
1613→ )
1614→ if (STATE.slowOperations.length === 0) {
1615→ return EMPTY_SLOW_OPERATIONS
1616→ }
1617→ }
1618→ // Safe to return directly: addSlowOperation() reassigns STATE.slowOperations
1619→ // before pushing, so the array held in React state is never mutated.
1620→ return STATE.slowOperations
1621→}
1622→
1623→export function getMainThreadAgentType(): string | undefined {
1624→ return STATE.mainThreadAgentType
1625→}
1626→
1627→export function setMainThreadAgentType(agentType: string | undefined): void {
1628→ STATE.mainThreadAgentType = agentType
1629→}
1630→
1631→export function getIsRemoteMode(): boolean {
1632→ return STATE.isRemoteMode
1633→}
1634→
1635→export function setIsRemoteMode(value: boolean): void {
1636→ STATE.isRemoteMode = value
1637→}
1638→
1639→// System prompt section accessors
1640→
1641→export function getSystemPromptSectionCache(): Map<string, string | null> {
1642→ return STATE.systemPromptSectionCache
1643→}
1644→
1645→export function setSystemPromptSectionCacheEntry(
1646→ name: string,
1647→ value: string | null,
1648→): void {
1649→ STATE.systemPromptSectionCache.set(name, value)
1650→}
1651→
1652→export function clearSystemPromptSectionState(): void {
1653→ STATE.systemPromptSectionCache.clear()
1654→}
1655→
1656→// Last emitted date accessors (for detecting midnight date changes)
1657→
1658→export function getLastEmittedDate(): string | null {
1659→ return STATE.lastEmittedDate
1660→}
1661→
1662→export function setLastEmittedDate(date: string | null): void {
1663→ STATE.lastEmittedDate = date
1664→}
1665→
1666→export function getAdditionalDirectoriesForClaudeMd(): string[] {
1667→ return STATE.additionalDirectoriesForClaudeMd
1668→}
1669→
1670→export function setAdditionalDirectoriesForClaudeMd(
1671→ directories: string[],
1672→): void {
1673→ STATE.additionalDirectoriesForClaudeMd = directories
1674→}
1675→
1676→export function getAllowedChannels(): ChannelEntry[] {
1677→ return STATE.allowedChannels
1678→}
1679→
1680→export function setAllowedChannels(entries: ChannelEntry[]): void {
1681→ STATE.allowedChannels = entries
1682→}
1683→
1684→export function getHasDevChannels(): boolean {
1685→ return STATE.hasDevChannels
1686→}
1687→
1688→export function setHasDevChannels(value: boolean): void {
1689→ STATE.hasDevChannels = value
1690→}
1691→
1692→export function getPromptCache1hAllowlist(): string[] | null {
1693→ return STATE.promptCache1hAllowlist
1694→}
1695→
1696→export function setPromptCache1hAllowlist(allowlist: string[] | null): void {
1697→ STATE.promptCache1hAllowlist = allowlist
1698→}
1699→
1700→export function getPromptCache1hEligible(): boolean | null {
1701→ return STATE.promptCache1hEligible
1702→}
1703→
1704→export function setPromptCache1hEligible(eligible: boolean | null): void {
1705→ STATE.promptCache1hEligible = eligible
1706→}
1707→
1708→export function getAfkModeHeaderLatched(): boolean | null {
1709→ return STATE.afkModeHeaderLatched
1710→}
1711→
1712→export function setAfkModeHeaderLatched(v: boolean): void {
1713→ STATE.afkModeHeaderLatched = v
1714→}
1715→
1716→export function getFastModeHeaderLatched(): boolean | null {
1717→ return STATE.fastModeHeaderLatched
1718→}
1719→
1720→export function setFastModeHeaderLatched(v: boolean): void {
1721→ STATE.fastModeHeaderLatched = v
1722→}
1723→
1724→export function getCacheEditingHeaderLatched(): boolean | null {
1725→ return STATE.cacheEditingHeaderLatched
1726→}
1727→
1728→export function setCacheEditingHeaderLatched(v: boolean): void {
1729→ STATE.cacheEditingHeaderLatched = v
1730→}
1731→
1732→export function getThinkingClearLatched(): boolean | null {
1733→ return STATE.thinkingClearLatched
1734→}
1735→
1736→export function setThinkingClearLatched(v: boolean): void {
1737→ STATE.thinkingClearLatched = v
1738→}
1739→
1740→/**
1741→ * Reset beta header latches to null. Called on /clear and /compact so a
1742→ * fresh conversation gets fresh header evaluation.
1743→ */
1744→export function clearBetaHeaderLatches(): void {
1745→ STATE.afkModeHeaderLatched = null
1746→ STATE.fastModeHeaderLatched = null
1747→ STATE.cacheEditingHeaderLatched = null
1748→ STATE.thinkingClearLatched = null
1749→}
1750→
1751→export function getPromptId(): string | null {
1752→ return STATE.promptId
1753→}
1754→
1755→export function setPromptId(id: string | null): void {
1756→ STATE.promptId = id
1757→}
1758→
1759→Tool Call: Read src\tools.ts (1 - 100) Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import { toolMatchesName, type Tool, type Tools } from './Tool.js'
3→import { AgentTool } from './tools/AgentTool/AgentTool.js'
4→import { SkillTool } from './tools/SkillTool/SkillTool.js'
5→import { BashTool } from './tools/BashTool/BashTool.js'
6→import { FileEditTool } from './tools/FileEditTool/FileEditTool.js'
7→import { FileReadTool } from './tools/FileReadTool/FileReadTool.js'
8→import { FileWriteTool } from './tools/FileWriteTool/FileWriteTool.js'
9→import { GlobTool } from './tools/GlobTool/GlobTool.js'
10→import { NotebookEditTool } from './tools/NotebookEditTool/NotebookEditTool.js'
11→import { WebFetchTool } from './tools/WebFetchTool/WebFetchTool.js'
12→import { TaskStopTool } from './tools/TaskStopTool/TaskStopTool.js'
13→import { BriefTool } from './tools/BriefTool/BriefTool.js'
14→// Dead code elimination: conditional import for ant-only tools
15→/* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
16→const REPLTool =
17→ process.env.USER_TYPE === 'ant'
18→ ? require('./tools/REPLTool/REPLTool.js').REPLTool
19→ : null
20→const SuggestBackgroundPRTool =
21→ process.env.USER_TYPE === 'ant'
22→ ? require('./tools/SuggestBackgroundPRTool/SuggestBackgroundPRTool.js')
23→ .SuggestBackgroundPRTool
24→ : null
25→const SleepTool =
26→ feature('PROACTIVE') || feature('KAIROS')
27→ ? require('./tools/SleepTool/SleepTool.js').SleepTool
28→ : null
29→const cronTools = feature('AGENT_TRIGGERS')
30→ ? [
31→ require('./tools/ScheduleCronTool/CronCreateTool.js').CronCreateTool,
32→ require('./tools/ScheduleCronTool/CronDeleteTool.js').CronDeleteTool,
33→ require('./tools/ScheduleCronTool/CronListTool.js').CronListTool,
34→ ]
35→ : []
36→const RemoteTriggerTool = feature('AGENT_TRIGGERS_REMOTE')
37→ ? require('./tools/RemoteTriggerTool/RemoteTriggerTool.js').RemoteTriggerTool
38→ : null
39→const MonitorTool = feature('MONITOR_TOOL')
40→ ? require('./tools/MonitorTool/MonitorTool.js').MonitorTool
41→ : null
42→const SendUserFileTool = feature('KAIROS')
43→ ? require('./tools/SendUserFileTool/SendUserFileTool.js').SendUserFileTool
44→ : null
45→const PushNotificationTool =
46→ feature('KAIROS') || feature('KAIROS_PUSH_NOTIFICATION')
47→ ? require('./tools/PushNotificationTool/PushNotificationTool.js')
48→ .PushNotificationTool
49→ : null
50→const SubscribePRTool = feature('KAIROS_GITHUB_WEBHOOKS')
51→ ? require('./tools/SubscribePRTool/SubscribePRTool.js').SubscribePRTool
52→ : null
53→/* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
54→import { TaskOutputTool } from './tools/TaskOutputTool/TaskOutputTool.js'
55→import { WebSearchTool } from './tools/WebSearchTool/WebSearchTool.js'
56→import { TodoWriteTool } from './tools/TodoWriteTool/TodoWriteTool.js'
57→import { ExitPlanModeV2Tool } from './tools/ExitPlanModeTool/ExitPlanModeV2Tool.js'
58→import { TestingPermissionTool } from './tools/testing/TestingPermissionTool.js'
59→import { GrepTool } from './tools/GrepTool/GrepTool.js'
60→import { TungstenTool } from './tools/TungstenTool/TungstenTool.js'
61→// Lazy require to break circular dependency: tools.ts -> TeamCreateTool/TeamDeleteTool -> ... -> tools.ts
62→/* eslint-disable @typescript-eslint/no-require-imports */
63→const getTeamCreateTool = () =>
64→ require('./tools/TeamCreateTool/TeamCreateTool.js')
65→ .TeamCreateTool as typeof import('./tools/TeamCreateTool/TeamCreateTool.js').TeamCreateTool
66→const getTeamDeleteTool = () =>
67→ require('./tools/TeamDeleteTool/TeamDeleteTool.js')
68→ .TeamDeleteTool as typeof import('./tools/TeamDeleteTool/TeamDeleteTool.js').TeamDeleteTool
69→const getSendMessageTool = () =>
70→ require('./tools/SendMessageTool/SendMessageTool.js')
71→ .SendMessageTool as typeof import('./tools/SendMessageTool/SendMessageTool.js').SendMessageTool
72→/* eslint-enable @typescript-eslint/no-require-imports */
73→import { AskUserQuestionTool } from './tools/AskUserQuestionTool/AskUserQuestionTool.js'
74→import { LSPTool } from './tools/LSPTool/LSPTool.js'
75→import { ListMcpResourcesTool } from './tools/ListMcpResourcesTool/ListMcpResourcesTool.js'
76→import { ReadMcpResourceTool } from './tools/ReadMcpResourceTool/ReadMcpResourceTool.js'
77→import { ToolSearchTool } from './tools/ToolSearchTool/ToolSearchTool.js'
78→import { EnterPlanModeTool } from './tools/EnterPlanModeTool/EnterPlanModeTool.js'
79→import { EnterWorktreeTool } from './tools/EnterWorktreeTool/EnterWorktreeTool.js'
80→import { ExitWorktreeTool } from './tools/ExitWorktreeTool/ExitWorktreeTool.js'
81→import { ConfigTool } from './tools/ConfigTool/ConfigTool.js'
82→import { TaskCreateTool } from './tools/TaskCreateTool/TaskCreateTool.js'
83→import { TaskGetTool } from './tools/TaskGetTool/TaskGetTool.js'
84→import { TaskUpdateTool } from './tools/TaskUpdateTool/TaskUpdateTool.js'
85→import { TaskListTool } from './tools/TaskListTool/TaskListTool.js'
86→import uniqBy from 'lodash-es/uniqBy.js'
87→import { isToolSearchEnabledOptimistic } from './utils/toolSearch.js'
88→import { isTodoV2Enabled } from './utils/tasks.js'
89→// Dead code elimination: conditional import for CLAUDE_CODE_VERIFY_PLAN
90→/* eslint-disable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
91→const VerifyPlanExecutionTool =
92→ process.env.CLAUDE_CODE_VERIFY_PLAN === 'true'
93→ ? require('./tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.js')
94→ .VerifyPlanExecutionTool
95→ : null
96→/* eslint-enable custom-rules/no-process-env-top-level, @typescript-eslint/no-require-imports */
97→import { SYNTHETIC_OUTPUT_TOOL_NAME } from './tools/SyntheticOutputTool/SyntheticOutputTool.js'
98→export {
99→ ALL_AGENT_DISALLOWED_TOOLS,
100→ CUSTOM_AGENT_DISALLOWED_TOOLS,Tool Call: Read src\query.ts (1 - 120) Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import type {
3→ ToolResultBlockParam,
4→ ToolUseBlock,
5→} from '@anthropic-ai/sdk/resources/index.mjs'
6→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
7→import { FallbackTriggeredError } from './services/api/withRetry.js'
8→import {
9→ calculateTokenWarningState,
10→ isAutoCompactEnabled,
11→ type AutoCompactTrackingState,
12→} from './services/compact/autoCompact.js'
13→import { buildPostCompactMessages } from './services/compact/compact.js'
14→/* eslint-disable @typescript-eslint/no-require-imports */
15→const reactiveCompact = feature('REACTIVE_COMPACT')
16→ ? (require('./services/compact/reactiveCompact.js') as typeof import('./services/compact/reactiveCompact.js'))
17→ : null
18→const contextCollapse = feature('CONTEXT_COLLAPSE')
19→ ? (require('./services/contextCollapse/index.js') as typeof import('./services/contextCollapse/index.js'))
20→ : null
21→/* eslint-enable @typescript-eslint/no-require-imports */
22→import {
23→ logEvent,
24→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
25→} from 'src/services/analytics/index.js'
26→import { ImageSizeError } from './utils/imageValidation.js'
27→import { ImageResizeError } from './utils/imageResizer.js'
28→import { findToolByName, type ToolUseContext } from './Tool.js'
29→import { asSystemPrompt, type SystemPrompt } from './utils/systemPromptType.js'
30→import type {
31→ AssistantMessage,
32→ AttachmentMessage,
33→ Message,
34→ RequestStartEvent,
35→ StreamEvent,
36→ ToolUseSummaryMessage,
37→ UserMessage,
38→ TombstoneMessage,
39→} from './types/message.js'
40→import { logError } from './utils/log.js'
41→import {
42→ PROMPT_TOO_LONG_ERROR_MESSAGE,
43→ isPromptTooLongMessage,
44→} from './services/api/errors.js'
45→import { logAntError, logForDebugging } from './utils/debug.js'
46→import {
47→ createUserMessage,
48→ createUserInterruptionMessage,
49→ normalizeMessagesForAPI,
50→ createSystemMessage,
51→ createAssistantAPIErrorMessage,
52→ getMessagesAfterCompactBoundary,
53→ createToolUseSummaryMessage,
54→ createMicrocompactBoundaryMessage,
55→ stripSignatureBlocks,
56→} from './utils/messages.js'
57→import { generateToolUseSummary } from './services/toolUseSummary/toolUseSummaryGenerator.js'
58→import { prependUserContext, appendSystemContext } from './utils/api.js'
59→import {
60→ createAttachmentMessage,
61→ filterDuplicateMemoryAttachments,
62→ getAttachmentMessages,
63→ startRelevantMemoryPrefetch,
64→} from './utils/attachments.js'
65→/* eslint-disable @typescript-eslint/no-require-imports */
66→const skillPrefetch = feature('EXPERIMENTAL_SKILL_SEARCH')
67→ ? (require('./services/skillSearch/prefetch.js') as typeof import('./services/skillSearch/prefetch.js'))
68→ : null
69→const jobClassifier = feature('TEMPLATES')
70→ ? (require('./jobs/classifier.js') as typeof import('./jobs/classifier.js'))
71→ : null
72→/* eslint-enable @typescript-eslint/no-require-imports */
73→import {
74→ remove as removeFromQueue,
75→ getCommandsByMaxPriority,
76→ isSlashCommand,
77→} from './utils/messageQueueManager.js'
78→import { notifyCommandLifecycle } from './utils/commandLifecycle.js'
79→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
80→import {
81→ getRuntimeMainLoopModel,
82→ renderModelName,
83→} from './utils/model/model.js'
84→import {
85→ doesMostRecentAssistantMessageExceed200k,
86→ finalContextTokensFromLastResponse,
87→ tokenCountWithEstimation,
88→} from './utils/tokens.js'
89→import { ESCALATED_MAX_TOKENS } from './utils/context.js'
90→import { getFeatureValue_CACHED_MAY_BE_STALE } from './services/analytics/growthbook.js'
91→import { SLEEP_TOOL_NAME } from './tools/SleepTool/prompt.js'
92→import { executePostSamplingHooks } from './utils/hooks/postSamplingHooks.js'
93→import { executeStopFailureHooks } from './utils/hooks.js'
94→import type { QuerySource } from './constants/querySource.js'
95→import { createDumpPromptsFetch } from './services/api/dumpPrompts.js'
96→import { StreamingToolExecutor } from './services/tools/StreamingToolExecutor.js'
97→import { queryCheckpoint } from './utils/queryProfiler.js'
98→import { runTools } from './services/tools/toolOrchestration.js'
99→import { applyToolResultBudget } from './utils/toolResultStorage.js'
100→import { recordContentReplacement } from './utils/sessionStorage.js'
101→import { handleStopHooks } from './query/stopHooks.js'
102→import { buildQueryConfig } from './query/config.js'
103→import { productionDeps, type QueryDeps } from './query/deps.js'
104→import type { Terminal, Continue } from './query/transitions.js'
105→import { feature } from 'bun:bundle'
106→import {
107→ getCurrentTurnTokenBudget,
108→ getTurnOutputTokens,
109→ incrementBudgetContinuationCount,
110→} from './bootstrap/state.js'
111→import { createBudgetTracker, checkTokenBudget } from './query/tokenBudget.js'
112→import { count } from './utils/array.js'
113→
114→/* eslint-disable @typescript-eslint/no-require-imports */
115→const snipModule = feature('HISTORY_SNIP')
116→ ? (require('./services/compact/snipCompact.js') as typeof import('./services/compact/snipCompact.js'))
117→ : null
118→const taskSummaryModule = feature('BG_SESSIONS')
119→ ? (require('./utils/taskSummary.js') as typeof import('./utils/taskSummary.js'))
120→ : nullTool Call: Find D:\code\play\stock_ai_rust\claude-code src/services/**/*.ts Status: Completed
src\services\AgentSummary\agentSummary.ts src\services\MagicDocs\magicDocs.ts src\services\MagicDocs\prompts.ts src\services\PromptSuggestion\promptSuggestion.ts src\services\PromptSuggestion\speculation.ts src\services\SessionMemory\prompts.ts src\services\SessionMemory\sessionMemory.ts src\services\analytics\config.ts src\services\SessionMemory\sessionMemoryUtils.ts src\services\analytics\datadog.ts src\services\analytics\firstPartyEventLogger.ts src\services\analytics\firstPartyEventLoggingExporter.ts src\services\analytics\growthbook.ts src\services\analytics\index.ts src\services\analytics\metadata.ts src\services\analytics\sink.ts src\services\analytics\sinkKillswitch.ts src\services\api\adminRequests.ts src\services\api\bootstrap.ts src\services\api\claude.ts src\services\api\client.ts src\services\api\dumpPrompts.ts src\services\api\emptyUsage.ts src\services\api\errorUtils.ts src\services\api\errors.ts src\services\api\filesApi.ts src\services\api\firstTokenDate.ts src\services\api\grove.ts src\services\api\logging.ts src\services\api\metricsOptOut.ts src\services\api\overageCreditGrant.ts src\services\api\promptCacheBreakDetection.ts src\services\api\referral.ts src\services\api\sessionIngress.ts src\services\api\ultrareviewQuota.ts src\services\api\usage.ts src\services\api\withRetry.ts src\services\autoDream\autoDream.ts src\services\autoDream\config.ts src\services\autoDream\consolidationLock.ts src\services\autoDream\consolidationPrompt.ts src\services\awaySummary.ts src\services\claudeAiLimits.ts src\services\claudeAiLimitsHook.ts src\services\compact\apiMicrocompact.ts src\services\compact\autoCompact.ts src\services\compact\compact.ts src\services\compact\compactWarningHook.ts src\services\compact\compactWarningState.ts src\services\compact\grouping.ts src\services\compact\microCompact.ts src\services\compact\postCompactCleanup.ts src\services\compact\prompt.ts src\services\compact\sessionMemoryCompact.ts src\services\compact\timeBasedMCConfig.ts src\services\diagnosticTracking.ts src\services\extractMemories\extractMemories.ts src\services\extractMemories\prompts.ts src\services\internalLogging.ts src\services\lsp\LSPClient.ts src\services\lsp\LSPDiagnosticRegistry.ts src\services\lsp\LSPServerInstance.ts src\services\lsp\config.ts src\services\lsp\LSPServerManager.ts src\services\lsp\manager.ts src\services\lsp\passiveFeedback.ts src\services\mcp\InProcessTransport.ts src\services\mcp\SdkControlTransport.ts src\services\mcp\auth.ts src\services\mcp\channelAllowlist.ts src\services\mcp\channelNotification.ts src\services\mcp\channelPermissions.ts src\services\mcp\claudeai.ts src\services\mcp\client.ts src\services\mcp\config.ts src\services\mcp\elicitationHandler.ts src\services\mcp\envExpansion.ts src\services\mcp\headersHelper.ts src\services\mcp\mcpStringUtils.ts src\services\mcp\normalization.ts src\services\mcp\oauthPort.ts src\services\mcp\officialRegistry.ts src\services\mcp\types.ts src\services\mcp\useManageMCPConnections.ts src\services\mcp\utils.ts src\services\mcp\vscodeSdkMcp.ts src\services\mcp\xaa.ts src\services\mcp\xaaIdpLogin.ts src\services\mockRateLimits.ts src\services\notifier.ts src\services\oauth\auth-code-listener.ts src\services\oauth\client.ts src\services\oauth\crypto.ts src\services\oauth\getOauthProfile.ts src\services\oauth\index.ts src\services\plugins\pluginCliCommands.ts src\services\plugins\PluginInstallationManager.ts src\services\plugins\pluginOperations.ts src\services\policyLimits\index.ts src\services\policyLimits\types.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\state\AppStateStore.ts (1 - 150) Status: Completed
1→import type { Notification } from 'src/context/notifications.js'
2→import type { TodoList } from 'src/utils/todo/types.js'
3→import type { BridgePermissionCallbacks } from '../bridge/bridgePermissionCallbacks.js'
4→import type { Command } from '../commands.js'
5→import type { ChannelPermissionCallbacks } from '../services/mcp/channelPermissions.js'
6→import type { ElicitationRequestEvent } from '../services/mcp/elicitationHandler.js'
7→import type {
8→ MCPServerConnection,
9→ ServerResource,
10→} from '../services/mcp/types.js'
11→import { shouldEnablePromptSuggestion } from '../services/PromptSuggestion/promptSuggestion.js'
12→import {
13→ getEmptyToolPermissionContext,
14→ type Tool,
15→ type ToolPermissionContext,
16→} from '../Tool.js'
17→import type { TaskState } from '../tasks/types.js'
18→import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js'
19→import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js'
20→import type { AllowedPrompt } from '../tools/ExitPlanModeTool/ExitPlanModeV2Tool.js'
21→import type { AgentId } from '../types/ids.js'
22→import type { Message, UserMessage } from '../types/message.js'
23→import type { LoadedPlugin, PluginError } from '../types/plugin.js'
24→import type { DeepImmutable } from '../types/utils.js'
25→import {
26→ type AttributionState,
27→ createEmptyAttributionState,
28→} from '../utils/commitAttribution.js'
29→import type { EffortValue } from '../utils/effort.js'
30→import type { FileHistoryState } from '../utils/fileHistory.js'
31→import type { REPLHookContext } from '../utils/hooks/postSamplingHooks.js'
32→import type { SessionHooksState } from '../utils/hooks/sessionHooks.js'
33→import type { ModelSetting } from '../utils/model/model.js'
34→import type { DenialTrackingState } from '../utils/permissions/denialTracking.js'
35→import type { PermissionMode } from '../utils/permissions/PermissionMode.js'
36→import { getInitialSettings } from '../utils/settings/settings.js'
37→import type { SettingsJson } from '../utils/settings/types.js'
38→import { shouldEnableThinkingByDefault } from '../utils/thinking.js'
39→import type { Store } from './store.js'
40→
41→export type CompletionBoundary =
42→ | { type: 'complete'; completedAt: number; outputTokens: number }
43→ | { type: 'bash'; command: string; completedAt: number }
44→ | { type: 'edit'; toolName: string; filePath: string; completedAt: number }
45→ | {
46→ type: 'denied_tool'
47→ toolName: string
48→ detail: string
49→ completedAt: number
50→ }
51→
52→export type SpeculationResult = {
53→ messages: Message[]
54→ boundary: CompletionBoundary | null
55→ timeSavedMs: number
56→}
57→
58→export type SpeculationState =
59→ | { status: 'idle' }
60→ | {
61→ status: 'active'
62→ id: string
63→ abort: () => void
64→ startTime: number
65→ messagesRef: { current: Message[] } // Mutable ref - avoids array spreading per message
66→ writtenPathsRef: { current: Set<string> } // Mutable ref - relative paths written to overlay
67→ boundary: CompletionBoundary | null
68→ suggestionLength: number
69→ toolUseCount: number
70→ isPipelined: boolean
71→ contextRef: { current: REPLHookContext }
72→ pipelinedSuggestion?: {
73→ text: string
74→ promptId: 'user_intent' | 'stated_intent'
75→ generationRequestId: string | null
76→ } | null
77→ }
78→
79→export const IDLE_SPECULATION_STATE: SpeculationState = { status: 'idle' }
80→
81→export type FooterItem =
82→ | 'tasks'
83→ | 'tmux'
84→ | 'bagel'
85→ | 'teams'
86→ | 'bridge'
87→ | 'companion'
88→
89→export type AppState = DeepImmutable<{
90→ settings: SettingsJson
91→ verbose: boolean
92→ mainLoopModel: ModelSetting
93→ mainLoopModelForSession: ModelSetting
94→ statusLineText: string | undefined
95→ expandedView: 'none' | 'tasks' | 'teammates'
96→ isBriefOnly: boolean
97→ // Optional - only present when ENABLE_AGENT_SWARMS is true (for dead code elimination)
98→ showTeammateMessagePreview?: boolean
99→ selectedIPAgentIndex: number
100→ // CoordinatorTaskPanel selection: -1 = pill, 0 = main, 1..N = agent rows.
101→ // AppState (not local) so the panel can read it directly without prop-drilling
102→ // through PromptInput → PromptInputFooter.
103→ coordinatorTaskIndex: number
104→ viewSelectionMode: 'none' | 'selecting-agent' | 'viewing-agent'
105→ // Which footer pill is focused (arrow-key navigation below the prompt).
106→ // Lives in AppState so pill components rendered outside PromptInput
107→ // (CompanionSprite in REPL.tsx) can read their own focused state.
108→ footerSelection: FooterItem | null
109→ toolPermissionContext: ToolPermissionContext
110→ spinnerTip?: string
111→ // Agent name from --agent CLI flag or settings (for logo display)
112→ agent: string | undefined
113→ // Assistant mode fully enabled (settings + GrowthBook gate + trust).
114→ // Single source of truth - computed once in main.tsx before option
115→ // mutation, consumers read this instead of re-calling isAssistantMode().
116→ kairosEnabled: boolean
117→ // Remote session URL for --remote mode (shown in footer indicator)
118→ remoteSessionUrl: string | undefined
119→ // Remote session WS state (`claude assistant` viewer). 'connected' means the
120→ // live event stream is open; 'reconnecting' = transient WS drop, backoff
121→ // in progress; 'disconnected' = permanent close or reconnects exhausted.
122→ remoteConnectionStatus:
123→ | 'connecting'
124→ | 'connected'
125→ | 'reconnecting'
126→ | 'disconnected'
127→ // `claude assistant`: count of background tasks (Agent calls, teammates,
128→ // workflows) running inside the REMOTE daemon child. Event-sourced from
129→ // system/task_started and system/task_notification on the WS. The local
130→ // AppState.tasks is always empty in viewer mode — the tasks live in a
131→ // different process.
132→ remoteBackgroundTaskCount: number
133→ // Always-on bridge: desired state (controlled by /config or footer toggle)
134→ replBridgeEnabled: boolean
135→ // Always-on bridge: true when activated via /remote-control command, false when config-driven
136→ replBridgeExplicit: boolean
137→ // Outbound-only mode: forward events to CCR but reject inbound prompts/control
138→ replBridgeOutboundOnly: boolean
139→ // Always-on bridge: env registered + session created (= "Ready")
140→ replBridgeConnected: boolean
141→ // Always-on bridge: ingress WebSocket is open (= "Connected" - user on claude.ai)
142→ replBridgeSessionActive: boolean
143→ // Always-on bridge: poll loop is in error backoff (= "Reconnecting")
144→ replBridgeReconnecting: boolean
145→ // Always-on bridge: connect URL for Ready state (?bridge=envId)
146→ replBridgeConnectUrl: string | undefined
147→ // Always-on bridge: session URL on claude.ai (set when connected)
148→ replBridgeSessionUrl: string | undefined
149→ // Always-on bridge: IDs for debugging (shown in dialog when --verbose)
150→ replBridgeEnvironmentId: string | undefinedTool Call: Read src\state\store.js (1 - 80) Status: Failed
File does not exist. Note: your current working directory is D:\code\play\stock_ai_rust\claude-code. Did you mean store.ts?Tool Call: Read src\services\api\claude.ts (1 - 80) Status: Completed
1→import type {
2→ BetaContentBlock,
3→ BetaContentBlockParam,
4→ BetaImageBlockParam,
5→ BetaJSONOutputFormat,
6→ BetaMessage,
7→ BetaMessageDeltaUsage,
8→ BetaMessageStreamParams,
9→ BetaOutputConfig,
10→ BetaRawMessageStreamEvent,
11→ BetaRequestDocumentBlock,
12→ BetaStopReason,
13→ BetaToolChoiceAuto,
14→ BetaToolChoiceTool,
15→ BetaToolResultBlockParam,
16→ BetaToolUnion,
17→ BetaUsage,
18→ BetaMessageParam as MessageParam,
19→} from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
20→import type { TextBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
21→import type { Stream } from '@anthropic-ai/sdk/streaming.mjs'
22→import { randomUUID } from 'crypto'
23→import {
24→ getAPIProvider,
25→ isFirstPartyAnthropicBaseUrl,
26→} from 'src/utils/model/providers.js'
27→import {
28→ getAttributionHeader,
29→ getCLISyspromptPrefix,
30→} from '../../constants/system.js'
31→import {
32→ getEmptyToolPermissionContext,
33→ type QueryChainTracking,
34→ type Tool,
35→ type ToolPermissionContext,
36→ type Tools,
37→ toolMatchesName,
38→} from '../../Tool.js'
39→import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js'
40→import {
41→ type ConnectorTextBlock,
42→ type ConnectorTextDelta,
43→ isConnectorTextBlock,
44→} from '../../types/connectorText.js'
45→import type {
46→ AssistantMessage,
47→ Message,
48→ StreamEvent,
49→ SystemAPIErrorMessage,
50→ UserMessage,
51→} from '../../types/message.js'
52→import {
53→ type CacheScope,
54→ logAPIPrefix,
55→ splitSysPromptPrefix,
56→ toolToAPISchema,
57→} from '../../utils/api.js'
58→import { getOauthAccountInfo } from '../../utils/auth.js'
59→import {
60→ getBedrockExtraBodyParamsBetas,
61→ getMergedBetas,
62→ getModelBetas,
63→} from '../../utils/betas.js'
64→import { getOrCreateUserID } from '../../utils/config.js'
65→import {
66→ CAPPED_DEFAULT_MAX_TOKENS,
67→ getModelMaxOutputTokens,
68→ getSonnet1mExpTreatmentEnabled,
69→} from '../../utils/context.js'
70→import { resolveAppliedEffort } from '../../utils/effort.js'
71→import { isEnvTruthy } from '../../utils/envUtils.js'
72→import { errorMessage } from '../../utils/errors.js'
73→import { computeFingerprintFromMessages } from '../../utils/fingerprint.js'
74→import { captureAPIRequest, logError } from '../../utils/log.js'
75→import {
76→ createAssistantAPIErrorMessage,
77→ createUserMessage,
78→ ensureToolResultPairing,
79→ normalizeContentFromAPI,
80→ normalizeMessagesForAPI,Tool Call: Read src\Tool.ts (100 - 219) Status: Completed
100→ errorCode: number
101→ }
102→
103→export type SetToolJSXFn = (
104→ args: {
105→ jsx: React.ReactNode | null
106→ shouldHidePromptInput: boolean
107→ shouldContinueAnimation?: true
108→ showSpinner?: boolean
109→ isLocalJSXCommand?: boolean
110→ isImmediate?: boolean
111→ /** Set to true to clear a local JSX command (e.g., from its onDone callback) */
112→ clearLocalJSX?: boolean
113→ } | null,
114→) => void
115→
116→// Import tool permission types from centralized location to break import cycles
117→import type { ToolPermissionRulesBySource } from './types/permissions.js'
118→
119→// Re-export for backwards compatibility
120→export type { ToolPermissionRulesBySource }
121→
122→// Apply DeepImmutable to the imported type
123→export type ToolPermissionContext = DeepImmutable<{
124→ mode: PermissionMode
125→ additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
126→ alwaysAllowRules: ToolPermissionRulesBySource
127→ alwaysDenyRules: ToolPermissionRulesBySource
128→ alwaysAskRules: ToolPermissionRulesBySource
129→ isBypassPermissionsModeAvailable: boolean
130→ isAutoModeAvailable?: boolean
131→ strippedDangerousRules?: ToolPermissionRulesBySource
132→ /** When true, permission prompts are auto-denied (e.g., background agents that can't show UI) */
133→ shouldAvoidPermissionPrompts?: boolean
134→ /** When true, automated checks (classifier, hooks) are awaited before showing the permission dialog (coordinator workers) */
135→ awaitAutomatedChecksBeforeDialog?: boolean
136→ /** Stores the permission mode before model-initiated plan mode entry, so it can be restored on exit */
137→ prePlanMode?: PermissionMode
138→}>
139→
140→export const getEmptyToolPermissionContext: () => ToolPermissionContext =
141→ () => ({
142→ mode: 'default',
143→ additionalWorkingDirectories: new Map(),
144→ alwaysAllowRules: {},
145→ alwaysDenyRules: {},
146→ alwaysAskRules: {},
147→ isBypassPermissionsModeAvailable: false,
148→ })
149→
150→export type CompactProgressEvent =
151→ | {
152→ type: 'hooks_start'
153→ hookType: 'pre_compact' | 'post_compact' | 'session_start'
154→ }
155→ | { type: 'compact_start' }
156→ | { type: 'compact_end' }
157→
158→export type ToolUseContext = {
159→ options: {
160→ commands: Command[]
161→ debug: boolean
162→ mainLoopModel: string
163→ tools: Tools
164→ verbose: boolean
165→ thinkingConfig: ThinkingConfig
166→ mcpClients: MCPServerConnection[]
167→ mcpResources: Record<string, ServerResource[]>
168→ isNonInteractiveSession: boolean
169→ agentDefinitions: AgentDefinitionsResult
170→ maxBudgetUsd?: number
171→ /** Custom system prompt that replaces the default system prompt */
172→ customSystemPrompt?: string
173→ /** Additional system prompt appended after the main system prompt */
174→ appendSystemPrompt?: string
175→ /** Override querySource for analytics tracking */
176→ querySource?: QuerySource
177→ /** Optional callback to get the latest tools (e.g., after MCP servers connect mid-query) */
178→ refreshTools?: () => Tools
179→ }
180→ abortController: AbortController
181→ readFileState: FileStateCache
182→ getAppState(): AppState
183→ setAppState(f: (prev: AppState) => AppState): void
184→ /**
185→ * Always-shared setAppState for session-scoped infrastructure (background
186→ * tasks, session hooks). Unlike setAppState, which is no-op for async agents
187→ * (see createSubagentContext), this always reaches the root store so agents
188→ * at any nesting depth can register/clean up infrastructure that outlives
189→ * a single turn. Only set by createSubagentContext; main-thread contexts
190→ * fall back to setAppState.
191→ */
192→ setAppStateForTasks?: (f: (prev: AppState) => AppState) => void
193→ /**
194→ * Optional handler for URL elicitations triggered by tool call errors (-32042).
195→ * In print/SDK mode, this delegates to structuredIO.handleElicitation.
196→ * In REPL mode, this is undefined and the queue-based UI path is used.
197→ */
198→ handleElicitation?: (
199→ serverName: string,
200→ params: ElicitRequestURLParams,
201→ signal: AbortSignal,
202→ ) => Promise<ElicitResult>
203→ setToolJSX?: SetToolJSXFn
204→ addNotification?: (notif: Notification) => void
205→ /** Append a UI-only system message to the REPL message list. Stripped at the
206→ * normalizeMessagesForAPI boundary — the Exclude<> makes that type-enforced. */
207→ appendSystemMessage?: (
208→ msg: Exclude<SystemMessage, SystemLocalCommandMessage>,
209→ ) => void
210→ /** Send an OS-level notification (iTerm2, Kitty, Ghostty, bell, etc.) */
211→ sendOSNotification?: (opts: {
212→ message: string
213→ notificationType: string
214→ }) => void
215→ nestedMemoryAttachmentTriggers?: Set<string>
216→ /**
217→ * CLAUDE.md paths already injected as nested_memory attachments this
218→ * session. Dedup for memoryFilesToAttachments — readFileState is an LRU
219→ * that evicts entries in busy sessions, so its .has() check alone canTool Call: Read src\state\store.ts Status: Completed
1→type Listener = () => void
2→type OnChange<T> = (args: { newState: T; oldState: T }) => void
3→
4→export type Store<T> = {
5→ getState: () => T
6→ setState: (updater: (prev: T) => T) => void
7→ subscribe: (listener: Listener) => () => void
8→}
9→
10→export function createStore<T>(
11→ initialState: T,
12→ onChange?: OnChange<T>,
13→): Store<T> {
14→ let state = initialState
15→ const listeners = new Set<Listener>()
16→
17→ return {
18→ getState: () => state,
19→
20→ setState: (updater: (prev: T) => T) => {
21→ const prev = state
22→ const next = updater(prev)
23→ if (Object.is(next, prev)) return
24→ state = next
25→ onChange?.({ newState: next, oldState: prev })
26→ for (const listener of listeners) listener()
27→ },
28→
29→ subscribe: (listener: Listener) => {
30→ listeners.add(listener)
31→ return () => listeners.delete(listener)
32→ },
33→ }
34→}
35→Tool Call: Read src\tools\BashTool\BashTool.tsx (1 - 100) Status: Completed
1→import { feature } from 'bun:bundle';
2→import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
3→import { copyFile, stat as fsStat, truncate as fsTruncate, link } from 'fs/promises';
4→import * as React from 'react';
5→import type { CanUseToolFn } from 'src/hooks/useCanUseTool.js';
6→import type { AppState } from 'src/state/AppState.js';
7→import { z } from 'zod/v4';
8→import { getKairosActive } from '../../bootstrap/state.js';
9→import { TOOL_SUMMARY_MAX_LENGTH } from '../../constants/toolLimits.js';
10→import { type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, logEvent } from '../../services/analytics/index.js';
11→import { notifyVscodeFileUpdated } from '../../services/mcp/vscodeSdkMcp.js';
12→import type { SetToolJSXFn, ToolCallProgress, ToolUseContext, ValidationResult } from '../../Tool.js';
13→import { buildTool, type ToolDef } from '../../Tool.js';
14→import { backgroundExistingForegroundTask, markTaskNotified, registerForeground, spawnShellTask, unregisterForeground } from '../../tasks/LocalShellTask/LocalShellTask.js';
15→import type { AgentId } from '../../types/ids.js';
16→import type { AssistantMessage } from '../../types/message.js';
17→import { parseForSecurity } from '../../utils/bash/ast.js';
18→import { splitCommand_DEPRECATED, splitCommandWithOperators } from '../../utils/bash/commands.js';
19→import { extractClaudeCodeHints } from '../../utils/claudeCodeHints.js';
20→import { detectCodeIndexingFromCommand } from '../../utils/codeIndexing.js';
21→import { isEnvTruthy } from '../../utils/envUtils.js';
22→import { isENOENT, ShellError } from '../../utils/errors.js';
23→import { detectFileEncoding, detectLineEndings, getFileModificationTime, writeTextContent } from '../../utils/file.js';
24→import { fileHistoryEnabled, fileHistoryTrackEdit } from '../../utils/fileHistory.js';
25→import { truncate } from '../../utils/format.js';
26→import { getFsImplementation } from '../../utils/fsOperations.js';
27→import { lazySchema } from '../../utils/lazySchema.js';
28→import { expandPath } from '../../utils/path.js';
29→import type { PermissionResult } from '../../utils/permissions/PermissionResult.js';
30→import { maybeRecordPluginHint } from '../../utils/plugins/hintRecommendation.js';
31→import { exec } from '../../utils/Shell.js';
32→import type { ExecResult } from '../../utils/ShellCommand.js';
33→import { SandboxManager } from '../../utils/sandbox/sandbox-adapter.js';
34→import { semanticBoolean } from '../../utils/semanticBoolean.js';
35→import { semanticNumber } from '../../utils/semanticNumber.js';
36→import { EndTruncatingAccumulator } from '../../utils/stringUtils.js';
37→import { getTaskOutputPath } from '../../utils/task/diskOutput.js';
38→import { TaskOutput } from '../../utils/task/TaskOutput.js';
39→import { isOutputLineTruncated } from '../../utils/terminal.js';
40→import { buildLargeToolResultMessage, ensureToolResultsDir, generatePreview, getToolResultPath, PREVIEW_SIZE_BYTES } from '../../utils/toolResultStorage.js';
41→import { userFacingName as fileEditUserFacingName } from '../FileEditTool/UI.js';
42→import { trackGitOperations } from '../shared/gitOperationTracking.js';
43→import { bashToolHasPermission, commandHasAnyCd, matchWildcardPattern, permissionRuleExtractPrefix } from './bashPermissions.js';
44→import { interpretCommandResult } from './commandSemantics.js';
45→import { getDefaultTimeoutMs, getMaxTimeoutMs, getSimplePrompt } from './prompt.js';
46→import { checkReadOnlyConstraints } from './readOnlyValidation.js';
47→import { parseSedEditCommand } from './sedEditParser.js';
48→import { shouldUseSandbox } from './shouldUseSandbox.js';
49→import { BASH_TOOL_NAME } from './toolName.js';
50→import { BackgroundHint, renderToolResultMessage, renderToolUseErrorMessage, renderToolUseMessage, renderToolUseProgressMessage, renderToolUseQueuedMessage } from './UI.js';
51→import { buildImageToolResult, isImageOutput, resetCwdIfOutsideProject, resizeShellImageOutput, stdErrAppendShellResetMessage, stripEmptyLines } from './utils.js';
52→const EOL = '\n';
53→
54→// Progress display constants
55→const PROGRESS_THRESHOLD_MS = 2000; // Show progress after 2 seconds
56→// In assistant mode, blocking bash auto-backgrounds after this many ms in the main agent
57→const ASSISTANT_BLOCKING_BUDGET_MS = 15_000;
58→
59→// Search commands for collapsible display (grep, find, etc.)
60→const BASH_SEARCH_COMMANDS = new Set(['find', 'grep', 'rg', 'ag', 'ack', 'locate', 'which', 'whereis']);
61→
62→// Read/view commands for collapsible display (cat, head, etc.)
63→const BASH_READ_COMMANDS = new Set(['cat', 'head', 'tail', 'less', 'more',
64→// Analysis commands
65→'wc', 'stat', 'file', 'strings',
66→// Data processing — commonly used to parse/transform file content in pipes
67→'jq', 'awk', 'cut', 'sort', 'uniq', 'tr']);
68→
69→// Directory-listing commands for collapsible display (ls, tree, du).
70→// Split from BASH_READ_COMMANDS so the summary says "Listed N directories"
71→// instead of the misleading "Read N files".
72→const BASH_LIST_COMMANDS = new Set(['ls', 'tree', 'du']);
73→
74→// Commands that are semantic-neutral in any position — pure output/status commands
75→// that don't change the read/search nature of the overall pipeline.
76→// e.g. `ls dir && echo "---" && ls dir2` is still a read-only compound command.
77→const BASH_SEMANTIC_NEUTRAL_COMMANDS = new Set(['echo', 'printf', 'true', 'false', ':' // bash no-op
78→]);
79→
80→// Commands that typically produce no stdout on success
81→const BASH_SILENT_COMMANDS = new Set(['mv', 'cp', 'rm', 'mkdir', 'rmdir', 'chmod', 'chown', 'chgrp', 'touch', 'ln', 'cd', 'export', 'unset', 'wait']);
82→
83→/**
84→ * Checks if a bash command is a search or read operation.
85→ * Used to determine if the command should be collapsed in the UI.
86→ * Returns an object indicating whether it's a search or read operation.
87→ *
88→ * For pipelines (e.g., `cat file | bq`), ALL parts must be search/read commands
89→ * for the whole command to be considered collapsible.
90→ *
91→ * Semantic-neutral commands (echo, printf, true, false, :) are skipped in any
92→ * position, as they're pure output/status commands that don't affect the read/search
93→ * nature of the pipeline (e.g. `ls dir && echo "---" && ls dir2` is still a read).
94→ */
95→export function isSearchOrReadBashCommand(command: string): {
96→ isSearch: boolean;
97→ isRead: boolean;
98→ isList: boolean;
99→} {
100→ let partsWithOperators: string[];Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/state/**/*.{ts,tsx} Status: Completed
src\state\AppState.tsx src\state\AppStateStore.ts src\state\onChangeAppState.ts src\state\selectors.ts src\state\store.ts src\state\teammateViewHelpers.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/entrypoints/**/*.{ts,tsx} Status: Completed
src\entrypoints\agentSdkTypes.ts src\entrypoints\cli.tsx src\entrypoints\init.ts src\entrypoints\mcp.ts src\entrypoints\sandboxTypes.ts src\entrypoints\sdk\controlSchemas.ts src\entrypoints\sdk\coreSchemas.ts src\entrypoints\sdk\coreTypes.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/services/**/*.{ts,tsx} Status: Completed
src\services\AgentSummary\agentSummary.ts src\services\MagicDocs\magicDocs.ts src\services\MagicDocs\prompts.ts src\services\PromptSuggestion\promptSuggestion.ts src\services\PromptSuggestion\speculation.ts src\services\SessionMemory\prompts.ts src\services\SessionMemory\sessionMemory.ts src\services\analytics\config.ts src\services\SessionMemory\sessionMemoryUtils.ts src\services\analytics\datadog.ts src\services\analytics\firstPartyEventLogger.ts src\services\analytics\firstPartyEventLoggingExporter.ts src\services\analytics\growthbook.ts src\services\analytics\index.ts src\services\analytics\metadata.ts src\services\analytics\sink.ts src\services\analytics\sinkKillswitch.ts src\services\api\adminRequests.ts src\services\api\bootstrap.ts src\services\api\claude.ts src\services\api\client.ts src\services\api\dumpPrompts.ts src\services\api\emptyUsage.ts src\services\api\errorUtils.ts src\services\api\errors.ts src\services\api\filesApi.ts src\services\api\firstTokenDate.ts src\services\api\grove.ts src\services\api\logging.ts src\services\api\metricsOptOut.ts src\services\api\overageCreditGrant.ts src\services\api\promptCacheBreakDetection.ts src\services\api\referral.ts src\services\api\sessionIngress.ts src\services\api\ultrareviewQuota.ts src\services\api\usage.ts src\services\api\withRetry.ts src\services\autoDream\autoDream.ts src\services\autoDream\config.ts src\services\autoDream\consolidationLock.ts src\services\autoDream\consolidationPrompt.ts src\services\awaySummary.ts src\services\claudeAiLimits.ts src\services\claudeAiLimitsHook.ts src\services\compact\apiMicrocompact.ts src\services\compact\autoCompact.ts src\services\compact\compact.ts src\services\compact\compactWarningHook.ts src\services\compact\compactWarningState.ts src\services\compact\grouping.ts src\services\compact\microCompact.ts src\services\compact\postCompactCleanup.ts src\services\compact\prompt.ts src\services\compact\sessionMemoryCompact.ts src\services\compact\timeBasedMCConfig.ts src\services\diagnosticTracking.ts src\services\extractMemories\extractMemories.ts src\services\extractMemories\prompts.ts src\services\internalLogging.ts src\services\lsp\LSPClient.ts src\services\lsp\LSPDiagnosticRegistry.ts src\services\lsp\LSPServerInstance.ts src\services\lsp\config.ts src\services\lsp\LSPServerManager.ts src\services\lsp\manager.ts src\services\lsp\passiveFeedback.ts src\services\mcp\InProcessTransport.ts src\services\mcp\MCPConnectionManager.tsx src\services\mcp\SdkControlTransport.ts src\services\mcp\auth.ts src\services\mcp\channelAllowlist.ts src\services\mcp\channelNotification.ts src\services\mcp\channelPermissions.ts src\services\mcp\claudeai.ts src\services\mcp\client.ts src\services\mcp\config.ts src\services\mcp\elicitationHandler.ts src\services\mcp\envExpansion.ts src\services\mcp\headersHelper.ts src\services\mcp\mcpStringUtils.ts src\services\mcp\normalization.ts src\services\mcp\oauthPort.ts src\services\mcp\officialRegistry.ts src\services\mcp\types.ts src\services\mcp\useManageMCPConnections.ts src\services\mcp\utils.ts src\services\mcp\vscodeSdkMcp.ts src\services\mcp\xaa.ts src\services\mcp\xaaIdpLogin.ts src\services\mcpServerApproval.tsx src\services\mockRateLimits.ts src\services\notifier.ts src\services\oauth\auth-code-listener.ts src\services\oauth\client.ts src\services\oauth\crypto.ts src\services\oauth\getOauthProfile.ts src\services\oauth\index.ts src\services\plugins\pluginCliCommands.ts src\services\plugins\PluginInstallationManager.ts src\services\plugins\pluginOperations.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\Tool.ts (220 - 339) Status: Completed
220→ * re-inject the same CLAUDE.md dozens of times.
221→ */
222→ loadedNestedMemoryPaths?: Set<string>
223→ dynamicSkillDirTriggers?: Set<string>
224→ /** Skill names surfaced via skill_discovery this session. Telemetry only (feeds was_discovered). */
225→ discoveredSkillNames?: Set<string>
226→ userModified?: boolean
227→ setInProgressToolUseIDs: (f: (prev: Set<string>) => Set<string>) => void
228→ /** Only wired in interactive (REPL) contexts; SDK/QueryEngine don't set this. */
229→ setHasInterruptibleToolInProgress?: (v: boolean) => void
230→ setResponseLength: (f: (prev: number) => number) => void
231→ /** Ant-only: push a new API metrics entry for OTPS tracking.
232→ * Called by subagent streaming when a new API request starts. */
233→ pushApiMetricsEntry?: (ttftMs: number) => void
234→ setStreamMode?: (mode: SpinnerMode) => void
235→ onCompactProgress?: (event: CompactProgressEvent) => void
236→ setSDKStatus?: (status: SDKStatus) => void
237→ openMessageSelector?: () => void
238→ updateFileHistoryState: (
239→ updater: (prev: FileHistoryState) => FileHistoryState,
240→ ) => void
241→ updateAttributionState: (
242→ updater: (prev: AttributionState) => AttributionState,
243→ ) => void
244→ setConversationId?: (id: UUID) => void
245→ agentId?: AgentId // Only set for subagents; use getSessionId() for session ID. Hooks use this to distinguish subagent calls.
246→ agentType?: string // Subagent type name. For the main thread's --agent type, hooks fall back to getMainThreadAgentType().
247→ /** When true, canUseTool must always be called even when hooks auto-approve.
248→ * Used by speculation for overlay file path rewriting. */
249→ requireCanUseTool?: boolean
250→ messages: Message[]
251→ fileReadingLimits?: {
252→ maxTokens?: number
253→ maxSizeBytes?: number
254→ }
255→ globLimits?: {
256→ maxResults?: number
257→ }
258→ toolDecisions?: Map<
259→ string,
260→ {
261→ source: string
262→ decision: 'accept' | 'reject'
263→ timestamp: number
264→ }
265→ >
266→ queryTracking?: QueryChainTracking
267→ /** Callback factory for requesting interactive prompts from the user.
268→ * Returns a prompt callback bound to the given source name.
269→ * Only available in interactive (REPL) contexts. */
270→ requestPrompt?: (
271→ sourceName: string,
272→ toolInputSummary?: string | null,
273→ ) => (request: PromptRequest) => Promise<PromptResponse>
274→ toolUseId?: string
275→ criticalSystemReminder_EXPERIMENTAL?: string
276→ /** When true, preserve toolUseResult on messages even for subagents.
277→ * Used by in-process teammates whose transcripts are viewable by the user. */
278→ preserveToolUseResults?: boolean
279→ /** Local denial tracking state for async subagents whose setAppState is a
280→ * no-op. Without this, the denial counter never accumulates and the
281→ * fallback-to-prompting threshold is never reached. Mutable — the
282→ * permissions code updates it in place. */
283→ localDenialTracking?: DenialTrackingState
284→ /**
285→ * Per-conversation-thread content replacement state for the tool result
286→ * budget. When present, query.ts applies the aggregate tool result budget.
287→ * Main thread: REPL provisions once (never resets — stale UUID keys
288→ * are inert). Subagents: createSubagentContext clones the parent's state
289→ * by default (cache-sharing forks need identical decisions), or
290→ * resumeAgentBackground threads one reconstructed from sidechain records.
291→ */
292→ contentReplacementState?: ContentReplacementState
293→ /**
294→ * Parent's rendered system prompt bytes, frozen at turn start.
295→ * Used by fork subagents to share the parent's prompt cache — re-calling
296→ * getSystemPrompt() at fork-spawn time can diverge (GrowthBook cold→warm)
297→ * and bust the cache. See forkSubagent.ts.
298→ */
299→ renderedSystemPrompt?: SystemPrompt
300→}
301→
302→// Re-export ToolProgressData from centralized location
303→export type { ToolProgressData }
304→
305→export type Progress = ToolProgressData | HookProgress
306→
307→export type ToolProgress<P extends ToolProgressData> = {
308→ toolUseID: string
309→ data: P
310→}
311→
312→export function filterToolProgressMessages(
313→ progressMessagesForMessage: ProgressMessage[],
314→): ProgressMessage<ToolProgressData>[] {
315→ return progressMessagesForMessage.filter(
316→ (msg): msg is ProgressMessage<ToolProgressData> =>
317→ msg.data?.type !== 'hook_progress',
318→ )
319→}
320→
321→export type ToolResult<T> = {
322→ data: T
323→ newMessages?: (
324→ | UserMessage
325→ | AssistantMessage
326→ | AttachmentMessage
327→ | SystemMessage
328→ )[]
329→ // contextModifier is only honored for tools that aren't concurrency safe.
330→ contextModifier?: (context: ToolUseContext) => ToolUseContext
331→ /** MCP protocol metadata (structuredContent, _meta) to pass through to SDK consumers */
332→ mcpMeta?: {
333→ _meta?: Record<string, unknown>
334→ structuredContent?: Record<string, unknown>
335→ }
336→}
337→
338→export type ToolCallProgress<P extends ToolProgressData = ToolProgressData> = (
339→ progress: ToolProgress<P>,Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/components/**/*.tsx Status: Completed
src\components\AgentProgressLine.tsx src\components\App.tsx src\components\ApproveApiKey.tsx src\components\AutoModeOptInDialog.tsx src\components\AutoUpdater.tsx src\components\AutoUpdaterWrapper.tsx src\components\AwsAuthStatusBox.tsx src\components\BaseTextInput.tsx src\components\BashModeProgress.tsx src\components\BridgeDialog.tsx src\components\BypassPermissionsModeDialog.tsx src\components\ChannelDowngradeDialog.tsx src\components\ClaudeCodeHint\PluginHintMenu.tsx src\components\ClaudeInChromeOnboarding.tsx src\components\ClaudeMdExternalIncludesDialog.tsx src\components\ClickableImageRef.tsx src\components\CompactSummary.tsx src\components\ConfigurableShortcutHint.tsx src\components\ConsoleOAuthFlow.tsx src\components\ContextSuggestions.tsx src\components\ContextVisualization.tsx src\components\CoordinatorAgentStatus.tsx src\components\CostThresholdDialog.tsx src\components\CtrlOToExpand.tsx src\components\CustomSelect\SelectMulti.tsx src\components\CustomSelect\select-input-option.tsx src\components\CustomSelect\select-option.tsx src\components\CustomSelect\select.tsx src\components\DesktopHandoff.tsx src\components\DesktopUpsell\DesktopUpsellStartup.tsx src\components\DevBar.tsx src\components\DevChannelsDialog.tsx src\components\DiagnosticsDisplay.tsx src\components\EffortCallout.tsx src\components\ExitFlow.tsx src\components\ExportDialog.tsx src\components\FallbackToolUseErrorMessage.tsx src\components\FallbackToolUseRejectedMessage.tsx src\components\FastIcon.tsx src\components\Feedback.tsx src\components\FeedbackSurvey\FeedbackSurvey.tsx src\components\FeedbackSurvey\FeedbackSurveyView.tsx src\components\FeedbackSurvey\TranscriptSharePrompt.tsx src\components\FeedbackSurvey\useFeedbackSurvey.tsx src\components\FeedbackSurvey\useMemorySurvey.tsx src\components\FeedbackSurvey\usePostCompactSurvey.tsx src\components\FeedbackSurvey\useSurveyState.tsx src\components\FileEditToolDiff.tsx src\components\FileEditToolUpdatedMessage.tsx src\components\FileEditToolUseRejectedMessage.tsx src\components\FilePathLink.tsx src\components\FullscreenLayout.tsx src\components\GlobalSearchDialog.tsx src\components\HelpV2\Commands.tsx src\components\HelpV2\General.tsx src\components\HelpV2\HelpV2.tsx src\components\HighlightedCode.tsx src\components\HighlightedCode\Fallback.tsx src\components\HistorySearchDialog.tsx src\components\IdeAutoConnectDialog.tsx src\components\IdeOnboardingDialog.tsx src\components\IdeStatusIndicator.tsx src\components\IdleReturnDialog.tsx src\components\InterruptedByUser.tsx src\components\InvalidConfigDialog.tsx src\components\InvalidSettingsDialog.tsx src\components\KeybindingWarnings.tsx src\components\LanguagePicker.tsx src\components\LogoV2\AnimatedAsterisk.tsx src\components\LogoV2\AnimatedClawd.tsx src\components\LogSelector.tsx src\components\LogoV2\ChannelsNotice.tsx src\components\LogoV2\Clawd.tsx src\components\LogoV2\CondensedLogo.tsx src\components\LogoV2\EmergencyTip.tsx src\components\LogoV2\Feed.tsx src\components\LogoV2\FeedColumn.tsx src\components\LogoV2\GuestPassesUpsell.tsx src\components\LogoV2\LogoV2.tsx src\components\LogoV2\Opus1mMergeNotice.tsx src\components\LogoV2\OverageCreditUpsell.tsx src\components\LogoV2\VoiceModeNotice.tsx src\components\LogoV2\WelcomeV2.tsx src\components\LogoV2\feedConfigs.tsx src\components\LspRecommendation\LspRecommendationMenu.tsx src\components\MCPServerApprovalDialog.tsx src\components\MCPServerDesktopImportDialog.tsx src\components\MCPServerDialogCopy.tsx src\components\MCPServerMultiselectDialog.tsx src\components\ManagedSettingsSecurityDialog\ManagedSettingsSecurityDialog.tsx src\components\Markdown.tsx src\components\MarkdownTable.tsx src\components\MemoryUsageIndicator.tsx src\components\Message.tsx src\components\MessageModel.tsx src\components\MessageResponse.tsx src\components\MessageRow.tsx src\components\MessageSelector.tsx src\components\MessageTimestamp.tsx src\components\Messages.tsx (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\state\AppState.tsx (1 - 80) Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→import { feature } from 'bun:bundle';
3→import React, { useContext, useEffect, useEffectEvent, useState, useSyncExternalStore } from 'react';
4→import { MailboxProvider } from '../context/mailbox.js';
5→import { useSettingsChange } from '../hooks/useSettingsChange.js';
6→import { logForDebugging } from '../utils/debug.js';
7→import { createDisabledBypassPermissionsContext, isBypassPermissionsModeDisabled } from '../utils/permissions/permissionSetup.js';
8→import { applySettingsChange } from '../utils/settings/applySettingsChange.js';
9→import type { SettingSource } from '../utils/settings/constants.js';
10→import { createStore } from './store.js';
11→
12→// DCE: voice context is ant-only. External builds get a passthrough.
13→/* eslint-disable @typescript-eslint/no-require-imports */
14→const VoiceProvider: (props: {
15→ children: React.ReactNode;
16→}) => React.ReactNode = feature('VOICE_MODE') ? require('../context/voice.js').VoiceProvider : ({
17→ children
18→}) => children;
19→
20→/* eslint-enable @typescript-eslint/no-require-imports */
21→import { type AppState, type AppStateStore, getDefaultAppState } from './AppStateStore.js';
22→
23→// TODO: Remove these re-exports once all callers import directly from
24→// ./AppStateStore.js. Kept for back-compat during migration so .ts callers
25→// can incrementally move off the .tsx import and stop pulling React.
26→export { type AppState, type AppStateStore, type CompletionBoundary, getDefaultAppState, IDLE_SPECULATION_STATE, type SpeculationResult, type SpeculationState } from './AppStateStore.js';
27→export const AppStoreContext = React.createContext<AppStateStore | null>(null);
28→type Props = {
29→ children: React.ReactNode;
30→ initialState?: AppState;
31→ onChangeAppState?: (args: {
32→ newState: AppState;
33→ oldState: AppState;
34→ }) => void;
35→};
36→const HasAppStateContext = React.createContext<boolean>(false);
37→export function AppStateProvider(t0) {
38→ const $ = _c(13);
39→ const {
40→ children,
41→ initialState,
42→ onChangeAppState
43→ } = t0;
44→ const hasAppStateContext = useContext(HasAppStateContext);
45→ if (hasAppStateContext) {
46→ throw new Error("AppStateProvider can not be nested within another AppStateProvider");
47→ }
48→ let t1;
49→ if ($[0] !== initialState || $[1] !== onChangeAppState) {
50→ t1 = () => createStore(initialState ?? getDefaultAppState(), onChangeAppState);
51→ $[0] = initialState;
52→ $[1] = onChangeAppState;
53→ $[2] = t1;
54→ } else {
55→ t1 = $[2];
56→ }
57→ const [store] = useState(t1);
58→ let t2;
59→ if ($[3] !== store) {
60→ t2 = () => {
61→ const {
62→ toolPermissionContext
63→ } = store.getState();
64→ if (toolPermissionContext.isBypassPermissionsModeAvailable && isBypassPermissionsModeDisabled()) {
65→ logForDebugging("Disabling bypass permissions mode on mount (remote settings loaded before mount)");
66→ store.setState(_temp);
67→ }
68→ };
69→ $[3] = store;
70→ $[4] = t2;
71→ } else {
72→ t2 = $[4];
73→ }
74→ let t3;
75→ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
76→ t3 = [];
77→ $[5] = t3;
78→ } else {
79→ t3 = $[5];
80→ }Tool Call: Read src\entrypoints\agentSdkTypes.ts (1 - 100) Status: Completed
1→/**
2→ * Main entrypoint for Claude Code Agent SDK types.
3→ *
4→ * This file re-exports the public SDK API from:
5→ * - sdk/coreTypes.ts - Common serializable types (messages, configs)
6→ * - sdk/runtimeTypes.ts - Non-serializable types (callbacks, interfaces)
7→ *
8→ * SDK builders who need control protocol types should import from
9→ * sdk/controlTypes.ts directly.
10→ */
11→
12→import type {
13→ CallToolResult,
14→ ToolAnnotations,
15→} from '@modelcontextprotocol/sdk/types.js'
16→
17→// Control protocol types for SDK builders (bridge subpath consumers)
18→/** @alpha */
19→export type {
20→ SDKControlRequest,
21→ SDKControlResponse,
22→} from './sdk/controlTypes.js'
23→// Re-export core types (common serializable types)
24→export * from './sdk/coreTypes.js'
25→// Re-export runtime types (callbacks, interfaces with methods)
26→export * from './sdk/runtimeTypes.js'
27→
28→// Re-export settings types (generated from settings JSON schema)
29→export type { Settings } from './sdk/settingsTypes.generated.js'
30→// Re-export tool types (all marked @internal until SDK API stabilizes)
31→export * from './sdk/toolTypes.js'
32→
33→// ============================================================================
34→// Functions
35→// ============================================================================
36→
37→import type {
38→ SDKMessage,
39→ SDKResultMessage,
40→ SDKSessionInfo,
41→ SDKUserMessage,
42→} from './sdk/coreTypes.js'
43→// Import types needed for function signatures
44→import type {
45→ AnyZodRawShape,
46→ ForkSessionOptions,
47→ ForkSessionResult,
48→ GetSessionInfoOptions,
49→ GetSessionMessagesOptions,
50→ InferShape,
51→ InternalOptions,
52→ InternalQuery,
53→ ListSessionsOptions,
54→ McpSdkServerConfigWithInstance,
55→ Options,
56→ Query,
57→ SDKSession,
58→ SDKSessionOptions,
59→ SdkMcpToolDefinition,
60→ SessionMessage,
61→ SessionMutationOptions,
62→} from './sdk/runtimeTypes.js'
63→
64→export type {
65→ ListSessionsOptions,
66→ GetSessionInfoOptions,
67→ SessionMutationOptions,
68→ ForkSessionOptions,
69→ ForkSessionResult,
70→ SDKSessionInfo,
71→}
72→
73→export function tool<Schema extends AnyZodRawShape>(
74→ _name: string,
75→ _description: string,
76→ _inputSchema: Schema,
77→ _handler: (
78→ args: InferShape<Schema>,
79→ extra: unknown,
80→ ) => Promise<CallToolResult>,
81→ _extras?: {
82→ annotations?: ToolAnnotations
83→ searchHint?: string
84→ alwaysLoad?: boolean
85→ },
86→): SdkMcpToolDefinition<Schema> {
87→ throw new Error('not implemented')
88→}
89→
90→type CreateSdkMcpServerOptions = {
91→ name: string
92→ version?: string
93→ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94→ tools?: Array<SdkMcpToolDefinition<any>>
95→}
96→
97→/**
98→ * Creates an MCP server instance that can be used with the SDK transport.
99→ * This allows SDK users to define custom tools that run in the same process.
100→ *Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/hooks/**/*.{ts,tsx} Status: Completed
src\hooks\fileSuggestions.ts src\hooks\notifs\useAutoModeUnavailableNotification.ts src\hooks\notifs\useCanSwitchToExistingSubscription.tsx src\hooks\notifs\useDeprecationWarningNotification.tsx src\hooks\notifs\useFastModeNotification.tsx src\hooks\notifs\useIDEStatusIndicator.tsx src\hooks\notifs\useInstallMessages.tsx src\hooks\notifs\useLspInitializationNotification.tsx src\hooks\notifs\useMcpConnectivityStatus.tsx src\hooks\notifs\useModelMigrationNotifications.tsx src\hooks\notifs\useNpmDeprecationNotification.tsx src\hooks\notifs\usePluginAutoupdateNotification.tsx src\hooks\notifs\usePluginInstallationStatus.tsx src\hooks\notifs\useRateLimitWarningNotification.tsx src\hooks\notifs\useSettingsErrors.tsx src\hooks\notifs\useStartupNotification.ts src\hooks\notifs\useTeammateShutdownNotification.ts src\hooks\renderPlaceholder.ts src\hooks\toolPermission\PermissionContext.ts src\hooks\toolPermission\handlers\coordinatorHandler.ts src\hooks\toolPermission\handlers\interactiveHandler.ts src\hooks\toolPermission\handlers\swarmWorkerHandler.ts src\hooks\toolPermission\permissionLogging.ts src\hooks\unifiedSuggestions.ts src\hooks\useAfterFirstRender.ts src\hooks\useApiKeyVerification.ts src\hooks\useArrowKeyHistory.tsx src\hooks\useAssistantHistory.ts src\hooks\useAwaySummary.ts src\hooks\useBackgroundTaskNavigation.ts src\hooks\useBlink.ts src\hooks\useCancelRequest.ts src\hooks\useCanUseTool.tsx src\hooks\useChromeExtensionNotification.tsx src\hooks\useClaudeCodeHintRecommendation.tsx src\hooks\useClipboardImageHint.ts src\hooks\useCommandKeybindings.tsx src\hooks\useCommandQueue.ts src\hooks\useCopyOnSelect.ts src\hooks\useDeferredHookMessages.ts src\hooks\useDiffData.ts src\hooks\useDiffInIDE.ts src\hooks\useDirectConnect.ts src\hooks\useDoublePress.ts src\hooks\useDynamicConfig.ts src\hooks\useElapsedTime.ts src\hooks\useExitOnCtrlCD.ts src\hooks\useExitOnCtrlCDWithKeybindings.ts src\hooks\useFileHistorySnapshotInit.ts src\hooks\useGlobalKeybindings.tsx src\hooks\useHistorySearch.ts src\hooks\useIdeAtMentioned.ts src\hooks\useIdeConnectionStatus.ts src\hooks\useIDEIntegration.tsx src\hooks\useIdeLogging.ts src\hooks\useIdeSelection.ts src\hooks\useInboxPoller.ts src\hooks\useInputBuffer.ts src\hooks\useIssueFlagBanner.ts src\hooks\useLogMessages.ts src\hooks\useLspPluginRecommendation.tsx src\hooks\useMailboxBridge.ts src\hooks\useMainLoopModel.ts src\hooks\useManagePlugins.ts src\hooks\useMemoryUsage.ts src\hooks\useMergedClients.ts src\hooks\useMergedCommands.ts src\hooks\useMergedTools.ts src\hooks\useMinDisplayTime.ts src\hooks\useNotifyAfterTimeout.ts src\hooks\useOfficialMarketplaceNotification.tsx src\hooks\usePasteHandler.ts src\hooks\usePluginRecommendationBase.tsx src\hooks\usePrStatus.ts src\hooks\usePromptsFromClaudeInChrome.tsx src\hooks\usePromptSuggestion.ts src\hooks\useQueueProcessor.ts src\hooks\useRemoteSession.ts src\hooks\useReplBridge.tsx src\hooks\useSSHSession.ts src\hooks\useScheduledTasks.ts src\hooks\useSearchInput.ts src\hooks\useSessionBackgrounding.ts src\hooks\useSettings.ts src\hooks\useSettingsChange.ts src\hooks\useSkillImprovementSurvey.ts src\hooks\useSkillsChange.ts src\hooks\useSwarmInitialization.ts src\hooks\useSwarmPermissionPoller.ts src\hooks\useTaskListWatcher.ts src\hooks\useTasksV2.ts src\hooks\useTeammateViewAutoExit.ts src\hooks\useTeleportResume.tsx src\hooks\useTerminalSize.ts src\hooks\useTextInput.ts src\hooks\useTimeout.ts src\hooks\useTurnDiffs.ts src\hooks\useTypeahead.tsx src\hooks\useUpdateNotification.ts src\hooks\useVimInput.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Read src\components\App.tsx (1 - 100) Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→import React from 'react';
3→import { FpsMetricsProvider } from '../context/fpsMetrics.js';
4→import { StatsProvider, type StatsStore } from '../context/stats.js';
5→import { type AppState, AppStateProvider } from '../state/AppState.js';
6→import { onChangeAppState } from '../state/onChangeAppState.js';
7→import type { FpsMetrics } from '../utils/fpsTracker.js';
8→type Props = {
9→ getFpsMetrics: () => FpsMetrics | undefined;
10→ stats?: StatsStore;
11→ initialState: AppState;
12→ children: React.ReactNode;
13→};
14→
15→/**
16→ * Top-level wrapper for interactive sessions.
17→ * Provides FPS metrics, stats context, and app state to the component tree.
18→ */
19→export function App(t0) {
20→ const $ = _c(9);
21→ const {
22→ getFpsMetrics,
23→ stats,
24→ initialState,
25→ children
26→ } = t0;
27→ let t1;
28→ if ($[0] !== children || $[1] !== initialState) {
29→ t1 = <AppStateProvider initialState={initialState} onChangeAppState={onChangeAppState}>{children}</AppStateProvider>;
30→ $[0] = children;
31→ $[1] = initialState;
32→ $[2] = t1;
33→ } else {
34→ t1 = $[2];
35→ }
36→ let t2;
37→ if ($[3] !== stats || $[4] !== t1) {
38→ t2 = <StatsProvider store={stats}>{t1}</StatsProvider>;
39→ $[3] = stats;
40→ $[4] = t1;
41→ $[5] = t2;
42→ } else {
43→ t2 = $[5];
44→ }
45→ let t3;
46→ if ($[6] !== getFpsMetrics || $[7] !== t2) {
47→ t3 = <FpsMetricsProvider getFpsMetrics={getFpsMetrics}>{t2}</FpsMetricsProvider>;
48→ $[6] = getFpsMetrics;
49→ $[7] = t2;
50→ $[8] = t3;
51→ } else {
52→ t3 = $[8];
53→ }
54→ return t3;
55→}
56→//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIkZwc01ldHJpY3NQcm92aWRlciIsIlN0YXRzUHJvdmlkZXIiLCJTdGF0c1N0b3JlIiwiQXBwU3RhdGUiLCJBcHBTdGF0ZVByb3ZpZGVyIiwib25DaGFuZ2VBcHBTdGF0ZSIsIkZwc01ldHJpY3MiLCJQcm9wcyIsImdldEZwc01ldHJpY3MiLCJzdGF0cyIsImluaXRpYWxTdGF0ZSIsImNoaWxkcmVuIiwiUmVhY3ROb2RlIiwiQXBwIiwidDAiLCIkIiwiX2MiLCJ0MSIsInQyIiwidDMiXSwic291cmNlcyI6WyJBcHAudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IEZwc01ldHJpY3NQcm92aWRlciB9IGZyb20gJy4uL2NvbnRleHQvZnBzTWV0cmljcy5qcydcbmltcG9ydCB7IFN0YXRzUHJvdmlkZXIsIHR5cGUgU3RhdHNTdG9yZSB9IGZyb20gJy4uL2NvbnRleHQvc3RhdHMuanMnXG5pbXBvcnQgeyB0eXBlIEFwcFN0YXRlLCBBcHBTdGF0ZVByb3ZpZGVyIH0gZnJvbSAnLi4vc3RhdGUvQXBwU3RhdGUuanMnXG5pbXBvcnQgeyBvbkNoYW5nZUFwcFN0YXRlIH0gZnJvbSAnLi4vc3RhdGUvb25DaGFuZ2VBcHBTdGF0ZS5qcydcbmltcG9ydCB0eXBlIHsgRnBzTWV0cmljcyB9IGZyb20gJy4uL3V0aWxzL2Zwc1RyYWNrZXIuanMnXG5cbnR5cGUgUHJvcHMgPSB7XG4gIGdldEZwc01ldHJpY3M6ICgpID0+IEZwc01ldHJpY3MgfCB1bmRlZmluZWRcbiAgc3RhdHM/OiBTdGF0c1N0b3JlXG4gIGluaXRpYWxTdGF0ZTogQXBwU3RhdGVcbiAgY2hpbGRyZW46IFJlYWN0LlJlYWN0Tm9kZVxufVxuXG4vKipcbiAqIFRvcC1sZXZlbCB3cmFwcGVyIGZvciBpbnRlcmFjdGl2ZSBzZXNzaW9ucy5cbiAqIFByb3ZpZGVzIEZQUyBtZXRyaWNzLCBzdGF0cyBjb250ZXh0LCBhbmQgYXBwIHN0YXRlIHRvIHRoZSBjb21wb25lbnQgdHJlZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwcCh7XG4gIGdldEZwc01ldHJpY3MsXG4gIHN0YXRzLFxuICBpbml0aWFsU3RhdGUsXG4gIGNoaWxkcmVuLFxufTogUHJvcHMpOiBSZWFjdC5SZWFjdE5vZGUge1xuICByZXR1cm4gKFxuICAgIDxGcHNNZXRyaWNzUHJvdmlkZXIgZ2V0RnBzTWV0cmljcz17Z2V0RnBzTWV0cmljc30+XG4gICAgICA8U3RhdHNQcm92aWRlciBzdG9yZT17c3RhdHN9PlxuICAgICAgICA8QXBwU3RhdGVQcm92aWRlclxuICAgICAgICAgIGluaXRpYWxTdGF0ZT17aW5pdGlhbFN0YXRlfVxuICAgICAgICAgIG9uQ2hhbmdlQXBwU3RhdGU9e29uQ2hhbmdlQXBwU3RhdGV9XG4gICAgICAgID5cbiAgICAgICAgICB7Y2hpbGRyZW59XG4gICAgICAgIDwvQXBwU3RhdGVQcm92aWRlcj5cbiAgICAgIDwvU3RhdHNQcm92aWRlcj5cbiAgICA8L0Zwc01ldHJpY3NQcm92aWRlcj5cbiAgKVxufVxuIl0sIm1hcHBpbmdzIjoiO0FBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsU0FBU0Msa0JBQWtCLFFBQVEsMEJBQTBCO0FBQzdELFNBQVNDLGFBQWEsRUFBRSxLQUFLQyxVQUFVLFFBQVEscUJBQXFCO0FBQ3BFLFNBQVMsS0FBS0MsUUFBUSxFQUFFQyxnQkFBZ0IsUUFBUSxzQkFBc0I7QUFDdEUsU0FBU0MsZ0JBQWdCLFFBQVEsOEJBQThCO0FBQy9ELGNBQWNDLFVBQVUsUUFBUSx3QkFBd0I7QUFFeEQsS0FBS0MsS0FBSyxHQUFHO0VBQ1hDLGFBQWEsRUFBRSxHQUFHLEdBQUdGLFVBQVUsR0FBRyxTQUFTO0VBQzNDRyxLQUFLLENBQUMsRUFBRVAsVUFBVTtFQUNsQlEsWUFBWSxFQUFFUCxRQUFRO0VBQ3RCUSxRQUFRLEVBQUVaLEtBQUssQ0FBQ2EsU0FBUztBQUMzQixDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFBQyxJQUFBQyxFQUFBO0VBQUEsTUFBQUMsQ0FBQSxHQUFBQyxFQUFBO0VBQWE7SUFBQVIsYUFBQTtJQUFBQyxLQUFBO0lBQUFDLFlBQUE7SUFBQUM7RUFBQSxJQUFBRyxFQUtaO0VBQUEsSUFBQUcsRUFBQTtFQUFBLElBQUFGLENBQUEsUUFBQUosUUFBQSxJQUFBSSxDQUFBLFFBQUFMLFlBQUE7SUFJQU8sRUFBQSxJQUFDLGdCQUFnQixDQUNEUCxZQUFZLENBQVpBLGFBQVcsQ0FBQyxDQUNSTCxnQkFBZ0IsQ0FBaEJBLGlCQUFlLENBQUMsQ0FFakNNLFNBQU8sQ0FDVixFQUxDLGdCQUFnQixDQUtFO0lBQUFJLENBQUEsTUFBQUosUUFBQTtJQUFBSSxDQUFBLE1BQUFMLFlBQUE7SUFBQUssQ0FBQSxNQUFBRSxFQUFBO0VBQUE7SUFBQUEsRUFBQSxHQUFBRixDQUFBO0VBQUE7RUFBQSxJQUFBRyxFQUFBO0VBQUEsSUFBQUgsQ0FBQSxRQUFBTixLQUFBLElBQUFNLENBQUEsUUFBQUUsRUFBQTtJQU5yQkMsRUFBQSxJQUFDLGFBQWEsQ0FBUVQsS0FBSyxDQUFMQSxNQUFJLENBQUMsQ0FDekIsQ0FBQVEsRUFLa0IsQ0FDcEIsRUFQQyxhQUFhLENBT0U7SUFBQUYsQ0FBQSxNQUFBTixLQUFBO0lBQUFNLENBQUEsTUFBQUUsRUFBQTtJQUFBRixDQUFBLE1BQUFHLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFILENBQUE7RUFBQTtFQUFBLElBQUFJLEVBQUE7RUFBQSxJQUFBSixDQUFBLFFBQUFQLGFBQUEsSUFBQU8sQ0FBQSxRQUFBRyxFQUFBO0lBUmxCQyxFQUFBLElBQUMsa0JBQWtCLENBQWdCWCxhQUFhLENBQWJBLGNBQVksQ0FBQyxDQUM5QyxDQUFBVSxFQU9lLENBQ2pCLEVBVEMsa0JBQWtCLENBU0U7SUFBQUgsQ0FBQSxNQUFBUCxhQUFBO0lBQUFPLENBQUEsTUFBQUcsRUFBQTtJQUFBSCxDQUFBLE1BQUFJLEVBQUE7RUFBQTtJQUFBQSxFQUFBLEdBQUFKLENBQUE7RUFBQTtFQUFBLE9BVHJCSSxFQVNxQjtBQUFBIiwiaWdub3JlTGlzdCI6W119Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/state/**/*.ts Status: Completed
src\state\AppStateStore.ts src\state\onChangeAppState.ts src\state\selectors.ts src\state\store.ts src\state\teammateViewHelpers.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/skills/**/* Status: Completed
src\skills\bundled\batch.ts src\skills\bundled\claudeApi.ts src\skills\bundled\claudeApiContent.ts src\skills\bundled\claudeInChrome.ts src\skills\bundled\debug.ts src\skills\bundled\index.ts src\skills\bundled\keybindings.ts src\skills\bundled\loop.ts src\skills\bundled\loremIpsum.ts src\skills\bundled\remember.ts src\skills\bundled\scheduleRemoteAgents.ts src\skills\bundled\simplify.ts src\skills\bundled\skillify.ts src\skills\bundled\stuck.ts src\skills\bundled\updateConfig.ts src\skills\bundled\verify.ts src\skills\bundled\verifyContent.ts src\skills\bundledSkills.ts src\skills\loadSkillsDir.ts src\skills\mcpSkillBuilders.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/plugins/**/* Status: Completed
src\plugins\builtinPlugins.ts src\plugins\bundled\index.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/utils/**/*.{ts,tsx} Status: Completed
src\utils\CircularBuffer.ts src\utils\Cursor.ts src\utils\QueryGuard.ts src\utils\Shell.ts src\utils\ShellCommand.ts src\utils\abortController.ts src\utils\activityManager.ts src\utils\advisor.ts src\utils\agentContext.ts src\utils\agenticSessionSearch.ts src\utils\agentId.ts src\utils\agentSwarmsEnabled.ts src\utils\analyzeContext.ts src\utils\ansiToPng.ts src\utils\ansiToSvg.ts src\utils\api.ts src\utils\apiPreconnect.ts src\utils\appleTerminalBackup.ts src\utils\argumentSubstitution.ts src\utils\array.ts src\utils\asciicast.ts src\utils\attachments.ts src\utils\attribution.ts src\utils\auth.ts src\utils\authFileDescriptor.ts src\utils\authPortable.ts src\utils\autoModeDenials.ts src\utils\autoRunIssue.tsx src\utils\autoUpdater.ts src\utils\aws.ts src\utils\awsAuthStatusManager.ts src\utils\background\remote\preconditions.ts src\utils\background\remote\remoteSession.ts src\utils\backgroundHousekeeping.ts src\utils\bash\ParsedCommand.ts src\utils\bash\ShellSnapshot.ts src\utils\bash\ast.ts src\utils\bash\bashParser.ts src\utils\bash\bashPipeCommand.ts src\utils\bash\commands.ts src\utils\bash\heredoc.ts src\utils\bash\parser.ts src\utils\bash\prefix.ts src\utils\bash\registry.ts src\utils\bash\shellCompletion.ts src\utils\bash\shellPrefix.ts src\utils\bash\shellQuote.ts src\utils\bash\shellQuoting.ts src\utils\bash\specs\alias.ts src\utils\bash\specs\index.ts src\utils\bash\specs\nohup.ts src\utils\bash\specs\pyright.ts src\utils\bash\specs\sleep.ts src\utils\bash\specs\srun.ts src\utils\bash\specs\time.ts src\utils\bash\specs\timeout.ts src\utils\bash\treeSitterAnalysis.ts src\utils\betas.ts src\utils\billing.ts src\utils\binaryCheck.ts src\utils\browser.ts src\utils\bufferedWriter.ts src\utils\bundledMode.ts src\utils\caCerts.ts src\utils\caCertsConfig.ts src\utils\cachePaths.ts src\utils\classifierApprovals.ts src\utils\classifierApprovalsHook.ts src\utils\claudeCodeHints.ts src\utils\claudeDesktop.ts src\utils\claudeInChrome\chromeNativeHost.ts src\utils\claudeInChrome\common.ts src\utils\claudeInChrome\mcpServer.ts src\utils\claudeInChrome\prompt.ts src\utils\claudeInChrome\setup.ts src\utils\claudeInChrome\setupPortable.ts src\utils\claudeInChrome\toolRendering.tsx src\utils\claudemd.ts src\utils\cleanup.ts src\utils\cleanupRegistry.ts src\utils\cliArgs.ts src\utils\cliHighlight.ts src\utils\codeIndexing.ts src\utils\collapseBackgroundBashNotifications.ts src\utils\collapseHookSummaries.ts src\utils\collapseReadSearch.ts src\utils\collapseTeammateShutdowns.ts src\utils\combinedAbortSignal.ts src\utils\commandLifecycle.ts src\utils\commitAttribution.ts src\utils\completionCache.ts src\utils\computerUse\appNames.ts src\utils\computerUse\cleanup.ts src\utils\computerUse\common.ts src\utils\computerUse\computerUseLock.ts src\utils\computerUse\drainRunLoop.ts src\utils\computerUse\escHotkey.ts src\utils\computerUse\executor.ts src\utils\computerUse\gates.ts src\utils\computerUse\hostAdapter.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/**/*.{ts,tsx} Status: Completed
src\types\command.ts src\types\generated\events_mono\claude_code\v1\claude_code_internal_event.ts src\types\generated\events_mono\common\v1\auth.ts src\types\generated\events_mono\growthbook\v1\growthbook_experiment_event.ts src\types\generated\google\protobuf\timestamp.ts src\types\hooks.ts src\types\ids.ts src\types\logs.ts src\types\permissions.ts src\types\plugin.ts src\types\textInputTypes.ts
Tool Call: Read src\state\AppStateStore.ts (1 - 100) Status: Completed
1→import type { Notification } from 'src/context/notifications.js'
2→import type { TodoList } from 'src/utils/todo/types.js'
3→import type { BridgePermissionCallbacks } from '../bridge/bridgePermissionCallbacks.js'
4→import type { Command } from '../commands.js'
5→import type { ChannelPermissionCallbacks } from '../services/mcp/channelPermissions.js'
6→import type { ElicitationRequestEvent } from '../services/mcp/elicitationHandler.js'
7→import type {
8→ MCPServerConnection,
9→ ServerResource,
10→} from '../services/mcp/types.js'
11→import { shouldEnablePromptSuggestion } from '../services/PromptSuggestion/promptSuggestion.js'
12→import {
13→ getEmptyToolPermissionContext,
14→ type Tool,
15→ type ToolPermissionContext,
16→} from '../Tool.js'
17→import type { TaskState } from '../tasks/types.js'
18→import type { AgentColorName } from '../tools/AgentTool/agentColorManager.js'
19→import type { AgentDefinitionsResult } from '../tools/AgentTool/loadAgentsDir.js'
20→import type { AllowedPrompt } from '../tools/ExitPlanModeTool/ExitPlanModeV2Tool.js'
21→import type { AgentId } from '../types/ids.js'
22→import type { Message, UserMessage } from '../types/message.js'
23→import type { LoadedPlugin, PluginError } from '../types/plugin.js'
24→import type { DeepImmutable } from '../types/utils.js'
25→import {
26→ type AttributionState,
27→ createEmptyAttributionState,
28→} from '../utils/commitAttribution.js'
29→import type { EffortValue } from '../utils/effort.js'
30→import type { FileHistoryState } from '../utils/fileHistory.js'
31→import type { REPLHookContext } from '../utils/hooks/postSamplingHooks.js'
32→import type { SessionHooksState } from '../utils/hooks/sessionHooks.js'
33→import type { ModelSetting } from '../utils/model/model.js'
34→import type { DenialTrackingState } from '../utils/permissions/denialTracking.js'
35→import type { PermissionMode } from '../utils/permissions/PermissionMode.js'
36→import { getInitialSettings } from '../utils/settings/settings.js'
37→import type { SettingsJson } from '../utils/settings/types.js'
38→import { shouldEnableThinkingByDefault } from '../utils/thinking.js'
39→import type { Store } from './store.js'
40→
41→export type CompletionBoundary =
42→ | { type: 'complete'; completedAt: number; outputTokens: number }
43→ | { type: 'bash'; command: string; completedAt: number }
44→ | { type: 'edit'; toolName: string; filePath: string; completedAt: number }
45→ | {
46→ type: 'denied_tool'
47→ toolName: string
48→ detail: string
49→ completedAt: number
50→ }
51→
52→export type SpeculationResult = {
53→ messages: Message[]
54→ boundary: CompletionBoundary | null
55→ timeSavedMs: number
56→}
57→
58→export type SpeculationState =
59→ | { status: 'idle' }
60→ | {
61→ status: 'active'
62→ id: string
63→ abort: () => void
64→ startTime: number
65→ messagesRef: { current: Message[] } // Mutable ref - avoids array spreading per message
66→ writtenPathsRef: { current: Set<string> } // Mutable ref - relative paths written to overlay
67→ boundary: CompletionBoundary | null
68→ suggestionLength: number
69→ toolUseCount: number
70→ isPipelined: boolean
71→ contextRef: { current: REPLHookContext }
72→ pipelinedSuggestion?: {
73→ text: string
74→ promptId: 'user_intent' | 'stated_intent'
75→ generationRequestId: string | null
76→ } | null
77→ }
78→
79→export const IDLE_SPECULATION_STATE: SpeculationState = { status: 'idle' }
80→
81→export type FooterItem =
82→ | 'tasks'
83→ | 'tmux'
84→ | 'bagel'
85→ | 'teams'
86→ | 'bridge'
87→ | 'companion'
88→
89→export type AppState = DeepImmutable<{
90→ settings: SettingsJson
91→ verbose: boolean
92→ mainLoopModel: ModelSetting
93→ mainLoopModelForSession: ModelSetting
94→ statusLineText: string | undefined
95→ expandedView: 'none' | 'tasks' | 'teammates'
96→ isBriefOnly: boolean
97→ // Optional - only present when ENABLE_AGENT_SWARMS is true (for dead code elimination)
98→ showTeammateMessagePreview?: boolean
99→ selectedIPAgentIndex: number
100→ // CoordinatorTaskPanel selection: -1 = pill, 0 = main, 1..N = agent rows.Tool Call: Read src\state\store.ts (1 - 80) Status: Completed
1→type Listener = () => void
2→type OnChange<T> = (args: { newState: T; oldState: T }) => void
3→
4→export type Store<T> = {
5→ getState: () => T
6→ setState: (updater: (prev: T) => T) => void
7→ subscribe: (listener: Listener) => () => void
8→}
9→
10→export function createStore<T>(
11→ initialState: T,
12→ onChange?: OnChange<T>,
13→): Store<T> {
14→ let state = initialState
15→ const listeners = new Set<Listener>()
16→
17→ return {
18→ getState: () => state,
19→
20→ setState: (updater: (prev: T) => T) => {
21→ const prev = state
22→ const next = updater(prev)
23→ if (Object.is(next, prev)) return
24→ state = next
25→ onChange?.({ newState: next, oldState: prev })
26→ for (const listener of listeners) listener()
27→ },
28→
29→ subscribe: (listener: Listener) => {
30→ listeners.add(listener)
31→ return () => listeners.delete(listener)
32→ },
33→ }
34→}
35→Tool Call: Read src\skills\loadSkillsDir.ts (1 - 80) Status: Completed
1→import { realpath } from 'fs/promises'
2→import ignore from 'ignore'
3→import memoize from 'lodash-es/memoize.js'
4→import {
5→ basename,
6→ dirname,
7→ isAbsolute,
8→ join,
9→ sep as pathSep,
10→ relative,
11→} from 'path'
12→import {
13→ getAdditionalDirectoriesForClaudeMd,
14→ getSessionId,
15→} from '../bootstrap/state.js'
16→import {
17→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
18→ logEvent,
19→} from '../services/analytics/index.js'
20→import { roughTokenCountEstimation } from '../services/tokenEstimation.js'
21→import type { Command, PromptCommand } from '../types/command.js'
22→import {
23→ parseArgumentNames,
24→ substituteArguments,
25→} from '../utils/argumentSubstitution.js'
26→import { logForDebugging } from '../utils/debug.js'
27→import {
28→ EFFORT_LEVELS,
29→ type EffortValue,
30→ parseEffortValue,
31→} from '../utils/effort.js'
32→import {
33→ getClaudeConfigHomeDir,
34→ isBareMode,
35→ isEnvTruthy,
36→} from '../utils/envUtils.js'
37→import { isENOENT, isFsInaccessible } from '../utils/errors.js'
38→import {
39→ coerceDescriptionToString,
40→ type FrontmatterData,
41→ type FrontmatterShell,
42→ parseBooleanFrontmatter,
43→ parseFrontmatter,
44→ parseShellFrontmatter,
45→ splitPathInFrontmatter,
46→} from '../utils/frontmatterParser.js'
47→import { getFsImplementation } from '../utils/fsOperations.js'
48→import { isPathGitignored } from '../utils/git/gitignore.js'
49→import { logError } from '../utils/log.js'
50→import {
51→ extractDescriptionFromMarkdown,
52→ getProjectDirsUpToHome,
53→ loadMarkdownFilesForSubdir,
54→ type MarkdownFile,
55→ parseSlashCommandToolsFromFrontmatter,
56→} from '../utils/markdownConfigLoader.js'
57→import { parseUserSpecifiedModel } from '../utils/model/model.js'
58→import { executeShellCommandsInPrompt } from '../utils/promptShellExecution.js'
59→import type { SettingSource } from '../utils/settings/constants.js'
60→import { isSettingSourceEnabled } from '../utils/settings/constants.js'
61→import { getManagedFilePath } from '../utils/settings/managedPath.js'
62→import { isRestrictedToPluginOnly } from '../utils/settings/pluginOnlyPolicy.js'
63→import { HooksSchema, type HooksSettings } from '../utils/settings/types.js'
64→import { createSignal } from '../utils/signal.js'
65→import { registerMCPSkillBuilders } from './mcpSkillBuilders.js'
66→
67→export type LoadedFrom =
68→ | 'commands_DEPRECATED'
69→ | 'skills'
70→ | 'plugin'
71→ | 'managed'
72→ | 'bundled'
73→ | 'mcp'
74→
75→/**
76→ * Returns a claude config directory path for a given source.
77→ */
78→export function getSkillsPath(
79→ source: SettingSource | 'plugin',
80→ dir: 'skills' | 'commands',Tool Call: Read src\types\hooks.ts Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import { z } from 'zod/v4'
3→import { lazySchema } from '../utils/lazySchema.js'
4→import {
5→ type HookEvent,
6→ HOOK_EVENTS,
7→ type HookInput,
8→ type PermissionUpdate,
9→} from 'src/entrypoints/agentSdkTypes.js'
10→import type {
11→ HookJSONOutput,
12→ AsyncHookJSONOutput,
13→ SyncHookJSONOutput,
14→} from 'src/entrypoints/agentSdkTypes.js'
15→import type { Message } from 'src/types/message.js'
16→import type { PermissionResult } from 'src/utils/permissions/PermissionResult.js'
17→import { permissionBehaviorSchema } from 'src/utils/permissions/PermissionRule.js'
18→import { permissionUpdateSchema } from 'src/utils/permissions/PermissionUpdateSchema.js'
19→import type { AppState } from '../state/AppState.js'
20→import type { AttributionState } from '../utils/commitAttribution.js'
21→
22→export function isHookEvent(value: string): value is HookEvent {
23→ return HOOK_EVENTS.includes(value as HookEvent)
24→}
25→
26→// Prompt elicitation protocol types. The `prompt` key acts as discriminator
27→// (mirroring the {async:true} pattern), with the id as its value.
28→export const promptRequestSchema = lazySchema(() =>
29→ z.object({
30→ prompt: z.string(), // request id
31→ message: z.string(),
32→ options: z.array(
33→ z.object({
34→ key: z.string(),
35→ label: z.string(),
36→ description: z.string().optional(),
37→ }),
38→ ),
39→ }),
40→)
41→
42→export type PromptRequest = z.infer<ReturnType<typeof promptRequestSchema>>
43→
44→export type PromptResponse = {
45→ prompt_response: string // request id
46→ selected: string
47→}
48→
49→// Sync hook response schema
50→export const syncHookResponseSchema = lazySchema(() =>
51→ z.object({
52→ continue: z
53→ .boolean()
54→ .describe('Whether Claude should continue after hook (default: true)')
55→ .optional(),
56→ suppressOutput: z
57→ .boolean()
58→ .describe('Hide stdout from transcript (default: false)')
59→ .optional(),
60→ stopReason: z
61→ .string()
62→ .describe('Message shown when continue is false')
63→ .optional(),
64→ decision: z.enum(['approve', 'block']).optional(),
65→ reason: z.string().describe('Explanation for the decision').optional(),
66→ systemMessage: z
67→ .string()
68→ .describe('Warning message shown to the user')
69→ .optional(),
70→ hookSpecificOutput: z
71→ .union([
72→ z.object({
73→ hookEventName: z.literal('PreToolUse'),
74→ permissionDecision: permissionBehaviorSchema().optional(),
75→ permissionDecisionReason: z.string().optional(),
76→ updatedInput: z.record(z.string(), z.unknown()).optional(),
77→ additionalContext: z.string().optional(),
78→ }),
79→ z.object({
80→ hookEventName: z.literal('UserPromptSubmit'),
81→ additionalContext: z.string().optional(),
82→ }),
83→ z.object({
84→ hookEventName: z.literal('SessionStart'),
85→ additionalContext: z.string().optional(),
86→ initialUserMessage: z.string().optional(),
87→ watchPaths: z
88→ .array(z.string())
89→ .describe('Absolute paths to watch for FileChanged hooks')
90→ .optional(),
91→ }),
92→ z.object({
93→ hookEventName: z.literal('Setup'),
94→ additionalContext: z.string().optional(),
95→ }),
96→ z.object({
97→ hookEventName: z.literal('SubagentStart'),
98→ additionalContext: z.string().optional(),
99→ }),
100→ z.object({
101→ hookEventName: z.literal('PostToolUse'),
102→ additionalContext: z.string().optional(),
103→ updatedMCPToolOutput: z
104→ .unknown()
105→ .describe('Updates the output for MCP tools')
106→ .optional(),
107→ }),
108→ z.object({
109→ hookEventName: z.literal('PostToolUseFailure'),
110→ additionalContext: z.string().optional(),
111→ }),
112→ z.object({
113→ hookEventName: z.literal('PermissionDenied'),
114→ retry: z.boolean().optional(),
115→ }),
116→ z.object({
117→ hookEventName: z.literal('Notification'),
118→ additionalContext: z.string().optional(),
119→ }),
120→ z.object({
121→ hookEventName: z.literal('PermissionRequest'),
122→ decision: z.union([
123→ z.object({
124→ behavior: z.literal('allow'),
125→ updatedInput: z.record(z.string(), z.unknown()).optional(),
126→ updatedPermissions: z.array(permissionUpdateSchema()).optional(),
127→ }),
128→ z.object({
129→ behavior: z.literal('deny'),
130→ message: z.string().optional(),
131→ interrupt: z.boolean().optional(),
132→ }),
133→ ]),
134→ }),
135→ z.object({
136→ hookEventName: z.literal('Elicitation'),
137→ action: z.enum(['accept', 'decline', 'cancel']).optional(),
138→ content: z.record(z.string(), z.unknown()).optional(),
139→ }),
140→ z.object({
141→ hookEventName: z.literal('ElicitationResult'),
142→ action: z.enum(['accept', 'decline', 'cancel']).optional(),
143→ content: z.record(z.string(), z.unknown()).optional(),
144→ }),
145→ z.object({
146→ hookEventName: z.literal('CwdChanged'),
147→ watchPaths: z
148→ .array(z.string())
149→ .describe('Absolute paths to watch for FileChanged hooks')
150→ .optional(),
151→ }),
152→ z.object({
153→ hookEventName: z.literal('FileChanged'),
154→ watchPaths: z
155→ .array(z.string())
156→ .describe('Absolute paths to watch for FileChanged hooks')
157→ .optional(),
158→ }),
159→ z.object({
160→ hookEventName: z.literal('WorktreeCreate'),
161→ worktreePath: z.string(),
162→ }),
163→ ])
164→ .optional(),
165→ }),
166→)
167→
168→// Zod schema for hook JSON output validation
169→export const hookJSONOutputSchema = lazySchema(() => {
170→ // Async hook response schema
171→ const asyncHookResponseSchema = z.object({
172→ async: z.literal(true),
173→ asyncTimeout: z.number().optional(),
174→ })
175→ return z.union([asyncHookResponseSchema, syncHookResponseSchema()])
176→})
177→
178→// Infer the TypeScript type from the schema
179→type SchemaHookJSONOutput = z.infer<ReturnType<typeof hookJSONOutputSchema>>
180→
181→// Type guard function to check if response is sync
182→export function isSyncHookJSONOutput(
183→ json: HookJSONOutput,
184→): json is SyncHookJSONOutput {
185→ return !('async' in json && json.async === true)
186→}
187→
188→// Type guard function to check if response is async
189→export function isAsyncHookJSONOutput(
190→ json: HookJSONOutput,
191→): json is AsyncHookJSONOutput {
192→ return 'async' in json && json.async === true
193→}
194→
195→// Compile-time assertion that SDK and Zod types match
196→import type { IsEqual } from 'type-fest'
197→type Assert<T extends true> = T
198→type _assertSDKTypesMatch = Assert<
199→ IsEqual<SchemaHookJSONOutput, HookJSONOutput>
200→>
201→
202→/** Context passed to callback hooks for state access */
203→export type HookCallbackContext = {
204→ getAppState: () => AppState
205→ updateAttributionState: (
206→ updater: (prev: AttributionState) => AttributionState,
207→ ) => void
208→}
209→
210→/** Hook that is a callback. */
211→export type HookCallback = {
212→ type: 'callback'
213→ callback: (
214→ input: HookInput,
215→ toolUseID: string | null,
216→ abort: AbortSignal | undefined,
217→ /** Hook index for SessionStart hooks to compute CLAUDE_ENV_FILE path */
218→ hookIndex?: number,
219→ /** Optional context for accessing app state */
220→ context?: HookCallbackContext,
221→ ) => Promise<HookJSONOutput>
222→ /** Timeout in seconds for this hook */
223→ timeout?: number
224→ /** Internal hooks (e.g. session file access analytics) are excluded from tengu_run_hook metrics */
225→ internal?: boolean
226→}
227→
228→export type HookCallbackMatcher = {
229→ matcher?: string
230→ hooks: HookCallback[]
231→ pluginName?: string
232→}
233→
234→export type HookProgress = {
235→ type: 'hook_progress'
236→ hookEvent: HookEvent
237→ hookName: string
238→ command: string
239→ promptText?: string
240→ statusMessage?: string
241→}
242→
243→export type HookBlockingError = {
244→ blockingError: string
245→ command: string
246→}
247→
248→export type PermissionRequestResult =
249→ | {
250→ behavior: 'allow'
251→ updatedInput?: Record<string, unknown>
252→ updatedPermissions?: PermissionUpdate[]
253→ }
254→ | {
255→ behavior: 'deny'
256→ message?: string
257→ interrupt?: boolean
258→ }
259→
260→export type HookResult = {
261→ message?: Message
262→ systemMessage?: Message
263→ blockingError?: HookBlockingError
264→ outcome: 'success' | 'blocking' | 'non_blocking_error' | 'cancelled'
265→ preventContinuation?: boolean
266→ stopReason?: string
267→ permissionBehavior?: 'ask' | 'deny' | 'allow' | 'passthrough'
268→ hookPermissionDecisionReason?: string
269→ additionalContext?: string
270→ initialUserMessage?: string
271→ updatedInput?: Record<string, unknown>
272→ updatedMCPToolOutput?: unknown
273→ permissionRequestResult?: PermissionRequestResult
274→ retry?: boolean
275→}
276→
277→export type AggregatedHookResult = {
278→ message?: Message
279→ blockingErrors?: HookBlockingError[]
280→ preventContinuation?: boolean
281→ stopReason?: string
282→ hookPermissionDecisionReason?: string
283→ permissionBehavior?: PermissionResult['behavior']
284→ additionalContexts?: string[]
285→ initialUserMessage?: string
286→ updatedInput?: Record<string, unknown>
287→ updatedMCPToolOutput?: unknown
288→ permissionRequestResult?: PermissionRequestResult
289→ retry?: boolean
290→}
291→Tool Call: Read src\types\command.ts (1 - 80) Status: Completed
1→import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
2→import type { UUID } from 'crypto'
3→import type { CanUseToolFn } from '../hooks/useCanUseTool.js'
4→import type { CompactionResult } from '../services/compact/compact.js'
5→import type { ScopedMcpServerConfig } from '../services/mcp/types.js'
6→import type { ToolUseContext } from '../Tool.js'
7→import type { EffortValue } from '../utils/effort.js'
8→import type { IDEExtensionInstallationStatus, IdeType } from '../utils/ide.js'
9→import type { SettingSource } from '../utils/settings/constants.js'
10→import type { HooksSettings } from '../utils/settings/types.js'
11→import type { ThemeName } from '../utils/theme.js'
12→import type { LogOption } from './logs.js'
13→import type { Message } from './message.js'
14→import type { PluginManifest } from './plugin.js'
15→
16→export type LocalCommandResult =
17→ | { type: 'text'; value: string }
18→ | {
19→ type: 'compact'
20→ compactionResult: CompactionResult
21→ displayText?: string
22→ }
23→ | { type: 'skip' } // Skip messages
24→
25→export type PromptCommand = {
26→ type: 'prompt'
27→ progressMessage: string
28→ contentLength: number // Length of command content in characters (used for token estimation)
29→ argNames?: string[]
30→ allowedTools?: string[]
31→ model?: string
32→ source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
33→ pluginInfo?: {
34→ pluginManifest: PluginManifest
35→ repository: string
36→ }
37→ disableNonInteractive?: boolean
38→ // Hooks to register when this skill is invoked
39→ hooks?: HooksSettings
40→ // Base directory for skill resources (used to set CLAUDE_PLUGIN_ROOT environment variable for skill hooks)
41→ skillRoot?: string
42→ // Execution context: 'inline' (default) or 'fork' (run as sub-agent)
43→ // 'inline' = skill content expands into the current conversation
44→ // 'fork' = skill runs in a sub-agent with separate context and token budget
45→ context?: 'inline' | 'fork'
46→ // Agent type to use when forked (e.g., 'Bash', 'general-purpose')
47→ // Only applicable when context is 'fork'
48→ agent?: string
49→ effort?: EffortValue
50→ // Glob patterns for file paths this skill applies to
51→ // When set, the skill is only visible after the model touches matching files
52→ paths?: string[]
53→ getPromptForCommand(
54→ args: string,
55→ context: ToolUseContext,
56→ ): Promise<ContentBlockParam[]>
57→}
58→
59→/**
60→ * The call signature for a local command implementation.
61→ */
62→export type LocalCommandCall = (
63→ args: string,
64→ context: LocalJSXCommandContext,
65→) => Promise<LocalCommandResult>
66→
67→/**
68→ * Module shape returned by load() for lazy-loaded local commands.
69→ */
70→export type LocalCommandModule = {
71→ call: LocalCommandCall
72→}
73→
74→type LocalCommand = {
75→ type: 'local'
76→ supportsNonInteractive: boolean
77→ load: () => Promise<LocalCommandModule>
78→}
79→
80→export type LocalJSXCommandContext = ToolUseContext & {Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/screens/**/*.{ts,tsx} Status: Completed
src\screens\Doctor.tsx src\screens\REPL.tsx src\screens\ResumeConversation.tsx
Tool Call: Read src\state\AppStateStore.ts (100 - 219) Status: Completed
100→ // CoordinatorTaskPanel selection: -1 = pill, 0 = main, 1..N = agent rows.
101→ // AppState (not local) so the panel can read it directly without prop-drilling
102→ // through PromptInput → PromptInputFooter.
103→ coordinatorTaskIndex: number
104→ viewSelectionMode: 'none' | 'selecting-agent' | 'viewing-agent'
105→ // Which footer pill is focused (arrow-key navigation below the prompt).
106→ // Lives in AppState so pill components rendered outside PromptInput
107→ // (CompanionSprite in REPL.tsx) can read their own focused state.
108→ footerSelection: FooterItem | null
109→ toolPermissionContext: ToolPermissionContext
110→ spinnerTip?: string
111→ // Agent name from --agent CLI flag or settings (for logo display)
112→ agent: string | undefined
113→ // Assistant mode fully enabled (settings + GrowthBook gate + trust).
114→ // Single source of truth - computed once in main.tsx before option
115→ // mutation, consumers read this instead of re-calling isAssistantMode().
116→ kairosEnabled: boolean
117→ // Remote session URL for --remote mode (shown in footer indicator)
118→ remoteSessionUrl: string | undefined
119→ // Remote session WS state (`claude assistant` viewer). 'connected' means the
120→ // live event stream is open; 'reconnecting' = transient WS drop, backoff
121→ // in progress; 'disconnected' = permanent close or reconnects exhausted.
122→ remoteConnectionStatus:
123→ | 'connecting'
124→ | 'connected'
125→ | 'reconnecting'
126→ | 'disconnected'
127→ // `claude assistant`: count of background tasks (Agent calls, teammates,
128→ // workflows) running inside the REMOTE daemon child. Event-sourced from
129→ // system/task_started and system/task_notification on the WS. The local
130→ // AppState.tasks is always empty in viewer mode — the tasks live in a
131→ // different process.
132→ remoteBackgroundTaskCount: number
133→ // Always-on bridge: desired state (controlled by /config or footer toggle)
134→ replBridgeEnabled: boolean
135→ // Always-on bridge: true when activated via /remote-control command, false when config-driven
136→ replBridgeExplicit: boolean
137→ // Outbound-only mode: forward events to CCR but reject inbound prompts/control
138→ replBridgeOutboundOnly: boolean
139→ // Always-on bridge: env registered + session created (= "Ready")
140→ replBridgeConnected: boolean
141→ // Always-on bridge: ingress WebSocket is open (= "Connected" - user on claude.ai)
142→ replBridgeSessionActive: boolean
143→ // Always-on bridge: poll loop is in error backoff (= "Reconnecting")
144→ replBridgeReconnecting: boolean
145→ // Always-on bridge: connect URL for Ready state (?bridge=envId)
146→ replBridgeConnectUrl: string | undefined
147→ // Always-on bridge: session URL on claude.ai (set when connected)
148→ replBridgeSessionUrl: string | undefined
149→ // Always-on bridge: IDs for debugging (shown in dialog when --verbose)
150→ replBridgeEnvironmentId: string | undefined
151→ replBridgeSessionId: string | undefined
152→ // Always-on bridge: error message when connection fails (shown in BridgeDialog)
153→ replBridgeError: string | undefined
154→ // Always-on bridge: session name set via `/remote-control <name>` (used as session title)
155→ replBridgeInitialName: string | undefined
156→ // Always-on bridge: first-time remote dialog pending (set by /remote-control command)
157→ showRemoteCallout: boolean
158→}> & {
159→ // Unified task state - excluded from DeepImmutable because TaskState contains function types
160→ tasks: { [taskId: string]: TaskState }
161→ // Name → AgentId registry populated by Agent tool when `name` is provided.
162→ // Latest-wins on collision. Used by SendMessage to route by name.
163→ agentNameRegistry: Map<string, AgentId>
164→ // Task ID that has been foregrounded - its messages are shown in main view
165→ foregroundedTaskId?: string
166→ // Task ID of in-process teammate whose transcript is being viewed (undefined = leader's view)
167→ viewingAgentTaskId?: string
168→ // Latest companion reaction from the friend observer (src/buddy/observer.ts)
169→ companionReaction?: string
170→ // Timestamp of last /buddy pet — CompanionSprite renders hearts while recent
171→ companionPetAt?: number
172→ // TODO (ashwin): see if we can use utility-types DeepReadonly for this
173→ mcp: {
174→ clients: MCPServerConnection[]
175→ tools: Tool[]
176→ commands: Command[]
177→ resources: Record<string, ServerResource[]>
178→ /**
179→ * Incremented by /reload-plugins to trigger MCP effects to re-run
180→ * and pick up newly-enabled plugin MCP servers. Effects read this
181→ * as a dependency; the value itself is not consumed.
182→ */
183→ pluginReconnectKey: number
184→ }
185→ plugins: {
186→ enabled: LoadedPlugin[]
187→ disabled: LoadedPlugin[]
188→ commands: Command[]
189→ /**
190→ * Plugin system errors collected during loading and initialization.
191→ * See {@link PluginError} type documentation for complete details on error
192→ * structure, context fields, and display format.
193→ */
194→ errors: PluginError[]
195→ // Installation status for background plugin/marketplace installation
196→ installationStatus: {
197→ marketplaces: Array<{
198→ name: string
199→ status: 'pending' | 'installing' | 'installed' | 'failed'
200→ error?: string
201→ }>
202→ plugins: Array<{
203→ id: string
204→ name: string
205→ status: 'pending' | 'installing' | 'installed' | 'failed'
206→ error?: string
207→ }>
208→ }
209→ /**
210→ * Set to true when plugin state on disk has changed (background reconcile,
211→ * /plugin menu install, external settings edit) and active components are
212→ * stale. In interactive mode, user runs /reload-plugins to consume. In
213→ * headless mode, refreshPluginState() auto-consumes via refreshActivePlugins().
214→ */
215→ needsRefresh: boolean
216→ }
217→ agentDefinitions: AgentDefinitionsResult
218→ fileHistory: FileHistoryState
219→ attribution: AttributionStateTool Call: Find D:\code\play\stock_ai_rust\claude-code src/context/**/*.{ts,tsx} Status: Completed
src\context\fpsMetrics.tsx src\context\mailbox.tsx src\context\QueuedMessageContext.tsx src\context\modalContext.tsx src\context\notifications.tsx src\context\overlayContext.tsx src\context\promptOverlayContext.tsx src\context\stats.tsx src\context\voice.tsx
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/replLauncher* Status: Completed
src\replLauncher.tsx
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/message.ts Status: Completed
No files found
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/query.ts Status: Completed
src\query.ts
Tool Call: Read src\replLauncher.tsx (1 - 120) Status: Completed
1→import React from 'react';
2→import type { StatsStore } from './context/stats.js';
3→import type { Root } from './ink.js';
4→import type { Props as REPLProps } from './screens/REPL.js';
5→import type { AppState } from './state/AppStateStore.js';
6→import type { FpsMetrics } from './utils/fpsTracker.js';
7→type AppWrapperProps = {
8→ getFpsMetrics: () => FpsMetrics | undefined;
9→ stats?: StatsStore;
10→ initialState: AppState;
11→};
12→export async function launchRepl(root: Root, appProps: AppWrapperProps, replProps: REPLProps, renderAndRun: (root: Root, element: React.ReactNode) => Promise<void>): Promise<void> {
13→ const {
14→ App
15→ } = await import('./components/App.js');
16→ const {
17→ REPL
18→ } = await import('./screens/REPL.js');
19→ await renderAndRun(root, <App {...appProps}>
20→ <REPL {...replProps} />
21→ </App>);
22→}
23→//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlN0YXRzU3RvcmUiLCJSb290IiwiUHJvcHMiLCJSRVBMUHJvcHMiLCJBcHBTdGF0ZSIsIkZwc01ldHJpY3MiLCJBcHBXcmFwcGVyUHJvcHMiLCJnZXRGcHNNZXRyaWNzIiwic3RhdHMiLCJpbml0aWFsU3RhdGUiLCJsYXVuY2hSZXBsIiwicm9vdCIsImFwcFByb3BzIiwicmVwbFByb3BzIiwicmVuZGVyQW5kUnVuIiwiZWxlbWVudCIsIlJlYWN0Tm9kZSIsIlByb21pc2UiLCJBcHAiLCJSRVBMIl0sInNvdXJjZXMiOlsicmVwbExhdW5jaGVyLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgdHlwZSB7IFN0YXRzU3RvcmUgfSBmcm9tICcuL2NvbnRleHQvc3RhdHMuanMnXG5pbXBvcnQgdHlwZSB7IFJvb3QgfSBmcm9tICcuL2luay5qcydcbmltcG9ydCB0eXBlIHsgUHJvcHMgYXMgUkVQTFByb3BzIH0gZnJvbSAnLi9zY3JlZW5zL1JFUEwuanMnXG5pbXBvcnQgdHlwZSB7IEFwcFN0YXRlIH0gZnJvbSAnLi9zdGF0ZS9BcHBTdGF0ZVN0b3JlLmpzJ1xuaW1wb3J0IHR5cGUgeyBGcHNNZXRyaWNzIH0gZnJvbSAnLi91dGlscy9mcHNUcmFja2VyLmpzJ1xuXG50eXBlIEFwcFdyYXBwZXJQcm9wcyA9IHtcbiAgZ2V0RnBzTWV0cmljczogKCkgPT4gRnBzTWV0cmljcyB8IHVuZGVmaW5lZFxuICBzdGF0cz86IFN0YXRzU3RvcmVcbiAgaW5pdGlhbFN0YXRlOiBBcHBTdGF0ZVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbGF1bmNoUmVwbChcbiAgcm9vdDogUm9vdCxcbiAgYXBwUHJvcHM6IEFwcFdyYXBwZXJQcm9wcyxcbiAgcmVwbFByb3BzOiBSRVBMUHJvcHMsXG4gIHJlbmRlckFuZFJ1bjogKHJvb3Q6IFJvb3QsIGVsZW1lbnQ6IFJlYWN0LlJlYWN0Tm9kZSkgPT4gUHJvbWlzZTx2b2lkPixcbik6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IEFwcCB9ID0gYXdhaXQgaW1wb3J0KCcuL2NvbXBvbmVudHMvQXBwLmpzJylcbiAgY29uc3QgeyBSRVBMIH0gPSBhd2FpdCBpbXBvcnQoJy4vc2NyZWVucy9SRVBMLmpzJylcbiAgYXdhaXQgcmVuZGVyQW5kUnVuKFxuICAgIHJvb3QsXG4gICAgPEFwcCB7Li4uYXBwUHJvcHN9PlxuICAgICAgPFJFUEwgey4uLnJlcGxQcm9wc30gLz5cbiAgICA8L0FwcD4sXG4gIClcbn1cbiJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBT0EsS0FBSyxNQUFNLE9BQU87QUFDekIsY0FBY0MsVUFBVSxRQUFRLG9CQUFvQjtBQUNwRCxjQUFjQyxJQUFJLFFBQVEsVUFBVTtBQUNwQyxjQUFjQyxLQUFLLElBQUlDLFNBQVMsUUFBUSxtQkFBbUI7QUFDM0QsY0FBY0MsUUFBUSxRQUFRLDBCQUEwQjtBQUN4RCxjQUFjQyxVQUFVLFFBQVEsdUJBQXVCO0FBRXZELEtBQUtDLGVBQWUsR0FBRztFQUNyQkMsYUFBYSxFQUFFLEdBQUcsR0FBR0YsVUFBVSxHQUFHLFNBQVM7RUFDM0NHLEtBQUssQ0FBQyxFQUFFUixVQUFVO0VBQ2xCUyxZQUFZLEVBQUVMLFFBQVE7QUFDeEIsQ0FBQztBQUVELE9BQU8sZUFBZU0sVUFBVUEsQ0FDOUJDLElBQUksRUFBRVYsSUFBSSxFQUNWVyxRQUFRLEVBQUVOLGVBQWUsRUFDekJPLFNBQVMsRUFBRVYsU0FBUyxFQUNwQlcsWUFBWSxFQUFFLENBQUNILElBQUksRUFBRVYsSUFBSSxFQUFFYyxPQUFPLEVBQUVoQixLQUFLLENBQUNpQixTQUFTLEVBQUUsR0FBR0MsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUN0RSxFQUFFQSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7RUFDZixNQUFNO0lBQUVDO0VBQUksQ0FBQyxHQUFHLE1BQU0sTUFBTSxDQUFDLHFCQUFxQixDQUFDO0VBQ25ELE1BQU07SUFBRUM7RUFBSyxDQUFDLEdBQUcsTUFBTSxNQUFNLENBQUMsbUJBQW1CLENBQUM7RUFDbEQsTUFBTUwsWUFBWSxDQUNoQkgsSUFBSSxFQUNKLENBQUMsR0FBRyxDQUFDLElBQUlDLFFBQVEsQ0FBQztBQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUlDLFNBQVMsQ0FBQztBQUMxQixJQUFJLEVBQUUsR0FBRyxDQUNQLENBQUM7QUFDSCIsImlnbm9yZUxpc3QiOltdfQ==Tool Call: Read src\screens\REPL.tsx (1 - 60) Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
3→import { feature } from 'bun:bundle';
4→import { spawnSync } from 'child_process';
5→import { snapshotOutputTokensForTurn, getCurrentTurnTokenBudget, getTurnOutputTokens, getBudgetContinuationCount, getTotalInputTokens } from '../bootstrap/state.js';
6→import { parseTokenBudget } from '../utils/tokenBudget.js';
7→import { count } from '../utils/array.js';
8→import { dirname, join } from 'path';
9→import { tmpdir } from 'os';
10→import figures from 'figures';
11→// eslint-disable-next-line custom-rules/prefer-use-keybindings -- / n N Esc [ v are bare letters in transcript modal context, same class as g/G/j/k in ScrollKeybindingHandler
12→import { useInput } from '../ink.js';
13→import { useSearchInput } from '../hooks/useSearchInput.js';
14→import { useTerminalSize } from '../hooks/useTerminalSize.js';
15→import { useSearchHighlight } from '../ink/hooks/use-search-highlight.js';
16→import type { JumpHandle } from '../components/VirtualMessageList.js';
17→import { renderMessagesToPlainText } from '../utils/exportRenderer.js';
18→import { openFileInExternalEditor } from '../utils/editor.js';
19→import { writeFile } from 'fs/promises';
20→import { Box, Text, useStdin, useTheme, useTerminalFocus, useTerminalTitle, useTabStatus } from '../ink.js';
21→import type { TabStatusKind } from '../ink/hooks/use-tab-status.js';
22→import { CostThresholdDialog } from '../components/CostThresholdDialog.js';
23→import { IdleReturnDialog } from '../components/IdleReturnDialog.js';
24→import * as React from 'react';
25→import { useEffect, useMemo, useRef, useState, useCallback, useDeferredValue, useLayoutEffect, type RefObject } from 'react';
26→import { useNotifications } from '../context/notifications.js';
27→import { sendNotification } from '../services/notifier.js';
28→import { startPreventSleep, stopPreventSleep } from '../services/preventSleep.js';
29→import { useTerminalNotification } from '../ink/useTerminalNotification.js';
30→import { hasCursorUpViewportYankBug } from '../ink/terminal.js';
31→import { createFileStateCacheWithSizeLimit, mergeFileStateCaches, READ_FILE_STATE_CACHE_SIZE } from '../utils/fileStateCache.js';
32→import { updateLastInteractionTime, getLastInteractionTime, getOriginalCwd, getProjectRoot, getSessionId, switchSession, setCostStateForRestore, getTurnHookDurationMs, getTurnHookCount, resetTurnHookDuration, getTurnToolDurationMs, getTurnToolCount, resetTurnToolDuration, getTurnClassifierDurationMs, getTurnClassifierCount, resetTurnClassifierDuration } from '../bootstrap/state.js';
33→import { asSessionId, asAgentId } from '../types/ids.js';
34→import { logForDebugging } from '../utils/debug.js';
35→import { QueryGuard } from '../utils/QueryGuard.js';
36→import { isEnvTruthy } from '../utils/envUtils.js';
37→import { formatTokens, truncateToWidth } from '../utils/format.js';
38→import { consumeEarlyInput } from '../utils/earlyInput.js';
39→import { setMemberActive } from '../utils/swarm/teamHelpers.js';
40→import { isSwarmWorker, generateSandboxRequestId, sendSandboxPermissionRequestViaMailbox, sendSandboxPermissionResponseViaMailbox } from '../utils/swarm/permissionSync.js';
41→import { registerSandboxPermissionCallback } from '../hooks/useSwarmPermissionPoller.js';
42→import { getTeamName, getAgentName } from '../utils/teammate.js';
43→import { WorkerPendingPermission } from '../components/permissions/WorkerPendingPermission.js';
44→import { injectUserMessageToTeammate, getAllInProcessTeammateTasks } from '../tasks/InProcessTeammateTask/InProcessTeammateTask.js';
45→import { isLocalAgentTask, queuePendingMessage, appendMessageToLocalAgent, type LocalAgentTaskState } from '../tasks/LocalAgentTask/LocalAgentTask.js';
46→import { registerLeaderToolUseConfirmQueue, unregisterLeaderToolUseConfirmQueue, registerLeaderSetToolPermissionContext, unregisterLeaderSetToolPermissionContext } from '../utils/swarm/leaderPermissionBridge.js';
47→import { endInteractionSpan } from '../utils/telemetry/sessionTracing.js';
48→import { useLogMessages } from '../hooks/useLogMessages.js';
49→import { useReplBridge } from '../hooks/useReplBridge.js';
50→import { type Command, type CommandResultDisplay, type ResumeEntrypoint, getCommandName, isCommandEnabled } from '../commands.js';
51→import type { PromptInputMode, QueuedCommand, VimMode } from '../types/textInputTypes.js';
52→import { MessageSelector, selectableUserMessagesFilter, messagesAfterAreOnlySynthetic } from '../components/MessageSelector.js';
53→import { useIdeLogging } from '../hooks/useIdeLogging.js';
54→import { PermissionRequest, type ToolUseConfirm } from '../components/permissions/PermissionRequest.js';
55→import { ElicitationDialog } from '../components/mcp/ElicitationDialog.js';
56→import { PromptDialog } from '../components/hooks/PromptDialog.js';
57→import type { PromptRequest, PromptResponse } from '../types/hooks.js';
58→import PromptInput from '../components/PromptInput/PromptInput.js';
59→import { PromptInputQueuedCommands } from '../components/PromptInput/PromptInputQueuedCommands.js';
60→import { useRemoteSession } from '../hooks/useRemoteSession.js';Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/context* Status: Completed
src\context.ts
Tool Call: Read src\entrypoints\cli.tsx (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle';
2→
3→// Bugfix for corepack auto-pinning, which adds yarnpkg to peoples' package.jsons
4→// eslint-disable-next-line custom-rules/no-top-level-side-effects
5→process.env.COREPACK_ENABLE_AUTO_PIN = '0';
6→
7→// Set max heap size for child processes in CCR environments (containers have 16GB)
8→// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level, custom-rules/safe-env-boolean-check
9→if (process.env.CLAUDE_CODE_REMOTE === 'true') {
10→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
11→ const existing = process.env.NODE_OPTIONS || '';
12→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
13→ process.env.NODE_OPTIONS = existing ? `${existing} --max-old-space-size=8192` : '--max-old-space-size=8192';
14→}
15→
16→// Harness-science L0 ablation baseline. Inlined here (not init.ts) because
17→// BashTool/AgentTool/PowerShellTool capture DISABLE_BACKGROUND_TASKS into
18→// module-level consts at import time — init() runs too late. feature() gate
19→// DCEs this entire block from external builds.
20→// eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
21→if (feature('ABLATION_BASELINE') && process.env.CLAUDE_CODE_ABLATION_BASELINE) {
22→ for (const k of ['CLAUDE_CODE_SIMPLE', 'CLAUDE_CODE_DISABLE_THINKING', 'DISABLE_INTERLEAVED_THINKING', 'DISABLE_COMPACT', 'DISABLE_AUTO_COMPACT', 'CLAUDE_CODE_DISABLE_AUTO_MEMORY', 'CLAUDE_CODE_DISABLE_BACKGROUND_TASKS']) {
23→ // eslint-disable-next-line custom-rules/no-top-level-side-effects, custom-rules/no-process-env-top-level
24→ process.env[k] ??= '1';
25→ }
26→}
27→
28→/**
29→ * Bootstrap entrypoint - checks for special flags before loading the full CLI.
30→ * All imports are dynamic to minimize module evaluation for fast paths.
31→ * Fast-path for --version has zero imports beyond this file.
32→ */
33→async function main(): Promise<void> {
34→ const args = process.argv.slice(2);
35→
36→ // Fast-path for --version/-v: zero module loading needed
37→ if (args.length === 1 && (args[0] === '--version' || args[0] === '-v' || args[0] === '-V')) {
38→ // MACRO.VERSION is inlined at build time
39→ // biome-ignore lint/suspicious/noConsole:: intentional console output
40→ console.log(`${MACRO.VERSION} (Claude Code)`);
41→ return;
42→ }
43→
44→ // For all other paths, load the startup profiler
45→ const {
46→ profileCheckpoint
47→ } = await import('../utils/startupProfiler.js');
48→ profileCheckpoint('cli_entry');
49→
50→ // Fast-path for --dump-system-prompt: output the rendered system prompt and exit.
51→ // Used by prompt sensitivity evals to extract the system prompt at a specific commit.
52→ // Ant-only: eliminated from external builds via feature flag.
53→ if (feature('DUMP_SYSTEM_PROMPT') && args[0] === '--dump-system-prompt') {
54→ profileCheckpoint('cli_dump_system_prompt_path');
55→ const {
56→ enableConfigs
57→ } = await import('../utils/config.js');
58→ enableConfigs();
59→ const {
60→ getMainLoopModel
61→ } = await import('../utils/model/model.js');
62→ const modelIdx = args.indexOf('--model');
63→ const model = modelIdx !== -1 && args[modelIdx + 1] || getMainLoopModel();
64→ const {
65→ getSystemPrompt
66→ } = await import('../constants/prompts.js');
67→ const prompt = await getSystemPrompt([], model);
68→ // biome-ignore lint/suspicious/noConsole:: intentional console output
69→ console.log(prompt.join('\n'));
70→ return;
71→ }
72→ if (process.argv[2] === '--claude-in-chrome-mcp') {
73→ profileCheckpoint('cli_claude_in_chrome_mcp_path');
74→ const {
75→ runClaudeInChromeMcpServer
76→ } = await import('../utils/claudeInChrome/mcpServer.js');
77→ await runClaudeInChromeMcpServer();
78→ return;
79→ } else if (process.argv[2] === '--chrome-native-host') {
80→ profileCheckpoint('cli_chrome_native_host_path');Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/*.ts Status: Completed
src\types\command.ts src\types\hooks.ts src\types\ids.ts src\types\logs.ts src\types\permissions.ts src\types\plugin.ts src\types\textInputTypes.ts
Tool Call: Read src\query.ts (1 - 80) Status: Completed
1→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
2→import type {
3→ ToolResultBlockParam,
4→ ToolUseBlock,
5→} from '@anthropic-ai/sdk/resources/index.mjs'
6→import type { CanUseToolFn } from './hooks/useCanUseTool.js'
7→import { FallbackTriggeredError } from './services/api/withRetry.js'
8→import {
9→ calculateTokenWarningState,
10→ isAutoCompactEnabled,
11→ type AutoCompactTrackingState,
12→} from './services/compact/autoCompact.js'
13→import { buildPostCompactMessages } from './services/compact/compact.js'
14→/* eslint-disable @typescript-eslint/no-require-imports */
15→const reactiveCompact = feature('REACTIVE_COMPACT')
16→ ? (require('./services/compact/reactiveCompact.js') as typeof import('./services/compact/reactiveCompact.js'))
17→ : null
18→const contextCollapse = feature('CONTEXT_COLLAPSE')
19→ ? (require('./services/contextCollapse/index.js') as typeof import('./services/contextCollapse/index.js'))
20→ : null
21→/* eslint-enable @typescript-eslint/no-require-imports */
22→import {
23→ logEvent,
24→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
25→} from 'src/services/analytics/index.js'
26→import { ImageSizeError } from './utils/imageValidation.js'
27→import { ImageResizeError } from './utils/imageResizer.js'
28→import { findToolByName, type ToolUseContext } from './Tool.js'
29→import { asSystemPrompt, type SystemPrompt } from './utils/systemPromptType.js'
30→import type {
31→ AssistantMessage,
32→ AttachmentMessage,
33→ Message,
34→ RequestStartEvent,
35→ StreamEvent,
36→ ToolUseSummaryMessage,
37→ UserMessage,
38→ TombstoneMessage,
39→} from './types/message.js'
40→import { logError } from './utils/log.js'
41→import {
42→ PROMPT_TOO_LONG_ERROR_MESSAGE,
43→ isPromptTooLongMessage,
44→} from './services/api/errors.js'
45→import { logAntError, logForDebugging } from './utils/debug.js'
46→import {
47→ createUserMessage,
48→ createUserInterruptionMessage,
49→ normalizeMessagesForAPI,
50→ createSystemMessage,
51→ createAssistantAPIErrorMessage,
52→ getMessagesAfterCompactBoundary,
53→ createToolUseSummaryMessage,
54→ createMicrocompactBoundaryMessage,
55→ stripSignatureBlocks,
56→} from './utils/messages.js'
57→import { generateToolUseSummary } from './services/toolUseSummary/toolUseSummaryGenerator.js'
58→import { prependUserContext, appendSystemContext } from './utils/api.js'
59→import {
60→ createAttachmentMessage,
61→ filterDuplicateMemoryAttachments,
62→ getAttachmentMessages,
63→ startRelevantMemoryPrefetch,
64→} from './utils/attachments.js'
65→/* eslint-disable @typescript-eslint/no-require-imports */
66→const skillPrefetch = feature('EXPERIMENTAL_SKILL_SEARCH')
67→ ? (require('./services/skillSearch/prefetch.js') as typeof import('./services/skillSearch/prefetch.js'))
68→ : null
69→const jobClassifier = feature('TEMPLATES')
70→ ? (require('./jobs/classifier.js') as typeof import('./jobs/classifier.js'))
71→ : null
72→/* eslint-enable @typescript-eslint/no-require-imports */
73→import {
74→ remove as removeFromQueue,
75→ getCommandsByMaxPriority,
76→ isSlashCommand,
77→} from './utils/messageQueueManager.js'
78→import { notifyCommandLifecycle } from './utils/commandLifecycle.js'
79→import { headlessProfilerCheckpoint } from './utils/headlessProfiler.js'
80→import {Tool Call: Read src\context.ts (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle'
2→import memoize from 'lodash-es/memoize.js'
3→import {
4→ getAdditionalDirectoriesForClaudeMd,
5→ setCachedClaudeMdContent,
6→} from './bootstrap/state.js'
7→import { getLocalISODate } from './constants/common.js'
8→import {
9→ filterInjectedMemoryFiles,
10→ getClaudeMds,
11→ getMemoryFiles,
12→} from './utils/claudemd.js'
13→import { logForDiagnosticsNoPII } from './utils/diagLogs.js'
14→import { isBareMode, isEnvTruthy } from './utils/envUtils.js'
15→import { execFileNoThrow } from './utils/execFileNoThrow.js'
16→import { getBranch, getDefaultBranch, getIsGit, gitExe } from './utils/git.js'
17→import { shouldIncludeGitInstructions } from './utils/gitSettings.js'
18→import { logError } from './utils/log.js'
19→
20→const MAX_STATUS_CHARS = 2000
21→
22→// System prompt injection for cache breaking (ant-only, ephemeral debugging state)
23→let systemPromptInjection: string | null = null
24→
25→export function getSystemPromptInjection(): string | null {
26→ return systemPromptInjection
27→}
28→
29→export function setSystemPromptInjection(value: string | null): void {
30→ systemPromptInjection = value
31→ // Clear context caches immediately when injection changes
32→ getUserContext.cache.clear?.()
33→ getSystemContext.cache.clear?.()
34→}
35→
36→export const getGitStatus = memoize(async (): Promise<string | null> => {
37→ if (process.env.NODE_ENV === 'test') {
38→ // Avoid cycles in tests
39→ return null
40→ }
41→
42→ const startTime = Date.now()
43→ logForDiagnosticsNoPII('info', 'git_status_started')
44→
45→ const isGitStart = Date.now()
46→ const isGit = await getIsGit()
47→ logForDiagnosticsNoPII('info', 'git_is_git_check_completed', {
48→ duration_ms: Date.now() - isGitStart,
49→ is_git: isGit,
50→ })
51→
52→ if (!isGit) {
53→ logForDiagnosticsNoPII('info', 'git_status_skipped_not_git', {
54→ duration_ms: Date.now() - startTime,
55→ })
56→ return null
57→ }
58→
59→ try {
60→ const gitCmdsStart = Date.now()
61→ const [branch, mainBranch, status, log, userName] = await Promise.all([
62→ getBranch(),
63→ getDefaultBranch(),
64→ execFileNoThrow(gitExe(), ['--no-optional-locks', 'status', '--short'], {
65→ preserveOutputOnError: false,
66→ }).then(({ stdout }) => stdout.trim()),
67→ execFileNoThrow(
68→ gitExe(),
69→ ['--no-optional-locks', 'log', '--oneline', '-n', '5'],
70→ {
71→ preserveOutputOnError: false,
72→ },
73→ ).then(({ stdout }) => stdout.trim()),
74→ execFileNoThrow(gitExe(), ['config', 'user.name'], {
75→ preserveOutputOnError: false,
76→ }).then(({ stdout }) => stdout.trim()),
77→ ])
78→
79→ logForDiagnosticsNoPII('info', 'git_commands_completed', {
80→ duration_ms: Date.now() - gitCmdsStart,Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/coordinator/**/*.{ts,tsx} Status: Completed
src\coordinator\coordinatorMode.ts
Tool Call: Read src\ink.ts (1 - 80) Status: Completed
1→import { createElement, type ReactNode } from 'react'
2→import { ThemeProvider } from './components/design-system/ThemeProvider.js'
3→import inkRender, {
4→ type Instance,
5→ createRoot as inkCreateRoot,
6→ type RenderOptions,
7→ type Root,
8→} from './ink/root.js'
9→
10→export type { RenderOptions, Instance, Root }
11→
12→// Wrap all CC render calls with ThemeProvider so ThemedBox/ThemedText work
13→// without every call site having to mount it. Ink itself is theme-agnostic.
14→function withTheme(node: ReactNode): ReactNode {
15→ return createElement(ThemeProvider, null, node)
16→}
17→
18→export async function render(
19→ node: ReactNode,
20→ options?: NodeJS.WriteStream | RenderOptions,
21→): Promise<Instance> {
22→ return inkRender(withTheme(node), options)
23→}
24→
25→export async function createRoot(options?: RenderOptions): Promise<Root> {
26→ const root = await inkCreateRoot(options)
27→ return {
28→ ...root,
29→ render: node => root.render(withTheme(node)),
30→ }
31→}
32→
33→export { color } from './components/design-system/color.js'
34→export type { Props as BoxProps } from './components/design-system/ThemedBox.js'
35→export { default as Box } from './components/design-system/ThemedBox.js'
36→export type { Props as TextProps } from './components/design-system/ThemedText.js'
37→export { default as Text } from './components/design-system/ThemedText.js'
38→export {
39→ ThemeProvider,
40→ usePreviewTheme,
41→ useTheme,
42→ useThemeSetting,
43→} from './components/design-system/ThemeProvider.js'
44→export { Ansi } from './ink/Ansi.js'
45→export type { Props as AppProps } from './ink/components/AppContext.js'
46→export type { Props as BaseBoxProps } from './ink/components/Box.js'
47→export { default as BaseBox } from './ink/components/Box.js'
48→export type {
49→ ButtonState,
50→ Props as ButtonProps,
51→} from './ink/components/Button.js'
52→export { default as Button } from './ink/components/Button.js'
53→export type { Props as LinkProps } from './ink/components/Link.js'
54→export { default as Link } from './ink/components/Link.js'
55→export type { Props as NewlineProps } from './ink/components/Newline.js'
56→export { default as Newline } from './ink/components/Newline.js'
57→export { NoSelect } from './ink/components/NoSelect.js'
58→export { RawAnsi } from './ink/components/RawAnsi.js'
59→export { default as Spacer } from './ink/components/Spacer.js'
60→export type { Props as StdinProps } from './ink/components/StdinContext.js'
61→export type { Props as BaseTextProps } from './ink/components/Text.js'
62→export { default as BaseText } from './ink/components/Text.js'
63→export type { DOMElement } from './ink/dom.js'
64→export { ClickEvent } from './ink/events/click-event.js'
65→export { EventEmitter } from './ink/events/emitter.js'
66→export { Event } from './ink/events/event.js'
67→export type { Key } from './ink/events/input-event.js'
68→export { InputEvent } from './ink/events/input-event.js'
69→export type { TerminalFocusEventType } from './ink/events/terminal-focus-event.js'
70→export { TerminalFocusEvent } from './ink/events/terminal-focus-event.js'
71→export { FocusManager } from './ink/focus.js'
72→export type { FlickerReason } from './ink/frame.js'
73→export { useAnimationFrame } from './ink/hooks/use-animation-frame.js'
74→export { default as useApp } from './ink/hooks/use-app.js'
75→export { default as useInput } from './ink/hooks/use-input.js'
76→export { useAnimationTimer, useInterval } from './ink/hooks/use-interval.js'
77→export { useSelection } from './ink/hooks/use-selection.js'
78→export { default as useStdin } from './ink/hooks/use-stdin.js'
79→export { useTabStatus } from './ink/hooks/use-tab-status.js'
80→export { useTerminalFocus } from './ink/hooks/use-terminal-focus.js'Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tasks/**/*.{ts,tsx} Status: Completed
src\tasks\DreamTask\DreamTask.ts src\tasks\InProcessTeammateTask\InProcessTeammateTask.tsx src\tasks\InProcessTeammateTask\types.ts src\tasks\LocalAgentTask\LocalAgentTask.tsx src\tasks\LocalMainSessionTask.ts src\tasks\LocalShellTask\LocalShellTask.tsx src\tasks\LocalShellTask\guards.ts src\tasks\LocalShellTask\killShellTasks.ts src\tasks\pillLabel.ts src\tasks\RemoteAgentTask\RemoteAgentTask.tsx src\tasks\stopTask.ts src\tasks\types.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/skills/**/*.{ts,tsx} Status: Completed
src\skills\bundled\batch.ts src\skills\bundled\claudeApi.ts src\skills\bundled\claudeApiContent.ts src\skills\bundled\claudeInChrome.ts src\skills\bundled\debug.ts src\skills\bundled\index.ts src\skills\bundled\keybindings.ts src\skills\bundled\loop.ts src\skills\bundled\loremIpsum.ts src\skills\bundled\remember.ts src\skills\bundled\scheduleRemoteAgents.ts src\skills\bundled\simplify.ts src\skills\bundled\skillify.ts src\skills\bundled\stuck.ts src\skills\bundled\updateConfig.ts src\skills\bundled\verify.ts src\skills\bundled\verifyContent.ts src\skills\bundledSkills.ts src\skills\loadSkillsDir.ts src\skills\mcpSkillBuilders.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/context/**/* Status: Completed
src\context\fpsMetrics.tsx src\context\mailbox.tsx src\context\QueuedMessageContext.tsx src\context\modalContext.tsx src\context\notifications.tsx src\context\overlayContext.tsx src\context\promptOverlayContext.tsx src\context\stats.tsx src\context\voice.tsx
Tool Call: Read src\types\ids.ts Status: Completed
1→/**
2→ * Branded types for session and agent IDs.
3→ * These prevent accidentally mixing up session IDs and agent IDs at compile time.
4→ */
5→
6→/**
7→ * A session ID uniquely identifies a Claude Code session.
8→ * Returned by getSessionId().
9→ */
10→export type SessionId = string & { readonly __brand: 'SessionId' }
11→
12→/**
13→ * An agent ID uniquely identifies a subagent within a session.
14→ * Returned by createAgentId().
15→ * When present, indicates the context is a subagent (not the main session).
16→ */
17→export type AgentId = string & { readonly __brand: 'AgentId' }
18→
19→/**
20→ * Cast a raw string to SessionId.
21→ * Use sparingly - prefer getSessionId() when possible.
22→ */
23→export function asSessionId(id: string): SessionId {
24→ return id as SessionId
25→}
26→
27→/**
28→ * Cast a raw string to AgentId.
29→ * Use sparingly - prefer createAgentId() when possible.
30→ */
31→export function asAgentId(id: string): AgentId {
32→ return id as AgentId
33→}
34→
35→const AGENT_ID_PATTERN = /^a(?:.+-)?[0-9a-f]{16}$/
36→
37→/**
38→ * Validate and brand a string as AgentId.
39→ * Matches the format produced by createAgentId(): `a` + optional `<label>-` + 16 hex chars.
40→ * Returns null if the string doesn't match (e.g. teammate names, team-addressing).
41→ */
42→export function toAgentId(s: string): AgentId | null {
43→ return AGENT_ID_PATTERN.test(s) ? (s as AgentId) : null
44→}
45→Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/screens/**/*.tsx Status: Completed
src\screens\Doctor.tsx src\screens\REPL.tsx src\screens\ResumeConversation.tsx
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/plugins/**/*.{ts,tsx} Status: Completed
src\plugins\builtinPlugins.ts src\plugins\bundled\index.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/ink/**/*.ts Status: Completed
src\ink\bidi.ts src\ink\clearTerminal.ts src\ink\colorize.ts src\ink\components\AppContext.ts src\ink\components\CursorDeclarationContext.ts src\ink\components\StdinContext.ts src\ink\constants.ts src\ink\dom.ts src\ink\events\click-event.ts src\ink\events\dispatcher.ts src\ink\events\emitter.ts src\ink\events\event-handlers.ts src\ink\events\event.ts src\ink\events\focus-event.ts src\ink\events\input-event.ts src\ink\events\keyboard-event.ts src\ink\events\terminal-event.ts src\ink\events\terminal-focus-event.ts src\ink\focus.ts src\ink\frame.ts src\ink\get-max-width.ts src\ink\hit-test.ts src\ink\hooks\use-animation-frame.ts src\ink\hooks\use-app.ts src\ink\hooks\use-declared-cursor.ts src\ink\hooks\use-input.ts src\ink\hooks\use-interval.ts src\ink\hooks\use-search-highlight.ts src\ink\hooks\use-selection.ts src\ink\hooks\use-stdin.ts src\ink\hooks\use-tab-status.ts src\ink\hooks\use-terminal-focus.ts src\ink\hooks\use-terminal-title.ts src\ink\hooks\use-terminal-viewport.ts src\ink\instances.ts src\ink\layout\engine.ts src\ink\layout\geometry.ts src\ink\layout\node.ts src\ink\layout\yoga.ts src\ink\line-width-cache.ts src\ink\log-update.ts src\ink\measure-element.ts src\ink\measure-text.ts src\ink\node-cache.ts src\ink\optimizer.ts src\ink\output.ts src\ink\parse-keypress.ts src\ink\reconciler.ts src\ink\render-border.ts src\ink\render-node-to-output.ts src\ink\render-to-screen.ts src\ink\renderer.ts src\ink\root.ts src\ink\screen.ts src\ink\searchHighlight.ts src\ink\selection.ts src\ink\squash-text-nodes.ts src\ink\stringWidth.ts src\ink\styles.ts src\ink\supports-hyperlinks.ts src\ink\tabstops.ts src\ink\terminal-focus-state.ts src\ink\terminal-querier.ts src\ink\terminal.ts src\ink\termio\ansi.ts src\ink\termio\csi.ts src\ink\termio\dec.ts src\ink\termio.ts src\ink\termio\esc.ts src\ink\termio\osc.ts src\ink\termio\parser.ts src\ink\termio\sgr.ts src\ink\termio\tokenize.ts src\ink\termio\types.ts src\ink\useTerminalNotification.ts src\ink\warn.ts src\ink\widest-line.ts src\ink\wrap-text.ts src\ink\wrapAnsi.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/remote/**/*.{ts,tsx} Status: Completed
src\remote\RemoteSessionManager.ts src\remote\remotePermissionBridge.ts src\remote\sdkMessageAdapter.ts src\remote\SessionsWebSocket.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/ink/**/*.{ts,tsx} Status: Completed
src\ink\Ansi.tsx src\ink\bidi.ts src\ink\clearTerminal.ts src\ink\colorize.ts src\ink\components\AlternateScreen.tsx src\ink\components\App.tsx src\ink\components\AppContext.ts src\ink\components\Box.tsx src\ink\components\Button.tsx src\ink\components\ClockContext.tsx src\ink\components\CursorDeclarationContext.ts src\ink\components\ErrorOverview.tsx src\ink\components\Link.tsx src\ink\components\Newline.tsx src\ink\components\NoSelect.tsx src\ink\components\RawAnsi.tsx src\ink\components\ScrollBox.tsx src\ink\components\Spacer.tsx src\ink\components\StdinContext.ts src\ink\components\TerminalFocusContext.tsx src\ink\components\TerminalSizeContext.tsx src\ink\components\Text.tsx src\ink\constants.ts src\ink\dom.ts src\ink\events\click-event.ts src\ink\events\dispatcher.ts src\ink\events\emitter.ts src\ink\events\event-handlers.ts src\ink\events\event.ts src\ink\events\focus-event.ts src\ink\events\input-event.ts src\ink\events\keyboard-event.ts src\ink\events\terminal-event.ts src\ink\events\terminal-focus-event.ts src\ink\focus.ts src\ink\frame.ts src\ink\get-max-width.ts src\ink\hit-test.ts src\ink\hooks\use-animation-frame.ts src\ink\hooks\use-app.ts src\ink\hooks\use-declared-cursor.ts src\ink\hooks\use-input.ts src\ink\hooks\use-interval.ts src\ink\hooks\use-search-highlight.ts src\ink\hooks\use-selection.ts src\ink\hooks\use-stdin.ts src\ink\hooks\use-tab-status.ts src\ink\hooks\use-terminal-focus.ts src\ink\hooks\use-terminal-title.ts src\ink\hooks\use-terminal-viewport.ts src\ink\ink.tsx src\ink\instances.ts src\ink\layout\engine.ts src\ink\layout\geometry.ts src\ink\layout\node.ts src\ink\layout\yoga.ts src\ink\line-width-cache.ts src\ink\log-update.ts src\ink\measure-element.ts src\ink\measure-text.ts src\ink\node-cache.ts src\ink\optimizer.ts src\ink\output.ts src\ink\parse-keypress.ts src\ink\reconciler.ts src\ink\render-border.ts src\ink\render-node-to-output.ts src\ink\render-to-screen.ts src\ink\renderer.ts src\ink\root.ts src\ink\screen.ts src\ink\searchHighlight.ts src\ink\selection.ts src\ink\squash-text-nodes.ts src\ink\stringWidth.ts src\ink\styles.ts src\ink\supports-hyperlinks.ts src\ink\tabstops.ts src\ink\terminal-focus-state.ts src\ink\terminal-querier.ts src\ink\terminal.ts src\ink\termio\ansi.ts src\ink\termio\csi.ts src\ink\termio\dec.ts src\ink\termio.ts src\ink\termio\esc.ts src\ink\termio\osc.ts src\ink\termio\parser.ts src\ink\termio\sgr.ts src\ink\termio\tokenize.ts src\ink\termio\types.ts src\ink\useTerminalNotification.ts src\ink\warn.ts src\ink\widest-line.ts src\ink\wrap-text.ts src\ink\wrapAnsi.ts
Tool Call: Read src\types\utils.ts Status: Failed
File does not exist. Note: your current working directory is D:\code\play\stock_ai_rust\claude-code.Tool Call: Read src\ink\root.ts (1 - 80) Status: Completed
1→import type { ReactNode } from 'react'
2→import { logForDebugging } from 'src/utils/debug.js'
3→import { Stream } from 'stream'
4→import type { FrameEvent } from './frame.js'
5→import Ink, { type Options as InkOptions } from './ink.js'
6→import instances from './instances.js'
7→
8→export type RenderOptions = {
9→ /**
10→ * Output stream where app will be rendered.
11→ *
12→ * @default process.stdout
13→ */
14→ stdout?: NodeJS.WriteStream
15→ /**
16→ * Input stream where app will listen for input.
17→ *
18→ * @default process.stdin
19→ */
20→ stdin?: NodeJS.ReadStream
21→ /**
22→ * Error stream.
23→ * @default process.stderr
24→ */
25→ stderr?: NodeJS.WriteStream
26→ /**
27→ * Configure whether Ink should listen to Ctrl+C keyboard input and exit the app. This is needed in case `process.stdin` is in raw mode, because then Ctrl+C is ignored by default and process is expected to handle it manually.
28→ *
29→ * @default true
30→ */
31→ exitOnCtrlC?: boolean
32→
33→ /**
34→ * Patch console methods to ensure console output doesn't mix with Ink output.
35→ *
36→ * @default true
37→ */
38→ patchConsole?: boolean
39→
40→ /**
41→ * Called after each frame render with timing and flicker information.
42→ */
43→ onFrame?: (event: FrameEvent) => void
44→}
45→
46→export type Instance = {
47→ /**
48→ * Replace previous root node with a new one or update props of the current root node.
49→ */
50→ rerender: Ink['render']
51→ /**
52→ * Manually unmount the whole Ink app.
53→ */
54→ unmount: Ink['unmount']
55→ /**
56→ * Returns a promise, which resolves when app is unmounted.
57→ */
58→ waitUntilExit: Ink['waitUntilExit']
59→ cleanup: () => void
60→}
61→
62→/**
63→ * A managed Ink root, similar to react-dom's createRoot API.
64→ * Separates instance creation from rendering so the same root
65→ * can be reused for multiple sequential screens.
66→ */
67→export type Root = {
68→ render: (node: ReactNode) => void
69→ unmount: () => void
70→ waitUntilExit: () => Promise<void>
71→}
72→
73→/**
74→ * Mount a component and render the output.
75→ */
76→export const renderSync = (
77→ node: ReactNode,
78→ options?: NodeJS.WriteStream | RenderOptions,
79→): Instance => {
80→ const opts = getOptions(options)Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/utils* Status: Completed
No files found
Tool Call: Read src\screens\REPL.tsx (1 - 80) Status: Completed
1→import { c as _c } from "react/compiler-runtime";
2→// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
3→import { feature } from 'bun:bundle';
4→import { spawnSync } from 'child_process';
5→import { snapshotOutputTokensForTurn, getCurrentTurnTokenBudget, getTurnOutputTokens, getBudgetContinuationCount, getTotalInputTokens } from '../bootstrap/state.js';
6→import { parseTokenBudget } from '../utils/tokenBudget.js';
7→import { count } from '../utils/array.js';
8→import { dirname, join } from 'path';
9→import { tmpdir } from 'os';
10→import figures from 'figures';
11→// eslint-disable-next-line custom-rules/prefer-use-keybindings -- / n N Esc [ v are bare letters in transcript modal context, same class as g/G/j/k in ScrollKeybindingHandler
12→import { useInput } from '../ink.js';
13→import { useSearchInput } from '../hooks/useSearchInput.js';
14→import { useTerminalSize } from '../hooks/useTerminalSize.js';
15→import { useSearchHighlight } from '../ink/hooks/use-search-highlight.js';
16→import type { JumpHandle } from '../components/VirtualMessageList.js';
17→import { renderMessagesToPlainText } from '../utils/exportRenderer.js';
18→import { openFileInExternalEditor } from '../utils/editor.js';
19→import { writeFile } from 'fs/promises';
20→import { Box, Text, useStdin, useTheme, useTerminalFocus, useTerminalTitle, useTabStatus } from '../ink.js';
21→import type { TabStatusKind } from '../ink/hooks/use-tab-status.js';
22→import { CostThresholdDialog } from '../components/CostThresholdDialog.js';
23→import { IdleReturnDialog } from '../components/IdleReturnDialog.js';
24→import * as React from 'react';
25→import { useEffect, useMemo, useRef, useState, useCallback, useDeferredValue, useLayoutEffect, type RefObject } from 'react';
26→import { useNotifications } from '../context/notifications.js';
27→import { sendNotification } from '../services/notifier.js';
28→import { startPreventSleep, stopPreventSleep } from '../services/preventSleep.js';
29→import { useTerminalNotification } from '../ink/useTerminalNotification.js';
30→import { hasCursorUpViewportYankBug } from '../ink/terminal.js';
31→import { createFileStateCacheWithSizeLimit, mergeFileStateCaches, READ_FILE_STATE_CACHE_SIZE } from '../utils/fileStateCache.js';
32→import { updateLastInteractionTime, getLastInteractionTime, getOriginalCwd, getProjectRoot, getSessionId, switchSession, setCostStateForRestore, getTurnHookDurationMs, getTurnHookCount, resetTurnHookDuration, getTurnToolDurationMs, getTurnToolCount, resetTurnToolDuration, getTurnClassifierDurationMs, getTurnClassifierCount, resetTurnClassifierDuration } from '../bootstrap/state.js';
33→import { asSessionId, asAgentId } from '../types/ids.js';
34→import { logForDebugging } from '../utils/debug.js';
35→import { QueryGuard } from '../utils/QueryGuard.js';
36→import { isEnvTruthy } from '../utils/envUtils.js';
37→import { formatTokens, truncateToWidth } from '../utils/format.js';
38→import { consumeEarlyInput } from '../utils/earlyInput.js';
39→import { setMemberActive } from '../utils/swarm/teamHelpers.js';
40→import { isSwarmWorker, generateSandboxRequestId, sendSandboxPermissionRequestViaMailbox, sendSandboxPermissionResponseViaMailbox } from '../utils/swarm/permissionSync.js';
41→import { registerSandboxPermissionCallback } from '../hooks/useSwarmPermissionPoller.js';
42→import { getTeamName, getAgentName } from '../utils/teammate.js';
43→import { WorkerPendingPermission } from '../components/permissions/WorkerPendingPermission.js';
44→import { injectUserMessageToTeammate, getAllInProcessTeammateTasks } from '../tasks/InProcessTeammateTask/InProcessTeammateTask.js';
45→import { isLocalAgentTask, queuePendingMessage, appendMessageToLocalAgent, type LocalAgentTaskState } from '../tasks/LocalAgentTask/LocalAgentTask.js';
46→import { registerLeaderToolUseConfirmQueue, unregisterLeaderToolUseConfirmQueue, registerLeaderSetToolPermissionContext, unregisterLeaderSetToolPermissionContext } from '../utils/swarm/leaderPermissionBridge.js';
47→import { endInteractionSpan } from '../utils/telemetry/sessionTracing.js';
48→import { useLogMessages } from '../hooks/useLogMessages.js';
49→import { useReplBridge } from '../hooks/useReplBridge.js';
50→import { type Command, type CommandResultDisplay, type ResumeEntrypoint, getCommandName, isCommandEnabled } from '../commands.js';
51→import type { PromptInputMode, QueuedCommand, VimMode } from '../types/textInputTypes.js';
52→import { MessageSelector, selectableUserMessagesFilter, messagesAfterAreOnlySynthetic } from '../components/MessageSelector.js';
53→import { useIdeLogging } from '../hooks/useIdeLogging.js';
54→import { PermissionRequest, type ToolUseConfirm } from '../components/permissions/PermissionRequest.js';
55→import { ElicitationDialog } from '../components/mcp/ElicitationDialog.js';
56→import { PromptDialog } from '../components/hooks/PromptDialog.js';
57→import type { PromptRequest, PromptResponse } from '../types/hooks.js';
58→import PromptInput from '../components/PromptInput/PromptInput.js';
59→import { PromptInputQueuedCommands } from '../components/PromptInput/PromptInputQueuedCommands.js';
60→import { useRemoteSession } from '../hooks/useRemoteSession.js';
61→import { useDirectConnect } from '../hooks/useDirectConnect.js';
62→import type { DirectConnectConfig } from '../server/directConnectManager.js';
63→import { useSSHSession } from '../hooks/useSSHSession.js';
64→import { useAssistantHistory } from '../hooks/useAssistantHistory.js';
65→import type { SSHSession } from '../ssh/createSSHSession.js';
66→import { SkillImprovementSurvey } from '../components/SkillImprovementSurvey.js';
67→import { useSkillImprovementSurvey } from '../hooks/useSkillImprovementSurvey.js';
68→import { useMoreRight } from '../moreright/useMoreRight.js';
69→import { SpinnerWithVerb, BriefIdleStatus, type SpinnerMode } from '../components/Spinner.js';
70→import { getSystemPrompt } from '../constants/prompts.js';
71→import { buildEffectiveSystemPrompt } from '../utils/systemPrompt.js';
72→import { getSystemContext, getUserContext } from '../context.js';
73→import { getMemoryFiles } from '../utils/claudemd.js';
74→import { startBackgroundHousekeeping } from '../utils/backgroundHousekeeping.js';
75→import { getTotalCost, saveCurrentSessionCosts, resetCostState, getStoredSessionCosts } from '../cost-tracker.js';
76→import { useCostSummary } from '../costHook.js';
77→import { useFpsMetrics } from '../context/fpsMetrics.js';
78→import { useAfterFirstRender } from '../hooks/useAfterFirstRender.js';
79→import { useDeferredHookMessages } from '../hooks/useDeferredHookMessages.js';
80→import { addToHistory, removeLastFromHistory, expandPastedTextRefs, parseReferences } from '../history.js';Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/memdir/**/*.{ts,tsx} Status: Completed
src\memdir\findRelevantMemories.ts src\memdir\memdir.ts src\memdir\memoryAge.ts src\memdir\memoryScan.ts src\memdir\memoryTypes.ts src\memdir\paths.ts src\memdir\teamMemPaths.ts src\memdir\teamMemPrompts.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/utils/processUserInput/**/* Status: Completed
src\utils\processUserInput\processBashCommand.tsx src\utils\processUserInput\processSlashCommand.tsx src\utils\processUserInput\processTextPrompt.ts src\utils\processUserInput\processUserInput.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/schemas/**/*.{ts,tsx} Status: Completed
src\schemas\hooks.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/migrations/**/*.{ts,tsx} Status: Completed
src\migrations\migrateAutoUpdatesToSettings.ts src\migrations\migrateBypassPermissionsAcceptedToSettings.ts src\migrations\migrateEnableAllProjectMcpServersToSettings.ts src\migrations\migrateFennecToOpus.ts src\migrations\migrateLegacyOpusToCurrent.ts src\migrations\migrateOpusToOpus1m.ts src\migrations\migrateReplBridgeEnabledToRemoteControlAtStartup.ts src\migrations\migrateSonnet1mToSonnet45.ts src\migrations\migrateSonnet45ToSonnet46.ts src\migrations\resetAutoModeOptInForDefaultOffer.ts src\migrations\resetProToOpusDefault.ts
Tool Call: Read src\utils\processUserInput\processUserInput.ts (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle'
2→import type {
3→ Base64ImageSource,
4→ ContentBlockParam,
5→ ImageBlockParam,
6→} from '@anthropic-ai/sdk/resources/messages.mjs'
7→import { randomUUID } from 'crypto'
8→import type { QuerySource } from 'src/constants/querySource.js'
9→import { logEvent } from 'src/services/analytics/index.js'
10→import { getContentText } from 'src/utils/messages.js'
11→import {
12→ findCommand,
13→ getCommandName,
14→ isBridgeSafeCommand,
15→ type LocalJSXCommandContext,
16→} from '../../commands.js'
17→import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
18→import type { IDESelection } from '../../hooks/useIdeSelection.js'
19→import type { SetToolJSXFn, ToolUseContext } from '../../Tool.js'
20→import type {
21→ AssistantMessage,
22→ AttachmentMessage,
23→ Message,
24→ ProgressMessage,
25→ SystemMessage,
26→ UserMessage,
27→} from '../../types/message.js'
28→import type { PermissionMode } from '../../types/permissions.js'
29→import {
30→ isValidImagePaste,
31→ type PromptInputMode,
32→} from '../../types/textInputTypes.js'
33→import {
34→ type AgentMentionAttachment,
35→ createAttachmentMessage,
36→ getAttachmentMessages,
37→} from '../attachments.js'
38→import type { PastedContent } from '../config.js'
39→import type { EffortValue } from '../effort.js'
40→import { toArray } from '../generators.js'
41→import {
42→ executeUserPromptSubmitHooks,
43→ getUserPromptSubmitHookBlockingMessage,
44→} from '../hooks.js'
45→import {
46→ createImageMetadataText,
47→ maybeResizeAndDownsampleImageBlock,
48→} from '../imageResizer.js'
49→import { storeImages } from '../imageStore.js'
50→import {
51→ createCommandInputMessage,
52→ createSystemMessage,
53→ createUserMessage,
54→} from '../messages.js'
55→import { queryCheckpoint } from '../queryProfiler.js'
56→import { parseSlashCommand } from '../slashCommandParsing.js'
57→import {
58→ hasUltraplanKeyword,
59→ replaceUltraplanKeyword,
60→} from '../ultraplan/keyword.js'
61→import { processTextPrompt } from './processTextPrompt.js'
62→export type ProcessUserInputContext = ToolUseContext & LocalJSXCommandContext
63→
64→export type ProcessUserInputBaseResult = {
65→ messages: (
66→ | UserMessage
67→ | AssistantMessage
68→ | AttachmentMessage
69→ | SystemMessage
70→ | ProgressMessage
71→ )[]
72→ shouldQuery: boolean
73→ allowedTools?: string[]
74→ model?: string
75→ effort?: EffortValue
76→ // Output text for non-interactive mode (e.g., forked commands)
77→ // When set, this is used as the result in -p mode instead of empty string
78→ resultText?: string
79→ // When set, prefills or submits the next input after command completes
80→ // Used by /discover to chain into the selected feature's commandTool Call: Find D:\code\play\stock_ai_rust\claude-code src/vim/**/*.{ts,tsx} Status: Completed
src\vim\motions.ts src\vim\operators.ts src\vim\textObjects.ts src\vim\transitions.ts src\vim\types.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/voice/**/*.{ts,tsx} Status: Completed
src\voice\voiceModeEnabled.ts
Tool Call: Read src\QueryEngine.ts (120 - 239) Status: Completed
120→// Dead code elimination: conditional import for snip compaction
121→/* eslint-disable @typescript-eslint/no-require-imports */
122→const snipModule = feature('HISTORY_SNIP')
123→ ? (require('./services/compact/snipCompact.js') as typeof import('./services/compact/snipCompact.js'))
124→ : null
125→const snipProjection = feature('HISTORY_SNIP')
126→ ? (require('./services/compact/snipProjection.js') as typeof import('./services/compact/snipProjection.js'))
127→ : null
128→/* eslint-enable @typescript-eslint/no-require-imports */
129→
130→export type QueryEngineConfig = {
131→ cwd: string
132→ tools: Tools
133→ commands: Command[]
134→ mcpClients: MCPServerConnection[]
135→ agents: AgentDefinition[]
136→ canUseTool: CanUseToolFn
137→ getAppState: () => AppState
138→ setAppState: (f: (prev: AppState) => AppState) => void
139→ initialMessages?: Message[]
140→ readFileCache: FileStateCache
141→ customSystemPrompt?: string
142→ appendSystemPrompt?: string
143→ userSpecifiedModel?: string
144→ fallbackModel?: string
145→ thinkingConfig?: ThinkingConfig
146→ maxTurns?: number
147→ maxBudgetUsd?: number
148→ taskBudget?: { total: number }
149→ jsonSchema?: Record<string, unknown>
150→ verbose?: boolean
151→ replayUserMessages?: boolean
152→ /** Handler for URL elicitations triggered by MCP tool -32042 errors. */
153→ handleElicitation?: ToolUseContext['handleElicitation']
154→ includePartialMessages?: boolean
155→ setSDKStatus?: (status: SDKStatus) => void
156→ abortController?: AbortController
157→ orphanedPermission?: OrphanedPermission
158→ /**
159→ * Snip-boundary handler: receives each yielded system message plus the
160→ * current mutableMessages store. Returns undefined if the message is not a
161→ * snip boundary; otherwise returns the replayed snip result. Injected by
162→ * ask() when HISTORY_SNIP is enabled so feature-gated strings stay inside
163→ * the gated module (keeps QueryEngine free of excluded strings and testable
164→ * despite feature() returning false under bun test). SDK-only: the REPL
165→ * keeps full history for UI scrollback and projects on demand via
166→ * projectSnippedView; QueryEngine truncates here to bound memory in long
167→ * headless sessions (no UI to preserve).
168→ */
169→ snipReplay?: (
170→ yieldedSystemMsg: Message,
171→ store: Message[],
172→ ) => { messages: Message[]; executed: boolean } | undefined
173→}
174→
175→/**
176→ * QueryEngine owns the query lifecycle and session state for a conversation.
177→ * It extracts the core logic from ask() into a standalone class that can be
178→ * used by both the headless/SDK path and (in a future phase) the REPL.
179→ *
180→ * One QueryEngine per conversation. Each submitMessage() call starts a new
181→ * turn within the same conversation. State (messages, file cache, usage, etc.)
182→ * persists across turns.
183→ */
184→export class QueryEngine {
185→ private config: QueryEngineConfig
186→ private mutableMessages: Message[]
187→ private abortController: AbortController
188→ private permissionDenials: SDKPermissionDenial[]
189→ private totalUsage: NonNullableUsage
190→ private hasHandledOrphanedPermission = false
191→ private readFileState: FileStateCache
192→ // Turn-scoped skill discovery tracking (feeds was_discovered on
193→ // tengu_skill_tool_invocation). Must persist across the two
194→ // processUserInputContext rebuilds inside submitMessage, but is cleared
195→ // at the start of each submitMessage to avoid unbounded growth across
196→ // many turns in SDK mode.
197→ private discoveredSkillNames = new Set<string>()
198→ private loadedNestedMemoryPaths = new Set<string>()
199→
200→ constructor(config: QueryEngineConfig) {
201→ this.config = config
202→ this.mutableMessages = config.initialMessages ?? []
203→ this.abortController = config.abortController ?? createAbortController()
204→ this.permissionDenials = []
205→ this.readFileState = config.readFileCache
206→ this.totalUsage = EMPTY_USAGE
207→ }
208→
209→ async *submitMessage(
210→ prompt: string | ContentBlockParam[],
211→ options?: { uuid?: string; isMeta?: boolean },
212→ ): AsyncGenerator<SDKMessage, void, unknown> {
213→ const {
214→ cwd,
215→ commands,
216→ tools,
217→ mcpClients,
218→ verbose = false,
219→ thinkingConfig,
220→ maxTurns,
221→ maxBudgetUsd,
222→ taskBudget,
223→ canUseTool,
224→ customSystemPrompt,
225→ appendSystemPrompt,
226→ userSpecifiedModel,
227→ fallbackModel,
228→ jsonSchema,
229→ getAppState,
230→ setAppState,
231→ replayUserMessages = false,
232→ includePartialMessages = false,
233→ agents = [],
234→ setSDKStatus,
235→ orphanedPermission,
236→ } = this.config
237→
238→ this.discoveredSkillNames.clear()
239→ setCwd(cwd)Tool Call: grep --type=ts "export type DeepImmutable" D:\code\play\stock_ai_rust\claude-code\src Status: Completed
No files found
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tasks/**/*.ts Status: Completed
src\tasks\DreamTask\DreamTask.ts src\tasks\InProcessTeammateTask\types.ts src\tasks\LocalMainSessionTask.ts src\tasks\LocalShellTask\guards.ts src\tasks\LocalShellTask\killShellTasks.ts src\tasks\pillLabel.ts src\tasks\stopTask.ts src\tasks\types.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/outputStyles/**/*.{ts,tsx} Status: Completed
src\outputStyles\loadOutputStylesDir.ts
Tool Call: Read src\tasks\types.ts (1 - 80) Status: Completed
1→// Union of all concrete task state types
2→// Use this for components that need to work with any task type
3→
4→import type { DreamTaskState } from './DreamTask/DreamTask.js'
5→import type { InProcessTeammateTaskState } from './InProcessTeammateTask/types.js'
6→import type { LocalAgentTaskState } from './LocalAgentTask/LocalAgentTask.js'
7→import type { LocalShellTaskState } from './LocalShellTask/guards.js'
8→import type { LocalWorkflowTaskState } from './LocalWorkflowTask/LocalWorkflowTask.js'
9→import type { MonitorMcpTaskState } from './MonitorMcpTask/MonitorMcpTask.js'
10→import type { RemoteAgentTaskState } from './RemoteAgentTask/RemoteAgentTask.js'
11→
12→export type TaskState =
13→ | LocalShellTaskState
14→ | LocalAgentTaskState
15→ | RemoteAgentTaskState
16→ | InProcessTeammateTaskState
17→ | LocalWorkflowTaskState
18→ | MonitorMcpTaskState
19→ | DreamTaskState
20→
21→// Task types that can appear in the background tasks indicator
22→export type BackgroundTaskState =
23→ | LocalShellTaskState
24→ | LocalAgentTaskState
25→ | RemoteAgentTaskState
26→ | InProcessTeammateTaskState
27→ | LocalWorkflowTaskState
28→ | MonitorMcpTaskState
29→ | DreamTaskState
30→
31→/**
32→ * Check if a task should be shown in the background tasks indicator.
33→ * A task is considered a background task if:
34→ * 1. It is running or pending
35→ * 2. It has been explicitly backgrounded (not a foreground task)
36→ */
37→export function isBackgroundTask(task: TaskState): task is BackgroundTaskState {
38→ if (task.status !== 'running' && task.status !== 'pending') {
39→ return false
40→ }
41→ // Foreground tasks (isBackgrounded === false) are not yet "background tasks"
42→ if ('isBackgrounded' in task && task.isBackgrounded === false) {
43→ return false
44→ }
45→ return true
46→}
47→Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/utils/**/*.ts Status: Completed
src\utils\CircularBuffer.ts src\utils\Cursor.ts src\utils\QueryGuard.ts src\utils\Shell.ts src\utils\ShellCommand.ts src\utils\abortController.ts src\utils\activityManager.ts src\utils\advisor.ts src\utils\agentContext.ts src\utils\agenticSessionSearch.ts src\utils\agentId.ts src\utils\agentSwarmsEnabled.ts src\utils\analyzeContext.ts src\utils\ansiToPng.ts src\utils\ansiToSvg.ts src\utils\api.ts src\utils\apiPreconnect.ts src\utils\appleTerminalBackup.ts src\utils\argumentSubstitution.ts src\utils\array.ts src\utils\asciicast.ts src\utils\attachments.ts src\utils\attribution.ts src\utils\auth.ts src\utils\authFileDescriptor.ts src\utils\authPortable.ts src\utils\autoModeDenials.ts src\utils\autoUpdater.ts src\utils\aws.ts src\utils\awsAuthStatusManager.ts src\utils\background\remote\preconditions.ts src\utils\background\remote\remoteSession.ts src\utils\backgroundHousekeeping.ts src\utils\bash\ParsedCommand.ts src\utils\bash\ShellSnapshot.ts src\utils\bash\ast.ts src\utils\bash\bashParser.ts src\utils\bash\bashPipeCommand.ts src\utils\bash\commands.ts src\utils\bash\heredoc.ts src\utils\bash\parser.ts src\utils\bash\prefix.ts src\utils\bash\registry.ts src\utils\bash\shellCompletion.ts src\utils\bash\shellPrefix.ts src\utils\bash\shellQuote.ts src\utils\bash\shellQuoting.ts src\utils\bash\specs\alias.ts src\utils\bash\specs\index.ts src\utils\bash\specs\nohup.ts src\utils\bash\specs\pyright.ts src\utils\bash\specs\sleep.ts src\utils\bash\specs\srun.ts src\utils\bash\specs\time.ts src\utils\bash\specs\timeout.ts src\utils\bash\treeSitterAnalysis.ts src\utils\betas.ts src\utils\billing.ts src\utils\binaryCheck.ts src\utils\browser.ts src\utils\bufferedWriter.ts src\utils\bundledMode.ts src\utils\caCerts.ts src\utils\caCertsConfig.ts src\utils\cachePaths.ts src\utils\classifierApprovals.ts src\utils\classifierApprovalsHook.ts src\utils\claudeCodeHints.ts src\utils\claudeDesktop.ts src\utils\claudeInChrome\chromeNativeHost.ts src\utils\claudeInChrome\common.ts src\utils\claudeInChrome\mcpServer.ts src\utils\claudeInChrome\prompt.ts src\utils\claudeInChrome\setup.ts src\utils\claudeInChrome\setupPortable.ts src\utils\claudemd.ts src\utils\cleanup.ts src\utils\cleanupRegistry.ts src\utils\cliArgs.ts src\utils\cliHighlight.ts src\utils\codeIndexing.ts src\utils\collapseBackgroundBashNotifications.ts src\utils\collapseHookSummaries.ts src\utils\collapseReadSearch.ts src\utils\collapseTeammateShutdowns.ts src\utils\combinedAbortSignal.ts src\utils\commandLifecycle.ts src\utils\commitAttribution.ts src\utils\completionCache.ts src\utils\computerUse\appNames.ts src\utils\computerUse\cleanup.ts src\utils\computerUse\common.ts src\utils\computerUse\computerUseLock.ts src\utils\computerUse\drainRunLoop.ts src\utils\computerUse\escHotkey.ts src\utils\computerUse\executor.ts src\utils\computerUse\gates.ts src\utils\computerUse\hostAdapter.ts src\utils\computerUse\inputLoader.ts src\utils\computerUse\mcpServer.ts (Results are truncated. Consider using a more specific path or pattern.)
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/moreright/**/*.{ts,tsx} Status: Completed
src\moreright\useMoreRight.tsx
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/native-ts/**/*.{ts,tsx} Status: Completed
src\native-ts\color-diff\index.ts src\native-ts\file-index\index.ts src\native-ts\yoga-layout\enums.ts src\native-ts\yoga-layout\index.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/keybindings/**/*.{ts,tsx} Status: Completed
src\keybindings\KeybindingContext.tsx src\keybindings\defaultBindings.ts src\keybindings\KeybindingProviderSetup.tsx src\keybindings\loadUserBindings.ts src\keybindings\match.ts src\keybindings\parser.ts src\keybindings\reservedShortcuts.ts src\keybindings\resolver.ts src\keybindings\schema.ts src\keybindings\shortcutFormat.ts src\keybindings\template.ts src\keybindings\useKeybinding.ts src\keybindings\useShortcutDisplay.ts src\keybindings\validate.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/upstreamproxy/**/*.{ts,tsx} Status: Completed
src\upstreamproxy\relay.ts src\upstreamproxy\upstreamproxy.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/server/**/*.{ts,tsx} Status: Completed
src\server\createDirectConnectSession.ts src\server\directConnectManager.ts src\server\types.ts
Tool Call: Read src\main.tsx (300 - 399) Status: Completed
300→ result.has_use_system_ca = true;
301→ }
302→ if (hasNodeOption('--use-openssl-ca')) {
303→ result.has_use_openssl_ca = true;
304→ }
305→ return result;
306→}
307→async function logStartupTelemetry(): Promise<void> {
308→ if (isAnalyticsDisabled()) return;
309→ const [isGit, worktreeCount, ghAuthStatus] = await Promise.all([getIsGit(), getWorktreeCount(), getGhAuthStatus()]);
310→ logEvent('tengu_startup_telemetry', {
311→ is_git: isGit,
312→ worktree_count: worktreeCount,
313→ gh_auth_status: ghAuthStatus as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
314→ sandbox_enabled: SandboxManager.isSandboxingEnabled(),
315→ are_unsandboxed_commands_allowed: SandboxManager.areUnsandboxedCommandsAllowed(),
316→ is_auto_bash_allowed_if_sandbox_enabled: SandboxManager.isAutoAllowBashIfSandboxedEnabled(),
317→ auto_updater_disabled: isAutoUpdaterDisabled(),
318→ prefers_reduced_motion: getInitialSettings().prefersReducedMotion ?? false,
319→ ...getCertEnvVarTelemetry()
320→ });
321→}
322→
323→// @[MODEL LAUNCH]: Consider any migrations you may need for model strings. See migrateSonnet1mToSonnet45.ts for an example.
324→// Bump this when adding a new sync migration so existing users re-run the set.
325→const CURRENT_MIGRATION_VERSION = 11;
326→function runMigrations(): void {
327→ if (getGlobalConfig().migrationVersion !== CURRENT_MIGRATION_VERSION) {
328→ migrateAutoUpdatesToSettings();
329→ migrateBypassPermissionsAcceptedToSettings();
330→ migrateEnableAllProjectMcpServersToSettings();
331→ resetProToOpusDefault();
332→ migrateSonnet1mToSonnet45();
333→ migrateLegacyOpusToCurrent();
334→ migrateSonnet45ToSonnet46();
335→ migrateOpusToOpus1m();
336→ migrateReplBridgeEnabledToRemoteControlAtStartup();
337→ if (feature('TRANSCRIPT_CLASSIFIER')) {
338→ resetAutoModeOptInForDefaultOffer();
339→ }
340→ if ("external" === 'ant') {
341→ migrateFennecToOpus();
342→ }
343→ saveGlobalConfig(prev => prev.migrationVersion === CURRENT_MIGRATION_VERSION ? prev : {
344→ ...prev,
345→ migrationVersion: CURRENT_MIGRATION_VERSION
346→ });
347→ }
348→ // Async migration - fire and forget since it's non-blocking
349→ migrateChangelogFromConfig().catch(() => {
350→ // Silently ignore migration errors - will retry on next startup
351→ });
352→}
353→
354→/**
355→ * Prefetch system context (including git status) only when it's safe to do so.
356→ * Git commands can execute arbitrary code via hooks and config (e.g., core.fsmonitor,
357→ * diff.external), so we must only run them after trust is established or in
358→ * non-interactive mode where trust is implicit.
359→ */
360→function prefetchSystemContextIfSafe(): void {
361→ const isNonInteractiveSession = getIsNonInteractiveSession();
362→
363→ // In non-interactive mode (--print), trust dialog is skipped and
364→ // execution is considered trusted (as documented in help text)
365→ if (isNonInteractiveSession) {
366→ logForDiagnosticsNoPII('info', 'prefetch_system_context_non_interactive');
367→ void getSystemContext();
368→ return;
369→ }
370→
371→ // In interactive mode, only prefetch if trust has already been established
372→ const hasTrust = checkHasTrustDialogAccepted();
373→ if (hasTrust) {
374→ logForDiagnosticsNoPII('info', 'prefetch_system_context_has_trust');
375→ void getSystemContext();
376→ } else {
377→ logForDiagnosticsNoPII('info', 'prefetch_system_context_skipped_no_trust');
378→ }
379→ // Otherwise, don't prefetch - wait for trust to be established first
380→}
381→
382→/**
383→ * Start background prefetches and housekeeping that are NOT needed before first render.
384→ * These are deferred from setup() to reduce event loop contention and child process
385→ * spawning during the critical startup path.
386→ * Call this after the REPL has been rendered.
387→ */
388→export function startDeferredPrefetches(): void {
389→ // This function runs after first render, so it doesn't block the initial paint.
390→ // However, the spawned processes and async work still contend for CPU and event
391→ // loop time, which skews startup benchmarks (CPU profiles, time-to-first-render
392→ // measurements). Skip all of it when we're only measuring startup performance.
393→ if (isEnvTruthy(process.env.CLAUDE_CODE_EXIT_AFTER_FIRST_RENDER) ||
394→ // --bare: skip ALL prefetches. These are cache-warms for the REPL's
395→ // first-turn responsiveness (initUser, getUserContext, tips, countFiles,
396→ // modelCapabilities, change detectors). Scripted -p calls don't have a
397→ // "user is typing" window to hide this work in — it's pure overhead on
398→ // the critical path.
399→ isBareMode()) {Tool Call: grep "type DeepImmutable" D:\code\play\stock_ai_rust\claude-code\src Status: Completed
No files found
Tool Call: Read src\entrypoints\mcp.ts (1 - 60) Status: Completed
1→import { Server } from '@modelcontextprotocol/sdk/server/index.js'
2→import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3→import {
4→ CallToolRequestSchema,
5→ type CallToolResult,
6→ ListToolsRequestSchema,
7→ type ListToolsResult,
8→ type Tool,
9→} from '@modelcontextprotocol/sdk/types.js'
10→import { getDefaultAppState } from 'src/state/AppStateStore.js'
11→import review from '../commands/review.js'
12→import type { Command } from '../commands.js'
13→import {
14→ findToolByName,
15→ getEmptyToolPermissionContext,
16→ type ToolUseContext,
17→} from '../Tool.js'
18→import { getTools } from '../tools.js'
19→import { createAbortController } from '../utils/abortController.js'
20→import { createFileStateCacheWithSizeLimit } from '../utils/fileStateCache.js'
21→import { logError } from '../utils/log.js'
22→import { createAssistantMessage } from '../utils/messages.js'
23→import { getMainLoopModel } from '../utils/model/model.js'
24→import { hasPermissionsToUseTool } from '../utils/permissions/permissions.js'
25→import { setCwd } from '../utils/Shell.js'
26→import { jsonStringify } from '../utils/slowOperations.js'
27→import { getErrorParts } from '../utils/toolErrors.js'
28→import { zodToJsonSchema } from '../utils/zodToJsonSchema.js'
29→
30→type ToolInput = Tool['inputSchema']
31→type ToolOutput = Tool['outputSchema']
32→
33→const MCP_COMMANDS: Command[] = [review]
34→
35→export async function startMCPServer(
36→ cwd: string,
37→ debug: boolean,
38→ verbose: boolean,
39→): Promise<void> {
40→ // Use size-limited LRU cache for readFileState to prevent unbounded memory growth
41→ // 100 files and 25MB limit should be sufficient for MCP server operations
42→ const READ_FILE_STATE_CACHE_SIZE = 100
43→ const readFileStateCache = createFileStateCacheWithSizeLimit(
44→ READ_FILE_STATE_CACHE_SIZE,
45→ )
46→ setCwd(cwd)
47→ const server = new Server(
48→ {
49→ name: 'claude/tengu',
50→ version: MACRO.VERSION,
51→ },
52→ {
53→ capabilities: {
54→ tools: {},
55→ },
56→ },
57→ )
58→
59→ server.setRequestHandler(
60→ ListToolsRequestSchema,Tool Call: Read src\tools\AgentTool\runAgent.ts (1 - 60) Status: Completed
1→import { feature } from 'bun:bundle'
2→import type { UUID } from 'crypto'
3→import { randomUUID } from 'crypto'
4→import uniqBy from 'lodash-es/uniqBy.js'
5→import { logForDebugging } from 'src/utils/debug.js'
6→import { getProjectRoot, getSessionId } from '../../bootstrap/state.js'
7→import { getCommand, getSkillToolCommands, hasCommand } from '../../commands.js'
8→import {
9→ DEFAULT_AGENT_PROMPT,
10→ enhanceSystemPromptWithEnvDetails,
11→} from '../../constants/prompts.js'
12→import type { QuerySource } from '../../constants/querySource.js'
13→import { getSystemContext, getUserContext } from '../../context.js'
14→import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
15→import { query } from '../../query.js'
16→import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js'
17→import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js'
18→import { cleanupAgentTracking } from '../../services/api/promptCacheBreakDetection.js'
19→import {
20→ connectToServer,
21→ fetchToolsForClient,
22→} from '../../services/mcp/client.js'
23→import { getMcpConfigByName } from '../../services/mcp/config.js'
24→import type {
25→ MCPServerConnection,
26→ ScopedMcpServerConfig,
27→} from '../../services/mcp/types.js'
28→import type { Tool, Tools, ToolUseContext } from '../../Tool.js'
29→import { killShellTasksForAgent } from '../../tasks/LocalShellTask/killShellTasks.js'
30→import type { Command } from '../../types/command.js'
31→import type { AgentId } from '../../types/ids.js'
32→import type {
33→ AssistantMessage,
34→ Message,
35→ ProgressMessage,
36→ RequestStartEvent,
37→ StreamEvent,
38→ SystemCompactBoundaryMessage,
39→ TombstoneMessage,
40→ ToolUseSummaryMessage,
41→ UserMessage,
42→} from '../../types/message.js'
43→import { createAttachmentMessage } from '../../utils/attachments.js'
44→import { AbortError } from '../../utils/errors.js'
45→import { getDisplayPath } from '../../utils/file.js'
46→import {
47→ cloneFileStateCache,
48→ createFileStateCacheWithSizeLimit,
49→ READ_FILE_STATE_CACHE_SIZE,
50→} from '../../utils/fileStateCache.js'
51→import {
52→ type CacheSafeParams,
53→ createSubagentContext,
54→} from '../../utils/forkedAgent.js'
55→import { registerFrontmatterHooks } from '../../utils/hooks/registerFrontmatterHooks.js'
56→import { clearSessionHooks } from '../../utils/hooks/sessionHooks.js'
57→import { executeSubagentStartHooks } from '../../utils/hooks.js'
58→import { createUserMessage } from '../../utils/messages.js'
59→import { getAgentModel } from '../../utils/model/agent.js'
60→import type { ModelAlias } from '../../utils/model/aliases.js'Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/query/**/*.{ts,tsx} Status: Completed
src\query\config.ts src\query\deps.ts src\query\stopHooks.ts src\query\tokenBudget.ts
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/constants/**/*.{ts,tsx} Status: Completed
src\constants\apiLimits.ts src\constants\betas.ts src\constants\common.ts src\constants\cyberRiskInstruction.ts src\constants\errorIds.ts src\constants\figures.ts src\constants\files.ts src\constants\github-app.ts src\constants\keys.ts src\constants\messages.ts src\constants\oauth.ts src\constants\outputStyles.ts src\constants\product.ts src\constants\prompts.ts src\constants\spinnerVerbs.ts src\constants\system.ts src\constants\systemPromptSections.ts src\constants\toolLimits.ts src\constants\tools.ts src\constants\turnCompletionVerbs.ts src\constants\xml.ts
Tool Call: Read src\main.tsx (400 - 499) Status: Completed
400→ return;
401→ }
402→
403→ // Process-spawning prefetches (consumed at first API call, user is still typing)
404→ void initUser();
405→ void getUserContext();
406→ prefetchSystemContextIfSafe();
407→ void getRelevantTips();
408→ if (isEnvTruthy(process.env.CLAUDE_CODE_USE_BEDROCK) && !isEnvTruthy(process.env.CLAUDE_CODE_SKIP_BEDROCK_AUTH)) {
409→ void prefetchAwsCredentialsAndBedRockInfoIfSafe();
410→ }
411→ if (isEnvTruthy(process.env.CLAUDE_CODE_USE_VERTEX) && !isEnvTruthy(process.env.CLAUDE_CODE_SKIP_VERTEX_AUTH)) {
412→ void prefetchGcpCredentialsIfSafe();
413→ }
414→ void countFilesRoundedRg(getCwd(), AbortSignal.timeout(3000), []);
415→
416→ // Analytics and feature flag initialization
417→ void initializeAnalyticsGates();
418→ void prefetchOfficialMcpUrls();
419→ void refreshModelCapabilities();
420→
421→ // File change detectors deferred from init() to unblock first render
422→ void settingsChangeDetector.initialize();
423→ if (!isBareMode()) {
424→ void skillChangeDetector.initialize();
425→ }
426→
427→ // Event loop stall detector — logs when the main thread is blocked >500ms
428→ if ("external" === 'ant') {
429→ void import('./utils/eventLoopStallDetector.js').then(m => m.startEventLoopStallDetector());
430→ }
431→}
432→function loadSettingsFromFlag(settingsFile: string): void {
433→ try {
434→ const trimmedSettings = settingsFile.trim();
435→ const looksLikeJson = trimmedSettings.startsWith('{') && trimmedSettings.endsWith('}');
436→ let settingsPath: string;
437→ if (looksLikeJson) {
438→ // It's a JSON string - validate and create temp file
439→ const parsedJson = safeParseJSON(trimmedSettings);
440→ if (!parsedJson) {
441→ process.stderr.write(chalk.red('Error: Invalid JSON provided to --settings\n'));
442→ process.exit(1);
443→ }
444→
445→ // Create a temporary file and write the JSON to it.
446→ // Use a content-hash-based path instead of random UUID to avoid
447→ // busting the Anthropic API prompt cache. The settings path ends up
448→ // in the Bash tool's sandbox denyWithinAllow list, which is part of
449→ // the tool description sent to the API. A random UUID per subprocess
450→ // changes the tool description on every query() call, invalidating
451→ // the cache prefix and causing a 12x input token cost penalty.
452→ // The content hash ensures identical settings produce the same path
453→ // across process boundaries (each SDK query() spawns a new process).
454→ settingsPath = generateTempFilePath('claude-settings', '.json', {
455→ contentHash: trimmedSettings
456→ });
457→ writeFileSync_DEPRECATED(settingsPath, trimmedSettings, 'utf8');
458→ } else {
459→ // It's a file path - resolve and validate by attempting to read
460→ const {
461→ resolvedPath: resolvedSettingsPath
462→ } = safeResolvePath(getFsImplementation(), settingsFile);
463→ try {
464→ readFileSync(resolvedSettingsPath, 'utf8');
465→ } catch (e) {
466→ if (isENOENT(e)) {
467→ process.stderr.write(chalk.red(`Error: Settings file not found: ${resolvedSettingsPath}\n`));
468→ process.exit(1);
469→ }
470→ throw e;
471→ }
472→ settingsPath = resolvedSettingsPath;
473→ }
474→ setFlagSettingsPath(settingsPath);
475→ resetSettingsCache();
476→ } catch (error) {
477→ if (error instanceof Error) {
478→ logError(error);
479→ }
480→ process.stderr.write(chalk.red(`Error processing settings: ${errorMessage(error)}\n`));
481→ process.exit(1);
482→ }
483→}
484→function loadSettingSourcesFromFlag(settingSourcesArg: string): void {
485→ try {
486→ const sources = parseSettingSourcesFlag(settingSourcesArg);
487→ setAllowedSettingSources(sources);
488→ resetSettingsCache();
489→ } catch (error) {
490→ if (error instanceof Error) {
491→ logError(error);
492→ }
493→ process.stderr.write(chalk.red(`Error processing --setting-sources: ${errorMessage(error)}\n`));
494→ process.exit(1);
495→ }
496→}
497→
498→/**
499→ * Parse and load settings flags early, before init()Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/types/**/*.ts Status: Completed
src\types\command.ts src\types\generated\events_mono\claude_code\v1\claude_code_internal_event.ts src\types\generated\events_mono\common\v1\auth.ts src\types\generated\events_mono\growthbook\v1\growthbook_experiment_event.ts src\types\generated\google\protobuf\timestamp.ts src\types\hooks.ts src\types\ids.ts src\types\logs.ts src\types\permissions.ts src\types\plugin.ts src\types\textInputTypes.ts
Tool Call: grep -l | head -0 "." D:/code/play/stock_ai_rust/claude-code/src/tools Status: Completed
Found 184 files src\tools\shared\spawnMultiAgent.ts src\tools\testing\TestingPermissionTool.tsx src\tools\utils.ts src\tools\shared\gitOperationTracking.ts src\tools\WebSearchTool\prompt.ts src\tools\WebFetchTool\prompt.ts src\tools\WebFetchTool\utils.ts src\tools\WebSearchTool\UI.tsx src\tools\WebSearchTool\WebSearchTool.ts src\tools\WebFetchTool\preapproved.ts src\tools\WebFetchTool\WebFetchTool.ts src\tools\ToolSearchTool\constants.ts src\tools\ToolSearchTool\prompt.ts src\tools\ToolSearchTool\ToolSearchTool.ts src\tools\WebFetchTool\UI.tsx src\tools\TeamDeleteTool\constants.ts src\tools\TeamDeleteTool\prompt.ts src\tools\TodoWriteTool\constants.ts src\tools\TodoWriteTool\prompt.ts src\tools\TodoWriteTool\TodoWriteTool.ts src\tools\TeamCreateTool\constants.ts src\tools\TeamCreateTool\prompt.ts src\tools\TeamCreateTool\UI.tsx src\tools\TeamDeleteTool\TeamDeleteTool.ts src\tools\TeamDeleteTool\UI.tsx src\tools\TaskUpdateTool\constants.ts src\tools\TaskUpdateTool\prompt.ts src\tools\TaskUpdateTool\TaskUpdateTool.ts src\tools\TeamCreateTool\TeamCreateTool.ts src\tools\TaskOutputTool\constants.ts src\tools\TaskStopTool\prompt.ts src\tools\TaskStopTool\TaskStopTool.ts src\tools\TaskStopTool\UI.tsx src\tools\TaskOutputTool\TaskOutputTool.tsx src\tools\TaskGetTool\constants.ts src\tools\TaskGetTool\prompt.ts src\tools\TaskGetTool\TaskGetTool.ts src\tools\TaskListTool\constants.ts src\tools\TaskListTool\prompt.ts src\tools\TaskListTool\TaskListTool.ts src\tools\SyntheticOutputTool\SyntheticOutputTool.ts src\tools\TaskCreateTool\constants.ts src\tools\TaskCreateTool\prompt.ts src\tools\TaskCreateTool\TaskCreateTool.ts src\tools\SkillTool\constants.ts src\tools\SkillTool\prompt.ts src\tools\SleepTool\prompt.ts src\tools\SendMessageTool\prompt.ts src\tools\SkillTool\SkillTool.ts src\tools\SkillTool\UI.tsx src\tools\ScheduleCronTool\prompt.ts src\tools\SendMessageTool\constants.ts src\tools\SendMessageTool\SendMessageTool.ts src\tools\SendMessageTool\UI.tsx src\tools\ScheduleCronTool\CronCreateTool.ts src\tools\ScheduleCronTool\CronDeleteTool.ts src\tools\ScheduleCronTool\CronListTool.ts src\tools\ScheduleCronTool\UI.tsx src\tools\RemoteTriggerTool\prompt.ts src\tools\RemoteTriggerTool\RemoteTriggerTool.ts src\tools\RemoteTriggerTool\UI.tsx src\tools\ReadMcpResourceTool\prompt.ts src\tools\ReadMcpResourceTool\UI.tsx src\tools\ReadMcpResourceTool\ReadMcpResourceTool.ts src\tools\REPLTool\primitiveTools.ts src\tools\PowerShellTool\readOnlyValidation.ts src\tools\PowerShellTool\toolName.ts src\tools\REPLTool\constants.ts src\tools\PowerShellTool\powershellSecurity.ts src\tools\PowerShellTool\prompt.ts src\tools\PowerShellTool\pathValidation.ts src\tools\PowerShellTool\powershellPermissions.ts src\tools\PowerShellTool\commandSemantics.ts src\tools\PowerShellTool\commonParameters.ts src\tools\PowerShellTool\destructiveCommandWarning.ts src\tools\PowerShellTool\gitSafety.ts src\tools\PowerShellTool\modeValidation.ts src\tools\PowerShellTool\clmTypes.ts src\tools\PowerShellTool\PowerShellTool.tsx src\tools\PowerShellTool\UI.tsx src\tools\NotebookEditTool\constants.ts src\tools\NotebookEditTool\prompt.ts src\tools\McpAuthTool\McpAuthTool.ts src\tools\NotebookEditTool\NotebookEditTool.ts src\tools\NotebookEditTool\UI.tsx src\tools\MCPTool\classifyForCollapse.ts src\tools\MCPTool\prompt.ts src\tools\MCPTool\UI.tsx src\tools\ListMcpResourcesTool\ListMcpResourcesTool.ts src\tools\ListMcpResourcesTool\prompt.ts src\tools\ListMcpResourcesTool\UI.tsx src\tools\MCPTool\MCPTool.ts src\tools\LSPTool\formatters.ts src\tools\LSPTool\prompt.ts src\tools\LSPTool\schemas.ts src\tools\LSPTool\symbolContext.ts src\tools\GrepTool\prompt.ts src\tools\LSPTool\LSPTool.ts src\tools\LSPTool\UI.tsx src\tools\GlobTool\prompt.ts src\tools\GlobTool\UI.tsx src\tools\GrepTool\GrepTool.ts src\tools\GrepTool\UI.tsx src\tools\FileWriteTool\FileWriteTool.ts src\tools\FileWriteTool\prompt.ts src\tools\FileWriteTool\UI.tsx src\tools\GlobTool\GlobTool.ts src\tools\FileReadTool\FileReadTool.ts src\tools\FileReadTool\imageProcessor.ts src\tools\FileReadTool\limits.ts src\tools\FileReadTool\prompt.ts src\tools\FileReadTool\UI.tsx src\tools\FileEditTool\types.ts src\tools\FileEditTool\utils.ts src\tools\FileEditTool\constants.ts src\tools\FileEditTool\prompt.ts src\tools\FileEditTool\UI.tsx src\tools\ExitWorktreeTool\constants.ts src\tools\ExitWorktreeTool\ExitWorktreeTool.ts src\tools\ExitWorktreeTool\prompt.ts src\tools\ExitWorktreeTool\UI.tsx src\tools\FileEditTool\FileEditTool.ts src\tools\ExitPlanModeTool\constants.ts src\tools\ExitPlanModeTool\ExitPlanModeV2Tool.ts src\tools\ExitPlanModeTool\prompt.ts src\tools\ExitPlanModeTool\UI.tsx src\tools\EnterWorktreeTool\constants.ts src\tools\EnterWorktreeTool\EnterWorktreeTool.ts src\tools\EnterWorktreeTool\prompt.ts src\tools\EnterWorktreeTool\UI.tsx src\tools\EnterPlanModeTool\constants.ts src\tools\EnterPlanModeTool\EnterPlanModeTool.ts src\tools\EnterPlanModeTool\prompt.ts src\tools\EnterPlanModeTool\UI.tsx src\tools\ConfigTool\ConfigTool.ts src\tools\ConfigTool\constants.ts src\tools\ConfigTool\prompt.ts src\tools\ConfigTool\supportedSettings.ts src\tools\ConfigTool\UI.tsx src\tools\BriefTool\attachments.ts src\tools\BriefTool\prompt.ts src\tools\BriefTool\UI.tsx src\tools\BriefTool\upload.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts src\tools\BriefTool\BriefTool.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\BashTool.tsx src\tools\BashTool\BashToolResultMessage.tsx src\tools\BashTool\UI.tsx src\tools\AgentTool\runAgent.ts src\tools\AskUserQuestionTool\AskUserQuestionTool.tsx src\tools\AskUserQuestionTool\prompt.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\built-in\verificationAgent.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\built-in\planAgent.ts src\tools\AgentTool\built-in\statuslineSetup.ts src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\built-in\claudeCodeGuideAgent.ts src\tools\AgentTool\built-in\exploreAgent.ts src\tools\AgentTool\built-in\generalPurposeAgent.ts src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\UI.tsx src\tools\AgentTool\AgentTool.tsx
Tool Call: grep -l | head -0 "." D:/code/play/stock_ai_rust/claude-code/src/utils Status: Completed
Found 564 files src\utils\worktreeModeEnabled.ts src\utils\xdg.ts src\utils\xml.ts src\utils\yaml.ts src\utils\zodToJsonSchema.ts src\utils\withResolvers.ts src\utils\words.ts src\utils\workloadContext.ts src\utils\worktree.ts src\utils\userPromptKeywords.ts src\utils\uuid.ts src\utils\warningHandler.ts src\utils\which.ts src\utils\windowsPaths.ts src\utils\ultraplan\keyword.ts src\utils\unaryLogging.ts src\utils\undercover.ts src\utils\user.ts src\utils\userAgent.ts src\utils\toolSchemaCache.ts src\utils\toolSearch.ts src\utils\transcriptSearch.ts src\utils\treeify.ts src\utils\truncate.ts src\utils\ultraplan\ccrSession.ts src\utils\tokens.ts src\utils\toolErrors.ts src\utils\toolPool.ts src\utils\toolResultStorage.ts src\utils\todo\types.ts src\utils\tokenBudget.ts src\utils\tmuxSocket.ts src\utils\tempfile.ts src\utils\terminal.ts src\utils\terminalPanel.ts src\utils\textHighlighting.ts src\utils\theme.ts src\utils\thinking.ts src\utils\timeouts.ts src\utils\teleport\api.ts src\utils\teleport\environments.ts src\utils\teleport\environmentSelection.ts src\utils\teleport\gitBundle.ts src\utils\teleport.tsx src\utils\telemetry\pluginTelemetry.ts src\utils\telemetry\sessionTracing.ts src\utils\telemetry\skillLoadedEvent.ts src\utils\telemetryAttributes.ts src\utils\telemetry\events.ts src\utils\telemetry\instrumentation.ts src\utils\telemetry\logger.ts src\utils\telemetry\perfettoTracing.ts src\utils\teammateMailbox.ts src\utils\telemetry\betaSessionTracing.ts src\utils\telemetry\bigqueryExporter.ts src\utils\teammate.ts src\utils\teammateContext.ts src\utils\task\outputFormatting.ts src\utils\task\sdkProgress.ts src\utils\tasks.ts src\utils\teamDiscovery.ts src\utils\teamMemoryOps.ts src\utils\taggedId.ts src\utils\task\diskOutput.ts src\utils\task\framework.ts src\utils\task\TaskOutput.ts src\utils\systemDirectories.ts src\utils\systemPrompt.ts src\utils\systemPromptType.ts src\utils\systemTheme.ts src\utils\swarm\spawnUtils.ts src\utils\swarm\teamHelpers.ts src\utils\swarm\teammateInit.ts src\utils\swarm\teammateLayoutManager.ts src\utils\swarm\teammateModel.ts src\utils\swarm\teammatePromptAddendum.ts src\utils\swarm\leaderPermissionBridge.ts src\utils\swarm\permissionSync.ts src\utils\swarm\reconnection.ts src\utils\swarm\spawnInProcess.ts src\utils\swarm\backends\teammateModeSnapshot.ts src\utils\swarm\backends\types.ts src\utils\swarm\constants.ts src\utils\swarm\inProcessRunner.ts src\utils\swarm\backends\detection.ts src\utils\swarm\backends\it2Setup.ts src\utils\swarm\backends\registry.ts src\utils\swarm\backends\TmuxBackend.ts src\utils\swarm\backends\InProcessBackend.ts src\utils\swarm\backends\ITermBackend.ts src\utils\swarm\backends\PaneBackendExecutor.ts src\utils\swarm\It2SetupPrompt.tsx src\utils\suggestions\commandSuggestions.ts src\utils\suggestions\directoryCompletion.ts src\utils\suggestions\shellHistoryCompletion.ts src\utils\suggestions\skillUsageTracking.ts src\utils\suggestions\slackChannelSuggestions.ts src\utils\stream.ts src\utils\streamJsonStdoutGuard.ts src\utils\streamlinedTransform.ts src\utils\stringUtils.ts src\utils\subprocessEnv.ts src\utils\statsCache.ts src\utils\status.tsx src\utils\statusNoticeDefinitions.tsx src\utils\statusNoticeHelpers.ts src\utils\startupProfiler.ts src\utils\staticRender.tsx src\utils\stats.ts src\utils\slashCommandParsing.ts src\utils\sleep.ts src\utils\sliceAnsi.ts src\utils\slowOperations.ts src\utils\standaloneAgent.ts src\utils\sideQuestion.ts src\utils\signal.ts src\utils\sinks.ts src\utils\skills\skillChangeDetector.ts src\utils\shell\shellToolUtils.ts src\utils\shell\specPrefix.ts src\utils\shellConfig.ts src\utils\sideQuery.ts src\utils\shell\prefix.ts src\utils\shell\readOnlyCommandValidation.ts src\utils\shell\resolveDefaultShell.ts src\utils\shell\shellProvider.ts src\utils\shell\bashProvider.ts src\utils\shell\outputLimits.ts src\utils\shell\powershellDetection.ts src\utils\shell\powershellProvider.ts src\utils\settings\types.ts src\utils\settings\validateEditTool.ts src\utils\settings\validation.ts src\utils\settings\validationTips.ts src\utils\settings\pluginOnlyPolicy.ts src\utils\settings\schemaOutput.ts src\utils\settings\settings.ts src\utils\settings\settingsCache.ts src\utils\settings\toolValidationConfig.ts src\utils\settings\managedPath.ts src\utils\settings\mdm\constants.ts src\utils\settings\mdm\rawRead.ts src\utils\settings\mdm\settings.ts src\utils\settings\permissionValidation.ts src\utils\settings\applySettingsChange.ts src\utils\settings\changeDetector.ts src\utils\settings\constants.ts src\utils\settings\internalWrites.ts src\utils\sessionStoragePortable.ts src\utils\sessionTitle.ts src\utils\sessionUrl.ts src\utils\set.ts src\utils\settings\allErrors.ts src\utils\sessionStorage.ts src\utils\sessionStart.ts src\utils\sessionState.ts src\utils\sessionEnvironment.ts src\utils\sessionEnvVars.ts src\utils\sessionFileAccessHooks.ts src\utils\sessionIngressAuth.ts src\utils\sessionRestore.ts src\utils\semanticBoolean.ts src\utils\semanticNumber.ts src\utils\semver.ts src\utils\sequential.ts src\utils\sessionActivity.ts src\utils\secureStorage\macOsKeychainHelpers.ts src\utils\secureStorage\macOsKeychainStorage.ts src\utils\secureStorage\plainTextStorage.ts src\utils\screenshotClipboard.ts src\utils\sdkEventQueue.ts src\utils\secureStorage\fallbackStorage.ts src\utils\secureStorage\index.ts src\utils\secureStorage\keychainPrefetch.ts src\utils\ripgrep.ts src\utils\sandbox\sandbox-adapter.ts src\utils\sandbox\sandbox-ui-utils.ts src\utils\sanitization.ts src\utils\releaseNotes.ts src\utils\renderOptions.ts src\utils\queryHelpers.ts src\utils\queryProfiler.ts src\utils\queueProcessor.ts src\utils\readEditContext.ts src\utils\readFileInRange.ts src\utils\promptEditor.ts src\utils\promptShellExecution.ts src\utils\proxy.ts src\utils\queryContext.ts src\utils\processUserInput\processUserInput.ts src\utils\profilerBase.ts src\utils\promptCategory.ts src\utils\processUserInput\processSlashCommand.tsx src\utils\processUserInput\processTextPrompt.ts src\utils\preflightChecks.tsx src\utils\privacyLevel.ts src\utils\process.ts src\utils\processUserInput\processBashCommand.tsx src\utils\powershell\parser.ts src\utils\powershell\staticPrefix.ts src\utils\plugins\walkPluginMarkdown.ts src\utils\plugins\zipCache.ts src\utils\plugins\zipCacheAdapters.ts src\utils\powershell\dangerousCmdlets.ts src\utils\plugins\refresh.ts src\utils\plugins\schemas.ts src\utils\plugins\validatePlugin.ts src\utils\plugins\pluginPolicy.ts src\utils\plugins\pluginStartupCheck.ts src\utils\plugins\pluginVersioning.ts src\utils\plugins\reconciler.ts src\utils\plugins\pluginLoader.ts src\utils\plugins\pluginOptionsStorage.ts src\utils\plugins\pluginInstallationHelpers.ts src\utils\plugins\pluginBlocklist.ts src\utils\plugins\pluginDirectories.ts src\utils\plugins\pluginFlagging.ts src\utils\plugins\pluginIdentifier.ts src\utils\plugins\orphanedPluginFilter.ts src\utils\plugins\parseMarketplaceInput.ts src\utils\plugins\performStartupChecks.tsx src\utils\plugins\pluginAutoupdate.ts src\utils\plugins\mcpbHandler.ts src\utils\plugins\officialMarketplace.ts src\utils\plugins\officialMarketplaceGcs.ts src\utils\plugins\officialMarketplaceStartupCheck.ts src\utils\plugins\marketplaceManager.ts src\utils\plugins\mcpPluginIntegration.ts src\utils\plugins\lspRecommendation.ts src\utils\plugins\managedPlugins.ts src\utils\plugins\marketplaceHelpers.ts src\utils\plugins\loadPluginCommands.ts src\utils\plugins\loadPluginHooks.ts src\utils\plugins\loadPluginOutputStyles.ts src\utils\plugins\lspPluginIntegration.ts src\utils\plugins\hintRecommendation.ts src\utils\plugins\installCounts.ts src\utils\plugins\installedPluginsManager.ts src\utils\plugins\loadPluginAgents.ts src\utils\plugins\cacheUtils.ts src\utils\plugins\dependencyResolver.ts src\utils\plugins\fetchTelemetry.ts src\utils\plugins\gitAvailability.ts src\utils\plugins\headlessPluginInstall.ts src\utils\plans.ts src\utils\platform.ts src\utils\plugins\addDirPluginSettings.ts src\utils\permissions\permissionsLoader.ts src\utils\permissions\shadowedRuleDetection.ts src\utils\permissions\shellRuleMatching.ts src\utils\permissions\yoloClassifier.ts src\utils\planModeV2.ts src\utils\permissions\permissionRuleParser.ts src\utils\permissions\permissions.ts src\utils\permissions\permissionSetup.ts src\utils\permissions\filesystem.ts src\utils\permissions\getNextPermissionMode.ts src\utils\permissions\pathValidation.ts src\utils\permissions\permissionExplainer.ts src\utils\permissions\classifierShared.ts src\utils\permissions\dangerousPatterns.ts src\utils\permissions\denialTracking.ts src\utils\permissions\autoModeState.ts src\utils\permissions\bashClassifier.ts src\utils\permissions\bypassPermissionsKillswitch.ts src\utils\permissions\classifierDecision.ts src\utils\permissions\PermissionUpdateSchema.ts src\utils\permissions\PermissionUpdate.ts src\utils\permissions\PermissionMode.ts src\utils\permissions\PermissionPromptToolResultSchema.ts src\utils\permissions\PermissionResult.ts src\utils\permissions\PermissionRule.ts src\utils\path.ts src\utils\pdf.ts src\utils\pdfUtils.ts src\utils\peerAddress.ts src\utils\nativeInstaller\packageManagers.ts src\utils\nativeInstaller\pidLock.ts src\utils\notebook.ts src\utils\objectGroupBy.ts src\utils\pasteStore.ts src\utils\nativeInstaller\download.ts src\utils\nativeInstaller\index.ts src\utils\nativeInstaller\installer.ts src\utils\model\validateModel.ts src\utils\modelCost.ts src\utils\modifiers.ts src\utils\mtls.ts src\utils\model\modelOptions.ts src\utils\model\modelStrings.ts src\utils\model\modelSupportOverrides.ts src\utils\model\providers.ts src\utils\model\model.ts src\utils\model\modelAllowlist.ts src\utils\model\modelCapabilities.ts src\utils\model\bedrock.ts src\utils\model\check1mAccess.ts src\utils\model\configs.ts src\utils\model\contextWindowUpgradeCheck.ts src\utils\model\deprecation.ts src\utils\messages\systemInit.ts src\utils\model\agent.ts src\utils\model\aliases.ts src\utils\model\antModels.ts src\utils\messages.ts src\utils\messages\mappers.ts src\utils\messagePredicates.ts src\utils\messageQueueManager.ts src\utils\memory\types.ts src\utils\memory\versions.ts src\utils\memoryFileDetection.ts src\utils\mcpValidation.ts src\utils\mcpWebSocketTransport.ts src\utils\memoize.ts src\utils\mcpInstructionsDelta.ts src\utils\mcpOutputStorage.ts src\utils\mcp\dateTimeParser.ts src\utils\mcp\elicitationValidation.ts src\utils\mailbox.ts src\utils\managedEnv.ts src\utils\managedEnvConstants.ts src\utils\markdown.ts src\utils\markdownConfigLoader.ts src\utils\localInstaller.ts src\utils\lockfile.ts src\utils\log.ts src\utils\logoV2Utils.ts src\utils\jsonRead.ts src\utils\keyboardShortcuts.ts src\utils\lazySchema.ts src\utils\listSessionsImpl.ts src\utils\ink.ts src\utils\inProcessTeammateHelpers.ts src\utils\intl.ts src\utils\jetbrains.ts src\utils\json.ts src\utils\imageResizer.ts src\utils\imageStore.ts src\utils\imageValidation.ts src\utils\immediateCommand.ts src\utils\ide.ts src\utils\idePathConversion.ts src\utils\idleTimeout.ts src\utils\imagePaste.ts src\utils\http.ts src\utils\hyperlink.ts src\utils\iTermBackup.ts src\utils\hooks\registerSkillHooks.ts src\utils\hooks\sessionHooks.ts src\utils\hooks\skillImprovement.ts src\utils\hooks\ssrfGuard.ts src\utils\horizontalScroll.ts src\utils\hooks\hooksConfigManager.ts src\utils\hooks\hooksConfigSnapshot.ts src\utils\hooks\hooksSettings.ts src\utils\hooks\postSamplingHooks.ts src\utils\hooks\registerFrontmatterHooks.ts src\utils\hooks\execPromptHook.ts src\utils\hooks\fileChangedWatcher.ts src\utils\hooks\hookEvents.ts src\utils\hooks\hookHelpers.ts src\utils\hooks.ts src\utils\hooks\apiQueryHookHelper.ts src\utils\hooks\AsyncHookRegistry.ts src\utils\hooks\execAgentHook.ts src\utils\hooks\execHttpHook.ts src\utils\highlightMatch.tsx src\utils\hash.ts src\utils\headlessProfiler.ts src\utils\heapDumpService.ts src\utils\heatmap.ts src\utils\glob.ts src\utils\gracefulShutdown.ts src\utils\groupToolUses.ts src\utils\handlePromptSubmit.ts src\utils\gitDiff.ts src\utils\github\ghAuthStatus.ts src\utils\githubRepoPathMapping.ts src\utils\gitSettings.ts src\utils\git\gitConfigParser.ts src\utils\git\gitFilesystem.ts src\utils\git\gitignore.ts src\utils\getWorktreePaths.ts src\utils\getWorktreePathsPortable.ts src\utils\ghPrStatus.ts src\utils\git.ts src\utils\generators.ts src\utils\genericProcessUtils.ts src\utils\frontmatterParser.ts src\utils\fsOperations.ts src\utils\fullscreen.ts src\utils\generatedFiles.ts src\utils\fingerprint.ts src\utils\forkedAgent.ts src\utils\format.ts src\utils\formatBriefTimestamp.ts src\utils\fpsTracker.ts src\utils\filePersistence\outputsScanner.ts src\utils\fileRead.ts src\utils\fileReadCache.ts src\utils\fileStateCache.ts src\utils\findExecutable.ts src\utils\file.ts src\utils\fileHistory.ts src\utils\fileOperationAnalytics.ts src\utils\filePersistence\filePersistence.ts src\utils\execFileNoThrowPortable.ts src\utils\execSyncWrapper.ts src\utils\exportRenderer.tsx src\utils\extraUsage.ts src\utils\fastMode.ts src\utils\envValidation.ts src\utils\errorLogSink.ts src\utils\errors.ts src\utils\exampleCommands.ts src\utils\execFileNoThrow.ts src\utils\effort.ts src\utils\embeddedTools.ts src\utils\env.ts src\utils\envDynamic.ts src\utils\envUtils.ts src\utils\doctorDiagnostic.ts src\utils\dxt\helpers.ts src\utils\dxt\zip.ts src\utils\earlyInput.ts src\utils\editor.ts src\utils\diff.ts src\utils\directMemberMessage.ts src\utils\displayTags.ts src\utils\doctorContextWarnings.ts src\utils\deepLink\terminalLauncher.ts src\utils\deepLink\terminalPreference.ts src\utils\desktopDeepLink.ts src\utils\detectRepository.ts src\utils\diagLogs.ts src\utils\deepLink\banner.ts src\utils\deepLink\parseDeepLink.ts src\utils\deepLink\protocolHandler.ts src\utils\deepLink\registerProtocol.ts src\utils\crossProjectResume.ts src\utils\crypto.ts src\utils\cwd.ts src\utils\debug.ts src\utils\debugFilter.ts src\utils\cronJitterConfig.ts src\utils\cronScheduler.ts src\utils\cronTasks.ts src\utils\cronTasksLock.ts src\utils\conversationRecovery.ts src\utils\cron.ts src\utils\contextSuggestions.ts src\utils\controlMessageCompat.ts src\utils\configConstants.ts src\utils\contentArray.ts src\utils\context.ts src\utils\contextAnalysis.ts src\utils\computerUse\wrapper.tsx src\utils\concurrentSessions.ts src\utils\config.ts src\utils\computerUse\mcpServer.ts src\utils\computerUse\setup.ts src\utils\computerUse\swiftLoader.ts src\utils\computerUse\toolRendering.tsx src\utils\computerUse\executor.ts src\utils\computerUse\gates.ts src\utils\computerUse\hostAdapter.ts src\utils\computerUse\inputLoader.ts src\utils\computerUse\common.ts src\utils\computerUse\computerUseLock.ts src\utils\computerUse\drainRunLoop.ts src\utils\computerUse\escHotkey.ts src\utils\commitAttribution.ts src\utils\completionCache.ts src\utils\computerUse\appNames.ts src\utils\computerUse\cleanup.ts src\utils\collapseReadSearch.ts src\utils\collapseTeammateShutdowns.ts src\utils\combinedAbortSignal.ts src\utils\commandLifecycle.ts src\utils\codeIndexing.ts src\utils\collapseBackgroundBashNotifications.ts src\utils\collapseHookSummaries.ts src\utils\cliArgs.ts src\utils\cliHighlight.ts src\utils\claudemd.ts src\utils\cleanup.ts src\utils\cleanupRegistry.ts src\utils\claudeInChrome\setupPortable.ts src\utils\claudeInChrome\toolRendering.tsx src\utils\claudeInChrome\setup.ts src\utils\claudeInChrome\common.ts src\utils\claudeInChrome\mcpServer.ts src\utils\claudeInChrome\prompt.ts src\utils\classifierApprovalsHook.ts src\utils\claudeCodeHints.ts src\utils\claudeDesktop.ts src\utils\claudeInChrome\chromeNativeHost.ts src\utils\caCertsConfig.ts src\utils\cachePaths.ts src\utils\classifierApprovals.ts src\utils\binaryCheck.ts src\utils\browser.ts src\utils\bufferedWriter.ts src\utils\bundledMode.ts src\utils\caCerts.ts src\utils\bash\treeSitterAnalysis.ts src\utils\betas.ts src\utils\billing.ts src\utils\bash\specs\sleep.ts src\utils\bash\specs\srun.ts src\utils\bash\specs\time.ts src\utils\bash\specs\timeout.ts src\utils\bash\specs\alias.ts src\utils\bash\specs\index.ts src\utils\bash\specs\nohup.ts src\utils\bash\specs\pyright.ts src\utils\bash\registry.ts src\utils\bash\shellCompletion.ts src\utils\bash\shellPrefix.ts src\utils\bash\shellQuote.ts src\utils\bash\shellQuoting.ts src\utils\bash\heredoc.ts src\utils\bash\parser.ts src\utils\bash\prefix.ts src\utils\bash\commands.ts src\utils\bash\bashParser.ts src\utils\bash\bashPipeCommand.ts src\utils\bash\ast.ts src\utils\bash\ShellSnapshot.ts src\utils\background\remote\remoteSession.ts src\utils\backgroundHousekeeping.ts src\utils\bash\ParsedCommand.ts src\utils\awsAuthStatusManager.ts src\utils\background\remote\preconditions.ts src\utils\aws.ts src\utils\autoModeDenials.ts src\utils\autoRunIssue.tsx src\utils\autoUpdater.ts src\utils\auth.ts src\utils\authFileDescriptor.ts src\utils\authPortable.ts src\utils\asciicast.ts src\utils\attachments.ts src\utils\attribution.ts src\utils\api.ts src\utils\apiPreconnect.ts src\utils\appleTerminalBackup.ts src\utils\argumentSubstitution.ts src\utils\array.ts src\utils\ansiToPng.ts src\utils\ansiToSvg.ts src\utils\agenticSessionSearch.ts src\utils\agentId.ts src\utils\agentSwarmsEnabled.ts src\utils\analyzeContext.ts src\utils\abortController.ts src\utils\activityManager.ts src\utils\advisor.ts src\utils\agentContext.ts src\utils\Cursor.ts src\utils\QueryGuard.ts src\utils\Shell.ts src\utils\ShellCommand.ts src\utils\CircularBuffer.ts
Tool Call: grep -l | head -0 "." D:/code/play/stock_ai_rust/claude-code/src/services Status: Completed
Found 130 files src\services\vcr.ts src\services\voice.ts src\services\voiceKeyterms.ts src\services\voiceStreamSTT.ts src\services\tools\toolHooks.ts src\services\tools\toolOrchestration.ts src\services\tools\StreamingToolExecutor.ts src\services\tools\toolExecution.ts src\services\toolUseSummary\toolUseSummaryGenerator.ts src\services\tips\tipHistory.ts src\services\tips\tipRegistry.ts src\services\tips\tipScheduler.ts src\services\tokenEstimation.ts src\services\teamMemorySync\index.ts src\services\teamMemorySync\secretScanner.ts src\services\teamMemorySync\teamMemSecretGuard.ts src\services\teamMemorySync\types.ts src\services\teamMemorySync\watcher.ts src\services\remoteManagedSettings\syncCache.ts src\services\remoteManagedSettings\syncCacheState.ts src\services\remoteManagedSettings\types.ts src\services\settingsSync\index.ts src\services\settingsSync\types.ts src\services\rateLimitMocking.ts src\services\remoteManagedSettings\index.ts src\services\remoteManagedSettings\securityCheck.tsx src\services\plugins\pluginOperations.ts src\services\policyLimits\index.ts src\services\policyLimits\types.ts src\services\preventSleep.ts src\services\rateLimitMessages.ts src\services\oauth\index.ts src\services\plugins\pluginCliCommands.ts src\services\plugins\PluginInstallationManager.ts src\services\oauth\auth-code-listener.ts src\services\oauth\client.ts src\services\oauth\crypto.ts src\services\oauth\getOauthProfile.ts src\services\mcp\xaaIdpLogin.ts src\services\mcpServerApproval.tsx src\services\mockRateLimits.ts src\services\notifier.ts src\services\mcp\useManageMCPConnections.ts src\services\mcp\utils.ts src\services\mcp\vscodeSdkMcp.ts src\services\mcp\xaa.ts src\services\mcp\officialRegistry.ts src\services\mcp\types.ts src\services\mcp\normalization.ts src\services\mcp\oauthPort.ts src\services\mcp\mcpStringUtils.ts src\services\mcp\client.ts src\services\mcp\config.ts src\services\mcp\elicitationHandler.ts src\services\mcp\envExpansion.ts src\services\mcp\headersHelper.ts src\services\mcp\channelNotification.ts src\services\mcp\channelPermissions.ts src\services\mcp\claudeai.ts src\services\mcp\auth.ts src\services\mcp\channelAllowlist.ts src\services\lsp\passiveFeedback.ts src\services\mcp\InProcessTransport.ts src\services\mcp\MCPConnectionManager.tsx src\services\mcp\SdkControlTransport.ts src\services\lsp\config.ts src\services\lsp\LSPServerManager.ts src\services\lsp\manager.ts src\services\lsp\LSPClient.ts src\services\lsp\LSPDiagnosticRegistry.ts src\services\lsp\LSPServerInstance.ts src\services\extractMemories\extractMemories.ts src\services\extractMemories\prompts.ts src\services\internalLogging.ts src\services\compact\sessionMemoryCompact.ts src\services\compact\timeBasedMCConfig.ts src\services\diagnosticTracking.ts src\services\compact\microCompact.ts src\services\compact\postCompactCleanup.ts src\services\compact\prompt.ts src\services\compact\compactWarningHook.ts src\services\compact\compactWarningState.ts src\services\compact\grouping.ts src\services\compact\compact.ts src\services\compact\autoCompact.ts src\services\compact\apiMicrocompact.ts src\services\claudeAiLimits.ts src\services\claudeAiLimitsHook.ts src\services\autoDream\consolidationPrompt.ts src\services\awaySummary.ts src\services\autoDream\autoDream.ts src\services\autoDream\config.ts src\services\autoDream\consolidationLock.ts src\services\api\withRetry.ts src\services\api\usage.ts src\services\api\sessionIngress.ts src\services\api\ultrareviewQuota.ts src\services\api\referral.ts src\services\api\overageCreditGrant.ts src\services\api\promptCacheBreakDetection.ts src\services\api\logging.ts src\services\api\metricsOptOut.ts src\services\api\firstTokenDate.ts src\services\api\grove.ts src\services\api\filesApi.ts src\services\api\errors.ts src\services\api\emptyUsage.ts src\services\api\errorUtils.ts src\services\api\client.ts src\services\api\dumpPrompts.ts src\services\api\claude.ts src\services\api\bootstrap.ts src\services\api\adminRequests.ts src\services\analytics\metadata.ts src\services\analytics\sink.ts src\services\analytics\sinkKillswitch.ts src\services\analytics\index.ts src\services\analytics\firstPartyEventLoggingExporter.ts src\services\analytics\growthbook.ts src\services\analytics\datadog.ts src\services\analytics\firstPartyEventLogger.ts src\services\analytics\config.ts src\services\SessionMemory\sessionMemoryUtils.ts src\services\SessionMemory\sessionMemory.ts src\services\PromptSuggestion\speculation.ts src\services\SessionMemory\prompts.ts src\services\AgentSummary\agentSummary.ts src\services\MagicDocs\magicDocs.ts src\services\MagicDocs\prompts.ts src\services\PromptSuggestion\promptSuggestion.ts
Tool Call: Read src\types\message.ts (1 - 60) Status: Failed
File does not exist. Note: your current working directory is D:\code\play\stock_ai_rust\claude-code.Tool Call: Read src\main.tsx (500 - 599) Status: Completed
500→ * This ensures settings are filtered from the start of initialization
501→ */
502→function eagerLoadSettings(): void {
503→ profileCheckpoint('eagerLoadSettings_start');
504→ // Parse --settings flag early to ensure settings are loaded before init()
505→ const settingsFile = eagerParseCliFlag('--settings');
506→ if (settingsFile) {
507→ loadSettingsFromFlag(settingsFile);
508→ }
509→
510→ // Parse --setting-sources flag early to control which sources are loaded
511→ const settingSourcesArg = eagerParseCliFlag('--setting-sources');
512→ if (settingSourcesArg !== undefined) {
513→ loadSettingSourcesFromFlag(settingSourcesArg);
514→ }
515→ profileCheckpoint('eagerLoadSettings_end');
516→}
517→function initializeEntrypoint(isNonInteractive: boolean): void {
518→ // Skip if already set (e.g., by SDK or other entrypoints)
519→ if (process.env.CLAUDE_CODE_ENTRYPOINT) {
520→ return;
521→ }
522→ const cliArgs = process.argv.slice(2);
523→
524→ // Check for MCP serve command (handle flags before mcp serve, e.g., --debug mcp serve)
525→ const mcpIndex = cliArgs.indexOf('mcp');
526→ if (mcpIndex !== -1 && cliArgs[mcpIndex + 1] === 'serve') {
527→ process.env.CLAUDE_CODE_ENTRYPOINT = 'mcp';
528→ return;
529→ }
530→ if (isEnvTruthy(process.env.CLAUDE_CODE_ACTION)) {
531→ process.env.CLAUDE_CODE_ENTRYPOINT = 'claude-code-github-action';
532→ return;
533→ }
534→
535→ // Note: 'local-agent' entrypoint is set by the local agent mode launcher
536→ // via CLAUDE_CODE_ENTRYPOINT env var (handled by early return above)
537→
538→ // Set based on interactive status
539→ process.env.CLAUDE_CODE_ENTRYPOINT = isNonInteractive ? 'sdk-cli' : 'cli';
540→}
541→
542→// Set by early argv processing when `claude open <url>` is detected (interactive mode only)
543→type PendingConnect = {
544→ url: string | undefined;
545→ authToken: string | undefined;
546→ dangerouslySkipPermissions: boolean;
547→};
548→const _pendingConnect: PendingConnect | undefined = feature('DIRECT_CONNECT') ? {
549→ url: undefined,
550→ authToken: undefined,
551→ dangerouslySkipPermissions: false
552→} : undefined;
553→
554→// Set by early argv processing when `claude assistant [sessionId]` is detected
555→type PendingAssistantChat = {
556→ sessionId?: string;
557→ discover: boolean;
558→};
559→const _pendingAssistantChat: PendingAssistantChat | undefined = feature('KAIROS') ? {
560→ sessionId: undefined,
561→ discover: false
562→} : undefined;
563→
564→// `claude ssh <host> [dir]` — parsed from argv early (same pattern as
565→// DIRECT_CONNECT above) so the main command path can pick it up and hand
566→// the REPL an SSH-backed session instead of a local one.
567→type PendingSSH = {
568→ host: string | undefined;
569→ cwd: string | undefined;
570→ permissionMode: string | undefined;
571→ dangerouslySkipPermissions: boolean;
572→ /** --local: spawn the child CLI directly, skip ssh/probe/deploy. e2e test mode. */
573→ local: boolean;
574→ /** Extra CLI args to forward to the remote CLI on initial spawn (--resume, -c). */
575→ extraCliArgs: string[];
576→};
577→const _pendingSSH: PendingSSH | undefined = feature('SSH_REMOTE') ? {
578→ host: undefined,
579→ cwd: undefined,
580→ permissionMode: undefined,
581→ dangerouslySkipPermissions: false,
582→ local: false,
583→ extraCliArgs: []
584→} : undefined;
585→export async function main() {
586→ profileCheckpoint('main_function_start');
587→
588→ // SECURITY: Prevent Windows from executing commands from current directory
589→ // This must be set before ANY command execution to prevent PATH hijacking attacks
590→ // See: https://docs.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-searchpathw
591→ process.env.NoDefaultCurrentDirectoryInExePath = '1';
592→
593→ // Initialize warning handler early to catch warnings
594→ initializeWarningHandler();
595→ process.on('exit', () => {
596→ resetCursor();
597→ });
598→ process.on('SIGINT', () => {
599→ // In print mode, print.ts registers its own SIGINT handler that abortsTool Call: grep -l | head -0 "." D:/code/play/stock_ai_rust/claude-code/src/commands Status: Completed
Found 207 files src\commands\voice\index.ts src\commands\voice\voice.ts src\commands\usage\usage.tsx src\commands\version.ts src\commands\vim\index.ts src\commands\vim\vim.ts src\commands\ultraplan.tsx src\commands\upgrade\index.ts src\commands\upgrade\upgrade.tsx src\commands\usage\index.ts src\commands\thinkback\thinkback.tsx src\commands\thinkback\index.ts src\commands\terminalSetup\terminalSetup.tsx src\commands\theme\index.ts src\commands\theme\theme.tsx src\commands\thinkback-play\index.ts src\commands\thinkback-play\thinkback-play.ts src\commands\tasks\tasks.tsx src\commands\teleport\index.js src\commands\terminalSetup\index.ts src\commands\tag\index.ts src\commands\tag\tag.tsx src\commands\tasks\index.ts src\commands\statusline.tsx src\commands\stickers\index.ts src\commands\stickers\stickers.ts src\commands\summary\index.js src\commands\status\index.ts src\commands\status\status.tsx src\commands\share\index.js src\commands\skills\index.ts src\commands\skills\skills.tsx src\commands\stats\index.ts src\commands\stats\stats.tsx src\commands\sandbox-toggle\index.ts src\commands\sandbox-toggle\sandbox-toggle.tsx src\commands\security-review.ts src\commands\session\index.ts src\commands\session\session.tsx src\commands\review\ultrareviewCommand.tsx src\commands\review\ultrareviewEnabled.ts src\commands\rewind\index.ts src\commands\rewind\rewind.ts src\commands\resume\resume.tsx src\commands\review.ts src\commands\review\reviewRemote.ts src\commands\review\UltrareviewOverageDialog.tsx src\commands\remote-setup\remote-setup.tsx src\commands\rename\generateSessionName.ts src\commands\rename\index.ts src\commands\rename\rename.ts src\commands\reset-limits\index.js src\commands\resume\index.ts src\commands\release-notes\index.ts src\commands\release-notes\release-notes.ts src\commands\reload-plugins\index.ts src\commands\reload-plugins\reload-plugins.ts src\commands\remote-env\index.ts src\commands\remote-env\remote-env.tsx src\commands\remote-setup\api.ts src\commands\remote-setup\index.ts src\commands\privacy-settings\index.ts src\commands\privacy-settings\privacy-settings.tsx src\commands\rate-limit-options\index.ts src\commands\rate-limit-options\rate-limit-options.tsx src\commands\plugin\pluginDetailsHelpers.tsx src\commands\plugin\usePagination.ts src\commands\pr_comments\index.ts src\commands\plugin\index.tsx src\commands\plugin\parseArgs.ts src\commands\plugin\plugin.tsx src\commands\plugin\UnifiedInstalledCell.tsx src\commands\plugin\ValidatePlugin.tsx src\commands\plugin\PluginSettings.tsx src\commands\plugin\PluginTrustWarning.tsx src\commands\plugin\PluginErrors.tsx src\commands\plugin\PluginOptionsDialog.tsx src\commands\plugin\PluginOptionsFlow.tsx src\commands\plugin\ManagePlugins.tsx src\commands\plugin\ManageMarketplaces.tsx src\commands\plugin\BrowseMarketplace.tsx src\commands\plugin\DiscoverPlugins.tsx src\commands\plugin\AddMarketplace.tsx src\commands\output-style\output-style.tsx src\commands\passes\index.ts src\commands\passes\passes.tsx src\commands\perf-issue\index.js src\commands\permissions\index.ts src\commands\permissions\permissions.tsx src\commands\plan\index.ts src\commands\plan\plan.tsx src\commands\model\model.tsx src\commands\oauth-refresh\index.js src\commands\onboarding\index.js src\commands\output-style\index.ts src\commands\mobile\index.ts src\commands\mobile\mobile.tsx src\commands\mock-limits\index.js src\commands\model\index.ts src\commands\mcp\addCommand.ts src\commands\mcp\index.ts src\commands\mcp\mcp.tsx src\commands\mcp\xaaIdpCommand.ts src\commands\memory\index.ts src\commands\memory\memory.tsx src\commands\login\index.ts src\commands\login\login.tsx src\commands\logout\index.ts src\commands\logout\logout.tsx src\commands\install.tsx src\commands\issue\index.js src\commands\keybindings\index.ts src\commands\keybindings\keybindings.ts src\commands\install-github-app\index.ts src\commands\install-github-app\install-github-app.tsx src\commands\install-github-app\setupGitHubActions.ts src\commands\install-slack-app\index.ts src\commands\install-slack-app\install-slack-app.ts src\commands\install-github-app\ExistingWorkflowStep.tsx src\commands\install-github-app\InstallAppStep.tsx src\commands\install-github-app\OAuthFlowStep.tsx src\commands\install-github-app\SuccessStep.tsx src\commands\install-github-app\WarningsStep.tsx src\commands\install-github-app\ChooseRepoStep.tsx src\commands\install-github-app\CreatingStep.tsx src\commands\install-github-app\ErrorStep.tsx src\commands\insights.ts src\commands\install-github-app\ApiKeyStep.tsx src\commands\install-github-app\CheckExistingSecretStep.tsx src\commands\install-github-app\CheckGitHubStep.tsx src\commands\ide\ide.tsx src\commands\ide\index.ts src\commands\init-verifiers.ts src\commands\init.ts src\commands\help\help.tsx src\commands\help\index.ts src\commands\hooks\hooks.tsx src\commands\hooks\index.ts src\commands\files\files.ts src\commands\files\index.ts src\commands\good-claude\index.js src\commands\heapdump\heapdump.ts src\commands\heapdump\index.ts src\commands\extra-usage\extra-usage.tsx src\commands\extra-usage\index.ts src\commands\fast\fast.tsx src\commands\fast\index.ts src\commands\feedback\feedback.tsx src\commands\feedback\index.ts src\commands\exit\exit.tsx src\commands\exit\index.ts src\commands\export\export.tsx src\commands\export\index.ts src\commands\extra-usage\extra-usage-core.ts src\commands\extra-usage\extra-usage-noninteractive.ts src\commands\doctor\doctor.tsx src\commands\doctor\index.ts src\commands\effort\effort.tsx src\commands\effort\index.ts src\commands\env\index.js src\commands\createMovedToPluginCommand.ts src\commands\ctx_viz\index.js src\commands\debug-tool-call\index.js src\commands\desktop\desktop.tsx src\commands\desktop\index.ts src\commands\diff\diff.tsx src\commands\diff\index.ts src\commands\context\index.ts src\commands\copy\copy.tsx src\commands\copy\index.ts src\commands\cost\cost.ts src\commands\cost\index.ts src\commands\commit-push-pr.ts src\commands\commit.ts src\commands\compact\compact.ts src\commands\compact\index.ts src\commands\config\config.tsx src\commands\config\index.ts src\commands\context\context-noninteractive.ts src\commands\context\context.tsx src\commands\clear\caches.ts src\commands\clear\clear.ts src\commands\clear\conversation.ts src\commands\clear\index.ts src\commands\color\color.ts src\commands\color\index.ts src\commands\btw\index.ts src\commands\bughunter\index.js src\commands\chrome\chrome.tsx src\commands\chrome\index.ts src\commands\bridge\bridge.tsx src\commands\bridge\index.ts src\commands\brief.ts src\commands\btw\btw.tsx src\commands\branch\branch.ts src\commands\branch\index.ts src\commands\break-cache\index.js src\commands\bridge-kick.ts src\commands\advisor.ts src\commands\agents\agents.tsx src\commands\agents\index.ts src\commands\ant-trace\index.js src\commands\autofix-pr\index.js src\commands\backfill-sessions\index.js src\commands\add-dir\add-dir.tsx src\commands\add-dir\index.ts src\commands\add-dir\validation.ts
Tool Call: grep -l | head -0 "." D:/code/play/stock_ai_rust/claude-code/src/components Status: Completed
Found 389 files src\components\wizard\index.ts src\components\wizard\useWizard.ts src\components\wizard\WizardDialogLayout.tsx src\components\wizard\WizardNavigationFooter.tsx src\components\wizard\WizardProvider.tsx src\components\ui\OrderedList.tsx src\components\ui\OrderedListItem.tsx src\components\ui\TreeSelect.tsx src\components\teams\TeamsDialog.tsx src\components\tasks\renderToolActivity.tsx src\components\tasks\ShellDetailDialog.tsx src\components\tasks\ShellProgress.tsx src\components\tasks\taskStatusUtils.tsx src\components\teams\TeamStatus.tsx src\components\tasks\InProcessTeammateDetailDialog.tsx src\components\tasks\RemoteSessionDetailDialog.tsx src\components\tasks\RemoteSessionProgress.tsx src\components\tasks\BackgroundTasksDialog.tsx src\components\tasks\DreamDetailDialog.tsx src\components\tasks\BackgroundTask.tsx src\components\tasks\BackgroundTaskStatus.tsx src\components\skills\SkillsMenu.tsx src\components\tasks\AsyncAgentDetailDialog.tsx src\components\shell\ExpandShellOutputContext.tsx src\components\shell\OutputLine.tsx src\components\shell\ShellProgressMessage.tsx src\components\shell\ShellTimeDisplay.tsx src\components\sandbox\SandboxDependenciesTab.tsx src\components\sandbox\SandboxDoctorSection.tsx src\components\sandbox\SandboxOverridesTab.tsx src\components\sandbox\SandboxSettings.tsx src\components\permissions\utils.ts src\components\sandbox\SandboxConfigTab.tsx src\components\permissions\rules\RecentDenialsTab.tsx src\components\permissions\rules\RemoveWorkspaceDirectory.tsx src\components\permissions\rules\WorkspaceTab.tsx src\components\permissions\shellPermissionHelpers.tsx src\components\permissions\useShellPermissionFeedback.ts src\components\permissions\rules\PermissionRuleList.tsx src\components\permissions\rules\AddPermissionRules.tsx src\components\permissions\rules\AddWorkspaceDirectory.tsx src\components\permissions\rules\PermissionRuleDescription.tsx src\components\permissions\rules\PermissionRuleInput.tsx src\components\permissions\hooks.ts src\components\permissions\WebFetchPermissionRequest\WebFetchPermissionRequest.tsx src\components\permissions\WorkerBadge.tsx src\components\permissions\WorkerPendingPermission.tsx src\components\permissions\SedEditPermissionRequest\SedEditPermissionRequest.tsx src\components\permissions\SkillPermissionRequest\SkillPermissionRequest.tsx src\components\permissions\PowerShellPermissionRequest\PowerShellPermissionRequest.tsx src\components\permissions\PowerShellPermissionRequest\powershellToolUseOptions.tsx src\components\permissions\SandboxPermissionRequest.tsx src\components\permissions\PermissionRuleExplanation.tsx src\components\permissions\PermissionExplanation.tsx src\components\permissions\PermissionPrompt.tsx src\components\permissions\PermissionRequest.tsx src\components\permissions\PermissionRequestTitle.tsx src\components\permissions\PermissionDecisionDebugInfo.tsx src\components\permissions\PermissionDialog.tsx src\components\permissions\FilesystemPermissionRequest\FilesystemPermissionRequest.tsx src\components\permissions\NotebookEditPermissionRequest\NotebookEditPermissionRequest.tsx src\components\permissions\NotebookEditPermissionRequest\NotebookEditToolDiff.tsx src\components\permissions\FilePermissionDialog\useFilePermissionDialog.ts src\components\permissions\FilePermissionDialog\usePermissionHandler.ts src\components\permissions\FileWritePermissionRequest\FileWritePermissionRequest.tsx src\components\permissions\FileWritePermissionRequest\FileWriteToolDiff.tsx src\components\permissions\FilePermissionDialog\FilePermissionDialog.tsx src\components\permissions\FilePermissionDialog\ideDiffConfig.ts src\components\permissions\FilePermissionDialog\permissionOptions.tsx src\components\permissions\ExitPlanModePermissionRequest\ExitPlanModePermissionRequest.tsx src\components\permissions\FallbackPermissionRequest.tsx src\components\permissions\FileEditPermissionRequest\FileEditPermissionRequest.tsx src\components\permissions\EnterPlanModePermissionRequest\EnterPlanModePermissionRequest.tsx src\components\permissions\BashPermissionRequest\BashPermissionRequest.tsx src\components\permissions\BashPermissionRequest\bashToolUseOptions.tsx src\components\permissions\ComputerUseApproval\ComputerUseApproval.tsx src\components\permissions\AskUserQuestionPermissionRequest\SubmitQuestionsView.tsx src\components\permissions\AskUserQuestionPermissionRequest\use-multiple-choice-state.ts src\components\permissions\AskUserQuestionPermissionRequest\PreviewQuestionView.tsx src\components\permissions\AskUserQuestionPermissionRequest\QuestionNavigationBar.tsx src\components\permissions\AskUserQuestionPermissionRequest\QuestionView.tsx src\components\permissions\AskUserQuestionPermissionRequest\AskUserQuestionPermissionRequest.tsx src\components\permissions\AskUserQuestionPermissionRequest\PreviewBox.tsx src\components\messages\nullRenderingAttachments.ts src\components\messages\teamMemCollapsed.tsx src\components\messages\teamMemSaved.ts src\components\messages\UserToolResultMessage\UserToolRejectMessage.tsx src\components\messages\UserToolResultMessage\UserToolResultMessage.tsx src\components\messages\UserToolResultMessage\UserToolSuccessMessage.tsx src\components\messages\UserToolResultMessage\utils.tsx src\components\messages\UserToolResultMessage\RejectedPlanMessage.tsx src\components\messages\UserToolResultMessage\RejectedToolUseMessage.tsx src\components\messages\UserToolResultMessage\UserToolCanceledMessage.tsx src\components\messages\UserToolResultMessage\UserToolErrorMessage.tsx src\components\messages\UserResourceUpdateMessage.tsx src\components\messages\UserTeammateMessage.tsx src\components\messages\UserTextMessage.tsx src\components\messages\UserPlanMessage.tsx src\components\messages\UserPromptMessage.tsx src\components\messages\UserCommandMessage.tsx src\components\messages\UserImageMessage.tsx src\components\messages\UserLocalCommandOutputMessage.tsx src\components\messages\UserMemoryInputMessage.tsx src\components\messages\UserAgentNotificationMessage.tsx src\components\messages\UserBashInputMessage.tsx src\components\messages\UserBashOutputMessage.tsx src\components\messages\UserChannelMessage.tsx src\components\messages\SystemAPIErrorMessage.tsx src\components\messages\SystemTextMessage.tsx src\components\messages\TaskAssignmentMessage.tsx src\components\messages\PlanApprovalMessage.tsx src\components\messages\RateLimitMessage.tsx src\components\messages\ShutdownMessage.tsx src\components\messages\CompactBoundaryMessage.tsx src\components\messages\GroupedToolUseContent.tsx src\components\messages\HighlightedThinkingText.tsx src\components\messages\HookProgressMessage.tsx src\components\messages\AttachmentMessage.tsx src\components\messages\CollapsedReadSearchContent.tsx src\components\messages\AssistantTextMessage.tsx src\components\messages\AssistantThinkingMessage.tsx src\components\messages\AssistantToolUseMessage.tsx src\components\messageActions.tsx src\components\messages\AdvisorMessage.tsx src\components\messages\AssistantRedactedThinkingMessage.tsx src\components\memory\MemoryFileSelector.tsx src\components\memory\MemoryUpdateNotification.tsx src\components\mcp\index.ts src\components\mcp\McpParsingWarnings.tsx src\components\mcp\MCPToolDetailView.tsx src\components\mcp\MCPToolListView.tsx src\components\mcp\utils\reconnectHelpers.tsx src\components\mcp\MCPSettings.tsx src\components\mcp\MCPStdioServerMenu.tsx src\components\mcp\MCPListPanel.tsx src\components\mcp\MCPReconnect.tsx src\components\mcp\MCPRemoteServerMenu.tsx src\components\mcp\ElicitationDialog.tsx src\components\mcp\MCPAgentServerMenu.tsx src\components\hooks\ViewHookMode.tsx src\components\mcp\CapabilitiesSection.tsx src\components\hooks\SelectHookMode.tsx src\components\hooks\SelectMatcherMode.tsx src\components\hooks\HooksConfigMenu.tsx src\components\hooks\PromptDialog.tsx src\components\hooks\SelectEventMode.tsx src\components\diff\DiffFileList.tsx src\components\grove\Grove.tsx src\components\diff\DiffDetailView.tsx src\components\diff\DiffDialog.tsx src\components\design-system\color.ts src\components\design-system\ThemedBox.tsx src\components\design-system\ThemedText.tsx src\components\design-system\ThemeProvider.tsx src\components\design-system\Ratchet.tsx src\components\design-system\StatusIcon.tsx src\components\design-system\Tabs.tsx src\components\design-system\ListItem.tsx src\components\design-system\LoadingState.tsx src\components\design-system\Pane.tsx src\components\design-system\ProgressBar.tsx src\components\design-system\Divider.tsx src\components\design-system\FuzzyPicker.tsx src\components\design-system\KeyboardShortcutHint.tsx src\components\agents\utils.ts src\components\agents\validateAgent.ts src\components\design-system\Byline.tsx src\components\design-system\Dialog.tsx src\components\agents\new-agent-creation\wizard-steps\ModelStep.tsx src\components\agents\new-agent-creation\wizard-steps\PromptStep.tsx src\components\agents\new-agent-creation\wizard-steps\ToolsStep.tsx src\components\agents\new-agent-creation\wizard-steps\TypeStep.tsx src\components\agents\types.ts src\components\agents\new-agent-creation\wizard-steps\GenerateStep.tsx src\components\agents\new-agent-creation\wizard-steps\LocationStep.tsx src\components\agents\new-agent-creation\wizard-steps\MemoryStep.tsx src\components\agents\new-agent-creation\wizard-steps\MethodStep.tsx src\components\agents\new-agent-creation\wizard-steps\ConfirmStep.tsx src\components\agents\new-agent-creation\wizard-steps\ConfirmStepWrapper.tsx src\components\agents\new-agent-creation\wizard-steps\DescriptionStep.tsx src\components\agents\agentFileUtils.ts src\components\agents\generateAgent.ts src\components\agents\new-agent-creation\CreateAgentWizard.tsx src\components\agents\new-agent-creation\wizard-steps\ColorStep.tsx src\components\agents\ColorPicker.tsx src\components\agents\ModelSelector.tsx src\components\agents\ToolSelector.tsx src\components\agents\AgentsList.tsx src\components\agents\AgentsMenu.tsx src\components\agents\AgentDetail.tsx src\components\agents\AgentEditor.tsx src\components\agents\AgentNavigationFooter.tsx src\components\WorktreeExitDialog.tsx src\components\VimTextInput.tsx src\components\VirtualMessageList.tsx src\components\WorkflowMultiselectDialog.tsx src\components\TrustDialog\TrustDialog.tsx src\components\TrustDialog\utils.ts src\components\ValidationErrorsList.tsx src\components\ThinkingToggle.tsx src\components\TokenWarning.tsx src\components\ToolUseLoader.tsx src\components\TeleportResumeWrapper.tsx src\components\TeleportStash.tsx src\components\TextInput.tsx src\components\ThemePicker.tsx src\components\TeleportError.tsx src\components\TeleportProgress.tsx src\components\TeleportRepoMismatchDialog.tsx src\components\TagTabs.tsx src\components\TaskListV2.tsx src\components\TeammateViewHeader.tsx src\components\StructuredDiff\colorDiff.ts src\components\StructuredDiff\Fallback.tsx src\components\StructuredDiffList.tsx src\components\StatusNotices.tsx src\components\StructuredDiff.tsx src\components\Stats.tsx src\components\StatusLine.tsx src\components\Spinner\teammateSelectHint.ts src\components\Spinner\useShimmerAnimation.ts src\components\Spinner\useStalledAnimation.ts src\components\Spinner\utils.ts src\components\Spinner\index.ts src\components\Spinner\SpinnerAnimationRow.tsx src\components\Spinner\SpinnerGlyph.tsx src\components\Spinner\TeammateSpinnerLine.tsx src\components\Spinner\TeammateSpinnerTree.tsx src\components\Spinner\FlashingChar.tsx src\components\Spinner\GlimmerMessage.tsx src\components\Spinner\ShimmerChar.tsx src\components\SkillImprovementSurvey.tsx src\components\Spinner.tsx src\components\Settings\Usage.tsx src\components\ShowInIDEPrompt.tsx src\components\Settings\Settings.tsx src\components\Settings\Status.tsx src\components\Settings\Config.tsx src\components\SessionBackgroundHint.tsx src\components\SessionPreview.tsx src\components\ScrollKeybindingHandler.tsx src\components\SearchBox.tsx src\components\SentryErrorBoundary.ts src\components\ResumeTask.tsx src\components\SandboxViolationExpandedView.tsx src\components\QuickOpenDialog.tsx src\components\RemoteCallout.tsx src\components\RemoteEnvironmentDialog.tsx src\components\PromptInput\useMaybeTruncateInput.ts src\components\PromptInput\usePromptInputPlaceholder.ts src\components\PromptInput\useShowFastIconHint.ts src\components\PromptInput\useSwarmBanner.ts src\components\PromptInput\utils.ts src\components\PromptInput\inputModes.ts src\components\PromptInput\inputPaste.ts src\components\PromptInput\ShimmeredInput.tsx src\components\PromptInput\VoiceIndicator.tsx src\components\PromptInput\PromptInputModeIndicator.tsx src\components\PromptInput\PromptInputQueuedCommands.tsx src\components\PromptInput\PromptInputStashNotice.tsx src\components\PromptInput\SandboxPromptFooterHint.tsx src\components\PromptInput\PromptInputFooterSuggestions.tsx src\components\PromptInput\PromptInputHelpMenu.tsx src\components\PromptInput\PromptInputFooter.tsx src\components\PromptInput\PromptInputFooterLeftSide.tsx src\components\PromptInput\PromptInput.tsx src\components\PromptInput\Notifications.tsx src\components\PressEnterToContinue.tsx src\components\PromptInput\HistorySearchInput.tsx src\components\PromptInput\IssueFlagBanner.tsx src\components\PackageManagerAutoUpdater.tsx src\components\Passes\Passes.tsx src\components\PrBadge.tsx src\components\OffscreenFreeze.tsx src\components\Onboarding.tsx src\components\OutputStylePicker.tsx src\components\NotebookEditToolUseRejectedMessage.tsx src\components\ModelPicker.tsx src\components\NativeAutoUpdater.tsx src\components\Messages.tsx src\components\MessageSelector.tsx src\components\MessageTimestamp.tsx src\components\Message.tsx src\components\MessageModel.tsx src\components\MessageResponse.tsx src\components\MessageRow.tsx src\components\MarkdownTable.tsx src\components\MemoryUsageIndicator.tsx src\components\ManagedSettingsSecurityDialog\ManagedSettingsSecurityDialog.tsx src\components\ManagedSettingsSecurityDialog\utils.ts src\components\Markdown.tsx src\components\MCPServerDesktopImportDialog.tsx src\components\MCPServerDialogCopy.tsx src\components\MCPServerMultiselectDialog.tsx src\components\LogoV2\feedConfigs.tsx src\components\LspRecommendation\LspRecommendationMenu.tsx src\components\MCPServerApprovalDialog.tsx src\components\LogoV2\VoiceModeNotice.tsx src\components\LogoV2\WelcomeV2.tsx src\components\LogoV2\FeedColumn.tsx src\components\LogoV2\GuestPassesUpsell.tsx src\components\LogoV2\LogoV2.tsx src\components\LogoV2\Opus1mMergeNotice.tsx src\components\LogoV2\OverageCreditUpsell.tsx src\components\LogoV2\ChannelsNotice.tsx src\components\LogoV2\Clawd.tsx src\components\LogoV2\CondensedLogo.tsx src\components\LogoV2\EmergencyTip.tsx src\components\LogoV2\Feed.tsx src\components\LogoV2\AnimatedAsterisk.tsx src\components\LogoV2\AnimatedClawd.tsx src\components\LogSelector.tsx src\components\LanguagePicker.tsx src\components\InvalidConfigDialog.tsx src\components\InvalidSettingsDialog.tsx src\components\KeybindingWarnings.tsx src\components\IdeStatusIndicator.tsx src\components\IdleReturnDialog.tsx src\components\InterruptedByUser.tsx src\components\HighlightedCode\Fallback.tsx src\components\HistorySearchDialog.tsx src\components\IdeAutoConnectDialog.tsx src\components\IdeOnboardingDialog.tsx src\components\HelpV2\General.tsx src\components\HelpV2\HelpV2.tsx src\components\HighlightedCode.tsx src\components\GlobalSearchDialog.tsx src\components\HelpV2\Commands.tsx src\components\FileEditToolUseRejectedMessage.tsx src\components\FilePathLink.tsx src\components\FullscreenLayout.tsx src\components\FeedbackSurvey\useSurveyState.tsx src\components\FileEditToolDiff.tsx src\components\FileEditToolUpdatedMessage.tsx src\components\FeedbackSurvey\submitTranscriptShare.ts src\components\FeedbackSurvey\TranscriptSharePrompt.tsx src\components\FeedbackSurvey\useDebouncedDigitInput.ts src\components\FeedbackSurvey\useFeedbackSurvey.tsx src\components\FeedbackSurvey\useMemorySurvey.tsx src\components\FeedbackSurvey\usePostCompactSurvey.tsx src\components\Feedback.tsx src\components\FeedbackSurvey\FeedbackSurvey.tsx src\components\FeedbackSurvey\FeedbackSurveyView.tsx src\components\FallbackToolUseErrorMessage.tsx src\components\FallbackToolUseRejectedMessage.tsx src\components\FastIcon.tsx src\components\EffortCallout.tsx src\components\EffortIndicator.ts src\components\ExitFlow.tsx src\components\ExportDialog.tsx src\components\DevBar.tsx src\components\DevChannelsDialog.tsx src\components\DiagnosticsDisplay.tsx src\components\CustomSelect\use-select-navigation.ts src\components\CustomSelect\use-select-state.ts src\components\DesktopHandoff.tsx src\components\DesktopUpsell\DesktopUpsellStartup.tsx src\components\CustomSelect\select.tsx src\components\CustomSelect\use-multi-select-state.ts src\components\CustomSelect\use-select-input.ts src\components\CustomSelect\select-input-option.tsx src\components\CustomSelect\select-option.tsx src\components\CustomSelect\index.ts src\components\CustomSelect\option-map.ts src\components\CustomSelect\SelectMulti.tsx src\components\CtrlOToExpand.tsx src\components\CoordinatorAgentStatus.tsx src\components\CostThresholdDialog.tsx src\components\ContextSuggestions.tsx src\components\ContextVisualization.tsx src\components\CompactSummary.tsx src\components\ConfigurableShortcutHint.tsx src\components\ConsoleOAuthFlow.tsx src\components\ClaudeCodeHint\PluginHintMenu.tsx src\components\ClaudeInChromeOnboarding.tsx src\components\ClaudeMdExternalIncludesDialog.tsx src\components\ClickableImageRef.tsx src\components\BridgeDialog.tsx src\components\BypassPermissionsModeDialog.tsx src\components\ChannelDowngradeDialog.tsx src\components\AutoUpdaterWrapper.tsx src\components\AwsAuthStatusBox.tsx src\components\BaseTextInput.tsx src\components\BashModeProgress.tsx src\components\ApproveApiKey.tsx src\components\AutoModeOptInDialog.tsx src\components\AutoUpdater.tsx src\components\AgentProgressLine.tsx src\components\App.tsx
Tool Call: Read src\main.tsx (600 - 719) Status: Completed
600→ // the in-flight query and calls gracefulShutdown; skip here to avoid
601→ // preempting it with a synchronous process.exit().
602→ if (process.argv.includes('-p') || process.argv.includes('--print')) {
603→ return;
604→ }
605→ process.exit(0);
606→ });
607→ profileCheckpoint('main_warning_handler_initialized');
608→
609→ // Check for cc:// or cc+unix:// URL in argv — rewrite so the main command
610→ // handles it, giving the full interactive TUI instead of a stripped-down subcommand.
611→ // For headless (-p), we rewrite to the internal `open` subcommand.
612→ if (feature('DIRECT_CONNECT')) {
613→ const rawCliArgs = process.argv.slice(2);
614→ const ccIdx = rawCliArgs.findIndex(a => a.startsWith('cc://') || a.startsWith('cc+unix://'));
615→ if (ccIdx !== -1 && _pendingConnect) {
616→ const ccUrl = rawCliArgs[ccIdx]!;
617→ const {
618→ parseConnectUrl
619→ } = await import('./server/parseConnectUrl.js');
620→ const parsed = parseConnectUrl(ccUrl);
621→ _pendingConnect.dangerouslySkipPermissions = rawCliArgs.includes('--dangerously-skip-permissions');
622→ if (rawCliArgs.includes('-p') || rawCliArgs.includes('--print')) {
623→ // Headless: rewrite to internal `open` subcommand
624→ const stripped = rawCliArgs.filter((_, i) => i !== ccIdx);
625→ const dspIdx = stripped.indexOf('--dangerously-skip-permissions');
626→ if (dspIdx !== -1) {
627→ stripped.splice(dspIdx, 1);
628→ }
629→ process.argv = [process.argv[0]!, process.argv[1]!, 'open', ccUrl, ...stripped];
630→ } else {
631→ // Interactive: strip cc:// URL and flags, run main command
632→ _pendingConnect.url = parsed.serverUrl;
633→ _pendingConnect.authToken = parsed.authToken;
634→ const stripped = rawCliArgs.filter((_, i) => i !== ccIdx);
635→ const dspIdx = stripped.indexOf('--dangerously-skip-permissions');
636→ if (dspIdx !== -1) {
637→ stripped.splice(dspIdx, 1);
638→ }
639→ process.argv = [process.argv[0]!, process.argv[1]!, ...stripped];
640→ }
641→ }
642→ }
643→
644→ // Handle deep link URIs early — this is invoked by the OS protocol handler
645→ // and should bail out before full init since it only needs to parse the URI
646→ // and open a terminal.
647→ if (feature('LODESTONE')) {
648→ const handleUriIdx = process.argv.indexOf('--handle-uri');
649→ if (handleUriIdx !== -1 && process.argv[handleUriIdx + 1]) {
650→ const {
651→ enableConfigs
652→ } = await import('./utils/config.js');
653→ enableConfigs();
654→ const uri = process.argv[handleUriIdx + 1]!;
655→ const {
656→ handleDeepLinkUri
657→ } = await import('./utils/deepLink/protocolHandler.js');
658→ const exitCode = await handleDeepLinkUri(uri);
659→ process.exit(exitCode);
660→ }
661→
662→ // macOS URL handler: when LaunchServices launches our .app bundle, the
663→ // URL arrives via Apple Event (not argv). LaunchServices overwrites
664→ // __CFBundleIdentifier to the launching bundle's ID, which is a precise
665→ // positive signal — cheaper than importing and guessing with heuristics.
666→ if (process.platform === 'darwin' && process.env.__CFBundleIdentifier === 'com.anthropic.claude-code-url-handler') {
667→ const {
668→ enableConfigs
669→ } = await import('./utils/config.js');
670→ enableConfigs();
671→ const {
672→ handleUrlSchemeLaunch
673→ } = await import('./utils/deepLink/protocolHandler.js');
674→ const urlSchemeResult = await handleUrlSchemeLaunch();
675→ process.exit(urlSchemeResult ?? 1);
676→ }
677→ }
678→
679→ // `claude assistant [sessionId]` — stash and strip so the main
680→ // command handles it, giving the full interactive TUI. Position-0 only
681→ // (matching the ssh pattern below) — indexOf would false-positive on
682→ // `claude -p "explain assistant"`. Root-flag-before-subcommand
683→ // (e.g. `--debug assistant`) falls through to the stub, which
684→ // prints usage.
685→ if (feature('KAIROS') && _pendingAssistantChat) {
686→ const rawArgs = process.argv.slice(2);
687→ if (rawArgs[0] === 'assistant') {
688→ const nextArg = rawArgs[1];
689→ if (nextArg && !nextArg.startsWith('-')) {
690→ _pendingAssistantChat.sessionId = nextArg;
691→ rawArgs.splice(0, 2); // drop 'assistant' and sessionId
692→ process.argv = [process.argv[0]!, process.argv[1]!, ...rawArgs];
693→ } else if (!nextArg) {
694→ _pendingAssistantChat.discover = true;
695→ rawArgs.splice(0, 1); // drop 'assistant'
696→ process.argv = [process.argv[0]!, process.argv[1]!, ...rawArgs];
697→ }
698→ // else: `claude assistant --help` → fall through to stub
699→ }
700→ }
701→
702→ // `claude ssh <host> [dir]` — strip from argv so the main command handler
703→ // runs (full interactive TUI), stash the host/dir for the REPL branch at
704→ // ~line 3720 to pick up. Headless (-p) mode not supported in v1: SSH
705→ // sessions need the local REPL to drive them (interrupt, permissions).
706→ if (feature('SSH_REMOTE') && _pendingSSH) {
707→ const rawCliArgs = process.argv.slice(2);
708→ // SSH-specific flags can appear before the host positional (e.g.
709→ // `ssh --permission-mode auto host /tmp` — standard POSIX flags-before-
710→ // positionals). Pull them all out BEFORE checking whether a host was
711→ // given, so `claude ssh --permission-mode auto host` and `claude ssh host
712→ // --permission-mode auto` are equivalent. The host check below only needs
713→ // to guard against `-h`/`--help` (which commander should handle).
714→ if (rawCliArgs[0] === 'ssh') {
715→ const localIdx = rawCliArgs.indexOf('--local');
716→ if (localIdx !== -1) {
717→ _pendingSSH.local = true;
718→ rawCliArgs.splice(localIdx, 1);
719→ }Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/BashTool/*.ts Status: Completed
src\tools\BashTool\bashCommandHelpers.ts src\tools\BashTool\bashPermissions.ts src\tools\BashTool\bashSecurity.ts src\tools\BashTool\commandSemantics.ts src\tools\BashTool\commentLabel.ts src\tools\BashTool\destructiveCommandWarning.ts src\tools\BashTool\modeValidation.ts src\tools\BashTool\pathValidation.ts src\tools\BashTool\prompt.ts src\tools\BashTool\readOnlyValidation.ts src\tools\BashTool\sedEditParser.ts src\tools\BashTool\sedValidation.ts src\tools\BashTool\shouldUseSandbox.ts src\tools\BashTool\toolName.ts src\tools\BashTool\utils.ts
Tool Call: grep | head -40 --type=ts "export (class|function|type|const) " D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool Status: Completed
D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:22:export function stripEmptyLines(content: string): string { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:49:export function isImageOutput(content: string): boolean { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:59:export function parseDataUri( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:71:export function buildImageToolResult( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:133:export function formatOutput(content: string): { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:167:export const stdErrAppendShellResetMessage = (stderr: string): string => D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:170:export function resetCwdIfOutsideProject( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\utils.ts:198:export function createContentSummary(content: ContentBlockParam[]): string { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:95:export function isSearchOrReadBashCommand(command: string): { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:264:export type BashToolInput = z.infer<ReturnType<typeof fullInputSchema>>; D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:296:export type Out = z.infer<OutputSchema>; D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:299:export type { BashProgress } from '../../types/tools.js'; D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:322:export function detectBlockedSleepPattern(command: string): string | null { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\BashTool.tsx:420:export const BashTool = buildTool({ D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\sedEditParser.ts:23:export type SedEditInfo = { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\sedEditParser.ts:40:export function isSedInPlaceEdit(command: string): boolean { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\sedEditParser.ts:49:export function parseSedEditCommand(command: string): SedEditInfo | null { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\sedEditParser.ts:244:export function applySedSubstitution( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\modeValidation.ts:72:export function checkPermissionMode( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\modeValidation.ts:111:export function getAutoAllowedCommands( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:103:export const MAX_SUBCOMMANDS_FOR_SECURITY_CHECK = 50 D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:110:export const MAX_SUGGESTED_RULES_FOR_COMPOUND = 5 D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:161:export function getSimpleCommandPrefix(command: string): string | null { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:243:export function getFirstWordPrefix(command: string): string | null { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:347:export const permissionRuleExtractPrefix = sharedPermissionRuleExtractPrefix D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:353:export function matchWildcardPattern( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:364:export const bashPermissionRule: ( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:524:export function stripSafeWrappers(command: string): string { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:678:export function stripWrappersFromArgv(argv: string[]): string[] { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:708:export const BINARY_HIJACK_VARS = /^(LD_|DYLD_|PATH$)/ D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:733:export function stripAllLeadingEnvVars( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:991:export const bashToolCheckExactMatchPermission = ( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:1050:export const bashToolCheckPermission = ( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:1491:export function peekSpeculativeClassifierCheck( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:1497:export function startSpeculativeClassifierCheck( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:1533:export function consumeSpeculativeClassifierCheck( D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:1543:export function clearSpeculativeChecks(): void { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:2567:export function isNormalizedGitCommand(command: string): boolean { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:2603:export function isNormalizedCdCommand(command: string): boolean { D:\code\play\stock_ai_rust\claude-code\src\tools\BashTool\bashPermissions.ts:2617:export function commandHasAnyCd(command: string): boolean {
[Showing results with pagination = limit: 40]
Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/tools/AgentTool/*.ts Status: Completed
src\tools\AgentTool\agentColorManager.ts src\tools\AgentTool\agentDisplay.ts src\tools\AgentTool\agentMemory.ts src\tools\AgentTool\agentMemorySnapshot.ts src\tools\AgentTool\agentToolUtils.ts src\tools\AgentTool\builtInAgents.ts src\tools\AgentTool\constants.ts src\tools\AgentTool\forkSubagent.ts src\tools\AgentTool\loadAgentsDir.ts src\tools\AgentTool\prompt.ts src\tools\AgentTool\resumeAgent.ts src\tools\AgentTool\runAgent.ts
Tool Call: Read src\tools\AgentTool\runAgent.ts (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle'
2→import type { UUID } from 'crypto'
3→import { randomUUID } from 'crypto'
4→import uniqBy from 'lodash-es/uniqBy.js'
5→import { logForDebugging } from 'src/utils/debug.js'
6→import { getProjectRoot, getSessionId } from '../../bootstrap/state.js'
7→import { getCommand, getSkillToolCommands, hasCommand } from '../../commands.js'
8→import {
9→ DEFAULT_AGENT_PROMPT,
10→ enhanceSystemPromptWithEnvDetails,
11→} from '../../constants/prompts.js'
12→import type { QuerySource } from '../../constants/querySource.js'
13→import { getSystemContext, getUserContext } from '../../context.js'
14→import type { CanUseToolFn } from '../../hooks/useCanUseTool.js'
15→import { query } from '../../query.js'
16→import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js'
17→import { getDumpPromptsPath } from '../../services/api/dumpPrompts.js'
18→import { cleanupAgentTracking } from '../../services/api/promptCacheBreakDetection.js'
19→import {
20→ connectToServer,
21→ fetchToolsForClient,
22→} from '../../services/mcp/client.js'
23→import { getMcpConfigByName } from '../../services/mcp/config.js'
24→import type {
25→ MCPServerConnection,
26→ ScopedMcpServerConfig,
27→} from '../../services/mcp/types.js'
28→import type { Tool, Tools, ToolUseContext } from '../../Tool.js'
29→import { killShellTasksForAgent } from '../../tasks/LocalShellTask/killShellTasks.js'
30→import type { Command } from '../../types/command.js'
31→import type { AgentId } from '../../types/ids.js'
32→import type {
33→ AssistantMessage,
34→ Message,
35→ ProgressMessage,
36→ RequestStartEvent,
37→ StreamEvent,
38→ SystemCompactBoundaryMessage,
39→ TombstoneMessage,
40→ ToolUseSummaryMessage,
41→ UserMessage,
42→} from '../../types/message.js'
43→import { createAttachmentMessage } from '../../utils/attachments.js'
44→import { AbortError } from '../../utils/errors.js'
45→import { getDisplayPath } from '../../utils/file.js'
46→import {
47→ cloneFileStateCache,
48→ createFileStateCacheWithSizeLimit,
49→ READ_FILE_STATE_CACHE_SIZE,
50→} from '../../utils/fileStateCache.js'
51→import {
52→ type CacheSafeParams,
53→ createSubagentContext,
54→} from '../../utils/forkedAgent.js'
55→import { registerFrontmatterHooks } from '../../utils/hooks/registerFrontmatterHooks.js'
56→import { clearSessionHooks } from '../../utils/hooks/sessionHooks.js'
57→import { executeSubagentStartHooks } from '../../utils/hooks.js'
58→import { createUserMessage } from '../../utils/messages.js'
59→import { getAgentModel } from '../../utils/model/agent.js'
60→import type { ModelAlias } from '../../utils/model/aliases.js'
61→import {
62→ clearAgentTranscriptSubdir,
63→ recordSidechainTranscript,
64→ setAgentTranscriptSubdir,
65→ writeAgentMetadata,
66→} from '../../utils/sessionStorage.js'
67→import {
68→ isRestrictedToPluginOnly,
69→ isSourceAdminTrusted,
70→} from '../../utils/settings/pluginOnlyPolicy.js'
71→import {
72→ asSystemPrompt,
73→ type SystemPrompt,
74→} from '../../utils/systemPromptType.js'
75→import {
76→ isPerfettoTracingEnabled,
77→ registerAgent as registerPerfettoAgent,
78→ unregisterAgent as unregisterPerfettoAgent,
79→} from '../../utils/telemetry/perfettoTracing.js'
80→import type { ContentReplacementState } from '../../utils/toolResultStorage.js'Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/services/mcp/*.ts Status: Completed
src\services\mcp\InProcessTransport.ts src\services\mcp\SdkControlTransport.ts src\services\mcp\auth.ts src\services\mcp\channelAllowlist.ts src\services\mcp\channelNotification.ts src\services\mcp\channelPermissions.ts src\services\mcp\claudeai.ts src\services\mcp\client.ts src\services\mcp\config.ts src\services\mcp\elicitationHandler.ts src\services\mcp\envExpansion.ts src\services\mcp\headersHelper.ts src\services\mcp\mcpStringUtils.ts src\services\mcp\normalization.ts src\services\mcp\oauthPort.ts src\services\mcp\officialRegistry.ts src\services\mcp\types.ts src\services\mcp\useManageMCPConnections.ts src\services\mcp\utils.ts src\services\mcp\vscodeSdkMcp.ts src\services\mcp\xaa.ts src\services\mcp\xaaIdpLogin.ts
Tool Call: Read src\services\mcp\types.ts (1 - 60) Status: Completed
1→import type { Client } from '@modelcontextprotocol/sdk/client/index.js'
2→import type {
3→ Resource,
4→ ServerCapabilities,
5→} from '@modelcontextprotocol/sdk/types.js'
6→import { z } from 'zod/v4'
7→import { lazySchema } from '../../utils/lazySchema.js'
8→
9→// Configuration schemas and types
10→export const ConfigScopeSchema = lazySchema(() =>
11→ z.enum([
12→ 'local',
13→ 'user',
14→ 'project',
15→ 'dynamic',
16→ 'enterprise',
17→ 'claudeai',
18→ 'managed',
19→ ]),
20→)
21→export type ConfigScope = z.infer<ReturnType<typeof ConfigScopeSchema>>
22→
23→export const TransportSchema = lazySchema(() =>
24→ z.enum(['stdio', 'sse', 'sse-ide', 'http', 'ws', 'sdk']),
25→)
26→export type Transport = z.infer<ReturnType<typeof TransportSchema>>
27→
28→export const McpStdioServerConfigSchema = lazySchema(() =>
29→ z.object({
30→ type: z.literal('stdio').optional(), // Optional for backwards compatibility
31→ command: z.string().min(1, 'Command cannot be empty'),
32→ args: z.array(z.string()).default([]),
33→ env: z.record(z.string(), z.string()).optional(),
34→ }),
35→)
36→
37→// Cross-App Access (XAA / SEP-990): just a per-server flag. IdP connection
38→// details (issuer, clientId, callbackPort) come from settings.xaaIdp — configured
39→// once, shared across all XAA-enabled servers. clientId/clientSecret (parent
40→// oauth config + keychain slot) are for the MCP server's AS.
41→const McpXaaConfigSchema = lazySchema(() => z.boolean())
42→
43→const McpOAuthConfigSchema = lazySchema(() =>
44→ z.object({
45→ clientId: z.string().optional(),
46→ callbackPort: z.number().int().positive().optional(),
47→ authServerMetadataUrl: z
48→ .string()
49→ .url()
50→ .startsWith('https://', {
51→ message: 'authServerMetadataUrl must use https://',
52→ })
53→ .optional(),
54→ xaa: McpXaaConfigSchema().optional(),
55→ }),
56→)
57→
58→export const McpSSEServerConfigSchema = lazySchema(() =>
59→ z.object({
60→ type: z.literal('sse'),Tool Call: Read src\query.ts (200 - 279) Status: Completed
200→
201→// -- query loop state
202→
203→// Mutable state carried between loop iterations
204→type State = {
205→ messages: Message[]
206→ toolUseContext: ToolUseContext
207→ autoCompactTracking: AutoCompactTrackingState | undefined
208→ maxOutputTokensRecoveryCount: number
209→ hasAttemptedReactiveCompact: boolean
210→ maxOutputTokensOverride: number | undefined
211→ pendingToolUseSummary: Promise<ToolUseSummaryMessage | null> | undefined
212→ stopHookActive: boolean | undefined
213→ turnCount: number
214→ // Why the previous iteration continued. Undefined on first iteration.
215→ // Lets tests assert recovery paths fired without inspecting message contents.
216→ transition: Continue | undefined
217→}
218→
219→export async function* query(
220→ params: QueryParams,
221→): AsyncGenerator<
222→ | StreamEvent
223→ | RequestStartEvent
224→ | Message
225→ | TombstoneMessage
226→ | ToolUseSummaryMessage,
227→ Terminal
228→> {
229→ const consumedCommandUuids: string[] = []
230→ const terminal = yield* queryLoop(params, consumedCommandUuids)
231→ // Only reached if queryLoop returned normally. Skipped on throw (error
232→ // propagates through yield*) and on .return() (Return completion closes
233→ // both generators). This gives the same asymmetric started-without-completed
234→ // signal as print.ts's drainCommandQueue when the turn fails.
235→ for (const uuid of consumedCommandUuids) {
236→ notifyCommandLifecycle(uuid, 'completed')
237→ }
238→ return terminal
239→}
240→
241→async function* queryLoop(
242→ params: QueryParams,
243→ consumedCommandUuids: string[],
244→): AsyncGenerator<
245→ | StreamEvent
246→ | RequestStartEvent
247→ | Message
248→ | TombstoneMessage
249→ | ToolUseSummaryMessage,
250→ Terminal
251→> {
252→ // Immutable params — never reassigned during the query loop.
253→ const {
254→ systemPrompt,
255→ userContext,
256→ systemContext,
257→ canUseTool,
258→ fallbackModel,
259→ querySource,
260→ maxTurns,
261→ skipCacheWrite,
262→ } = params
263→ const deps = params.deps ?? productionDeps()
264→
265→ // Mutable cross-iteration state. The loop body destructures this at the top
266→ // of each iteration so reads stay bare-name (`messages`, `toolUseContext`).
267→ // Continue sites write `state = { ... }` instead of 9 separate assignments.
268→ let state: State = {
269→ messages: params.messages,
270→ toolUseContext: params.toolUseContext,
271→ maxOutputTokensOverride: params.maxOutputTokensOverride,
272→ autoCompactTracking: undefined,
273→ stopHookActive: undefined,
274→ maxOutputTokensRecoveryCount: 0,
275→ hasAttemptedReactiveCompact: false,
276→ turnCount: 1,
277→ pendingToolUseSummary: undefined,
278→ transition: undefined,
279→ }Tool Call: Read src\query.ts (280 - 359) Status: Completed
280→ const budgetTracker = feature('TOKEN_BUDGET') ? createBudgetTracker() : null
281→
282→ // task_budget.remaining tracking across compaction boundaries. Undefined
283→ // until first compact fires — while context is uncompacted the server can
284→ // see the full history and handles the countdown from {total} itself (see
285→ // api/api/sampling/prompt/renderer.py:292). After a compact, the server sees
286→ // only the summary and would under-count spend; remaining tells it the
287→ // pre-compact final window that got summarized away. Cumulative across
288→ // multiple compacts: each subtracts the final context at that compact's
289→ // trigger point. Loop-local (not on State) to avoid touching the 7 continue
290→ // sites.
291→ let taskBudgetRemaining: number | undefined = undefined
292→
293→ // Snapshot immutable env/statsig/session state once at entry. See QueryConfig
294→ // for what's included and why feature() gates are intentionally excluded.
295→ const config = buildQueryConfig()
296→
297→ // Fired once per user turn — the prompt is invariant across loop iterations,
298→ // so per-iteration firing would ask sideQuery the same question N times.
299→ // Consume point polls settledAt (never blocks). `using` disposes on all
300→ // generator exit paths — see MemoryPrefetch for dispose/telemetry semantics.
301→ using pendingMemoryPrefetch = startRelevantMemoryPrefetch(
302→ state.messages,
303→ state.toolUseContext,
304→ )
305→
306→ // eslint-disable-next-line no-constant-condition
307→ while (true) {
308→ // Destructure state at the top of each iteration. toolUseContext alone
309→ // is reassigned within an iteration (queryTracking, messages updates);
310→ // the rest are read-only between continue sites.
311→ let { toolUseContext } = state
312→ const {
313→ messages,
314→ autoCompactTracking,
315→ maxOutputTokensRecoveryCount,
316→ hasAttemptedReactiveCompact,
317→ maxOutputTokensOverride,
318→ pendingToolUseSummary,
319→ stopHookActive,
320→ turnCount,
321→ } = state
322→
323→ // Skill discovery prefetch — per-iteration (uses findWritePivot guard
324→ // that returns early on non-write iterations). Discovery runs while the
325→ // model streams and tools execute; awaited post-tools alongside the
326→ // memory prefetch consume. Replaces the blocking assistant_turn path
327→ // that ran inside getAttachmentMessages (97% of those calls found
328→ // nothing in prod). Turn-0 user-input discovery still blocks in
329→ // userInputAttachments — that's the one signal where there's no prior
330→ // work to hide under.
331→ const pendingSkillPrefetch = skillPrefetch?.startSkillDiscoveryPrefetch(
332→ null,
333→ messages,
334→ toolUseContext,
335→ )
336→
337→ yield { type: 'stream_request_start' }
338→
339→ queryCheckpoint('query_fn_entry')
340→
341→ // Record query start for headless latency tracking (skip for subagents)
342→ if (!toolUseContext.agentId) {
343→ headlessProfilerCheckpoint('query_started')
344→ }
345→
346→ // Initialize or increment query chain tracking
347→ const queryTracking = toolUseContext.queryTracking
348→ ? {
349→ chainId: toolUseContext.queryTracking.chainId,
350→ depth: toolUseContext.queryTracking.depth + 1,
351→ }
352→ : {
353→ chainId: deps.uuid(),
354→ depth: 0,
355→ }
356→
357→ const queryChainIdForAnalytics =
358→ queryTracking.chainId as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
359→Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/services/compact/*.ts Status: Completed
src\services\compact\apiMicrocompact.ts src\services\compact\autoCompact.ts src\services\compact\compact.ts src\services\compact\compactWarningHook.ts src\services\compact\compactWarningState.ts src\services\compact\grouping.ts src\services\compact\microCompact.ts src\services\compact\postCompactCleanup.ts src\services\compact\prompt.ts src\services\compact\sessionMemoryCompact.ts src\services\compact\timeBasedMCConfig.ts
Tool Call: Read src\services\compact\autoCompact.ts (1 - 60) Status: Completed
1→import { feature } from 'bun:bundle'
2→import { markPostCompaction } from 'src/bootstrap/state.js'
3→import { getSdkBetas } from '../../bootstrap/state.js'
4→import type { QuerySource } from '../../constants/querySource.js'
5→import type { ToolUseContext } from '../../Tool.js'
6→import type { Message } from '../../types/message.js'
7→import { getGlobalConfig } from '../../utils/config.js'
8→import { getContextWindowForModel } from '../../utils/context.js'
9→import { logForDebugging } from '../../utils/debug.js'
10→import { isEnvTruthy } from '../../utils/envUtils.js'
11→import { hasExactErrorMessage } from '../../utils/errors.js'
12→import type { CacheSafeParams } from '../../utils/forkedAgent.js'
13→import { logError } from '../../utils/log.js'
14→import { tokenCountWithEstimation } from '../../utils/tokens.js'
15→import { getFeatureValue_CACHED_MAY_BE_STALE } from '../analytics/growthbook.js'
16→import { getMaxOutputTokensForModel } from '../api/claude.js'
17→import { notifyCompaction } from '../api/promptCacheBreakDetection.js'
18→import { setLastSummarizedMessageId } from '../SessionMemory/sessionMemoryUtils.js'
19→import {
20→ type CompactionResult,
21→ compactConversation,
22→ ERROR_MESSAGE_USER_ABORT,
23→ type RecompactionInfo,
24→} from './compact.js'
25→import { runPostCompactCleanup } from './postCompactCleanup.js'
26→import { trySessionMemoryCompaction } from './sessionMemoryCompact.js'
27→
28→// Reserve this many tokens for output during compaction
29→// Based on p99.99 of compact summary output being 17,387 tokens.
30→const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000
31→
32→// Returns the context window size minus the max output tokens for the model
33→export function getEffectiveContextWindowSize(model: string): number {
34→ const reservedTokensForSummary = Math.min(
35→ getMaxOutputTokensForModel(model),
36→ MAX_OUTPUT_TOKENS_FOR_SUMMARY,
37→ )
38→ let contextWindow = getContextWindowForModel(model, getSdkBetas())
39→
40→ const autoCompactWindow = process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW
41→ if (autoCompactWindow) {
42→ const parsed = parseInt(autoCompactWindow, 10)
43→ if (!isNaN(parsed) && parsed > 0) {
44→ contextWindow = Math.min(contextWindow, parsed)
45→ }
46→ }
47→
48→ return contextWindow - reservedTokensForSummary
49→}
50→
51→export type AutoCompactTrackingState = {
52→ compacted: boolean
53→ turnCounter: number
54→ // Unique ID per turn
55→ turnId: string
56→ // Consecutive autocompact failures. Reset on success.
57→ // Used as a circuit breaker to stop retrying when the context is
58→ // irrecoverably over the limit (e.g., prompt_too_long).
59→ consecutiveFailures?: number
60→}Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/utils/settings/*.ts Status: Completed
src\utils\settings\allErrors.ts src\utils\settings\applySettingsChange.ts src\utils\settings\changeDetector.ts src\utils\settings\constants.ts src\utils\settings\internalWrites.ts src\utils\settings\managedPath.ts src\utils\settings\permissionValidation.ts src\utils\settings\pluginOnlyPolicy.ts src\utils\settings\schemaOutput.ts src\utils\settings\settings.ts src\utils\settings\settingsCache.ts src\utils\settings\toolValidationConfig.ts src\utils\settings\types.ts src\utils\settings\validateEditTool.ts src\utils\settings\validation.ts src\utils\settings\validationTips.ts
Tool Call: Read src\utils\settings\settings.ts (1 - 60) Status: Completed
1→import { feature } from 'bun:bundle'
2→import mergeWith from 'lodash-es/mergeWith.js'
3→import { dirname, join, resolve } from 'path'
4→import { z } from 'zod/v4'
5→import {
6→ getFlagSettingsInline,
7→ getFlagSettingsPath,
8→ getOriginalCwd,
9→ getUseCoworkPlugins,
10→} from '../../bootstrap/state.js'
11→import { getRemoteManagedSettingsSyncFromCache } from '../../services/remoteManagedSettings/syncCacheState.js'
12→import { uniq } from '../array.js'
13→import { logForDebugging } from '../debug.js'
14→import { logForDiagnosticsNoPII } from '../diagLogs.js'
15→import { getClaudeConfigHomeDir, isEnvTruthy } from '../envUtils.js'
16→import { getErrnoCode, isENOENT } from '../errors.js'
17→import { writeFileSyncAndFlush_DEPRECATED } from '../file.js'
18→import { readFileSync } from '../fileRead.js'
19→import { getFsImplementation, safeResolvePath } from '../fsOperations.js'
20→import { addFileGlobRuleToGitignore } from '../git/gitignore.js'
21→import { safeParseJSON } from '../json.js'
22→import { logError } from '../log.js'
23→import { getPlatform } from '../platform.js'
24→import { clone, jsonStringify } from '../slowOperations.js'
25→import { profileCheckpoint } from '../startupProfiler.js'
26→import {
27→ type EditableSettingSource,
28→ getEnabledSettingSources,
29→ type SettingSource,
30→} from './constants.js'
31→import { markInternalWrite } from './internalWrites.js'
32→import {
33→ getManagedFilePath,
34→ getManagedSettingsDropInDir,
35→} from './managedPath.js'
36→import { getHkcuSettings, getMdmSettings } from './mdm/settings.js'
37→import {
38→ getCachedParsedFile,
39→ getCachedSettingsForSource,
40→ getPluginSettingsBase,
41→ getSessionSettingsCache,
42→ resetSettingsCache,
43→ setCachedParsedFile,
44→ setCachedSettingsForSource,
45→ setSessionSettingsCache,
46→} from './settingsCache.js'
47→import { type SettingsJson, SettingsSchema } from './types.js'
48→import {
49→ filterInvalidPermissionRules,
50→ formatZodError,
51→ type SettingsWithErrors,
52→ type ValidationError,
53→} from './validation.js'
54→
55→/**
56→ * Get the path to the managed settings file based on the current platform
57→ */
58→function getManagedSettingsFilePath(): string {
59→ return join(getManagedFilePath(), 'managed-settings.json')
60→}Tool Call: Read src\utils\settings\types.ts (1 - 80) Status: Completed
1→import { feature } from 'bun:bundle'
2→import { z } from 'zod/v4'
3→import { SandboxSettingsSchema } from '../../entrypoints/sandboxTypes.js'
4→import { isEnvTruthy } from '../envUtils.js'
5→import { lazySchema } from '../lazySchema.js'
6→import {
7→ EXTERNAL_PERMISSION_MODES,
8→ PERMISSION_MODES,
9→} from '../permissions/PermissionMode.js'
10→import { MarketplaceSourceSchema } from '../plugins/schemas.js'
11→import { CLAUDE_CODE_SETTINGS_SCHEMA_URL } from './constants.js'
12→import { PermissionRuleSchema } from './permissionValidation.js'
13→
14→// Re-export hook schemas and types from centralized location for backward compatibility
15→export {
16→ type AgentHook,
17→ type BashCommandHook,
18→ type HookCommand,
19→ HookCommandSchema,
20→ type HookMatcher,
21→ HookMatcherSchema,
22→ HooksSchema,
23→ type HooksSettings,
24→ type HttpHook,
25→ type PromptHook,
26→} from '../../schemas/hooks.js'
27→
28→// Also import for use within this file
29→import { type HookCommand, HooksSchema } from '../../schemas/hooks.js'
30→import { count } from '../array.js'
31→
32→/**
33→ * Schema for environment variables
34→ */
35→export const EnvironmentVariablesSchema = lazySchema(() =>
36→ z.record(z.string(), z.coerce.string()),
37→)
38→
39→/**
40→ * Schema for permissions section
41→ */
42→export const PermissionsSchema = lazySchema(() =>
43→ z
44→ .object({
45→ allow: z
46→ .array(PermissionRuleSchema())
47→ .optional()
48→ .describe('List of permission rules for allowed operations'),
49→ deny: z
50→ .array(PermissionRuleSchema())
51→ .optional()
52→ .describe('List of permission rules for denied operations'),
53→ ask: z
54→ .array(PermissionRuleSchema())
55→ .optional()
56→ .describe(
57→ 'List of permission rules that should always prompt for confirmation',
58→ ),
59→ defaultMode: z
60→ .enum(
61→ feature('TRANSCRIPT_CLASSIFIER')
62→ ? PERMISSION_MODES
63→ : EXTERNAL_PERMISSION_MODES,
64→ )
65→ .optional()
66→ .describe('Default permission mode when Claude Code needs access'),
67→ disableBypassPermissionsMode: z
68→ .enum(['disable'])
69→ .optional()
70→ .describe('Disable the ability to bypass permission prompts'),
71→ ...(feature('TRANSCRIPT_CLASSIFIER')
72→ ? {
73→ disableAutoMode: z
74→ .enum(['disable'])
75→ .optional()
76→ .describe('Disable auto mode'),
77→ }
78→ : {}),
79→ additionalDirectories: z
80→ .array(z.string())Tool Call: grep -l --type=ts "^export function buildTool" D:\code\play\stock_ai_rust\claude-code\src Status: Completed
Found 1 file src\Tool.ts
Tool Call: grep -l | head -5 "buildTool(" D:\code\play\stock_ai_rust\claude-code\src Status: Completed
Found 5 files limit: 5 src\tools\testing\TestingPermissionTool.tsx src\tools\WebSearchTool\WebSearchTool.ts src\tools\WebFetchTool\WebFetchTool.ts src\tools\ToolSearchTool\ToolSearchTool.ts src\tools\TodoWriteTool\TodoWriteTool.ts
Tool Call: Read src\Tool.ts (350 - 429) Status: Completed
350→ name: string,
351→): boolean {
352→ return tool.name === name || (tool.aliases?.includes(name) ?? false)
353→}
354→
355→/**
356→ * Finds a tool by name or alias from a list of tools.
357→ */
358→export function findToolByName(tools: Tools, name: string): Tool | undefined {
359→ return tools.find(t => toolMatchesName(t, name))
360→}
361→
362→export type Tool<
363→ Input extends AnyObject = AnyObject,
364→ Output = unknown,
365→ P extends ToolProgressData = ToolProgressData,
366→> = {
367→ /**
368→ * Optional aliases for backwards compatibility when a tool is renamed.
369→ * The tool can be looked up by any of these names in addition to its primary name.
370→ */
371→ aliases?: string[]
372→ /**
373→ * One-line capability phrase used by ToolSearch for keyword matching.
374→ * Helps the model find this tool via keyword search when it's deferred.
375→ * 3–10 words, no trailing period.
376→ * Prefer terms not already in the tool name (e.g. 'jupyter' for NotebookEdit).
377→ */
378→ searchHint?: string
379→ call(
380→ args: z.infer<Input>,
381→ context: ToolUseContext,
382→ canUseTool: CanUseToolFn,
383→ parentMessage: AssistantMessage,
384→ onProgress?: ToolCallProgress<P>,
385→ ): Promise<ToolResult<Output>>
386→ description(
387→ input: z.infer<Input>,
388→ options: {
389→ isNonInteractiveSession: boolean
390→ toolPermissionContext: ToolPermissionContext
391→ tools: Tools
392→ },
393→ ): Promise<string>
394→ readonly inputSchema: Input
395→ // Type for MCP tools that can specify their input schema directly in JSON Schema format
396→ // rather than converting from Zod schema
397→ readonly inputJSONSchema?: ToolInputJSONSchema
398→ // Optional because TungstenTool doesn't define this. TODO: Make it required.
399→ // When we do that, we can also go through and make this a bit more type-safe.
400→ outputSchema?: z.ZodType<unknown>
401→ inputsEquivalent?(a: z.infer<Input>, b: z.infer<Input>): boolean
402→ isConcurrencySafe(input: z.infer<Input>): boolean
403→ isEnabled(): boolean
404→ isReadOnly(input: z.infer<Input>): boolean
405→ /** Defaults to false. Only set when the tool performs irreversible operations (delete, overwrite, send). */
406→ isDestructive?(input: z.infer<Input>): boolean
407→ /**
408→ * What should happen when the user submits a new message while this tool
409→ * is running.
410→ *
411→ * - `'cancel'` — stop the tool and discard its result
412→ * - `'block'` — keep running; the new message waits
413→ *
414→ * Defaults to `'block'` when not implemented.
415→ */
416→ interruptBehavior?(): 'cancel' | 'block'
417→ /**
418→ * Returns information about whether this tool use is a search or read operation
419→ * that should be collapsed into a condensed display in the UI. Examples include
420→ * file searching (Grep, Glob), file reading (Read), and bash commands like find,
421→ * grep, wc, etc.
422→ *
423→ * Returns an object indicating whether the operation is a search or read operation:
424→ * - `isSearch: true` for search operations (grep, find, glob patterns)
425→ * - `isRead: true` for read operations (cat, head, tail, file read)
426→ * - `isList: true` for directory-listing operations (ls, tree, du)
427→ * - All can be false if the operation shouldn't be collapsed
428→ */
429→ isSearchOrReadCommand?(input: z.infer<Input>): {Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/plugins/**/*.ts Status: Completed
src\plugins\builtinPlugins.ts src\plugins\bundled\index.ts
Tool Call: Read src\Tool.ts (430 - 509) Status: Completed
430→ isSearch: boolean
431→ isRead: boolean
432→ isList?: boolean
433→ }
434→ isOpenWorld?(input: z.infer<Input>): boolean
435→ requiresUserInteraction?(): boolean
436→ isMcp?: boolean
437→ isLsp?: boolean
438→ /**
439→ * When true, this tool is deferred (sent with defer_loading: true) and requires
440→ * ToolSearch to be used before it can be called.
441→ */
442→ readonly shouldDefer?: boolean
443→ /**
444→ * When true, this tool is never deferred — its full schema appears in the
445→ * initial prompt even when ToolSearch is enabled. For MCP tools, set via
446→ * `_meta['anthropic/alwaysLoad']`. Use for tools the model must see on
447→ * turn 1 without a ToolSearch round-trip.
448→ */
449→ readonly alwaysLoad?: boolean
450→ /**
451→ * For MCP tools: the server and tool names as received from the MCP server (unnormalized).
452→ * Present on all MCP tools regardless of whether `name` is prefixed (mcp__server__tool)
453→ * or unprefixed (CLAUDE_AGENT_SDK_MCP_NO_PREFIX mode).
454→ */
455→ mcpInfo?: { serverName: string; toolName: string }
456→ readonly name: string
457→ /**
458→ * Maximum size in characters for tool result before it gets persisted to disk.
459→ * When exceeded, the result is saved to a file and Claude receives a preview
460→ * with the file path instead of the full content.
461→ *
462→ * Set to Infinity for tools whose output must never be persisted (e.g. Read,
463→ * where persisting creates a circular Read→file→Read loop and the tool
464→ * already self-bounds via its own limits).
465→ */
466→ maxResultSizeChars: number
467→ /**
468→ * When true, enables strict mode for this tool, which causes the API to
469→ * more strictly adhere to tool instructions and parameter schemas.
470→ * Only applied when the tengu_tool_pear is enabled.
471→ */
472→ readonly strict?: boolean
473→
474→ /**
475→ * Called on copies of tool_use input before observers see it (SDK stream,
476→ * transcript, canUseTool, PreToolUse/PostToolUse hooks). Mutate in place
477→ * to add legacy/derived fields. Must be idempotent. The original API-bound
478→ * input is never mutated (preserves prompt cache). Not re-applied when a
479→ * hook/permission returns a fresh updatedInput — those own their shape.
480→ */
481→ backfillObservableInput?(input: Record<string, unknown>): void
482→
483→ /**
484→ * Determines if this tool is allowed to run with this input in the current context.
485→ * It informs the model of why the tool use failed, and does not directly display any UI.
486→ * @param input
487→ * @param context
488→ */
489→ validateInput?(
490→ input: z.infer<Input>,
491→ context: ToolUseContext,
492→ ): Promise<ValidationResult>
493→
494→ /**
495→ * Determines if the user is asked for permission. Only called after validateInput() passes.
496→ * General permission logic is in permissions.ts. This method contains tool-specific logic.
497→ * @param input
498→ * @param context
499→ */
500→ checkPermissions(
501→ input: z.infer<Input>,
502→ context: ToolUseContext,
503→ ): Promise<PermissionResult>
504→
505→ // Optional method for tools that operate on a file path
506→ getPath?(input: z.infer<Input>): string
507→
508→ /**
509→ * Prepare a matcher for hook `if` conditions (permission-rule patterns likeTool Call: Find D:\code\play\stock_ai_rust\claude-code src/skills/**/*.ts Status: Completed
src\skills\bundled\batch.ts src\skills\bundled\claudeApi.ts src\skills\bundled\claudeApiContent.ts src\skills\bundled\claudeInChrome.ts src\skills\bundled\debug.ts src\skills\bundled\index.ts src\skills\bundled\keybindings.ts src\skills\bundled\loop.ts src\skills\bundled\loremIpsum.ts src\skills\bundled\remember.ts src\skills\bundled\scheduleRemoteAgents.ts src\skills\bundled\simplify.ts src\skills\bundled\skillify.ts src\skills\bundled\stuck.ts src\skills\bundled\updateConfig.ts src\skills\bundled\verify.ts src\skills\bundled\verifyContent.ts src\skills\bundledSkills.ts src\skills\loadSkillsDir.ts src\skills\mcpSkillBuilders.ts
Tool Call: Read src\skills\loadSkillsDir.ts (1 - 60) Status: Completed
1→import { realpath } from 'fs/promises'
2→import ignore from 'ignore'
3→import memoize from 'lodash-es/memoize.js'
4→import {
5→ basename,
6→ dirname,
7→ isAbsolute,
8→ join,
9→ sep as pathSep,
10→ relative,
11→} from 'path'
12→import {
13→ getAdditionalDirectoriesForClaudeMd,
14→ getSessionId,
15→} from '../bootstrap/state.js'
16→import {
17→ type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
18→ logEvent,
19→} from '../services/analytics/index.js'
20→import { roughTokenCountEstimation } from '../services/tokenEstimation.js'
21→import type { Command, PromptCommand } from '../types/command.js'
22→import {
23→ parseArgumentNames,
24→ substituteArguments,
25→} from '../utils/argumentSubstitution.js'
26→import { logForDebugging } from '../utils/debug.js'
27→import {
28→ EFFORT_LEVELS,
29→ type EffortValue,
30→ parseEffortValue,
31→} from '../utils/effort.js'
32→import {
33→ getClaudeConfigHomeDir,
34→ isBareMode,
35→ isEnvTruthy,
36→} from '../utils/envUtils.js'
37→import { isENOENT, isFsInaccessible } from '../utils/errors.js'
38→import {
39→ coerceDescriptionToString,
40→ type FrontmatterData,
41→ type FrontmatterShell,
42→ parseBooleanFrontmatter,
43→ parseFrontmatter,
44→ parseShellFrontmatter,
45→ splitPathInFrontmatter,
46→} from '../utils/frontmatterParser.js'
47→import { getFsImplementation } from '../utils/fsOperations.js'
48→import { isPathGitignored } from '../utils/git/gitignore.js'
49→import { logError } from '../utils/log.js'
50→import {
51→ extractDescriptionFromMarkdown,
52→ getProjectDirsUpToHome,
53→ loadMarkdownFilesForSubdir,
54→ type MarkdownFile,
55→ parseSlashCommandToolsFromFrontmatter,
56→} from '../utils/markdownConfigLoader.js'
57→import { parseUserSpecifiedModel } from '../utils/model/model.js'
58→import { executeShellCommandsInPrompt } from '../utils/promptShellExecution.js'
59→import type { SettingSource } from '../utils/settings/constants.js'
60→import { isSettingSourceEnabled } from '../utils/settings/constants.js'Tool Call: Find D:\code\play\stock_ai_rust\claude-code src/hooks/*.ts Status: Completed
src\hooks\fileSuggestions.ts src\hooks\renderPlaceholder.ts src\hooks\unifiedSuggestions.ts src\hooks\useAfterFirstRender.ts src\hooks\useApiKeyVerification.ts src\hooks\useAssistantHistory.ts src\hooks\useAwaySummary.ts src\hooks\useBackgroundTaskNavigation.ts src\hooks\useBlink.ts src\hooks\useCancelRequest.ts src\hooks\useClipboardImageHint.ts src\hooks\useCommandQueue.ts src\hooks\useCopyOnSelect.ts src\hooks\useDeferredHookMessages.ts src\hooks\useDiffData.ts src\hooks\useDiffInIDE.ts src\hooks\useDirectConnect.ts src\hooks\useDoublePress.ts src\hooks\useDynamicConfig.ts src\hooks\useElapsedTime.ts src\hooks\useExitOnCtrlCD.ts src\hooks\useExitOnCtrlCDWithKeybindings.ts src\hooks\useFileHistorySnapshotInit.ts src\hooks\useHistorySearch.ts src\hooks\useIdeAtMentioned.ts src\hooks\useIdeConnectionStatus.ts src\hooks\useIdeLogging.ts src\hooks\useIdeSelection.ts src\hooks\useInboxPoller.ts src\hooks\useInputBuffer.ts src\hooks\useIssueFlagBanner.ts src\hooks\useLogMessages.ts src\hooks\useMailboxBridge.ts src\hooks\useMainLoopModel.ts src\hooks\useManagePlugins.ts src\hooks\useMemoryUsage.ts src\hooks\useMergedClients.ts src\hooks\useMergedCommands.ts src\hooks\useMergedTools.ts src\hooks\useMinDisplayTime.ts src\hooks\useNotifyAfterTimeout.ts src\hooks\usePasteHandler.ts src\hooks\usePrStatus.ts src\hooks\usePromptSuggestion.ts src\hooks\useQueueProcessor.ts src\hooks\useRemoteSession.ts src\hooks\useSSHSession.ts src\hooks\useScheduledTasks.ts src\hooks\useSearchInput.ts src\hooks\useSessionBackgrounding.ts src\hooks\useSettings.ts src\hooks\useSettingsChange.ts src\hooks\useSkillImprovementSurvey.ts src\hooks\useSkillsChange.ts src\hooks\useSwarmInitialization.ts src\hooks\useSwarmPermissionPoller.ts src\hooks\useTaskListWatcher.ts src\hooks\useTasksV2.ts src\hooks\useTeammateViewAutoExit.ts src\hooks\useTerminalSize.ts src\hooks\useTextInput.ts src\hooks\useTimeout.ts src\hooks\useTurnDiffs.ts src\hooks\useUpdateNotification.ts src\hooks\useVimInput.ts src\hooks\useVirtualScroll.ts src\hooks\useVoice.ts src\hooks\useVoiceEnabled.ts
Assistant
<thinking> All three agents have returned comprehensive analysis. Now I need to:
- Consolidate the findings into analysis documents
- Write them to
docs/analysis/
Let me create the three analysis documents. But first, let me create the docs directory structure.
The analysis is very thorough. Let me now write the three documents to docs/analysis/:
project-overview.md— Architecture, tech stack, entry points, build systemmodule-inventory.md— Every module with detailsrisk-assessment.md— Technical risks, complexity hotspots
Then I'll move to Phase 2. </thinking>
三个分析 Agent 全部返回。1884 个源文件的全面剖析已完成。现在整合分析结果并写入文档。
Tool Call: mkdir -p "D:/code/play/stock_ai_rust/claude-code/docs/analysis" Status: Completed
Terminal:
(Bash completed with no output)Tool Call: Write docs\analysis\project-overview.md Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\analysis\project-overview.md
# Claude Code - Project Overview
## Technology Stack
| Technology | Version / Notes |
|---|---|
| TypeScript | 5.x, strict mode |
| React | 19.x, with React Compiler output |
| Bun | Runtime + bundler, `bun:bundle` feature flags for DCE |
| Ink (custom fork) | Full TUI framework in `src/ink/`, not the npm package |
| @anthropic-ai/sdk | Claude API client, Beta Messages API |
| @modelcontextprotocol/sdk | MCP server/client protocol |
| @commander-js/extra-typings | CLI argument parsing |
| Zod v4 | Runtime type validation & schema definition |
| lodash-es | Utility functions (memoize, mergeWith, uniqBy, etc.) |
| OpenTelemetry | Telemetry/tracing (sdk-logs, sdk-metrics, sdk-trace-base) |
| GrowthBook | Feature flags & A/B testing |
| chalk | Terminal color output |
| Yoga (WASM) | Ink layout engine, CSS Flexbox implementation |
## Architecture Pattern
**Event-driven Async Generator Pipeline with Layered Dependency Injection**
The system is not traditional MVC. It's built around a "message stream pipeline":CLI (commander) -> main.tsx -> query() generator -> API -> Tool execution -> Result ^ | +------------- loop ----------------------+
## Entry Points & Startup Flow
### Primary Entry: `src/entrypoints/cli.tsx`
- Zero-dependency fast-path dispatcher
- Handles `--version`, `--daemon-worker`, `bridge`, `daemon` before loading full CLI
- Minimizes startup time by deferring heavy imports via dynamic `import()`
- ~250 lines
### Initialization: `src/entrypoints/init.ts`
- Core app initialization: config system, env vars, mTLS, telemetry, LSP, policy
- Two-phase: pre-trust-dialog and post-trust-dialog
- Memoized to execute only once
- ~400 lines
### Main Function: `src/main.tsx`
- Parses all Commander.js arguments
- Handles all run modes: interactive REPL, headless, MCP server, remote, print
- Assembles `ToolUseContext` (the primary dependency injection object)
- Calls `launchRepl()` or `runHeadless()`
- ~4000+ lines (the "god function")
### Bootstrap State: `src/bootstrap/state.ts`
- Global singleton state store
- Holds session ID, CWD, model config, telemetry counters, OAuth tokens
- ~80 getter/setter functions, ~1759 lines
- Comment warns: "DO NOT ADD MORE STATE HERE"
## Core Data Flow
### 1. Startup Pathcli.tsx::main() -> fast-path dispatch -> main.tsx::main() -> init() -> parse CLI args -> build AppState + ToolUseContext -> launchRepl() or ask()
### 2. Interactive Session PathlaunchRepl() -> React + Ink render <App><REPL/></App> -> user types in PromptInput -> REPL.tsx calls QueryEngine.submitMessage() -> query() generator -> claude.ts API call -> streaming StreamEvent -> tool calls trigger toolOrchestration.ts -> tool results appended -> loop continues until stop_reason === "end_turn"
### 3. Tool Execution Pathtool.checkPermissions() -> permission dialog (interactive) or auto-decision -> tool.call() -> ToolResult -> serialized as UserMessage tool_result -> appended to conversation -> API loop continues
### 4. Sub-Agent PathAgentTool.call() -> runAgent() -> clone ToolUseContext (fork) -> independent query() loop -> results aggregated -> return to parent
### 5. CLAUDE.md Injection Pathcontext.ts::getUserContext() -> scan CWD to home path -> read CLAUDE.md files -> memoize cache -> inject into system prompt before each API call
## Key Configuration
- **CLAUDE.md files**: Project/user instructions injected into system prompt (hierarchical: project > user > global)
- **settings.json**: Multi-source settings merge (user-level `~/.claude/settings.json`, project-level `.claude/settings.json`, enterprise MDM/HKCU, CLI flags, remote hosted)
- **Feature flags**: `bun:bundle` compile-time DCE + GrowthBook runtime overrides
- **Permission modes**: 5 modes defined in `src/types/permissions.ts` (e.g., default, plan, yolo, etc.)
- **Hooks**: Pre/post tool-use hooks configured in settings
## Cross-Cutting Concerns
- **Permission system**: `ToolPermissionContext` (immutable) flows through the entire tool call chain
- **Telemetry**: GrowthBook feature flags + OpenTelemetry + `logEvent()` throughout
- **Context compaction**: `services/compact/` auto-triggers when context window approaches limit
- **Error handling**: AbortController signal propagation + try/catch + `gracefulShutdown` registry
- **Multi-agent coordination**: Coordinator Mode manages worker agent networks, permissions proxy from worker to leader UI
## Build & Distribution
- **Runtime**: Bun (not Node.js)
- **Bundler**: Bun's built-in bundler with `bun:bundle` feature flags
- **Dead Code Elimination**: `feature('FLAG')` calls are evaluated at build time; unreachable branches are removed
- **React Compiler**: Some `.tsx` files contain React Compiler output (`_c()` cache slots)
- **Source Maps**: Embedded as base64 comments in compiled `.tsx` filesTool Call: Write docs\analysis\module-inventory.md Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\analysis\module-inventory.md
# Claude Code - Module Inventory
## Summary Statistics
- **Total source files**: 1884 (.ts/.tsx)
- **Top-level modules**: 35 subdirectories + 18 root-level files
- **Core modules**: 15 (essential for understanding the system)
- **Supporting modules**: 8 (important but not entry points)
- **Peripheral modules**: 12 (feature-specific or auxiliary)
## Module Classification
### CORE Modules (Detailed Coverage Required)
| Module | Path | Files | Complexity | Responsibility |
|--------|------|-------|-----------|----------------|
| Tool contract | `src/Tool.ts` | 1 (793 lines) | Critical | `Tool<Input,Output>` interface, `ToolUseContext` (40+ fields), `buildTool()` factory |
| QueryEngine | `src/QueryEngine.ts` | 1 (1296 lines) | Critical | SDK/headless conversation engine, `submitMessage()` async generator |
| query loop | `src/query.ts` + `src/query/` | 5 | Critical | Core agentic loop: API calls, streaming, tool execution, compaction |
| bootstrap/state | `src/bootstrap/` | 1 (1759 lines) | Critical | Global singleton: session ID, cost, model, telemetry, ~80 getters/setters |
| tools | `src/tools/` | 184 | Critical | All tool implementations (Bash, Agent, FileEdit, FileRead, Grep, etc.) |
| commands | `src/commands/` + `src/commands.ts` | 208 | High | 70+ slash commands registry, feature-flag conditional loading |
| screens/REPL | `src/screens/` | 3 | Critical | Interactive terminal session, most complex UI component (~3000 lines) |
| ink | `src/ink/` | 85 | Critical | Custom React reconciler for terminal, Yoga WASM layout, ANSI rendering |
| components | `src/components/` | 389 | High | All UI components: messages, permissions, prompt input, design system |
| hooks | `src/hooks/` | ~100 | High | React hooks: permission handling, command processing, typeahead, etc. |
| state | `src/state/` | 6 | High | AppState (150+ fields), Zustand-like store, React context provider |
| services | `src/services/` | 130 | High | API client, MCP, compaction, analytics, LSP, OAuth, tool orchestration |
| utils | `src/utils/` | 564 | High | Largest module: bash parsing, permissions, plugins, settings, swarm, model, telemetry |
| entrypoints | `src/entrypoints/` | 8 | High | CLI bootstrap, MCP server mode, SDK type exports |
| types | `src/types/` | ~10 | Medium | Shared types: Command, permissions, hooks, IDs, plugins |
### SUPPORTING Modules (Brief Coverage)
| Module | Path | Files | Complexity | Responsibility |
|--------|------|-------|-----------|----------------|
| tasks | `src/tasks/` | 12 | High | Background task runners: shell, agent, teammate, dream, workflow |
| skills | `src/skills/` | 20 | Medium | Markdown skill loading from `.claude/skills/`, bundled skills |
| bridge | `src/bridge/` | 33 | High | Remote control bridge: mobile/web -> local CLI session |
| cli | `src/cli/` | 15 | Medium | CLI I/O, structured output, SSE/WebSocket transports |
| memdir | `src/memdir/` | 8 | Medium | Memory directory: `.claude/memory/` file management |
| keybindings | `src/keybindings/` | 14 | Medium | Customizable keyboard shortcuts |
| constants | `src/constants/` | 20 | Low | API limits, beta headers, product strings, prompts |
| context | `src/context/` | 9 | Medium | React contexts: notifications, mailbox, modal, voice |
### PERIPHERAL Modules (Mention Only)
| Module | Path | Files | Complexity | Responsibility |
|--------|------|-------|-----------|----------------|
| coordinator | `src/coordinator/` | 1 | Low | Swarm coordinator mode context injection |
| schemas | `src/schemas/` | 1 | Low | Zod schema for hooks config |
| buddy | `src/buddy/` | 6 | Low | Companion mascot feature (feature-flagged) |
| plugins | `src/plugins/` | 2 | Low | Built-in plugin registration |
| remote | `src/remote/` | 4 | Medium | Remote session management (`--remote` mode) |
| server | `src/server/` | 3 | Medium | Direct Connect server (Unix domain socket) |
| migrations | `src/migrations/` | 11 | Low | One-time data migrations for settings |
| vim | `src/vim/` | 5 | Medium | Vim mode for prompt input |
| voice | `src/voice/` | 1 | Low | Voice mode feature flag check |
| outputStyles | `src/outputStyles/` | 1 | Low | Custom output style definitions |
| native-ts | `src/native-ts/` | 4 | Low (interface) | TS ports of native libs (yoga-layout, color-diff) |
| moreright | `src/moreright/` | 1 | Low | Content overflow detection hook |
| assistant | `src/assistant/` | 1 | Low | Remote session history for Kairos feature |
| upstreamproxy | `src/upstreamproxy/` | 2 | Low | HTTP proxy support for enterprise firewalls |
## Root-Level Files
| File | Responsibility | Complexity |
|------|---------------|-----------|
| `src/main.tsx` | Main CLI entry, all run modes, ToolUseContext assembly | Critical |
| `src/Tool.ts` | Tool interface & ToolUseContext definition | Critical |
| `src/QueryEngine.ts` | SDK conversation engine | Critical |
| `src/query.ts` | Core agentic loop | Critical |
| `src/commands.ts` | Command registry (70+ commands) | High |
| `src/setup.ts` | Process-level initialization | High |
| `src/context.ts` | CLAUDE.md loading & system context | Medium |
| `src/tools.ts` | Tool assembly & registration | Medium |
| `src/tasks.ts` | Task type handler registration | Low |
| `src/Task.ts` | Task interface & types (7 task types) | Medium |
| `src/ink.ts` | Re-exports custom Ink library | Low |
| `src/cost-tracker.ts` | API cost tracking per session | Low |
| `src/history.ts` | Session history read/write | Medium |
| `src/costHook.ts` | Cost tracking hook | Low |
| `src/dialogLaunchers.tsx` | Dialog launch helpers | Low |
| `src/interactiveHelpers.tsx` | Interactive mode helpers | Low |
| `src/replLauncher.tsx` | REPL launch orchestrator | Medium |
| `src/projectOnboardingState.ts` | Project onboarding state management | Low |
## Key Tool Implementations
| Tool | Path | Files | Complexity | Notes |
|------|------|-------|-----------|-------|
| AgentTool | `src/tools/AgentTool/` | 22 | Critical | Recursive sub-agent, context forking, MCP connection |
| BashTool | `src/tools/BashTool/` | 18 | Critical | Shell execution, security validation, 2600-line permission file |
| FileEditTool | `src/tools/FileEditTool/` | ~8 | High | String replacement, diff display, permission prompts |
| FileReadTool | `src/tools/FileReadTool/` | ~6 | Medium | File reading, image processing, size limits |
| FileWriteTool | `src/tools/FileWriteTool/` | ~6 | Medium | File creation/overwrite |
| GrepTool | `src/tools/GrepTool/` | ~4 | Medium | Ripgrep-based content search |
| GlobTool | `src/tools/GlobTool/` | ~4 | Low-Medium | Pattern-based file search |
| MCPTool | `src/tools/MCPTool/` | ~6 | High | MCP server tool proxy |
| LSPTool | `src/tools/LSPTool/` | ~4 | Medium | Language server protocol |
| WebSearchTool | `src/tools/WebSearchTool/` | ~4 | Medium | Web search |
| WebFetchTool | `src/tools/WebFetchTool/` | ~4 | Medium | Web page fetching |
| SkillTool | `src/tools/SkillTool/` | ~4 | Medium | Skill command invocation |
| NotebookEditTool | `src/tools/NotebookEditTool/` | ~4 | Medium | Jupyter notebook editing |
## Key Service Modules
| Service | Path | Files | Complexity | Notes |
|---------|------|-------|-----------|-------|
| api | `src/services/api/` | 19 | High | Anthropic API client, retry, usage tracking, cost calculation |
| mcp | `src/services/mcp/` | 22 | High | MCP connection management, OAuth, 4 transport types |
| compact | `src/services/compact/` | 12 | High | Context window management: auto/micro/snip compaction |
| analytics | `src/services/analytics/` | 9 | Medium | GrowthBook, event logging, Datadog |
| tools | `src/services/tools/` | 4 | High | StreamingToolExecutor, tool orchestration |
| lsp | `src/services/lsp/` | 6 | Medium | Language server lifecycle |
| oauth | `src/services/oauth/` | 5 | Medium | OAuth2 authentication flow |
| plugins | `src/services/plugins/` | 3 | Medium | Plugin installation & operations |
| SessionMemory | `src/services/SessionMemory/` | 3 | Medium | Session memory extraction/injection |
| autoDream | `src/services/autoDream/` | 4 | Medium | Background dream consolidation |
## Essential Files for Understanding the Codebase (Top 15)
1. `src/Tool.ts` — Tool type contract + ToolUseContext
2. `src/QueryEngine.ts` — Headless conversation lifecycle
3. `src/query.ts` — Inner agentic loop
4. `src/bootstrap/state.ts` — Global singleton state
5. `src/commands.ts` — Command registry
6. `src/state/store.ts` — Minimal pub/sub store (35 lines, best starting point)
7. `src/state/AppStateStore.ts` — AppState type definition
8. `src/screens/REPL.tsx` — Interactive session orchestrator
9. `src/tools/AgentTool/runAgent.ts` — Recursive sub-agent invocation
10. `src/tools/BashTool/BashTool.tsx` — Most security-sensitive tool
11. `src/hooks/useCanUseTool.tsx` — Central permission decision point
12. `src/services/api/claude.ts` — Anthropic API streaming client
13. `src/services/compact/autoCompact.ts` — Context window management
14. `src/types/permissions.ts` — Permission type definitions (9-variant union)
15. `src/context.ts` — CLAUDE.md loading & system context injectionTool Call: Write docs\analysis\risk-assessment.md Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\analysis\risk-assessment.md
# Claude Code - Risk Assessment & Teaching Complexity Analysis
## Coding Conventions
### Naming Conventions
- **Files**: PascalCase for classes/components (`BashTool.tsx`, `QueryEngine.ts`), camelCase for utilities (`processUserInput.ts`)
- **Directories**: PascalCase for tool/component directories (`AgentTool/`, `FileEditTool/`), camelCase for utility modules (`settings/`, `permissions/`)
- **Types**: PascalCase, often with descriptive suffixes (`ToolUseContext`, `PermissionDecisionReason`, `TaskStateBase`)
- **Functions**: camelCase, verb-first (`buildTool()`, `findToolByName()`, `getSystemPrompt()`)
- **Constants**: SCREAMING_SNAKE_CASE (`REMOTE_SAFE_COMMANDS`, `INTERNAL_ONLY_COMMANDS`)
### File Organization Patterns
- Each tool: `XxxTool.ts(x)` (core) + `prompt.ts` (model description) + `UI.tsx` (render) + `constants.ts`
- Each command: sub-directory with `index.ts` or `command-name.ts`
- Root-level files serve as "barrel" re-exports or top-level orchestrators
- `types/` directory breaks circular import cycles
### TypeScript Patterns
- **Zod v4** for runtime schema validation (tool inputs, settings)
- **Discriminated unions** for `Command` (3 variants), `PermissionDecisionReason` (9 variants), `TaskType` (7 variants)
- **Branded types** for `SessionId`, `AgentId` via `ids.ts`
- **DeepImmutable<>** wrapper for `AppState` to enforce immutable updates
- **AsyncGenerator** for streaming data flow (`query()`, `submitMessage()`)
- **`feature()` from `bun:bundle`** for compile-time dead code elimination
- **`memoize` from lodash-es** for caching expensive computations
## Key Design Patterns
### 1. Builder/Factory Pattern: `buildTool()`
- Location: `src/Tool.ts`
- Every tool is constructed via `buildTool(def)`, which merges defaults for optional methods
- The `ToolDef` type defines what implementors must/may provide; `Tool` is the fully-resolved type
### 2. Dependency Injection: `ToolUseContext`
- Location: `src/Tool.ts`
- A 40+ field context object passed through the entire tool call chain as function arguments
- Avoids global state; different modes (REPL/SDK/sub-agent) provide different field subsets
- This is NOT a traditional DI container; it's a large "environment" bag
### 3. AsyncGenerator/Coroutine Pattern
- Location: `src/query.ts`, `src/QueryEngine.ts`
- `query()` and `submitMessage()` are both `AsyncGenerator` functions
- Enables backpressure-aware streaming consumption
- Natural fit for "produce events as they happen" model
### 4. Observer/Pub-Sub Pattern
- Location: `src/state/store.ts`
- 35-line Zustand-style store: `createStore<T>()` -> `{ getState, setState, subscribe }`
- React integration via `useSyncExternalStore` in `src/state/AppState.tsx`
### 5. Command Pattern (Discriminated Union)
- Location: `src/types/command.ts`
- Three command variants: `PromptCommand`, `LocalCommand`, `LocalJSXCommand`
- Dispatched by `type` field in the command registry
### 6. Strategy Pattern: Permission Handlers
- Location: `src/hooks/useCanUseTool.tsx`
- Three-way handler chain: coordinator -> swarm worker -> interactive
- Selection based on runtime context (is coordinator? is swarm worker? is interactive?)
### 7. Decorator Pattern
- Location: `src/QueryEngine.ts`
- `wrappedCanUseTool` wraps the original `canUseTool` to append permission denial records
### 8. Plugin/Extension Pattern
- Location: `src/skills/`, `src/plugins/`, `src/services/mcp/`
- Skills: Markdown files with YAML frontmatter -> dynamic `Command` generation
- Plugins: Structured packages providing MCP servers, slash commands, hooks
- MCP: External tool servers connected via stdio/SSE/HTTP/WebSocket
## Complexity Hotspots (Teaching Difficulty Ranking)
### Critical Complexity (Require Dedicated Chapters)
**1. `src/main.tsx` — The God Function**
- ~4000+ lines in a single file
- Contains ALL CLI argument parsing, ALL run mode branches, ALL precondition validation
- Teaching approach: Draw a mode branch tree first, then deep-dive per-branch
**2. `src/query.ts` — The Agentic Loop**
- `while(true)` loop with 7 `continue` paths
- Implicit state machine: auto-compact, max-token recovery, reactive compact, etc.
- No explicit state machine definition; trigger conditions scattered across conditionals
**3. `src/tools/BashTool/bashPermissions.ts` — 2600-line Permission Engine**
- Wildcard matching, command parsing, speculative classifier
- The single most complex file in the tools/ directory
**4. `src/ink/` — Custom React Reconciler**
- Complete TUI framework: reconciler, Yoga WASM layout, ANSI rendering, terminal I/O
- ~85 files implementing a full React renderer targeting terminal output
- Requires deep React internals knowledge to understand
**5. `src/screens/REPL.tsx` — The Interactive Session**
- ~3000+ lines orchestrating all UI interactions
- Manages message display, user input, permission dialogs, task panels, teammate views
### High Complexity (Substantial Explanation Needed)
**6. `src/hooks/useCanUseTool.tsx` — Permission Decision Tree**
- Multi-layer async race: coordinator -> swarm -> speculative classifier (2s timeout) -> interactive dialog
- `Promise.race` with timeout, multiple fallback paths
- Note: File is React Compiler output, harder to read than source
**7. `src/QueryEngine.ts::submitMessage()` — ~900 lines**
- Single async generator function containing transcript persistence, budget checks, snip compaction, message dispatch
- Multiple interleaved concerns in one function
**8. `src/bootstrap/state.ts` — Global Mutable Singleton**
- 80+ getter/setter functions, implicit temporal coupling
- Some getters return uninitialized values before `init()` completes
**9. `src/Tool.ts::ToolUseContext` — 40+ Field Context Object**
- Optional fields mean different modes provide different subsets
- No type-level enforcement of which fields exist in which mode
### Medium Complexity (Moderate Explanation)
**10. `src/commands.ts` — Feature Flag Conditional Loading**
- `feature('FLAG') ? require('./module') : null` pattern breaks static analysis
- 70+ commands with dynamic skill/plugin merging
**11. `src/services/mcp/` — MCP Client Management**
- 4 transport types (stdio, SSE, HTTP, WebSocket)
- OAuth authentication, tool/resource enumeration
**12. `src/services/compact/` — Context Window Management**
- Auto-compact, micro-compact, snip strategies
- Critical for understanding how Claude Code handles long conversations
## Teaching-Relevant "Aha Moments"
These are the non-obvious architectural decisions that will create the biggest learning impact:
1. **The AsyncGenerator Pipeline**: Why `query()` is a generator, not a callback/promise — it enables natural backpressure and streaming without complex event emitter wiring
2. **ToolUseContext as "Everything Bag"**: Why a single 40-field object instead of 10 smaller interfaces — pragmatic trade-off for a system where most tools need most context
3. **The 35-Line Store**: How `src/state/store.ts` achieves Zustand-like functionality in 35 lines, and why the team chose this over a library
4. **buildTool() Factory**: How a single factory function with TypeScript generics ensures every tool implements the full `Tool` interface while making most methods optional
5. **Compile-Time Feature Flags**: How `bun:bundle`'s `feature()` enables dead code elimination at build time while GrowthBook provides runtime overrides
6. **Permission Decision Cascade**: The 9-variant `PermissionDecisionReason` union that traces exactly why every permission decision was made — a lesson in auditability
7. **Recursive Agent Architecture**: How `AgentTool` calls `query()` recursively to create sub-agents, sharing some context (file cache) while isolating others (message history)
8. **Custom React Reconciler for Terminal**: Why Anthropic built their own Ink fork instead of using the npm package — performance and control needs for a production CLI tool
## Risks for Teaching Guide Creation
### Content Organization Risks
**R1: main.tsx is too large to explain linearly**
- Mitigation: Break into "mode branches" and explain each as a separate path through the function
**R2: React Compiler output files are unreadable**
- Affected: `AppState.tsx`, `useCanUseTool.tsx`
- Mitigation: Explain the pre-compilation logic; reference source maps embedded in file footers
**R3: Circular dependency patterns**
- The `types/` directory exists specifically to break cycles
- Teaching must explain why certain types live in `types/` vs their "natural" module
**R4: Feature flag dead code**
- Readers may be confused by code blocks wrapped in `feature('FLAG')` that are never reachable in open-source builds
- Mitigation: Explain the DCE system early, mark feature-gated code clearly
### Scope Risks
**R5: utils/ is 564 files — cannot cover exhaustively**
- Strategy: Cover key sub-areas (bash/, permissions/, settings/, swarm/, model/) and provide a directory map for the rest
**R6: components/ is 389 files — UI coverage needs scoping**
- Strategy: Focus on message rendering pipeline, permission dialogs, and the design system; treat rest as referenceAssistant
Phase 1 完成。现在进入 Phase 2: 章节任务分解与学习路径设计。
基于分析结果,我来设计按学习路径组织的章节结构。核心思路是:从宏观到微观,从启动入口到深层机制,从简单概念到复杂交互。
Tool Call: mkdir -p "D:/code/play/stock_ai_rust/claude-code/docs/plan" Status: Completed
Terminal:
(Bash completed with no output)Tool Call: Write docs\plan\task-breakdown.md Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\plan\task-breakdown.md
# Task Breakdown: Claude Code Source Teaching Guide
## Chapter Plan (Learning Path Order)
The guide is organized in 4 phases, progressing from high-level overview to deep internals.
---
## Phase 1: Foundation (Chapters 1-4)
Build the reader's mental model of what Claude Code is, how it starts, and the core abstractions.
### Chapter 1: Project Overview & Architecture
- **ID**: CH01
- **CN Title**: 第1章 - 项目总览与架构设计
- **EN Title**: Chapter 01 - Project Overview & Architecture
- **Priority**: P0
- **Effort**: L
- **Dependencies**: None
- **Core/Brief**: CORE
- **Content Outline**:
- What is Claude Code? (CLI-based AI coding agent)
- Technology stack overview (TypeScript, React, Bun, Ink, Zod)
- Directory structure walkthrough (all 35 modules with one-line descriptions)
- Architecture diagram: Event-driven AsyncGenerator Pipeline
- Data flow overview: User input -> query loop -> API -> tools -> result
- Key configuration: CLAUDE.md, settings.json, feature flags
- **Key Files**: project root, `src/` directory listing
- **Acceptance Criteria**: Reader can explain the overall architecture and locate any module by purpose
### Chapter 2: Startup & Bootstrap
- **ID**: CH02
- **CN Title**: 第2章 - 启动流程与初始化
- **EN Title**: Chapter 02 - Startup & Bootstrap
- **Priority**: P0
- **Effort**: L
- **Dependencies**: CH01
- **Core/Brief**: CORE
- **Content Outline**:
- Entry point: `src/entrypoints/cli.tsx` (fast-path dispatcher)
- Initialization: `src/entrypoints/init.ts` (two-phase: pre/post trust dialog)
- Global state: `src/bootstrap/state.ts` (singleton pattern, 80+ getters/setters)
- Main function: `src/main.tsx` (Commander.js args, mode branching)
- Mode tree: Interactive REPL vs Headless vs MCP Server vs Remote vs Print
- ToolUseContext assembly (the DI "everything bag")
- REPL launch: `src/replLauncher.tsx` -> React/Ink rendering
- **Key Files**: `entrypoints/cli.tsx`, `entrypoints/init.ts`, `bootstrap/state.ts`, `main.tsx`, `replLauncher.tsx`
- **Acceptance Criteria**: Reader can trace the full startup path from CLI invocation to REPL rendering
### Chapter 3: Core Type System
- **ID**: CH03
- **CN Title**: 第3章 - 核心类型体系
- **EN Title**: Chapter 03 - Core Type System
- **Priority**: P0
- **Effort**: M
- **Dependencies**: CH01
- **Core/Brief**: CORE
- **Content Outline**:
- `Tool<Input, Output>` interface (the universal tool contract)
- `ToolUseContext` (40+ field dependency injection object)
- `buildTool()` factory function (Builder pattern with TypeScript generics)
- `Command` discriminated union (3 variants: Prompt/Local/LocalJSX)
- `Task` and `TaskType` (7 task types, 5 status states)
- `PermissionMode`, `PermissionResult`, `PermissionDecisionReason` (9-variant union)
- `AppState` (150+ field DeepImmutable state)
- Branded types: `SessionId`, `AgentId`
- Zod v4 usage for runtime schema validation
- **Key Files**: `Tool.ts`, `Task.ts`, `types/command.ts`, `types/permissions.ts`, `state/AppStateStore.ts`, `types/ids.ts`
- **Acceptance Criteria**: Reader understands all core type contracts and how they interconnect
### Chapter 4: State Management
- **ID**: CH04
- **CN Title**: 第4章 - 状态管理机制
- **EN Title**: Chapter 04 - State Management
- **Priority**: P0
- **Effort**: M
- **Dependencies**: CH03
- **Core/Brief**: CORE
- **Content Outline**:
- Two-tier state architecture: bootstrap (process-level) vs AppState (React-level)
- `src/state/store.ts`: The 35-line Zustand-style store (createStore, getState, setState, subscribe)
- `src/state/AppStateStore.ts`: AppState type definition (150+ fields)
- `src/state/AppState.tsx`: React Context Provider + useSyncExternalStore
- `src/state/selectors.ts`: State selectors
- `src/state/onChangeAppState.ts`: Side effect handlers
- `src/bootstrap/state.ts`: Global singleton (when to use which state tier)
- Immutability enforcement via DeepImmutable<>
- **Key Files**: `state/store.ts`, `state/AppStateStore.ts`, `state/AppState.tsx`, `bootstrap/state.ts`
- **Acceptance Criteria**: Reader can explain the dual-tier state model and implement a new state field
---
## Phase 2: Core Mechanics (Chapters 5-9)
Deep dive into the engine that powers Claude Code's AI agent behavior.
### Chapter 5: The Agentic Loop
- **ID**: CH05
- **CN Title**: 第5章 - Agent 循环引擎
- **EN Title**: Chapter 05 - The Agentic Loop
- **Priority**: P0
- **Effort**: XL
- **Dependencies**: CH03, CH04
- **Core/Brief**: CORE
- **Content Outline**:
- `src/query.ts`: The `query()` async generator (while(true) loop)
- 7 continue paths: auto-compact, max-token recovery, reactive compact, etc.
- `src/query/config.ts`: QueryConfig assembly
- `src/query/stopHooks.ts`: Post-response hooks
- `src/query/tokenBudget.ts`: Per-turn token limits
- `src/services/api/claude.ts`: Anthropic API streaming client
- Message format: system prompt + conversation history + tool results
- Streaming events: how tool_use blocks trigger execution
- Stop conditions: end_turn, max_tokens, tool_use
- **Key Files**: `query.ts`, `query/`, `services/api/claude.ts`
- **Acceptance Criteria**: Reader can trace a complete API call cycle and explain all 7 continue paths
### Chapter 6: Tool System Deep Dive
- **ID**: CH06
- **CN Title**: 第6章 - 工具系统深度剖析
- **EN Title**: Chapter 06 - Tool System Deep Dive
- **Priority**: P0
- **Effort**: XL
- **Dependencies**: CH03, CH05
- **Core/Brief**: CORE
- **Content Outline**:
- Tool lifecycle: registration -> selection -> permission check -> execution -> result rendering
- `src/tools.ts`: Tool registry assembly (feature-flag conditional)
- `buildTool()` deep dive: how generics ensure type safety
- Tool anatomy (using FileReadTool as simple example):
- Input schema (Zod)
- `call()` implementation
- `checkPermissions()`
- `renderToolUseMessage()` / `renderToolResultMessage()`
- `prompt.ts` (model-visible description)
- BashTool deep dive: the most complex tool
- `bashPermissions.ts` (2600 lines): command parsing, wildcard matching, speculative classifier
- Security model: sandbox, sed detection, env protection
- Tool orchestration: `services/tools/toolOrchestration.ts`, `StreamingToolExecutor`
- **Key Files**: `tools.ts`, `Tool.ts`, `tools/FileReadTool/`, `tools/BashTool/`, `services/tools/`
- **Acceptance Criteria**: Reader can implement a new custom tool from scratch following the buildTool() pattern
### Chapter 7: Permission System
- **ID**: CH07
- **CN Title**: 第7章 - 权限与安全模型
- **EN Title**: Chapter 07 - Permission & Security Model
- **Priority**: P0
- **Effort**: L
- **Dependencies**: CH06
- **Core/Brief**: CORE
- **Content Outline**:
- Permission modes: 5 modes defined in `types/permissions.ts`
- Permission rule evaluation: `utils/permissions/`
- `useCanUseTool.tsx`: The central decision point
- Rule check -> allow/deny/ask
- Coordinator permission -> Swarm worker -> Speculative classifier (2s race) -> Interactive dialog
- `PermissionDecisionReason`: 9-variant audit trail
- Settings-based permissions: allow/deny lists in settings.json
- Hook-based permissions: PreToolUse/PostToolUse hooks
- BashTool-specific: command analysis, auto-approval classifier
- **Key Files**: `types/permissions.ts`, `hooks/useCanUseTool.tsx`, `utils/permissions/`, `tools/BashTool/bashPermissions.ts`
- **Acceptance Criteria**: Reader can trace a permission decision through all 9 possible reasons
### Chapter 8: Command System
- **ID**: CH08
- **CN Title**: 第8章 - 命令系统
- **EN Title**: Chapter 08 - Command System
- **Priority**: P1
- **Effort**: M
- **Dependencies**: CH03
- **Core/Brief**: CORE
- **Content Outline**:
- Command types: PromptCommand, LocalCommand, LocalJSXCommand
- `src/commands.ts`: Registry assembly (70+ commands, feature-flag gating)
- Command discovery: `findCommand()`, `meetsAvailabilityRequirement()`
- User input processing: `utils/processUserInput/processUserInput.ts`
- Example commands by category:
- Session: /clear, /compact, /resume
- Config: /config, /permissions, /model
- Info: /cost, /context, /doctor, /help
- How to add a new command
- **Key Files**: `commands.ts`, `types/command.ts`, `commands/` (selected examples), `utils/processUserInput/`
- **Acceptance Criteria**: Reader understands all 3 command types and can add a new slash command
### Chapter 9: QueryEngine & SDK Interface
- **ID**: CH09
- **CN Title**: 第9章 - QueryEngine 与 SDK 接口
- **EN Title**: Chapter 09 - QueryEngine & SDK Interface
- **Priority**: P1
- **Effort**: L
- **Dependencies**: CH05
- **Core/Brief**: CORE
- **Content Outline**:
- `QueryEngine` class: session state management
- `submitMessage()`: ~900-line async generator
- Message preprocessing
- Budget checking
- Query loop invocation
- SDKMessage emission (mapping StreamEvent -> SDKMessage)
- Transcript persistence
- Snip compaction
- `ask()`: One-shot convenience wrapper
- SDK types: `src/entrypoints/sdk/` (core/control/runtime split)
- `src/entrypoints/agentSdkTypes.ts`: Public type surface
- Headless mode vs Interactive mode differences
- **Key Files**: `QueryEngine.ts`, `entrypoints/sdk/`, `entrypoints/agentSdkTypes.ts`
- **Acceptance Criteria**: Reader can use QueryEngine programmatically and understands the SDK type surface
---
## Phase 3: UI & Interaction Layer (Chapters 10-13)
How Claude Code renders its terminal interface and handles user interaction.
### Chapter 10: Custom Ink Framework
- **ID**: CH10
- **CN Title**: 第10章 - 自研终端 UI 框架 (Ink)
- **EN Title**: Chapter 10 - Custom Terminal UI Framework (Ink)
- **Priority**: P1
- **Effort**: XL
- **Dependencies**: CH04
- **Core/Brief**: CORE
- **Content Outline**:
- Why a custom Ink fork? (performance, control, production CLI needs)
- React Reconciler: `src/ink/reconciler.ts` (custom fiber implementation)
- Layout engine: `src/ink/layout/` (Yoga WASM, CSS Flexbox for terminal)
- Rendering pipeline: virtual DOM -> layout -> ANSI escape codes
- Terminal I/O: `src/ink/termio/` (input parsing, key events, mouse)
- Focus management, virtual scrolling, text wrapping
- Component primitives: Box, Text, and custom terminal components
- **Key Files**: `ink/reconciler.ts`, `ink/layout/`, `ink/termio/`, `ink/render.ts`
- **Acceptance Criteria**: Reader understands how React components become terminal output
### Chapter 11: REPL & Interactive Session
- **ID**: CH11
- **CN Title**: 第11章 - REPL 交互式会话
- **EN Title**: Chapter 11 - REPL & Interactive Session
- **Priority**: P1
- **Effort**: L
- **Dependencies**: CH10, CH05
- **Core/Brief**: CORE
- **Content Outline**:
- `src/screens/REPL.tsx`: The main interactive component (~3000 lines)
- Message display pipeline: query events -> message batching -> virtual list
- User input: PromptInput component, typeahead, vim mode
- Permission dialogs: how tool permission requests become UI dialogs
- Task panels: background task monitoring
- Teammate views: multi-agent visual coordination
- Transcript search and navigation
- **Key Files**: `screens/REPL.tsx`, `components/PromptInput/`, `components/messages/`, `components/permissions/`
- **Acceptance Criteria**: Reader can trace user input through the REPL to tool execution and result display
### Chapter 12: Component Library
- **ID**: CH12
- **CN Title**: 第12章 - 组件库与设计系统
- **EN Title**: Chapter 12 - Component Library & Design System
- **Priority**: P2
- **Effort**: M
- **Dependencies**: CH10
- **Core/Brief**: Brief
- **Content Outline**:
- Component organization: messages/, permissions/, design-system/, agents/, mcp/
- Design system primitives: Dialog, Tabs, FuzzyPicker, ThemedBox
- Message rendering: how different message types get rendered
- Permission dialog patterns: per-tool permission UI
- Theme system
- Key component walkthroughs (2-3 representative examples)
- **Key Files**: `components/design-system/`, `components/messages/`, `components/permissions/`
- **Acceptance Criteria**: Reader knows where to find any component and understands the design patterns
### Chapter 13: Hooks Layer
- **ID**: CH13
- **CN Title**: 第13章 - Hooks 层:业务逻辑桥梁
- **EN Title**: Chapter 13 - Hooks Layer: Business Logic Bridge
- **Priority**: P1
- **Effort**: M
- **Dependencies**: CH11
- **Core/Brief**: CORE
- **Content Outline**:
- Role of hooks: wiring business logic to the REPL UI
- `useCanUseTool.tsx`: Central permission hook (recap from CH07 with UI perspective)
- `useLogMessages.ts`: Message batching from query loop to React state
- `useCommandQueue.ts`: Slash command processing
- `useTextInput.ts`: Prompt input state management
- `useTypeahead.tsx`: Command/file completion
- `useReplBridge.tsx`: Remote bridge sync
- `toolPermission/`: Coordinator, interactive, swarm permission handlers
- **Key Files**: `hooks/useCanUseTool.tsx`, `hooks/useLogMessages.ts`, `hooks/useCommandQueue.ts`, `hooks/toolPermission/`
- **Acceptance Criteria**: Reader understands the hooks as the bridge between business logic and UI
---
## Phase 4: Extension & Advanced (Chapters 14-20)
Services, extensions, and advanced features.
### Chapter 14: Context & System Prompt
- **ID**: CH14
- **CN Title**: 第14章 - 上下文构建与系统提示
- **EN Title**: Chapter 14 - Context Construction & System Prompt
- **Priority**: P1
- **Effort**: M
- **Dependencies**: CH05
- **Core/Brief**: CORE
- **Content Outline**:
- `src/context.ts`: getUserContext(), getSystemContext()
- CLAUDE.md loading: hierarchical (project > user > global)
- `src/constants/prompts.ts`: getSystemPrompt() builder
- Memory injection: `src/memdir/` (per-project memory files)
- Context window management: `src/services/compact/`
- Auto-compact, micro-compact, snip strategies
- When and how conversations get compressed
- **Key Files**: `context.ts`, `constants/prompts.ts`, `memdir/`, `services/compact/`
- **Acceptance Criteria**: Reader understands how the system prompt is assembled and how context stays within limits
### Chapter 15: MCP Integration
- **ID**: CH15
- **CN Title**: 第15章 - MCP 协议集成
- **EN Title**: Chapter 15 - MCP Protocol Integration
- **Priority**: P1
- **Effort**: L
- **Dependencies**: CH06
- **Core/Brief**: CORE
- **Content Outline**:
- What is MCP? Model Context Protocol overview
- `src/services/mcp/`: Client management
- 4 transport types: stdio, SSE, HTTP, WebSocket
- Server discovery, OAuth authentication
- Tool/resource enumeration from MCP servers
- `src/tools/MCPTool/`: How MCP tools become Claude Code tools
- Permission scoping for MCP tools
- **Key Files**: `services/mcp/`, `tools/MCPTool/`
- **Acceptance Criteria**: Reader can explain how external MCP servers extend Claude Code's capabilities
### Chapter 16: Sub-Agent & Multi-Agent
- **ID**: CH16
- **CN Title**: 第16章 - 子 Agent 与多 Agent 协作
- **EN Title**: Chapter 16 - Sub-Agent & Multi-Agent Coordination
- **Priority**: P0
- **Effort**: L
- **Dependencies**: CH05, CH06
- **Core/Brief**: CORE
- **Content Outline**:
- AgentTool: `src/tools/AgentTool/`
- `runAgent.ts`: Context forking, MCP connection, recursive query() loop
- `createSubagentContext()`: Which fields are cloned vs shared
- Memory snapshots and resume
- Coordinator Mode: `src/coordinator/coordinatorMode.ts`
- Swarm coordination: `src/utils/swarm/`
- Teammate spawning backends (iTerm, Tmux, In-Process)
- Task system: `src/tasks/` (7 task types)
- InProcessTeammateTask: full sub-REPL in same process
- LocalAgentTask, RemoteAgentTask
- Permission proxy: worker -> leader permission bridge
- **Key Files**: `tools/AgentTool/`, `coordinator/`, `utils/swarm/`, `tasks/`
- **Acceptance Criteria**: Reader understands the full multi-agent architecture and permission delegation model
### Chapter 17: Skills & Plugin System
- **ID**: CH17
- **CN Title**: 第17章 - Skills 与插件系统
- **EN Title**: Chapter 17 - Skills & Plugin System
- **Priority**: P1
- **Effort**: M
- **Dependencies**: CH08
- **Core/Brief**: CORE
- **Content Outline**:
- Skills: Markdown-driven prompt commands
- `src/skills/loadSkillsDir.ts`: File scanning, frontmatter parsing
- `src/skills/bundledSkills.ts`: Built-in skills
- YAML frontmatter: whenToUse, paths, hooks, model, effort
- Skill invocation via SkillTool
- Plugins: Structured extension packages
- `src/plugins/`: Registration
- `src/services/plugins/`: Installation, operations
- Plugin capabilities: MCP servers, slash commands, hooks
- How skills and plugins merge into the command registry
- **Key Files**: `skills/`, `plugins/`, `services/plugins/`, `tools/SkillTool/`
- **Acceptance Criteria**: Reader can create a custom skill and understands the plugin architecture
### Chapter 18: Services Layer
- **ID**: CH18
- **CN Title**: 第18章 - 服务层:API、分析与 LSP
- **EN Title**: Chapter 18 - Services Layer: API, Analytics & LSP
- **Priority**: P2
- **Effort**: M
- **Dependencies**: CH05
- **Core/Brief**: Brief
- **Content Outline**:
- `services/api/`: Anthropic API client details
- BetaMessageStreamParams assembly
- Provider support: Bedrock, Vertex AI
- Retry logic, usage tracking, cost calculation
- `services/analytics/`: GrowthBook + Datadog + first-party events
- `services/lsp/`: Language Server Protocol integration
- `services/oauth/`: OAuth2 authentication flow
- `services/SessionMemory/`: Session memory extraction
- `services/autoDream/`: Background consolidation
- **Key Files**: `services/api/`, `services/analytics/`, `services/lsp/`, `services/oauth/`
- **Acceptance Criteria**: Reader has a map of all service modules and their responsibilities
### Chapter 19: Settings, Configuration & Hooks
- **ID**: CH19
- **CN Title**: 第19章 - 配置系统与 Hooks 机制
- **EN Title**: Chapter 19 - Settings, Configuration & Hooks
- **Priority**: P1
- **Effort**: M
- **Dependencies**: CH03
- **Core/Brief**: CORE
- **Content Outline**:
- Multi-source settings merge:
- User: `~/.claude/settings.json`
- Project: `.claude/settings.json`
- Enterprise: MDM/HKCU
- CLI flags, remote hosted
- `src/utils/settings/`: Zod schema validation, merge logic
- Hooks system:
- `src/types/hooks.ts`: 9 hook event types
- `src/schemas/hooks.ts`: Zod schema
- `src/utils/hooks/`: Hook execution engine
- PreToolUse, PostToolUse, PostSampling hooks
- Keybindings: `src/keybindings/` (custom shortcuts)
- **Key Files**: `utils/settings/`, `types/hooks.ts`, `schemas/hooks.ts`, `utils/hooks/`, `keybindings/`
- **Acceptance Criteria**: Reader understands the full configuration hierarchy and can implement a custom hook
### Chapter 20: Peripheral Features & Utilities
- **ID**: CH20
- **CN Title**: 第20章 - 周边功能与工具集
- **EN Title**: Chapter 20 - Peripheral Features & Utilities
- **Priority**: P2
- **Effort**: M
- **Dependencies**: CH01
- **Core/Brief**: Brief
- **Content Outline**:
- Bridge: `src/bridge/` (remote control from mobile/web)
- CLI transports: `src/cli/` (SSE, WebSocket, structured IO)
- Remote sessions: `src/remote/` (CCR integration)
- Direct Connect: `src/server/` (Unix domain socket)
- Vim mode: `src/vim/` (vi motions, operators, state machine)
- Migrations: `src/migrations/` (settings data migration)
- Utils overview: `src/utils/` (564 files, key sub-areas map)
- bash/, permissions/, plugins/, settings/, swarm/, model/, telemetry/
- Buddy, voice, outputStyles, native-ts (brief mentions)
- **Key Files**: `bridge/`, `cli/`, `remote/`, `server/`, `vim/`, `utils/` (overview)
- **Acceptance Criteria**: Reader has a reference map for all peripheral features
---
## Parallel Execution Lanes
### Phase 1 (Foundation)
- **Lane A**: CH01 (no deps)
- **Lane B**: CH02 (after CH01)
- **Lane C**: CH03 (after CH01) — can run parallel with CH02
- **Lane D**: CH04 (after CH03)
- Merge risk: **Low** (chapters are independent files)
### Phase 2 (Core Mechanics)
- **Lane A**: CH05 (after CH03, CH04)
- **Lane B**: CH08 (after CH03) — can start parallel with CH05
- **Lane C**: CH06 (after CH03, CH05) -> CH07 (after CH06)
- **Lane D**: CH09 (after CH05)
- Merge risk: **Low**
### Phase 3 (UI & Interaction)
- **Lane A**: CH10 (after CH04) -> CH12 (after CH10)
- **Lane B**: CH11 (after CH10, CH05) -> CH13 (after CH11)
- Merge risk: **Low**
### Phase 4 (Extension & Advanced)
- **Lane A**: CH14 (after CH05), CH18 (after CH05) — parallel
- **Lane B**: CH15 (after CH06), CH16 (after CH05, CH06) — sequential
- **Lane C**: CH17 (after CH08), CH19 (after CH03) — parallel
- **Lane D**: CH20 (after CH01) — independent
- Merge risk: **Low**
---
## Effort Summary
| Effort | Count | Chapters |
|--------|-------|----------|
| S | 0 | — |
| M | 8 | CH03, CH04, CH08, CH12, CH13, CH17, CH18, CH19 |
| L | 7 | CH01, CH02, CH07, CH09, CH15, CH16, CH20 |
| XL | 3 | CH05, CH06, CH10 |
Total: 20 chapters (12 CN + 12 EN files = 40 markdown files)Tool Call: Write docs\plan\dependency-graph.md Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\plan\dependency-graph.md
# Dependency Graph
```mermaid
graph TD
subgraph "Phase 1: Foundation"
CH01["CH01: Project Overview"]
CH02["CH02: Startup & Bootstrap"]
CH03["CH03: Core Type System"]
CH04["CH04: State Management"]
end
subgraph "Phase 2: Core Mechanics"
CH05["CH05: Agentic Loop"]
CH06["CH06: Tool System"]
CH07["CH07: Permission System"]
CH08["CH08: Command System"]
CH09["CH09: QueryEngine & SDK"]
end
subgraph "Phase 3: UI & Interaction"
CH10["CH10: Ink Framework"]
CH11["CH11: REPL Session"]
CH12["CH12: Component Library"]
CH13["CH13: Hooks Layer"]
end
subgraph "Phase 4: Extension & Advanced"
CH14["CH14: Context & Prompt"]
CH15["CH15: MCP Integration"]
CH16["CH16: Multi-Agent"]
CH17["CH17: Skills & Plugins"]
CH18["CH18: Services Layer"]
CH19["CH19: Settings & Hooks"]
CH20["CH20: Peripheral Features"]
end
CH01 --> CH02
CH01 --> CH03
CH03 --> CH04
CH03 --> CH05
CH04 --> CH05
CH03 --> CH06
CH05 --> CH06
CH06 --> CH07
CH03 --> CH08
CH05 --> CH09
CH04 --> CH10
CH10 --> CH11
CH05 --> CH11
CH10 --> CH12
CH11 --> CH13
CH05 --> CH14
CH06 --> CH15
CH05 --> CH16
CH06 --> CH16
CH08 --> CH17
CH03 --> CH19
CH05 --> CH18
CH01 --> CH20Parallel Execution Lanes
Phase 1
Lane A: CH01 ──────────────────────────>
Lane B: CH02 ──────────────────-> (after CH01)
Lane C: CH03 ────────> CH04 ───-> (after CH01)Phase 2
Lane A: CH05 ──────────────────────────> (after CH03+CH04)
Lane B: CH08 ──────────────────────────> (after CH03, parallel with CH05)
Lane C: CH06 ────────> CH07 ───-> (after CH05)
Lane D: CH09 ──────────────────-> (after CH05, parallel with CH06)Phase 3
Lane A: CH10 ────────> CH12 ──────────-> (after CH04)
Lane B: CH11 ────────> CH13 ───-> (after CH10+CH05)Phase 4
Lane A: CH14 + CH18 ──────────────────-> (after CH05, parallel)
Lane B: CH15 ────────> CH16 ──────────-> (after CH06)
Lane C: CH17 + CH19 ──────────────────-> (after CH08/CH03, parallel)
Lane D: CH20 ─────────────────────────-> (after CH01, independent)
**Tool Call: Write docs\plan\milestones.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\plan\milestones.mdMilestones
M1: Foundation Complete
- Target: Phase 1 (Chapters 1-4) all complete
- Criteria:
- [ ] CH01: Project overview & architecture (CN + EN)
- [ ] CH02: Startup & bootstrap (CN + EN)
- [ ] CH03: Core type system (CN + EN)
- [ ] CH04: State management (CN + EN)
- Deliverable: 8 markdown files in
books/ - Reader outcome: Can navigate the codebase, understand core types, and trace the startup flow
M2: Core Mechanics Complete
- Target: Phase 2 (Chapters 5-9) all complete
- Criteria:
- [ ] CH05: Agentic loop (CN + EN)
- [ ] CH06: Tool system deep dive (CN + EN)
- [ ] CH07: Permission & security model (CN + EN)
- [ ] CH08: Command system (CN + EN)
- [ ] CH09: QueryEngine & SDK (CN + EN)
- Deliverable: 10 markdown files in
books/ - Reader outcome: Understands the full query -> tool -> permission cycle and can extend it
M3: UI Layer Complete
- Target: Phase 3 (Chapters 10-13) all complete
- Criteria:
- [ ] CH10: Custom Ink framework (CN + EN)
- [ ] CH11: REPL interactive session (CN + EN)
- [ ] CH12: Component library (CN + EN)
- [ ] CH13: Hooks layer (CN + EN)
- Deliverable: 8 markdown files in
books/ - Reader outcome: Understands terminal rendering, UI architecture, and React hooks bridge
M4: Full Guide Complete
- Target: Phase 4 (Chapters 14-20) all complete
- Criteria:
- [ ] CH14: Context & system prompt (CN + EN)
- [ ] CH15: MCP integration (CN + EN)
- [ ] CH16: Sub-agent & multi-agent (CN + EN)
- [ ] CH17: Skills & plugin system (CN + EN)
- [ ] CH18: Services layer (CN + EN)
- [ ] CH19: Settings & hooks (CN + EN)
- [ ] CH20: Peripheral features (CN + EN)
- Deliverable: 14 markdown files in
books/ - Reader outcome: Complete understanding of Claude Code internals, can extend any part of the system
Summary
| Milestone | Chapters | Files | Cumulative |
|---|---|---|---|
| M1 | 4 | 8 | 8 |
| M2 | 5 | 10 | 18 |
| M3 | 4 | 8 | 26 |
| M4 | 7 | 14 | 40 |
| Total | 20 | 40 | 40 |
## Assistant
Phase 2 完成。现在进入 **Phase 3: 进度跟踪文档体系**。
**Tool Call: mkdir -p "D:/code/play/stock_ai_rust/claude-code/docs/progress"**
Status: Completed
Terminal:(Bash completed with no output)
**Tool Call: Write docs\progress\MASTER.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\progress\MASTER.mdMASTER Progress Tracker
Task Definition
Create a comprehensive, bilingual (CN+EN) Claude Code source code teaching guide in books/ directory. 20 chapters organized by learning path, covering all 1884 source files across 35 modules. Each chapter has separate CN and EN files (40 total files).
Analysis Documents
Plan Documents
Phase Summary
| Phase | Name | Tasks | Status |
|---|---|---|---|
| Phase 1 | Foundation (CH01-CH04) | 0/8 | Not Started |
| Phase 2 | Core Mechanics (CH05-CH09) | 0/10 | Not Started |
| Phase 3 | UI & Interaction (CH10-CH13) | 0/8 | Not Started |
| Phase 4 | Extension & Advanced (CH14-CH20) | 0/14 | Not Started |
- [ ] Phase 1: Foundation (0/8 tasks) details
- [ ] Phase 2: Core Mechanics (0/10 tasks) details
- [ ] Phase 3: UI & Interaction (0/8 tasks) details
- [ ] Phase 4: Extension & Advanced (0/14 tasks) details
Current Status
- Phase: Pre-development (preparation complete)
- Active Task: None — awaiting user confirmation to begin writing
- Last Updated: 2026-03-31
Next Steps
- User confirms readiness to begin development
- Start Phase 1, Lane A: CH01 (Project Overview)
- Parallel: CH01 CN + CH01 EN can be written simultaneously
**Tool Call: Write docs\progress\phase-1-foundation.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\progress\phase-1-foundation.mdPhase 1: Foundation (Chapters 1-4)
Tasks
CH01: Project Overview & Architecture
- [ ] CH01-CN: 第1章 - 项目总览与架构设计
- [ ] CH01-EN: Chapter 01 - Project Overview & Architecture
- Acceptance: Reader can explain the overall architecture and locate any module by purpose
CH02: Startup & Bootstrap
- [ ] CH02-CN: 第2章 - 启动流程与初始化
- [ ] CH02-EN: Chapter 02 - Startup & Bootstrap
- Acceptance: Reader can trace the full startup path from CLI invocation to REPL rendering
CH03: Core Type System
- [ ] CH03-CN: 第3章 - 核心类型体系
- [ ] CH03-EN: Chapter 03 - Core Type System
- Acceptance: Reader understands all core type contracts and how they interconnect
CH04: State Management
- [ ] CH04-CN: 第4章 - 状态管理机制
- [ ] CH04-EN: Chapter 04 - State Management
- Acceptance: Reader can explain the dual-tier state model and implement a new state field
Notes
- CH01 has no dependencies, can start immediately
- CH02 and CH03 can run in parallel after CH01
- CH04 depends on CH03
**Tool Call: Write docs\progress\phase-2-core-mechanics.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\progress\phase-2-core-mechanics.mdPhase 2: Core Mechanics (Chapters 5-9)
Tasks
CH05: The Agentic Loop
- [ ] CH05-CN: 第5章 - Agent 循环引擎
- [ ] CH05-EN: Chapter 05 - The Agentic Loop
- Acceptance: Reader can trace a complete API call cycle and explain all 7 continue paths
CH06: Tool System Deep Dive
- [ ] CH06-CN: 第6章 - 工具系统深度剖析
- [ ] CH06-EN: Chapter 06 - Tool System Deep Dive
- Acceptance: Reader can implement a new custom tool from scratch following the buildTool() pattern
CH07: Permission & Security Model
- [ ] CH07-CN: 第7章 - 权限与安全模型
- [ ] CH07-EN: Chapter 07 - Permission & Security Model
- Acceptance: Reader can trace a permission decision through all 9 possible reasons
CH08: Command System
- [ ] CH08-CN: 第8章 - 命令系统
- [ ] CH08-EN: Chapter 08 - Command System
- Acceptance: Reader understands all 3 command types and can add a new slash command
CH09: QueryEngine & SDK Interface
- [ ] CH09-CN: 第9章 - QueryEngine 与 SDK 接口
- [ ] CH09-EN: Chapter 09 - QueryEngine & SDK Interface
- Acceptance: Reader can use QueryEngine programmatically and understands the SDK type surface
Notes
- CH05 depends on CH03 + CH04
- CH08 can start parallel with CH05 (only needs CH03)
- CH06 depends on CH05 completion
- CH07 depends on CH06
- CH09 depends on CH05
**Tool Call: Write docs\progress\phase-3-ui-interaction.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\progress\phase-3-ui-interaction.mdPhase 3: UI & Interaction (Chapters 10-13)
Tasks
CH10: Custom Ink Framework
- [ ] CH10-CN: 第10章 - 自研终端 UI 框架 (Ink)
- [ ] CH10-EN: Chapter 10 - Custom Terminal UI Framework (Ink)
- Acceptance: Reader understands how React components become terminal output
CH11: REPL & Interactive Session
- [ ] CH11-CN: 第11章 - REPL 交互式会话
- [ ] CH11-EN: Chapter 11 - REPL & Interactive Session
- Acceptance: Reader can trace user input through the REPL to tool execution and result display
CH12: Component Library & Design System
- [ ] CH12-CN: 第12章 - 组件库与设计系统
- [ ] CH12-EN: Chapter 12 - Component Library & Design System
- Acceptance: Reader knows where to find any component and understands the design patterns
CH13: Hooks Layer
- [ ] CH13-CN: 第13章 - Hooks 层:业务逻辑桥梁
- [ ] CH13-EN: Chapter 13 - Hooks Layer: Business Logic Bridge
- Acceptance: Reader understands the hooks as the bridge between business logic and UI
Notes
- CH10 depends on CH04
- CH11 depends on CH10 + CH05
- CH12 can start parallel with CH11 (only needs CH10)
- CH13 depends on CH11
**Tool Call: Write docs\progress\phase-4-extension-advanced.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\docs\progress\phase-4-extension-advanced.mdPhase 4: Extension & Advanced (Chapters 14-20)
Tasks
CH14: Context & System Prompt
- [ ] CH14-CN: 第14章 - 上下文构建与系统提示
- [ ] CH14-EN: Chapter 14 - Context Construction & System Prompt
- Acceptance: Reader understands how the system prompt is assembled and how context stays within limits
CH15: MCP Integration
- [ ] CH15-CN: 第15章 - MCP 协议集成
- [ ] CH15-EN: Chapter 15 - MCP Protocol Integration
- Acceptance: Reader can explain how external MCP servers extend Claude Code's capabilities
CH16: Sub-Agent & Multi-Agent
- [ ] CH16-CN: 第16章 - 子 Agent 与多 Agent 协作
- [ ] CH16-EN: Chapter 16 - Sub-Agent & Multi-Agent Coordination
- Acceptance: Reader understands the full multi-agent architecture and permission delegation model
CH17: Skills & Plugin System
- [ ] CH17-CN: 第17章 - Skills 与插件系统
- [ ] CH17-EN: Chapter 17 - Skills & Plugin System
- Acceptance: Reader can create a custom skill and understands the plugin architecture
CH18: Services Layer
- [ ] CH18-CN: 第18章 - 服务层:API、分析与 LSP
- [ ] CH18-EN: Chapter 18 - Services Layer: API, Analytics & LSP
- Acceptance: Reader has a map of all service modules and their responsibilities
CH19: Settings, Configuration & Hooks
- [ ] CH19-CN: 第19章 - 配置系统与 Hooks 机制
- [ ] CH19-EN: Chapter 19 - Settings, Configuration & Hooks
- Acceptance: Reader understands the full configuration hierarchy and can implement a custom hook
CH20: Peripheral Features & Utilities
- [ ] CH20-CN: 第20章 - 周边功能与工具集
- [ ] CH20-EN: Chapter 20 - Peripheral Features & Utilities
- Acceptance: Reader has a reference map for all peripheral features
Notes
- CH14 and CH18 can run in parallel (both depend on CH05)
- CH15 depends on CH06; CH16 depends on CH05 + CH06
- CH17 and CH19 can run in parallel (depend on CH08/CH03)
- CH20 is independent (only needs CH01)
## Assistant
Phase 3 完成。进入 **Phase 4: 生成教学写作专用 Sub-SKILL**。
按照工作流要求,我需要确认 Sub-SKILL 的安装位置。考虑到这是项目级别的任务,我建议安装在项目本地。具体来说:
- **安装路径**: `D:\code\play\stock_ai_rust\claude-code\.claude\skills\write-teaching-chapter.md`
这样 SKILL 只在本项目中生效,任务完成后可以清理。我直接在这个路径创建。
**Tool Call: mkdir -p "D:/code/play/stock_ai_rust/claude-code/.claude/skills"**
Status: Completed
Terminal:(Bash completed with no output)
**Tool Call: Write .claude\skills\write-teaching-chapter.md**
Status: Completed
Diff: D:\code\play\stock_ai_rust\claude-code\.claude\skills\write-teaching-chapter.mdname: write-teaching-chapter description: Write bilingual (CN+EN) Claude Code source code teaching chapters. Use when continuing chapter writing work for the books/ directory. whenToUse: When the user asks to write, continue, or work on teaching guide chapters for Claude Code
Claude Code Teaching Guide Writer
You are writing a comprehensive, bilingual source code teaching guide for Claude Code. Each chapter has a CN file and an EN file in the books/ directory.
Before You Begin: Read MASTER.md
CRITICAL: At the start of EVERY conversation, read docs/progress/MASTER.md first. Identify:
- Which chapters are complete
- Which chapter is currently active
- What the next task is
Then read the relevant phase progress file to see detailed task status.
Chapter Writing Protocol
1. Pre-Writing Research
Before writing any chapter:
- Read the task breakdown in
docs/plan/task-breakdown.mdfor the chapter's content outline and key files - Read all key source files listed for that chapter
- Understand the code deeply before explaining it
2. Writing Standards
Chinese (CN) files:
- Filename:
第XX章-标题.md(e.g.,第01章-项目总览与架构设计.md) - Written entirely in Chinese, natural and engaging tone
- Code comments remain in English (as they are in the source)
- Technical terms: use Chinese explanation with English term in parentheses on first mention
- No emojis, no AI-sounding language
English (EN) files:
- Filename:
Chapter-XX-Title.md(e.g.,Chapter-01-Project-Overview-and-Architecture.md) - Written entirely in English, professional technical writing tone
- Clear, precise, avoid unnecessary jargon
Both languages:
- Heavy source code quoting with line-by-line explanation
- Use
file_path:line_numberreferences when citing code - Include architecture diagrams using Mermaid where helpful
- Code blocks must have language tags (typescript, tsx, etc.)
- Each chapter starts with a "What You'll Learn" section
- Each chapter ends with a "Key Takeaways" section
- Cross-reference other chapters where relevant (e.g., "See Chapter 7 for permission details")
3. Code Quoting Guidelines
- Quote actual source code, not paraphrased versions
- For long files (>100 lines), quote the most important sections and explain the structure of the rest
- Annotate code with inline comments explaining non-obvious logic
- When a function is complex, break it down step by step
- Show the type signatures first, then the implementation
4. Depth Control
CORE chapters: Deep, thorough coverage
- Full type definitions with field-by-field explanation
- Complete function walkthroughs for key functions
- Architectural decision explanations ("why this approach?")
- Data flow diagrams
- Edge cases and error handling
Brief chapters: Concise reference
- Module purpose and responsibility
- Key API surface (exports, main functions)
- Directory structure with one-line descriptions
- 2-3 representative code examples
- Pointers to where to look for more detail
5. Post-Writing Progress Update
After completing each file:
- Update the checkbox in the relevant
docs/progress/phase-N-*.mdfile - Update the task count in
docs/progress/MASTER.md - If all tasks in a phase are complete, mark the phase as complete in MASTER.md
6. Parallel Execution
When writing chapters, you may use task-executor sub-agents to write CN and EN versions simultaneously:
- Each agent gets: chapter ID, content outline, key files list, writing standards
- CN and EN files have no file overlap - safe to parallelize
- After both complete, verify cross-references are consistent between CN and EN versions
File Naming Convention
books/
第01章-项目总览与架构设计.md
Chapter-01-Project-Overview-and-Architecture.md
第02章-启动流程与初始化.md
Chapter-02-Startup-and-Bootstrap.md
...Quality Checklist (per chapter)
- [ ] All key files from task-breakdown.md have been read and referenced
- [ ] Source code quotes are accurate (copied from actual files, not paraphrased)
- [ ] Line numbers in references are correct
- [ ] Mermaid diagrams render correctly
- [ ] Cross-references to other chapters are accurate
- [ ] "What You'll Learn" and "Key Takeaways" sections present
- [ ] CN and EN versions cover the same content (not translations, but same scope)
- [ ] No emojis in either version
- [ ] Progress files updated
Cleanup Trigger
When ALL 40 files (20 chapters x 2 languages) are complete and all checkboxes in MASTER.md are checked, notify the user that the teaching guide is complete and initiate Phase 6 (Cleanup) from the spec-driven-develop workflow.
## Assistant
所有准备工作完成。进入 **Phase 5: 交付确认**。
---
## 准备工作总结
### 任务定义
在 `books/` 下创建 Claude Code 源码教学指南,20 章 x 2 语言 = 40 个 Markdown 文件,按学习路径从入口到深层机制循序渐进。
### 分析发现
- 源码规模:**1884 个 TypeScript/TSX 文件**,分布在 35 个模块中
- 架构模式:**事件驱动的 AsyncGenerator 管道** + 分层依赖注入
- 核心文件:15 个关键文件(Tool.ts、query.ts、QueryEngine.ts 等)
- 复杂度热点:main.tsx (4000+ 行)、BashTool 权限 (2600 行)、自研 Ink 框架 (85 文件)
### 章节计划 (4 阶段 20 章)
| 阶段 | 章节 | 定位 |
|------|------|------|
| **Phase 1: 基础** | CH01-04 | 项目总览、启动流程、核心类型、状态管理 |
| **Phase 2: 核心机制** | CH05-09 | Agent 循环、工具系统、权限模型、命令系统、QueryEngine |
| **Phase 3: UI 交互** | CH10-13 | Ink 框架、REPL、组件库、Hooks 层 |
| **Phase 4: 扩展进阶** | CH14-20 | 上下文、MCP、多 Agent、Skills/插件、服务层、配置、周边功能 |
### 生成的全部文档docs/ analysis/ project-overview.md -- 架构与技术栈 module-inventory.md -- 模块清单 (35 模块详情) risk-assessment.md -- 复杂度热点与设计模式 plan/ task-breakdown.md -- 20 章详细内容大纲与依赖关系 dependency-graph.md -- Mermaid 依赖图 + 并行执行车道 milestones.md -- 4 个里程碑定义 progress/ MASTER.md -- 主控文件 (跨会话续接入口) phase-1-foundation.md -- Phase 1 详细进度 phase-2-core-mechanics.md -- Phase 2 详细进度 phase-3-ui-interaction.md -- Phase 3 详细进度 phase-4-extension-advanced.md -- Phase 4 详细进度
.claude/skills/ write-teaching-chapter.md -- 教学写作专用 SKILL (项目级)
---
**所有准备工作已完成。是否开始 Phase 1 的章节写作?** 我建议从 CH01(项目总览与架构设计)开始,中英文版本可以并行写作。