Skip to content

[pull] main from claude-code-best:main#6

Open
pull[bot] wants to merge 633 commits into
Tialon:mainfrom
claude-code-best:main
Open

[pull] main from claude-code-best:main#6
pull[bot] wants to merge 633 commits into
Tialon:mainfrom
claude-code-best:main

Conversation

@pull

@pull pull Bot commented Apr 3, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

@pull pull Bot locked and limited conversation to collaborators Apr 3, 2026
@pull pull Bot added the ⤵️ pull label Apr 3, 2026
claude-code-best and others added 27 commits May 2, 2026 09:29
- FileReadTool maxResultSizeChars 从 Infinity 改为 100KB,大文件持久化到磁盘
- Messages.tsx 新增 computeMessageStructureKey 缓存,流式 delta 时跳过 8 个 Map/Set 重建
- microcompact 返回 clearedToolUseIds,query.ts 消费后清理 replacements Map 释放原始字符串
- 更新内存分析报告 Round 5 和 file-operations 文档

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…399)

DeepSeek v4 in thinking mode sometimes returns reasoning_content: ""
when the model answers directly without internal reasoning. Two places
were filtering the empty string out, which dropped the thinking block
from the assistant turn entirely. The next request then omitted
reasoning_content for that prior turn, and DeepSeek rejected with
400 "reasoning_content ... must be passed back to the API".

Fix:
- openaiStreamAdapter: open a thinking block whenever reasoning_content
  is present (including ""); skip the empty thinking_delta event since
  the empty value is already conveyed by the block's initial state.
- openaiConvertMessages: preserve empty thinking blocks as
  reasoning_content: "" when serializing assistant messages back to
  the OpenAI/DeepSeek format.

Tests:
- New: empty reasoning_content opens a thinking block (adapter).
- Updated: empty thinking blocks now round-trip as reasoning_content: ""
  instead of being dropped.
- New: assistant messages with no thinking block still omit
  reasoning_content (regression guard for non-thinking models).
…ntent

