@openprd/cli 0.1.1 → 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 (137) 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 +399 -438
  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 +31 -20
  73. package/skills/openprd-requirement-intake/references/prd-template-lenses.md +6 -6
  74. package/skills/openprd-requirement-intake/references/routing-rubric.md +10 -2
  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/session-binding.js +40 -3
  131. package/src/session-registry.js +159 -0
  132. package/src/standards.js +5 -3
  133. package/src/test-strategy.js +386 -0
  134. package/src/visual-compare.js +915 -34
  135. package/src/work-unit-migration.js +5 -1
  136. package/src/workspace-core.js +343 -19
  137. package/src/workspace-workflow.js +538 -134
@@ -0,0 +1,268 @@
1
+ /*
2
+ * 核心功能
3
+ * 渲染 agent integration、doctor、fleet、self-update 和 upgrade 等诊断类命令输出。
4
+ *
5
+ * 输入
6
+ * 接收诊断、迁移、工具健康、自更新和批量项目扫描等结构化结果对象。
7
+ *
8
+ * 输出
9
+ * 向终端输出诊断结论、修复建议和批量处理摘要,或在 `--json` 模式下直出 JSON。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的诊断输出模块,负责工具链和项目健康相关的终端呈现。
13
+ *
14
+ * 依赖
15
+ * 仅依赖终端输出和诊断 result 契约,不承担修复执行。
16
+ *
17
+ * 维护规则
18
+ * 诊断类输出新增字段时要保持错误、建议和命令展示顺序稳定,避免隐藏关键信息。
19
+ */
20
+ import { printOptionalCapabilitySuggestions } from './shared-print.js';
21
+
22
+ function printAgentIntegrationResult(result, json) {
23
+ if (json) {
24
+ console.log(JSON.stringify(result, null, 2));
25
+ return;
26
+ }
27
+
28
+ console.log(`OpenPrd agent ${result.action}: ${result.ok ? '通过' : '需修复'}`);
29
+ console.log(`项目: ${result.projectRoot}`);
30
+ console.log(`工具: ${result.tools.join(', ')}`);
31
+ if (result.hookProfile) {
32
+ console.log(`Hook 模式: ${result.hookProfile}`);
33
+ }
34
+ if (result.initialized) {
35
+ console.log(`已初始化工作区: ${result.init.workspaceRoot}`);
36
+ }
37
+ if (result.standards) {
38
+ console.log(`标准化文档: ${result.standards.docsRoot}`);
39
+ }
40
+ if (result.migration) {
41
+ const changed = result.migration.changes.filter((change) => change.status !== 'unchanged').length;
42
+ console.log(`工作区迁移: ${changed} 项`);
43
+ }
44
+ if (result.registry) {
45
+ console.log(`全局 registry: ${result.registry.status === 'created' ? '已登记' : '已刷新'} (${result.registry.registryPath})`);
46
+ }
47
+ console.log('变更:');
48
+ for (const change of result.changes) {
49
+ const detail = change.message ? ` (${change.message})` : '';
50
+ console.log(`- ${change.status}: ${change.path}${detail}`);
51
+ if (change.repairHint) {
52
+ console.log(` 修复建议: ${change.repairHint}`);
53
+ }
54
+ }
55
+ if (result.doctor?.errors?.length > 0) {
56
+ console.log('待处理:');
57
+ for (const error of result.doctor.errors) {
58
+ console.log(`- ${error}`);
59
+ }
60
+ }
61
+ printOptionalCapabilitySuggestions(result.optionalCapabilities ?? result.doctor?.optionalCapabilities);
62
+ }
63
+
64
+ function doctorCheckLabel(check) {
65
+ if (check.ok) return '通过';
66
+ if (check.reason === 'missing-file') return '缺失';
67
+ if (check.reason === 'missing-generated-marker') return '未受管';
68
+ if (check.reason === 'checksum-drift') return '漂移';
69
+ return '失败';
70
+ }
71
+
72
+ function printCodexRuntimeResult(codexRuntime, prefix = '') {
73
+ if (!codexRuntime) {
74
+ return;
75
+ }
76
+ const health = codexRuntime.preflight;
77
+ console.log(`${prefix}Codex CLI 健康检查: ${codexRuntime.ok ? '通过' : '失败'}`);
78
+ if (health?.command?.display) {
79
+ console.log(`${prefix}检查命令: ${health.command.display}`);
80
+ }
81
+ if (health?.version) {
82
+ console.log(`${prefix}Codex 版本: ${health.version}`);
83
+ }
84
+ if (health?.diagnostic) {
85
+ console.log(`${prefix}诊断: ${health.diagnostic.summary}`);
86
+ if (health.diagnostic.missingPackage) {
87
+ console.log(`${prefix}缺失组件: ${health.diagnostic.missingPackage}`);
88
+ }
89
+ console.log(`${prefix}修复命令: ${health.diagnostic.manualCommand}`);
90
+ }
91
+ if (codexRuntime.repairAttempted) {
92
+ console.log(`${prefix}显式修复: ${codexRuntime.repair?.ok ? '通过' : '失败'}`);
93
+ if (codexRuntime.repair?.command?.display) {
94
+ console.log(`${prefix}修复执行: ${codexRuntime.repair.command.display}`);
95
+ }
96
+ if (codexRuntime.repair?.result) {
97
+ console.log(`${prefix}修复退出码: ${codexRuntime.repair.result.exitCode ?? 'unknown'}`);
98
+ }
99
+ if (codexRuntime.repair?.recheck?.version) {
100
+ console.log(`${prefix}复查版本: ${codexRuntime.repair.recheck.version}`);
101
+ }
102
+ } else if (health?.diagnostic && health?.repairCommand?.display) {
103
+ console.log(`${prefix}提示: OpenPrd 默认不会静默安装全局依赖;需要显式运行 openprd doctor . --tools codex --fix 或 openprd loop . --run --agent codex --repair-agent。`);
104
+ }
105
+ }
106
+
107
+ function printDoctorResult(result, json) {
108
+ if (json) {
109
+ console.log(JSON.stringify(result, null, 2));
110
+ return;
111
+ }
112
+
113
+ console.log(`OpenPrd doctor: ${result.ok ? '通过' : '失败'}`);
114
+ console.log(`项目: ${result.projectRoot}`);
115
+ console.log(`工具: ${result.tools.join(', ')}`);
116
+ if (result.agentIntegration.hookProfile) {
117
+ console.log(`Hook 模式: ${result.agentIntegration.hookProfile}`);
118
+ }
119
+ console.log(`标准化: ${result.standards.ok ? '通过' : '失败'}`);
120
+ console.log(`工作区验证: ${result.validation.valid ? '通过' : '失败'}`);
121
+ if (result.agentIntegration.drift) {
122
+ console.log(`生成物漂移: ${result.agentIntegration.drift.ok ? '无' : '存在'}`);
123
+ }
124
+ printCodexRuntimeResult(result.codexRuntime);
125
+ console.log('Agent 集成检查:');
126
+ for (const check of result.agentIntegration.checks) {
127
+ const reason = !check.ok && check.reason ? ` (${check.reason})` : '';
128
+ console.log(`- ${doctorCheckLabel(check)}: ${check.path}${reason}`);
129
+ if (!check.ok && check.repairHint) {
130
+ console.log(` 修复建议: ${check.repairHint}`);
131
+ }
132
+ }
133
+ if (result.errors.length > 0) {
134
+ console.log('错误:');
135
+ for (const error of result.errors) {
136
+ console.log(`- ${error}`);
137
+ }
138
+ }
139
+ printOptionalCapabilitySuggestions(result.agentIntegration.optionalCapabilities);
140
+ }
141
+
142
+ function printFleetResult(result, json) {
143
+ if (json) {
144
+ console.log(JSON.stringify(result, null, 2));
145
+ return;
146
+ }
147
+
148
+ const mode = result.dryRun
149
+ ? 'dry-run'
150
+ : Object.entries(result.requestedActions)
151
+ .filter(([, enabled]) => enabled)
152
+ .map(([name]) => name)
153
+ .join(', ');
154
+ console.log(`OpenPrd fleet: ${result.ok ? '通过' : '需处理'}`);
155
+ console.log(`根目录: ${result.root}`);
156
+ console.log(`模式: ${mode || 'report'}`);
157
+ console.log(`最大深度: ${result.maxDepth}`);
158
+ console.log(`项目: ${result.summary.total}`);
159
+ console.log(`- OpenPrd: ${result.summary.openprd}`);
160
+ console.log(`- Agent-only: ${result.summary.agentConfigured}`);
161
+ console.log(`- Plain: ${result.summary.plain}`);
162
+ console.log(`结果: 计划 ${result.summary.planned},已更新 ${result.summary.updated},已接入 ${result.summary.setup},已检查 ${result.summary.doctored},已补身份 ${result.summary.backfilled},已同步 registry ${result.summary.synced},失败 ${result.summary.failed},跳过 ${result.summary.skipped}`);
163
+ if (result.registry) {
164
+ console.log(`全局 registry: 已知 ${result.registry.knownTotal},当前 root 命中 ${result.registry.scopedKnown},root 外 ${result.registry.outsideRoot},失效 ${result.registry.stale}`);
165
+ }
166
+ if ((result.summary.healthAttention ?? 0) > 0) {
167
+ console.log(`项目健康: ${result.summary.healthAttention} 个需关注(已报告,不阻断本次更新)`);
168
+ }
169
+
170
+ const visibleProjects = result.projects
171
+ .filter((project) => project.category !== 'plain-project' || project.status === 'failed' || (project.healthErrors?.length ?? 0) > 0)
172
+ .slice(0, 50);
173
+ if (visibleProjects.length > 0) {
174
+ console.log('项目明细:');
175
+ for (const project of visibleProjects) {
176
+ console.log(`- ${project.status}: ${project.relativePath} (${project.category}) -> ${project.plannedAction}`);
177
+ if (project.workUnits) {
178
+ console.log(` 工作单元: ${project.workUnits.changedVersions}/${project.workUnits.totalVersions} 个历史版本已覆盖或计划覆盖`);
179
+ }
180
+ for (const error of project.errors.slice(0, 3)) {
181
+ console.log(` 错误: ${error}`);
182
+ }
183
+ for (const error of (project.healthErrors ?? []).slice(0, 3)) {
184
+ console.log(` 需关注: ${error}`);
185
+ }
186
+ }
187
+ }
188
+ const hiddenCount = result.projects.length - visibleProjects.length;
189
+ if (hiddenCount > 0) {
190
+ console.log(`还有 ${hiddenCount} 个 plain/skipped 项目未展开;使用 --json 查看完整明细。`);
191
+ }
192
+ if (result.reportPath) {
193
+ console.log(`报告: ${result.reportPath}`);
194
+ }
195
+ }
196
+
197
+ function printSelfUpdateResult(result, json) {
198
+ if (json) {
199
+ console.log(JSON.stringify(result, null, 2));
200
+ return;
201
+ }
202
+
203
+ const status = result.dryRun
204
+ ? '预演'
205
+ : result.ok
206
+ ? '完成'
207
+ : result.skipped
208
+ ? '已跳过'
209
+ : '失败';
210
+ console.log(`OpenPrd self-update: ${status}`);
211
+ console.log(`当前版本: ${result.package?.version ?? 'unknown'}`);
212
+ console.log(`安装源: ${result.source}`);
213
+ console.log(`计划命令: ${result.installCommand.display}`);
214
+ if (result.localCheckout) {
215
+ console.log('运行环境: 本地源码 checkout');
216
+ }
217
+ if (result.dryRun) {
218
+ console.log('dry-run: 未修改 CLI、项目或 registry。');
219
+ }
220
+ if (result.result) {
221
+ console.log(`安装退出码: ${result.result.exitCode}`);
222
+ }
223
+ if (result.resolvedExecutable?.executable) {
224
+ console.log(`OpenPrd 可执行文件: ${result.resolvedExecutable.executable}`);
225
+ }
226
+ for (const action of result.nextActions ?? []) {
227
+ console.log(`下一步: ${action}`);
228
+ }
229
+ for (const error of result.errors ?? []) {
230
+ console.log(`错误: ${error}`);
231
+ }
232
+ }
233
+
234
+ function printUpgradeResult(result, json) {
235
+ if (json) {
236
+ console.log(JSON.stringify(result, null, 2));
237
+ return;
238
+ }
239
+
240
+ console.log(`OpenPrd upgrade: ${result.dryRun ? '预演' : result.ok ? '完成' : '失败'}`);
241
+ console.log(`模式: ${result.mode === 'fleet' ? '历史项目批量刷新' : '单项目刷新'}`);
242
+ console.log(`目标: ${result.targetPath}`);
243
+ console.log(`阶段 self-update: ${result.stages.selfUpdateOk ? '通过' : '失败'}`);
244
+ console.log(`阶段 project-refresh: ${result.stages.projectRefreshOk ? '通过' : result.projectRefresh.skipped ? '跳过' : '失败'}`);
245
+ console.log(`self-update 命令: ${result.selfUpdate.installCommand.display}`);
246
+ console.log(`项目刷新命令: ${result.projectRefresh.command.display}`);
247
+ if (result.dryRun) {
248
+ console.log('dry-run: 未执行工具更新,也未刷新项目。');
249
+ }
250
+ if (result.selfUpdate.result) {
251
+ console.log(`self-update 退出码: ${result.selfUpdate.result.exitCode}`);
252
+ }
253
+ if (result.projectRefresh.result) {
254
+ console.log(`project-refresh 退出码: ${result.projectRefresh.result.exitCode}`);
255
+ }
256
+ for (const error of result.errors ?? []) {
257
+ console.log(`错误: ${error}`);
258
+ }
259
+ }
260
+
261
+ export {
262
+ printAgentIntegrationResult,
263
+ printCodexRuntimeResult,
264
+ printDoctorResult,
265
+ printFleetResult,
266
+ printSelfUpdateResult,
267
+ printUpgradeResult,
268
+ };
@@ -0,0 +1,176 @@
1
+ /*
2
+ * 核心功能
3
+ * 渲染 growth 候选、自动补齐和 benchmark 推荐相关的人类可读输出。
4
+ *
5
+ * 输入
6
+ * 接收 growth init/review/apply/reject 等结构化结果对象和候选元数据。
7
+ *
8
+ * 输出
9
+ * 向终端输出候选状态、证据、拟写入内容和 benchmark 推荐摘要,或在 `--json` 模式下直出 JSON。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的 growth 输出模块,专门承接自我成长和规则固化反馈。
13
+ *
14
+ * 依赖
15
+ * 仅依赖终端输出和候选字段契约。
16
+ *
17
+ * 维护规则
18
+ * growth 输出要优先保留范围、置信度、采纳影响和拟写入内容,避免用户难以判断是否固化。
19
+ */
20
+ function growthCandidateStatusLabel(status) {
21
+ if (status === 'applied') return '已应用';
22
+ if (status === 'rejected') return '已拒绝';
23
+ return '待确认';
24
+ }
25
+
26
+ function growthCandidateApplyModeLabel(candidate) {
27
+ if (candidate.applyMode === 'auto') return '自动补齐';
28
+ if (candidate.applyMode === 'manual') return '手动采纳';
29
+ return '未应用';
30
+ }
31
+
32
+ function growthCandidateScopeLabel(scope) {
33
+ if (scope === 'user-local') return '当前用户本地偏好';
34
+ if (scope === 'openprd-core') return 'OpenPrd 核心规则';
35
+ return '项目共享规则';
36
+ }
37
+
38
+ function formatGrowthConfidence(confidence) {
39
+ if (typeof confidence !== 'number' || Number.isNaN(confidence)) {
40
+ return '未提供';
41
+ }
42
+ return `${Math.round(confidence * 100)}%`;
43
+ }
44
+
45
+ function describeGrowthCandidateImpact(candidate) {
46
+ if (candidate.type === 'code-extension') {
47
+ return `会把匹配 ${candidate.key} 的文件纳入代码文件识别,减少后续同类 dev-check 重复提醒。`;
48
+ }
49
+ if (candidate.type === 'exempt-path-segment') {
50
+ return `会把路径片段 ${candidate.key} 加入代码行数规则豁免,影响对应目录下文件的 dev-check 判断。`;
51
+ }
52
+ if (candidate.type === 'exempt-file-pattern') {
53
+ return `会把文件模式 ${candidate.key} 加入代码行数规则豁免,影响命中的文件。`;
54
+ }
55
+ if (candidate.type === 'user-preference') {
56
+ return `会把偏好 ${candidate.key} 写入当前用户本地配置,不进入项目共享规则。`;
57
+ }
58
+ if (candidate.scope === 'openprd-core') {
59
+ return '采纳后会进入 OpenPrd 核心规则,请确认是否值得作为跨项目默认行为。';
60
+ }
61
+ return `采纳后会写入${growthCandidateScopeLabel(candidate.scope)},请确认这是否是你想要固化的范围。`;
62
+ }
63
+
64
+ function formatGrowthEvidenceItem(item = {}) {
65
+ if (typeof item === 'string') {
66
+ return item;
67
+ }
68
+ const parts = [];
69
+ if (item.path) {
70
+ parts.push(String(item.path));
71
+ }
72
+ if (item.lineCount !== null && item.lineCount !== undefined) {
73
+ parts.push(`${item.lineCount} 行`);
74
+ }
75
+ if (item.reason) {
76
+ parts.push(`原因: ${item.reason}`);
77
+ }
78
+ if (item.note) {
79
+ parts.push(`说明: ${item.note}`);
80
+ }
81
+ return parts.length > 0 ? parts.join(';') : JSON.stringify(item);
82
+ }
83
+
84
+ function formatGrowthSuggestedPatch(patch) {
85
+ if (!patch) {
86
+ return '未提供';
87
+ }
88
+ if (typeof patch === 'string') {
89
+ return patch;
90
+ }
91
+ const file = patch.file ? String(patch.file) : 'unknown-file';
92
+ const pathText = patch.path ? String(patch.path) : 'unknown-path';
93
+ const op = patch.op ? String(patch.op) : 'update';
94
+ const value = patch.value === undefined ? '' : ` ${JSON.stringify(patch.value)}`;
95
+ return `${file} -> ${pathText} ${op}${value}`.trim();
96
+ }
97
+
98
+ function printGrowthLedger(ledger) {
99
+ if (!ledger?.summary) {
100
+ return;
101
+ }
102
+ const summary = ledger.summary;
103
+ console.log(`账本: events ${summary.eventCount ?? 0},observe ${summary.observed},pending ${summary.pendingObserved},auto ${summary.autoApplied},manual ${summary.manualApplied},reconcile ${summary.reconciledAutoApplied},checkpoint ${summary.completionCheckpoints ?? 0},reject ${summary.rejected},skip ${summary.skipped}`);
104
+ if (summary.current) {
105
+ console.log(`当前状态: ${summary.current.total} 个候选,${summary.current.pending} 待确认,${summary.current.applied} 已应用,${summary.current.rejected} 已拒绝`);
106
+ }
107
+ const skippedReasons = Object.entries(summary.skippedReasons ?? {});
108
+ if (skippedReasons.length > 0) {
109
+ console.log(`跳过原因: ${skippedReasons.map(([reason, count]) => `${reason}=${count}`).join(';')}`);
110
+ }
111
+ }
112
+
113
+ function printGrowthResult(result, json) {
114
+ if (json) {
115
+ console.log(JSON.stringify(result, null, 2));
116
+ return;
117
+ }
118
+
119
+ if (result.action === 'growth-init') {
120
+ console.log('OpenPrd growth: 已初始化');
121
+ console.log(`候选队列: ${result.files.candidates}`);
122
+ printGrowthLedger(result.ledger);
123
+ return;
124
+ }
125
+
126
+ console.log(`OpenPrd growth: ${result.ok ? '完成' : '失败'}`);
127
+ if (result.summary) {
128
+ console.log(`候选: ${result.summary.pending} 待确认,${result.summary.applied} 已应用,${result.summary.rejected} 已拒绝。`);
129
+ }
130
+ printGrowthLedger(result.ledger);
131
+ const candidates = result.pending ?? (result.candidate ? [result.candidate] : []);
132
+ for (const candidate of candidates) {
133
+ console.log(`- ${candidate.id}: ${candidate.title}`);
134
+ console.log(` 状态: ${growthCandidateStatusLabel(candidate.status)}`);
135
+ console.log(` 作用范围: ${growthCandidateScopeLabel(candidate.scope)}`);
136
+ if (candidate.status === 'applied') {
137
+ console.log(` 应用方式: ${growthCandidateApplyModeLabel(candidate)}`);
138
+ }
139
+ console.log(` 置信度: ${formatGrowthConfidence(candidate.confidence)}`);
140
+ if (candidate.summary) {
141
+ console.log(` 摘要: ${candidate.summary}`);
142
+ }
143
+ console.log(` 采纳影响: ${describeGrowthCandidateImpact(candidate)}`);
144
+ if ((candidate.evidence ?? []).length > 0) {
145
+ console.log(' 证据:');
146
+ for (const evidence of candidate.evidence) {
147
+ console.log(` - ${formatGrowthEvidenceItem(evidence)}`);
148
+ }
149
+ }
150
+ if (candidate.suggestedPatch) {
151
+ console.log(' 拟写入:');
152
+ console.log(` - ${formatGrowthSuggestedPatch(candidate.suggestedPatch)}`);
153
+ }
154
+ if (candidate.status === 'pending') {
155
+ console.log(` 收工复盘采纳命令: openprd grow . --apply --id ${candidate.id}`);
156
+ console.log(` 拒绝命令: openprd grow . --reject --id ${candidate.id}`);
157
+ }
158
+ }
159
+ for (const change of result.changed ?? []) {
160
+ console.log(`- 已更新: ${change}`);
161
+ }
162
+ const shouldSkipNextActions = candidates.some((candidate) => candidate.status === 'pending');
163
+ for (const action of shouldSkipNextActions ? [] : (result.nextActions ?? [])) {
164
+ console.log(`- 下一步: ${action}`);
165
+ }
166
+ for (const recommendation of result.benchmarkRecommendations ?? []) {
167
+ console.log(`- Benchmark 推荐: ${recommendation.sourceKey} 最近 ${recommendation.windowDays} 天已采纳 ${recommendation.adoptedCount}/${recommendation.threshold} 次,累计 ${recommendation.totalAdoptedCount} 次;确认后运行 ${recommendation.approveCommand}`);
168
+ }
169
+ for (const error of result.errors ?? []) {
170
+ console.log(`- ${error}`);
171
+ }
172
+ }
173
+
174
+ export {
175
+ printGrowthResult,
176
+ };