@chllming/wave-orchestration 0.8.8 → 0.9.0

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 (49) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/README.md +23 -8
  3. package/docs/README.md +5 -3
  4. package/docs/concepts/context7-vs-skills.md +1 -1
  5. package/docs/concepts/operating-modes.md +1 -1
  6. package/docs/concepts/what-is-a-wave.md +1 -1
  7. package/docs/guides/author-and-run-waves.md +14 -1
  8. package/docs/guides/monorepo-projects.md +226 -0
  9. package/docs/guides/planner.md +9 -2
  10. package/docs/guides/{recommendations-0.8.8.md → recommendations-0.9.0.md} +7 -7
  11. package/docs/plans/current-state.md +8 -6
  12. package/docs/plans/end-state-architecture.md +1 -1
  13. package/docs/plans/examples/wave-example-design-handoff.md +3 -1
  14. package/docs/plans/examples/wave-example-live-proof.md +6 -1
  15. package/docs/plans/examples/wave-example-rollout-fidelity.md +2 -0
  16. package/docs/plans/migration.md +21 -18
  17. package/docs/plans/wave-orchestrator.md +4 -4
  18. package/docs/reference/cli-reference.md +55 -51
  19. package/docs/reference/coordination-and-closure.md +1 -1
  20. package/docs/reference/npmjs-trusted-publishing.md +2 -2
  21. package/docs/reference/runtime-config/README.md +140 -12
  22. package/docs/reference/sample-waves.md +100 -5
  23. package/docs/reference/skills.md +1 -1
  24. package/docs/reference/wave-control.md +23 -5
  25. package/docs/roadmap.md +2 -2
  26. package/package.json +1 -1
  27. package/releases/manifest.json +37 -0
  28. package/scripts/wave-orchestrator/adhoc.mjs +49 -17
  29. package/scripts/wave-orchestrator/autonomous.mjs +49 -15
  30. package/scripts/wave-orchestrator/benchmark-external.mjs +23 -7
  31. package/scripts/wave-orchestrator/benchmark.mjs +33 -10
  32. package/scripts/wave-orchestrator/config.mjs +239 -24
  33. package/scripts/wave-orchestrator/control-cli.mjs +29 -23
  34. package/scripts/wave-orchestrator/coord-cli.mjs +22 -14
  35. package/scripts/wave-orchestrator/coordination-store.mjs +8 -0
  36. package/scripts/wave-orchestrator/dashboard-renderer.mjs +10 -3
  37. package/scripts/wave-orchestrator/dep-cli.mjs +47 -21
  38. package/scripts/wave-orchestrator/feedback.mjs +28 -11
  39. package/scripts/wave-orchestrator/human-input-resolution.mjs +5 -1
  40. package/scripts/wave-orchestrator/launcher.mjs +200 -112
  41. package/scripts/wave-orchestrator/planner.mjs +48 -27
  42. package/scripts/wave-orchestrator/project-profile.mjs +31 -8
  43. package/scripts/wave-orchestrator/proof-cli.mjs +18 -12
  44. package/scripts/wave-orchestrator/retry-cli.mjs +19 -13
  45. package/scripts/wave-orchestrator/shared.mjs +77 -14
  46. package/scripts/wave-orchestrator/traces.mjs +7 -0
  47. package/scripts/wave-orchestrator/wave-control-client.mjs +84 -16
  48. package/scripts/wave-orchestrator/wave-files.mjs +5 -1
  49. package/scripts/wave-orchestrator/wave-state-reducer.mjs +8 -1
@@ -15,10 +15,10 @@ import { parseWaveFiles } from "./wave-files.mjs";
15
15
 
