@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,1150 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>OpenPrd 用户视角变化摘要</title>
7
+ <style>
8
+ :root {
9
+ color-scheme: light;
10
+ --review-bg: #f6f8fb;
11
+ --review-panel: #ffffff;
12
+ --review-panel-soft: #f9fafb;
13
+ --review-text: #172033;
14
+ --review-muted: #667085;
15
+ --review-line: #d8dee8;
16
+ --review-blue: #2563eb;
17
+ --review-teal: #0f766e;
18
+ --review-indigo: #4f46e5;
19
+ --review-amber: #b45309;
20
+ --review-red: #dc2626;
21
+ --review-green: #15803d;
22
+ --review-mono: "JetBrains Mono", "SFMono-Regular", Menlo, monospace;
23
+ }
24
+ * { box-sizing: border-box; }
25
+ body {
26
+ margin: 0;
27
+ background: var(--review-bg);
28
+ color: var(--review-text);
29
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
30
+ overflow-x: hidden;
31
+ }
32
+ .review-page {
33
+ max-width: 1220px;
34
+ margin: 0 auto;
35
+ padding: 28px 22px 120px;
36
+ }
37
+ .review-topbar {
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: space-between;
41
+ flex-wrap: wrap;
42
+ gap: 16px;
43
+ margin-bottom: 16px;
44
+ }
45
+ .review-brand {
46
+ display: inline-flex;
47
+ align-items: center;
48
+ min-height: 34px;
49
+ border: 1px solid var(--review-line);
50
+ border-radius: 999px;
51
+ background: var(--review-panel);
52
+ color: var(--review-muted);
53
+ padding: 0 12px;
54
+ font-size: 13px;
55
+ font-weight: 700;
56
+ letter-spacing: 0;
57
+ }
58
+ .review-project-version {
59
+ display: grid;
60
+ gap: 4px;
61
+ min-width: 220px;
62
+ margin-left: auto;
63
+ padding: 12px 16px;
64
+ border: 1px solid #bfdbfe;
65
+ border-radius: 16px;
66
+ background: linear-gradient(135deg, #eff6ff 0%, #ffffff 100%);
67
+ box-shadow: 0 12px 24px rgba(37, 99, 235, 0.08);
68
+ }
69
+ .review-project-version-label {
70
+ color: var(--review-blue);
71
+ font-size: 12px;
72
+ font-weight: 800;
73
+ letter-spacing: 0;
74
+ }
75
+ .review-project-version-value {
76
+ color: var(--review-text);
77
+ font-family: var(--review-mono);
78
+ font-size: 22px;
79
+ line-height: 1.1;
80
+ }
81
+ .review-project-version-meta {
82
+ color: var(--review-muted);
83
+ font-size: 12px;
84
+ font-weight: 700;
85
+ letter-spacing: 0;
86
+ }
87
+ .review-kicker {
88
+ margin: 0 0 6px;
89
+ color: var(--review-muted);
90
+ font-size: 13px;
91
+ font-weight: 800;
92
+ letter-spacing: 0;
93
+ }
94
+ .review-overview,
95
+ .review-map {
96
+ border: 1px solid var(--review-line);
97
+ border-radius: 8px;
98
+ background: var(--review-panel);
99
+ box-shadow: 0 16px 34px rgba(15, 23, 42, 0.06);
100
+ }
101
+ .review-overview {
102
+ display: block;
103
+ padding: 24px;
104
+ }
105
+ .review-overview-copy,
106
+ .review-panel {
107
+ min-width: 0;
108
+ }
109
+ .review-overview h1,
110
+ .review-map h2,
111
+ .review-panel h3 {
112
+ margin: 0;
113
+ color: var(--review-text);
114
+ letter-spacing: 0;
115
+ overflow-wrap: anywhere;
116
+ }
117
+ .review-overview h1 {
118
+ font-size: 32px;
119
+ line-height: 1.16;
120
+ word-break: break-word;
121
+ }
122
+ .review-problem {
123
+ max-width: 760px;
124
+ margin: 12px 0 0;
125
+ color: var(--review-muted);
126
+ font-size: 16px;
127
+ line-height: 1.75;
128
+ overflow-wrap: anywhere;
129
+ }
130
+ .review-map {
131
+ margin-top: 18px;
132
+ padding: 20px;
133
+ }
134
+ .review-section-heading,
135
+ .review-panel-head {
136
+ display: flex;
137
+ gap: 12px;
138
+ align-items: flex-start;
139
+ }
140
+ .review-section-heading h2 {
141
+ font-size: 22px;
142
+ }
143
+ .review-icon {
144
+ flex: 0 0 auto;
145
+ display: inline-flex;
146
+ width: 38px;
147
+ height: 38px;
148
+ align-items: center;
149
+ justify-content: center;
150
+ border-radius: 8px;
151
+ }
152
+ .review-icon svg {
153
+ width: 22px;
154
+ height: 22px;
155
+ fill: none;
156
+ stroke: currentColor;
157
+ stroke-width: 2;
158
+ stroke-linecap: round;
159
+ stroke-linejoin: round;
160
+ }
161
+ .review-icon-map { color: var(--review-indigo); background: #eef2ff; }
162
+ .review-icon-flow { color: var(--review-teal); background: #ccfbf1; }
163
+ .review-icon-function { color: var(--review-blue); background: #dbeafe; }
164
+ .review-icon-guardrail { color: var(--review-amber); background: #fef3c7; }
165
+ .review-icon-risk { color: var(--review-red); background: #fee2e2; }
166
+ .review-map-canvas {
167
+ margin-top: 14px;
168
+ overflow-x: auto;
169
+ max-width: 100%;
170
+ }
171
+ .review-map-canvas svg {
172
+ display: block;
173
+ width: 100%;
174
+ min-width: 680px;
175
+ height: auto;
176
+ }
177
+ .review-map-bg {
178
+ fill: #f8fafc;
179
+ stroke: #e2e8f0;
180
+ }
181
+ .review-map-arrow {
182
+ fill: none;
183
+ stroke: var(--review-indigo);
184
+ stroke-width: 3;
185
+ stroke-linecap: round;
186
+ }
187
+ .review-map-link {
188
+ fill: none;
189
+ stroke: #a5b4fc;
190
+ stroke-width: 2.5;
191
+ stroke-linecap: round;
192
+ }
193
+ .review-map-node {
194
+ fill: #ffffff;
195
+ stroke: #cbd5e1;
196
+ stroke-width: 1.5;
197
+ filter: drop-shadow(0 10px 16px rgba(15, 23, 42, 0.08));
198
+ }
199
+ .review-map-center {
200
+ fill: #eef2ff;
201
+ stroke: #818cf8;
202
+ stroke-width: 1.5;
203
+ filter: drop-shadow(0 14px 18px rgba(79, 70, 229, 0.12));
204
+ }
205
+ .review-map-node.node-1 { stroke: #99f6e4; }
206
+ .review-map-node.node-2 { stroke: #bfdbfe; }
207
+ .review-map-node.node-3 { stroke: #fde68a; }
208
+ .review-map-node.node-4 { stroke: #fecaca; }
209
+ .review-map-step {
210
+ fill: var(--review-indigo);
211
+ font-size: 13px;
212
+ font-weight: 800;
213
+ }
214
+ .review-map-tag {
215
+ fill: var(--review-muted);
216
+ font-size: 11px;
217
+ font-weight: 800;
218
+ }
219
+ .review-map-tag-pill {
220
+ fill: #f8fafc;
221
+ stroke: #cbd5e1;
222
+ stroke-width: 1;
223
+ }
224
+ .review-map-tag-pill.center { fill: #e0e7ff; stroke: #a5b4fc; }
225
+ .review-map-tag-pill.node-1 { fill: #ccfbf1; stroke: #5eead4; }
226
+ .review-map-tag-pill.node-2 { fill: #dbeafe; stroke: #93c5fd; }
227
+ .review-map-tag-pill.node-3 { fill: #fef3c7; stroke: #facc15; }
228
+ .review-map-tag-pill.node-4 { fill: #fee2e2; stroke: #fca5a5; }
229
+ .review-map-tag.center { fill: var(--review-indigo); }
230
+ .review-map-tag.node-1 { fill: #0f766e; }
231
+ .review-map-tag.node-2 { fill: #2563eb; }
232
+ .review-map-tag.node-3 { fill: #b45309; }
233
+ .review-map-tag.node-4 { fill: #dc2626; }
234
+ .review-map-label {
235
+ fill: var(--review-text);
236
+ font-size: 12px;
237
+ font-weight: 680;
238
+ }
239
+ .review-map-note {
240
+ margin: 10px 0 0;
241
+ color: var(--review-muted);
242
+ font-size: 13px;
243
+ }
244
+ .review-panel-grid {
245
+ display: grid;
246
+ grid-template-columns: repeat(2, minmax(0, 1fr));
247
+ gap: 16px;
248
+ margin-top: 18px;
249
+ }
250
+ .review-panel {
251
+ min-height: 260px;
252
+ border: 1px solid var(--review-line);
253
+ border-radius: 8px;
254
+ background: var(--review-panel);
255
+ padding: 18px;
256
+ box-shadow: 0 12px 28px rgba(15, 23, 42, 0.05);
257
+ }
258
+ .review-panel h3 {
259
+ font-size: 20px;
260
+ }
261
+ .review-panel-head p {
262
+ margin: 5px 0 0;
263
+ color: var(--review-muted);
264
+ font-size: 14px;
265
+ line-height: 1.55;
266
+ }
267
+ .review-chip-row {
268
+ display: flex;
269
+ flex-wrap: wrap;
270
+ gap: 8px;
271
+ margin-top: 16px;
272
+ padding: 12px;
273
+ border-radius: 8px;
274
+ background: var(--review-panel-soft);
275
+ border: 1px solid var(--review-line);
276
+ }
277
+ .review-chip {
278
+ display: inline-flex;
279
+ align-items: center;
280
+ width: fit-content;
281
+ max-width: 100%;
282
+ min-height: 28px;
283
+ padding: 5px 10px;
284
+ border-radius: 999px;
285
+ border: 1px solid var(--review-line);
286
+ background: #ffffff;
287
+ color: var(--review-text);
288
+ font-size: 13px;
289
+ font-weight: 750;
290
+ line-height: 1.25;
291
+ white-space: nowrap;
292
+ overflow-wrap: normal;
293
+ word-break: keep-all;
294
+ }
295
+ .review-panel-flow .review-chip { border-color: #99f6e4; background: #f0fdfa; color: #115e59; }
296
+ .review-panel-function .review-chip { border-color: #bfdbfe; background: #eff6ff; color: #1d4ed8; }
297
+ .review-panel-guardrail .review-chip { border-color: #fde68a; background: #fffbeb; color: #92400e; }
298
+ .review-panel-risk .review-chip { border-color: #fecaca; background: #fff1f2; color: #991b1b; }
299
+ .review-chip.empty {
300
+ color: var(--review-muted);
301
+ background: #ffffff;
302
+ border-color: var(--review-line);
303
+ }
304
+ .review-journey-map {
305
+ margin-top: 12px;
306
+ border: 1px solid var(--review-line);
307
+ border-radius: 8px;
308
+ background: #f8fafc;
309
+ overflow-x: auto;
310
+ overflow-y: hidden;
311
+ }
312
+ .review-journey-map svg {
313
+ display: block;
314
+ width: 100%;
315
+ min-width: 0;
316
+ min-height: 230px;
317
+ }
318
+ .review-journey-bg {
319
+ fill: #fbfdff;
320
+ stroke: none;
321
+ }
322
+ .review-journey-arrow {
323
+ fill: none;
324
+ stroke: #0d9488;
325
+ stroke-width: 2;
326
+ stroke-linecap: round;
327
+ }
328
+ .review-journey-arrow.branch {
329
+ stroke: #94a3b8;
330
+ stroke-dasharray: 5 6;
331
+ }
332
+ .review-journey-node {
333
+ fill: #ffffff;
334
+ stroke-width: 1.6;
335
+ filter: drop-shadow(0 10px 18px rgba(15, 23, 42, 0.08));
336
+ }
337
+ .review-journey-node.stage-journey { stroke: #5eead4; }
338
+ .review-journey-node.stage-step { stroke: #93c5fd; }
339
+ .review-journey-node.stage-outcome { stroke: #a5b4fc; }
340
+ .review-journey-node.stage-boundary { stroke: #fde68a; }
341
+ .review-journey-node.stage-recovery { stroke: #fecaca; }
342
+ .review-journey-dot {
343
+ fill: #0f172a;
344
+ }
345
+ .review-journey-dot.stage-journey { fill: #0d9488; }
346
+ .review-journey-dot.stage-step { fill: #2563eb; }
347
+ .review-journey-dot.stage-outcome { fill: #4f46e5; }
348
+ .review-journey-dot.stage-boundary { fill: #ca8a04; }
349
+ .review-journey-dot.stage-recovery { fill: #dc2626; }
350
+ .review-journey-number {
351
+ fill: #ffffff;
352
+ font-size: 11px;
353
+ font-weight: 850;
354
+ dominant-baseline: central;
355
+ }
356
+ .review-journey-tag {
357
+ fill: #64748b;
358
+ font-size: 12px;
359
+ font-weight: 850;
360
+ }
361
+ .review-journey-label {
362
+ fill: #0f172a;
363
+ font-size: 12px;
364
+ font-weight: 760;
365
+ }
366
+ .review-panel-list {
367
+ margin: 16px 0 0;
368
+ padding-left: 18px;
369
+ color: var(--review-text);
370
+ font-size: 15px;
371
+ line-height: 1.72;
372
+ overflow-wrap: anywhere;
373
+ }
374
+ .review-panel-list li + li {
375
+ margin-top: 9px;
376
+ }
377
+ .review-detail-summary {
378
+ font-weight: 850;
379
+ color: var(--review-text);
380
+ }
381
+ .review-detail-body {
382
+ color: var(--review-text);
383
+ }
384
+ .review-panel-list .empty {
385
+ color: var(--review-muted);
386
+ }
387
+ .review-bottom-bar {
388
+ position: fixed;
389
+ left: 0;
390
+ right: 0;
391
+ bottom: 0;
392
+ z-index: 30;
393
+ padding: 12px 22px calc(12px + env(safe-area-inset-bottom));
394
+ border-top: 1px solid var(--review-line);
395
+ background: rgba(246, 248, 251, 0.94);
396
+ box-shadow: 0 -14px 32px rgba(15, 23, 42, 0.08);
397
+ backdrop-filter: blur(14px);
398
+ }
399
+ .review-bottom-bar-inner {
400
+ display: flex;
401
+ justify-content: flex-end;
402
+ gap: 12px;
403
+ max-width: 1220px;
404
+ margin: 0 auto;
405
+ }
406
+ .review-bottom-action {
407
+ cursor: pointer;
408
+ display: inline-flex;
409
+ align-items: center;
410
+ justify-content: center;
411
+ min-width: 152px;
412
+ min-height: 48px;
413
+ border: 1px solid transparent;
414
+ border-radius: 12px;
415
+ padding: 0 20px;
416
+ font: inherit;
417
+ font-size: 16px;
418
+ font-weight: 850;
419
+ letter-spacing: 0;
420
+ line-height: 1;
421
+ white-space: nowrap;
422
+ box-shadow: 0 8px 18px rgba(15, 23, 42, 0.06);
423
+ transition: background-color 160ms ease, border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease;
424
+ }
425
+ .review-bottom-action.revise {
426
+ border-color: #fecaca;
427
+ background: #fff1f2;
428
+ color: #b42318;
429
+ }
430
+ .review-bottom-action.confirm {
431
+ border-color: #bbf7d0;
432
+ background: #ecfdf3;
433
+ color: #067647;
434
+ }
435
+ .review-bottom-action:hover,
436
+ .review-bottom-action:focus-visible {
437
+ box-shadow: 0 10px 22px rgba(15, 23, 42, 0.1);
438
+ transform: translateY(-1px);
439
+ outline: none;
440
+ }
441
+ .review-bottom-action.revise:hover,
442
+ .review-bottom-action.revise:focus-visible {
443
+ border-color: #fda4af;
444
+ background: #ffe4e6;
445
+ }
446
+ .review-bottom-action.confirm:hover,
447
+ .review-bottom-action.confirm:focus-visible {
448
+ border-color: #86efac;
449
+ background: #dcfce7;
450
+ }
451
+ .review-bottom-action:active {
452
+ box-shadow: 0 4px 10px rgba(15, 23, 42, 0.08);
453
+ transform: translateY(0);
454
+ }
455
+ @media (max-width: 860px) {
456
+ .review-overview {
457
+ grid-template-columns: 1fr;
458
+ }
459
+ .review-panel-grid {
460
+ grid-template-columns: 1fr;
461
+ }
462
+ }
463
+ @media (max-width: 620px) {
464
+ .review-page { padding: 18px 12px 128px; }
465
+ .review-topbar { align-items: flex-start; flex-direction: column; }
466
+ .review-project-version {
467
+ min-width: 0;
468
+ width: 100%;
469
+ margin-left: 0;
470
+ }
471
+ .review-overview { padding: 18px; }
472
+ .review-overview h1 {
473
+ font-size: 26px;
474
+ word-break: break-all;
475
+ }
476
+ .review-problem { word-break: break-all; }
477
+ .review-map-canvas svg { min-width: 0; }
478
+ .review-journey-map svg { min-width: 620px; }
479
+ .review-section-heading h2 { font-size: 20px; }
480
+ .review-bottom-bar { padding-inline: 12px; }
481
+ .review-bottom-bar-inner {
482
+ display: grid;
483
+ grid-template-columns: 1fr 1fr;
484
+ gap: 8px;
485
+ }
486
+ .review-bottom-action {
487
+ justify-content: center;
488
+ padding-inline: 10px;
489
+ font-size: 15px;
490
+ }
491
+ }
492
+ </style>
493
+ </head>
494
+ <body>
495
+ <main class="review-page">
496
+ <header class="review-topbar">
497
+ <div class="review-brand">OpenPrd / 评审面板</div>
498
+
499
+ <div class="review-project-version" aria-label="项目版本">
500
+ <span class="review-project-version-label">项目版本</span>
501
+ <strong class="review-project-version-value">0.1.2</strong>
502
+ <span class="review-project-version-meta">当前版本 · 6 条变化</span>
503
+ </div>
504
+
505
+ </header>
506
+
507
+ <section class="review-overview" aria-labelledby="reviewOverviewTitle">
508
+ <div class="review-overview-copy">
509
+ <p class="review-kicker">需求概览</p>
510
+ <h1 id="reviewOverviewTitle">OpenPrd 用户视角变化摘要</h1>
511
+ <p class="review-problem">OpenPrd 现在已经有内部 PRD 版本和用户视角变化摘要,但还没有一个可选的项目级 release/version 轨道来维护当前版本号、版本内更新项,以及与 commit tag 的协同规则。结果是版本号已经在项目里被真实使用,却缺少一个本地真源来累计本版本的需求、Bug、handoff 摘要和最终发布说明。</p>
512
+ </div>
513
+ </section>
514
+
515
+
516
+ <section class="review-map" aria-labelledby="reviewMapTitle">
517
+ <div class="review-section-heading">
518
+ <span class="review-icon review-icon-map" aria-hidden="true"><svg viewBox="0 0 24 24" role="img" aria-label="图谱"><path d="M12 5v14" /><path d="M5 8h14" /><path d="M7 16h10" /><circle cx="12" cy="5" r="2" /><circle cx="5" cy="8" r="2" /><circle cx="19" cy="8" r="2" /><circle cx="7" cy="16" r="2" /><circle cx="17" cy="16" r="2" /></svg></span>
519
+ <div>
520
+ <h2 id="reviewMapTitle">需求关系图</h2>
521
+ </div>
522
+ </div>
523
+ <div class="review-map-canvas">
524
+ <svg viewBox="0 0 960 336" role="img" aria-label="需求关系图" preserveAspectRatio="xMidYMid meet">
525
+ <rect class="review-map-bg" x="2" y="2" width="956" height="332" rx="8" />
526
+ <path class="review-map-link" d="M 480 168 L 250 94" /><path class="review-map-link" d="M 480 168 L 710 94" /><path class="review-map-link" d="M 480 168 L 250 242" /><path class="review-map-link" d="M 480 168 L 710 242" />
527
+
528
+ <g>
529
+ <rect class="review-map-node node-1" x="128" y="51" width="244" height="86" rx="8" />
530
+
531
+ <rect class="review-map-tag-pill node-1" x="209" y="59" width="82" height="26" rx="13" />
532
+ <text class="review-map-tag node-1" x="250" y="76" text-anchor="middle">版本轨道</text>
533
+
534
+ <text class="review-map-label" x="156" y="100" text-anchor="start"><tspan x="156" dy="0">统一版本号、变化条目和tag</tspan></text>
535
+ </g>
536
+
537
+ <g>
538
+ <rect class="review-map-node node-2" x="588" y="51" width="244" height="86" rx="8" />
539
+
540
+ <rect class="review-map-tag-pill node-2" x="669" y="59" width="82" height="26" rx="13" />
541
+ <text class="review-map-tag node-2" x="710" y="76" text-anchor="middle">四处落点</text>
542
+
543
+ <text class="review-map-label" x="616" y="100" text-anchor="start"><tspan x="616" dy="0">ledger、commit、handoff、</tspan><tspan x="616" dy="14">同步</tspan></text>
544
+ </g>
545
+
546
+ <g>
547
+ <rect class="review-map-node node-3" x="128" y="199" width="244" height="86" rx="8" />
548
+
549
+ <rect class="review-map-tag-pill node-3" x="216" y="207" width="68" height="26" rx="13" />
550
+ <text class="review-map-tag node-3" x="250" y="224" text-anchor="middle">主流程</text>
551
+
552
+ <text class="review-map-label" x="156" y="248" text-anchor="start"><tspan x="156" dy="0">版本累计变化,commit可挂tag</tspan></text>
553
+ </g>
554
+
555
+ <g>
556
+ <rect class="review-map-node node-4" x="588" y="199" width="244" height="86" rx="8" />
557
+
558
+ <rect class="review-map-tag-pill node-4" x="669" y="207" width="82" height="26" rx="13" />
559
+ <text class="review-map-tag node-4" x="710" y="224" text-anchor="middle">主要风险</text>
560
+
561
+ <text class="review-map-label" x="616" y="248" text-anchor="start"><tspan x="616" dy="0">远端tag覆盖和版本混用</tspan></text>
562
+ </g>
563
+
564
+
565
+ <g class="review-map-center-group">
566
+ <rect class="review-map-center" x="330" y="124" width="300" height="88" rx="8" />
567
+
568
+ <rect class="review-map-tag-pill center" x="439" y="133" width="82" height="26" rx="13" />
569
+ <text class="review-map-tag center" x="480" y="150" text-anchor="middle">问题定义</text>
570
+
571
+ <text class="review-map-label center" x="360" y="176" text-anchor="start"><tspan x="360" dy="0">缺少项目级版本真源与tag协同</tspan></text>
572
+ </g>
573
+
574
+ </svg>
575
+ </div>
576
+ </section>
577
+
578
+ <section class="review-panel-grid" aria-label="固定评审项">
579
+
580
+ <section class="review-panel review-panel-flow">
581
+ <header class="review-panel-head">
582
+ <span class="review-icon review-icon-flow" aria-hidden="true"><svg viewBox="0 0 24 24" role="img" aria-label="流程"><path d="M5 6.5h6.4a3.6 3.6 0 0 1 3.6 3.6v.8" /><path d="M15 17.5H8.6A3.6 3.6 0 0 1 5 13.9v-.8" /><path d="m12 8.5 3-3 3 3" /><path d="m8 15.5-3 3-3-3" /></svg></span>
583
+ <div>
584
+ <h3>主流程与边界情况</h3>
585
+ <p>确认用户旅程、关键步骤和恢复路径是否已经讲清楚,能否进入实现前确认</p>
586
+ </div>
587
+ </header>
588
+ <div class="review-chip-row" aria-label="主流程与边界情况重点摘要">
589
+ <span class="review-chip">新增轨道</span><span class="review-chip">关联提交</span><span class="review-chip">导出说明</span>
590
+ </div>
591
+
592
+ <div class="review-journey-map" aria-label="主流程小图">
593
+ <svg viewBox="0 0 680 320" role="img" aria-label="用户旅程、关键步骤、边界情况和恢复路径" preserveAspectRatio="xMidYMid meet">
594
+ <defs>
595
+ <marker id="reviewJourneyArrow" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto">
596
+ <path d="M 0 0 L 10 5 L 0 10 z" fill="#0d9488" />
597
+ </marker>
598
+ </defs>
599
+ <rect class="review-journey-bg" x="2" y="2" width="676" height="316" rx="8" />
600
+ <path class="review-journey-arrow" d="M 202 88 H 248" marker-end="url(#reviewJourneyArrow)" />
601
+ <path class="review-journey-arrow" d="M 432 88 H 478" marker-end="url(#reviewJourneyArrow)" />
602
+ <path class="review-journey-arrow branch" d="M 340 134 V 164 H 236 V 190" marker-end="url(#reviewJourneyArrow)" />
603
+ <path class="review-journey-arrow branch" d="M 340 134 V 164 H 454 V 190" marker-end="url(#reviewJourneyArrow)" />
604
+ <g>
605
+ <rect class="review-journey-node stage-journey" x="26" y="40" width="176" height="96" rx="8" />
606
+ <circle class="review-journey-dot stage-journey" cx="56" cy="64" r="12" />
607
+ <text class="review-journey-number" x="56" y="64" text-anchor="middle">1</text>
608
+ <text class="review-journey-tag" x="114" y="66" text-anchor="middle">用户旅程</text>
609
+ <text class="review-journey-label" x="114" y="92" text-anchor="middle"><tspan x="114" dy="0">重点说明</tspan></text>
610
+ </g>
611
+ <g>
612
+ <rect class="review-journey-node stage-step" x="252" y="40" width="176" height="96" rx="8" />
613
+ <circle class="review-journey-dot stage-step" cx="282" cy="64" r="12" />
614
+ <text class="review-journey-number" x="282" y="64" text-anchor="middle">2</text>
615
+ <text class="review-journey-tag" x="340" y="66" text-anchor="middle">关键步骤</text>
616
+ <text class="review-journey-label" x="340" y="92" text-anchor="middle"><tspan x="340" dy="0">重点说明</tspan></text>
617
+ </g>
618
+ <g>
619
+ <rect class="review-journey-node stage-outcome" x="478" y="40" width="176" height="96" rx="8" />
620
+ <circle class="review-journey-dot stage-outcome" cx="508" cy="64" r="12" />
621
+ <text class="review-journey-number" x="508" y="64" text-anchor="middle">3</text>
622
+ <text class="review-journey-tag" x="566" y="66" text-anchor="middle">结果确认</text>
623
+ <text class="review-journey-label" x="566" y="92" text-anchor="middle"><tspan x="566" dy="0">重点说明</tspan></text>
624
+ </g>
625
+ <g>
626
+ <rect class="review-journey-node stage-boundary" x="126" y="194" width="220" height="88" rx="8" />
627
+ <circle class="review-journey-dot stage-boundary" cx="158" cy="218" r="12" />
628
+ <text class="review-journey-number" x="158" y="218" text-anchor="middle">B</text>
629
+ <text class="review-journey-tag" x="236" y="220" text-anchor="middle">边界情况</text>
630
+ <text class="review-journey-label" x="236" y="246" text-anchor="middle"><tspan x="236" dy="0">项目可能已经有自己的一套版本号</tspan><tspan x="236" dy="13">规则</tspan></text>
631
+ </g>
632
+ <g>
633
+ <rect class="review-journey-node stage-recovery" x="356" y="194" width="220" height="88" rx="8" />
634
+ <circle class="review-journey-dot stage-recovery" cx="388" cy="218" r="12" />
635
+ <text class="review-journey-number" x="388" y="218" text-anchor="middle">R</text>
636
+ <text class="review-journey-tag" x="466" y="220" text-anchor="middle">恢复路径</text>
637
+ <text class="review-journey-label" x="466" y="246" text-anchor="middle"><tspan x="466" dy="0">commit</tspan></text>
638
+ </g>
639
+ </svg>
640
+ </div>
641
+
642
+ <ul class="review-panel-list"><li><strong class="review-detail-summary">新增轨道</strong><span class="review-detail-body">:项目可记录当前版本,并累计该版本内的需求、Bug和摘要。</span></li><li><strong class="review-detail-summary">关联提交</strong><span class="review-detail-body">:启用版本轨道后,commit 可读取当前版本并辅助挂本地 tag。</span></li><li><strong class="review-detail-summary">导出说明</strong><span class="review-detail-body">:handoff、版本说明和外部同步都可复用同一版本条目。</span></li></ul>
643
+ </section>
644
+
645
+
646
+ <section class="review-panel review-panel-function">
647
+ <header class="review-panel-head">
648
+ <span class="review-icon review-icon-function" aria-hidden="true"><svg viewBox="0 0 24 24" role="img" aria-label="功能"><path d="M5 7h14" /><path d="M5 12h14" /><path d="M5 17h14" /><circle cx="8" cy="7" r="2" /><circle cx="16" cy="12" r="2" /><circle cx="11" cy="17" r="2" /></svg></span>
649
+ <div>
650
+ <h3>功能与约束</h3>
651
+ <p>区分必须交付、非功能要求和当前依赖假设</p>
652
+ </div>
653
+ </header>
654
+ <div class="review-chip-row" aria-label="功能与约束重点摘要">
655
+ <span class="review-chip">保留短文案</span><span class="review-chip">手动修正版</span><span class="review-chip">同版续提</span>
656
+ </div>
657
+
658
+ <ul class="review-panel-list"><li><strong class="review-detail-summary">保留短文案</strong><span class="review-detail-body">:新增、修复、优化、调整、移除继续作为版本条目的默认动作词。</span></li><li><strong class="review-detail-summary">手动修正版</strong><span class="review-detail-body">:用户可以随时把当前版本从 0.1.23 调整到下一个版本。</span></li><li><strong class="review-detail-summary">同版续提</strong><span class="review-detail-body">:未切新版本时,后续提交继续累计到当前版本。</span></li></ul>
659
+ </section>
660
+
661
+
662
+ <section class="review-panel review-panel-guardrail">
663
+ <header class="review-panel-head">
664
+ <span class="review-icon review-icon-guardrail" aria-hidden="true"><svg viewBox="0 0 24 24" role="img" aria-label="护栏"><path d="M12 3 5 6v5c0 4.4 2.8 8.4 7 9.8 4.2-1.4 7-5.4 7-9.8V6l-7-3Z" /><path d="M9 12.2 11 14l4-4.4" /></svg></span>
665
+ <div>
666
+ <h3>业务成本与滥用护栏</h3>
667
+ <p>涉及免费额度、消耗型成本或第三方调用时,先确认限制、报警和止损动作</p>
668
+ </div>
669
+ </header>
670
+ <div class="review-chip-row" aria-label="业务成本与滥用护栏重点摘要">
671
+ <span class="review-chip">分层版本</span><span class="review-chip">不强推送</span><span class="review-chip">可分开启用</span>
672
+ </div>
673
+
674
+ <ul class="review-panel-list"><li><strong class="review-detail-summary">分层版本</strong><span class="review-detail-body">:内部 PRD 版本 v000x 不直接等于项目发版号。</span></li><li><strong class="review-detail-summary">不强推送</strong><span class="review-detail-body">:不默认自动 push、发布或 force 更新远端 tag。</span></li><li><strong class="review-detail-summary">可分开启用</strong><span class="review-detail-body">:只想维护版本说明的项目可以不开 tag 辅助。</span></li></ul>
675
+ </section>
676
+
677
+
678
+ <section class="review-panel review-panel-risk">
679
+ <header class="review-panel-head">
680
+ <span class="review-icon review-icon-risk" aria-hidden="true"><svg viewBox="0 0 24 24" role="img" aria-label="风险"><path d="M12 4 3.5 19h17L12 4Z" /><path d="M12 9v4" /><path d="M12 16.5h.01" /></svg></span>
681
+ <div>
682
+ <h3>开放问题与风险</h3>
683
+ <p>需求定稿前还没关掉的问题要留在这里,不要默默假定解决</p>
684
+ </div>
685
+ </header>
686
+ <div class="review-chip-row" aria-label="开放问题与风险重点摘要">
687
+ <span class="review-chip">远端冲突</span><span class="review-chip">版本混用</span><span class="review-chip">事实失真</span>
688
+ </div>
689
+
690
+ <ul class="review-panel-list"><li><strong class="review-detail-summary">远端冲突</strong><span class="review-detail-body">:同名 tag 已推到远端时,继续移动会变成高风险操作。</span></li><li><strong class="review-detail-summary">版本混用</strong><span class="review-detail-body">:若把 PRD 版本当发版号,会让 review 和 release 都变乱。</span></li><li><strong class="review-detail-summary">事实失真</strong><span class="review-detail-body">:变化条目归错版本,会让 handoff 和外部同步失真。</span></li></ul>
691
+ </section>
692
+
693
+ </section>
694
+
695
+ <nav class="review-bottom-bar" aria-label="评审决定">
696
+ <div class="review-bottom-bar-inner">
697
+ <button type="button" class="review-bottom-action revise" data-copy-value="OpenPrD Review: 需要调整
698
+
699
+ 命令:
700
+
701
+ openprd review . --mark needs-revision --version &#39;v0003&#39; --digest &#39;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&#39; --work-unit &#39;wu-20260602122244-78656aaf&#39; --notes &#39;说明需要调整的点&#39;
702
+
703
+ 上下文:
704
+
705
+ {
706
+ &quot;versionId&quot;: &quot;v0003&quot;,
707
+ &quot;title&quot;: &quot;OpenPrd 用户视角变化摘要&quot;,
708
+ &quot;digest&quot;: &quot;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&quot;,
709
+ &quot;workUnitId&quot;: &quot;wu-20260602122244-78656aaf&quot;,
710
+ &quot;targetRoot&quot;: &quot;/Users/chaojifeng/Projects/harness-engineer/openprd&quot;,
711
+ &quot;reviewStatus&quot;: &quot;pending-confirmation&quot;,
712
+ &quot;recommendedActions&quot;: [
713
+ &quot;确认问题与目标&quot;,
714
+ &quot;确认范围内 / 范围外&quot;,
715
+ &quot;确认主流程与失败路径&quot;,
716
+ &quot;确认关键风险与开放问题&quot;
717
+ ],
718
+ &quot;summaryStyle&quot;: {
719
+ &quot;perspective&quot;: &quot;从用户可感知变化出发,优先写用户现在能做什么、会看到什么、哪个问题被修好。&quot;,
720
+ &quot;preferredVerbs&quot;: [
721
+ &quot;新增&quot;,
722
+ &quot;修复&quot;,
723
+ &quot;优化&quot;,
724
+ &quot;调整&quot;,
725
+ &quot;移除&quot;
726
+ ],
727
+ &quot;panelExamples&quot;: {
728
+ &quot;flow&quot;: {
729
+ &quot;summary&quot;: &quot;新增入口&quot;,
730
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
731
+ },
732
+ &quot;function&quot;: {
733
+ &quot;summary&quot;: &quot;优化说明&quot;,
734
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
735
+ },
736
+ &quot;guardrail&quot;: {
737
+ &quot;summary&quot;: &quot;调整边界&quot;,
738
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
739
+ },
740
+ &quot;risk&quot;: {
741
+ &quot;summary&quot;: &quot;修复误判&quot;,
742
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
743
+ }
744
+ }
745
+ },
746
+ &quot;sectionKeys&quot;: [
747
+ &quot;meta&quot;,
748
+ &quot;problem&quot;,
749
+ &quot;users&quot;,
750
+ &quot;goals&quot;,
751
+ &quot;scope&quot;,
752
+ &quot;scenarios&quot;,
753
+ &quot;requirements&quot;,
754
+ &quot;businessGuardrails&quot;,
755
+ &quot;constraints&quot;,
756
+ &quot;risks&quot;,
757
+ &quot;handoff&quot;,
758
+ &quot;typeSpecific&quot;
759
+ ],
760
+ &quot;presentationContract&quot;: {
761
+ &quot;intent&quot;: &quot;这些限制用于反馈给 Agent 重新概括,不由 HTML 模板截断原文。&quot;,
762
+ &quot;summaryStyle&quot;: {
763
+ &quot;perspective&quot;: &quot;从用户可感知变化出发,优先写用户现在能做什么、会看到什么、哪个问题被修好。&quot;,
764
+ &quot;preferredVerbs&quot;: [
765
+ &quot;新增&quot;,
766
+ &quot;修复&quot;,
767
+ &quot;优化&quot;,
768
+ &quot;调整&quot;,
769
+ &quot;移除&quot;
770
+ ],
771
+ &quot;panelExamples&quot;: {
772
+ &quot;flow&quot;: {
773
+ &quot;summary&quot;: &quot;新增入口&quot;,
774
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
775
+ },
776
+ &quot;function&quot;: {
777
+ &quot;summary&quot;: &quot;优化说明&quot;,
778
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
779
+ },
780
+ &quot;guardrail&quot;: {
781
+ &quot;summary&quot;: &quot;调整边界&quot;,
782
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
783
+ },
784
+ &quot;risk&quot;: {
785
+ &quot;summary&quot;: &quot;修复误判&quot;,
786
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
787
+ }
788
+ }
789
+ },
790
+ &quot;expectedDataShape&quot;: {
791
+ &quot;reviewPresentation&quot;: {
792
+ &quot;diagram&quot;: {
793
+ &quot;type&quot;: &quot;map&quot;,
794
+ &quot;note&quot;: &quot;默认用关系图;只有确认为线性流程时改为 flow,并用 flowEdges 明确哪些节点有箭头。&quot;
795
+ },
796
+ &quot;mapNodes&quot;: {
797
+ &quot;problem&quot;: {
798
+ &quot;title&quot;: &quot;问题定义&quot;,
799
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
800
+ },
801
+ &quot;goal&quot;: {
802
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
803
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
804
+ },
805
+ &quot;scope&quot;: {
806
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
807
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
808
+ },
809
+ &quot;flow&quot;: {
810
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
811
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
812
+ },
813
+ &quot;risk&quot;: {
814
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
815
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
816
+ }
817
+ },
818
+ &quot;flowNodes&quot;: [
819
+ {
820
+ &quot;id&quot;: &quot;step1&quot;,
821
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
822
+ },
823
+ {
824
+ &quot;id&quot;: &quot;step2&quot;,
825
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
826
+ },
827
+ {
828
+ &quot;id&quot;: &quot;step3&quot;,
829
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
830
+ }
831
+ ],
832
+ &quot;flowEdges&quot;: [
833
+ {
834
+ &quot;from&quot;: &quot;step1&quot;,
835
+ &quot;to&quot;: &quot;step2&quot;
836
+ },
837
+ {
838
+ &quot;from&quot;: &quot;step2&quot;,
839
+ &quot;to&quot;: &quot;step3&quot;
840
+ }
841
+ ],
842
+ &quot;panels&quot;: {
843
+ &quot;flow&quot;: [
844
+ {
845
+ &quot;summary&quot;: &quot;新增入口&quot;,
846
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
847
+ }
848
+ ],
849
+ &quot;function&quot;: [
850
+ {
851
+ &quot;summary&quot;: &quot;优化说明&quot;,
852
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
853
+ }
854
+ ],
855
+ &quot;guardrail&quot;: [
856
+ {
857
+ &quot;summary&quot;: &quot;调整边界&quot;,
858
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
859
+ }
860
+ ],
861
+ &quot;risk&quot;: [
862
+ {
863
+ &quot;summary&quot;: &quot;修复误判&quot;,
864
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
865
+ }
866
+ ]
867
+ }
868
+ }
869
+ },
870
+ &quot;rules&quot;: [
871
+ {
872
+ &quot;id&quot;: &quot;review-map-card-text&quot;,
873
+ &quot;area&quot;: &quot;需求关系图 / 需求流程图&quot;,
874
+ &quot;target&quot;: &quot;图中每个卡片的正文&quot;,
875
+ &quot;maxChars&quot;: 30,
876
+ &quot;action&quot;: &quot;请写入 reviewPresentation.mapNodes.*.text 或 reviewPresentation.flowNodes[].text,重写成用户一眼能扫懂的短句,不要靠省略号或截断。&quot;
877
+ },
878
+ {
879
+ &quot;id&quot;: &quot;review-map-card-title&quot;,
880
+ &quot;area&quot;: &quot;需求关系图 / 需求流程图&quot;,
881
+ &quot;target&quot;: &quot;图中卡片标题胶囊&quot;,
882
+ &quot;maxChars&quot;: 15,
883
+ &quot;action&quot;: &quot;请写入 reviewPresentation.mapNodes.*.title,重写成短标题,优先使用业务词,不使用内部技术词。&quot;
884
+ },
885
+ {
886
+ &quot;id&quot;: &quot;review-highlight-chip&quot;,
887
+ &quot;area&quot;: &quot;四个评审卡片&quot;,
888
+ &quot;target&quot;: &quot;重点摘要胶囊&quot;,
889
+ &quot;maxChars&quot;: 15,
890
+ &quot;action&quot;: &quot;请重写成短标签,优先使用 新增 / 修复 / 优化 / 调整 / 移除 这类用户能一眼看懂的动作词,再补必要对象。&quot;
891
+ },
892
+ {
893
+ &quot;id&quot;: &quot;review-panel-detail-format&quot;,
894
+ &quot;area&quot;: &quot;四个评审卡片&quot;,
895
+ &quot;target&quot;: &quot;明细分点&quot;,
896
+ &quot;format&quot;: &quot;- **摘要内容**:明细一句话&quot;,
897
+ &quot;action&quot;: &quot;请写入 reviewPresentation.panels.&lt;kind&gt;[],把每个明细改写为“加粗短摘要 + 一句话说明”,短摘要优先使用 新增 / 修复 / 优化 / 调整 / 移除。&quot;
898
+ }
899
+ ]
900
+ },
901
+ &quot;presentationFeedback&quot;: [],
902
+ &quot;exportedAt&quot;: &quot;2026-06-05T00:44:22.422Z&quot;
903
+ }" title="openprd review . --mark needs-revision --version &#39;v0003&#39; --digest &#39;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&#39; --work-unit &#39;wu-20260602122244-78656aaf&#39; --notes &#39;说明需要调整的点&#39;">
904
+ 需要调整
905
+ </button>
906
+ <button type="button" class="review-bottom-action confirm" data-copy-value="OpenPrD Review: 认可并继续下一步
907
+
908
+ 当前稳定评审稿 v0003已确认。请先记录这版稳定评审稿,并继续当前 OpenPrd 下一步。若 review 后 tasks 已就绪但还需要执行授权,请直接展示执行确认清单,不要再泛泛确认。
909
+
910
+ 命令:
911
+
912
+ openprd review . --mark confirmed --version &#39;v0003&#39; --digest &#39;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&#39; --work-unit &#39;wu-20260602122244-78656aaf&#39;
913
+
914
+ 上下文:
915
+
916
+ {
917
+ &quot;versionId&quot;: &quot;v0003&quot;,
918
+ &quot;title&quot;: &quot;OpenPrd 用户视角变化摘要&quot;,
919
+ &quot;digest&quot;: &quot;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&quot;,
920
+ &quot;workUnitId&quot;: &quot;wu-20260602122244-78656aaf&quot;,
921
+ &quot;targetRoot&quot;: &quot;/Users/chaojifeng/Projects/harness-engineer/openprd&quot;,
922
+ &quot;reviewStatus&quot;: &quot;pending-confirmation&quot;,
923
+ &quot;recommendedActions&quot;: [
924
+ &quot;确认问题与目标&quot;,
925
+ &quot;确认范围内 / 范围外&quot;,
926
+ &quot;确认主流程与失败路径&quot;,
927
+ &quot;确认关键风险与开放问题&quot;
928
+ ],
929
+ &quot;summaryStyle&quot;: {
930
+ &quot;perspective&quot;: &quot;从用户可感知变化出发,优先写用户现在能做什么、会看到什么、哪个问题被修好。&quot;,
931
+ &quot;preferredVerbs&quot;: [
932
+ &quot;新增&quot;,
933
+ &quot;修复&quot;,
934
+ &quot;优化&quot;,
935
+ &quot;调整&quot;,
936
+ &quot;移除&quot;
937
+ ],
938
+ &quot;panelExamples&quot;: {
939
+ &quot;flow&quot;: {
940
+ &quot;summary&quot;: &quot;新增入口&quot;,
941
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
942
+ },
943
+ &quot;function&quot;: {
944
+ &quot;summary&quot;: &quot;优化说明&quot;,
945
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
946
+ },
947
+ &quot;guardrail&quot;: {
948
+ &quot;summary&quot;: &quot;调整边界&quot;,
949
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
950
+ },
951
+ &quot;risk&quot;: {
952
+ &quot;summary&quot;: &quot;修复误判&quot;,
953
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
954
+ }
955
+ }
956
+ },
957
+ &quot;sectionKeys&quot;: [
958
+ &quot;meta&quot;,
959
+ &quot;problem&quot;,
960
+ &quot;users&quot;,
961
+ &quot;goals&quot;,
962
+ &quot;scope&quot;,
963
+ &quot;scenarios&quot;,
964
+ &quot;requirements&quot;,
965
+ &quot;businessGuardrails&quot;,
966
+ &quot;constraints&quot;,
967
+ &quot;risks&quot;,
968
+ &quot;handoff&quot;,
969
+ &quot;typeSpecific&quot;
970
+ ],
971
+ &quot;presentationContract&quot;: {
972
+ &quot;intent&quot;: &quot;这些限制用于反馈给 Agent 重新概括,不由 HTML 模板截断原文。&quot;,
973
+ &quot;summaryStyle&quot;: {
974
+ &quot;perspective&quot;: &quot;从用户可感知变化出发,优先写用户现在能做什么、会看到什么、哪个问题被修好。&quot;,
975
+ &quot;preferredVerbs&quot;: [
976
+ &quot;新增&quot;,
977
+ &quot;修复&quot;,
978
+ &quot;优化&quot;,
979
+ &quot;调整&quot;,
980
+ &quot;移除&quot;
981
+ ],
982
+ &quot;panelExamples&quot;: {
983
+ &quot;flow&quot;: {
984
+ &quot;summary&quot;: &quot;新增入口&quot;,
985
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
986
+ },
987
+ &quot;function&quot;: {
988
+ &quot;summary&quot;: &quot;优化说明&quot;,
989
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
990
+ },
991
+ &quot;guardrail&quot;: {
992
+ &quot;summary&quot;: &quot;调整边界&quot;,
993
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
994
+ },
995
+ &quot;risk&quot;: {
996
+ &quot;summary&quot;: &quot;修复误判&quot;,
997
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
998
+ }
999
+ }
1000
+ },
1001
+ &quot;expectedDataShape&quot;: {
1002
+ &quot;reviewPresentation&quot;: {
1003
+ &quot;diagram&quot;: {
1004
+ &quot;type&quot;: &quot;map&quot;,
1005
+ &quot;note&quot;: &quot;默认用关系图;只有确认为线性流程时改为 flow,并用 flowEdges 明确哪些节点有箭头。&quot;
1006
+ },
1007
+ &quot;mapNodes&quot;: {
1008
+ &quot;problem&quot;: {
1009
+ &quot;title&quot;: &quot;问题定义&quot;,
1010
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
1011
+ },
1012
+ &quot;goal&quot;: {
1013
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
1014
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
1015
+ },
1016
+ &quot;scope&quot;: {
1017
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
1018
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
1019
+ },
1020
+ &quot;flow&quot;: {
1021
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
1022
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
1023
+ },
1024
+ &quot;risk&quot;: {
1025
+ &quot;title&quot;: &quot;15 字以内标题&quot;,
1026
+ &quot;text&quot;: &quot;30 字以内的图中正文&quot;
1027
+ }
1028
+ },
1029
+ &quot;flowNodes&quot;: [
1030
+ {
1031
+ &quot;id&quot;: &quot;step1&quot;,
1032
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
1033
+ },
1034
+ {
1035
+ &quot;id&quot;: &quot;step2&quot;,
1036
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
1037
+ },
1038
+ {
1039
+ &quot;id&quot;: &quot;step3&quot;,
1040
+ &quot;text&quot;: &quot;30 字以内的流程卡片正文&quot;
1041
+ }
1042
+ ],
1043
+ &quot;flowEdges&quot;: [
1044
+ {
1045
+ &quot;from&quot;: &quot;step1&quot;,
1046
+ &quot;to&quot;: &quot;step2&quot;
1047
+ },
1048
+ {
1049
+ &quot;from&quot;: &quot;step2&quot;,
1050
+ &quot;to&quot;: &quot;step3&quot;
1051
+ }
1052
+ ],
1053
+ &quot;panels&quot;: {
1054
+ &quot;flow&quot;: [
1055
+ {
1056
+ &quot;summary&quot;: &quot;新增入口&quot;,
1057
+ &quot;detail&quot;: &quot;用户现在可以直接进入对应流程,不用再自己找路径。&quot;
1058
+ }
1059
+ ],
1060
+ &quot;function&quot;: [
1061
+ {
1062
+ &quot;summary&quot;: &quot;优化说明&quot;,
1063
+ &quot;detail&quot;: &quot;用户先看到新增、修复、优化这类短摘要,再决定是否继续细读。&quot;
1064
+ }
1065
+ ],
1066
+ &quot;guardrail&quot;: [
1067
+ {
1068
+ &quot;summary&quot;: &quot;调整边界&quot;,
1069
+ &quot;detail&quot;: &quot;只保留用户需要知道的限制、影响和下一步。&quot;
1070
+ }
1071
+ ],
1072
+ &quot;risk&quot;: [
1073
+ {
1074
+ &quot;summary&quot;: &quot;修复误判&quot;,
1075
+ &quot;detail&quot;: &quot;避免把实现授权写成再次索取确认。&quot;
1076
+ }
1077
+ ]
1078
+ }
1079
+ }
1080
+ },
1081
+ &quot;rules&quot;: [
1082
+ {
1083
+ &quot;id&quot;: &quot;review-map-card-text&quot;,
1084
+ &quot;area&quot;: &quot;需求关系图 / 需求流程图&quot;,
1085
+ &quot;target&quot;: &quot;图中每个卡片的正文&quot;,
1086
+ &quot;maxChars&quot;: 30,
1087
+ &quot;action&quot;: &quot;请写入 reviewPresentation.mapNodes.*.text 或 reviewPresentation.flowNodes[].text,重写成用户一眼能扫懂的短句,不要靠省略号或截断。&quot;
1088
+ },
1089
+ {
1090
+ &quot;id&quot;: &quot;review-map-card-title&quot;,
1091
+ &quot;area&quot;: &quot;需求关系图 / 需求流程图&quot;,
1092
+ &quot;target&quot;: &quot;图中卡片标题胶囊&quot;,
1093
+ &quot;maxChars&quot;: 15,
1094
+ &quot;action&quot;: &quot;请写入 reviewPresentation.mapNodes.*.title,重写成短标题,优先使用业务词,不使用内部技术词。&quot;
1095
+ },
1096
+ {
1097
+ &quot;id&quot;: &quot;review-highlight-chip&quot;,
1098
+ &quot;area&quot;: &quot;四个评审卡片&quot;,
1099
+ &quot;target&quot;: &quot;重点摘要胶囊&quot;,
1100
+ &quot;maxChars&quot;: 15,
1101
+ &quot;action&quot;: &quot;请重写成短标签,优先使用 新增 / 修复 / 优化 / 调整 / 移除 这类用户能一眼看懂的动作词,再补必要对象。&quot;
1102
+ },
1103
+ {
1104
+ &quot;id&quot;: &quot;review-panel-detail-format&quot;,
1105
+ &quot;area&quot;: &quot;四个评审卡片&quot;,
1106
+ &quot;target&quot;: &quot;明细分点&quot;,
1107
+ &quot;format&quot;: &quot;- **摘要内容**:明细一句话&quot;,
1108
+ &quot;action&quot;: &quot;请写入 reviewPresentation.panels.&lt;kind&gt;[],把每个明细改写为“加粗短摘要 + 一句话说明”,短摘要优先使用 新增 / 修复 / 优化 / 调整 / 移除。&quot;
1109
+ }
1110
+ ]
1111
+ },
1112
+ &quot;presentationFeedback&quot;: [],
1113
+ &quot;exportedAt&quot;: &quot;2026-06-05T00:44:22.422Z&quot;
1114
+ }" title="openprd review . --mark confirmed --version &#39;v0003&#39; --digest &#39;f1b18bc47cbd76f784b7682483eafa24eb02230e23189dad29a2202b61544918&#39; --work-unit &#39;wu-20260602122244-78656aaf&#39;">
1115
+ 认可并继续
1116
+ </button>
1117
+ </div>
1118
+ </nav>
1119
+
1120
+ <script>
1121
+ async function copyReviewText(text) {
1122
+ try {
1123
+ await navigator.clipboard.writeText(text);
1124
+ } catch (error) {
1125
+ const textarea = document.createElement('textarea');
1126
+ textarea.value = text;
1127
+ textarea.setAttribute('readonly', '');
1128
+ textarea.style.position = 'fixed';
1129
+ textarea.style.left = '-9999px';
1130
+ document.body.appendChild(textarea);
1131
+ textarea.select();
1132
+ document.execCommand('copy');
1133
+ textarea.remove();
1134
+ }
1135
+ }
1136
+ function flashCopied(button) {
1137
+ const old = button.innerHTML;
1138
+ button.textContent = '已复制';
1139
+ setTimeout(() => { button.innerHTML = old; }, 1200);
1140
+ }
1141
+ document.querySelectorAll('[data-copy-value]').forEach((button) => {
1142
+ button.addEventListener('click', async () => {
1143
+ await copyReviewText(button.dataset.copyValue || '');
1144
+ flashCopied(button);
1145
+ });
1146
+ });
1147
+ </script>
1148
+ </main>
1149
+ </body>
1150
+ </html>