@openprd/cli 0.1.0 → 0.1.8

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 (138) hide show
  1. package/.openprd/README.md +43 -69
  2. package/.openprd/README_EN.md +84 -0
  3. package/.openprd/benchmarks/index.md +7 -0
  4. package/.openprd/benchmarks/sources.yaml +25 -3
  5. package/.openprd/discovery/config.json +16 -2
  6. package/.openprd/engagements/active/flows.md +19 -14
  7. package/.openprd/engagements/active/handoff.md +11 -4
  8. package/.openprd/engagements/active/prd.md +99 -71
  9. package/.openprd/engagements/active/review.html +4 -4
  10. package/.openprd/engagements/active/roles.md +9 -8
  11. package/.openprd/engagements/work-units/wu-20260524015648-6d33ded7.json +4 -4
  12. package/.openprd/engagements/work-units/wu-20260602113956-a99b5b88.json +18 -0
  13. package/.openprd/engagements/work-units/wu-20260602122244-78656aaf.json +18 -0
  14. package/.openprd/engagements/work-units/wu-20260602122442-e96489e2.json +18 -0
  15. package/.openprd/engagements/work-units/wu-20260602132835-695429e8.json +18 -0
  16. package/.openprd/knowledge/candidates/candidate-turn-1780116203372-5f266a79e968c758/candidate.json +78 -0
  17. package/.openprd/knowledge/candidates/candidate-turn-1780116203372-5f266a79e968c758/diagnostic-report.json +129 -0
  18. package/.openprd/knowledge/candidates/candidate-turn-1780116203372-5f266a79e968c758/root-cause-candidates.json +41 -0
  19. package/.openprd/knowledge/candidates/candidate-turn-1780116203372-5f266a79e968c758/timeline.json +14 -0
  20. package/.openprd/knowledge/drafts/openprd-experience-diagnostic-candidate-turn-1780116203372-5f266a79e968c758/SKILL.md +49 -0
  21. package/.openprd/knowledge/index.json +44 -4
  22. package/.openprd/reviews/v0001.html +195 -129
  23. package/.openprd/reviews/v0002.html +1150 -0
  24. package/.openprd/reviews/v0003.html +1150 -0
  25. package/.openprd/reviews/v0004.html +1150 -0
  26. package/.openprd/reviews/v0005.html +1150 -0
  27. package/.openprd/standards/config.json +12 -9
  28. package/.openprd/state/changes.json +17 -2
  29. package/.openprd/state/current.json +399 -63
  30. package/.openprd/state/release-ledger.json +344 -0
  31. package/.openprd/state/version-index.json +52 -0
  32. package/.openprd/state/versions/v0002.json +264 -0
  33. package/.openprd/state/versions/v0002.md +183 -0
  34. package/.openprd/state/versions/v0003.json +269 -0
  35. package/.openprd/state/versions/v0003.md +188 -0
  36. package/.openprd/state/versions/v0004.json +274 -0
  37. package/.openprd/state/versions/v0004.md +193 -0
  38. package/.openprd/state/versions/v0005.json +299 -0
  39. package/.openprd/state/versions/v0005.md +189 -0
  40. package/.openprd/templates/agent/intake.md +5 -4
  41. package/.openprd/templates/b2b/intake.md +5 -4
  42. package/.openprd/templates/base/intake.md +10 -4
  43. package/.openprd/templates/company/README.md +9 -7
  44. package/.openprd/templates/company/README_EN.md +12 -0
  45. package/.openprd/templates/consumer/intake.md +5 -4
  46. package/.openprd/templates/industry/README.md +12 -10
  47. package/.openprd/templates/industry/README_EN.md +18 -0
  48. package/.openprd/templates/project/README.md +11 -9
  49. package/.openprd/templates/project/README_EN.md +16 -0
  50. package/.openprd/templates/session/README.md +11 -9
  51. package/.openprd/templates/session/README_EN.md +16 -0
  52. package/AGENTS.md +12 -8
  53. package/README.md +402 -441
  54. package/README_CN.md +4 -578
  55. package/README_EN.md +850 -0
  56. package/docs/assets/openprd-requirement-routing-en.png +0 -0
  57. package/docs/assets/openprd-requirement-routing-en.svg +102 -0
  58. package/docs/assets/openprd-requirement-routing-zh-refined.png +0 -0
  59. package/docs/assets/openprd-requirement-routing-zh.png +0 -0
  60. package/docs/assets/openprd-requirement-routing-zh.svg +102 -0
  61. package/package.json +6 -2
  62. package/scripts/dev-check-wrapup-copy.mjs +110 -0
  63. package/scripts/openprd-github-release-notes.mjs +99 -0
  64. package/scripts/quality-perf-check.mjs +203 -0
  65. package/skills/openprd-benchmark-router/SKILL.md +1 -0
  66. package/skills/openprd-benchmark-router/references/benchmark-sources.md +1 -0
  67. package/skills/openprd-benchmark-router/references/source-policy.md +2 -0
  68. package/skills/openprd-discovery-loop/SKILL.md +2 -2
  69. package/skills/openprd-harness/SKILL.md +46 -24
  70. package/skills/openprd-harness/references/workflow-gates.md +15 -0
  71. package/skills/openprd-quality/SKILL.md +10 -4
  72. package/skills/openprd-requirement-intake/SKILL.md +39 -23
  73. package/skills/openprd-requirement-intake/references/prd-template-lenses.md +6 -6
  74. package/skills/openprd-requirement-intake/references/routing-rubric.md +22 -8
  75. package/skills/openprd-router/SKILL.md +2 -2
  76. package/skills/openprd-shared/SKILL.md +51 -23
  77. package/skills/openprd-standards/SKILL.md +2 -1
  78. package/src/agent-integration.js +265 -65
  79. package/src/benchmark/constants.js +107 -0
  80. package/src/benchmark/operations.js +235 -0
  81. package/src/benchmark/registry.js +64 -0
  82. package/src/benchmark/render.js +115 -0
  83. package/src/benchmark/source.js +617 -0
  84. package/src/benchmark/storage.js +121 -0
  85. package/src/benchmark/verify.js +235 -0
  86. package/src/benchmark.js +50 -851
  87. package/src/change-summary.js +339 -0
  88. package/src/cli/args.js +67 -6
  89. package/src/cli/basic-print.js +365 -0
  90. package/src/cli/benchmark-print.js +91 -0
  91. package/src/cli/change-print.js +221 -0
  92. package/src/cli/doctor-print.js +268 -0
  93. package/src/cli/growth-print.js +176 -0
  94. package/src/cli/print.js +73 -1384
  95. package/src/cli/quality-print.js +284 -0
  96. package/src/cli/run-print.js +297 -0
  97. package/src/cli/shared-print.js +127 -0
  98. package/src/cli/workflow-print.js +195 -0
  99. package/src/codex-hook-runner-template.mjs +639 -117
  100. package/src/codex-runtime.js +324 -0
  101. package/src/dev-standards.js +178 -5
  102. package/src/diagram-core.js +5 -5
  103. package/src/discovery.js +2 -1
  104. package/src/execution-strategy.js +369 -0
  105. package/src/fleet.js +4 -0
  106. package/src/github-release.js +156 -0
  107. package/src/growth.js +311 -13
  108. package/src/html-artifact-utils.js +25 -0
  109. package/src/html-artifacts.js +157 -1596
  110. package/src/knowledge.js +1176 -75
  111. package/src/language-policy.js +2 -112
  112. package/src/learning-html-artifact.js +1031 -0
  113. package/src/learning-review.js +3 -2
  114. package/src/loop.js +280 -9
  115. package/src/openprd.js +341 -38
  116. package/src/openspec/change-validate.js +0 -9
  117. package/src/openspec/execute.js +79 -3
  118. package/src/openspec/generate.js +33 -20
  119. package/src/openspec/tasks.js +33 -2
  120. package/src/prd-core.js +10 -9
  121. package/src/product-type-copy.js +69 -0
  122. package/src/quality-html-artifact.js +108 -9
  123. package/src/quality-learning.js +30 -0
  124. package/src/quality-visual-review.js +237 -0
  125. package/src/quality.js +329 -43
  126. package/src/registry-hygiene.js +54 -0
  127. package/src/release-ledger.js +413 -0
  128. package/src/review-presentation.js +12 -6
  129. package/src/run-harness.js +722 -48
  130. package/src/self-update.js +1 -1
  131. package/src/session-binding.js +40 -3
  132. package/src/session-registry.js +159 -0
  133. package/src/standards.js +5 -3
  134. package/src/test-strategy.js +386 -0
  135. package/src/visual-compare.js +915 -34
  136. package/src/work-unit-migration.js +5 -1
  137. package/src/workspace-core.js +343 -19
  138. package/src/workspace-workflow.js +538 -134