fix: 保留 DeepSeek v4 thinking mode 的空 reasoning_content (#399)
- P0: REPL.tsx 用 useMemo 包裹 deferred messages slice,避免每次渲染创建新数组引用导致不必要的后台重渲染
- P1: 预测性 compact 阈值改用 effectiveContextWindow - growth,消除与 autocompact buffer 的双重预留;TOOL_RESULT_GROWTH_ESTIMATE 从 20K 降至 15K
- P2: 增量 lookups 增加 lastAssistantMsgId 一致性检查和 orphaned server_tool_use/mcp_tool_use 扫描,防止 UI 永久 loading
- P3: reactiveCompact 类型断言改为直接使用 'compact' 字面量
- docs: CLAUDE.md 统一使用 precheck 替代分散的 typecheck/lint/test 命令

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
为 AgentTool 引入 fork 布尔参数,支持子代理从父对话上下文中 fork 出独立分支,
继承完整历史、系统提示和模型配置。重构 inputSchema 条件逻辑以适配 fork 模式。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
审查任务管理 CRUD 模块:创建/读取/更新/删除、高水位标记、文件锁并发安全、
claimTask 竞态保护、resetTaskList、通知信号、并发创建唯一 ID 验证。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- jsonStringify mock 参数类型改为 Parameters<typeof JSON.stringify>[1][] 消除 TS2769
- 并发测试改为顺序执行以适配 Bun 下 proper-lockfile 的 advisory lock 行为

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- vite.config.ts: codeSplitting: false 替代多 chunk 输出,产出单文件 dist/cli.js
- vite.config.ts: ssr.external 排除 doubaoime-asr/opus-encdec,避免 require.resolve 路径失效
- scripts/post-build.ts: 简化为直接处理单文件 dist/cli.js
- src/services/doubaoSTT.ts: 改进错误信息,输出具体异常内容便于排查

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
bun update -g 只更新到 package.json 版本范围内的最新版,无法跨版本升级。
改为 bun install -g @latest 与 npm 侧行为一致,强制拉取最新发布版。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 禁用 HISTORY_SNIP feature flag 并新增 proactiveTruncate 防止无 compact_boundary 时内存无限增长
- 跳过未启用 telemetry 时的 OTel 初始化,防止长会话 PerformanceMeasure 堆积
- OTel 导出遇 401/403 自动关闭 reader,防止 handle 泄漏
- Vite 构建启用 minify

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 为 budget/turns/structured-output 三种错误消息添加 Tip 提示,指导用户如何继续
- Onboarding 安全步骤标题从 "Security notes" 改为更友好的 "Before you start, keep in mind"
- Trust Dialog 精简为两句核心信息,降低认知负荷
- 新增 7 个测试验证消息内容包含关键引导信息

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Help General 页添加 3 步 Getting started 引导,替代单段描述
- 权限对话框底部 "Esc to cancel" → "Esc to reject","Tab to amend" → "Tab to add feedback"
- .claude/ 文件夹权限选项标签从 60 字符缩至 49 字符,避免窄终端截断
- 新增 10 个测试覆盖权限提示文案和帮助页引导内容

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- ModelPicker 副标题从技术说明改为操作提示(effort 调整、1M 切换)
- /resume 错误提示添加 "Run /resume to browse" 操作引导
- 新增 6 个测试覆盖模型选择器、会话恢复和 cost 消息文案

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
claude-code-best and others added 30 commits June 20, 2026 12:38
session/delete(rfds/session-delete.mdx):
- sessionCapabilities.delete: {} 能力广告(类型增强写入,SDK 0.19.0 早于该 RFD)
- extMethod 钩子路由 session/delete → unstable_deleteSession
- 硬删除 .jsonl 文件,ENOENT 视为成功(幂等)
- 未知方法抛 RequestError.methodNotFound(JSON-RPC -32601)

message-id(rfds/message-id.mdx):
- agent_message_chunk / user_message_chunk / agent_thought_chunk 携带 messageId
- forwardSessionUpdates 维护 currentAgentMessageId,lazy 生成 UUID
- streaming text/thinking chunks 与最终 assistant message 共享同一 ID
- replayHistoryMessages per-message 生成 UUID
- PromptRequest.messageId → PromptResponse.userMessageId 回显
- tool_call / plan / subagent 不带 messageId(spec 仅规定 chunk 类型)

测试:ACP service 从 176 → 191 (+15)
- bridge.test.ts: +9 个 message-id 测试
- agent.test.ts: +6 个 session/delete + userMessageId 测试
- 总测试 5851 → 5866,全通过

审计文档:新增附录 A.2 记录两个 UNSTABLE RFD 实现状态

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
67fdd4ca 那次合规审计误将 models 从响应里移除,但 SDK 0.19.2 的 schema 实际允许
models?: SessionModelState | null(标注 UNSTABLE 仅表示"未来可能变",并非
"agent 禁止返回")。标准 ACP 客户端(Cursor/Zed/VS Code/RCS)依赖此字段填充
模型选择器 —— 缺失会导致客户端 supportsModelSelection=false,模型切换 UI 不可用。

- createSessionMethod: return 里加回 models
- sessionLifecycle: getOrCreateSession 两处 return 透传 models(resume/load 路径)
- agent.test: 更新过时的 "models omitted for v1 compliance" 断言

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
之前 bypassPermissions 需要本地显式 opt-in(ACP_PERMISSION_MODE 环境变量、
CLAUDE_CODE_ACP_ALLOW_BYPASS_PERMISSIONS 环境变量、或 settings.permissions.defaultMode)
才会出现在 modes 列表里 —— 标准客户端看不到这个 mode,永远没法切换。

去掉 opt-in 后,只要进程级允许(非 root 或 IS_SANDBOX=1)就显示。
- permissionMode: isAcpBypassPermissionModeAvailable 只保留进程级检查,删除
  isAcpBypassLocallyEnabled / isSettingsBypassPermissionMode / isTruthyEnv 等
  只服务于 opt-in 的辅助函数
- createSessionMethod: 调用方去掉 settingsMode 参数
- agent.test: 反转所有依赖 "bypass 需要 opt-in" 的断言

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
- listSessions: 客户端省略 cwd 时回退到 getOriginalCwd(),并对每个候选会话的
  存储 cwd 做 canonicalizePath 规范化后与请求 cwd 严格匹配,确保只返回真正属
  于当前工作区的会话(符合 session-list.mdx "Only sessions with a matching
  cwd are returned")
- sessionLifecycle: 移除 getOrCreateSession 中审计 2.2 添加的 cwd 一致性校验,
  它会拒绝 resolveSessionFilePath worktree fallback 找到的合法会话加载
- 补充 listSessions 的 5 个测试用例覆盖 cwd 透传/fallback/分页拒绝/无 cwd 过滤

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
- persistence: listPersistedRuns 加 limit 参数;新增 cleanupOldRuns 在 run_done 后异步清理超过 50 个的旧 run(负数 keepMax clamp 到 0)
- service: loadPersistedRuns 限制 hydrate 最近 20 个;resolveSource 读 input.title 对齐 WorkflowTool 优先级链

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
* feat: 新增 cloud-artifacts 包(Cloudflare Worker HTML artifact 托管)

POST /upload 鉴权上传 HTML 到 R2 返回 hash URL,GET /<7d|30d>/<id>.html
由 Worker 代理读取并直出 text/html。R2 lifecycle rule 自动 7/30 天删除。
独立服务,不被主 CLI 引用(类似 packages/remote-control-server/ 定位)。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* docs: 完善 cloud-artifacts 文档并统一出口域名

- CLAUDE.md 加 cloud-artifacts 到 Workspace Packages 表和新增 HTML Artifact Hosting 段落
- docs.json 注册 cloud-artifacts 到运行模式 group
- README 加 Quickstart、架构图(含 Deno Deploy 代理层)、Security Considerations、Troubleshooting
- 统一出口域名为 https://cloud-artifacts.claude-code-best.win(wrangler.toml PUBLIC_URL、test.sh 默认 WORKER_URL、所有文档示例)
- test.sh expect() 加 [via body] fallback:经 Deno Deploy 代理(status 抹平为 200)时按 body 的 error 字段断言

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* docs: 修正 CLAUDE.md cloud-artifacts 引用死链

之前指向不存在的 docs/features/cloud-artifacts.md(用户未注册到 docs.json),
改为指向已存在的 packages/cloud-artifacts/README.md,并补充生产出口域名
与 Deno Deploy status 抹平副作用的说明。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 同步 cloud-artifacts 测试默认 TOKEN 到新值

用户已通过 wrangler secret put 把生产 TOKEN 改为 claude-code-best,
test.sh 的默认值(之前用旧 token 作 fallback)和注释示例同步更新。
现在直接 bash scripts/test.sh 即可跑通(无需显式传 TOKEN)。

src/index.ts 不依赖具体 token 值(只读 env.TOKEN 做比较),
wrangler.toml 不含 secret,README/.dev.vars.example 用 <your-token>
占位符故无需改。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* docs: add artifacts feature implementation plan

* feat(artifact): add cloud-artifacts config with token/URL defaults

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add HTTP client with body-error parsing

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add tool name, description, and prompt

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add buildTool definition with file validation

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* test(artifact): add end-to-end tool tests for upload/error paths

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): export ArtifactTool from builtin-tools barrel

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): register ArtifactTool in tools list

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add /use-artifacts bundled skill

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add extractArtifacts message scanner

