@openprd/cli 0.1.10 → 0.1.18

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 (146) hide show
  1. package/.openprd/benchmarks/index.md +17 -15
  2. package/.openprd/benchmarks/sources.yaml +53 -1
  3. package/.openprd/changes/adaptive-project-framing/.openprd.yaml +2 -0
  4. package/.openprd/changes/adaptive-project-framing/design.md +47 -0
  5. package/.openprd/changes/adaptive-project-framing/proposal.md +35 -0
  6. package/.openprd/changes/adaptive-project-framing/specs/agent-requirements/spec.md +16 -0
  7. package/.openprd/changes/adaptive-project-framing/task-events.jsonl +20 -0
  8. package/.openprd/changes/adaptive-project-framing/tasks.md +340 -0
  9. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/.openprd.yaml +2 -0
  10. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/design.md +34 -0
  11. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/proposal.md +23 -0
  12. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/specs/agent-requirements/spec.md +16 -0
  13. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/task-events.jsonl +14 -0
  14. package/.openprd/changes/docs-anti-pollution-and-design-direction-review/tasks.md +238 -0
  15. package/.openprd/changes/loop-isolated-worktree-commit/.openprd.yaml +2 -0
  16. package/.openprd/changes/loop-isolated-worktree-commit/design.md +53 -0
  17. package/.openprd/changes/loop-isolated-worktree-commit/proposal.md +38 -0
  18. package/.openprd/changes/loop-isolated-worktree-commit/specs/agent-requirements/spec.md +16 -0
  19. package/.openprd/changes/loop-isolated-worktree-commit/task-events.jsonl +22 -0
  20. package/.openprd/changes/loop-isolated-worktree-commit/tasks.md +357 -0
  21. package/.openprd/changes/openprd/.openprd.yaml +2 -0
  22. package/.openprd/changes/openprd/design.md +46 -0
  23. package/.openprd/changes/openprd/proposal.md +36 -0
  24. package/.openprd/changes/openprd/specs/agent-requirements/spec.md +16 -0
  25. package/.openprd/changes/openprd/task-events.jsonl +23 -0
  26. package/.openprd/changes/openprd/tasks.md +242 -0
  27. package/.openprd/changes/pm-human-in-the-loop/.openprd.yaml +2 -0
  28. package/.openprd/changes/pm-human-in-the-loop/design.md +38 -0
  29. package/.openprd/changes/pm-human-in-the-loop/proposal.md +29 -0
  30. package/.openprd/changes/pm-human-in-the-loop/specs/agent-requirements/spec.md +16 -0
  31. package/.openprd/changes/pm-human-in-the-loop/task-events.jsonl +18 -0
  32. package/.openprd/changes/pm-human-in-the-loop/tasks.md +306 -0
  33. package/.openprd/changes/test-strategy-router/.openprd.yaml +2 -0
  34. package/.openprd/changes/test-strategy-router/design.md +65 -0
  35. package/.openprd/changes/test-strategy-router/proposal.md +45 -0
  36. package/.openprd/changes/test-strategy-router/specs/agent-requirements/spec.md +16 -0
  37. package/.openprd/changes/test-strategy-router/task-events.jsonl +1 -0
  38. package/.openprd/changes/test-strategy-router/tasks.md +132 -0
  39. package/.openprd/changes/verify-boundaries-and-historical-refresh/.openprd.yaml +2 -0
  40. package/.openprd/changes/verify-boundaries-and-historical-refresh/design.md +28 -0
  41. package/.openprd/changes/verify-boundaries-and-historical-refresh/proposal.md +23 -0
  42. package/.openprd/changes/verify-boundaries-and-historical-refresh/specs/agent-requirements/spec.md +16 -0
  43. package/.openprd/changes/verify-boundaries-and-historical-refresh/task-events.jsonl +11 -0
  44. package/.openprd/changes/verify-boundaries-and-historical-refresh/tasks.md +66 -0
  45. package/.openprd/changes/vibe-coding-dev-check/.openprd.yaml +2 -0
  46. package/.openprd/changes/vibe-coding-dev-check/design.md +37 -0
  47. package/.openprd/changes/vibe-coding-dev-check/proposal.md +28 -0
  48. package/.openprd/changes/vibe-coding-dev-check/specs/agent-requirements/spec.md +16 -0
  49. package/.openprd/changes/vibe-coding-dev-check/task-events.jsonl +18 -0
  50. package/.openprd/changes/vibe-coding-dev-check/tasks.md +306 -0
  51. package/.openprd/design/README.md +11 -6
  52. package/.openprd/design/README_EN.md +4 -1
  53. package/.openprd/design/active/asset-spec.md +6 -0
  54. package/.openprd/design/active/direction-plan.md +5 -5
  55. package/.openprd/design/active/selected-direction.md +2 -0
  56. package/.openprd/design/anti-slop.md +26 -1
  57. package/.openprd/design/assets/surface-presets.md +6 -0
  58. package/.openprd/design/checklists/ui-quality-gate.md +7 -0
  59. package/.openprd/design/lenses/frontend-lenses.md +28 -0
  60. package/.openprd/design/recipes/content-experience.md +8 -1
  61. package/.openprd/design/recipes/operational-tool.md +7 -0
  62. package/.openprd/design/recipes/product-launch.md +8 -1
  63. package/.openprd/design/templates/README.md +6 -3
  64. package/.openprd/design/templates/README_EN.md +6 -3
  65. package/.openprd/design/templates/ops-dashboard.html +8 -1
  66. package/.openprd/design/templates/product-launch.html +2 -1
  67. package/.openprd/design/themes/theme-catalog.json +23 -5
  68. package/.openprd/engagements/active/prd.md +103 -100
  69. package/.openprd/schema/prd.schema.yaml +15 -0
  70. package/.openprd/standards/config.json +7 -1
  71. package/.openprd/templates/base/intake.md +13 -0
  72. package/.openprd/templates/base/prd.md +15 -0
  73. package/AGENTS.md +14 -4
  74. package/README.md +107 -14
  75. package/README_EN.md +131 -13
  76. package/package.json +1 -1
  77. package/scripts/dev-check-wrapup-copy.mjs +46 -21
  78. package/skills/openprd-benchmark-router/SKILL.md +2 -1
  79. package/skills/openprd-diagram-review/SKILL.md +27 -2
  80. package/skills/openprd-diagram-review/references/explanation-svg-patterns.md +131 -0
  81. package/skills/openprd-discovery-loop/SKILL.md +2 -2
  82. package/skills/openprd-frontend-design/SKILL.md +44 -20
  83. package/skills/openprd-frontend-design/references/design-asset-contract.md +6 -0
  84. package/skills/openprd-frontend-design/references/direction-engine.md +29 -4
  85. package/skills/openprd-harness/SKILL.md +22 -16
  86. package/skills/openprd-quality/SKILL.md +10 -8
  87. package/skills/openprd-requirement-intake/SKILL.md +5 -3
  88. package/skills/openprd-requirement-intake/references/prd-template-lenses.md +2 -2
  89. package/skills/openprd-requirement-intake/references/startup-validation-lens.md +98 -13
  90. package/skills/openprd-router/SKILL.md +2 -1
  91. package/skills/openprd-shared/SKILL.md +27 -17
  92. package/skills/openprd-standards/SKILL.md +4 -2
  93. package/src/agent-canonical-content.js +808 -0
  94. package/src/agent-integration.js +259 -778
  95. package/src/brainstorm-artifacts.js +156 -8
  96. package/src/brainstorm-presentation.js +14 -4
  97. package/src/brainstorm.js +165 -2
  98. package/src/canvas-app.html.js +2910 -0
  99. package/src/canvas-i18n.js +274 -0
  100. package/src/canvas-workspace.js +2271 -0
  101. package/src/cli/args.js +72 -4
  102. package/src/cli/basic-print.js +3 -0
  103. package/src/cli/canvas-print.js +106 -0
  104. package/src/cli/doctor-print.js +20 -0
  105. package/src/cli/print.js +2 -0
  106. package/src/cli/quality-commands.js +222 -0
  107. package/src/cli/quality-print.js +37 -5
  108. package/src/cli/run-print.js +5 -0
  109. package/src/cli/workflow-print.js +3 -0
  110. package/src/codex-app-server-relay.js +251 -0
  111. package/src/codex-hook-runner-template.mjs +963 -65
  112. package/src/design-starter-support.js +2 -2
  113. package/src/design-starter.js +39 -3
  114. package/src/dev-standards.js +125 -10
  115. package/src/diagram-core.js +390 -171
  116. package/src/discovery.js +2 -8
  117. package/src/docs-compact.js +125 -0
  118. package/src/execution-strategy.js +1 -1
  119. package/src/fleet.js +9 -3
  120. package/src/guide.js +227 -0
  121. package/src/html-artifacts.js +825 -51
  122. package/src/knowledge.js +101 -20
  123. package/src/language-policy.js +63 -3
  124. package/src/learning-review.js +1 -1
  125. package/src/loop.js +1 -1
  126. package/src/openprd.js +68 -131
  127. package/src/openspec/change-validate.js +2 -2
  128. package/src/openspec/constants.js +6 -7
  129. package/src/openspec/execute.js +2 -2
  130. package/src/openspec/generate.js +318 -102
  131. package/src/openspec/migration.js +168 -0
  132. package/src/openspec/paths.js +1 -22
  133. package/src/prd-core.js +102 -3
  134. package/src/quality-html-artifact.js +30 -5
  135. package/src/quality-visual-review.js +257 -14
  136. package/src/quality.js +66 -18
  137. package/src/review-presentation.js +60 -0
  138. package/src/run-harness.js +41 -3
  139. package/src/session-evidence.js +363 -0
  140. package/src/standards.js +64 -0
  141. package/src/test-strategy.js +7 -4
  142. package/src/visual-compare-centering.js +622 -0
  143. package/src/visual-compare-core.js +1123 -0
  144. package/src/visual-compare.js +620 -698
  145. package/src/workspace-core.js +132 -4
  146. package/src/workspace-workflow.js +172 -10
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Core purpose
4
+ * Relay an OpenPrd Canvas handoff into a Codex Desktop thread through the
5
+ * local Codex app-server protocol.
6
+ *
7
+ * Inputs
8
+ * Receives a payload JSON path. The payload contains the target thread ID,
9
+ * JSON-RPC input items, status path, log path, cwd, and optional timeout.
10
+ *
11
+ * Outputs
12
+ * Writes a small status JSON file as the turn is queued, started, completed,
13
+ * failed, or timed out. This lets the canvas UI return quickly while the Codex
14
+ * turn continues in the background.
15
+ *
16
+ * Positioning
17
+ * This is intentionally a thin transport worker. Image generation still belongs
18
+ * to Codex native tools after the message reaches the thread.
19
+ *
20
+ * Maintenance rules
21
+ * Keep the payload schema explicit and do not expose arbitrary app-server
22
+ * methods through the canvas HTTP API.
23
+ */
24
+ import fs from 'node:fs/promises';
25
+ import path from 'node:path';
26
+ import { spawn } from 'node:child_process';
27
+
28
+ const payloadPath = process.argv[2];
29
+
30
+ if (!payloadPath) {
31
+ console.error('Usage: codex-app-server-relay <payload.json>');
32
+ process.exit(2);
33
+ }
34
+
35
+ const payload = JSON.parse(await fs.readFile(payloadPath, 'utf8'));
36
+ const statusPath = payload.statusPath;
37
+ const logPath = payload.logPath;
38
+ const timeoutMs = Number.isFinite(Number(payload.timeoutMs)) ? Number(payload.timeoutMs) : 20 * 60 * 1000;
39
+ const codexBin = payload.codexBin || 'codex';
40
+
41
+ let finalized = false;
42
+ let started = false;
43
+ let stderrTail = '';
44
+ let turnSummary = null;
45
+ let resolvedThread = null;
46
+
47
+ async function appendLog(line) {
48
+ if (!logPath) {
49
+ return;
50
+ }
51
+ await fs.appendFile(logPath, `${new Date().toISOString()} ${line}\n`, 'utf8').catch(() => {});
52
+ }
53
+
54
+ async function writeStatus(status, extra = {}) {
55
+ if (!statusPath) {
56
+ return;
57
+ }
58
+ await fs.mkdir(path.dirname(statusPath), { recursive: true });
59
+ await fs.writeFile(statusPath, JSON.stringify({
60
+ schema: 'openprd.codex.app-server-relay.status.v1',
61
+ status,
62
+ updatedAt: new Date().toISOString(),
63
+ payloadPath,
64
+ handoffOperationId: payload.handoffOperationId ?? null,
65
+ threadId: payload.threadId ?? null,
66
+ threadTitle: payload.threadTitle ?? null,
67
+ resolvedThread,
68
+ turn: turnSummary,
69
+ stderrTail: stderrTail || undefined,
70
+ ...extra,
71
+ }, null, 2), 'utf8');
72
+ }
73
+
74
+ function sendRpc(child, id, method, params = {}) {
75
+ child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id, method, params })}\n`);
76
+ }
77
+
78
+ async function finalize(status, extra = {}, child = null) {
79
+ if (finalized) {
80
+ return;
81
+ }
82
+ finalized = true;
83
+ await appendLog(`finalize ${status}`);
84
+ await writeStatus(status, extra);
85
+ if (child && !child.killed) {
86
+ child.kill('SIGTERM');
87
+ }
88
+ }
89
+
90
+ await writeStatus('starting');
91
+ await appendLog(`starting ${codexBin} app-server relay`);
92
+
93
+ const child = spawn(codexBin, ['app-server', '--listen', 'stdio://'], {
94
+ cwd: payload.cwd || process.cwd(),
95
+ stdio: ['pipe', 'pipe', 'pipe'],
96
+ });
97
+
98
+ const timer = setTimeout(() => {
99
+ finalize(started ? 'timeout-after-start' : 'timeout-before-start', {
100
+ timeoutMs,
101
+ }, child).catch(() => {});
102
+ }, timeoutMs);
103
+
104
+ child.once('error', (error) => {
105
+ clearTimeout(timer);
106
+ finalize('failed', {
107
+ error: error.message || String(error),
108
+ }).catch(() => {});
109
+ });
110
+
111
+ child.once('close', (code, signal) => {
112
+ clearTimeout(timer);
113
+ if (!finalized) {
114
+ finalize(started ? 'closed-after-start' : 'failed', {
115
+ exitCode: code,
116
+ signal,
117
+ }).catch(() => {});
118
+ }
119
+ });
120
+
121
+ child.stderr.on('data', (chunk) => {
122
+ stderrTail = `${stderrTail}${chunk.toString('utf8')}`.slice(-6000);
123
+ appendLog(`stderr ${chunk.toString('utf8').trim()}`).catch(() => {});
124
+ });
125
+
126
+ let stdoutBuffer = '';
127
+ child.stdout.on('data', (chunk) => {
128
+ stdoutBuffer += chunk.toString('utf8');
129
+ const lines = stdoutBuffer.split(/\r?\n/);
130
+ stdoutBuffer = lines.pop() || '';
131
+ for (const line of lines) {
132
+ const trimmed = line.trim();
133
+ if (!trimmed) {
134
+ continue;
135
+ }
136
+ let message = null;
137
+ try {
138
+ message = JSON.parse(trimmed);
139
+ } catch (error) {
140
+ appendLog(`unparsed ${trimmed}`).catch(() => {});
141
+ continue;
142
+ }
143
+ handleRpcMessage(message).catch((error) => {
144
+ finalize('failed', {
145
+ error: error.message || String(error),
146
+ }, child).catch(() => {});
147
+ });
148
+ }
149
+ });
150
+
151
+ async function handleRpcMessage(message) {
152
+ if (message.id === 1) {
153
+ if (message.error) {
154
+ await finalize('failed', {
155
+ phase: 'initialize',
156
+ error: message.error,
157
+ }, child);
158
+ return;
159
+ }
160
+ sendRpc(child, 2, 'thread/resume', {
161
+ threadId: payload.threadId,
162
+ excludeTurns: true,
163
+ });
164
+ await writeStatus('resuming');
165
+ return;
166
+ }
167
+
168
+ if (message.id === 2) {
169
+ if (message.error) {
170
+ await finalize('failed', {
171
+ phase: 'thread/resume',
172
+ error: message.error,
173
+ }, child);
174
+ return;
175
+ }
176
+ const thread = message.result?.thread ?? null;
177
+ resolvedThread = thread ? {
178
+ id: thread.id ?? null,
179
+ name: thread.name ?? null,
180
+ cwd: thread.cwd ?? null,
181
+ status: thread.status ?? null,
182
+ path: thread.path ?? null,
183
+ source: thread.source ?? null,
184
+ cliVersion: thread.cliVersion ?? null,
185
+ } : null;
186
+ sendRpc(child, 3, 'turn/start', {
187
+ threadId: resolvedThread?.id || payload.threadId,
188
+ input: Array.isArray(payload.input) ? payload.input : [],
189
+ });
190
+ await writeStatus('connecting', {
191
+ resume: {
192
+ model: message.result?.model ?? null,
193
+ modelProvider: message.result?.modelProvider ?? null,
194
+ },
195
+ });
196
+ return;
197
+ }
198
+
199
+ if (message.id === 3) {
200
+ if (message.error) {
201
+ await finalize('failed', {
202
+ phase: 'turn/start',
203
+ error: message.error,
204
+ }, child);
205
+ return;
206
+ }
207
+ started = true;
208
+ turnSummary = message.result?.turn ?? message.result ?? null;
209
+ await writeStatus('started', {
210
+ result: message.result ?? null,
211
+ });
212
+ return;
213
+ }
214
+
215
+ if (message.method === 'turn/started') {
216
+ started = true;
217
+ turnSummary = message.params?.turn ?? message.params ?? turnSummary;
218
+ await writeStatus('started', {
219
+ notification: message.params ?? null,
220
+ });
221
+ return;
222
+ }
223
+
224
+ if (message.method === 'turn/completed' || message.method === 'turn/failed' || message.method === 'turn/cancelled') {
225
+ turnSummary = message.params?.turn ?? message.params ?? turnSummary;
226
+ await finalize(message.method === 'turn/completed' ? 'completed' : 'failed', {
227
+ notification: message.params ?? null,
228
+ }, child);
229
+ return;
230
+ }
231
+
232
+ if (message.method) {
233
+ await appendLog(`notification ${message.method}`);
234
+ }
235
+ }
236
+
237
+ sendRpc(child, 1, 'initialize', {
238
+ clientInfo: {
239
+ name: 'openprd-canvas',
240
+ version: '0.0.0',
241
+ },
242
+ capabilities: {
243
+ experimentalApi: true,
244
+ optOutNotificationMethods: [
245
+ 'mcpServer/startupStatus/updated',
246
+ 'skills/changed',
247
+ 'account/rateLimits/updated',
248
+ 'app/list/updated',
249
+ ],
250
+ },
251
+ });