This commit is contained in:
DeviosLang 2026-06-11 12:37:34 +08:00 committed by GitHub
commit 03a41d19e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 48 additions and 48 deletions

View File

@ -1,6 +1,6 @@
# `/autofix-pr` 命令实现规格文档
> **状态**规划阶段2026-04-29等待评审通过后进入实施
> **状态**已实现598 行代码 + 5 个测试文件)
> **Worktree**`E:\Source_code\Claude-code-bast-autofix-pr`,分支 `feat/autofix-pr`,基于 `origin/main` 4f1649e2。
> **架构**RRemote-via-CCR完整版含 stop 子命令、单例锁、subscribePR、in-process teammate、skills 探测)。

View File

@ -1,7 +1,7 @@
# BASH_CLASSIFIER — Bash 命令分类器
> Feature Flag: `FEATURE_BASH_CLASSIFIER=1`
> 实现状态bashClassifier.ts 全部 StubyoloClassifier.ts 完整实现可参考
> 实现状态bashClassifier.ts 为 ANT-ONLY stub需要 Anthropic 内部 API开源版使用 yoloClassifier.ts (1496行) 作为完整替代方案
> 引用数45
## 一、功能概述

View File

@ -90,7 +90,7 @@ export function isCoordinatorMode(): boolean {
文件:`src/coordinator/workerAgent.ts`
当前为 stub。Worker 实际使用通用 AgentTool 的 `worker` subagent_type。
Worker 使用通用 AgentTool 的 `worker` subagent_type。工具过滤通过 `getWorkerTools()` 排除内部编排工具TeamCreate/TeamDelete/SendMessage/SyntheticOutput
### 3.6 数据流
@ -147,5 +147,5 @@ CLAUDE_CODE_SIMPLE=1 bun run dev
| 文件 | 行数 | 职责 |
|------|------|------|
| `src/coordinator/coordinatorMode.ts` | 370 | 模式检测 + 系统提示 + 用户上下文 |
| `src/coordinator/workerAgent.ts` | — | Worker agent 定义stub |
| `src/coordinator/workerAgent.ts` | 68 | Worker agent 定义(完整 |
| `src/constants/tools.ts` | — | `ASYNC_AGENT_ALLOWED_TOOLS` 工具白名单 |

View File

@ -31,7 +31,7 @@ Agent({ subagent_type: "general-purpose", prompt: "..." })
### /fork 命令
注册了 `/fork` 斜杠命令(当前为 stub。当 FORK_SUBAGENT 开启时,`/branch` 命令失去 `fork` 别名,避免冲突。
注册了 `/fork` 斜杠命令。当 FORK_SUBAGENT 开启时,`/branch` 命令失去 `fork` 别名,避免冲突。
## 三、实现架构
@ -192,4 +192,4 @@ FEATURE_FORK_SUBAGENT=1 bun run dev
| `packages/builtin-tools/src/tools/AgentTool/resumeAgent.ts` | — | Fork agent 恢复 |
| `src/constants/xml.ts` | — | XML 标签常量 |
| `src/utils/forkedAgent.ts` | — | CacheSafeParams + ContentReplacementState 克隆 |
| `src/commands/fork/index.ts` | — | /fork 命令stub |
| `src/commands/fork/index.ts` | — | /fork 命令 |

View File

@ -1,7 +1,7 @@
# MCP_SKILLS — MCP 技能发现
> Feature Flag: `FEATURE_MCP_SKILLS=1`
> 实现状态:功能性实现config 门控筛选器完整,核心 fetcher 为 stub
> 实现状态:完整实现fetcher + 缓存 + 实时刷新 + 安全措施
> 引用数9
## 一、功能概述
@ -86,7 +86,7 @@ const fetchMcpSkillsForClient = feature('MCP_SKILLS')
## 三、关键设计决策
1. **Feature gate 隔离**`feature('MCP_SKILLS')` 守护条件 `require()` 和所有调用点。关闭时无模块加载、无获取操作
2. **资源到技能映射**:技能从 MCP 服务器的 `skill://` URI 资源中发现。`fetchMcpSkillsForClient` 负责转换(当前为 stub
2. **资源到技能映射**:技能从 MCP 服务器的 `skill://` URI 资源中发现。`fetchMcpSkillsForClient` 负责转换(LRU 缓存20 条目
3. **循环依赖避免**`mcpSkillBuilders.ts` 作为依赖图叶节点,避免 `client.ts ↔ mcpSkills.ts ↔ loadSkillsDir.ts` 循环
4. **服务器能力检查**:技能获取还需要 MCP 服务器支持 resources (`!!client.capabilities?.resources`)
@ -105,8 +105,8 @@ FEATURE_MCP_SKILLS=1 bun run dev
| 文件 | 状态 | 需要实现 |
|------|------|---------|
| `src/skills/mcpSkills.ts` | Stub | `fetchMcpSkillsForClient()` — 从 MCP 资源列表中筛选 `skill://` URI 并转换为 Command 对象 |
| `src/skills/mcpSkillBuilders.ts` | Stub | 技能构建器注册(避免循环依赖) |
| `src/skills/mcpSkills.ts` | 143 行 | `fetchMcpSkillsForClient()` — 从 MCP 资源列表中筛选 `skill://` URI 并转换为 Command 对象 |
| `src/skills/mcpSkillBuilders.ts` | 45 行 | 技能构建器注册(避免循环依赖) |
## 六、文件索引
@ -115,4 +115,4 @@ FEATURE_MCP_SKILLS=1 bun run dev
| `src/commands.ts:547-608` | 技能命令过滤 |
| `src/services/mcp/client.ts:117-2358` | 技能获取 + 缓存管理 |
| `src/services/mcp/useManageMCPConnections.ts` | 实时刷新 |
| `src/skills/mcpSkills.ts` | 核心转换逻辑(stub |
| `src/skills/mcpSkills.ts` | 核心转换逻辑(完整实现 |

View File

@ -1,7 +1,7 @@
# WEB_BROWSER_TOOL — 浏览器工具
> Feature Flag: `FEATURE_WEB_BROWSER_TOOL=1`
> 实现状态:核心工具已实现,面板为 Stub布线完整
> 实现状态:核心工具已实现,面板故意为 null结果在对话中内联显示
> 引用数4
## 一、功能概述
@ -14,7 +14,7 @@ WEB_BROWSER_TOOL 让模型可以启动浏览器实例、导航网页、与页面
| 模块 | 文件 | 状态 |
|------|------|------|
| 浏览器面板 | `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts` | **Stub** — 返回 null |
| 浏览器面板 | `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserPanel.ts` | **Null by design** — 结果内联显示,不需面板 |
| 浏览器工具 | `packages/builtin-tools/src/tools/WebBrowserTool/WebBrowserTool.ts` | **已实现** |
| REPL 集成 | `src/screens/REPL.tsx` | **布线** — 渲染 WebBrowserPanel |
| 工具注册 | `src/tools.ts` | **布线** — 动态加载 |

View File

@ -1,7 +1,7 @@
# WORKFLOW_SCRIPTS — 工作流自动化
> Feature Flag: `FEATURE_WORKFLOW_SCRIPTS=1`
> 实现状态:全部 Stub7 个文件),布线完整
> 实现状态:已实现 — WorkflowTool (432行), LocalWorkflowTask (212行), WorkflowDetailDialog (103行), 含测试
> 引用数10
## 一、功能概述

View File

@ -581,18 +581,11 @@ if (snipResult !== undefined) {
### 问题详情
`LSPServerManager` 中的 `openedFiles: Map<string, string>` 追踪所有通过 `didOpen` 打开的文件。`closeFile()` 方法存在可以发送 `didClose` 通知并清理 Map 条目,但代码注释明确标注:
`LSPServerManager` 中的 `openedFiles: Map<string, string>` 追踪所有通过 `didOpen` 打开的文件。`closeAllFiles()` 方法已实现,在 compaction 后通过 `postCompactCleanup` 自动调用,释放所有 LSP 服务器端的文件状态。
```
NOTE: Currently available but not yet integrated with compact flow.
TODO: Integrate with compact - call closeFile() when compact removes files from context
```
### 修复方式(已完成)
长时间会话中,每次读取/编辑文件都会通过 `openFile()` 添加条目,但 compaction 不会清理这些条目,导致 Map 无限增长。
### 修复方式
1. **添加 `closeAllFiles()` 方法**:遍历 `openedFiles` Map对每个文件发送 `didClose` 通知,然后清空 Map。Best-effort 错误处理。
1. **`closeAllFiles()` 方法**LSPServerManager.ts:414遍历 `openedFiles` Map对每个文件发送 `didClose` 通知,然后清空 Map。Best-effort 错误处理。
```typescript
async function closeAllFiles(): Promise<void> {
@ -612,18 +605,16 @@ async function closeAllFiles(): Promise<void> {
}
```
2. **集成到 `postCompactCleanup`**:在 compaction 后自动调用 `closeAllFiles()`释放所有 LSP 服务器端的文件状态
2. **集成到 `postCompactCleanup`**(已完成):在 compaction 后自动调用 `closeAllFiles()`使用 fire-and-forget async 模式(与 sweepFileContentCache 一致)
```typescript
// postCompactCleanup.ts
try {
const lspManager = getLspServerManager()
if (lspManager) {
await lspManager.closeAllFiles()
}
} catch {
// LSP module may not be available in all environments
}
// postCompactCleanup.ts — isMainThreadCompact guard
void import('../lsp/manager.js')
.then(m => {
const manager = m.getLspServerManager()
if (manager) return manager.closeAllFiles()
})
.catch(error => { logError(error) })
```
---
@ -632,7 +623,7 @@ try {
```
确认已实现 (12): #1 图片 #2 /usage #3 进度消息 #4 空闲渲染 #5 虚拟滚动器 #6 管道输出 #10 MCP缓冲区
已修复 (7): #7 语法加载 #8 NO_FLICKER #9 RC权限 #11 LRU缓存键 #12 snipCompact #17 LSP文件追踪 #18 Permission Polling
已修复 (8): #7 语法加载 #8 NO_FLICKER #9 RC权限 #11 LRU缓存键 #12 snipCompact #14 LSP compact集成 #17 LSP文件追踪 #18 Permission Polling
### 测试覆盖

View File

@ -3,7 +3,7 @@
> 来源: [stub-recovery-design-1-4.md](../features/stub-recovery-design-1-4.md) 第 4 项
> 优先级: P3
> 工作量: Phase 4A 中等4A-4D 全做完很大
> 状态: Phase 4A DONE, 4B-4D TODO
> 状态: Phase 4A-4D 全部实现 (src/assistant/ 350行, src/commands/assistant/ 完整)
## 目标

View File

@ -39,23 +39,16 @@ export async function call(
}
try {
// Reuse AgentTool logic for fork path.
// Omitting subagent_type triggers implicit fork.
// Omitting subagent_type triggers the fork path in AgentTool:
// isForkSubagentEnabled() && !subagent_type → fork routing → inherits
// parent context + system prompt + model + tools.
// run_in_background is omitted: when fork gate is on, all agents are
// forced async via forceAsync flag (the param is removed from schema).
const input = {
prompt: directive,
fork: true, // 触发 AgentTool 的 fork 路径:继承父会话上下文 + system prompt + 模型
run_in_background: true, // fork always runs async
// description 只显示在底部 selector / BackgroundTasksDialog保持简短标签
// 即可;用户输入的 prompt 会作为第一条用户消息呈现在主视图里,这里不要
// 重复显示。
description: 'forked from main',
};
// Call AgentTool with proper parameters:
// - input: the agent parameters (no subagent_type => fork path)
// - toolUseContext: the current context (ToolUseContext)
// - canUseTool: permission-check function from context
// - assistantMessage: the last assistant message to fork from
AgentTool.call(input, context, context.canUseTool!, lastAssistantMessage).catch(error => {
logForDebugging(`Fork subagent async error: ${error}`, { level: 'error' });
});

View File

@ -99,6 +99,22 @@ export function runPostCompactCleanup(querySource?: QuerySource): void {
})
}
clearSessionMessagesCache()
// Memory leak #14: Release LSP server file tracking state.
// closeAllFiles() sends didClose for every tracked file and clears the Map.
// Next file access re-opens only what's needed, preventing unbounded growth
// in long sessions. Fire-and-forget: best-effort release, non-blocking.
if (isMainThreadCompact) {
void import('../lsp/manager.js')
.then(m => {
const manager = m.getLspServerManager()
if (manager) return manager.closeAllFiles()
})
.catch(error => {
logError(error)
})
}
for (const cb of compactCleanupCallbacks) {
try {
cb()