paseo-req-kit 0.0.0-stage → 1.8.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +283 -0
  2. package/LICENSE +21 -0
  3. package/README.md +146 -2
  4. package/SCOPE.md +11 -0
  5. package/bin/locate.mjs +46 -0
  6. package/bin/req-doctor.mjs +21 -0
  7. package/bin/req.mjs +179 -0
  8. package/bin/start-pipeline +21 -0
  9. package/bin/start-pipeline.mjs +22 -0
  10. package/config.example.json +132 -0
  11. package/contracts/README.md +18 -0
  12. package/contracts/feature-files.md +117 -0
  13. package/contracts/notifier-event.md +72 -0
  14. package/contracts/result-file.md +21 -0
  15. package/contracts/spec.md +36 -0
  16. package/contracts/state.md +49 -0
  17. package/contracts/verify.md +41 -0
  18. package/docs/adr/0001-step-agents-under-origin-chat.md +15 -0
  19. package/docs/adr/0002-no-directory-switch-in-chat.md +15 -0
  20. package/docs/adr/0003-script-engine-not-hub.md +15 -0
  21. package/docs/adr/0004-result-files.md +15 -0
  22. package/docs/adr/0005-no-default-branch-local-commits-only.md +15 -0
  23. package/docs/adr/0006-skill-install-targets.md +15 -0
  24. package/docs/adr/0007-own-interview-skill.md +15 -0
  25. package/docs/adr/0008-entries-do-not-call-entries.md +15 -0
  26. package/docs/adr/0009-versioned-install-layout.md +15 -0
  27. package/docs/adr/0010-generated-feature-overview.md +15 -0
  28. package/docs/adr/0011-resume-after-completion.md +15 -0
  29. package/docs/adr/0012-review-panel.md +18 -0
  30. package/docs/adr/0013-no-release-tooling.md +15 -0
  31. package/docs/adr/0014-notifier-slot.md +19 -0
  32. package/docs/adr/0015-incremental-continue.md +17 -0
  33. package/docs/adr/0016-upgrade-from-tags.md +19 -0
  34. package/docs/adr/0017-use-paseo-capabilities.md +18 -0
  35. package/docs/adr/0018-own-worktree-option.md +21 -0
  36. package/docs/adr/0019-parallel-orchestration.md +21 -0
  37. package/docs/adr/0020-scheduling-through-the-chat.md +21 -0
  38. package/docs/adr/0021-npm-version-manager.md +19 -0
  39. package/docs/adr/0022-develop-and-verify-phases.md +32 -0
  40. package/docs/adr/0023-types-gate-slices.md +54 -0
  41. package/docs/adr/0024-confirm-early-review-axes.md +27 -0
  42. package/docs/adr/0025-joint-requirements.md +27 -0
  43. package/docs/adr/README.md +29 -0
  44. package/docs/guide//344/275/277/347/224/250/350/200/205/346/214/207/345/215/227.md +96 -0
  45. package/docs/guide//345/256/211/350/243/205/344/270/216/345/215/207/347/272/247.md +348 -0
  46. package/docs/guide//347/273/264/346/212/244/350/200/205/346/214/207/345/215/227.md +85 -0
  47. package/docs/guide//351/241/271/347/233/256/345/256/232/345/210/266/344/270/216/350/277/220/350/241/214/350/247/204/345/210/231.md +356 -0
  48. package/engine/prompts/00-shared-context.md +104 -0
  49. package/engine/prompts/02-spec-review.md +46 -0
  50. package/engine/prompts/03-design.md +73 -0
  51. package/engine/prompts/03a-design-proposal.md +30 -0
  52. package/engine/prompts/04-design-review.md +73 -0
  53. package/engine/prompts/04b-design-revise.md +41 -0
  54. package/engine/prompts/05-implement.md +72 -0
  55. package/engine/prompts/06-code-review.md +70 -0
  56. package/engine/prompts/07-review-fix.md +41 -0
  57. package/engine/prompts/07b-handoff.md +45 -0
  58. package/engine/prompts/08-service-start.md +59 -0
  59. package/engine/prompts/09-verify.md +90 -0
  60. package/engine/prompts/10-defect-fix.md +41 -0
  61. package/engine/prompts/10b-reverify.md +43 -0
  62. package/engine/prompts/11-report.md +112 -0
  63. package/engine/prompts/browser-verify.md +13 -0
  64. package/engine/prompts/incremental.md +22 -0
  65. package/engine/prompts/joint.md +55 -0
  66. package/engine/prompts/panel-member.md +38 -0
  67. package/engine/prompts/paseo-services.md +9 -0
  68. package/engine/prompts/related-repos.md +7 -0
  69. package/engine/prompts/review-axis-spec.md +10 -0
  70. package/engine/prompts/review-axis-standards.md +11 -0
  71. package/engine/prompts/types/assessment.md +41 -0
  72. package/engine/prompts/types/defect.md +55 -0
  73. package/engine/prompts/types/refactor.md +39 -0
  74. package/engine/prompts/verify-deployed.md +14 -0
  75. package/engine/src/activity.ts +87 -0
  76. package/engine/src/cli-args.ts +217 -0
  77. package/engine/src/config.ts +619 -0
  78. package/engine/src/configure.ts +237 -0
  79. package/engine/src/control.ts +246 -0
  80. package/engine/src/daemon-check.ts +104 -0
  81. package/engine/src/daemon-version.ts +66 -0
  82. package/engine/src/digest.ts +142 -0
  83. package/engine/src/doctor.ts +462 -0
  84. package/engine/src/eval.ts +324 -0
  85. package/engine/src/features.ts +270 -0
  86. package/engine/src/gate.ts +157 -0
  87. package/engine/src/git.ts +30 -0
  88. package/engine/src/joint.ts +173 -0
  89. package/engine/src/launch.ts +405 -0
  90. package/engine/src/lessons.ts +72 -0
  91. package/engine/src/locations.ts +55 -0
  92. package/engine/src/main.ts +346 -0
  93. package/engine/src/messages.ts +394 -0
  94. package/engine/src/notifiers.ts +76 -0
  95. package/engine/src/notify-test.ts +101 -0
  96. package/engine/src/paseo-json.ts +73 -0
  97. package/engine/src/paseo-profiles.ts +133 -0
  98. package/engine/src/paseo-runtime.ts +437 -0
  99. package/engine/src/paths.ts +10 -0
  100. package/engine/src/pipeline.ts +1840 -0
  101. package/engine/src/playbooks.ts +46 -0
  102. package/engine/src/preflight.ts +337 -0
  103. package/engine/src/prompts.ts +72 -0
  104. package/engine/src/queue.ts +61 -0
  105. package/engine/src/runtime-loader.ts +14 -0
  106. package/engine/src/runtime.ts +155 -0
  107. package/engine/src/schedule-time.ts +51 -0
  108. package/engine/src/smoke-test.ts +202 -0
  109. package/engine/src/spec-review.ts +100 -0
  110. package/engine/src/state.ts +333 -0
  111. package/engine/src/steps.ts +266 -0
  112. package/engine/src/usage.ts +67 -0
  113. package/engine/src/worktree.ts +72 -0
  114. package/install.mjs +928 -0
  115. package/notifiers/im-template.mjs +60 -0
  116. package/package.json +67 -4
  117. package/principles/INDEX.md +11 -0
  118. package/skills/acceptance-criteria/SKILL.md +61 -0
  119. package/skills/principle-delete-before-add/SKILL.md +33 -0
  120. package/skills/principle-dont-block-on-humans/SKILL.md +35 -0
  121. package/skills/principle-fix-root-cause/SKILL.md +33 -0
  122. package/skills/principle-prove-it-works/SKILL.md +33 -0
  123. package/skills/principle-report-honestly/SKILL.md +33 -0
  124. package/skills/principle-speak-to-reader/SKILL.md +33 -0
  125. package/skills/principle-this-requirement-only/SKILL.md +33 -0
  126. package/skills/req/SKILL.md +101 -0
  127. package/skills/req/playbooks/accept.md +65 -0
  128. package/skills/req/playbooks/change.md +51 -0
  129. package/skills/req/playbooks/incident.md +55 -0
  130. package/skills/req/playbooks/new.md +94 -0
  131. package/skills/req/playbooks/small.md +48 -0
  132. package/skills/req/playbooks/status.md +41 -0
  133. package/skills/req/playbooks/takeover.md +51 -0
  134. package/skills/req/playbooks/verify.md +57 -0
  135. package/skills/req-doctor/SKILL.md +36 -0
  136. package/skills/req-retro/SKILL.md +81 -0
  137. package/skills/req-setup/SKILL.md +118 -0
  138. package/skills/req-setup/templates/paseo/copy-local-files.mjs +32 -0
  139. package/skills/req-setup/templates/paseo/with-port.mjs +36 -0
  140. package/skills/requirement-interview/SKILL.md +97 -0
  141. package/skills/requirement-kickoff/SKILL.md +17 -0
  142. package/skills/result-report/SKILL.md +34 -0
  143. package/skills/spec-writing/SKILL.md +55 -0
  144. package/skills/spec-writing/spec-template.md +109 -0
