@chllming/wave-orchestration 0.5.1

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 (68) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +549 -0
  3. package/docs/agents/wave-deploy-verifier-role.md +34 -0
  4. package/docs/agents/wave-documentation-role.md +30 -0
  5. package/docs/agents/wave-evaluator-role.md +43 -0
  6. package/docs/agents/wave-infra-role.md +34 -0
  7. package/docs/agents/wave-integration-role.md +32 -0
  8. package/docs/agents/wave-launcher-role.md +37 -0
  9. package/docs/context7/bundles.json +91 -0
  10. package/docs/plans/component-cutover-matrix.json +112 -0
  11. package/docs/plans/component-cutover-matrix.md +49 -0
  12. package/docs/plans/context7-wave-orchestrator.md +130 -0
  13. package/docs/plans/current-state.md +44 -0
  14. package/docs/plans/master-plan.md +16 -0
  15. package/docs/plans/migration.md +23 -0
  16. package/docs/plans/wave-orchestrator.md +254 -0
  17. package/docs/plans/waves/wave-0.md +165 -0
  18. package/docs/reference/github-packages-setup.md +52 -0
  19. package/docs/reference/migration-0.2-to-0.5.md +622 -0
  20. package/docs/reference/npmjs-trusted-publishing.md +55 -0
  21. package/docs/reference/repository-guidance.md +18 -0
  22. package/docs/reference/runtime-config/README.md +85 -0
  23. package/docs/reference/runtime-config/claude.md +105 -0
  24. package/docs/reference/runtime-config/codex.md +81 -0
  25. package/docs/reference/runtime-config/opencode.md +93 -0
  26. package/docs/research/agent-context-sources.md +57 -0
  27. package/docs/roadmap.md +626 -0
  28. package/package.json +53 -0
  29. package/releases/manifest.json +101 -0
  30. package/scripts/context7-api-check.sh +21 -0
  31. package/scripts/context7-export-env.sh +52 -0
  32. package/scripts/research/agent-context-archive.mjs +472 -0
  33. package/scripts/research/generate-agent-context-indexes.mjs +85 -0
  34. package/scripts/research/import-agent-context-archive.mjs +793 -0
  35. package/scripts/research/manifests/harness-and-blackboard-2026-03-21.mjs +201 -0
  36. package/scripts/wave-autonomous.mjs +13 -0
  37. package/scripts/wave-cli-bootstrap.mjs +27 -0
  38. package/scripts/wave-dashboard.mjs +11 -0
  39. package/scripts/wave-human-feedback.mjs +11 -0
  40. package/scripts/wave-launcher.mjs +11 -0
  41. package/scripts/wave-local-executor.mjs +13 -0
  42. package/scripts/wave-orchestrator/agent-state.mjs +416 -0
  43. package/scripts/wave-orchestrator/autonomous.mjs +367 -0
  44. package/scripts/wave-orchestrator/clarification-triage.mjs +605 -0
  45. package/scripts/wave-orchestrator/config.mjs +848 -0
  46. package/scripts/wave-orchestrator/context7.mjs +464 -0
  47. package/scripts/wave-orchestrator/coord-cli.mjs +286 -0
  48. package/scripts/wave-orchestrator/coordination-store.mjs +987 -0
  49. package/scripts/wave-orchestrator/coordination.mjs +768 -0
  50. package/scripts/wave-orchestrator/dashboard-renderer.mjs +254 -0
  51. package/scripts/wave-orchestrator/dashboard-state.mjs +473 -0
  52. package/scripts/wave-orchestrator/dep-cli.mjs +219 -0
  53. package/scripts/wave-orchestrator/docs-queue.mjs +75 -0
  54. package/scripts/wave-orchestrator/executors.mjs +385 -0
  55. package/scripts/wave-orchestrator/feedback.mjs +372 -0
  56. package/scripts/wave-orchestrator/install.mjs +540 -0
  57. package/scripts/wave-orchestrator/launcher.mjs +3879 -0
  58. package/scripts/wave-orchestrator/ledger.mjs +332 -0
  59. package/scripts/wave-orchestrator/local-executor.mjs +263 -0
  60. package/scripts/wave-orchestrator/replay.mjs +246 -0
  61. package/scripts/wave-orchestrator/roots.mjs +10 -0
  62. package/scripts/wave-orchestrator/routing-state.mjs +542 -0
  63. package/scripts/wave-orchestrator/shared.mjs +405 -0
  64. package/scripts/wave-orchestrator/terminals.mjs +209 -0
  65. package/scripts/wave-orchestrator/traces.mjs +1094 -0
  66. package/scripts/wave-orchestrator/wave-files.mjs +1923 -0
  67. package/scripts/wave.mjs +103 -0
  68. package/wave.config.json +115 -0
