Files
claude-code/docs/features/summary-command-design.md
unraid 95fece4b51 feat: 整合功能恢复与技能学习闭环(含 ECC v2.1 parity + Opus 4.7 接入 + prompt 工程优化)
主要变更:
- Skill Learning 闭环系统 (9/9 AC)
- Opus 4.7 模型层接入 + adaptive thinking
- Prompt 工程优化 (64 审计测试)
- Agent Teams 简化门控 (默认启用)
- Windows Terminal 后端修复 (EncodedCommand/WT_SESSION)
- TF-IDF 技能搜索精准化 (字段加权/CJK 优化)
- Autonomy 系统 (/autonomy 命令)
- ACP 协议完整实现
- mock.module 泄漏修复 (CI 全绿)
- 152+ lint/type 修复
2026-04-22 16:07:42 +08:00

13 KiB
Raw Blame History

/summary 完整实现设计(基于现有代码反推)

更新日期: 2026-04-15 设计目标: 基于当前仓库已有能力,设计一个完整可交付/summary 命令,而不是只补最小可用版本。 结论口径: 以当前源码为准,优先复用现有 SessionMemory、session transcript、resume/session listing 相关能力,不另起一套平行系统。

一、设计结论

/summary 的完整实现,应该分成两条能力线:

  1. 当前会话摘要

    • 显式触发一次最新摘要生成
    • 读取并展示当前 session memory 的 summary.md
  2. 历史会话摘要查看

    • 查看最近会话的摘要
    • 按 session id 查看指定会话的摘要
    • 按标题关键词查找会话摘要

这两条能力线应复用两套已有系统:

  • 当前会话SessionMemory
  • 历史会话sessionStorage.ts / listSessionsImpl.ts

不应该做的是:

  • 新造一个“即时摘要模型调用”系统
  • 用另一套 prompt 平行生成 summary
  • /summary 做成和现有 session memory 脱钩的独立功能

二、现有代码里已经具备的基础

2.1 命令入口已注册,但当前仍是 stub

文件:

  • src/commands/summary/index.js
  • src/commands.ts

现状:

  • src/commands.ts 已静态导入 summary
  • src/commands/summary/index.js 仍为隐藏 stub

这说明:

  • /summary 已经是一个明确存在的产品面
  • 不是“新功能提案”,而是“已注册但未实现的命令”

2.2 当前会话摘要:已有专门的手动触发入口

文件:

  • src/services/SessionMemory/sessionMemory.ts

现状:

源码注释已经明确说明:

/**
 * Manually trigger session memory extraction, bypassing threshold checks.
 * Used by the /summary command.
 */
export async function manuallyExtractSessionMemory(...)

这意味着 /summary 当前会话模式的核心调用入口已经被设计好了。

2.3 当前会话摘要内容:已有统一读取口

文件:

  • src/services/SessionMemory/sessionMemoryUtils.ts
  • src/utils/permissions/filesystem.ts

现状:

  • getSessionMemoryPath() 返回当前 session memory 文件路径
  • getSessionMemoryContent() 返回当前 summary.md 内容

因此 /summary 不需要再自己拼装“当前会话摘要文本”,而应直接展示该文件内容。

2.4 历史会话摘要:已有 transcript 元数据能力

文件:

  • src/utils/sessionStorage.ts
  • src/utils/listSessionsImpl.ts

已有能力:

  • getLastSessionLog(sessionId):读取单个 session 的 transcript 汇总视图
  • searchSessionsByCustomTitle(query):按自定义标题搜索 session
  • listSessionsImpl(options):列出 session 摘要元数据
  • getSessionFilesLite(projectDir, limit):快速拿 lite logs

这意味着:

  • /summary session <id> 不需要重新扫完整 transcript 逻辑
  • /summary find <query> 不需要重新造搜索层
  • /summary recent 可以直接复用 session listing

2.5 现有命令体系支持“一级命令 + 二级动作”

文件:

  • src/types/command.ts
  • src/utils/processUserInput/processSlashCommand.tsx
  • src/commands/mcp/mcp.tsx
  • src/commands/job/job.tsx
  • src/commands/daemon/daemon.tsx

当前 slash command 体系本来就是:

  1. processSlashCommand() 解析 /command [args]
  2. 再把 args 原样传给命令实现
  3. 命令自己解析二级动作

因此 /summary 最合理的实现方式也是:

  • 一级命令:/summary
  • 二级动作:由 args 解析

而不是额外拆成:

  • /summary-last
  • /summary-find
  • /summary-session

这种平铺命名。

三、命令形态:一级命令 + 二级动作