@@ -0,0 +1,112 @@
1
+ # 本步骤任务:完成报告与总结(第 11 步)
2
+
3
+ ## 目标
4
+
5
+ 为提出这个需求的人写一份报告 `report.md`,让他们读完之后知道三件事:需求做成了没有、现在可以怎么用、接下来需要他们做什么。
6
+
7
+ 读者是需求方:测试、产品或项目经理这类有一定技术背景、但不读代码的同事,也没有看过中间任何过程。他们会根据这份报告决定是否验收,并且可能亲自核对,所以报告里的每个结论都必须有前面步骤的记录作为依据,并写明证据在哪里(运行的命令、关键输出、截图或日志的路径)。
8
+
9
+ 无论流水线走到了哪一步,本步骤都会执行。如果前面在方案审核时被阻塞,或者验证没有通过,报告的任务就是把实际情况和需要他们做的决定讲清楚。
10
+
11
+ ## 做法
12
+
13
+ 1. 阅读功能目录里的全部文件。有些文件可能不存在,这说明对应的步骤没有执行。根据 `progress.md` 和现有的文件,判断流水线实际走到了哪里。
14
+ 2. 确定总体结论,按下面的规则从严判定:
15
+ - **已完成,可以验收**:所有 AC 的最终结论都是通过,没有遗留的"严重"或"一般"缺陷,也没有未处理的"阻塞"或"重要"评审意见。
16
+ - **已完成,有遗留问题**:功能已经实现并且主流程可用,但有 AC 不通过或无法验证,或有尚未解决的问题。
17
+ - **未完成**:没有进入实现(例如方案审核阻塞),或者实现没有做完,或者主流程不可用。
18
+
19
+ 流水线质量门中"要求修复后仍失败"的检查(见 `<pipeline-context>`),视同未解决的问题:结论最高为"已完成,有遗留问题",并在遗留问题中说明是哪个检查、对使用者意味着什么。
20
+
21
+ AC 的最终结论以 `verification.md` 中最后一轮"复验结果"为准;没有复验时以功能验证的结果为准;没有做过验证的 AC 一律按"未验证"处理,不能算作通过。
22
+ 3. 花一点时间核对最关键的事实:功能分支是否存在、最近的提交是否与记录一致。如果发现记录之间互相矛盾,采用更保守的那个说法,并在报告里指出。
23
+ 4. 写 `report.md`。
24
+
25
+ ## 写作要求
26
+
27
+ - 第一句话就给出结论,不要铺垫。
28
+ - 正文讲需求和结果,不讲代码实现。说"提交之后审批人会立刻收到通知",而不是"实现了事件发布和订阅"。接口、字段、页面、测试命令这类需求方熟悉的内容可以直接写;类名、函数名、提交号放到附录里。
29
+ - 引用 spec 的编号(FR、AC)时,同时写出它的内容,读者不会去翻 spec。
30
+ - 不夸大,也不轻描淡写。有问题的地方,说明它对使用者意味着什么(谁会受到影响、在什么情况下出现、有没有临时的应对办法)。
31
+ - 需要读者做决定的事项,写成他们可以直接回答的问题,并附上你的建议。
32
+ - 篇幅以读者能在五分钟内读完正文为准。
33
+
34
+ ## `report.md` 的结构
35
+
36
+ **正文(给需求方)**
37
+
38
+ 1. **结论**:三种结论之一,加上一两句话说明
39
+ 2. **现在可以做什么**:做成之后用户能看到的变化。可以引用 `design.md` 的"影响摘要",但要按照实际完成的情况修正。
40
+ 3. **验收对照**:
41
+
42
+ | 你提的要求 | 结果(已达成 / 未达成 / 未验证) | 是怎么确认的 |
43
+ | --- | --- | --- |
44
+
45
+ 每条 AC 一行,"你提的要求"一栏转述它的内容;"是怎么确认的"一栏写明证据,例如运行的测试命令及结果、截图路径,方便需求方自己复核。
46
+ 4. **遗留问题与风险**:每一项说明现象、复现方式、对使用者的影响、建议的处理方式。没有就写"无"。
47
+ 5. **需要你确认的决定**:汇总 spec、方案、实现各阶段的假设,以及 `decisions.tsv` 中 `needs_human` 为 `yes` 的行,请他们确认。每条写清:做了什么决定、为什么、如果不同意会怎样。被驳回的评审意见只要影响使用者能看到的结果,也列在这里。纯技术性的决定不放在这里,放在附录。
48
+ 6. **需要你做的事**:按顺序列出。通常包括:怎么亲自试用一下(给出具体步骤,能用命令验证的给出命令)、需要回答的问题、请开发同事审阅代码并合并上线。
49
+ 7. **没有做的事**:spec 中明确不做的范围,以及这次没有完成的部分,避免误会。
50
+
51
+ **过程总结**
52
+
53
+ 8. **各阶段情况**:方案设计、方案审核、代码实现、代码评审、服务启动、功能验证、缺陷修复,每个阶段用一两句话说明结果和经过了几轮(例如"审核两轮:第一轮提出 3 条必须修改的意见,修订后第二轮通过")。没有执行的阶段写明"未执行"和原因。
54
+ 9. **经验与改进建议**:这次过程中暴露了什么(例如某个问题本来可以在需求对齐阶段就问清楚),下次可以怎么改进。只写确实从这次过程中观察到的,两三条即可。
55
+
56
+ **附录(给开发同事)**
57
+
58
+ 10. 功能分支名、基线提交和最终提交
59
+ 11. 改动文件概览
60
+ 12. 测试情况:数量、通过率、新增的测试;流水线质量门的结果(照抄 `<pipeline-context>` 中"质量门"几行的结论:基线、每次运行是否通过、要求修复后仍失败的检查);范围检查的结论(方案之外改动了哪些文件、评审的判断)
61
+ 13. 未处理的评审意见和缺陷的编号清单;`decisions.tsv` 中 `needs_human` 为 `no` 的决定条数,以及其中的驳回意见
62
+ 14. 各产物文件的路径
63
+ 15. 用时与用量:照抄 `<pipeline-context>` 中"用时与用量"的数字,不要自行估算;没有时写"未记录"
64
+
65
+ ## 记录可以变成规则的问题(`lessons.tsv`)
66
+
67
+ 报告写完后,从 `code-review.md`(包括评审小组和"规范评审"的意见)、质量门的结果和 `verification.md` 的缺陷中,挑出**一条项目级的规则就能在以后挡住**的问题:例如"拼接 SQL 字符串""接口没有校验分页参数""测试里用了真实的当前时间"。只和这个需求本身有关的问题不算。
68
+
69
+ 有这样的问题时,在功能目录写 `lessons.tsv`(UTF-8,制表符分隔,第一行为表头,同一个问题只写一行):
70
+
71
+ ```text
72
+ category finding source rule layer
73
+ ```
74
+
75
+ - `category`:问题的类别,两到六个字,例如"输入校验""SQL 拼接""时间处理"。先看看其他需求的 `docs/features/*/lessons.tsv` 用过哪些类别,同一类问题沿用同一个名字,这样才能看出它在反复出现
76
+ - `finding`:一句话说明这次的问题;`source`:出处,如 `CR-3`、`缺陷 D-2`、`质量门 lint`
77
+ - `rule`:建议的规则,一句话,例如"lint 规则 no-restricted-syntax 禁止模板字符串拼接 SQL"
78
+ - `layer`:规则放在哪一层:`lint`、`类型`、`测试`、`项目说明`(能用前三种的,不写成项目说明)
79
+
80
+ 没有这样的问题就不写这个文件。它和报告一起提交。需求总览会提示在几个需求里反复出现的类别,`/req-retro` 会据此建议把它变成项目的规则。
81
+
82
+ ## 只做研发时
83
+
84
+ `<pipeline-context>` 中有"只做研发"一行时,流水线没有做测试验证,测试由人按 `handoff.md` 来做。这时写的是**研发报告**:
85
+
86
+ - 结论一节说明"研发已完成,待人工测试",再按上面的规则给出结论,但 AC 没有经过验证这件事本身不算遗留问题。
87
+ - 验收对照表的"结果"一栏,有自动化测试覆盖的写"自动化测试通过(待人工确认)",其余写"待人工测试";"是怎么确认的"一栏写对应的测试或"未测试"。
88
+ - "需要你做的事"第一条是按 `handoff.md` 做人工测试,列出"建议重点测试"中的要点。
89
+ - 结果文件的 `outcome`:研发完成且代码评审没有遗留"阻塞"或"重要"意见时写 `completed`;有遗留意见或未完成项时写 `completed_with_issues`;没有完成实现时写 `not_completed`。
90
+
91
+ ## 测试验证的其他做法
92
+
93
+ `<pipeline-context>` 中的"测试验证"一行说明这次验证的环境和缺陷处理方式:
94
+
95
+ - 在已部署的测试环境中验证的,在验收对照的证据中写明测试环境和被测的版本;"待重新部署后复验"的项目列入"需要你做的事"。
96
+ - 缺陷"只记录,不修复"的,所有缺陷都列入遗留问题,写明严重程度和复现方式,结论按上面的规则判定。
97
+ - 缺陷"退回研发阶段修复"的,在各阶段情况中写明退回了几次、每次修了什么(见 `changes.md` 中"测试验证退回"各节)。
98
+
99
+ ## 结果文件
100
+
101
+ ```json
102
+ {
103
+ "outcome": "completed",
104
+ "summary": "给需求方的结果摘要"
105
+ }
106
+ ```
107
+
108
+ - `outcome`,三选一,与报告结论一致:
109
+ - `completed`:已完成,可以验收
110
+ - `completed_with_issues`:已完成,有遗留问题
111
+ - `not_completed`:未完成
112
+ - `summary`:不超过 8 行的摘要,会被直接转达给需求方。包括:做成了什么、有什么遗留问题(如有)、需要他们做的第一件事。不讲代码实现,不写文件路径(报告路径会另外附上)。
@@ -0,0 +1,13 @@
1
+ # 用浏览器验证网页界面
2
+
3
+ `<pipeline-context>` 中有"浏览器"一行,说明你可以使用 Paseo 内置的浏览器(`browser_*` 工具)。需求方可以在 Paseo 桌面端实时看到你在浏览器中的操作。
4
+
5
+ 涉及网页界面的验收标准,**像使用者一样在浏览器里实际操作一遍**,而不是只看代码或只调接口:
6
+
7
+ 1. 用 `browser_new_tab` 打开服务地址(服务由 Paseo 管理时用给出的地址)。
8
+ 2. 按验收标准的"操作"一步步做:`browser_snapshot` 找到元素,用 `browser_click`、`browser_fill`、`browser_select` 等操作,用 `browser_wait` 等待结果出现。
9
+ 3. 用 `browser_snapshot` 核对页面上的结果是否符合"预期结果";关键画面用 `browser_screenshot` 截图。需要检查手机布局时用 `browser_resize`。出现异常时用 `browser_logs` 查看控制台和网络请求。
10
+ 4. 在产物中记录:打开的地址、操作步骤、看到的结果、对应的 AC 编号,并注明"浏览器验证,截图见该步骤 agent 的对话记录"。
11
+ 5. 用完关闭你打开的标签页(`browser_close_tab`)。
12
+
13
+ 浏览器工具返回 `browser_no_host`(桌面端没有连接)或 `browser_disabled` 时,不要反复重试,改用接口调用、端到端测试等其他方式验证,并在产物中说明浏览器验证没能进行。不要在浏览器中登录生产环境或输入真实的个人信息。
@@ -0,0 +1,22 @@
1
+ # 这次是需求变更后的继续
2
+
3
+ `<pipeline-context>` 中有"增量继续"一行,说明这个需求之前已经做过一轮(方案,可能还有代码),之后需求说明被修改了:需求方改了需求、回答了方案审核提出的问题,或者验收时发现了问题。这一次**在已有工作的基础上只处理变化的部分**,不要推倒重来。
4
+
5
+ 先了解变了什么:
6
+
7
+ - 读 `changes.md` 的最后一节(变更内容、原因),再对照 `spec.md` 当前版本。没有 `changes.md` 时,用 `git log -p -- <功能目录>/spec.md` 查看 spec 最近的改动。
8
+ - 方案审核提出过问题的,读 `design-review.md` 最后一轮的问题和 `alignment.md` 中对应的回答。
9
+ - 验收发现问题的,读 `acceptance.md` 中"不通过的处理"。
10
+ - 方案确认时需求方提出修改的(`changes.md` 最后一节的原因写着"方案确认时的修改"),方案设计按修改调整方案,并同步更新 `preview.md` 和 `prototype/`,之后会再请需求方确认一次。
11
+ - 测试验证退回的(增量继续的原因写着"测试验证发现缺陷"),读 `changes.md` 最后的"测试验证退回"一节和 `verification.md` 最后一轮的缺陷清单。这一次只修这些缺陷:方案设计写修复计划,代码实现逐个修复并补测试,最后重新写 `handoff.md`(追加"第 N 次提测"一节,说明修了哪些缺陷)。
12
+
13
+ 各步骤的做法:
14
+
15
+ - **方案设计**:保留仍然成立的部分,在 `design.md` 末尾追加"## 第 N 次尝试:需求变更"一节,写明变化点、受影响的 FR/AC、对已有代码的改动计划(改哪些、新增哪些、哪些不动),以及需要补充或修改的测试。原有内容中已经不成立的地方,就地标注"(第 N 次尝试起不再适用,见下文)",不要整篇重写。
16
+ - **方案审核**:重点审核变化部分是否完整、是否与没变的部分冲突。
17
+ - **代码实现**:在现有代码上修改,只动与变化相关的部分;已有的、仍然正确的实现和测试保留。在 `implementation.md` 末尾追加本次的记录。
18
+ - **代码评审**:评审范围是"本次开始时的提交"之后的改动(`git diff <该提交>..HEAD`),同时确认这些改动没有破坏之前已经通过评审的部分。
19
+ - **功能验证**:变化涉及的 AC 全部重新验证;其余 AC 至少跑一遍现有的自动化测试,确认没有回退。
20
+ - **完成报告**:在开头说明这是第几次尝试、因为什么变化,验收对照表中标出哪些 AC 是这次新增或修改的。
21
+
22
+ 上一次没有写过代码时(`<pipeline-context>` 中"上一次是否已经写过代码:否"),实现类步骤按正常方式进行,只是方案设计要在已有的 `design.md` 基础上修订。
@@ -0,0 +1,55 @@
1
+ # 联合需求:一个需求,几个仓库
2
+
3
+ 这个需求同时要改几个仓库(例如前端和后端),见 `<pipeline-context>` 中"联合需求"几行。发起需求的仓库是**主仓库**:需求说明、方案、接口约定、提测说明和报告都在它的功能目录里。其他仓库各有一个为这个需求新建的工作区,分支同名;它们的功能目录中是从主仓库同步过来的需求说明、方案和接口约定,以及在那里进行的实现和评审记录。
4
+
5
+ ## 所有步骤
6
+
7
+ - **接口约定**(主仓库功能目录的 `contract.md`)是各仓库之间唯一的约定:接口路径、请求和响应的字段、错误码、示例。方案审核通过后它就冻结了,各仓库按它同时开发、互不等待。实现中发现它有错或不够用时,不要各自改成不同的样子:在你的产物里写明问题和建议的修改,交给评审和报告,由人决定。
8
+ - 每个仓库只改它自己的代码,只在它自己的工作区提交。不要修改其他仓库的文件,也不要去别的仓库提交。需要了解另一边的现状时,读它工作区中的代码(只读)。
9
+ - 只做本地提交,不 push,不合并。各仓库的合并顺序(通常先合提供接口的一边)写在提测说明和报告里,由人来合并。
10
+
11
+ ## 方案设计(design)
12
+
13
+ 在主仓库中设计整个需求:
14
+
15
+ 1. 读所有仓库的相关代码(各仓库工作区的路径见 `<pipeline-context>`)。
16
+ 2. 写 `contract.md`:每个接口一节,写路径和方法、请求字段(类型、是否必填、取值范围)、响应字段、错误码和对应的提示、一两组真实的请求和响应示例。示例要能直接用作测试数据:提供接口的一边用它写接口测试,调用的一边用它做测试替身(mock)。
17
+ 3. `design.md` 的方案和实施计划**按仓库分开**写:每个仓库一节,写它要改的文件、任务、测试,以及参照的已有文件。写明哪些验收标准由哪个仓库负责,哪些需要几个仓库一起才能验证(端到端)。
18
+ 4. 结果文件的 `files` 只写主仓库中的文件;其他仓库的改动范围写在 `design.md` 对应的一节。
19
+
20
+ ## 方案审核(design_review)
21
+
22
+ 额外检查 `contract.md`:字段和错误码是否完整、两边的理解会不会不同、示例是否覆盖了正常和出错的情况;各仓库的计划是否都只依赖接口约定,而不依赖对方未写明的实现细节。
23
+
24
+ ## 代码实现(implement)
25
+
26
+ 你在哪个仓库,见 `<pipeline-context>`。只实现方案中**这个仓库**的那一节,严格按 `contract.md` 来:
27
+
28
+ - 提供接口的一边:为约定中的每个接口写接口测试,请求和响应用约定中的示例。
29
+ - 调用接口的一边:用约定中的示例做测试替身,不要等另一边写完,也不要去调用另一边正在开发的代码。
30
+
31
+ ## 代码评审(code_review)
32
+
33
+ 评审的是**这个仓库**的改动。额外核对:实现与 `contract.md` 是否完全一致(路径、字段名、类型、错误码、提示文字);有没有依赖约定之外的东西。
34
+
35
+ ## 提测说明(handoff)
36
+
37
+ `handoff.md` 写在主仓库,覆盖所有仓库:每个仓库的工作区、分支和提交范围、各自改了什么;合并顺序;怎么把几个仓库一起跑起来(各自的启动方式、调用的一边怎么指向提供接口的一边的地址)。分阶段提测时写明几个仓库都要部署到测试环境。
38
+
39
+ ## 功能验证(verify)
40
+
41
+ 几个仓库一起验证:`<pipeline-context>` 中有各仓库由 Paseo 启动的服务和地址;调用的一边需要指向提供接口的一边时,按各自的验证方法配置(例如环境变量),配置方法写进 `verification.md`。按端到端的验收标准从用户入口走一遍,并核对接口的实际请求和响应与 `contract.md` 一致。
42
+
43
+ 每个缺陷写明属于哪个仓库。结果文件中加上 `defect_repos`:有缺陷的仓库名称,主仓库写 `"本仓库"`,例如 `{ "result": "defects_found", "defect_repos": ["后端"] }`。判断不了的,几个都写上。
44
+
45
+ ## 复验(reverify)
46
+
47
+ 各仓库的缺陷处理记录在各自功能目录的 `verification.md` 中(主仓库的在这里,其他仓库的在它们的工作区),都要读。其余与功能验证相同:仍有缺陷时,结果文件中的 `defect_repos` 写明这些缺陷所在的仓库。
48
+
49
+ ## 缺陷修复(defect_fix)
50
+
51
+ 你在哪个仓库,见 `<pipeline-context>`。缺陷登记在主仓库的 `verification.md` 中(`<pipeline-context>` 中"联合需求的主仓库"一行给出了它的位置),只修其中属于这个仓库的。处理记录写在**这个仓库**功能目录的 `verification.md` 末尾("## 缺陷处理记录(第 N 轮)",没有这个文件就新建),和代码一起提交在这个仓库;不要修改主仓库的文件。修复要符合 `contract.md`;缺陷其实是约定本身的问题时,不要改约定,写明情况交给复验和报告。
52
+
53
+ ## 完成报告(report)
54
+
55
+ 报告在主仓库,覆盖所有仓库。附录中按仓库列出工作区、分支、改动前后的提交、改动的文件和质量门的结果,并写明合并顺序。某个仓库没有完成的,结论最高为"已完成,有遗留问题",并说明对使用者意味着什么。
@@ -0,0 +1,38 @@
1
+ # 本步骤任务:评审小组成员
2
+
3
+ ## 目标
4
+
5
+ 这一轮评审由一个评审小组完成:几位评审者(通常使用不同的模型)各自独立评审,之后由一位汇总者核实全部意见、归类,并写出正式的评审结论。你是其中一位成员。你是哪一轮、哪一位、意见写到哪里,见 `<pipeline-context>` 中"评审小组"和"你的意见文件"两行。
6
+
7
+ 不同评审者容易发现不同的问题,所以请**独立判断**:不要读其他成员的意见文件(`review-panel/` 目录下的其他文件),也不要试图和他们保持一致。
8
+
9
+ ## 做法
10
+
11
+ 1. 按下文"评审标准"中的方法评审:读什么、检查什么、意见怎么分级,都以它为准。
12
+ 2. `<pipeline-context>` 中有"你的关注重点"时,在完整评审的基础上,对那个方面看得更仔细。
13
+ 3. 把意见写进**你自己的意见文件**(路径见 `<pipeline-context>`)。不要写入或修改 `design-review.md`、`code-review.md`,也不要改动代码。
14
+
15
+ ## 意见文件的内容
16
+
17
+ 1. **总体判断**:你认为应该通过、需要修改,还是存在必须由需求方决定的问题,一句话理由
18
+ 2. **你实际检查了什么**:读了哪些文件,运行了哪些命令及结果
19
+ 3. **意见**:按"评审标准"中的格式和级别逐条列出。每条写清问题、依据(代码位置、spec 编号、能触发问题的输入或步骤)和修复方向。只写你确认过的问题;有怀疑但没能确认的,标为"待核实"
20
+ 4. **需要需求方决定的问题**(如有)
21
+
22
+ 没有发现问题时如实写明,不需要凑数。
23
+
24
+ ## 与其他成员同时运行
25
+
26
+ 其他成员和你在同一个目录中同时工作,所以:
27
+
28
+ - 不要提交任何东西,也不要写 `progress.md` 和 `decisions.tsv`。这些优先于前文"结束方式"和"记录不显而易见的决定"中的要求;你的判断写在意见文件里,由汇总者决定是否记入决策记录。汇总者会核实你的意见,并把意见文件和正式结论一起提交。
29
+ - 不要修改任何已有文件,只写你自己的意见文件和结果文件。
30
+ - 需要启动服务时,使用不会与别人冲突的端口;拿不准时以阅读代码、运行单元测试和静态检查为主,并在意见文件中说明。
31
+
32
+ ## 结果文件
33
+
34
+ ```json
35
+ { "status": "done" }
36
+ ```
37
+
38
+ - `status`:完成了完整的评审时为 `"done"`;因为时间或环境原因只评审了一部分时为 `"partial"`,并在意见文件的"你实际检查了什么"中说明没有覆盖的部分。
@@ -0,0 +1,9 @@
1
+ # Paseo 管理的服务
2
+
3
+ 这个项目在 `paseo.json` 中定义了服务,流水线已经在本步骤开始前,通过 Paseo 带着当前的代码把它们启动好了(见 `<pipeline-context>` 中"Paseo 管理的服务"几行)。Paseo 为每个工作区分配独立的端口,同时进行的其他需求不会和你冲突。
4
+
5
+ - **直接使用给出的地址**访问服务,不要再自己启动同一个服务的另一份(会占用端口、读到旧代码)。
6
+ - 服务**没有启动成功**或**健康检查没有通过**时,先读给出的输出文件找原因。原因在这次的代码改动里的,按本步骤的要求处理;属于环境问题的,如实记录。需要时可以按项目的验证方法自己另起一份(换一个空闲端口),用完关掉。
7
+ - 你修改了代码、而服务不会自动加载修改时:如果你有 Paseo 的工作区脚本工具(`stop_workspace_script`、`start_workspace_script`),用它们重启;没有的话,按项目的验证方法另起一份带着新代码的服务来确认,用完关掉。流水线在下一个需要服务的步骤开始前,会重新启动这些服务。
8
+ - **不需要关闭** Paseo 管理的服务,流水线会在验证结束后停止它们。
9
+ - 在产物中写启动方法时,写 `paseo.json` 中的脚本名和对应的命令,并注明"由 Paseo 管理"。
@@ -0,0 +1,7 @@
1
+ # 关联仓库(只读参考)
2
+
3
+ `<pipeline-context>` 中的"关联仓库"是与本项目相关的其他代码库(例如前端项目对应的后端),由项目维护者登记,供你**阅读参考**:
4
+
5
+ - 需要了解对方的接口、数据格式、错误码、调用方式时,去读它的代码和文档,不要猜。在产物里引用时写明仓库名和文件路径,以及上下文中给出的分支和提交(对方的代码会变)。
6
+ - **只读**:不修改、不提交、不切换它的分支,不在其中安装依赖或运行会改动文件的命令。发现对方的问题,或需要对方配合的改动,写进你的产物(假设、风险或遗留问题),交给人协调。
7
+ - 验证需要对方的服务运行时:优先使用已部署的测试环境(如有说明);需要在本地启动对方的服务时,按它自己的说明启动、只用测试数据,用完关掉,不改它的任何文件。启动不了的,把相关验证记为"无法验证"并写明原因。
@@ -0,0 +1,10 @@
1
+ # 你的评审方向:规格(做的是不是要做的事)
2
+
3
+ 这一轮代码评审分两个方向,由两位评审者同时进行:你负责**规格**,另一位负责**规范**。在按上文"评审标准"完整评审的基础上,你重点回答:
4
+
5
+ - **每条 AC**:是否真的实现了(读代码,运行测试,能操作的实际操作一遍),是否有测试覆盖;测试的期望值是否与 spec 中这条 AC 的例子一致。
6
+ - **范围**:有没有做 spec 没要求的事(多出来的功能、改变了不该变的行为);`<pipeline-context>` 中"范围检查"列出的方案外文件是否必要。
7
+ - **与确认过的预览一致**:有 `preview.md`、`prototype/` 时,做出来的界面和行为是否与它们一致。
8
+ - **异常和边界**:spec 中写到的异常情况、业务规则是否都处理了,处理得是否与 spec 一致。
9
+
10
+ 项目惯例、代码风格、测试写法不是你的重点,另一位会看;顺带发现的可以简要提一句。
@@ -0,0 +1,11 @@
1
+ # 你的评审方向:规范(做得是否符合项目的标准)
2
+
3
+ 这一轮代码评审分两个方向,由两位评审者同时进行:你负责**规范**,另一位负责**规格**。在按上文"评审标准"完整评审的基础上,你重点检查:
4
+
5
+ - **项目惯例**:命名、目录结构、错误处理、日志、配置的写法是否跟随项目现状,以及方案中写明的参照文件;`GLOSSARY.md` 中业务词对应的代码名称是否一致使用。
6
+ - **测试质量**:测试检查的是行为还是实现细节;有没有恒为真的断言;有没有删除、跳过、放宽已有测试;新测试的位置和写法是否符合项目约定。
7
+ - **安全与数据**:输入校验、权限、注入、敏感信息、数据变更能否回退。
8
+ - **简单性**:不必要的抽象、重复的代码、遗留的调试代码。
9
+ - **可以变成规则的问题**:一类能用 lint 规则、类型约束或测试挡住的写法问题,在意见里写明建议的规则;完成报告会把它记入 `lessons.tsv`,同类问题在几个需求里反复出现时,会建议把它变成项目的规则。
10
+
11
+ 每条 AC 是否实现不是你的重点,另一位会看。
@@ -0,0 +1,41 @@
1
+ # 本需求类型的做法:评估
2
+
3
+ 这个需求是一次调研评估:spec 列出了要回答的问题(能不能做、怎么做、影响多大、大概要多少工作量)。**只读,不写代码**:不修改产品代码、测试和配置,功能目录之外不提交任何文件。流程是调研评估 → 评估审阅 ⇄ 评估修订 → 评估报告,没有代码实现、代码评审和验证。
4
+
5
+ ## 所有步骤
6
+
7
+ - 结论要有依据:引用代码位置(文件和行号)、实际运行的命令和输出、文档链接。推测要标明是推测。
8
+ - 可以运行只读的命令(运行测试、构建、查看依赖、在本地启动服务看看),不做会留下改动的操作,启动的进程用完关掉。需要写一次性的试验代码来回答问题时,写在功能目录的 `spike/` 下,不改项目代码。
9
+
10
+ ## 调研评估(design)
11
+
12
+ 本步骤写 `assessment.md`,不写 `design.md`。结构:
13
+
14
+ 1. **结论摘要**:逐条回答 spec 中的问题,各一两句话
15
+ 2. **现状**:相关的模块、数据、接口,带代码位置
16
+ 3. **可选方案**:两到三种(只有一种合理做法时就写一种)。每种写做法、优点、风险、影响到的模块和功能、大致工作量(按"小 / 中 / 大"给,并列出主要的工作项,不编造精确的人天)
17
+ 4. **推荐**:推荐哪一种、为什么、前提条件
18
+ 5. **风险与未知**:哪些还不确定,要怎样才能确定
19
+ 6. **如果要做**:把推荐方案写成需求草稿(标题、要做的事、建议的验收标准),可以直接作为下一个需求的起点
20
+
21
+ 结果文件中 `has_runnable_service` 写 `false`,不需要 `slices` 和 `files`。
22
+
23
+ ## 评估审阅(design_review)
24
+
25
+ 你审阅的是 `assessment.md`,不是技术方案:逐条核实其中关于代码的说法(读对应的代码);结论是否回答了 spec 中的每个问题;方案比较是否公平、风险有没有遗漏;工作量的判断有没有依据。意见按"必须修改 / 建议 / 备注"写进 `design-review.md`,结论和结果文件的规则不变。
26
+
27
+ ## 评估修订(design_revise)
28
+
29
+ 按审阅意见修订 `assessment.md`(不是 `design.md`),在它的末尾追加修订记录。
30
+
31
+ ## 评估报告(report)
32
+
33
+ `report.md` 是给需求方的评估结论,不按"验收对照"的结构写:
34
+
35
+ 1. **结论**:逐条回答 spec 中的问题
36
+ 2. **推荐的做法**和理由;其他做法为什么没选
37
+ 3. **风险**和还不确定的事
38
+ 4. **如果决定要做**:下一步怎么走(需求草稿在 `assessment.md` 最后一节;在对话里说"按评估结果提一个新需求"即可开始)
39
+ 5. **附录**:调研中实际运行的命令、引用的代码位置、审阅经过了几轮、用时与用量
40
+
41
+ 结果文件的 `outcome`:问题都有了有依据的回答时写 `completed`;部分问题没能回答时写 `completed_with_issues`;评估没有完成时写 `not_completed`。
@@ -0,0 +1,55 @@
1
+ # 本需求类型的做法:缺陷修复
2
+
3
+ 这个需求是修复一个缺陷:spec 描述了现象、复现步骤和修复后应有的行为。缺陷修复的关键是**先证明问题存在、找到原因,再修**。没有复现就动手修,等于在猜。
4
+
5
+ ## 所有步骤
6
+
7
+ - "复现"指一个能稳定重现问题的自动化测试,或者一个可以重复执行的复现脚本(命令、接口调用),修复前失败、修复后通过。它是这个需求最重要的证据,各步骤都围绕它来做和查。
8
+ - 只修这个缺陷和它的根因。看到别处有不相关的问题,记下来交给人决定;同一个根因在别处造成的问题,修在同一处的一并修好并写明。
9
+
10
+ ## 复现与定位(design)
11
+
12
+ 本步骤代替通常的方案设计,产出 `diagnosis.md` 和一份简短的 `design.md`。
13
+
14
+ 1. 按 spec 中的复现步骤,在本地实际重现问题。先写成自动化测试(项目有测试框架时首选);写不了测试的,写成复现脚本,放在测试目录或功能目录的 `repro/` 下。运行它,确认它**失败,并且失败的方式与 spec 描述的现象一致**(而不是因为测试本身写错)。
15
+ 2. 缩小范围:找到最小的触发条件,排除其他可能的原因(数据、配置、环境)。
16
+ 3. 定位根因:读代码、加临时日志、查提交历史(`git log -p`、`git bisect`),直到能用代码位置说清楚"为什么会这样"。临时的日志和调试代码用完删掉。
17
+ 4. 判断影响面:同样的原因还会在哪里造成问题;已有的错误数据是否需要修正(spec 没有提到的,写进阻塞问题或假设)。
18
+ 5. 提交复现测试或脚本。这时它是失败的,提交信息注明"复现,修复前失败"。
19
+
20
+ `diagnosis.md` 的内容:现象与复现(复现测试或脚本的位置、运行命令、失败输出的摘要)、根因(带代码位置)、排除了哪些其他原因、影响面、修复思路。
21
+
22
+ `design.md` 按通常的结构写,但可以简短:修复方案、改动的文件、实施计划(通常一片)、测试策略(复现测试,加上相邻的、不应受影响的行为)。
23
+
24
+ **复现不了时**:按 spec 的步骤和合理的变化尝试过,仍然重现不了,不要猜着改代码。在 `diagnosis.md` 中写明你尝试了什么、看到了什么,然后在结果文件中写 `"reproduced": false`,在 `questions` 中写需要需求方补充的信息,具体到能直接回答的程度(例如"出错时用的是哪种账号?大约几点操作的?")。流水线会暂停,把这些问题转给需求方。
25
+
26
+ 结果文件在通常的字段之外加上 `reproduced`:
27
+
28
+ ```json
29
+ { "has_runnable_service": true, "reproduced": true, "files": ["src/order/price.ts", "test/order/price.test.ts"] }
30
+ ```
31
+
32
+ ## 方案审核(design_review)
33
+
34
+ 重点审核 `diagnosis.md`:复现是否真的对应 spec 描述的现象;根因有没有代码上的依据,还是只是猜测;修复针对的是根因,还是只让这个现象消失;影响面是否查过。复现或根因站不住的,提为"必须修改"。
35
+
36
+ ## 代码实现(implement)
37
+
38
+ - 复现测试已经由上一步提交。先运行它,确认仍然失败,再修复,直到它通过。
39
+ - 不要修改复现测试的断言来让它通过。确实写错了的,在 `implementation.md` 中说明改了什么、为什么。
40
+ - 为影响面中提到的相关情况补测试。
41
+
42
+ ## 代码评审(code_review)
43
+
44
+ 额外核对:
45
+ - 复现测试在修复前确实失败、修复后通过:检出修复前的提交(或用 `git stash`)实际运行一次,不要只看记录。
46
+ - 修复针对的是 `diagnosis.md` 中的根因;同一个根因造成的其他问题是否处理或记录。
47
+ - 复现测试的断言在修复过程中有没有被放宽。
48
+
49
+ ## 功能验证(verify)
50
+
51
+ 按 spec 的复现步骤从用户入口重做一遍,确认现象消失;再验证相邻的、不应受影响的行为。在 `verification.md` 中写明复现步骤修复前后的对比。
52
+
53
+ ## 完成报告(report)
54
+
55
+ 用需求方能懂的话说明:问题是什么原因造成的、修了什么、怎么确认修好了(复现步骤修复前后的结果)、有没有同类问题或需要修正的数据。
@@ -0,0 +1,39 @@
1
+ # 本需求类型的做法:重构
2
+
3
+ 这个需求是改进代码本身(整理结构、拆分模块、升级依赖、消除重复等),对使用者来说**行为不变**。重构的关键是先把现有行为锁住,再小步改动,每一步都保持全部检查通过。
4
+
5
+ ## 所有步骤
6
+
7
+ - "行为不变"是这个需求最重要的验收标准,spec 中的改进目标(例如"订单模块不再依赖旧的支付库")是第二个。
8
+ - 不借重构修改行为。发现现有行为有缺陷时,记下来交给人决定,不要顺手修:修了就不再是"行为不变",也会让评审和验证无从比较。
9
+
10
+ ## 方案设计与行为锁定(design)
11
+
12
+ 1. 列出要改动的代码对外的行为:接口的输入输出、页面上看到的结果、命令的输出、写入的数据、发出的事件和日志中被别处依赖的部分。
13
+ 2. 检查这些行为现有的测试覆盖。没有覆盖的,在方案中安排**特征测试**(按代码现在的实际行为写断言,哪怕行为看起来不合理)或快照,在改动代码之前补上。
14
+ 3. 实施计划:第一个任务(或第一片)是补特征测试并提交,这时它们应当全部通过;之后每个任务都是一小步,每步结束时全部检查通过、可以单独提交和回退。
15
+ 4. 写明怎么证明"行为不变":用哪些测试和快照,改动前后怎样各运行一次来对比。
16
+
17
+ ## 方案审核(design_review)
18
+
19
+ 重点审核:行为清单是否完整(尤其是边界情况和错误处理);特征测试是否安排在改动之前;每一步是否小到可以单独回退;有没有夹带行为变化。
20
+
21
+ ## 代码实现(implement)
22
+
23
+ - 第一个任务是补特征测试:在改动前的代码上运行,全部通过后单独提交,提交信息注明"特征测试"。之后不再修改这些测试的断言;确实需要改的(例如测的是内部细节而不是行为),在 `implementation.md` 中逐个说明理由。
24
+ - 之后每一小步:改动 → 运行全部测试和检查 → 通过后提交。不通过就修到通过或撤回这一步,不要攒一大批改动再一起修。
25
+
26
+ ## 代码评审(code_review)
27
+
28
+ 首要问题是"行为有没有变":
29
+ - 找到特征测试的提交,检查之后的提交有没有修改这些测试的断言(`git diff <特征测试的提交>..HEAD -- <测试文件>`)。有修改且理由不充分的,提为"阻塞"。
30
+ - 对外接口、数据格式、错误信息、被别处依赖的日志有没有变化。
31
+ - 改进目标是否真的达成(例如依赖是否真的去掉了)。
32
+
33
+ ## 功能验证(verify)
34
+
35
+ 重点验证行为没有变:运行全部测试和快照对比;从用户入口把主要流程走一遍,与改动前的表现对比(需要时检出改动前的提交运行一次作为对照)。
36
+
37
+ ## 完成报告(report)
38
+
39
+ 用需求方能懂的话说明:改进了什么,怎么确认使用者看到的行为没有变化(哪些测试、对比的结果),以及发现但没有修的现有问题。
@@ -0,0 +1,14 @@
1
+ # 在已部署的测试环境中验证
2
+
3
+ 这一次的测试验证不在本地启动服务,而是对已经部署好的测试环境进行(`<pipeline-context>` 中有"验证环境:已部署的测试环境")。环境的情况写在功能目录的 `test-env.md` 中:访问地址、测试账号和口令从哪里取、可以使用的测试数据、不能碰的东西。
4
+
5
+ 规则:
6
+
7
+ - **先读 `test-env.md`,只使用其中列出的地址、账号和数据。** 文件里没有写的环境、账号、数据,一律不要用;需要而没有的,把相关 AC 记为"无法验证",并写明需要补充什么。
8
+ - **绝不连接生产环境,绝不使用生产凭据。** 地址看起来像生产环境,或者 `test-env.md` 里写了生产环境的内容时,停止端到端验证,在 `verification.md` 中写明原因,结果文件的 `result` 写 `"blocked"`。
9
+ - 口令、令牌按 `test-env.md` 写明的位置读取(例如环境变量、本机的配置文件),不要把它们写进任何产物、日志或提交。
10
+ - 测试环境是共享的。只做 `test-env.md` 允许的写操作;自己造的数据,结束后按 `test-env.md` 的方法清理,清理不了的在 `verification.md` 中列出。
11
+ - 先确认测试环境上运行的就是这次要测的版本:按 `test-env.md` 写的方式查看版本号、提交号或部署时间,与 `handoff.md` 中的提交范围对照。对不上时,不要继续测;在 `verification.md` 中写明,结果文件的 `result` 写 `"blocked"`。
12
+ - 单元测试和其他自动化检查仍然在本地运行。
13
+
14
+ **缺陷修复和复验**:修复只发生在本地代码里,不会自动出现在测试环境中。修复步骤在本地用测试证明修复有效;复验步骤能在本地验证的就在本地验证(单元测试、本地运行),只能在测试环境里确认的,标为"待重新部署后复验",并写明需要重新部署哪个提交。
@@ -0,0 +1,87 @@
1
+ // Turns an agent's Paseo timeline into a few plain-language lines for "做到哪了":
2
+ // what it ran, read or changed most recently. Shapes follow
3
+ // @getpaseo/protocol agent-types.ts (AgentTimelineItem, ToolCallDetail).
4
+
5
+ import type { ActivityItem } from "./runtime.js";
6
+
7
+ interface TimelineEntry {
8
+ timestamp: string;
9
+ item: unknown;
10
+ }
11
+
12
+ const clip = (text: string, max = 80) => {
13
+ const one = text.replace(/\s+/g, " ").trim();
14
+ return one.length > max ? `${one.slice(0, max - 1)}…` : one;
15
+ };
16
+
17
+ function shortPath(file: string): string {
18
+ const parts = file.split(/[\\/]/).filter(Boolean);
19
+ return parts.length > 3 ? `…/${parts.slice(-3).join("/")}` : parts.join("/");
20
+ }
21
+
22
+ function describeTool(item: Record<string, unknown>): string | null {
23
+ const detail = (item.detail ?? {}) as Record<string, unknown>;
24
+ const failed = item.status === "failed" ? "(失败)" : "";
25
+ switch (detail.type) {
26
+ case "shell":
27
+ return `运行命令:${clip(String(detail.command ?? ""))}${failed}`;
28
+ case "read":
29
+ return `阅读 ${shortPath(String(detail.filePath ?? ""))}`;
30
+ case "edit":
31
+ return `修改 ${shortPath(String(detail.filePath ?? ""))}${failed}`;
32
+ case "write":
33
+ return `写入 ${shortPath(String(detail.filePath ?? ""))}${failed}`;
34
+ case "search":
35
+ return `搜索:${clip(String(detail.query ?? ""), 50)}`;
36
+ case "fetch":
37
+ return `访问 ${clip(String(detail.url ?? ""), 60)}`;
38
+ case "sub_agent":
39
+ return `子任务:${clip(String(detail.description ?? detail.subAgentType ?? ""), 60)}`;
40
+ default: {
41
+ const name = String(item.name ?? "");
42
+ if (name.startsWith("browser_")) return `操作浏览器(${name.slice("browser_".length)})`;
43
+ return name ? `使用工具 ${name}${failed}` : null;
44
+ }
45
+ }
46
+ }
47
+
48
+ function describeItem(item: unknown): string | null {
49
+ if (typeof item !== "object" || item === null) return null;
50
+ const it = item as Record<string, unknown>;
51
+ switch (it.type) {
52
+ case "tool_call":
53
+ return describeTool(it);
54
+ case "assistant_message":
55
+ return typeof it.text === "string" && it.text.trim() ? `说明:${clip(it.text)}` : null;
56
+ case "todo": {
57
+ const items = Array.isArray(it.items) ? (it.items as Array<{ completed?: boolean }>) : [];
58
+ return items.length ? `待办清单:完成 ${items.filter((t) => t.completed).length}/${items.length}` : null;
59
+ }
60
+ case "error":
61
+ return `出错:${clip(String(it.message ?? ""))}`;
62
+ default:
63
+ return null;
64
+ }
65
+ }
66
+
67
+ /** The last `limit` describable entries, oldest first, with repeats of the same line collapsed. */
68
+ export function summarizeActivity(entries: TimelineEntry[], limit: number): ActivityItem[] {
69
+ const out: ActivityItem[] = [];
70
+ for (const entry of entries) {
71
+ const text = describeItem(entry.item);
72
+ if (!text) continue;
73
+ if (out.at(-1)?.text === text) out[out.length - 1] = { at: entry.timestamp, text };
74
+ else out.push({ at: entry.timestamp, text });
75
+ }
76
+ return out.slice(-limit);
77
+ }
78
+
79
+ /** Lines for the status output, e.g. " 10:42 运行命令:npm test". */
80
+ export function describeActivity(items: ActivityItem[], now = new Date()): string[] {
81
+ return items.map((a) => {
82
+ const at = new Date(a.at);
83
+ const minutes = Math.round((now.getTime() - at.getTime()) / 60_000);
84
+ const when = Number.isNaN(minutes) ? "" : minutes < 1 ? "刚刚" : minutes < 60 ? `${minutes} 分钟前` : `${Math.floor(minutes / 60)} 小时前`;
85
+ return ` ${when ? `${when}:` : ""}${a.text}`;
86
+ });
87
+ }