Scans Message[] for artifact tool_use/tool_result pairs, parses URL/id/expires
from the upload response string, and returns ArtifactInfo[] newest-first.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* fix(artifact): scanner type narrowing and url regex

- Use double assertion (`as unknown as Record<string, unknown>`) at lines 30
  and 90 to fix TS2352 per project convention
- Tighten URL_REGEX to avoid capturing trailing punctuation (parens,
  quotes, commas) when URL is embedded in text
- Add test case for array-form tool_result content path

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add ArtifactsMenu Ink component

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): add /artifacts slash command entry

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): register /artifacts command

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* fix(artifact): use setClipboard instead of pbcopy for cross-platform support

* fix(artifact): drop userFacingName override so display matches /artifacts

* fix(rcs): add resJson helper to resolve strict mode type errors in tests

Hono Response.json() returns Promise<unknown> under strict TypeScript,
causing 121 TS errors across middleware and routes test files.

Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>

* fix(cloud-artifacts): add type stubs so tsc passes without worker-configuration.d.ts

The wrangler-generated worker-configuration.d.ts is gitignored, causing CI to
fail with missing ExportedHandler/Env/R2Bucket types. This file provides minimal
stubs for all Cloudflare Workers types used by the artifact upload Worker.

Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>

* fix(query): shallow-copy messages before stripping toolUseResult

Previously the per-query cleanup mutated messagesForQuery entries in
place via `delete msg.toolUseResult`. Those entries are references
shared with mutableMessages (UI state), so the delete stripped the
field from the live message object. The next query can start within
milliseconds of tool_result creation — before the React UI commit
lands — so UserToolSuccessMessage's `!message.toolUseResult` check
returned null and tool.renderToolResultMessage was never called,
leaving tool-result rows blank.

Map to a stripped copy instead so mutableMessages keeps the original
for the UI. Downstream API transformations (applyToolResultBudget,
snip, microcompact) already build new arrays via .map(), so they
compose cleanly with this copy.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* feat(artifact): show uploaded URL inline below ExecuteExtraTool

Deferred tools (shouldDefer: true) are invoked via SearchExtraTools →
ExecuteExtraTool, so their tool_result rows used to render blank —
the UI looked up ExecuteExtraTool, which had no renderToolResultMessage,
and returned null. Add a generic delegation in ExecuteTool that forwards
renderToolResultMessage to the inner tool when it defines one, unwrapping
the { result, tool_name } envelope and the params from the input shape.
All 28 deferred tools can now render their own UI by defining
renderToolResultMessage.

For ArtifactTool specifically, render the uploaded URL as an OSC 8
hyperlink (Link component) in warning color so it's visually prominent,
with the expiry timestamp on a second line and a separate error branch.
Also add `error: z.string().optional()` to outputSchema — zod's default
strip mode was dropping the field, so error states never reached the UI.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* fix(cloud-artifacts): make Env stubs actually take effect in CI

The previous stub file (2e29e36) wrapped `interface Env` in
`declare global { ... }`, but the file has no top-level import/export so
it's a script, not a module. TS2669 forbids `declare global` in scripts,
and in .d.ts files that error is silently swallowed — so the Env stubs
were never merged into the global scope. Locally typecheck passed only
because worker-configuration.d.ts (gitignored) provided Env separately;
in CI / fresh clones, `BUCKET`, `MAX_BYTES`, `DEFAULT_TTL_DAYS`,
`PUBLIC_URL` were all missing on Env.

Drop the wrapper. Top-level `interface Env` in a script .d.ts is already
global ambient and merges with worker-configuration.d.ts via interface
declaration merging, so both environments typecheck cleanly.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

