@chllming/wave-orchestration 0.9.1 → 0.9.2
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 +30 -1
- package/LICENSE.md +21 -0
- package/README.md +18 -6
- package/docs/README.md +8 -4
- package/docs/agents/wave-security-role.md +1 -0
- package/docs/architecture/README.md +1 -1
- package/docs/concepts/operating-modes.md +1 -1
- package/docs/guides/author-and-run-waves.md +1 -1
- package/docs/guides/planner.md +2 -2
- package/docs/guides/{recommendations-0.9.1.md → recommendations-0.9.2.md} +7 -7
- package/docs/guides/sandboxed-environments.md +2 -2
- package/docs/plans/current-state.md +8 -2
- package/docs/plans/end-state-architecture.md +1 -1
- package/docs/plans/examples/wave-example-design-handoff.md +1 -1
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +42 -18
- package/docs/reference/cli-reference.md +1 -1
- package/docs/reference/coordination-and-closure.md +18 -1
- package/docs/reference/corridor.md +225 -0
- package/docs/reference/npmjs-token-publishing.md +2 -2
- package/docs/reference/package-publishing-flow.md +11 -11
- package/docs/reference/runtime-config/README.md +61 -3
- package/docs/reference/sample-waves.md +5 -5
- package/docs/reference/skills.md +1 -1
- package/docs/reference/wave-control.md +358 -27
- package/docs/roadmap.md +12 -19
- package/package.json +1 -1
- package/releases/manifest.json +22 -3
- package/scripts/wave-cli-bootstrap.mjs +52 -1
- package/scripts/wave-orchestrator/config.mjs +199 -3
- package/scripts/wave-orchestrator/context7.mjs +231 -29
- package/scripts/wave-orchestrator/coordination.mjs +14 -0
- package/scripts/wave-orchestrator/corridor.mjs +363 -0
- package/scripts/wave-orchestrator/derived-state-engine.mjs +38 -1
- package/scripts/wave-orchestrator/gate-engine.mjs +20 -0
- package/scripts/wave-orchestrator/install.mjs +34 -1
- package/scripts/wave-orchestrator/launcher-runtime.mjs +111 -7
- package/scripts/wave-orchestrator/planner.mjs +1 -0
- package/scripts/wave-orchestrator/projection-writer.mjs +23 -0
- package/scripts/wave-orchestrator/provider-runtime.mjs +104 -0
- package/scripts/wave-orchestrator/shared.mjs +1 -0
- package/scripts/wave-orchestrator/traces.mjs +25 -0
- package/scripts/wave-orchestrator/wave-control-client.mjs +14 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { buildExecutionPrompt } from "./coordination.mjs";
|
|
4
|
+
import {
|
|
5
|
+
materializeWaveCorridorContext,
|
|
6
|
+
renderCorridorPromptContext,
|
|
7
|
+
waveCorridorContextPath,
|
|
8
|
+
} from "./corridor.mjs";
|
|
4
9
|
import {
|
|
5
10
|
DEFAULT_AGENT_RATE_LIMIT_BASE_DELAY_SECONDS,
|
|
6
11
|
DEFAULT_AGENT_RATE_LIMIT_MAX_DELAY_SECONDS,
|
|
@@ -15,7 +20,12 @@ import {
|
|
|
15
20
|
import { readStatusCodeIfPresent } from "./dashboard-state.mjs";
|
|
16
21
|
import { buildExecutorLaunchSpec } from "./executors.mjs";
|
|
17
22
|
import { hashAgentPromptFingerprint, prefetchContext7ForSelection } from "./context7.mjs";
|
|
18
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
isDesignAgent,
|
|
25
|
+
isSecurityReviewAgent,
|
|
26
|
+
resolveDesignReportPath,
|
|
27
|
+
resolveWaveRoleBindings,
|
|
28
|
+
} from "./role-helpers.mjs";
|
|
19
29
|
import {
|
|
20
30
|
resolveAgentSkills,
|
|
21
31
|
summarizeResolvedSkills,
|
|
@@ -30,6 +40,44 @@ import {
|
|
|
30
40
|
spawnAgentProcessRunner,
|
|
31
41
|
terminateAgentProcessRuntime,
|
|
32
42
|
} from "./agent-process-runner.mjs";
|
|
43
|
+
import {
|
|
44
|
+
requestWaveControlCredentialEnv,
|
|
45
|
+
requestWaveControlProviderEnv,
|
|
46
|
+
} from "./provider-runtime.mjs";
|
|
47
|
+
|
|
48
|
+
function redactPreviewEnv(env = {}, redactedKeys = []) {
|
|
49
|
+
const output = { ...(env || {}) };
|
|
50
|
+
for (const key of redactedKeys) {
|
|
51
|
+
if (Object.prototype.hasOwnProperty.call(output, key)) {
|
|
52
|
+
output[key] = "[redacted]";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return output;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function buildDryRunContext7Preview(selection) {
|
|
59
|
+
if (
|
|
60
|
+
!selection ||
|
|
61
|
+
selection.bundleId === "none" ||
|
|
62
|
+
!Array.isArray(selection.libraries) ||
|
|
63
|
+
selection.libraries.length === 0
|
|
64
|
+
) {
|
|
65
|
+
return {
|
|
66
|
+
mode: "none",
|
|
67
|
+
selection,
|
|
68
|
+
promptText: "",
|
|
69
|
+
snippetHash: "",
|
|
70
|
+
warning: "",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
mode: "dry-run",
|
|
75
|
+
selection,
|
|
76
|
+
promptText: "",
|
|
77
|
+
snippetHash: "",
|
|
78
|
+
warning: "Context7 prefetch skipped during dry-run preview.",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
33
81
|
|
|
34
82
|
export function refreshResolvedSkillsForRun(runInfo, waveDefinition, lanePaths) {
|
|
35
83
|
runInfo.agent.skillsResolved = resolveAgentSkills(
|
|
@@ -141,13 +189,31 @@ export async function launchAgentSession(
|
|
|
141
189
|
fs.rmSync(runtimePath, { force: true });
|
|
142
190
|
}
|
|
143
191
|
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
192
|
+
const resolvedWaveDefinition = waveDefinition || { deployEnvironments: [] };
|
|
193
|
+
const context7 = dryRun
|
|
194
|
+
? buildDryRunContext7Preview(agent.context7Resolved || null)
|
|
195
|
+
: await prefetchContext7ForSelection(agent.context7Resolved, {
|
|
196
|
+
lanePaths,
|
|
197
|
+
cacheDir: lanePaths.context7CacheDir,
|
|
198
|
+
disabled: !context7Enabled,
|
|
199
|
+
});
|
|
200
|
+
const integrationAgentId =
|
|
201
|
+
waveDefinition?.integrationAgentId || lanePaths.integrationAgentId || "A8";
|
|
202
|
+
const shouldLoadCorridorContext =
|
|
203
|
+
lanePaths.externalProviders?.corridor?.enabled === true &&
|
|
204
|
+
(isSecurityReviewAgent(agent) || agent.agentId === integrationAgentId);
|
|
205
|
+
const corridorContext = !dryRun && shouldLoadCorridorContext
|
|
206
|
+
? await materializeWaveCorridorContext(lanePaths, resolvedWaveDefinition)
|
|
207
|
+
: null;
|
|
208
|
+
const corridorContextPath = !dryRun && shouldLoadCorridorContext
|
|
209
|
+
? waveCorridorContextPath(lanePaths, wave)
|
|
210
|
+
: null;
|
|
211
|
+
const corridorContextText =
|
|
212
|
+
dryRun && shouldLoadCorridorContext
|
|
213
|
+
? "Corridor context omitted in dry-run preview."
|
|
214
|
+
: renderCorridorPromptContext(corridorContext);
|
|
148
215
|
const overlayDir = path.join(lanePaths.executorOverlaysDir, `wave-${wave}`, agent.slug);
|
|
149
216
|
ensureDirectory(overlayDir);
|
|
150
|
-
const resolvedWaveDefinition = waveDefinition || { deployEnvironments: [] };
|
|
151
217
|
const skillsResolved =
|
|
152
218
|
agent.skillsResolved ||
|
|
153
219
|
resolveAgentSkills(agent, resolvedWaveDefinition, {
|
|
@@ -176,6 +242,8 @@ export async function launchAgentSession(
|
|
|
176
242
|
inboxPath,
|
|
177
243
|
inboxText,
|
|
178
244
|
context7,
|
|
245
|
+
corridorContextPath,
|
|
246
|
+
corridorContextText,
|
|
179
247
|
componentPromotions: resolvedWaveDefinition.componentPromotions,
|
|
180
248
|
evalTargets: resolvedWaveDefinition.evalTargets,
|
|
181
249
|
benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
|
|
@@ -201,11 +269,45 @@ export async function launchAgentSession(
|
|
|
201
269
|
overlayDir,
|
|
202
270
|
skillProjection: agent.skillsResolved,
|
|
203
271
|
});
|
|
272
|
+
const requestedCredentialProviders = Array.isArray(lanePaths.waveControl?.credentialProviders)
|
|
273
|
+
? lanePaths.waveControl.credentialProviders
|
|
274
|
+
: [];
|
|
275
|
+
const requestedCredentials = Array.isArray(lanePaths.waveControl?.credentials)
|
|
276
|
+
? lanePaths.waveControl.credentials
|
|
277
|
+
: [];
|
|
278
|
+
const leasedProviderEnv =
|
|
279
|
+
!dryRun && requestedCredentialProviders.length > 0
|
|
280
|
+
? await requestWaveControlProviderEnv(fetch, lanePaths.waveControl, requestedCredentialProviders)
|
|
281
|
+
: {};
|
|
282
|
+
const leasedCredentialEnv =
|
|
283
|
+
!dryRun && requestedCredentials.length > 0
|
|
284
|
+
? await requestWaveControlCredentialEnv(fetch, lanePaths.waveControl, requestedCredentials)
|
|
285
|
+
: {};
|
|
286
|
+
const overlappingLeasedEnvVars = Object.keys(leasedProviderEnv).filter((key) =>
|
|
287
|
+
Object.prototype.hasOwnProperty.call(leasedCredentialEnv, key),
|
|
288
|
+
);
|
|
289
|
+
if (overlappingLeasedEnvVars.length > 0) {
|
|
290
|
+
throw new Error(
|
|
291
|
+
`Wave Control leased duplicate environment variables: ${overlappingLeasedEnvVars.join(", ")}.`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
const leasedEnv = {
|
|
295
|
+
...leasedProviderEnv,
|
|
296
|
+
...leasedCredentialEnv,
|
|
297
|
+
};
|
|
298
|
+
if (Object.keys(leasedEnv).length > 0) {
|
|
299
|
+
launchSpec.env = {
|
|
300
|
+
...(launchSpec.env || {}),
|
|
301
|
+
...leasedEnv,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
204
304
|
const resolvedExecutorMode = launchSpec.executorId || agent.executorResolved?.id || "codex";
|
|
205
305
|
writeJsonAtomic(path.join(overlayDir, "launch-preview.json"), {
|
|
206
306
|
executorId: resolvedExecutorMode,
|
|
207
307
|
command: launchSpec.command,
|
|
208
|
-
env: launchSpec.env || {},
|
|
308
|
+
env: redactPreviewEnv(launchSpec.env || {}, Object.keys(leasedEnv)),
|
|
309
|
+
credentialProviders: requestedCredentialProviders,
|
|
310
|
+
credentials: requestedCredentials,
|
|
209
311
|
useRateLimitRetries: launchSpec.useRateLimitRetries === true,
|
|
210
312
|
invocationLines: launchSpec.invocationLines,
|
|
211
313
|
limits: launchSpec.limits || null,
|
|
@@ -215,6 +317,7 @@ export async function launchAgentSession(
|
|
|
215
317
|
return {
|
|
216
318
|
promptHash,
|
|
217
319
|
context7,
|
|
320
|
+
corridorContext,
|
|
218
321
|
executorId: resolvedExecutorMode,
|
|
219
322
|
launchSpec,
|
|
220
323
|
dryRun: true,
|
|
@@ -339,6 +442,7 @@ export async function launchAgentSession(
|
|
|
339
442
|
return {
|
|
340
443
|
promptHash,
|
|
341
444
|
context7,
|
|
445
|
+
corridorContext,
|
|
342
446
|
executorId: resolvedExecutorMode,
|
|
343
447
|
skills: summarizeResolvedSkills(agent.skillsResolved),
|
|
344
448
|
runtimePath,
|
|
@@ -2625,6 +2625,7 @@ async function runAgenticDraftFlow(options = {}) {
|
|
|
2625
2625
|
request,
|
|
2626
2626
|
});
|
|
2627
2627
|
const plannerContext7Prefetch = await prefetchContext7ForSelection(plannerContext7Selection, {
|
|
2628
|
+
lanePaths,
|
|
2628
2629
|
cacheDir: lanePaths.context7CacheDir,
|
|
2629
2630
|
});
|
|
2630
2631
|
const promptText = buildPlannerPromptText({
|
|
@@ -126,6 +126,8 @@ export function writeWaveAttemptTraceProjection({
|
|
|
126
126
|
capabilityAssignments: derivedState.capabilityAssignments,
|
|
127
127
|
dependencySnapshot: derivedState.dependencySnapshot,
|
|
128
128
|
securitySummary: derivedState.securitySummary,
|
|
129
|
+
corridorSummary: derivedState.corridorSummary,
|
|
130
|
+
corridorSummaryPath: derivedState.corridorSummaryPath,
|
|
129
131
|
integrationSummary: derivedState.integrationSummary,
|
|
130
132
|
integrationMarkdownPath: derivedState.integrationMarkdownPath,
|
|
131
133
|
proofRegistryPath: lanePaths.proofDir ? waveProofRegistryPath(lanePaths, wave.wave) : null,
|
|
@@ -191,6 +193,7 @@ export function writeWaveRelaunchProjection({
|
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
function renderWaveSecuritySummaryMarkdown(securitySummary) {
|
|
196
|
+
const corridor = securitySummary?.corridor || null;
|
|
194
197
|
return [
|
|
195
198
|
`# Wave ${securitySummary.wave} Security Summary`,
|
|
196
199
|
"",
|
|
@@ -199,7 +202,18 @@ function renderWaveSecuritySummaryMarkdown(securitySummary) {
|
|
|
199
202
|
`- Total findings: ${securitySummary.totalFindings || 0}`,
|
|
200
203
|
`- Total approvals: ${securitySummary.totalApprovals || 0}`,
|
|
201
204
|
`- Reviewers: ${(securitySummary.agents || []).length}`,
|
|
205
|
+
`- Corridor: ${corridor ? (corridor.ok ? (corridor.blocking ? "blocking" : "clear") : "fetch-failed") : "not-configured"}`,
|
|
202
206
|
"",
|
|
207
|
+
...(corridor
|
|
208
|
+
? [
|
|
209
|
+
"## Corridor",
|
|
210
|
+
`- Source: ${corridor.source || corridor.providerMode || "unknown"}`,
|
|
211
|
+
`- Matched findings: ${(corridor.matchedFindings || []).length}`,
|
|
212
|
+
`- Blocking findings: ${(corridor.blockingFindings || []).length}`,
|
|
213
|
+
...(corridor.error ? [`- Error: ${corridor.error}`] : []),
|
|
214
|
+
"",
|
|
215
|
+
]
|
|
216
|
+
: []),
|
|
203
217
|
"## Reviews",
|
|
204
218
|
...((securitySummary.agents || []).length > 0
|
|
205
219
|
? securitySummary.agents.map(
|
|
@@ -220,6 +234,7 @@ function renderIntegrationSection(title, items) {
|
|
|
220
234
|
}
|
|
221
235
|
|
|
222
236
|
function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
237
|
+
const corridor = integrationSummary?.corridor || null;
|
|
223
238
|
return [
|
|
224
239
|
`# Wave ${integrationSummary.wave} Integration Summary`,
|
|
225
240
|
"",
|
|
@@ -239,6 +254,7 @@ function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
|
239
254
|
`- Inbound dependencies: ${(integrationSummary.inboundDependencies || []).length}`,
|
|
240
255
|
`- Outbound dependencies: ${(integrationSummary.outboundDependencies || []).length}`,
|
|
241
256
|
`- Helper assignments: ${(integrationSummary.helperAssignments || []).length}`,
|
|
257
|
+
`- Corridor blocking findings: ${(corridor?.blockingFindings || []).length}`,
|
|
242
258
|
"",
|
|
243
259
|
...renderIntegrationSection("## Open Claims", integrationSummary.openClaims),
|
|
244
260
|
...renderIntegrationSection("## Conflicting Claims", integrationSummary.conflictingClaims),
|
|
@@ -251,6 +267,13 @@ function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
|
251
267
|
...renderIntegrationSection("## Proof Gaps", integrationSummary.proofGaps),
|
|
252
268
|
...renderIntegrationSection("## Deploy Risks", integrationSummary.deployRisks),
|
|
253
269
|
...renderIntegrationSection("## Security Findings", integrationSummary.securityFindings),
|
|
270
|
+
...renderIntegrationSection(
|
|
271
|
+
"## Corridor Findings",
|
|
272
|
+
corridor?.matchedFindings?.map(
|
|
273
|
+
(finding) =>
|
|
274
|
+
`${finding.severity || "unknown"} ${finding.affectedFile || "unknown-file"}: ${finding.title || "finding"}`,
|
|
275
|
+
) || [],
|
|
276
|
+
),
|
|
254
277
|
...renderIntegrationSection("## Security Approvals", integrationSummary.securityApprovals),
|
|
255
278
|
...renderIntegrationSection("## Inbound Dependencies", integrationSummary.inboundDependencies),
|
|
256
279
|
...renderIntegrationSection("## Outbound Dependencies", integrationSummary.outboundDependencies),
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { DEFAULT_WAVE_CONTROL_ENDPOINT } from "./config.mjs";
|
|
2
|
+
|
|
3
|
+
export function resolveEnvValue(envVars, env = process.env) {
|
|
4
|
+
for (const envVar of Array.isArray(envVars) ? envVars : [envVars]) {
|
|
5
|
+
const value = envVar ? String(env[envVar] || "").trim() : "";
|
|
6
|
+
if (value) {
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function resolveWaveControlAuthToken(waveControl = {}, env = process.env) {
|
|
14
|
+
const envVars = Array.isArray(waveControl?.authTokenEnvVars)
|
|
15
|
+
? waveControl.authTokenEnvVars
|
|
16
|
+
: [waveControl?.authTokenEnvVar].filter(Boolean);
|
|
17
|
+
return resolveEnvValue(envVars, env);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isDefaultWaveControlEndpoint(endpoint) {
|
|
21
|
+
const normalized = String(endpoint || "").trim().replace(/\/+$/, "");
|
|
22
|
+
return normalized === String(DEFAULT_WAVE_CONTROL_ENDPOINT).trim().replace(/\/+$/, "");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function readJsonResponse(response, fallback = null) {
|
|
26
|
+
try {
|
|
27
|
+
return await response.json();
|
|
28
|
+
} catch {
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function requestProvider(fetchImpl, url, options = {}) {
|
|
34
|
+
const response = await fetchImpl(url, options);
|
|
35
|
+
if (response.ok) {
|
|
36
|
+
return response;
|
|
37
|
+
}
|
|
38
|
+
const payload = await readJsonResponse(response, null);
|
|
39
|
+
throw new Error(
|
|
40
|
+
`${options.method || "GET"} ${url} failed (${response.status}): ${payload?.error || payload?.message || response.statusText || "unknown error"}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function requestWaveControlProviderEnv(fetchImpl, waveControl = {}, providers = []) {
|
|
45
|
+
const endpoint = String(waveControl.endpoint || DEFAULT_WAVE_CONTROL_ENDPOINT).trim();
|
|
46
|
+
if (!endpoint) {
|
|
47
|
+
throw new Error("Wave Control endpoint is not configured.");
|
|
48
|
+
}
|
|
49
|
+
if (isDefaultWaveControlEndpoint(endpoint)) {
|
|
50
|
+
throw new Error("Wave Control provider credential leasing requires an owned Wave Control deployment.");
|
|
51
|
+
}
|
|
52
|
+
const token = resolveWaveControlAuthToken(waveControl);
|
|
53
|
+
if (!token) {
|
|
54
|
+
throw new Error("WAVE_API_TOKEN is not set; Wave Control credential leasing is unavailable.");
|
|
55
|
+
}
|
|
56
|
+
const response = await requestProvider(
|
|
57
|
+
fetchImpl,
|
|
58
|
+
`${endpoint.replace(/\/$/, "")}/runtime/provider-env`,
|
|
59
|
+
{
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
authorization: `Bearer ${token}`,
|
|
63
|
+
"content-type": "application/json",
|
|
64
|
+
accept: "application/json",
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({ providers }),
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
const payload = await readJsonResponse(response, null);
|
|
70
|
+
return payload?.env && typeof payload.env === "object" && !Array.isArray(payload.env)
|
|
71
|
+
? payload.env
|
|
72
|
+
: {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function requestWaveControlCredentialEnv(fetchImpl, waveControl = {}, credentials = []) {
|
|
76
|
+
const endpoint = String(waveControl.endpoint || DEFAULT_WAVE_CONTROL_ENDPOINT).trim();
|
|
77
|
+
if (!endpoint) {
|
|
78
|
+
throw new Error("Wave Control endpoint is not configured.");
|
|
79
|
+
}
|
|
80
|
+
if (isDefaultWaveControlEndpoint(endpoint)) {
|
|
81
|
+
throw new Error("Wave Control credential leasing requires an owned Wave Control deployment.");
|
|
82
|
+
}
|
|
83
|
+
const token = resolveWaveControlAuthToken(waveControl);
|
|
84
|
+
if (!token) {
|
|
85
|
+
throw new Error("WAVE_API_TOKEN is not set; Wave Control credential leasing is unavailable.");
|
|
86
|
+
}
|
|
87
|
+
const response = await requestProvider(
|
|
88
|
+
fetchImpl,
|
|
89
|
+
`${endpoint.replace(/\/$/, "")}/runtime/credential-env`,
|
|
90
|
+
{
|
|
91
|
+
method: "POST",
|
|
92
|
+
headers: {
|
|
93
|
+
authorization: `Bearer ${token}`,
|
|
94
|
+
"content-type": "application/json",
|
|
95
|
+
accept: "application/json",
|
|
96
|
+
},
|
|
97
|
+
body: JSON.stringify({ credentials }),
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
const payload = await readJsonResponse(response, null);
|
|
101
|
+
return payload?.env && typeof payload.env === "object" && !Array.isArray(payload.env)
|
|
102
|
+
? payload.env
|
|
103
|
+
: {};
|
|
104
|
+
}
|
|
@@ -279,6 +279,7 @@ export function buildLanePaths(laneInput = DEFAULT_WAVE_LANE, options = {}) {
|
|
|
279
279
|
executors: laneProfile.executors,
|
|
280
280
|
skills: laneProfile.skills,
|
|
281
281
|
capabilityRouting: laneProfile.capabilityRouting,
|
|
282
|
+
externalProviders: laneProfile.externalProviders,
|
|
282
283
|
projectId: buildTelemetryProjectId(laneProfile.waveControl || { projectId }),
|
|
283
284
|
projectRootDir: path.join(REPO_ROOT, laneProfile.projectRootDir || "."),
|
|
284
285
|
runtimeVersion: readRuntimeVersion(),
|
|
@@ -798,6 +798,8 @@ export function writeTraceBundle({
|
|
|
798
798
|
capabilityAssignments = [],
|
|
799
799
|
dependencySnapshot = null,
|
|
800
800
|
securitySummary = null,
|
|
801
|
+
corridorSummary = null,
|
|
802
|
+
corridorSummaryPath = null,
|
|
801
803
|
integrationSummary,
|
|
802
804
|
integrationMarkdownPath,
|
|
803
805
|
proofRegistryPath = null,
|
|
@@ -860,6 +862,28 @@ export function writeTraceBundle({
|
|
|
860
862
|
"json",
|
|
861
863
|
true,
|
|
862
864
|
);
|
|
865
|
+
const corridorArtifact =
|
|
866
|
+
corridorSummaryPath || corridorSummary
|
|
867
|
+
? corridorSummaryPath
|
|
868
|
+
? copyArtifactDescriptor(
|
|
869
|
+
dir,
|
|
870
|
+
corridorSummaryPath,
|
|
871
|
+
path.join(dir, "corridor.json"),
|
|
872
|
+
false,
|
|
873
|
+
)
|
|
874
|
+
: writeArtifactDescriptor(
|
|
875
|
+
dir,
|
|
876
|
+
path.join(dir, "corridor.json"),
|
|
877
|
+
corridorSummary || {},
|
|
878
|
+
"json",
|
|
879
|
+
false,
|
|
880
|
+
)
|
|
881
|
+
: {
|
|
882
|
+
path: "corridor.json",
|
|
883
|
+
required: false,
|
|
884
|
+
present: false,
|
|
885
|
+
sha256: null,
|
|
886
|
+
};
|
|
863
887
|
const integrationArtifact = writeArtifactDescriptor(
|
|
864
888
|
dir,
|
|
865
889
|
path.join(dir, "integration.json"),
|
|
@@ -1023,6 +1047,7 @@ export function writeTraceBundle({
|
|
|
1023
1047
|
capabilityAssignments: capabilityAssignmentsArtifact,
|
|
1024
1048
|
dependencySnapshot: dependencySnapshotArtifact,
|
|
1025
1049
|
security: securityArtifact,
|
|
1050
|
+
corridor: corridorArtifact,
|
|
1026
1051
|
integration: integrationArtifact,
|
|
1027
1052
|
integrationMarkdown: integrationMarkdownArtifact,
|
|
1028
1053
|
proofRegistry: proofRegistryArtifact,
|
|
@@ -154,6 +154,19 @@ function resolveWaveControlConfig(lanePaths, overrides = {}) {
|
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
function resolveWaveControlAuthToken(config) {
|
|
158
|
+
const authVars = Array.isArray(config.authTokenEnvVars)
|
|
159
|
+
? config.authTokenEnvVars
|
|
160
|
+
: [config.authTokenEnvVar].filter(Boolean);
|
|
161
|
+
for (const envVar of authVars) {
|
|
162
|
+
const value = envVar ? String(process.env[envVar] || "").trim() : "";
|
|
163
|
+
if (value) {
|
|
164
|
+
return value;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return "";
|
|
168
|
+
}
|
|
169
|
+
|
|
157
170
|
function buildWorkspaceId(lanePaths, config) {
|
|
158
171
|
return normalizeText(config.workspaceId, buildWorkspaceTmuxToken(REPO_ROOT));
|
|
159
172
|
}
|
|
@@ -505,7 +518,7 @@ export async function flushWaveControlQueue(lanePaths, options = {}) {
|
|
|
505
518
|
|
|
506
519
|
try {
|
|
507
520
|
const ingestUrl = resolveIngestUrl(config.endpoint);
|
|
508
|
-
const authToken = config
|
|
521
|
+
const authToken = resolveWaveControlAuthToken(config);
|
|
509
522
|
await postBatch(
|
|
510
523
|
ingestUrl,
|
|
511
524
|
authToken,
|