@@ -0,0 +1,332 @@
1
+ import {
2
+ DEFAULT_DOCUMENTATION_AGENT_ID,
3
+ DEFAULT_EVALUATOR_AGENT_ID,
4
+ DEFAULT_INTEGRATION_AGENT_ID,
5
+ } from "./config.mjs";
6
+ import {
7
+ validateDocumentationClosureSummary,
8
+ validateEvaluatorSummary,
9
+ validateImplementationSummary,
10
+ } from "./agent-state.mjs";
11
+ import { openClarificationLinkedRequests } from "./coordination-store.mjs";
12
+ import { buildHelperTasks } from "./routing-state.mjs";
13
+ import { readJsonOrNull, toIsoTimestamp, writeJsonAtomic } from "./shared.mjs";
14
+
15
+ function taskId(prefix, suffix) {
16
+ return `${prefix}:${suffix}`;
17
+ }
18
+
19
+ function taskStateFromValidation(validation) {
20
+ if (validation?.ok) {
21
+ return "done";
22
+ }
23
+ return validation ? "blocked" : "planned";
24
+ }
25
+
26
+ function openHighPriorityBlockers(state) {
27
+ return (state?.blockers || []).filter(
28
+ (record) =>
29
+ ["open", "acknowledged", "in_progress"].includes(record.status) &&
30
+ ["high", "urgent"].includes(record.priority),
31
+ );
32
+ }
33
+
34
+ function openClarifications(state) {
35
+ return (state?.clarifications || []).filter((record) =>
36
+ ["open", "acknowledged", "in_progress"].includes(record.status),
37
+ );
38
+ }
39
+
40
+ export function buildSeedWaveLedger({
41
+ lane,
42
+ wave,
43
+ evaluatorAgentId = DEFAULT_EVALUATOR_AGENT_ID,
44
+ integrationAgentId = DEFAULT_INTEGRATION_AGENT_ID,
45
+ documentationAgentId = DEFAULT_DOCUMENTATION_AGENT_ID,
46
+ }) {
47
+ const tasks = [];
48
+ for (const agent of wave.agents) {
49
+ const kind =
50
+ agent.agentId === evaluatorAgentId
51
+ ? "evaluator"
52
+ : agent.agentId === integrationAgentId
53
+ ? "integration"
54
+ : agent.agentId === documentationAgentId
55
+ ? "documentation"
56
+ : "implementation";
57
+ tasks.push({
58
+ id: taskId(kind, agent.agentId),
59
+ title: `${agent.agentId}: ${agent.title}`,
60
+ owner: agent.agentId,
61
+ kind,
62
+ dependsOn: [],
63
+ state: "planned",
64
+ proofState: "pending",
65
+ docState: "pending",
66
+ infraState: "n/a",
67
+ priority:
68
+ kind === "implementation" ? "normal" : kind === "integration" ? "high" : "high",
69
+ artifactRefs: agent.ownedPaths || [],
70
+ runtime: agent.executorResolved
71
+ ? {
72
+ executorId: agent.executorResolved.id,
73
+ role: agent.executorResolved.role,
74
+ profile: agent.executorResolved.profile,
75
+ selectedBy: agent.executorResolved.selectedBy,
76
+ fallbacks: agent.executorResolved.fallbacks || [],
77
+ fallbackUsed: agent.executorResolved.fallbackUsed === true,
78
+ }
79
+ : null,
80
+ });
81
+ }
82
+ for (const promotion of wave.componentPromotions || []) {
83
+ tasks.push({
84
+ id: taskId("component", promotion.componentId),
85
+ title: `Promote ${promotion.componentId} to ${promotion.targetLevel}`,
86
+ owner: null,
87
+ kind: "component",
88
+ dependsOn: [],
89
+ state: "planned",
90
+ proofState: "pending",
91
+ docState: "pending",
92
+ infraState: "n/a",
93
+ priority: "high",
94
+ artifactRefs: [promotion.componentId],
95
+ runtime: null,
96
+ });
97
+ }
98
+ return {
99
+ wave: wave.wave,
100
+ lane,
101
+ attempt: 0,
102
+ phase: "planned",
103
+ tasks,
104
+ blockers: [],
105
+ openRequests: [],
106
+ openClarifications: [],
107
+ clarificationLinkedRequests: [],
108
+ humanFeedback: [],
109
+ humanEscalations: [],
110
+ integrationState: "pending",
111
+ docClosureState: "pending",
112
+ evaluatorState: "pending",
113
+ updatedAt: toIsoTimestamp(),
114
+ };
115
+ }
116
+
117
+ function derivePhase({
118
+ tasks,
119
+ integrationSummary,
120
+ docValidation,
121
+ evaluatorValidation,
122
+ state,
123
+ dependencySnapshot = null,
124
+ }) {
125
+ const blockers = openHighPriorityBlockers(state);
126
+ if (blockers.length > 0) {
127
+ return "blocked";
128
+ }
129
+ if (
130
+ openClarifications(state).length > 0 ||
131
+ openClarificationLinkedRequests(state).length > 0
132
+ ) {
133
+ return "clarifying";
134
+ }
135
+ const dependencyBlockers =
136
+ (dependencySnapshot?.requiredInbound || []).length + (dependencySnapshot?.requiredOutbound || []).length;
137
+ if (dependencyBlockers > 0) {
138
+ return "blocked";
139
+ }
140
+ const blockingHelperTasks = tasks.filter((task) =>
141
+ ["helper", "dependency", "dependency-outbound"].includes(task.kind) &&
142
+ !["done", "closed", "resolved"].includes(task.state),
143
+ );
144
+ if (blockingHelperTasks.length > 0) {
145
+ return blockingHelperTasks.some((task) => task.state === "blocked") ? "blocked" : "running";
146
+ }
147
+ const implementationTasks = tasks.filter((task) => task.kind === "implementation");
148
+ const allImplementationDone = implementationTasks.every((task) => task.state === "done");
149
+ if (!allImplementationDone) {
150
+ return "running";
151
+ }
152
+ if (integrationSummary?.recommendation !== "ready-for-doc-closure") {
153
+ return "integrating";
154
+ }
155
+ if (!docValidation?.ok) {
156
+ return "docs-closure";
157
+ }
158
+ if (!evaluatorValidation?.ok) {
159
+ return "evaluator-closure";
160
+ }
161
+ return "completed";
162
+ }
163
+
164
+ export function deriveWaveLedger({
165
+ lane,
166
+ wave,
167
+ summariesByAgentId = {},
168
+ coordinationState = null,
169
+ integrationSummary = null,
170
+ docsQueue = null,
171
+ attempt = 0,
172
+ evaluatorAgentId = DEFAULT_EVALUATOR_AGENT_ID,
173
+ integrationAgentId = DEFAULT_INTEGRATION_AGENT_ID,
174
+ documentationAgentId = DEFAULT_DOCUMENTATION_AGENT_ID,
175
+ capabilityAssignments = [],
176
+ dependencySnapshot = null,
177
+ }) {
178
+ const seed = buildSeedWaveLedger({
179
+ lane,
180
+ wave,
181
+ evaluatorAgentId,
182
+ integrationAgentId,
183
+ documentationAgentId,
184
+ });
185
+ const primaryTasks = seed.tasks.map((task) => {
186
+ const agent = wave.agents.find((item) => item.agentId === task.owner);
187
+ const summary = task.owner ? summariesByAgentId[task.owner] : null;
188
+ if (task.kind === "implementation" && agent) {
189
+ const validation = validateImplementationSummary(agent, summary);
190
+ return {
191
+ ...task,
192
+ state: taskStateFromValidation(validation),
193
+ proofState: validation.ok ? "met" : "gap",
194
+ docState: summary?.docDelta?.state || "pending",
195
+ };
196
+ }
197
+ if (task.kind === "documentation" && agent) {
198
+ const validation = validateDocumentationClosureSummary(agent, summary);
199
+ return {
200
+ ...task,
201
+ state: taskStateFromValidation(validation),
202
+ proofState: "n/a",
203
+ docState: validation.ok ? "closed" : "open",
204
+ };
205
+ }
206
+ if (task.kind === "evaluator" && agent) {
207
+ const validation = validateEvaluatorSummary(agent, summary);
208
+ return {
209
+ ...task,
210
+ state: taskStateFromValidation(validation),
211
+ proofState: validation.ok ? "met" : "gap",
212
+ docState: "n/a",
213
+ };
214
+ }
215
+ if (task.kind === "integration") {
216
+ const ready = integrationSummary?.recommendation === "ready-for-doc-closure";
217
+ return {
218
+ ...task,
219
+ state: ready ? "done" : integrationSummary ? "blocked" : "planned",
220
+ proofState: ready ? "met" : "pending",
221
+ docState: "n/a",
222
+ };
223
+ }
224
+ if (task.kind === "component") {
225
+ const owners = wave.agents.filter((agent) =>
226
+ Array.isArray(agent.components) && agent.components.includes(task.artifactRefs[0]),
227
+ );
228
+ const complete = owners.length > 0 && owners.every((agent) => {
229
+ const summary = summariesByAgentId[agent.agentId];
230
+ return Array.isArray(summary?.components)
231
+ ? summary.components.some(
232
+ (component) =>
233
+ component.componentId === task.artifactRefs[0] && component.state === "met",
234
+ )
235
+ : false;
236
+ });
237
+ return {
238
+ ...task,
239
+ state: complete ? "done" : "blocked",
240
+ proofState: complete ? "met" : "gap",
241
+ docState:
242
+ Array.isArray(docsQueue?.items) && docsQueue.items.some((item) => item.kind === "component-matrix")
243
+ ? "pending"
244
+ : "n/a",
245
+ };
246
+ }
247
+ return task;
248
+ });
249
+ const helperTasks = buildHelperTasks({
250
+ wave,
251
+ assignments: capabilityAssignments,
252
+ dependencySnapshot,
253
+ docsQueue,
254
+ documentationAgentId,
255
+ });
256
+ const tasks = [...primaryTasks, ...helperTasks];
257
+ const docAgent = wave.agents.find((agent) => agent.agentId === documentationAgentId);
258
+ const evaluatorAgent = wave.agents.find((agent) => agent.agentId === evaluatorAgentId);
259
+ const docValidation = docAgent
260
+ ? validateDocumentationClosureSummary(docAgent, summariesByAgentId[documentationAgentId])
261
+ : { ok: true };
262
+ const evaluatorValidation = evaluatorAgent
263
+ ? validateEvaluatorSummary(evaluatorAgent, summariesByAgentId[evaluatorAgentId])
264
+ : { ok: true };
265
+ return {
266
+ wave: wave.wave,
267
+ lane,
268
+ attempt,
269
+ phase: derivePhase({
270
+ tasks,
271
+ integrationSummary,
272
+ docValidation,
273
+ evaluatorValidation,
274
+ state: coordinationState,
275
+ dependencySnapshot,
276
+ }),
277
+ tasks,
278
+ blockers: (coordinationState?.blockers || []).map((record) => record.id),
279
+ openClarifications: openClarifications(coordinationState).map((record) => record.id),
280
+ clarificationLinkedRequests: openClarificationLinkedRequests(coordinationState).map(
281
+ (record) => record.id,
282
+ ),
283
+ openRequests: (coordinationState?.requests || [])
284
+ .filter((record) => ["open", "acknowledged", "in_progress"].includes(record.status))
285
+ .map((record) => record.id),
286
+ capabilityAssignments: (capabilityAssignments || []).map((assignment) => ({
287
+ id: assignment.id,
288
+ requestId: assignment.requestId,
289
+ assignedAgentId: assignment.assignedAgentId,
290
+ target: assignment.target,
291
+ targetType: assignment.targetType,
292
+ capability: assignment.capability,
293
+ blocking: assignment.blocking,
294
+ assignmentReason: assignment.assignmentReason,
295
+ state: assignment.state,
296
+ })),
297
+ dependencySnapshot: dependencySnapshot
298
+ ? {
299
+ openInbound: dependencySnapshot.openInbound.map((record) => record.id),
300
+ openOutbound: dependencySnapshot.openOutbound.map((record) => record.id),
301
+ requiredInbound: dependencySnapshot.requiredInbound.map((record) => record.id),
302
+ requiredOutbound: dependencySnapshot.requiredOutbound.map((record) => record.id),
303
+ unresolvedInboundAssignments: dependencySnapshot.unresolvedInboundAssignments.map(
304
+ (record) => record.id,
305
+ ),
306
+ }
307
+ : null,
308
+ humanFeedback: [
309
+ ...(coordinationState?.humanFeedback || [])
310
+ .filter((record) => ["open", "acknowledged", "in_progress"].includes(record.status))
311
+ .map((record) => record.id),
312
+ ...(coordinationState?.humanEscalations || [])
313
+ .filter((record) => ["open", "acknowledged", "in_progress"].includes(record.status))
314
+ .map((record) => record.id),
315
+ ],
316
+ humanEscalations: (coordinationState?.humanEscalations || [])
317
+ .filter((record) => ["open", "acknowledged", "in_progress"].includes(record.status))
318
+ .map((record) => record.id),
319
+ integrationState: integrationSummary?.recommendation || "pending",
320
+ docClosureState: docValidation.ok ? "closed" : "open",
321
+ evaluatorState: evaluatorValidation.ok ? "pass" : "open",
322
+ updatedAt: toIsoTimestamp(),
323
+ };
324
+ }
325
+
326
+ export function writeWaveLedger(filePath, payload) {
327
+ writeJsonAtomic(filePath, payload);
328
+ }
329
+
330
+ export function readWaveLedger(filePath) {
331
+ return readJsonOrNull(filePath);
332
+ }
@@ -0,0 +1,263 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { REPO_ROOT, ensureDirectory } from "./shared.mjs";
4
+
5
+ function titleFromPath(relPath) {
6
+ return path
7
+ .basename(relPath, path.extname(relPath))
8
+ .replace(/[-_]+/g, " ")
9
+ .replace(/\b\w/g, (char) => char.toUpperCase());
10
+ }
11
+
12
+ function extractAssignedPrompt(raw) {
13
+ const match = raw.match(/Assigned implementation prompt:\s*```[a-zA-Z0-9_-]*\n([\s\S]*?)\n```/);
14
+ return match ? match[1].trim() : raw;
15
+ }
16
+
17
+ function extractAgentId(rawPrompt) {
18
+ const match = String(rawPrompt || "").match(
19
+ /You are the Wave executor running Wave \d+ \/ Agent ([A-Za-z0-9.]+):/,
20
+ );
21
+ return match ? match[1].trim() : "";
22
+ }
23
+
24
+ function extractRoleAgentIds(rawPrompt) {
25
+ const evaluatorMatch = String(rawPrompt || "").match(/- Evaluator agent id:\s*([A-Za-z0-9.]+)/);
26
+ const integrationMatch = String(rawPrompt || "").match(
27
+ /- Integration steward agent id:\s*([A-Za-z0-9.]+)/,
28
+ );
29
+ const documentationMatch = String(rawPrompt || "").match(
30
+ /- Documentation steward agent id:\s*([A-Za-z0-9.]+)/,
31
+ );
32
+ return {
33
+ evaluatorAgentId: evaluatorMatch ? evaluatorMatch[1].trim() : "A0",
34
+ integrationAgentId: integrationMatch ? integrationMatch[1].trim() : "A8",
35
+ documentationAgentId: documentationMatch ? documentationMatch[1].trim() : "A9",
36
+ };
37
+ }
38
+
39
+ function extractOwnedComponents(rawPrompt) {
40
+ const lines = String(rawPrompt || "").split(/\r?\n/);
41
+ const components = [];
42
+ let inComponents = false;
43
+ for (const line of lines) {
44
+ if (/^\s*Components you own in this wave:\s*$/i.test(line)) {
45
+ inComponents = true;
46
+ continue;
47
+ }
48
+ if (inComponents && /^\s*[A-Za-z][A-Za-z0-9 _/-]*:\s*$/.test(line)) {
49
+ inComponents = false;
50
+ }
51
+ if (!inComponents) {
52
+ continue;
53
+ }
54
+ const bulletMatch = line.match(/^\s*-\s+([a-z0-9._-]+)(?:\s*:\s*([a-z0-9._-]+))?\s*$/i);
55
+ if (!bulletMatch) {
56
+ continue;
57
+ }
58
+ components.push({
59
+ componentId: bulletMatch[1],
60
+ level: bulletMatch[2] || null,
61
+ });
62
+ }
63
+ return components;
64
+ }
65
+
66
+ function extractDeliverables(promptText) {
67
+ const out = [];
68
+ let inFileOwnership = false;
69
+ for (const line of promptText.split(/\r?\n/)) {
70
+ if (/^\s*File ownership\b/i.test(line)) {
71
+ inFileOwnership = true;
72
+ continue;
73
+ }
74
+ if (inFileOwnership && /^\s*[A-Za-z][A-Za-z0-9 _-]*:\s*$/.test(line)) {
75
+ inFileOwnership = false;
76
+ }
77
+ if (inFileOwnership) {
78
+ const bulletMatch = line.match(/^\s*-\s+(.+?)\s*$/);
79
+ if (bulletMatch) {
80
+ const cleaned = bulletMatch[1].replace(/[`"']/g, "").trim();
81
+ if (
82
+ cleaned.includes("/") ||
83
+ /\.(md|mdx|js|mjs|ts|go|json|yaml|yml|sh|sql)$/.test(cleaned)
84
+ ) {
85
+ out.push(cleaned);
86
+ continue;
87
+ }
88
+ }
89
+ }
90
+ const match = line.match(/^\s*\d+[.)]\s*(.+?)\s*$/);
91
+ if (!match) {
92
+ continue;
93
+ }
94
+ const cleaned = match[1].replace(/[`"']/g, "").trim();
95
+ if (cleaned.includes("/") || /\.(md|mdx|js|mjs|ts|go|json|yaml|yml|sh)$/.test(cleaned)) {
96
+ out.push(cleaned);
97
+ }
98
+ }
99
+ return Array.from(new Set(out));
100
+ }
101
+
102
+ export function resolveRepoOwnedDeliverablePath(relPath) {
103
+ if (!relPath || path.isAbsolute(relPath)) {
104
+ throw new Error(`Unsafe deliverable path: ${String(relPath || "")}`);
105
+ }
106
+ const absPath = path.resolve(REPO_ROOT, relPath);
107
+ const relative = path.relative(REPO_ROOT, absPath);
108
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
109
+ throw new Error(`Deliverable escapes repo root: ${relPath}`);
110
+ }
111
+ return absPath;
112
+ }
113
+
114
+ function markdownTemplate(relPath, promptText, options = {}) {
115
+ const requirements = promptText
116
+ .split(/\r?\n/)
117
+ .map((line) => line.match(/^\s*-\s+(.+)$/)?.[1]?.trim())
118
+ .filter(Boolean)
119
+ .slice(0, 12);
120
+
121
+ return [
122
+ `# ${titleFromPath(relPath)}`,
123
+ "",
124
+ "Generated by `wave-local-executor` for smoke-testing the Wave framework.",
125
+ "",
126
+ "## Objective",
127
+ `Create an implementation-ready placeholder for \`${relPath}\` so the local executor path can complete.`,
128
+ "",
129
+ "## Scope",
130
+ ...(requirements.length > 0
131
+ ? requirements.map((item) => `- ${item}`)
132
+ : ["- Derived from assigned wave prompt."]),
133
+ "",
134
+ ...(options.evaluatorReport ? ["## Verdict", "Verdict: PASS", ""] : []),
135
+ "## Note",
136
+ "- Replace this placeholder with real implementation work before relying on it.",
137
+ "",
138
+ ].join("\n");
139
+ }
140
+
141
+ function sourceTemplate(relPath) {
142
+ return [
143
+ "// Generated by wave-local-executor for smoke-testing only.",
144
+ `// Source deliverable: ${relPath}`,
145
+ "",
146
+ "export {};",
147
+ "",
148
+ ].join("\n");
149
+ }
150
+
151
+ function writeDeliverable(relPath, promptText, options = {}) {
152
+ const absPath = resolveRepoOwnedDeliverablePath(relPath);
153
+ ensureDirectory(path.dirname(absPath));
154
+ if (fs.existsSync(absPath)) {
155
+ return "exists";
156
+ }
157
+ if (/\.(md|mdx)$/i.test(absPath)) {
158
+ const evaluatorReport =
159
+ options.evaluatorAgent === true &&
160
+ /(?:^|\/)(?:reviews?|.*evaluator).*\.(md|mdx)$/i.test(relPath);
161
+ fs.writeFileSync(
162
+ absPath,
163
+ `${markdownTemplate(relPath, promptText, { evaluatorReport })}\n`,
164
+ "utf8",
165
+ );
166
+ return "created";
167
+ }
168
+ fs.writeFileSync(absPath, `${sourceTemplate(relPath)}\n`, "utf8");
169
+ return "created";
170
+ }
171
+
172
+ function parseArgs(argv) {
173
+ const options = { promptFile: null };
174
+ for (let i = 0; i < argv.length; i += 1) {
175
+ const arg = argv[i];
176
+ if (arg === "--") {
177
+ continue;
178
+ }
179
+ if (arg === "--prompt-file") {
180
+ options.promptFile = argv[++i] ? path.resolve(REPO_ROOT, argv[i]) : null;
181
+ } else if (arg === "--help" || arg === "-h") {
182
+ return { help: true, options };
183
+ } else {
184
+ throw new Error(`Unknown argument: ${arg}`);
185
+ }
186
+ }
187
+ if (!options.promptFile) {
188
+ throw new Error("--prompt-file is required");
189
+ }
190
+ return { help: false, options };
191
+ }
192
+
193
+ export function runLocalExecutorCli(argv) {
194
+ const { help, options } = parseArgs(argv);
195
+ if (help) {
196
+ console.log("Usage: pnpm exec wave local --prompt-file <path>");
197
+ return;
198
+ }
199
+ const rawPrompt = fs.readFileSync(options.promptFile, "utf8");
200
+ const agentId = extractAgentId(rawPrompt);
201
+ const { evaluatorAgentId, integrationAgentId, documentationAgentId } = extractRoleAgentIds(rawPrompt);
202
+ const evaluatorAgent = agentId === evaluatorAgentId;
203
+ const integrationAgent = agentId === integrationAgentId;
204
+ const ownedComponents = extractOwnedComponents(rawPrompt);
205
+ const assignedPrompt = extractAssignedPrompt(rawPrompt);
206
+ const deliverables = extractDeliverables(assignedPrompt);
207
+ if (deliverables.length === 0) {
208
+ console.log("[local-executor] no deliverables detected; nothing to do.");
209
+ if (evaluatorAgent) {
210
+ console.log(
211
+ "[wave-gate] architecture=pass integration=pass durability=pass live=pass docs=pass detail=local-executor-no-deliverables",
212
+ );
213
+ console.log("[wave-verdict] pass detail=local-executor-no-deliverables");
214
+ } else if (integrationAgent) {
215
+ console.log(
216
+ "[wave-integration] state=ready-for-doc-closure claims=0 conflicts=0 blockers=0 detail=local-executor-no-deliverables",
217
+ );
218
+ } else if (agentId === documentationAgentId) {
219
+ console.log("[wave-doc-closure] state=no-change detail=local-executor-no-deliverables");
220
+ } else if (agentId) {
221
+ console.log(
222
+ "[wave-proof] completion=contract durability=none proof=unit state=met detail=local-executor-no-deliverables",
223
+ );
224
+ console.log("[wave-doc-delta] state=none detail=local-executor-no-deliverables");
225
+ for (const component of ownedComponents) {
226
+ console.log(
227
+ `[wave-component] component=${component.componentId} level=${component.level || "repo-landed"} state=met detail=local-executor-no-deliverables`,
228
+ );
229
+ }
230
+ }
231
+ return;
232
+ }
233
+ console.log(`[local-executor] prompt=${path.relative(REPO_ROOT, options.promptFile)}`);
234
+ console.log(`[local-executor] deliverables=${deliverables.join(", ")}`);
235
+ for (const deliverable of deliverables) {
236
+ console.log(
237
+ `[local-executor] ${writeDeliverable(deliverable, assignedPrompt, { evaluatorAgent })}: ${deliverable}`,
238
+ );
239
+ }
240
+ if (evaluatorAgent) {
241
+ console.log(
242
+ "[wave-gate] architecture=pass integration=pass durability=pass live=pass docs=pass detail=local-executor-smoke",
243
+ );
244
+ console.log("[wave-verdict] pass detail=local-executor-smoke");
245
+ } else if (integrationAgent) {
246
+ console.log(
247
+ "[wave-integration] state=ready-for-doc-closure claims=0 conflicts=0 blockers=0 detail=local-executor-smoke",
248
+ );
249
+ } else if (agentId === documentationAgentId) {
250
+ console.log("[wave-doc-closure] state=no-change detail=local-executor-smoke");
251
+ } else if (agentId) {
252
+ console.log(
253
+ "[wave-proof] completion=contract durability=none proof=unit state=met detail=local-executor-smoke",
254
+ );
255
+ console.log("[wave-doc-delta] state=owned detail=local-executor-smoke");
256
+ for (const component of ownedComponents) {
257
+ console.log(
258
+ `[wave-component] component=${component.componentId} level=${component.level || "repo-landed"} state=met detail=local-executor-smoke`,
259
+ );
260
+ }
261
+ }
262
+ console.log("[local-executor] completed.");
263
+ }