16
16
  function printUsage() {
17
17
  console.log(`Usage:
18
- wave dep post --owner-lane <lane> --requester-lane <lane> --owner-wave <n> --requester-wave <n> --agent <id> --summary <text> [options]
19
- wave dep show --lane <lane> [--wave <n>] [--json]
20
- wave dep resolve --lane <lane> --id <id> --agent <id> [--detail <text>] [--status resolved|closed]
21
- wave dep render --lane <lane> [--wave <n>] [--json]
18
+ wave dep post --owner-project <id> --owner-lane <lane> --requester-project <id> --requester-lane <lane> --owner-wave <n> --requester-wave <n> --agent <id> --summary <text> [options]
19
+ wave dep show --project <id> --lane <lane> [--wave <n>] [--json]
20
+ wave dep resolve --project <id> --lane <lane> --id <id> --agent <id> [--detail <text>] [--status resolved|closed]
21
+ wave dep render --project <id> --lane <lane> [--wave <n>] [--json]
22
22
  `);
23
23
  }
24
24
 
@@ -26,6 +26,9 @@ function parseArgs(argv) {
26
26
  const args = argv[0] === "--" ? argv.slice(1) : argv;
27
27
  const subcommand = String(args[0] || "").trim().toLowerCase();
28
28
  const options = {
29
+ project: "",
30
+ ownerProject: "",
31
+ requesterProject: "",
29
32
  lane: "",
30
33
  ownerLane: "",
31
34
  requesterLane: "",
@@ -46,7 +49,13 @@ function parseArgs(argv) {
46
49
  };
47
50
  for (let index = 1; index < args.length; index += 1) {
48
51
  const arg = args[index];
49
- if (arg === "--lane") {
52
+ if (arg === "--project") {
53
+ options.project = String(args[++index] || "").trim();
54
+ } else if (arg === "--owner-project") {
55
+ options.ownerProject = String(args[++index] || "").trim();
56
+ } else if (arg === "--requester-project") {
57
+ options.requesterProject = String(args[++index] || "").trim();
58
+ } else if (arg === "--lane") {
50
59
  options.lane = String(args[++index] || "").trim();
51
60
  } else if (arg === "--owner-lane") {
52
61
  options.ownerLane = String(args[++index] || "").trim();
@@ -112,11 +121,15 @@ export async function runDependencyCli(argv) {
112
121
  return;
113
122
  }
114
123
  const { subcommand, options } = parseArgs(argv);
124
+ const baseProject =
125
+ options.project || options.ownerProject || options.requesterProject || undefined;
115
126
  const baseLane = options.lane || options.ownerLane || options.requesterLane || "main";
116
- const lanePaths = buildLanePaths(baseLane);
127
+ const lanePaths = buildLanePaths(baseLane, { project: baseProject });
117
128
  ensureDirectory(lanePaths.crossLaneDependenciesDir);
118
129
 
119
130
  if (subcommand === "post") {
131
+ const ownerProject = options.ownerProject || options.project || lanePaths.project;
132
+ const requesterProject = options.requesterProject || options.project || lanePaths.project;
120
133
  const ownerLane = options.ownerLane || options.lane;
121
134
  const requesterLane = options.requesterLane || lanePaths.lane;
122
135
  if (!ownerLane || !requesterLane || options.ownerWave === null || options.requesterWave === null) {
@@ -125,13 +138,17 @@ export async function runDependencyCli(argv) {
125
138
  if (!options.agent || !options.summary) {
126
139
  throw new Error("--agent and --summary are required");
127
140
  }
128
- const record = appendDependencyTicket(lanePaths.crossLaneDependenciesDir, ownerLane, {
141
+ const ownerLanePaths = buildLanePaths(ownerLane, { project: ownerProject });
142
+ ensureDirectory(ownerLanePaths.crossLaneDependenciesDir);
143
+ const record = appendDependencyTicket(ownerLanePaths.crossLaneDependenciesDir, ownerLane, {
129
144
  id: options.id || `dep-${Date.now().toString(36)}`,
130
145
  kind: "request",
131
146
  lane: ownerLane,
132
147
  wave: options.ownerWave,
148
+ ownerProject,
133
149
  ownerLane,
134
150
  ownerWave: options.ownerWave,
151
+ requesterProject,
135
152
  requesterLane,
136
153
  requesterWave: options.requesterWave,
137
154
  agentId: options.agent,
@@ -155,14 +172,15 @@ export async function runDependencyCli(argv) {
155
172
  if (!lane || !options.id || !options.agent) {
156
173
  throw new Error("--lane, --id, and --agent are required for resolve");
157
174
  }
158
- const filePath = dependencyFilePath(lanePaths, lane);
159
- const latest = materializeCoordinationState(readDependencyTickets(lanePaths.crossLaneDependenciesDir, lane)).byId.get(
175
+ const targetProject = options.project || options.ownerProject || lanePaths.project;
176
+ const targetLanePaths = buildLanePaths(lane, { project: targetProject });
177
+ const latest = materializeCoordinationState(readDependencyTickets(targetLanePaths.crossLaneDependenciesDir, lane)).byId.get(
160
178
  options.id,
161
179
  );
162
180
  if (!latest) {
163
181
  throw new Error(`Dependency ${options.id} not found for lane ${lane}`);
164
182
  }
165
- const record = appendDependencyTicket(lanePaths.crossLaneDependenciesDir, lane, {
183
+ const record = appendDependencyTicket(targetLanePaths.crossLaneDependenciesDir, lane, {
166
184
  ...latest,
167
185
  agentId: options.agent,
168
186
  status: options.status || "resolved",
@@ -175,17 +193,23 @@ export async function runDependencyCli(argv) {
175
193
 
176
194
  if (subcommand === "show") {
177
195
  const lane = options.lane || options.ownerLane || lanePaths.lane;
196
+ const targetProject = options.project || options.ownerProject || lanePaths.project;
197
+ const targetLanePaths = buildLanePaths(lane, { project: targetProject });
178
198
  const records =
179
199
  options.wave === null
180
- ? readAllDependencyTickets(lanePaths.crossLaneDependenciesDir).filter(
181
- (record) => record.ownerLane === lane || record.requesterLane === lane || record.lane === lane,
200
+ ? readAllDependencyTickets(targetLanePaths.crossLaneDependenciesDir).filter(
201
+ (record) =>
202
+ (record.ownerLane === lane || record.requesterLane === lane || record.lane === lane) &&
203
+ (!options.project ||
204
+ record.ownerProject === targetProject ||
205
+ record.requesterProject === targetProject),
182
206
  )
183
207
  : buildDependencySnapshot({
184
- dirPath: lanePaths.crossLaneDependenciesDir,
208
+ dirPath: targetLanePaths.crossLaneDependenciesDir,
185
209
  lane,
186
210
  waveNumber: options.wave,
187
- agents: loadWaveAgents(lanePaths, options.wave),
188
- capabilityRouting: lanePaths.capabilityRouting,
211
+ agents: loadWaveAgents(targetLanePaths, options.wave),
212
+ capabilityRouting: targetLanePaths.capabilityRouting,
189
213
  });
190
214
  if (options.json || options.wave !== null) {
191
215
  console.log(JSON.stringify(records, null, 2));
@@ -201,20 +225,22 @@ export async function runDependencyCli(argv) {
201
225
 
202
226
  if (subcommand === "render") {
203
227
  const lane = options.lane || options.ownerLane || lanePaths.lane;
228
+ const targetProject = options.project || options.ownerProject || lanePaths.project;
229
+ const targetLanePaths = buildLanePaths(lane, { project: targetProject });
204
230
  const snapshot = buildDependencySnapshot({
205
- dirPath: lanePaths.crossLaneDependenciesDir,
231
+ dirPath: targetLanePaths.crossLaneDependenciesDir,
206
232
  lane,
207
233
  waveNumber: options.wave ?? 0,
208
- agents: loadWaveAgents(lanePaths, options.wave ?? 0),
209
- capabilityRouting: lanePaths.capabilityRouting,
234
+ agents: loadWaveAgents(targetLanePaths, options.wave ?? 0),
235
+ capabilityRouting: targetLanePaths.capabilityRouting,
210
236
  });
211
- const markdownPath = dependencyMarkdownPath(lanePaths, lane);
212
- writeDependencySnapshot(path.join(lanePaths.crossLaneDependenciesDir, `${lane}.json`), snapshot, {
237
+ const markdownPath = dependencyMarkdownPath(targetLanePaths, lane);
238
+ writeDependencySnapshot(path.join(targetLanePaths.crossLaneDependenciesDir, `${lane}.json`), snapshot, {
213
239
  lane,
214
240
  wave: options.wave ?? 0,
215
241
  });
216
242
  writeTextAtomic(markdownPath, `${renderDependencySnapshotMarkdown(snapshot)}\n`);
217
- console.log(JSON.stringify({ markdownPath, jsonPath: path.join(lanePaths.crossLaneDependenciesDir, `${lane}.json`) }, null, 2));
243
+ console.log(JSON.stringify({ markdownPath, jsonPath: path.join(targetLanePaths.crossLaneDependenciesDir, `${lane}.json`) }, null, 2));
218
244
  return;
219
245
  }
220
246
 
@@ -6,10 +6,10 @@ import {
6
6
  DEFAULT_WAIT_TIMEOUT_SECONDS,
7
7
  DEFAULT_WATCH_REFRESH_MS,
8
8
  DEFAULT_WAVE_LANE,
9
- REPO_ROOT,
10
9
  buildLanePaths,
11
10
  compactSingleLine,
12
11
  ensureDirectory,
12
+ findAdhocRunRecord,
13
13
  formatAgeFromTimestamp,
14
14
  parseNonNegativeInt,
15
15
  parsePositiveInt,
@@ -41,9 +41,12 @@ function requestFilePath(feedbackRequestsDir, requestId) {
41
41
  return path.join(feedbackRequestsDir, `${requestId}.json`);
42
42
  }
43
43
 
44
- function resolveLaneForRun(runId, fallbackLane) {
45
- const resultPath = path.join(REPO_ROOT, ".wave", "adhoc", "runs", runId, "result.json");
46
- return readJsonOrNull(resultPath)?.lane || fallbackLane;
44
+ function resolveRunContext(runId, fallbackProject, fallbackLane) {
45
+ const record = findAdhocRunRecord(runId);
46
+ return {
47
+ project: record?.project || fallbackProject,
48
+ lane: record?.result?.lane || fallbackLane,
49
+ };
47
50
  }
48
51
 
49
52
  function buildRequestId({ lane, wave, agentId }) {
@@ -55,6 +58,7 @@ function buildRequestId({ lane, wave, agentId }) {
55
58
  export function createFeedbackRequest({
56
59
  feedbackStateDir,
57
60
  feedbackRequestsDir,
61
+ project = null,
58
62
  lane,
59
63
  wave,
60
64
  agentId,
@@ -69,6 +73,7 @@ export function createFeedbackRequest({
69
73
  const now = toIsoTimestamp();
70
74
  const payload = {
71
75
  id: requestId,
76
+ project: project || null,
72
77
  createdAt: now,
73
78
  updatedAt: now,
74
79
  lane,
@@ -88,7 +93,9 @@ export function createFeedbackRequest({
88
93
  });
89
94
  if (recordTelemetry) {
90
95
  try {
91
- const lanePaths = buildLanePaths(lane);
96
+ const lanePaths = buildLanePaths(lane, {
97
+ project: project || undefined,
98
+ });
92
99
  safeQueueWaveControlEvent(lanePaths, {
93
100
  category: "feedback",
94
101
  entityType: "human_input",
@@ -148,7 +155,9 @@ export function answerFeedbackRequest({
148
155
  });
149
156
  if (recordTelemetry) {
150
157
  try {
151
- const lanePaths = buildLanePaths(answeredPayload?.lane || DEFAULT_WAVE_LANE);
158
+ const lanePaths = buildLanePaths(answeredPayload?.lane || DEFAULT_WAVE_LANE, {
159
+ project: answeredPayload?.project || undefined,
160
+ });
152
161
  safeQueueWaveControlEvent(lanePaths, {
153
162
  category: "feedback",
154
163
  entityType: "human_input",
@@ -245,6 +254,7 @@ function parseFeedbackArgs(argv) {
245
254
  id: "",
246
255
  response: "",
247
256
  operator: "human-operator",
257
+ project: "",
248
258
  force: false,
249
259
  pending: false,
250
260
  json: false,
@@ -255,7 +265,9 @@ function parseFeedbackArgs(argv) {
255
265
  if (arg === "--") {
256
266
  continue;
257
267
  }
258
- if (arg === "--lane") {
268
+ if (arg === "--project") {
269
+ out.project = String(args[++i] || "").trim();
270
+ } else if (arg === "--lane") {
259
271
  out.lane = sanitizeLaneName(args[++i]);
260
272
  } else if (arg === "--run") {
261
273
  out.runId = sanitizeAdhocRunId(args[++i]);
@@ -310,10 +322,10 @@ async function waitForAnswer(filePath, timeoutSeconds) {
310
322
 
311
323
  function printHelp() {
312
324
  console.log(`Usage:
313
- pnpm exec wave-feedback ask --lane <lane> --wave <n> --agent <id> --question "<text>" [options]
325
+ pnpm exec wave-feedback ask --project <id> --lane <lane> --wave <n> --agent <id> --question "<text>" [options]
314
326
  pnpm exec wave-feedback respond --id <request-id> --response "<text>" [options]
315
- pnpm exec wave-feedback list [--pending] [--lane <lane>] [--wave <n>] [--agent <id>] [--json]
316
- pnpm exec wave-feedback watch [--pending] [--lane <lane>] [--wave <n>] [--agent <id>] [--refresh-ms <n>]
327
+ pnpm exec wave-feedback list [--pending] [--project <id>] [--lane <lane>] [--wave <n>] [--agent <id>] [--json]
328
+ pnpm exec wave-feedback watch [--pending] [--project <id>] [--lane <lane>] [--wave <n>] [--agent <id>] [--refresh-ms <n>]
317
329
  pnpm exec wave-feedback show --id <request-id>
318
330
  `);
319
331
  }
@@ -325,9 +337,12 @@ export async function runFeedbackCli(argv) {
325
337
  return;
326
338
  }
327
339
  if (options.runId) {
328
- options.lane = resolveLaneForRun(options.runId, options.lane);
340
+ const context = resolveRunContext(options.runId, options.project, options.lane);
341
+ options.project = context.project;
342
+ options.lane = context.lane;
329
343
  }
330
344
  const lanePaths = buildLanePaths(options.lane, {
345
+ project: options.project || undefined,
331
346
  adhocRunId: options.runId || null,
332
347
  });
333
348
  const requestsDir = lanePaths.feedbackRequestsDir;
@@ -340,6 +355,7 @@ export async function runFeedbackCli(argv) {
340
355
  const result = createFeedbackRequest({
341
356
  feedbackStateDir: stateDir,
342
357
  feedbackRequestsDir: requestsDir,
358
+ project: lanePaths.project,
343
359
  lane: options.lane,
344
360
  wave: options.wave,
345
361
  agentId: options.agent,
@@ -375,6 +391,7 @@ export async function runFeedbackCli(argv) {
375
391
  });
376
392
  if (answered?.lane && Number.isFinite(Number(answered.wave))) {
377
393
  answerHumanInputByRequest({
394
+ project: answered.project || options.project || null,
378
395
  lane: answered.lane,
379
396
  waveNumber: Number(answered.wave),
380
397
  requestId: options.id,
@@ -331,13 +331,17 @@ export function answerHumanInputAndReconcile({
331
331
  }
332
332
 
333
333
  export function answerHumanInputByRequest({
334
+ project = null,
334
335
  lane,
335
336
  waveNumber,
336
337
  requestId,
337
338
  operator = "human-operator",
338
339
  runId = null,
339
340
  }) {
340
- const lanePaths = buildLanePaths(lane, { adhocRunId: runId || null });
341
+ const lanePaths = buildLanePaths(lane, {
342
+ project: project || undefined,
343
+ adhocRunId: runId || null,
344
+ });
341
345
  const wave = loadWave(lanePaths, waveNumber);
342
346
  return answerHumanInputAndReconcile({
343
347
  lanePaths,