@@ -0,0 +1,284 @@
1
+ /*
2
+ * 核心功能
3
+ * 渲染 standards、dev-check、quality、knowledge 和 visual compare 等质量相关命令输出。
4
+ *
5
+ * 输入
6
+ * 接收标准校验、研发期行数检查、质量报告、知识候选和视觉对比等结构化结果对象。
7
+ *
8
+ * 输出
9
+ * 向终端输出质量门禁、证据状态、知识候选和视觉对比摘要,或在 `--json` 模式下直出 JSON。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的质量输出模块,负责 standards/quality 这一类高频质量反馈。
13
+ *
14
+ * 依赖
15
+ * 依赖 shared-print 中的知识回顾 helper,不承担实际检测逻辑。
16
+ *
17
+ * 维护规则
18
+ * 质量类输出要优先保留 production-ready、门禁范围和证据状态,避免把关键风险埋进长文本里。
19
+ */
20
+ import { printKnowledgeReview } from './shared-print.js';
21
+
22
+ function describeFeatureCoverageLedger(report) {
23
+ const activeTasks = report?.evalHarness?.featureCoverage?.activeTasks ?? null;
24
+ if (!activeTasks || Number(activeTasks.pending ?? 0) <= 0) {
25
+ return null;
26
+ }
27
+ const total = Number(activeTasks.total ?? 0);
28
+ const done = Number(activeTasks.done ?? 0);
29
+ const pending = Number(activeTasks.pending ?? 0);
30
+ const blocked = Number(activeTasks.blocked ?? 0);
31
+ const progress = total > 0 ? `${done}/${total}` : `${done}`;
32
+ const changeLabel = activeTasks.activeChange ? `当前变更 ${activeTasks.activeChange}` : '当前任务账本';
33
+ return `${changeLabel} 仍有 ${pending} 个未完成任务(已完成 ${progress}${blocked > 0 ? `,其中 ${blocked} 个因依赖阻塞` : ''})。这表示账本未收口,不等于当前实现失败。`;
34
+ }
35
+
36
+ function printStandardsResult(result, json) {
37
+ if (json) {
38
+ console.log(JSON.stringify(result, null, 2));
39
+ return;
40
+ }
41
+
42
+ if (result.action === 'init') {
43
+ console.log(`已初始化 OpenPrd standards: ${result.docsRoot}`);
44
+ for (const item of result.changed) {
45
+ console.log(`- ${item.status}: ${item.path}`);
46
+ }
47
+ return;
48
+ }
49
+ if (result.action === 'classify-external-reference') {
50
+ console.log(`已归类外部参考源码: ${result.path}`);
51
+ console.log(`配置: ${result.configPath}`);
52
+ console.log(`状态: ${result.alreadyPresent ? '已存在' : '已写入'}`);
53
+ return;
54
+ }
55
+
56
+ console.log(`OpenPrd standards: ${result.ok ? '通过' : '失败'}`);
57
+ console.log(`Docs root: ${result.docsRoot}`);
58
+ for (const check of result.checks) {
59
+ console.log(`- ${check}`);
60
+ }
61
+ if (result.errors.length > 0) {
62
+ console.log('错误:');
63
+ for (const error of result.errors) {
64
+ console.log(`- ${error}`);
65
+ }
66
+ }
67
+ if (result.warnings.length > 0) {
68
+ console.log('警告:');
69
+ for (const warning of result.warnings) {
70
+ console.log(`- ${warning}`);
71
+ }
72
+ }
73
+ const candidates = result.manualReport?.externalReferenceCandidates ?? [];
74
+ if (candidates.length > 0) {
75
+ console.log('外部参考源码候选:');
76
+ console.log('请先询问用户这些目录是否只作为外部参考;用户确认后再运行归类命令。');
77
+ for (const candidate of candidates) {
78
+ console.log(`- ${candidate.path}: ${candidate.missingFiles} 个文件、${candidate.missingFolders} 个文件夹缺说明书;原因: ${candidate.reason};建议确认后运行 ${candidate.suggestedCommand}`);
79
+ }
80
+ }
81
+ }
82
+
83
+ function printDevelopmentStandardsResult(result, json) {
84
+ if (json) {
85
+ console.log(JSON.stringify(result, null, 2));
86
+ return;
87
+ }
88
+
89
+ console.log(`OpenPrd 后续建议: ${result.ok ? '完成' : '失败'}`);
90
+ const attentionFiles = result.files.filter((file) => ['attention', 'warning', 'error'].includes(file.status));
91
+ if (attentionFiles.length > 0) {
92
+ console.log(`关注程度: 🟡 低风险|建议留意,🟠 中风险|建议优先关注,🔴 高风险|需要先处理。`);
93
+ } else {
94
+ console.log(`本轮已回顾 ${result.files.length} 个改动文件,暂未发现需要额外说明的影响对象。`);
95
+ }
96
+ for (const file of attentionFiles) {
97
+ const lineText = file.lineCount === null || file.lineCount === undefined ? '未知行数' : `${file.lineCount} 行`;
98
+ console.log(`- ${file.statusLabel ?? file.status}: ${file.path} (${lineText})`);
99
+ console.log(` ${file.nextAction}`);
100
+ }
101
+ if (result.wrapUp?.required && result.wrapUp.markdownTable) {
102
+ console.log(result.wrapUp.markdownBlock ?? result.wrapUp.markdownTable);
103
+ }
104
+ printKnowledgeReview(result.knowledgeReview);
105
+ for (const error of result.errors ?? []) {
106
+ console.log(`- ${error}`);
107
+ }
108
+ }
109
+
110
+ function printQualityResult(result, json) {
111
+ if (json) {
112
+ console.log(JSON.stringify(result, null, 2));
113
+ return;
114
+ }
115
+
116
+ if (result.action === 'quality-init') {
117
+ console.log(`OpenPrd quality: 已初始化 (${result.changed})`);
118
+ console.log(`配置: ${result.files.config}`);
119
+ console.log(`报告目录: ${result.files.reportsDir}`);
120
+ console.log(`知识库索引: ${result.files.knowledgeIndex}`);
121
+ return;
122
+ }
123
+
124
+ if (result.action === 'quality-learn') {
125
+ console.log(`OpenPrd quality learn: ${result.ok ? '已沉淀' : '失败'}`);
126
+ if (result.ok) {
127
+ console.log(`来源类型: ${result.sourceKind}`);
128
+ console.log(`来源: ${result.sourcePath}`);
129
+ if (Array.isArray(result.sourcePaths) && result.sourcePaths.length > 1) {
130
+ console.log(`证据数: ${result.sourcePaths.length}`);
131
+ }
132
+ console.log(`事故: ${result.files.incident}`);
133
+ console.log(`模式: ${result.files.pattern}`);
134
+ console.log(`经验 Skill: ${result.files.skill}`);
135
+ return;
136
+ }
137
+ for (const error of result.errors ?? []) {
138
+ console.log(`- ${error}`);
139
+ }
140
+ return;
141
+ }
142
+
143
+ if (result.action === 'quality-knowledge-review') {
144
+ console.log('OpenPrd quality review: 已完成');
145
+ printKnowledgeReview(result);
146
+ return;
147
+ }
148
+
149
+ const headline = result.report
150
+ ? (result.report.readiness.ok && !result.report.readiness.productionReady
151
+ ? '需关注'
152
+ : (result.ok ? '完成' : '失败'))
153
+ : (result.ok ? '完成' : '失败');
154
+ console.log(`OpenPrd quality: ${headline}`);
155
+ if (result.report) {
156
+ console.log(`质量状态: ${result.report.summary.status}`);
157
+ console.log(`生产就绪: ${result.report.readiness.productionReady ? '是' : '否'}`);
158
+ console.log(`执行模式: ${result.report.readiness.enforcement}`);
159
+ if (result.report.qualityPolicy) {
160
+ console.log(`场景标签: ${result.report.qualityPolicy.scenarioTags.join(', ')}`);
161
+ console.log(`必需门禁: ${result.report.qualityPolicy.requiredGates.join(', ') || '无'}`);
162
+ }
163
+ if (result.report.readiness.attentionGates.length > 0) {
164
+ console.log(`需关注门禁: ${result.report.readiness.attentionGates.join(', ')}`);
165
+ }
166
+ const featureCoverageLedger = describeFeatureCoverageLedger(result.report);
167
+ if (featureCoverageLedger) {
168
+ console.log(`账本提示: ${featureCoverageLedger}`);
169
+ }
170
+ console.log('门禁:');
171
+ for (const gate of result.report.gates) {
172
+ const scope = gate.required ? '必需' : '可选';
173
+ const evidence = gate.evidence?.present ? `证据 ${gate.evidence.sources.length}` : '缺证据';
174
+ console.log(`- ${gate.status}: ${gate.label} (${scope}, ${evidence})`);
175
+ }
176
+ }
177
+ if (result.reportPath) {
178
+ console.log(`JSON: ${result.reportPath}`);
179
+ }
180
+ if (result.htmlPath) {
181
+ console.log(`HTML: ${result.htmlPath}`);
182
+ }
183
+ printKnowledgeReview(result.knowledgeReview);
184
+ for (const error of result.errors ?? []) {
185
+ console.log(`- ${error}`);
186
+ }
187
+ }
188
+
189
+ function printKnowledgeResult(result, json) {
190
+ if (json) {
191
+ console.log(JSON.stringify(result, null, 2));
192
+ return;
193
+ }
194
+
195
+ if (!result.ok) {
196
+ console.log(`OpenPrd knowledge: 失败 (${result.action ?? 'unknown'})`);
197
+ for (const error of result.errors ?? []) {
198
+ console.log(`- ${error}`);
199
+ }
200
+ return;
201
+ }
202
+
203
+ if (result.action === 'knowledge-candidates') {
204
+ const counts = result.counts ?? {};
205
+ console.log(`OpenPrd knowledge candidates: ${result.candidates.length} 个 (${result.status})`);
206
+ console.log(`统计: pending ${counts.pending ?? 0}, promoted ${counts.promoted ?? 0}, rejected ${counts.rejected ?? 0}, archived ${counts.archived ?? 0}, reviewed ${counts.reviewed ?? 0}, total ${counts.total ?? 0}`);
207
+ for (const candidate of result.candidates) {
208
+ console.log(`- ${candidate.candidateId}: ${candidate.title ?? candidate.candidateId}`);
209
+ console.log(` 状态: ${candidate.status}`);
210
+ console.log(` 候选: ${candidate.path ?? candidate.files?.candidate}`);
211
+ if (candidate.draftSkillPath ?? candidate.files?.draftSkill) {
212
+ console.log(` 草案 Skill: ${candidate.draftSkillPath ?? candidate.files?.draftSkill}`);
213
+ }
214
+ if (candidate.pending) {
215
+ console.log(` 拒绝: openprd knowledge reject --id ${candidate.candidateId} --reason <原因>`);
216
+ console.log(` 归档: openprd knowledge archive --id ${candidate.candidateId} --reason <原因>`);
217
+ }
218
+ }
219
+ if (result.candidates.length === 0) {
220
+ console.log('没有匹配的 knowledge candidate。');
221
+ }
222
+ return;
223
+ }
224
+
225
+ console.log(`OpenPrd knowledge ${result.action?.replace(/^knowledge-/, '') ?? 'update'}: ${result.candidateId}`);
226
+ if (result.candidate) {
227
+ console.log(`状态: ${result.candidate.status}`);
228
+ if (result.candidate.reviewDecision) {
229
+ console.log(`决定: ${result.candidate.reviewDecision}`);
230
+ }
231
+ if (result.candidate.reviewReason) {
232
+ console.log(`原因: ${result.candidate.reviewReason}`);
233
+ }
234
+ }
235
+ if (result.files?.candidate) {
236
+ console.log(`候选: ${result.files.candidate}`);
237
+ }
238
+ if (result.files?.knowledgeIndex) {
239
+ console.log(`索引: ${result.files.knowledgeIndex}`);
240
+ }
241
+ }
242
+
243
+ function printVisualCompareResult(result, json) {
244
+ if (json) {
245
+ console.log(JSON.stringify(result, null, 2));
246
+ return;
247
+ }
248
+
249
+ const modeLabel = result.mode === 'before-after'
250
+ ? '修改前后自检'
251
+ : result.mode === 'focus-board'
252
+ ? '局部焦点证据板'
253
+ : result.mode === 'parallel-board'
254
+ ? '并行实验证据板'
255
+ : '效果图对比';
256
+ console.log('OpenPrd visual compare: 已生成');
257
+ console.log(`输出图片: ${result.outputPath}`);
258
+ console.log(`模式: ${modeLabel}`);
259
+ console.log(`格式: ${result.format}${result.quality ? `, quality=${result.quality}` : ''}`);
260
+ console.log(`画布: ${result.canvas.width}x${result.canvas.height}`);
261
+ if (result.labels?.reference && result.reference?.rendered) {
262
+ console.log(`左侧: ${result.labels.reference} (${result.reference.rendered.width}x${result.reference.rendered.height})`);
263
+ }
264
+ if (result.labels?.actual && result.actual?.rendered) {
265
+ console.log(`右侧: ${result.labels.actual} (${result.actual.rendered.width}x${result.actual.rendered.height})`);
266
+ }
267
+ if (Array.isArray(result.focusRegions) && result.focusRegions.length > 0) {
268
+ console.log(`焦点区域: ${result.focusRegions.length}`);
269
+ }
270
+ if (Array.isArray(result.items) && result.items.length > 0) {
271
+ console.log(`实验卡片: ${result.items.length}`);
272
+ }
273
+ for (const action of result.nextActions ?? []) {
274
+ console.log(`- 下一步: ${action}`);
275
+ }
276
+ }
277
+
278
+ export {
279
+ printStandardsResult,
280
+ printDevelopmentStandardsResult,
281
+ printQualityResult,
282
+ printKnowledgeResult,
283
+ printVisualCompareResult,
284
+ };
@@ -0,0 +1,297 @@
1
+ /*
2
+ * 核心功能
3
+ * 渲染 run / loop 相关命令的人类可读输出或 JSON 输出。
4
+ *
5
+ * 输入
6
+ * 接收 run context、run verify、loop prompt/run/finish 和执行确认清单等结构化结果对象。
7
+ *
8
+ * 输出
9
+ * 向终端输出当前执行流、任务状态、Loop 运行信息和知识回顾摘要。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的执行路径输出模块,专门承接 run/loop 相关的密集终端信息。
13
+ *
14
+ * 依赖
15
+ * 依赖 shared-print 与 doctor-print 提供的复用 helper,不承担实际执行。
16
+ *
17
+ * 维护规则
18
+ * run/loop 输出字段变更时要保持任务态、验证态和确认清单的展示顺序稳定,避免遗漏执行门槛。
19
+ */
20
+ import { labelExecutionMode } from '../execution-strategy.js';
21
+ import { printCodexRuntimeResult } from './doctor-print.js';
22
+ import { printKnowledgeReview, printKnowledgeSkillMatches } from './shared-print.js';
23
+
24
+ function printExecutionConfirmationChecklist(checklist) {
25
+ if (!checklist?.required) {
26
+ return;
27
+ }
28
+ console.log(`${checklist.title ?? '开始动手前先确认这些'}:`);
29
+ if (checklist.objective) {
30
+ console.log(`- 这次要做什么: ${checklist.objective}`);
31
+ }
32
+ if (checklist.scope?.length > 0) {
33
+ console.log(`- 这次范围: ${checklist.scope.join(';')}`);
34
+ }
35
+ if (checklist.implementationItems?.length > 0) {
36
+ console.log(`- 我会这样推进: ${checklist.implementationItems.join(';')}`);
37
+ }
38
+ if (checklist.outOfScope?.length > 0) {
39
+ console.log(`- 这次先不做: ${checklist.outOfScope.join(';')}`);
40
+ }
41
+ if (checklist.verification?.length > 0) {
42
+ console.log(`- 完成后会检查: ${checklist.verification.join(';')}`);
43
+ }
44
+ if (checklist.risks?.length > 0) {
45
+ console.log(`- 需要提前知道: ${checklist.risks.join(';')}`);
46
+ }
47
+ if (checklist.confirmationPrompt) {
48
+ console.log(`- 如果要我现在继续: ${checklist.confirmationPrompt}`);
49
+ }
50
+ }
51
+
52
+ function printRunResult(result, json) {
53
+ if (json) {
54
+ console.log(JSON.stringify(result, null, 2));
55
+ return;
56
+ }
57
+
58
+ if (result.action === 'run-record-hook') {
59
+ console.log(`OpenPrd run hook 已记录: ${result.event.eventName} -> ${result.event.outcome}`);
60
+ console.log(`迭代记录: ${result.files.iterations}`);
61
+ return;
62
+ }
63
+
64
+ if (result.action === 'run-verify') {
65
+ const taskReady = result.readiness?.taskReady !== false;
66
+ const workspaceReady = result.readiness?.workspaceReady !== false;
67
+ const workspaceAttention = result.workspaceAttention ?? null;
68
+ const status = taskReady
69
+ ? (workspaceReady ? '通过' : '当前任务通过,工作区待关注')
70
+ : '当前任务失败';
71
+ console.log(`OpenPrd run verify: ${status}`);
72
+ if (result.readiness) {
73
+ console.log(`任务就绪: ${taskReady ? '是' : '否'}`);
74
+ console.log(`工作区就绪: ${workspaceReady ? '是' : '否'}`);
75
+ if (result.readiness.qualityProductionReady !== null) {
76
+ console.log(`质量门禁: ${result.readiness.qualityProductionReady ? 'production-ready' : '待补证据'}`);
77
+ }
78
+ }
79
+ for (const check of result.checks) {
80
+ const scope = check.scope === 'workspace' ? '工作区' : '任务';
81
+ const detail = check.name === 'quality' && check.productionReady === false
82
+ ? ' (production-ready=false)'
83
+ : '';
84
+ console.log(`- ${check.ok ? '通过' : '失败'}: ${check.name} [${scope}]${detail}`);
85
+ }
86
+ if (workspaceAttention?.kind === 'feature-coverage-ledger') {
87
+ const changeLabel = workspaceAttention.activeChange
88
+ ? `激活变更 ${workspaceAttention.activeChange}`
89
+ : '当前激活任务';
90
+ const progress = workspaceAttention.total > 0
91
+ ? `${workspaceAttention.done}/${workspaceAttention.total}`
92
+ : `${workspaceAttention.done}`;
93
+ console.log('工作区待关注原因: feature-coverage 账本未收口');
94
+ console.log(`- ${changeLabel} 已完成 ${progress},待处理 ${workspaceAttention.pending}${workspaceAttention.blocked > 0 ? `,阻塞 ${workspaceAttention.blocked}` : ''}`);
95
+ console.log('- 这通常表示任务账本或覆盖证据还没补齐,不等于本次功能失败。');
96
+ } else if (workspaceAttention?.summary) {
97
+ console.log(`工作区待关注原因: ${workspaceAttention.summary}`);
98
+ }
99
+ printKnowledgeReview(result.knowledgeReview);
100
+ const extraWarnings = workspaceAttention?.detail
101
+ ? result.warnings.filter((warning) => warning !== `quality: ${workspaceAttention.detail}`)
102
+ : result.warnings;
103
+ if (extraWarnings.length > 0) {
104
+ console.log('工作区待关注:');
105
+ for (const warning of extraWarnings) {
106
+ console.log(`- ${warning}`);
107
+ }
108
+ }
109
+ if (result.errors.length > 0) {
110
+ console.log('错误:');
111
+ for (const error of result.errors) {
112
+ console.log(`- ${error}`);
113
+ }
114
+ }
115
+ return;
116
+ }
117
+
118
+ console.log('当前进展参考');
119
+ console.log(`当前项目: ${result.projectRoot}`);
120
+ console.log(`基础检查: ${result.validation.valid ? '通过' : '失败'}`);
121
+ if (result.lane?.summary) {
122
+ console.log(`当前处理路径: ${result.lane.summary}`);
123
+ }
124
+ if (result.activeChange) {
125
+ const label = result.recommendation?.type === 'requirement-intake' ? '历史聚焦事项' : '当前聚焦事项';
126
+ console.log(`${label}: ${result.activeChange}`);
127
+ }
128
+ if (result.focus?.changeId && result.focus.changeId !== result.activeChange) {
129
+ console.log(`当前补充焦点: ${result.focus.changeId}`);
130
+ }
131
+ if (result.activeRequirementGate) {
132
+ const gateStatus = result.activeRequirementGate.status ?? 'active';
133
+ const gateSuffix = result.activeRequirementGate.relevance === 'background' ? '(仅背景提醒)' : '';
134
+ console.log(`当前处理阶段: ${gateStatus}${gateSuffix}`);
135
+ }
136
+ if (result.taskSummary) {
137
+ console.log(`后续任务进度: ${result.taskSummary.completed}/${result.taskSummary.total} 完成,${result.taskSummary.pending} 待处理,${result.taskSummary.blocked} 阻塞`);
138
+ if (result.taskSummary.implementation) {
139
+ console.log(`待落地任务: ${result.taskSummary.implementation.completed}/${result.taskSummary.implementation.total} 完成,${result.taskSummary.implementation.pending} 待处理`);
140
+ }
141
+ }
142
+ if (result.discovery) {
143
+ console.log(`调研进度: ${result.discovery.runId} 已覆盖 ${result.discovery.summary.covered}/${result.discovery.summary.total},待处理 ${result.discovery.summary.pending}`);
144
+ }
145
+ printKnowledgeSkillMatches(result.knowledgeSkills);
146
+ console.log('对外表达: 面向用户时,请优先说“本次调整”“后续任务”“继续落地”“完成后检查”这类人话,不要直接复述内部编号、命令、路径、版本号或流程术语。');
147
+ console.log(`建议下一步: ${result.recommendation.title}`);
148
+ if (result.recommendation.executionMode) {
149
+ console.log(`推进方式: ${labelExecutionMode(result.recommendation.executionMode)}`);
150
+ }
151
+ if (result.recommendation.parallelPlan?.eligible) {
152
+ console.log(`协作建议: ${result.recommendation.parallelPlan.summary}`);
153
+ }
154
+ console.log(`这样安排的原因: ${result.recommendation.reason}`);
155
+ if (result.recommendation.preparationCommand || result.recommendation.executionCommand || result.recommendation.commitCommand) {
156
+ console.log('开始动手前提: 只有在用户明确要求继续落地、实现、修复、深挖或提交时,才继续往下做;如果还缺这一步,就先用人话说明范围和影响。');
157
+ }
158
+ printExecutionConfirmationChecklist(result.recommendation.executionConfirmationChecklist);
159
+ if (result.recommendation.preparationCommand) {
160
+ console.log(`内部准备参考: ${result.recommendation.preparationCommand}`);
161
+ }
162
+ if (result.recommendation.executionCommand) {
163
+ console.log(`内部执行参考: ${result.recommendation.executionCommand}`);
164
+ }
165
+ if (result.recommendation.commitCommand) {
166
+ console.log(`内部提交参考: ${result.recommendation.commitCommand}`);
167
+ }
168
+ if (result.recommendation.loop?.worktreeRecommended) {
169
+ console.log('环境建议: 最好放到单独环境里继续,避免和别的事项串线。');
170
+ }
171
+ console.log(`内部检查参考: ${result.recommendation.verifyCommand}`);
172
+ console.log(`内部状态参考: ${result.files.runState}`);
173
+ }
174
+
175
+ function printLoopResult(result, json) {
176
+ if (json) {
177
+ console.log(JSON.stringify(result, null, 2));
178
+ return;
179
+ }
180
+
181
+ if (result.action === 'loop-prompt') {
182
+ console.log(`OpenPrd loop 提示词: ${result.ok ? '就绪' : '阻塞'}`);
183
+ if (result.task) {
184
+ console.log(`任务: ${result.task.id} ${result.task.title}`);
185
+ if (result.task.taskHandle) console.log(`任务句柄: ${result.task.taskHandle}`);
186
+ }
187
+ if (result.promptPath) {
188
+ console.log(`提示词: ${result.promptPath}`);
189
+ }
190
+ if (result.invocation?.display) {
191
+ console.log(`执行: ${result.invocation.display}`);
192
+ }
193
+ if (result.errors?.length) {
194
+ for (const error of result.errors) console.log(`- ${error}`);
195
+ }
196
+ return;
197
+ }
198
+
199
+ if (result.action === 'loop-run') {
200
+ console.log(`OpenPrd loop 运行: ${result.ok ? '通过' : '失败'}${result.dryRun ? ' (dry-run)' : ''}`);
201
+ if (result.task) console.log(`任务: ${result.task.id} ${result.task.title}`);
202
+ if (result.task?.taskHandle) console.log(`任务句柄: ${result.task.taskHandle}`);
203
+ if (result.promptPath) console.log(`提示词: ${result.promptPath}`);
204
+ if (result.invocation?.display) console.log(`执行: ${result.invocation.display}`);
205
+ if (result.codexRuntime || result.preflight) {
206
+ printCodexRuntimeResult(result.codexRuntime ?? {
207
+ ok: result.preflight.ok,
208
+ preflight: result.preflight,
209
+ repair: result.repair,
210
+ repairAttempted: Boolean(result.repairAttempted),
211
+ });
212
+ }
213
+ if (result.finish?.commit) {
214
+ console.log(`提交: ${result.finish.commit.skipped ? '跳过' : result.finish.commit.sha}`);
215
+ }
216
+ if (result.finish?.projectRelease?.version) {
217
+ console.log(`项目版本: ${result.finish.projectRelease.version}`);
218
+ if (result.finish.projectRelease.tag?.tagName) {
219
+ const localSha = result.finish.projectRelease.tag.localSha ? ` -> ${result.finish.projectRelease.tag.localSha}` : '';
220
+ console.log(`版本 tag: ${result.finish.projectRelease.tag.tagName}${localSha}`);
221
+ }
222
+ }
223
+ if (result.finish?.testReport) {
224
+ console.log(`测试报告: ${result.finish.testReport}`);
225
+ }
226
+ if (result.errors?.length) {
227
+ for (const error of result.errors) console.log(`- ${error}`);
228
+ }
229
+ return;
230
+ }
231
+
232
+ if (result.action === 'loop-finish') {
233
+ console.log(`OpenPrd loop finish: ${result.ok ? '通过' : '失败'}`);
234
+ if (result.task) console.log(`任务: ${result.task.id} ${result.task.title}`);
235
+ if (result.task?.taskHandle) console.log(`任务句柄: ${result.task.taskHandle}`);
236
+ if (result.commit) console.log(`提交: ${result.commit.skipped ? '跳过' : result.commit.sha}`);
237
+ if (result.projectRelease?.version) {
238
+ console.log(`项目版本: ${result.projectRelease.version}`);
239
+ if (result.projectRelease.tag?.tagName) {
240
+ const localSha = result.projectRelease.tag.localSha ? ` -> ${result.projectRelease.tag.localSha}` : '';
241
+ console.log(`版本 tag: ${result.projectRelease.tag.tagName}${localSha}`);
242
+ }
243
+ }
244
+ if (result.testReport) console.log(`测试报告: ${result.testReport}`);
245
+ if (result.learningReview) {
246
+ if (result.learningReview.skipped) {
247
+ console.log(`复盘学习包: 已跳过 (${result.learningReview.reason})`);
248
+ } else if (result.learningReview.ok === false) {
249
+ console.log(`复盘学习包: 生成失败 (${result.learningReview.errors?.[0] ?? 'unknown'})`);
250
+ } else {
251
+ console.log(`复盘学习包: ${result.learningReview.packageId}`);
252
+ console.log(`HTML: ${result.learningReview.packagePaths?.readerHtml ?? '无'}`);
253
+ console.log(`题材: ${result.learningReview.genre?.label ?? '未知'}`);
254
+ if (result.learningReview.packageMeta?.styleLabel) console.log(`子风格: ${result.learningReview.packageMeta.styleLabel}`);
255
+ if (result.learningReview.packageMeta?.authoringStatus) console.log(`写作状态: ${result.learningReview.packageMeta.authoringStatus}`);
256
+ if (result.learningReview.packagePaths?.agentPrompt) console.log(`Agent 写作提示: ${result.learningReview.packagePaths.agentPrompt}`);
257
+ console.log(`已打开: ${result.learningReview.opened ? '是' : '否'}`);
258
+ }
259
+ }
260
+ printKnowledgeReview(result.knowledgeReview);
261
+ if (result.next) {
262
+ console.log(`下一任务: ${result.next.id} ${result.next.title}`);
263
+ if (result.next.taskHandle) console.log(`下一任务句柄: ${result.next.taskHandle}`);
264
+ }
265
+ if (result.projectRelease?.warnings?.length) {
266
+ for (const warning of result.projectRelease.warnings) {
267
+ console.log(`- ${warning}`);
268
+ }
269
+ }
270
+ if (result.errors?.length) {
271
+ for (const error of result.errors) console.log(`- ${error}`);
272
+ }
273
+ return;
274
+ }
275
+
276
+ console.log(`OpenPrd loop: ${result.action} ${result.ok ? '通过' : '失败'}`);
277
+ if (result.changeId) console.log(`变更: ${result.changeId}`);
278
+ if (result.summary) {
279
+ console.log(`任务: ${result.summary.done}/${result.summary.total} 完成,${result.summary.pending} 待处理,${result.summary.failed} 失败,${result.summary.blocked} 阻塞`);
280
+ }
281
+ if (result.next) {
282
+ console.log(`下一任务: ${result.next.id} ${result.next.title}`);
283
+ if (result.next.taskHandle) console.log(`下一任务句柄: ${result.next.taskHandle}`);
284
+ }
285
+ if (result.files) {
286
+ console.log(`任务清单: ${result.files.featureList}`);
287
+ }
288
+ if (result.errors?.length) {
289
+ for (const error of result.errors) console.log(`- ${error}`);
290
+ }
291
+ }
292
+
293
+ export {
294
+ printExecutionConfirmationChecklist,
295
+ printRunResult,
296
+ printLoopResult,
297
+ };