@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.
- package/CHANGELOG.md +48 -0
- package/README.md +23 -8
- package/docs/README.md +5 -3
- package/docs/concepts/context7-vs-skills.md +1 -1
- package/docs/concepts/operating-modes.md +1 -1
- package/docs/concepts/what-is-a-wave.md +1 -1
- package/docs/guides/author-and-run-waves.md +14 -1
- package/docs/guides/monorepo-projects.md +226 -0
- package/docs/guides/planner.md +9 -2
- package/docs/guides/{recommendations-0.8.8.md → recommendations-0.9.0.md} +7 -7
- package/docs/plans/current-state.md +8 -6
- package/docs/plans/end-state-architecture.md +1 -1
- package/docs/plans/examples/wave-example-design-handoff.md +3 -1
- package/docs/plans/examples/wave-example-live-proof.md +6 -1
- package/docs/plans/examples/wave-example-rollout-fidelity.md +2 -0
- package/docs/plans/migration.md +21 -18
- package/docs/plans/wave-orchestrator.md +4 -4
- package/docs/reference/cli-reference.md +55 -51
- package/docs/reference/coordination-and-closure.md +1 -1
- package/docs/reference/npmjs-trusted-publishing.md +2 -2
- package/docs/reference/runtime-config/README.md +140 -12
- package/docs/reference/sample-waves.md +100 -5
- package/docs/reference/skills.md +1 -1
- package/docs/reference/wave-control.md +23 -5
- package/docs/roadmap.md +2 -2
- package/package.json +1 -1
- package/releases/manifest.json +37 -0
- package/scripts/wave-orchestrator/adhoc.mjs +49 -17
- package/scripts/wave-orchestrator/autonomous.mjs +49 -15
- package/scripts/wave-orchestrator/benchmark-external.mjs +23 -7
- package/scripts/wave-orchestrator/benchmark.mjs +33 -10
- package/scripts/wave-orchestrator/config.mjs +239 -24
- package/scripts/wave-orchestrator/control-cli.mjs +29 -23
- package/scripts/wave-orchestrator/coord-cli.mjs +22 -14
- package/scripts/wave-orchestrator/coordination-store.mjs +8 -0
- package/scripts/wave-orchestrator/dashboard-renderer.mjs +10 -3
- package/scripts/wave-orchestrator/dep-cli.mjs +47 -21
- package/scripts/wave-orchestrator/feedback.mjs +28 -11
- package/scripts/wave-orchestrator/human-input-resolution.mjs +5 -1
- package/scripts/wave-orchestrator/launcher.mjs +200 -112
- package/scripts/wave-orchestrator/planner.mjs +48 -27
- package/scripts/wave-orchestrator/project-profile.mjs +31 -8
- package/scripts/wave-orchestrator/proof-cli.mjs +18 -12
- package/scripts/wave-orchestrator/retry-cli.mjs +19 -13
- package/scripts/wave-orchestrator/shared.mjs +77 -14
- package/scripts/wave-orchestrator/traces.mjs +7 -0
- package/scripts/wave-orchestrator/wave-control-client.mjs +84 -16
- package/scripts/wave-orchestrator/wave-files.mjs +5 -1
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +8 -1
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
buildLanePaths,
|
|
26
26
|
compactSingleLine,
|
|
27
27
|
ensureDirectory,
|
|
28
|
+
findAdhocRunRecord,
|
|
28
29
|
parseNonNegativeInt,
|
|
29
30
|
readJsonOrNull,
|
|
30
31
|
REPO_ROOT,
|
|
@@ -205,8 +206,8 @@ async function withSuppressedNestedUpdateNotice(fn) {
|
|
|
205
206
|
}
|
|
206
207
|
}
|
|
207
208
|
|
|
208
|
-
function readEffectiveProjectProfile(config) {
|
|
209
|
-
return readProjectProfile({ config }) || buildDefaultProjectProfile(config);
|
|
209
|
+
function readEffectiveProjectProfile(config, project) {
|
|
210
|
+
return readProjectProfile({ config, project }) || buildDefaultProjectProfile(config);
|
|
210
211
|
}
|
|
211
212
|
|
|
212
213
|
function detectKeyword(text, keywords) {
|
|
@@ -451,6 +452,10 @@ function buildCommonRequiredContext() {
|
|
|
451
452
|
);
|
|
452
453
|
}
|
|
453
454
|
|
|
455
|
+
function adhocReportPath(lanePaths, filename) {
|
|
456
|
+
return repoRelativePath(path.join(lanePaths.adhocRunDir, "reports", filename));
|
|
457
|
+
}
|
|
458
|
+
|
|
454
459
|
function buildDocumentationOwnedPaths({ lanePaths, waveNumber, mode }) {
|
|
455
460
|
const canonicalPaths = requiredDocumentationStewardPathsForWave(waveNumber, {
|
|
456
461
|
laneProfile: lanePaths.laneProfile,
|
|
@@ -459,7 +464,7 @@ function buildDocumentationOwnedPaths({ lanePaths, waveNumber, mode }) {
|
|
|
459
464
|
return canonicalPaths;
|
|
460
465
|
}
|
|
461
466
|
return uniqueStrings([
|
|
462
|
-
|
|
467
|
+
adhocReportPath(lanePaths, `wave-${waveNumber}-doc-closure.md`),
|
|
463
468
|
...canonicalPaths,
|
|
464
469
|
]);
|
|
465
470
|
}
|
|
@@ -476,11 +481,11 @@ function buildSpecialAgents({
|
|
|
476
481
|
const contQaReportPath =
|
|
477
482
|
mode === "roadmap"
|
|
478
483
|
? `docs/plans/waves/reviews/wave-${waveNumber}-cont-qa.md`
|
|
479
|
-
:
|
|
484
|
+
: adhocReportPath(lanePaths, `wave-${waveNumber}-cont-qa.md`);
|
|
480
485
|
const contEvalReportPath =
|
|
481
486
|
mode === "roadmap"
|
|
482
487
|
? `docs/plans/waves/reviews/wave-${waveNumber}-cont-eval.md`
|
|
483
|
-
:
|
|
488
|
+
: adhocReportPath(lanePaths, `wave-${waveNumber}-cont-eval.md`);
|
|
484
489
|
const documentationOwnedPaths = buildDocumentationOwnedPaths({
|
|
485
490
|
lanePaths,
|
|
486
491
|
waveNumber,
|
|
@@ -489,7 +494,7 @@ function buildSpecialAgents({
|
|
|
489
494
|
const securityReportPath =
|
|
490
495
|
mode === "roadmap"
|
|
491
496
|
? relativeStatePath(path.join(lanePaths.securityDir, `wave-${waveNumber}-review.md`))
|
|
492
|
-
:
|
|
497
|
+
: adhocReportPath(lanePaths, `wave-${waveNumber}-security-review.md`);
|
|
493
498
|
const integrationOwnedPaths = [
|
|
494
499
|
relativeStatePath(path.join(lanePaths.integrationDir, `wave-${waveNumber}.md`)),
|
|
495
500
|
relativeStatePath(path.join(lanePaths.integrationDir, `wave-${waveNumber}.json`)),
|
|
@@ -727,6 +732,7 @@ function buildAdhocRequest({ runId, lanePaths, profile, tasks, launcherArgs = []
|
|
|
727
732
|
schemaVersion: ADHOC_SCHEMA_VERSION,
|
|
728
733
|
runKind: "adhoc",
|
|
729
734
|
runId,
|
|
735
|
+
project: lanePaths.project,
|
|
730
736
|
lane: lanePaths.lane,
|
|
731
737
|
createdAt: toIsoTimestamp(),
|
|
732
738
|
oversightMode: profile.defaultOversightMode,
|
|
@@ -846,6 +852,7 @@ function buildResultRecord(lanePaths, request, spec, status, extra = {}) {
|
|
|
846
852
|
schemaVersion: ADHOC_SCHEMA_VERSION,
|
|
847
853
|
runKind: "adhoc",
|
|
848
854
|
runId: request.runId,
|
|
855
|
+
project: request.project || lanePaths.project,
|
|
849
856
|
lane: request.lane,
|
|
850
857
|
title: spec.title,
|
|
851
858
|
status,
|
|
@@ -1009,6 +1016,7 @@ function parseArgs(argv) {
|
|
|
1009
1016
|
const args = Array.isArray(argv) ? argv.slice() : [];
|
|
1010
1017
|
const subcommand = cleanText(args.shift()).toLowerCase();
|
|
1011
1018
|
const options = {
|
|
1019
|
+
project: "",
|
|
1012
1020
|
lane: "",
|
|
1013
1021
|
runId: "",
|
|
1014
1022
|
wave: null,
|
|
@@ -1022,6 +1030,8 @@ function parseArgs(argv) {
|
|
|
1022
1030
|
const arg = args.shift();
|
|
1023
1031
|
if (arg === "--task") {
|
|
1024
1032
|
options.tasks.push(cleanText(args.shift()));
|
|
1033
|
+
} else if (arg === "--project") {
|
|
1034
|
+
options.project = cleanText(args.shift());
|
|
1025
1035
|
} else if (arg === "--lane") {
|
|
1026
1036
|
options.lane = cleanText(args.shift());
|
|
1027
1037
|
} else if (arg === "--run") {
|
|
@@ -1074,24 +1084,25 @@ function parseArgs(argv) {
|
|
|
1074
1084
|
|
|
1075
1085
|
function printUsage() {
|
|
1076
1086
|
console.log(`Usage:
|
|
1077
|
-
wave adhoc plan --task <text> [--task <text>] [--lane <lane>] [--json]
|
|
1078
|
-
wave adhoc run --task <text> [--task <text>] [--lane <lane>] [--yes] [--json] [launcher options]
|
|
1079
|
-
wave adhoc list [--lane <lane>] [--json]
|
|
1087
|
+
wave adhoc plan --task <text> [--task <text>] [--project <id>] [--lane <lane>] [--json]
|
|
1088
|
+
wave adhoc run --task <text> [--task <text>] [--project <id>] [--lane <lane>] [--yes] [--json] [launcher options]
|
|
1089
|
+
wave adhoc list [--project <id>] [--lane <lane>] [--json]
|
|
1080
1090
|
wave adhoc show --run <id> [--json]
|
|
1081
|
-
wave adhoc promote --run <id> --wave <n> [--force] [--json]
|
|
1091
|
+
wave adhoc promote --run <id> [--project <id>] --wave <n> [--force] [--json]
|
|
1082
1092
|
`);
|
|
1083
1093
|
}
|
|
1084
1094
|
|
|
1085
1095
|
function resolveLaneForOptions(config, options) {
|
|
1086
|
-
const profile = readEffectiveProjectProfile(config);
|
|
1096
|
+
const profile = readEffectiveProjectProfile(config, options.project || config.defaultProject);
|
|
1087
1097
|
return cleanText(options.lane) || profile.plannerDefaults?.lane || config.defaultLane;
|
|
1088
1098
|
}
|
|
1089
1099
|
|
|
1090
1100
|
function createStoredRun({ config, options }) {
|
|
1091
|
-
const
|
|
1101
|
+
const projectId = options.project || config.defaultProject;
|
|
1102
|
+
const profile = readEffectiveProjectProfile(config, projectId);
|
|
1092
1103
|
const lane = resolveLaneForOptions(config, options);
|
|
1093
1104
|
const runId = buildAdhocRunId();
|
|
1094
|
-
const lanePaths = buildLanePaths(lane, { config, adhocRunId: runId });
|
|
1105
|
+
const lanePaths = buildLanePaths(lane, { config, project: projectId, adhocRunId: runId });
|
|
1095
1106
|
const request = buildAdhocRequest({
|
|
1096
1107
|
runId,
|
|
1097
1108
|
lanePaths,
|
|
@@ -1114,7 +1125,17 @@ function createStoredRun({ config, options }) {
|
|
|
1114
1125
|
}
|
|
1115
1126
|
|
|
1116
1127
|
function readStoredRun(runId) {
|
|
1117
|
-
const
|
|
1128
|
+
const record = findAdhocRunRecord(runId);
|
|
1129
|
+
if (!record) {
|
|
1130
|
+
throw new Error(`Ad-hoc run not found: ${runId}`);
|
|
1131
|
+
}
|
|
1132
|
+
const lanePaths = buildLanePaths(
|
|
1133
|
+
record.result?.lane || DEFAULT_LANE_PLACEHOLDER,
|
|
1134
|
+
{
|
|
1135
|
+
project: record.project,
|
|
1136
|
+
adhocRunId: runId,
|
|
1137
|
+
},
|
|
1138
|
+
);
|
|
1118
1139
|
const request = readJsonOrNull(lanePaths.adhocRequestPath);
|
|
1119
1140
|
const spec = readJsonOrNull(lanePaths.adhocSpecPath);
|
|
1120
1141
|
const result = readJsonOrNull(lanePaths.adhocResultPath);
|
|
@@ -1166,6 +1187,7 @@ export async function runAdhocCli(argv) {
|
|
|
1166
1187
|
}
|
|
1167
1188
|
const launchLanePaths = buildLanePaths(stored.lanePaths.lane, {
|
|
1168
1189
|
config,
|
|
1190
|
+
project: stored.request.project || stored.lanePaths.project,
|
|
1169
1191
|
adhocRunId: stored.lanePaths.runId,
|
|
1170
1192
|
runVariant: options.launcherArgs.includes("--dry-run") ? "dry-run" : undefined,
|
|
1171
1193
|
});
|
|
@@ -1178,6 +1200,8 @@ export async function runAdhocCli(argv) {
|
|
|
1178
1200
|
try {
|
|
1179
1201
|
await withSuppressedNestedUpdateNotice(() =>
|
|
1180
1202
|
runLauncherCli([
|
|
1203
|
+
"--project",
|
|
1204
|
+
stored.request.project || stored.lanePaths.project,
|
|
1181
1205
|
"--lane",
|
|
1182
1206
|
stored.lanePaths.lane,
|
|
1183
1207
|
"--adhoc-run",
|
|
@@ -1219,9 +1243,10 @@ export async function runAdhocCli(argv) {
|
|
|
1219
1243
|
|
|
1220
1244
|
if (subcommand === "list") {
|
|
1221
1245
|
const lane = cleanText(options.lane);
|
|
1222
|
-
const
|
|
1246
|
+
const projectId = options.project || config.defaultProject;
|
|
1247
|
+
const lanePaths = buildLanePaths(lane || config.defaultLane, { config, project: projectId });
|
|
1223
1248
|
const runs = collectStoredRuns(lanePaths.adhocIndexPath).filter((run) =>
|
|
1224
|
-
lane ? run.lane === lane : true,
|
|
1249
|
+
(lane ? run.lane === lane : true) && (options.project ? run.project === projectId : true),
|
|
1225
1250
|
);
|
|
1226
1251
|
if (options.json) {
|
|
1227
1252
|
console.log(JSON.stringify(runs, null, 2));
|
|
@@ -1242,6 +1267,7 @@ export async function runAdhocCli(argv) {
|
|
|
1242
1267
|
const { lanePaths, request, spec, result } = readStoredRun(options.runId);
|
|
1243
1268
|
const payload = {
|
|
1244
1269
|
runId: options.runId,
|
|
1270
|
+
project: result.project || request.project || lanePaths.project,
|
|
1245
1271
|
lane: result.lane,
|
|
1246
1272
|
status: result.status,
|
|
1247
1273
|
title: result.title,
|
|
@@ -1263,6 +1289,7 @@ export async function runAdhocCli(argv) {
|
|
|
1263
1289
|
return;
|
|
1264
1290
|
}
|
|
1265
1291
|
console.log(`[wave:adhoc] run=${payload.runId}`);
|
|
1292
|
+
console.log(`[wave:adhoc] project=${payload.project}`);
|
|
1266
1293
|
console.log(`[wave:adhoc] lane=${payload.lane}`);
|
|
1267
1294
|
console.log(`[wave:adhoc] status=${payload.status}`);
|
|
1268
1295
|
console.log(`[wave:adhoc] title=${payload.title}`);
|
|
@@ -1290,8 +1317,13 @@ export async function runAdhocCli(argv) {
|
|
|
1290
1317
|
throw new Error("--wave <n> is required for `wave adhoc promote`.");
|
|
1291
1318
|
}
|
|
1292
1319
|
const stored = readStoredRun(options.runId);
|
|
1320
|
+
const projectId =
|
|
1321
|
+
cleanText(options.project) ||
|
|
1322
|
+
cleanText(stored.result.project) ||
|
|
1323
|
+
cleanText(stored.request.project) ||
|
|
1324
|
+
config.defaultProject;
|
|
1293
1325
|
const lane = cleanText(options.lane) || stored.result.lane || config.defaultLane;
|
|
1294
|
-
const lanePaths = buildLanePaths(lane, { config });
|
|
1326
|
+
const lanePaths = buildLanePaths(lane, { config, project: projectId });
|
|
1295
1327
|
const wavePath = path.join(lanePaths.wavesDir, `wave-${options.wave}.md`);
|
|
1296
1328
|
const specPath = path.join(lanePaths.wavesDir, "specs", `wave-${options.wave}.json`);
|
|
1297
1329
|
if (!options.force && (fs.existsSync(wavePath) || fs.existsSync(specPath))) {
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_CODEX_SANDBOX_MODE,
|
|
6
6
|
DEFAULT_EXECUTOR_MODE,
|
|
7
|
+
loadWaveConfig,
|
|
7
8
|
normalizeCodexSandboxMode,
|
|
8
9
|
normalizeExecutorMode,
|
|
9
10
|
SUPPORTED_EXECUTOR_MODES,
|
|
@@ -42,6 +43,7 @@ function printUsage() {
|
|
|
42
43
|
console.log(`Usage: pnpm exec wave autonomous [options]
|
|
43
44
|
|
|
44
45
|
Options:
|
|
46
|
+
--project <id> Project id
|
|
45
47
|
--lane <name> Lane name (default: ${DEFAULT_WAVE_LANE})
|
|
46
48
|
--timeout-minutes <n> Per-wave timeout passed to launcher (default: ${DEFAULT_TIMEOUT_MINUTES})
|
|
47
49
|
--max-retries-per-wave <n> Per-wave relaunches inside launcher (default: ${DEFAULT_MAX_RETRIES_PER_WAVE})
|
|
@@ -64,7 +66,9 @@ Options:
|
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
export function parseArgs(argv) {
|
|
69
|
+
const config = loadWaveConfig();
|
|
67
70
|
const options = {
|
|
71
|
+
project: config.defaultProject,
|
|
68
72
|
lane: DEFAULT_WAVE_LANE,
|
|
69
73
|
timeoutMinutes: DEFAULT_TIMEOUT_MINUTES,
|
|
70
74
|
maxRetriesPerWave: DEFAULT_MAX_RETRIES_PER_WAVE,
|
|
@@ -92,6 +96,8 @@ export function parseArgs(argv) {
|
|
|
92
96
|
}
|
|
93
97
|
if (arg === "--lane") {
|
|
94
98
|
options.lane = sanitizeLaneName(argv[++i]);
|
|
99
|
+
} else if (arg === "--project") {
|
|
100
|
+
options.project = String(argv[++i] || "").trim();
|
|
95
101
|
} else if (arg === "--timeout-minutes") {
|
|
96
102
|
options.timeoutMinutes = parsePositiveInt(argv[++i], "--timeout-minutes");
|
|
97
103
|
} else if (arg === "--max-retries-per-wave") {
|
|
@@ -132,7 +138,10 @@ export function parseArgs(argv) {
|
|
|
132
138
|
}
|
|
133
139
|
}
|
|
134
140
|
if (!executorProvided) {
|
|
135
|
-
options.executorMode = buildLanePaths(options.lane
|
|
141
|
+
options.executorMode = buildLanePaths(options.lane, {
|
|
142
|
+
config,
|
|
143
|
+
project: options.project,
|
|
144
|
+
}).executors.default;
|
|
136
145
|
}
|
|
137
146
|
options.orchestratorId ||= `${options.lane}-autonomous`;
|
|
138
147
|
if (options.executorMode === "local") {
|
|
@@ -146,8 +155,8 @@ export function parseArgs(argv) {
|
|
|
146
155
|
return { help: false, options };
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
function getWaveNumbers(lane) {
|
|
150
|
-
const lanePaths = buildLanePaths(lane);
|
|
158
|
+
function getWaveNumbers(lane, project) {
|
|
159
|
+
const lanePaths = buildLanePaths(lane, { project });
|
|
151
160
|
if (!fs.existsSync(lanePaths.wavesDir)) {
|
|
152
161
|
throw new Error(`Waves directory not found: ${path.relative(REPO_ROOT, lanePaths.wavesDir)}`);
|
|
153
162
|
}
|
|
@@ -184,27 +193,52 @@ function runCommand(args, envOverrides = {}) {
|
|
|
184
193
|
return Number.isInteger(result.status) ? result.status : 1;
|
|
185
194
|
}
|
|
186
195
|
|
|
187
|
-
function reconcile(lane) {
|
|
196
|
+
function reconcile(lane, project) {
|
|
188
197
|
return runCommand(
|
|
189
|
-
[
|
|
198
|
+
[
|
|
199
|
+
path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"),
|
|
200
|
+
"--project",
|
|
201
|
+
project,
|
|
202
|
+
"--lane",
|
|
203
|
+
lane,
|
|
204
|
+
"--reconcile-status",
|
|
205
|
+
],
|
|
190
206
|
{ [WAVE_SUPPRESS_UPDATE_NOTICE_ENV]: "1" },
|
|
191
207
|
);
|
|
192
208
|
}
|
|
193
209
|
|
|
194
|
-
function dryRun(lane) {
|
|
210
|
+
function dryRun(lane, project) {
|
|
195
211
|
return runCommand(
|
|
196
|
-
[
|
|
212
|
+
[
|
|
213
|
+
path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"),
|
|
214
|
+
"--project",
|
|
215
|
+
project,
|
|
216
|
+
"--lane",
|
|
217
|
+
lane,
|
|
218
|
+
"--dry-run",
|
|
219
|
+
"--no-dashboard",
|
|
220
|
+
],
|
|
197
221
|
{ [WAVE_SUPPRESS_UPDATE_NOTICE_ENV]: "1" },
|
|
198
222
|
);
|
|
199
223
|
}
|
|
200
224
|
|
|
201
|
-
function listPendingFeedback(lane) {
|
|
202
|
-
return runCommand([
|
|
225
|
+
function listPendingFeedback(lane, project) {
|
|
226
|
+
return runCommand([
|
|
227
|
+
path.join(PACKAGE_ROOT, "scripts", "wave-human-feedback.mjs"),
|
|
228
|
+
"list",
|
|
229
|
+
"--project",
|
|
230
|
+
project,
|
|
231
|
+
"--lane",
|
|
232
|
+
lane,
|
|
233
|
+
"--pending",
|
|
234
|
+
]);
|
|
203
235
|
}
|
|
204
236
|
|
|
205
237
|
function launchSingleWave(params) {
|
|
206
238
|
const args = [
|
|
207
239
|
path.join(PACKAGE_ROOT, "scripts", "wave-launcher.mjs"),
|
|
240
|
+
"--project",
|
|
241
|
+
params.project,
|
|
208
242
|
"--lane",
|
|
209
243
|
params.lane,
|
|
210
244
|
"--start-wave",
|
|
@@ -359,27 +393,27 @@ export async function runAutonomousCli(argv) {
|
|
|
359
393
|
}
|
|
360
394
|
await maybeAnnouncePackageUpdate();
|
|
361
395
|
const options = parsed.options;
|
|
362
|
-
const allWaves = getWaveNumbers(options.lane);
|
|
396
|
+
const allWaves = getWaveNumbers(options.lane, options.project);
|
|
363
397
|
console.log(`[autonomous] lane=${options.lane} orchestrator=${options.orchestratorId}`);
|
|
364
398
|
console.log(`[autonomous] executor=${options.executorMode}`);
|
|
365
399
|
console.log(`[autonomous] codex_sandbox=${options.codexSandboxMode}`);
|
|
366
400
|
console.log(`[autonomous] waves=${allWaves.join(", ")}`);
|
|
367
401
|
|
|
368
|
-
const dryRunStatus = dryRun(options.lane);
|
|
402
|
+
const dryRunStatus = dryRun(options.lane, options.project);
|
|
369
403
|
if (dryRunStatus !== 0) {
|
|
370
404
|
throw new Error(`[autonomous] dry-run preflight failed with status=${dryRunStatus}`);
|
|
371
405
|
}
|
|
372
|
-
const feedbackListStatus = listPendingFeedback(options.lane);
|
|
406
|
+
const feedbackListStatus = listPendingFeedback(options.lane, options.project);
|
|
373
407
|
if (feedbackListStatus !== 0) {
|
|
374
408
|
throw new Error(`[autonomous] feedback preflight failed with status=${feedbackListStatus}`);
|
|
375
409
|
}
|
|
376
|
-
const reconcileStatus = reconcile(options.lane);
|
|
410
|
+
const reconcileStatus = reconcile(options.lane, options.project);
|
|
377
411
|
if (reconcileStatus !== 0) {
|
|
378
412
|
throw new Error(`[autonomous] initial reconcile failed with status=${reconcileStatus}`);
|
|
379
413
|
}
|
|
380
414
|
|
|
381
415
|
let launchedCount = 0;
|
|
382
|
-
const lanePaths = buildLanePaths(options.lane);
|
|
416
|
+
const lanePaths = buildLanePaths(options.lane, { project: options.project });
|
|
383
417
|
while (true) {
|
|
384
418
|
const completed = readRunState(lanePaths.defaultRunStatePath).completedWaves;
|
|
385
419
|
const wave = nextIncompleteWave(allWaves, completed);
|
|
@@ -405,7 +439,7 @@ export async function runAutonomousCli(argv) {
|
|
|
405
439
|
wave,
|
|
406
440
|
attempt,
|
|
407
441
|
});
|
|
408
|
-
reconcile(options.lane);
|
|
442
|
+
reconcile(options.lane, options.project);
|
|
409
443
|
if (status === 0) {
|
|
410
444
|
launchedCount += 1;
|
|
411
445
|
success = true;
|
|
@@ -2,7 +2,6 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import {
|
|
5
|
-
DEFAULT_WAVE_LANE,
|
|
6
5
|
REPO_ROOT,
|
|
7
6
|
buildLanePaths,
|
|
8
7
|
ensureDirectory,
|
|
@@ -107,9 +106,11 @@ function escapeMarkdownCell(value) {
|
|
|
107
106
|
.replace(/\|/g, "\\|");
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
function benchmarkTelemetryLanePaths() {
|
|
109
|
+
function benchmarkTelemetryLanePaths(options = {}) {
|
|
111
110
|
try {
|
|
112
|
-
return buildLanePaths(
|
|
111
|
+
return buildLanePaths(options.lane || undefined, {
|
|
112
|
+
project: options.project || undefined,
|
|
113
|
+
});
|
|
113
114
|
} catch {
|
|
114
115
|
return null;
|
|
115
116
|
}
|
|
@@ -119,6 +120,15 @@ function benchmarkRunId(output) {
|
|
|
119
120
|
return `bench-${output.adapter.id}-${output.manifest.id}-${String(output.generatedAt || toIsoTimestamp()).replace(/[-:.TZ]/g, "").slice(0, 14)}`;
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
function flushBenchmarkTelemetryBestEffort(lanePaths) {
|
|
124
|
+
return flushWaveControlQueue(lanePaths).catch((error) => {
|
|
125
|
+
console.warn(
|
|
126
|
+
`[wave:benchmark] telemetry flush skipped: ${error instanceof Error ? error.message : String(error)}`,
|
|
127
|
+
);
|
|
128
|
+
return null;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
function reviewValidityForResult(result, output) {
|
|
123
133
|
if (result.success && output.comparisonReady) {
|
|
124
134
|
return "comparison-valid";
|
|
@@ -179,8 +189,8 @@ function externalTaskArtifacts(result) {
|
|
|
179
189
|
return artifacts;
|
|
180
190
|
}
|
|
181
191
|
|
|
182
|
-
function publishExternalBenchmarkTelemetry({ output, outputDir, failureReview }) {
|
|
183
|
-
const lanePaths = benchmarkTelemetryLanePaths();
|
|
192
|
+
function publishExternalBenchmarkTelemetry({ output, outputDir, failureReview, project, lane }) {
|
|
193
|
+
const lanePaths = benchmarkTelemetryLanePaths({ project, lane });
|
|
184
194
|
if (!lanePaths || lanePaths.waveControl?.captureBenchmarkRuns === false) {
|
|
185
195
|
return null;
|
|
186
196
|
}
|
|
@@ -338,7 +348,7 @@ function publishExternalBenchmarkTelemetry({ output, outputDir, failureReview })
|
|
|
338
348
|
},
|
|
339
349
|
});
|
|
340
350
|
}
|
|
341
|
-
void
|
|
351
|
+
void flushBenchmarkTelemetryBestEffort(lanePaths);
|
|
342
352
|
return benchmarkRunIdValue;
|
|
343
353
|
}
|
|
344
354
|
|
|
@@ -1376,7 +1386,13 @@ export function runExternalBenchmarkPilot(options = {}) {
|
|
|
1376
1386
|
writeTextAtomic(path.join(outputDir, "results.md"), `${renderExternalResultsMarkdown(output)}\n`);
|
|
1377
1387
|
writeJsonAtomic(path.join(outputDir, "failure-review.json"), failureReview);
|
|
1378
1388
|
writeTextAtomic(path.join(outputDir, "failure-review.md"), `${renderExternalFailureReviewMarkdown(failureReview)}\n`);
|
|
1379
|
-
publishExternalBenchmarkTelemetry({
|
|
1389
|
+
publishExternalBenchmarkTelemetry({
|
|
1390
|
+
output,
|
|
1391
|
+
outputDir,
|
|
1392
|
+
failureReview,
|
|
1393
|
+
project: options.project,
|
|
1394
|
+
lane: options.lane,
|
|
1395
|
+
});
|
|
1380
1396
|
return {
|
|
1381
1397
|
...output,
|
|
1382
1398
|
outputDir: path.relative(REPO_ROOT, outputDir).replaceAll(path.sep, "/"),
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
import { buildRequestAssignments } from "./routing-state.mjs";
|
|
8
8
|
import { loadBenchmarkCases, loadExternalBenchmarkAdapters } from "./benchmark-cases.mjs";
|
|
9
9
|
import {
|
|
10
|
-
DEFAULT_WAVE_LANE,
|
|
11
10
|
REPO_ROOT,
|
|
12
11
|
buildLanePaths,
|
|
13
12
|
ensureDirectory,
|
|
@@ -44,9 +43,11 @@ function normalizeId(value, label) {
|
|
|
44
43
|
return normalized;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
function benchmarkTelemetryLanePaths() {
|
|
46
|
+
function benchmarkTelemetryLanePaths(options = {}) {
|
|
48
47
|
try {
|
|
49
|
-
return buildLanePaths(
|
|
48
|
+
return buildLanePaths(options.lane || undefined, {
|
|
49
|
+
project: options.project || undefined,
|
|
50
|
+
});
|
|
50
51
|
} catch {
|
|
51
52
|
return null;
|
|
52
53
|
}
|
|
@@ -56,8 +57,17 @@ function localBenchmarkRunId(output) {
|
|
|
56
57
|
return `bench-local-${String(output.generatedAt || toIsoTimestamp()).replace(/[-:.TZ]/g, "").slice(0, 14)}`;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
function
|
|
60
|
-
|
|
60
|
+
function flushBenchmarkTelemetryBestEffort(lanePaths) {
|
|
61
|
+
return flushWaveControlQueue(lanePaths).catch((error) => {
|
|
62
|
+
console.warn(
|
|
63
|
+
`[wave:benchmark] telemetry flush skipped: ${error instanceof Error ? error.message : String(error)}`,
|
|
64
|
+
);
|
|
65
|
+
return null;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function publishLocalBenchmarkTelemetry({ output, outputDir, project, lane }) {
|
|
70
|
+
const lanePaths = benchmarkTelemetryLanePaths({ project, lane });
|
|
61
71
|
if (!lanePaths || lanePaths.waveControl?.captureBenchmarkRuns === false) {
|
|
62
72
|
return null;
|
|
63
73
|
}
|
|
@@ -140,7 +150,7 @@ function publishLocalBenchmarkTelemetry({ output, outputDir }) {
|
|
|
140
150
|
});
|
|
141
151
|
}
|
|
142
152
|
}
|
|
143
|
-
void
|
|
153
|
+
void flushBenchmarkTelemetryBestEffort(lanePaths);
|
|
144
154
|
return benchmarkRunIdValue;
|
|
145
155
|
}
|
|
146
156
|
|
|
@@ -718,7 +728,12 @@ export function runBenchmarkSuite(options = {}) {
|
|
|
718
728
|
ensureDirectory(outputDir);
|
|
719
729
|
writeJsonAtomic(path.join(outputDir, "results.json"), output);
|
|
720
730
|
writeTextAtomic(path.join(outputDir, "results.md"), `${renderMarkdownReport(output)}\n`);
|
|
721
|
-
publishLocalBenchmarkTelemetry({
|
|
731
|
+
publishLocalBenchmarkTelemetry({
|
|
732
|
+
output,
|
|
733
|
+
outputDir,
|
|
734
|
+
project: options.project,
|
|
735
|
+
lane: options.lane,
|
|
736
|
+
});
|
|
722
737
|
output.outputDir = path.relative(REPO_ROOT, outputDir).replaceAll(path.sep, "/");
|
|
723
738
|
}
|
|
724
739
|
return output;
|
|
@@ -728,12 +743,12 @@ function printUsage() {
|
|
|
728
743
|
console.log(`Usage:
|
|
729
744
|
wave benchmark list [--json]
|
|
730
745
|
wave benchmark show --case <id> [--json]
|
|
731
|
-
wave benchmark run [--case <id>] [--family <id>] [--benchmark <id>] [--arm <id>] [--output-dir <path>] [--json]
|
|
746
|
+
wave benchmark run [--project <id>] [--lane <lane>] [--case <id>] [--family <id>] [--benchmark <id>] [--arm <id>] [--output-dir <path>] [--json]
|
|
732
747
|
wave benchmark adapters [--json]
|
|
733
748
|
wave benchmark external-list [--json]
|
|
734
749
|
wave benchmark external-show --adapter <id> [--json]
|
|
735
|
-
wave benchmark external-pilots [--json]
|
|
736
|
-
wave benchmark external-run --adapter <id> [--manifest <path>] [--task <id>] [--arm <id>] [--dry-run] [--command-config <path>] [run options] [--json]
|
|
750
|
+
wave benchmark external-pilots [--project <id>] [--lane <lane>] [--json]
|
|
751
|
+
wave benchmark external-run --adapter <id> [--project <id>] [--lane <lane>] [--manifest <path>] [--task <id>] [--arm <id>] [--dry-run] [--command-config <path>] [run options] [--json]
|
|
737
752
|
`);
|
|
738
753
|
}
|
|
739
754
|
|
|
@@ -741,6 +756,8 @@ function parseArgs(argv) {
|
|
|
741
756
|
const args = Array.isArray(argv) ? argv.slice() : [];
|
|
742
757
|
const subcommand = cleanText(args.shift()).toLowerCase();
|
|
743
758
|
const options = {
|
|
759
|
+
project: "",
|
|
760
|
+
lane: "",
|
|
744
761
|
json: false,
|
|
745
762
|
caseIds: [],
|
|
746
763
|
familyIds: [],
|
|
@@ -768,6 +785,10 @@ function parseArgs(argv) {
|
|
|
768
785
|
const arg = args[index];
|
|
769
786
|
if (arg === "--json") {
|
|
770
787
|
options.json = true;
|
|
788
|
+
} else if (arg === "--project") {
|
|
789
|
+
options.project = cleanText(args[++index]);
|
|
790
|
+
} else if (arg === "--lane") {
|
|
791
|
+
options.lane = cleanText(args[++index]);
|
|
771
792
|
} else if (arg === "--case") {
|
|
772
793
|
options.caseIds.push(args[++index]);
|
|
773
794
|
} else if (arg === "--family") {
|
|
@@ -929,6 +950,8 @@ export async function runBenchmarkCli(argv) {
|
|
|
929
950
|
throw new Error("wave benchmark external-run requires --adapter <id>");
|
|
930
951
|
}
|
|
931
952
|
const output = runExternalBenchmarkPilot({
|
|
953
|
+
project: options.project || undefined,
|
|
954
|
+
lane: options.lane || undefined,
|
|
932
955
|
adapterId: options.adapterId,
|
|
933
956
|
manifestPath: options.manifestPath || undefined,
|
|
934
957
|
taskIds: options.taskIds,
|