建议统一语法:

/summary <subcommand> [args]

无参数时:

/summary

等价于:

/summary refresh

也就是:

  • 对当前会话显式触发一次 session memory 提取
  • 然后展示摘要结果

3.1 当前会话动作

/summary
/summary refresh
/summary raw
/summary path

语义:

  • /summary 刷新当前会话摘要并以友好格式展示
  • /summary refresh/summary 等价,但语义更显式
  • /summary raw 刷新后输出完整 summary.md
  • /summary path 输出当前摘要文件路径

3.2 历史会话动作

/summary last
/summary recent
/summary recent <n>
/summary session <session-id>
/summary find <query>

语义:

  • /summary last 查看最近一个会话的摘要
  • /summary recent 列出最近若干会话摘要
  • /summary recent <n> 列出最近 n 个会话摘要
  • /summary session <session-id> 查看指定 session 的摘要
  • /summary find <query> 按标题关键词搜索并展示匹配会话摘要

3.3 为什么 find <query> 第一版只查 title

因为当前已有现成能力就是:

  • searchSessionsByCustomTitle(query)

如果第一版就强行做:

  • title + firstPrompt + summary 全字段模糊搜索

那就会把简单实现拖进一个新的 session search 设计里。

完整实现不等于“一口气做最大范围”;完整实现应该先建立稳定语义,再逐步扩展搜索范围。

四、每种模式对应的数据源

模式 数据源 说明
summary / refresh / raw / path SessionMemory 当前会话,显式触发提取后读取 summary.md
last listSessionsImpl + getLastSessionLog 先找最近 session再读详细摘要
session <id> getLastSessionLog 直接读取指定 session
recent [n] listSessionsImpl 展示摘要列表,不需要全量 transcript
find <query> searchSessionsByCustomTitle 第一版先按 customTitle 查找

五、命令模块设计

建议实现文件:

  • src/commands/summary/index.ts

导出形态:

const summary = {
  type: 'local',
  name: 'summary',
  description: 'Generate or view session summaries',
  supportsNonInteractive: true,
  load: () => Promise.resolve({ call }),
} satisfies Command

5.1 为什么是 local

因为当前实现需要:

  • 参数路由
  • 条件分支
  • 调用已有函数
  • 错误处理
  • 文件读取

这不是“给模型一段说明让它去决定”的场景,而是“命令协调器”的场景。

5.2 为什么不拆成多条平铺命令

因为当前仓库已有约定是:

  • 一个命令负责一个命名空间
  • 子动作由 args 解析

所以 /summary 的实现应更接近:

  • /mcp ...
  • /job ...
  • /daemon ...

而不是单独拆出多条并列命令。

六、内部实现结构建议

建议拆成 4 组 helper而不是把所有逻辑塞进 call()

6.1 参数解析

建议函数:

function parseSummaryArgs(args: string): SummaryCommandInput

返回一个判别联合:

type SummaryCommandInput =
  | { mode: 'current'; raw: boolean }
  | { mode: 'path' }
  | { mode: 'last' }
  | { mode: 'session'; sessionId: UUID }
  | { mode: 'recent'; limit: number }
  | { mode: 'find'; query: string }

建议实际解析规则:

''         -> { mode: 'current', raw: false }
'refresh'  -> { mode: 'current', raw: false }
'raw'      -> { mode: 'current', raw: true }
'path'     -> { mode: 'path' }
'last'     -> { mode: 'last' }
'recent'   -> { mode: 'recent', limit: DEFAULT_RECENT_LIMIT }
'recent 5' -> { mode: 'recent', limit: 5 }
'session <id>' -> { mode: 'session', sessionId }
'find foo bar' -> { mode: 'find', query: 'foo bar' }

6.2 当前会话摘要执行

建议函数:

async function runCurrentSessionSummary(
  messages: Message[],
  toolUseContext: ToolUseContext,
  opts: { raw?: boolean }
): Promise<LocalCommandResult>

职责:

  1. 校验是否有消息
  2. 调用 manuallyExtractSessionMemory()
  3. 调用 getSessionMemoryContent()
  4. 组装文本结果

6.3 历史会话摘要读取

建议函数:

async function runHistoricalSummary(
  input: HistoricalSummaryInput
): Promise<LocalCommandResult>

支持:

  • last
  • session
  • recent
  • find

6.4 格式化输出

建议统一 formatter

function formatCurrentSummary(...)
function formatSessionSummary(...)
function formatRecentSessionList(...)

避免命令逻辑和显示逻辑缠在一起。

七、当前会话模式的完整调用链