---------

Co-authored-by: glm-5.2 <zai-org@claude-code-best.win>
* fix: 终端内容溢出 viewport 时的重影 bug

主屏幕模式下 frame 持续溢出 viewport 时,cursor-restore LF 把内容滚入 scrollback
导致相对光标追踪漂移,可见区 diff 落到错误行产生重影(重复 banner / 错位)。
扩展 log-update overflow 分支为无条件 fullReset(含 \x1b[3J 清 scrollback),
并将主屏 self-healing 清屏从 ERASE_SCREEN (CSI 2 J) 换成 ERASE_DOWN (CSI J),
避免 xterm.js / VSCode 集成终端的 scrollback 边界副作用。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 删除 3 个孤立诊断脚本

- scripts/verify-autofix-pr.ts: 一次性 autofix-pr 验证脚本,全仓零引用
- scripts/smoke-test-commands.ts: 开发期冒烟测试脚本,无任何 import
- scripts/probe-subscription-endpoints.ts: 手动 endpoint 探针,无引用

均不在 package.json scripts、build.ts、vite.config.ts、CI workflows 中。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 self-hosted-runner stub 及其 cli.tsx fast-path

- 删除 src/self-hosted-runner/main.ts(自动生成的 Promise.resolve() stub)
- 同步移除 src/entrypoints/cli.tsx 中 feature('SELF_HOSTED_RUNNER') 守卫的 fast-path 分支
- 该 flag 不在 build.ts DEFAULT_BUILD_FEATURES 也不在 dev 默认列表,所有默认配置下整段为构建期死代码

删除 stub 单独会留下未解析的动态 import,必须协同拆除。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 删除 agentSdkTypes 中三个 not-implemented stub

移除 watchScheduledTasks、buildMissedTaskNotification、connectRemoteControl 三个 stub 函数(函数体仅 throw new Error('not implemented')),以及仅被这些 stub 引用的孤儿类型(ScheduledTasksHandle、ConnectRemoteControlOptions、RemoteControlHandle、InboundPrompt 等)。

全仓零外部引用。buildMissedTaskNotification 在 src/utils/cronScheduler.ts 有真实可用实现,未受影响。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 Cursor.ts 中未引用的 kill ring 访问器

- 删除 getKillRingItem、getKillRingSize、clearKillRing、canYankPop(全仓零引用的独立 export)
- 移除 VIM_WORD_CHAR_REGEX 的 export 关键字(仍由 isVimWordChar 内部使用,保留常量本体)

kill ring 特性本身仍活跃(getLastKill/pushToKillRing/yankPop 在 useSearchInput/useTextInput 使用),仅这几个孤儿 helper 未接入。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 insights.ts 中未引用的导出

- 删除 deduplicateSessionBranches(全仓零调用,含 JSDoc)
- 删除 buildExportData(全仓零调用,原 S3 上传路径实际用 HTML 而非 JSON)
- InsightsExport 仅移除 export 关键字(保留类型本体,仍作为内部返回类型)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 autonomyCommandSpec.ts 中未引用的导出

- 删除 AUTONOMY_CLI(CLI 子命令描述对象,零引用;handler 仅用 AUTONOMY_USAGE)
- 删除 AUTONOMY_COMMAND_DESCRIPTION(值已在 main.tsx:5181 内联)
- ParsedAutonomyCommand 仅移除 export 关键字(保留类型作为 parseAutonomyArgs 返回类型)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 binaryCheck/claudeAiLimits/codeIndexing 中未引用的导出

- binaryCheck.ts: 删除 clearBinaryCache(零调用,binaryCache 仍由 isBinaryInstalled 使用)
- claudeAiLimits.ts: 删除 RATE_LIMIT_DISPLAY_NAMES 常量 + getRateLimitDisplayName(互为唯一消费者)
- codeIndexing.ts: 删除 detectCodeIndexingFromMcpTool(同胞 detectCodeIndexingFromCommand/McpServerName 仍活跃)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除多处仅内部使用的 export 关键字

下列符号均仅在本文件内被引用,export 关键字冗余;保留符号本体不动:

- internalLogging.ts: getContainerId(line 88 内部调用)
- api/errors.ts: isMediaSizeError(line 151 内部调用)
- api/withRetry.ts: parseMaxTokensContextOverflowError(line 389/724 内部调用)
- statsCache.ts: STATS_CACHE_VERSION(7 处内部使用)
- startupProfiler.ts: logStartupPerf(line 128 内部调用)
- bashCommandHelpers.ts: CommandIdentityCheckers(3 处内部参数类型)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 清理注释代码块与 legacy shim

注释代码(已死的、引用不存在符号的注释块):
- Onboarding.tsx: 注释化的 preflight if-block(引用不存在的 preflightStep)
- ultraplan.tsx: 两处引用不存在符号的注释(ULTRAPLAN_INSTRUCTIONS、getUltraplanModel)
- types/hooks.ts: 禁用的 type-fest IsEqual 类型断言块
- types/global.d.ts: 已被真实模块取代的 Ultraplan ambient declares
- types/textInputTypes.ts: 注释化的 onMessage interface 成员

legacy shim:
- cli/bg.ts: 删除 handleBgFlag 别名 export(同胞 handleBgStart 已被所有调用点使用)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 ccshareResume stub 及 main.tsx 的 ccshare fast-path

- 删除 src/utils/ccshareResume.ts(parseCcshareId 恒返回 null、loadCcshare 恒抛错的 stub)
- 同步移除 src/main.tsx 中 USER_TYPE === 'ant' 守卫下的 if (ccshareId) {...} else {...} 双分支
- 提升 else 块(文件路径 resume 处理)为直接进入 if (options.resume) 块内

ccshare 是 Anthropic 内部特性(go/ccshare URL),stub 未实现导致 ccshareId 恒为 null,整个 ccshare 分支永不进入;保留的文件路径 resume 路径不变。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 environment-runner stub 及其 cli.tsx fast-path

与 self-hosted-runner 相同模式的 sibling(工作流 1 verifier 建议同步处理):

- 删除 src/environment-runner/main.ts(自动生成的 Promise.resolve() stub)
- 同步移除 src/entrypoints/cli.tsx 中 feature('BYOC_ENVIRONMENT_RUNNER') 守卫的 fast-path 分支
- 清理两个空目录(src/self-hosted-runner/、src/environment-runner/)

BYOC_ENVIRONMENT_RUNNER flag 不在 build.ts DEFAULT_BUILD_FEATURES 也不在 dev 默认列表,所有默认配置下整段为构建期死代码。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 删除孤立诊断脚本 probe-local-wiring.ts

#!/usr/bin/env bun shebang 的手动诊断脚本,全仓零引用,不在 package.json/build.ts/vite.config.ts/CI workflows 中。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 ultrareview preflight stub 及其测试

- 删除 src/services/api/ultrareviewPreflight.ts(自动生成的 stub)
- 删除 src/commands/review/UltrareviewPreflightDialog.tsx(依赖前者的 UI stub)
- 删除 src/services/api/__tests__/ultrareviewPreflight.test.ts(测试已删代码)
- 同步移除 ultrareviewCommand.test.tsx 中对 UltrareviewPreflightDialog 的 mock

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 cachedMCConfig stub 及 prompts.ts 的 CACHED_MICROCOMPACT 死代码

- 删除 src/services/compact/cachedMCConfig.ts(自动生成的 stub)
- 同步移除 src/constants/prompts.ts 中依赖该 stub 的代码:
  - getCachedMCConfigForFRC 变量(feature('CACHED_MICROCOMPACT') 守卫的 require)
  - getFunctionResultClearingSection 函数(约 18 行)
  - systemPrompt 数组中的 frc section 调用与注册

CACHED_MICROCOMPACT 不在 build.ts DEFAULT_BUILD_FEATURES 也不在 dev 默认列表,所有默认配置下整段为构建期死代码。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 goalAudit stub 及其测试引用

- 删除 src/services/goal/goalAudit.ts(导出 COMPLETION_AUDIT_RULES/BLOCKED_AUDIT_RULES/isGoalTerminal 等未引用的 stub)
- 同步移除 tests/integration/goal-lifecycle.test.ts 中对 goalAudit 的 import 和一个测试用例(budget_limited is terminal)

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 删除 agentSdkTypes 第二批 not-implemented stub

移除运行时函数体仅为 throw new Error 或 placeholder 的 stub:
- createSdkMcpToolDefinition、createSdkMcpServer
- query 函数重载与实现
- unstable_v2_* 系列函数
- session 操作 stub(getSessionMessages/listSessions/getSessionInfo/renameSession/tagSession/forkSession)
- AbortError 类

保留所有 export type 重导出和类型别名(仍是公共类型面)。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 Tool.ts 中 backwards-compat 重导出 shim

删除 "// Re-export progress types for backwards compatibility" 注释块及其重导出语句。所有消费方已直接从 src/types/tools.js 导入,无需重导出转发。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 bootstrap/state.ts 中 4 个未引用的 export

- clearRegisteredHooks(STATE.registeredHooks 仍由其他函数管理)
- getInvokedSkills(getInvokedSkillsForAgent 是活跃入口)
- getSessionSource(setSessionSource 仍活跃,sessionSource state 字段保留)
- markScrollActivity(scrollDraining/getIsScrollDraining/waitForScrollDrain 仍活跃)

仅删除孤儿访问器,不动模块级 state 副作用。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 src/ 下多处未引用的导出

涉及 18 个文件,每处均为独立的 unreferenced export 删除或 export 关键字冗余移除:

- bridge/bridgeStatusUtil.ts、components/TrustDialog/utils.ts、context/stats.tsx
- keybindings/loadUserBindings.ts、memdir/paths.ts、remote/sdkMessageAdapter.ts
- services/acp/utils.ts(删除 nodeToWebReadable,全仓零引用)
- services/api/metricsOptOut.ts、services/lsp/LSPDiagnosticRegistry.ts、services/lsp/manager.ts
- services/mcp/utils.ts、services/skillLearning/projectContext.ts
- services/teamMemorySync/secretScanner.ts、services/teamMemorySync/watcher.ts
- skills/loadSkillsDir.ts、utils/attachments.ts、utils/filePersistence/filePersistence.ts
- utils/messageQueueManager.ts

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* chore: 移除 packages/ 下多处未引用的导出

涉及 11 个 workspace 包文件,每处均为独立的 unreferenced export 删除或 export 关键字冗余移除:

- @ant/ink/core/termio/csi.ts(eraseLine)
- acp-link/manager/types.ts、acp-link/ws-message.ts
- builtin-tools/AgentTool/agentMemory.ts、BashTool/bashSecurity.ts、BashTool/sedEditParser.ts
- builtin-tools/ConfigTool/supportedSettings.ts、FileEditTool/utils.ts
- remote-control-server/store.ts、transport/event-bus.ts、types/messages.ts

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* Revert "fix: 终端内容溢出 viewport 时的重影 bug"

This reverts commit 3d18e1d.

* revert: 移除主屏幕周期性 self-healing 重绘

回退 f69c705 中引入的 ink.tsx self-healing 机制(lastMainScreenHealTime 字段
+ 每 5 秒触发全量重绘 + needsEraseBeforePaint 主屏幕分支)。该机制在 workflow
面板持续刷新场景下表现为可见的"重复刷新",且修复效果不稳定。

alt-screen 的 needsEraseBeforePaint 路径和 prevFrameContaminated 字段保留,
它们仍服务于 handleResize / layout shift / selection 高亮。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* fix: /workflows 面板默认只显示运行中 run,根治 tab 行乱码

之前几次渲染层修复都失败,因为没动 tab 列表的数据源:打开 /workflows 会
自动 hydrate 最多 20 个历史 done/killed run,全部塞进一行 TabsBar,超出
终端宽度后 Ink 把字符画到屏外造成重影乱码。

- selectors.ts 加 filterActiveRuns(只留 status === 'running')和
  capTabsForDisplay(超额 fold 成 +N)两个 pure function
- WorkflowsPanel 接线 activeRuns:focus clamp、focused、nextTab/prevTab、
  TabsBar 全部基于过滤后的 activeRuns
- TabsBar 复用 truncateLabel 限制每个 tab 名 18 字符 + 最多 6 个 tab,
  多余显示 +N,从结构上钉死单行总宽度

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* fix: /workflows 面板 phase 状态在脚本省略 phase() 时显示错乱

ultracode canonical pipeline 脚本常在 agent() 直接传 opts.phase 而不调 phase()
hook,导致 phase_started 从未发出;同时 phase_done 只在下次 phase() 触发,上一
个 phase 在 run.phases 里一直停在 running。mergePhases 之前把 actual 当权威,
于是出现 "Map 8/8 全 done 还显示 running、Find 1/4 running 反而显示 pending"。

改为派生层修复:mergePhases 新增 derivePhaseStatus——actual.status==='done'
权威;否则有 agents 就按 agents 状态推(全 done→done,否则 running);否则看
actual 是否 running。再补一层遍历,让只在 agents 上出现的 phase 也进 sidebar。
不改 store 状态语义,已有 state.json 无需迁移。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

* docs: 更新 readme

* fix: ACP 模式未读取 settings.local.json

entry.ts 在 ACP 握手期调用的 applySafeConfigEnvironmentVariables 触发了
loadSettingsFromDisk,此时 getOriginalCwd() 还是进程启动 cwd(非项目目录),
导致 localSettings/projectSettings 按错误路径解析为空并被 session cache 锁住,
后续 createSession 里 setOriginalCwd 也无法纠正。在 setOriginalCwd 与 chdir
之后清缓存并重新应用,让 settings.local.json 和项目级 env 对
readSettingsPermissionMode 及下游可见。

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>

---------

Co-authored-by: glm-5.2 <zai-org@claude-code-best.win>
- 移除 private,补全 exports/types/files/publishConfig/license/repository 等
- 添加 LICENSE (MIT) 与 README
- 添加 scripts/build.ts + tsconfig.build.json,用 tsc emit 输出 dist/**/*.js + .d.ts
  (Bun bundle + external zod 会丢失 createWorkflowTool/workflowInputSchema/persistInlineScript 符号,改用 tsc emit)
- 修 src/index.ts 的 WORKFLOW_TOOL_NAME 重复 export;tool/* 的 named re-export 改为 import + 再 export

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
* 完善所有用到的type对象,并添加中文注释

* 补充遗失的type

* 修改pipe模式卡死的问题,增加trycatch捕获错误信息。

* 修改为英文报错信息。
normalizeMessages and toSDKMessages access message.error in flatMap
callbacks executed during React render (via useMemo). When a null
element is present in the messages array at runtime (e.g., from
corrupted JSONL deserialization or streaming race conditions),
null.error throws "Cannot read properties of null (reading 'error')".

Add null guards to flatMap/forEach callbacks and optional chaining
on message.error access points in normalizeMessages and
toSDKMessages.

Fixes: React Rendering Error in MessagesBoundary

Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
Co-Authored-By: deepseek-v4-pro[1m] <deepseek-ai@claude-code-best.win>
ToolCallLocation.path and Diff.path emitted over ACP must be absolute
and POSIX-style per the v1 spec (tool-calls.mdx:304-306). The previous
code used platform-specific `node:path` which on Windows prepends the
drive letter (e.g. "D:\...") to POSIX-style inputs like
"/Users/test/project" — silently corrupting paths emitted to ACP
clients on Windows hosts. CI runs on Linux so the latent issue went
undetected. Switch to `node:path/posix` so the path normalisation is
host-OS independent.

Co-Authored-By: Claude <noreply@anthropic.com>
fix(acp): use POSIX path semantics for ACP wire format paths
fix: prevent null reference reading 'error' in MessagesBoundary
`findGitBashPath` previously only checked `C:\Program Files\Git\` and
`C:\Program Files (x86)\Git\` for git.exe, and assumed bash lived at
`<git>/../../bin/bash.exe`. On non-default installs — for example
`D:\software\Git\` (portableGit), scoop, chocolatey, or any manual
placement — git is found via `where.exe` but the derived bash path
doesn't exist, so the function fell through to `process.exit(1)`.

This crashed entire test suites on Windows (e.g.
`src/__tests__/queryAutonomyProviderBoundary.test.ts` transitively
triggered the exit) and blocked every Windows user whose Git lived
outside the two hard-coded paths from using the CLI at all.

The fix:
- Add `where.exe bash` as a primary discovery step (most reliable: it
  returns the actual bash.exe the user's shell will execute).
- Try multiple derived layouts from git's location (standard,
  portable `usr/bin/bash.exe`, sibling `bin/`).
- Expand default-locations fallback to include `usr/bin/bash.exe` and
  scoop install paths.
- Extract the discovery logic into a pure
  `findGitBashPathOrNullWithDeps` function that takes its dependencies
  as parameters, so the branching can be unit-tested without
  `mock.module` polluting other tests in the same `bun test` process
  (see CLAUDE.md "跨文件 mock 污染").

Test coverage added in `src/utils/__tests__/windowsPaths.test.ts`:
- env-var override (existing and missing file)
- `where.exe bash` PATH lookup
- All three git-path derivation layouts
- Default-locations fallback (both standard and `usr/bin` variants)
- SECURITY: filters malicious `where.exe` hits from cwd
- Behavior: `where.exe git` is skipped once bash is already found

Verified on Windows 11 + Bun 1.3.14:
- `bun run precheck`: 5896/5896 pass (was 5883/5883, +13 new tests)
- `bun run build`: succeeds
- `findGitBashPath()` now returns `D:\software\Git\usr\bin\bash.exe`
  on the actual dev machine that previously hard-crashed

Co-Authored-By: Claude <noreply@anthropic.com>
…tion

`validatePath` previously used platform-specific `path.isAbsolute` and
`path.resolve`. On Windows, this created a sandbox-escape class:

- A model emitting `/c/Users/foo/sensitive.txt` (MinGW form, the way
  Git Bash writes paths) reaches `validatePath`.
- `path.isAbsolute('/c/Users/foo/sensitive.txt')` returns true on
  Windows (treated as a drive-relative absolute path).
- `path.resolve('D:\\project', '/c/Users/foo/sensitive.txt')` returns
  `D:\\c\\Users\\foo\\sensitive.txt` (resolved against the current drive).
- The validator compares `D:\\c\\Users\\foo\\sensitive.txt` against the
  allowed-directories list. If `D:\\` is broadly allowed (e.g. the
  user's working directory is on D:), validation passes.
- Git Bash actually writes to `C:\\Users\\foo\\sensitive.txt` — a
  completely different filesystem location — bypassing the sandbox.

The fix: on Windows, normalize MinGW-style absolute paths
(`/c/Users/foo`, `/cygdrive/c/Users/foo`) to Windows paths
(`C:\\Users\\foo`) via `posixPathToWindowsPath` BEFORE the
isAbsolute/resolve step. The validator's path space now matches the
shell's, so the comparison is against the actual target the shell will
write to.

`posixPathToWindowsPath` is a no-op for already-Windows paths and
relative paths (it just flips slashes), so applying it
unconditionally on Windows is safe.

Test coverage added in
`src/utils/permissions/__tests__/pathValidation.test.ts`:
- `/c/...` → `C:\\...` conversion (all 7 cases incl. drive-letter case,
  bare mount, nested paths)
- `/cygdrive/c/...` → `C:\\...` conversion
- Already-Windows paths pass through unchanged
- Relative paths pass through (just slash direction flipped)
- SECURITY regression test: MinGW path that escapes allowed dirs is
  now correctly denied at the right location
- SECURITY regression test: cygdrive variant of the above

Verified on Windows 11 + Bun 1.3.14:
- `bun run precheck`: 5906/5906 pass (was 5896/5896, +10 new tests)
- `bun run build`: succeeds

Co-Authored-By: Claude <noreply@anthropic.com>
Three improvements suggested by CodeRabbit's PR review:

1. Use path.win32 for processing `where.exe` results (MAJOR). On POSIX
   hosts, `path.resolve('C:\\foo')` treats backslashes as literal
   characters and produces a wrong (relative) result, which would let
   cwd shadowing slip past the security check. Switch to `path.win32.*`
   so the cwd filtering evaluates `where.exe`'s Windows-style paths
   with Windows semantics regardless of host OS.

   Also switched the cwd check from `startsWith` to `path.win32.relative`,
   which is more robust: returns `''` for cwd itself, `..`/`../...` for
   outside, and a non-absolute path for inside. Avoids edge cases with
   trailing separators and mixed case.

2. Inject `USERPROFILE` through `GitBashDiscoveryDeps` (NITPICK). The
   Scoop fallback in `searchDefaultBashLocations` was reading
   `process.env.USERPROFILE` directly, breaking hermetic testing of
   that branch. Threaded through as an optional deps field, defaults
   to `process.env.USERPROFILE` for production.

3. Add `envOverride: ''` to the manual `GitBashDiscoveryDeps` fixture
   in the "skips where.exe git when bash is already found via PATH"
   test (INLINE). Without this, the test would pass for the wrong
   reason (env override) on developer machines that have
   `CLAUDE_CODE_GIT_BASH_PATH` set, instead of exercising the PATH
   short-circuit behavior the test is named after.

Co-Authored-By: Claude <noreply@anthropic.com>
UserToolSuccessMessage now requires parsedOutput.success before trusting
data, and guards toolResult against non-object values before calling
renderToolResultMessage. String renderedMessage is wrapped in <Text> so
multi-line tool reports (e.g. GoalTool usage report) don't crash Ink.

Defense in depth added to VaultHttpFetchTool/UI (matches the existing
pattern in LocalMemoryRecallTool and GoalTool) and to the
mapToolResultToToolResultBlockParam of both vault/memory tools.

Co-Authored-By: glm-5.2 <zai-org@claude-code-best.win>
… warning

CodeRabbit flagged the PR with "Docstring coverage is 50.00% which is
insufficient (threshold 80.00%)". Added JSDoc to:

1. `formatDirectoryList` in pathValidation.ts — the only production
   function in the changed files that lacked JSDoc. Brief description
   of the truncation behavior + reference to MAX_DIRS_TO_LIST.

2. Both `describeIfWindows` blocks in pathValidation.test.ts — explain
   the security rationale of the MinGW-normalization fix and the
   sandbox-escape regression scenarios. Individual `test()` calls
   already self-document via their string descriptions.

Co-Authored-By: Claude <noreply@anthropic.com>
…nded growth

`getSessionMessages` was implemented via `lodash memoize`, which has no
size cap. Each unique sessionId adds a `Promise<Set<UUID>>` entry that
is only cleared by `clearSessionMessagesCache()` — and that call is
only made from `postCompactCleanup`, which fires once per compaction.

In long-running daemon / swarm sessions that spawn many agents (each
with its own transcript), the cache grows unbounded for the process
lifetime. Per-entry Sets are MUCH larger than the file-path strings
the adjacent `existingSessionFiles` cache stores, so the leak is more
severe than the one fixed for that cache at `sessionStorage.ts:535`.

The fix mirrors the existing `existingSessionFiles` pattern: replace
lodash `memoize` with a `Map<UUID, Promise<Set<UUID>>>` and evict the
oldest entry (FIFO via Map insertion order) when at
`MAX_CACHED_SESSION_FILES` capacity. Re-uses the same constant for
consistency.

Concretely:
- `sessionStorage.ts`: refactor `getSessionMessages` to be a regular
  `async function` backed by a module-level `Map`, with FIFO eviction
  at `MAX_CACHED_SESSION_FILES`. Export `getSessionMessagesCache()` so
  `getLastSessionLog`'s priming logic (and tests) can interact with the
  underlying Map directly. Export `getSessionMessages` itself with a
  `@internal`-style comment noting it's not part of the public API
  (callers should keep using `doesMessageExistInSession`).
- `src/utils/__tests__/sessionStorage.test.ts` (new): 7 tests covering
  cache identity, clear behavior, concurrent-call dedup, bounded size
  after many distinct sessionIds, FIFO eviction order, and refill
  after clear. Uses real temp directory + `CLAUDE_CONFIG_DIR` env to
  keep tests hermetic — no `mock.module` pollution.

Verified on Windows 11 + Bun 1.3.14:
- `bun run precheck`: 5899/5900 pass (the 1 fail is a pre-existing flaky
  `toolEventObserver` test that times out on Windows runners, unrelated
  to this change)
- 7/7 new tests pass
- No regressions in other test files

Co-Authored-By: Claude <noreply@anthropic.com>
fix(utils): discover git-bash on non-default Windows install paths
…lization

fix(permissions): normalize MinGW paths in validatePath before resolu…
…unded

 fix(session-storage): bound getSessionMessages cache to prevent unbounded growth
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.