@openprd/cli 0.1.1 → 0.1.9

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 +387 -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 +419 -438
  54. package/README_CN.md +4 -578
  55. package/README_EN.md +870 -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 +47 -25
  70. package/skills/openprd-harness/references/workflow-gates.md +15 -0
  71. package/skills/openprd-quality/SKILL.md +11 -5
  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 +271 -71
  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 +659 -124
  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 +1321 -76
  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,127 @@
1
+ /*
2
+ * 核心功能
3
+ * 提供多个 CLI 输出模块共享的轻量打印 helper。
4
+ *
5
+ * 输入
6
+ * 接收知识回顾等横向复用的结构化子对象。
7
+ *
8
+ * 输出
9
+ * 输出统一格式的辅助文本片段,供 run、quality、growth 等模块复用。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的共享工具模块,只承载跨模块复用的打印逻辑。
13
+ *
14
+ * 依赖
15
+ * 仅依赖终端输出,不依赖其他业务模块。
16
+ *
17
+ * 维护规则
18
+ * 共享 helper 只放稳定、无副作用的格式化逻辑,避免再次把大型输出文件堆回一起。
19
+ */
20
+ function printKnowledgeReview(knowledgeReview) {
21
+ if (!knowledgeReview) {
22
+ return;
23
+ }
24
+ if (knowledgeReview.skipped) {
25
+ console.log(`项目经验回顾: 已跳过 (${knowledgeReview.reason})`);
26
+ return;
27
+ }
28
+ if (knowledgeReview.ok === false) {
29
+ console.log(`项目经验回顾: 失败 (${knowledgeReview.errors?.[0] ?? 'unknown'})`);
30
+ return;
31
+ }
32
+ console.log(`项目经验草案: ${knowledgeReview.candidateId}`);
33
+ if (knowledgeReview.summary) {
34
+ console.log(`摘要: ${knowledgeReview.summary}`);
35
+ }
36
+ if (Array.isArray(knowledgeReview.categories) && knowledgeReview.categories.length > 0) {
37
+ console.log(`类别: ${knowledgeReview.categories.join(', ')}`);
38
+ }
39
+ if (knowledgeReview.files?.draftSkill) {
40
+ console.log(`Draft Skill: ${knowledgeReview.files.draftSkill}`);
41
+ }
42
+ if (knowledgeReview.files?.candidateDir) {
43
+ console.log(`诊断候选: ${knowledgeReview.files.candidateDir}`);
44
+ }
45
+ if (knowledgeReview.suggestedLearnCommand) {
46
+ console.log(`Promote: ${knowledgeReview.suggestedLearnCommand}`);
47
+ }
48
+ }
49
+
50
+ function knowledgeAdoptionLabel(adoption = {}) {
51
+ return `命中 ${adoption.hitCount ?? 0} / 引用 ${adoption.referencedCount ?? 0} / 注入 ${adoption.injectedCount ?? 0}`;
52
+ }
53
+
54
+ function printKnowledgeSkillMatches(knowledgeSkills) {
55
+ const matched = Array.isArray(knowledgeSkills?.matched) ? knowledgeSkills.matched : [];
56
+ if (matched.length === 0) {
57
+ return;
58
+ }
59
+ const summary = knowledgeSkills?.summary ?? {};
60
+ console.log(`项目级 Skill: 命中 ${matched.length} 个${summary.hookInjected ? ',已自动注入当前上下文' : ''}`);
61
+ for (const skill of matched.slice(0, 3)) {
62
+ console.log(`- ${skill.skillName}: ${skill.matchSummary ?? '命中当前上下文'}`);
63
+ if (skill.description) {
64
+ console.log(` 说明: ${skill.description}`);
65
+ }
66
+ if (Array.isArray(skill.touchedFiles) && skill.touchedFiles.length > 0) {
67
+ console.log(` 相关文件: ${skill.touchedFiles.slice(0, 4).join(';')}`);
68
+ }
69
+ console.log(` 复用指标: ${knowledgeAdoptionLabel(skill.adoption ?? {})}`);
70
+ }
71
+ }
72
+
73
+ function optionalCapabilityLocationLabel(location) {
74
+ const clientLabels = {
75
+ codex: 'Codex',
76
+ cursor: 'Cursor',
77
+ claude: 'Claude Code',
78
+ };
79
+ const scopeLabel = location.scope === 'user' ? '用户级' : '项目级';
80
+ return `${clientLabels[location.client] ?? location.client} ${scopeLabel} (${location.path})`;
81
+ }
82
+
83
+ function printOptionalCapabilitySuggestions(optionalCapabilities) {
84
+ if (!Array.isArray(optionalCapabilities) || optionalCapabilities.length === 0) {
85
+ return;
86
+ }
87
+ const configured = optionalCapabilities.filter((capability) => capability.configured);
88
+ const recommended = optionalCapabilities.filter((capability) => !capability.configured);
89
+ if (configured.length === 0 && recommended.length === 0) {
90
+ return;
91
+ }
92
+
93
+ if (configured.length > 0) {
94
+ const configuredSummary = configured
95
+ .map((capability) => {
96
+ const locations = capability.configuredLocations.map(optionalCapabilityLocationLabel).join(';');
97
+ return locations ? `${capability.name}(${locations})` : capability.name;
98
+ })
99
+ .join(',');
100
+ console.log(`已检测可选增强能力: ${configuredSummary}`);
101
+ }
102
+
103
+ if (recommended.length === 0) {
104
+ return;
105
+ }
106
+
107
+ console.log('可选增强建议:');
108
+ for (const capability of recommended) {
109
+ console.log(`- ${capability.name}: ${capability.summary}`);
110
+ if (capability.recommendedFor) {
111
+ console.log(` 适合场景: ${capability.recommendedFor}`);
112
+ }
113
+ if (Array.isArray(capability.checkedLocations) && capability.checkedLocations.length > 0) {
114
+ console.log(` 建议检查位置: ${capability.checkedLocations.map(optionalCapabilityLocationLabel).join(';')}`);
115
+ }
116
+ console.log(` 文档: ${capability.docsUrl}`);
117
+ console.log(` GitHub: ${capability.repoUrl}`);
118
+ console.log(` MCP: ${capability.serverUrl}`);
119
+ }
120
+ }
121
+
122
+ export {
123
+ knowledgeAdoptionLabel,
124
+ printKnowledgeReview,
125
+ printKnowledgeSkillMatches,
126
+ printOptionalCapabilitySuggestions,
127
+ };
@@ -0,0 +1,195 @@
1
+ /*
2
+ * 核心功能
3
+ * 渲染 PRD 工作流中 synthesize、review、history、diff、next、freeze、diagram、handoff 等阶段输出。
4
+ *
5
+ * 输入
6
+ * 接收版本快照、评审状态、流程建议和图表 artifact 等结构化结果对象。
7
+ *
8
+ * 输出
9
+ * 向终端输出工作流摘要或 JSON,帮助用户理解当前阶段和下一步动作。
10
+ *
11
+ * 定位
12
+ * 位于 CLI 表现层的工作流输出模块,负责版本化 PRD 生命周期的呈现。
13
+ *
14
+ * 依赖
15
+ * 仅依赖终端输出和工作流 result 契约,不承担写入或规则计算。
16
+ *
17
+ * 维护规则
18
+ * 变更评审或交接相关字段时,必须同步维护普通输出与 JSON 输出的一致性。
19
+ */
20
+ import { formatProductTypeDisplay } from '../product-type-copy.js';
21
+
22
+ function printSynthesizeResult(result, json) {
23
+ if (json) {
24
+ console.log(JSON.stringify(result, null, 2));
25
+ return;
26
+ }
27
+
28
+ console.log('已整理出一版可评审的需求稿');
29
+ console.log(`标题: ${result.snapshot.title}`);
30
+ console.log(`产品场景: ${formatProductTypeDisplay(result.snapshot.productType, { fallback: '待确认' })}`);
31
+ if (!result.reviewPresentationRequired && (result.reviewPath ?? result.stableReviewArtifact)) {
32
+ console.log('确认页面: 已生成');
33
+ }
34
+ console.log(`已自动打开确认页面: ${result.opened ? '是' : '否'}`);
35
+ if (result.reviewPresentationRequired) {
36
+ console.log('确认页面: 还没到可以直接确认的状态');
37
+ console.log('下一步: 先把展示文案补齐,再重新生成确认页面。');
38
+ const feedback = result.reviewPresentationGate?.violations ?? [];
39
+ for (const item of feedback.slice(0, 6)) {
40
+ const pathHint = item.jsonPath ? `${item.jsonPath}: ` : '';
41
+ console.log(`- ${pathHint}${item.action}`);
42
+ }
43
+ } else if (result.reviewPath ?? result.stableReviewArtifact) {
44
+ console.log('请先让用户查看确认页面;用户认可后,再用页面提供的确认方式记录结果。');
45
+ }
46
+ }
47
+
48
+ function printReviewResult(result, json) {
49
+ if (json) {
50
+ console.log(JSON.stringify(result, null, 2));
51
+ return;
52
+ }
53
+
54
+ if (!result.ok) {
55
+ console.log('PRD 评审状态不可用');
56
+ for (const error of result.errors ?? []) {
57
+ console.log(`- ${error}`);
58
+ }
59
+ if (result.requiredCommand) {
60
+ console.log(`下一步: ${result.requiredCommand}`);
61
+ }
62
+ for (const item of (result.presentationFeedback ?? []).slice(0, 6)) {
63
+ const pathHint = item.jsonPath ? `${item.jsonPath}: ` : '';
64
+ console.log(`- ${pathHint}${item.action}`);
65
+ }
66
+ return;
67
+ }
68
+
69
+ console.log(`确认结果: ${result.status}`);
70
+ console.log('确认页面: 已就绪');
71
+ if (result.marked) {
72
+ console.log(`状态已从 ${result.previousStatus} 更新为 ${result.status}`);
73
+ }
74
+ if (result.opened) {
75
+ console.log('已打开确认页面');
76
+ }
77
+ }
78
+
79
+ function printHistoryResult(result, json) {
80
+ if (json) {
81
+ console.log(JSON.stringify(result, null, 2));
82
+ return;
83
+ }
84
+
85
+ console.log(`版本历史: ${result.ws.workspaceRoot}`);
86
+ for (const entry of result.versions) {
87
+ console.log(`- ${entry.versionId} | ${entry.title} | ${formatProductTypeDisplay(entry.productType, { fallback: '待确认' })} | ${entry.createdAt}`);
88
+ }
89
+ }
90
+
91
+ function printDiffResult(result, json) {
92
+ if (json) {
93
+ console.log(JSON.stringify(result.diff, null, 2));
94
+ return;
95
+ }
96
+
97
+ console.log(`差异 ${result.diff.fromVersionId} -> ${result.diff.toVersionId}`);
98
+ console.log(`变更章节: ${result.diff.changedSections.length > 0 ? result.diff.changedSections.join(', ') : '无'}`);
99
+ for (const change of result.diff.changes) {
100
+ console.log(`- ${change.path}: ${JSON.stringify(change.before)} -> ${JSON.stringify(change.after)}`);
101
+ }
102
+ }
103
+
104
+ function printNextResult(result, json) {
105
+ if (json) {
106
+ console.log(JSON.stringify(result, null, 2));
107
+ return;
108
+ }
109
+
110
+ const { recommendation, analysis, workflow, taskGraph } = result;
111
+ console.log(`下一步动作: ${recommendation.nextAction}`);
112
+ if (recommendation.currentGate) {
113
+ console.log(`当前门禁: ${recommendation.currentGate}`);
114
+ }
115
+ if (recommendation.upcomingGate) {
116
+ console.log(`后续门禁: ${recommendation.upcomingGate}`);
117
+ }
118
+ console.log(`原因: ${recommendation.reason}`);
119
+ console.log(`建议命令: ${recommendation.suggestedCommand}`);
120
+ console.log(`完成度: ${analysis.completedRequiredFields}/${analysis.totalRequiredFields}`);
121
+ if (taskGraph?.nextReadyNode) {
122
+ console.log(`下一个就绪节点: ${taskGraph.nextReadyNode}`);
123
+ }
124
+ if (result.diagramState?.needed) {
125
+ console.log(`图表门禁: ${result.diagramState.shouldGateFreeze ? '激活' : '已满足'}`);
126
+ console.log(`建议图表: ${result.diagramState.preferredType}`);
127
+ }
128
+ console.log('工作流:');
129
+ console.log(` ${workflow.join(' -> ')}`);
130
+ if (recommendation.suggestedQuestions.length > 0) {
131
+ console.log('建议问题:');
132
+ for (const question of recommendation.suggestedQuestions) {
133
+ console.log(`- ${question}`);
134
+ }
135
+ }
136
+ }
137
+
138
+ function printFreezeResult(result, json) {
139
+ if (json) {
140
+ console.log(JSON.stringify(result, null, 2));
141
+ return;
142
+ }
143
+
144
+ console.log('这版需求已经定稿,可以进入交接准备');
145
+ console.log(`定稿对象: ${result.snapshot.title ?? result.ws.workspaceRoot}`);
146
+ }
147
+
148
+ function printDiagramResult(result, json) {
149
+ if (json) {
150
+ console.log(JSON.stringify(result, null, 2));
151
+ return;
152
+ }
153
+
154
+ if (result.snapshot) {
155
+ console.log(`已为 ${result.snapshot.title} 生成${result.type === 'product-flow' ? '产品流程' : '架构'}图`);
156
+ } else {
157
+ console.log(`已更新${result.type === 'product-flow' ? '产品流程' : '架构'}图`);
158
+ }
159
+ console.log(`HTML: ${result.htmlPath}`);
160
+ console.log(`JSON: ${result.jsonPath}`);
161
+ console.log(`Mermaid: ${result.mermaidPath}`);
162
+ if (result.inputPath) {
163
+ console.log(`输入 contract: ${result.inputPath}`);
164
+ }
165
+ if (result.marked) {
166
+ console.log(`评审状态: ${result.marked}`);
167
+ } else if (result.model?.metadata?.reviewStatus) {
168
+ console.log(`评审状态: ${result.model.metadata.reviewStatus}`);
169
+ }
170
+ console.log(`已打开: ${result.opened ? '是' : '否'}`);
171
+ }
172
+
173
+ function printHandoffResult(result, json) {
174
+ if (json) {
175
+ console.log(JSON.stringify(result, null, 2));
176
+ return;
177
+ }
178
+
179
+ console.log('交接资料已经生成');
180
+ console.log(`交接去向: ${result.handoff.target}`);
181
+ if (result.handoff.nextStep) {
182
+ console.log(`建议下一步: ${result.handoff.nextStep}`);
183
+ }
184
+ }
185
+
186
+ export {
187
+ printSynthesizeResult,
188
+ printReviewResult,
189
+ printHistoryResult,
190
+ printDiffResult,
191
+ printNextResult,
192
+ printFreezeResult,
193
+ printDiagramResult,
194
+ printHandoffResult,
195
+ };