/summary
  -> processSlashCommand()
  -> commands.ts 中 summary
  -> summary/index.ts local call()
  -> parseSummaryArgs()
  -> runCurrentSessionSummary()
  -> manuallyExtractSessionMemory(messages, toolUseContext)
  -> SessionMemory 子代理更新 summary.md
  -> getSessionMemoryContent()
  -> formatCurrentSummary()
  -> 返回 LocalCommandResult { type: 'text' }

八、历史会话模式的完整调用链

8.1 /summary last

/summary last
  -> listSessionsImpl({ dir: getOriginalCwd(), includeWorktrees: true, limit: 2+ })
  -> 取最近一条非当前 session
  -> getLastSessionLog(sessionId)
  -> formatSessionSummary()

8.2 /summary session <id>

/summary session <id>
  -> getLastSessionLog(sessionId)
  -> formatSessionSummary()

8.3 /summary recent [n]

/summary recent 5
  -> listSessionsImpl({ dir: getOriginalCwd(), includeWorktrees: true, limit: 5 })
  -> formatRecentSessionList()

8.4 /summary find <query>

/summary find auth
  -> searchSessionsByCustomTitle('auth')
  -> formatSessionSummary() or formatRecentSessionList()

九、输出格式设计

9.1 当前会话默认输出

建议:

Session summary updated.

<summary.md 内容>

9.2 当前会话 path 模式

Session summary path:
<absolute-path>

9.3 历史会话摘要输出

建议包含:

  • session id
  • custom title / summary / firstPrompt 的优先展示
  • modified 时间
  • tag / gitBranch / projectPath若存在

例如:

Session: <id>
Title: Fix auth redirect loop
Updated: 2026-04-15 14:20
Branch: fix/auth-redirect
Tag: auth

Summary:
<summary text>

9.4 recent 模式输出

建议压缩成列表:

Recent sessions:

1. <id>  Fix auth redirect loop
   Updated: 2026-04-15 14:20

2. <id>  Add session memory tests
   Updated: 2026-04-15 10:03

十、错误模型

至少覆盖以下情况:

10.1 当前会话

  • 没有消息可总结
  • 手动提取失败
  • 提取成功但读取失败
  • 文件为空

10.2 历史会话

  • session id 不合法
  • session 不存在
  • session 存在但没有可提取摘要
  • find 无匹配结果

建议文案:

  • No messages to summarize.
  • Failed to generate session summary: <error>
  • Session summary was updated, but could not be read back.
  • Session summary is empty.
  • Session not found: <id>
  • No matching sessions found for "<query>".

十一、和现有能力的边界

11.1 不替代 task summary

task summary 仍然只负责:

  • 后台会话中途状态
  • claude ps 风格展示

/summary 不要去读或改 saveTaskSummary() 这条链。

11.2 不替代 away summary

away summary 仍然是:

  • 极短 recap
  • 离开/回来场景

/summary 应该输出更完整内容。

11.3 不新造第二套 session summary 存储

当前会话继续使用:

  • summary.md

历史会话继续使用:

  • transcript 中已有 summary/customTitle/firstPrompt

十二、测试设计

建议新建:

  • src/commands/__tests__/summary.test.ts

至少覆盖:

12.1 当前会话

  1. /summary 成功路径
  2. /summary raw
  3. /summary path
  4. manuallyExtractSessionMemory() 失败
  5. getSessionMemoryContent() 返回空

12.2 历史会话

  1. /summary session <id> 成功
  2. /summary session <id> 找不到 session
  3. /summary last
  4. /summary recent
  5. /summary find <query> 有结果
  6. /summary find <query> 无结果

12.3 参数解析

  1. 无参数
  2. 非法参数
  3. 缺少 session <id> 的 id
  4. recent 的 limit 非法

十三、分阶段落地

Phase 1当前会话

  • /summary
  • /summary refresh
  • /summary raw
  • /summary path

Phase 2历史会话

  • /summary last
  • /summary session <id>
  • /summary recent [n]

Phase 3搜索

  • /summary find <query>
  • 搜索范围增强(如标题之外的字段)

十四、验收标准

完整实现完成时,应满足:

  1. /summary 不再是隐藏 stub
  2. 当前会话摘要链路完整可用
  3. 历史会话摘要查看链路完整可用
  4. 参数语义稳定
  5. 错误分支有清晰输出
  6. 测试覆盖当前会话 + 历史会话主路径

十五、后续扩展

在完整实现落地后,再考虑:

  1. section 过滤
  2. richer search
  3. 指定输出格式markdown/plain/json
  4. /resume 和 session picker 的更强联动

但这些不应阻塞本次实现。