@aiwg/cli 2026.8.16 → 2026.8.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aiwg.mjs +24 -2
- package/dist/src/a2a/agent-card.js +4 -1
- package/dist/src/a2a/client.js +148 -68
- package/dist/src/a2a/codecs.js +480 -0
- package/dist/src/a2a/events.js +226 -0
- package/dist/src/a2a/hitl-driver.js +8 -6
- package/dist/src/a2a/hitl.js +2 -1
- package/dist/src/a2a/http.js +85 -5
- package/dist/src/a2a/protocol.js +136 -0
- package/dist/src/a2a/types.js +4 -14
- package/dist/src/a2a/webhook.js +101 -4
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/cli.js +1 -1
- package/dist/src/artifacts/fortemi-core-query-adapter.js +6 -0
- package/dist/src/artifacts/types.js +73 -1
- package/dist/src/audit/operator-decision.js +15 -1
- package/dist/src/channel/manager.mjs +89 -17
- package/dist/src/cli/agent-spawn.js +4 -2
- package/dist/src/cli/handlers/cockpit.js +41 -0
- package/dist/src/cli/handlers/help.js +1 -1
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/installation.js +79 -0
- package/dist/src/cli/handlers/ralph.js +2 -1
- package/dist/src/cli/handlers/refresh.js +4 -2
- package/dist/src/cli/handlers/runtime-info.js +9 -1
- package/dist/src/cli/handlers/sdlc-accelerate.js +2 -1
- package/dist/src/cli/handlers/serve.js +107 -4
- package/dist/src/cli/handlers/session.js +12 -26
- package/dist/src/cli/handlers/use.js +117 -12
- package/dist/src/cli/handlers/utilities.js +4 -0
- package/dist/src/cli/handlers/version.js +4 -0
- package/dist/src/cli/handlers/workspace.js +24 -2
- package/dist/src/cli/services/deployment-verification.js +9 -2
- package/dist/src/cockpit/doctor.js +257 -0
- package/dist/src/config/aiwg-config.js +36 -3
- package/dist/src/config/user-config-dir.mjs +29 -0
- package/dist/src/config/user-config.js +4 -22
- package/dist/src/extensions/commands/definitions.js +20 -1
- package/dist/src/features/catalog.js +2 -1
- package/dist/src/flow/graph-metadata.js +56 -0
- package/dist/src/installation/manager.mjs +243 -0
- package/dist/src/providers/transformation-receipt-integration.js +130 -3
- package/dist/src/security/artifact-verifier.js +7 -1
- package/dist/src/serve/a2a-terminal-observer.js +28 -5
- package/dist/src/serve/dispatch-router.js +32 -4
- package/dist/src/serve/executor-registry.js +29 -0
- package/dist/src/serve/mission-conductor.js +15 -1
- package/dist/src/serve/pty-bridge.js +6 -11
- package/dist/src/serve/stack-adapters.js +2 -1
- package/dist/src/serve/telemetry.js +5 -1
- package/dist/src/skills/run.js +15 -6
- package/dist/src/update/checker.mjs +16 -15
- package/dist/src/update/notifier.mjs +8 -3
- package/dist/src/update/service.mjs +49 -5
- package/package.json +2 -1
|
@@ -91,7 +91,7 @@ function displayHelp() {
|
|
|
91
91
|
]);
|
|
92
92
|
helpGroup('FEATURES', [
|
|
93
93
|
['features', 'Show optional feature install status'],
|
|
94
|
-
['cockpit [--status]', 'Launch
|
|
94
|
+
['cockpit [--status|doctor]', 'Launch Cockpit or diagnose its executor topology'],
|
|
95
95
|
]);
|
|
96
96
|
helpGroup('VALIDATION', [
|
|
97
97
|
['validate-metadata [path]', 'Validate AIWG component metadata (defaults to agentic/code)'],
|
|
@@ -63,12 +63,13 @@ import { costReportHandler } from './cost-report.js';
|
|
|
63
63
|
import { evidenceHandler } from './evidence.js';
|
|
64
64
|
import { artifactVerifyHandler } from './artifact-verify.js';
|
|
65
65
|
import { outputModeHandler } from './output-mode.js';
|
|
66
|
+
import { installationHandler } from './installation.js';
|
|
66
67
|
// Re-export individual handlers
|
|
67
68
|
export {
|
|
68
69
|
// Maintenance
|
|
69
70
|
helpHandler, versionHandler, authHandler, doctorHandler, contextFirewallHandler, updateHandler, refreshHandler, regenerateHandler, workspaceContextHandler,
|
|
70
71
|
// Framework management
|
|
71
|
-
useHandler, listHandler, removeHandler, promoteHandler, installHandler, packagesHandler, marketplaceHandler, initHandler, setupHandler, setupGenerateHandler, setupRunHandler, setupValidateHandler, issueHandler, issueAuditHandler, runHandler, jobHandler, costReportHandler, evidenceHandler, artifactVerifyHandler, outputModeHandler,
|
|
72
|
+
useHandler, listHandler, removeHandler, promoteHandler, installHandler, packagesHandler, marketplaceHandler, initHandler, setupHandler, setupGenerateHandler, setupRunHandler, setupValidateHandler, issueHandler, issueAuditHandler, runHandler, jobHandler, costReportHandler, evidenceHandler, artifactVerifyHandler, outputModeHandler, installationHandler,
|
|
72
73
|
// Project
|
|
73
74
|
newBundleHandler, quickrefHandler, newProjectHandler, sessionHandler, sessionsHandler,
|
|
74
75
|
// Workspace
|
|
@@ -125,6 +126,7 @@ export const allHandlers = [
|
|
|
125
126
|
contextFirewallHandler,
|
|
126
127
|
updateHandler,
|
|
127
128
|
refreshHandler,
|
|
129
|
+
installationHandler,
|
|
128
130
|
regenerateHandler,
|
|
129
131
|
workspaceContextHandler,
|
|
130
132
|
// Framework management
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { getPackageRoot } from '../../channel/manager.mjs';
|
|
2
|
+
import { adoptInstallation, inspectInstallation, loadInstallationIdentity, switchInstallation, } from '../../installation/manager.mjs';
|
|
3
|
+
function valueAfter(args, flag) {
|
|
4
|
+
const index = args.indexOf(flag);
|
|
5
|
+
return index >= 0 ? args[index + 1] : undefined;
|
|
6
|
+
}
|
|
7
|
+
function display(status, json) {
|
|
8
|
+
if (json) {
|
|
9
|
+
console.log(JSON.stringify(status, null, 2));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
console.log('\nCanonical AIWG Installation');
|
|
13
|
+
console.log('===========================');
|
|
14
|
+
console.log(`State: ${status.state}`);
|
|
15
|
+
console.log(`Canonical method: ${status.identity?.method ?? '(unrecorded)'}`);
|
|
16
|
+
console.log(`Canonical root: ${status.identity?.root ?? '(unrecorded)'}`);
|
|
17
|
+
console.log(`Manager: ${status.identity?.managerExecutable ?? '(internal)'}`);
|
|
18
|
+
console.log(`Update strategy: ${status.identity?.updateStrategy ?? '(unrecorded)'}`);
|
|
19
|
+
console.log(`Run mode: ${status.identity?.runMode ?? '(unrecorded)'}`);
|
|
20
|
+
console.log(`Release channel: ${status.identity?.channel ?? '(unrecorded)'}`);
|
|
21
|
+
console.log(`Actual method: ${status.actualMethod}`);
|
|
22
|
+
console.log(`Actual root: ${status.actualRoot}`);
|
|
23
|
+
if (status.drift.length > 0) {
|
|
24
|
+
console.log('Drift:');
|
|
25
|
+
for (const item of status.drift)
|
|
26
|
+
console.log(` - ${item}`);
|
|
27
|
+
}
|
|
28
|
+
console.log('');
|
|
29
|
+
}
|
|
30
|
+
export const installationHandler = {
|
|
31
|
+
id: 'installation',
|
|
32
|
+
name: 'Installation',
|
|
33
|
+
description: 'Inspect, adopt, or deliberately switch the canonical global installation',
|
|
34
|
+
category: 'maintenance',
|
|
35
|
+
aliases: [],
|
|
36
|
+
async execute(ctx) {
|
|
37
|
+
const [action = 'show'] = ctx.args;
|
|
38
|
+
const json = ctx.args.includes('--json');
|
|
39
|
+
const actualRoot = getPackageRoot();
|
|
40
|
+
const common = {
|
|
41
|
+
actualRoot,
|
|
42
|
+
configDir: valueAfter(ctx.args, '--config-dir'),
|
|
43
|
+
managerExecutable: valueAfter(ctx.args, '--manager'),
|
|
44
|
+
channel: valueAfter(ctx.args, '--channel'),
|
|
45
|
+
};
|
|
46
|
+
if (action === 'show') {
|
|
47
|
+
const identity = loadInstallationIdentity({ ...common, createIfMissing: true });
|
|
48
|
+
display(inspectInstallation({ ...common, identity }), json);
|
|
49
|
+
return { exitCode: 0 };
|
|
50
|
+
}
|
|
51
|
+
if (action === 'adopt') {
|
|
52
|
+
const method = valueAfter(ctx.args, '--method');
|
|
53
|
+
const status = adoptInstallation({
|
|
54
|
+
...common,
|
|
55
|
+
method,
|
|
56
|
+
runMode: valueAfter(ctx.args, '--run-mode'),
|
|
57
|
+
});
|
|
58
|
+
display(status, json);
|
|
59
|
+
return { exitCode: 0 };
|
|
60
|
+
}
|
|
61
|
+
if (action === 'switch') {
|
|
62
|
+
const root = valueAfter(ctx.args, '--root');
|
|
63
|
+
const method = valueAfter(ctx.args, '--method');
|
|
64
|
+
if (!root || !method) {
|
|
65
|
+
return { exitCode: 2, message: 'Usage: aiwg installation switch --root <path> --method <npm|web|source> [--manager <absolute-path>]' };
|
|
66
|
+
}
|
|
67
|
+
const status = switchInstallation({
|
|
68
|
+
...common,
|
|
69
|
+
root,
|
|
70
|
+
method,
|
|
71
|
+
runMode: valueAfter(ctx.args, '--run-mode'),
|
|
72
|
+
});
|
|
73
|
+
display(status, json);
|
|
74
|
+
return { exitCode: 0 };
|
|
75
|
+
}
|
|
76
|
+
return { exitCode: 2, message: 'Usage: aiwg installation <show|adopt|switch> [options]' };
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=installation.js.map
|
|
@@ -278,7 +278,8 @@ LFD LOOP CONTROLS (hard cumulative ceilings; loop stops with a best-output repor
|
|
|
278
278
|
Spawnable: claude, opencode, codex, hermes
|
|
279
279
|
--dangerous Enable unrestricted mode for the selected provider.
|
|
280
280
|
Passes the provider's native flag (e.g. --dangerously-skip-permissions
|
|
281
|
-
for claude/opencode,
|
|
281
|
+
for claude/opencode,
|
|
282
|
+
--dangerously-bypass-approvals-and-sandbox for codex). No effect if the
|
|
282
283
|
provider doesn't have a dangerous mode flag.
|
|
283
284
|
--params "<args>" Pass arbitrary args verbatim to the agent binary.
|
|
284
285
|
Appended after all other flags. Quoted segments preserved.
|
|
@@ -242,8 +242,10 @@ export const refreshHandler = {
|
|
|
242
242
|
ui.success('Package up to date');
|
|
243
243
|
}
|
|
244
244
|
else {
|
|
245
|
-
|
|
246
|
-
|
|
245
|
+
return {
|
|
246
|
+
exitCode: updateResult.exitCode,
|
|
247
|
+
message: 'Installation update failed; refresh stopped before re-deployment. Run `aiwg installation show` for canonical-install diagnostics.',
|
|
248
|
+
};
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import path from 'path';
|
|
12
12
|
import { AiwgError, EXIT_CODES, handlerResultFromError } from '../errors.js';
|
|
13
|
+
import { getPackageRoot } from '../../channel/manager.mjs';
|
|
14
|
+
import { inspectInstallation } from '../../installation/manager.mjs';
|
|
13
15
|
function isMissingRuntimeCatalogError(error) {
|
|
14
16
|
return error instanceof Error && error.message.includes('No catalog found');
|
|
15
17
|
}
|
|
@@ -237,8 +239,9 @@ async function handleRuntimeInfo(args, cwd = process.cwd()) {
|
|
|
237
239
|
await discovery.discover();
|
|
238
240
|
summary = await discovery.getSummary();
|
|
239
241
|
}
|
|
242
|
+
const installation = inspectInstallation({ actualRoot: getPackageRoot() });
|
|
240
243
|
if (hasJson) {
|
|
241
|
-
console.log(JSON.stringify(summary, null, 2));
|
|
244
|
+
console.log(JSON.stringify({ ...summary, installation }, null, 2));
|
|
242
245
|
}
|
|
243
246
|
else {
|
|
244
247
|
console.log(`\nRuntime Environment Summary`);
|
|
@@ -256,6 +259,11 @@ async function handleRuntimeInfo(args, cwd = process.cwd()) {
|
|
|
256
259
|
console.log(`\nTotal: ${summary.totalTools} verified tools`);
|
|
257
260
|
console.log(`\nLast Discovery: ${summary.lastDiscovery}`);
|
|
258
261
|
console.log(`Catalog: ${summary.catalogPath}`);
|
|
262
|
+
console.log(`\nAIWG Installation:`);
|
|
263
|
+
console.log(` Canonical: ${installation.identity?.method ?? 'unrecorded'} at ${installation.identity?.root ?? '(unrecorded)'}`);
|
|
264
|
+
console.log(` Actual: ${installation.actualMethod} at ${installation.actualRoot}`);
|
|
265
|
+
console.log(` Run mode: ${installation.identity?.runMode ?? '(unrecorded)'}`);
|
|
266
|
+
console.log(` State: ${installation.state}`);
|
|
259
267
|
// Scheduler backend detection
|
|
260
268
|
const { execSync } = await import('child_process');
|
|
261
269
|
let schedulerBackend = 'external trigger required (system cron/systemd/CI)';
|
|
@@ -123,7 +123,8 @@ AGENT OPTIONS:
|
|
|
123
123
|
IDE-integrated (guidance only): copilot, cursor, factory, warp, windsurf
|
|
124
124
|
--dangerous Enable unrestricted mode (skips permission prompts).
|
|
125
125
|
Maps to the provider's native flag — e.g. claude gets
|
|
126
|
-
--dangerously-skip-permissions, codex gets
|
|
126
|
+
--dangerously-skip-permissions, codex gets
|
|
127
|
+
--dangerously-bypass-approvals-and-sandbox.
|
|
127
128
|
Has no effect on providers that don't support it.
|
|
128
129
|
--params "<args>" Pass arbitrary args directly to the agent binary.
|
|
129
130
|
Appended verbatim after all other flags. You are
|
|
@@ -27,8 +27,14 @@ const pushSecretRegistry = new PushSecretRegistry();
|
|
|
27
27
|
const webhookIdempotency = new IdempotencyCache();
|
|
28
28
|
const DEFAULT_PORT = 7337;
|
|
29
29
|
const DEFAULT_HOST = '127.0.0.1';
|
|
30
|
+
function readA2AProtocolPolicy(value) {
|
|
31
|
+
const policy = value ?? '0.3';
|
|
32
|
+
if (policy === '0.3' || policy === '1.0' || policy === 'auto')
|
|
33
|
+
return policy;
|
|
34
|
+
throw new Error(`AIWG_A2A_PROTOCOL_POLICY must be 0.3, 1.0, or auto (received '${policy}')`);
|
|
35
|
+
}
|
|
30
36
|
/**
|
|
31
|
-
* Parse
|
|
37
|
+
* Parse dashboard and A2A negotiation flags from args.
|
|
32
38
|
*/
|
|
33
39
|
function parseServeArgs(args) {
|
|
34
40
|
let port = DEFAULT_PORT;
|
|
@@ -36,6 +42,9 @@ function parseServeArgs(args) {
|
|
|
36
42
|
let open = true;
|
|
37
43
|
let readOnly = false;
|
|
38
44
|
let sandbox = null;
|
|
45
|
+
let a2aProtocolPolicy;
|
|
46
|
+
let allowA2AProtocolFallback;
|
|
47
|
+
let allowLegacyExecutorFallback;
|
|
39
48
|
for (let i = 0; i < args.length; i++) {
|
|
40
49
|
const arg = args[i];
|
|
41
50
|
if (arg === '--port' && args[i + 1]) {
|
|
@@ -58,8 +67,33 @@ function parseServeArgs(args) {
|
|
|
58
67
|
else if (arg === '--read-only') {
|
|
59
68
|
readOnly = true;
|
|
60
69
|
}
|
|
70
|
+
else if (arg === '--a2a-protocol' && args[i + 1]) {
|
|
71
|
+
a2aProtocolPolicy = readA2AProtocolPolicy(args[i + 1]);
|
|
72
|
+
i++;
|
|
73
|
+
}
|
|
74
|
+
else if (arg === '--a2a-protocol-fallback') {
|
|
75
|
+
allowA2AProtocolFallback = true;
|
|
76
|
+
}
|
|
77
|
+
else if (arg === '--no-a2a-protocol-fallback') {
|
|
78
|
+
allowA2AProtocolFallback = false;
|
|
79
|
+
}
|
|
80
|
+
else if (arg === '--a2a-legacy-executor-fallback') {
|
|
81
|
+
allowLegacyExecutorFallback = true;
|
|
82
|
+
}
|
|
83
|
+
else if (arg === '--no-a2a-legacy-executor-fallback') {
|
|
84
|
+
allowLegacyExecutorFallback = false;
|
|
85
|
+
}
|
|
61
86
|
}
|
|
62
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
port,
|
|
89
|
+
host,
|
|
90
|
+
open,
|
|
91
|
+
readOnly,
|
|
92
|
+
sandbox,
|
|
93
|
+
...(a2aProtocolPolicy ? { a2aProtocolPolicy } : {}),
|
|
94
|
+
...(allowA2AProtocolFallback !== undefined ? { allowA2AProtocolFallback } : {}),
|
|
95
|
+
...(allowLegacyExecutorFallback !== undefined ? { allowLegacyExecutorFallback } : {}),
|
|
96
|
+
};
|
|
63
97
|
}
|
|
64
98
|
// ============================================================
|
|
65
99
|
// WebSocket routing (#851)
|
|
@@ -499,6 +533,13 @@ async function setupWebSockets(httpServer, readOnly) {
|
|
|
499
533
|
* @see #1277 — moves the integration suite off spawn-based testing
|
|
500
534
|
*/
|
|
501
535
|
export async function startServer(opts) {
|
|
536
|
+
const configuredA2AProtocolPolicy = opts.a2aProtocolPolicy
|
|
537
|
+
?? readA2AProtocolPolicy(process.env['AIWG_A2A_PROTOCOL_POLICY']);
|
|
538
|
+
const configuredA2AProtocolFallback = opts.allowA2AProtocolFallback
|
|
539
|
+
?? process.env['AIWG_A2A_PROTOCOL_FALLBACK'] === 'true';
|
|
540
|
+
const configuredLegacyExecutorFallback = configuredA2AProtocolPolicy !== '1.0'
|
|
541
|
+
&& (opts.allowLegacyExecutorFallback
|
|
542
|
+
?? process.env['AIWG_A2A_LEGACY_EXECUTOR_FALLBACK'] !== 'false');
|
|
502
543
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
503
544
|
let honoMod;
|
|
504
545
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -760,8 +801,32 @@ export async function startServer(opts) {
|
|
|
760
801
|
let a2aInstanceId;
|
|
761
802
|
let dispatchPath = 'v2';
|
|
762
803
|
let a2aTask = undefined;
|
|
804
|
+
let a2aProtocolVersion;
|
|
805
|
+
let a2aInterface;
|
|
806
|
+
let a2aFallbackReason;
|
|
807
|
+
const a2aProtocolPolicy = configuredA2AProtocolPolicy;
|
|
763
808
|
try {
|
|
764
809
|
const result = await routeDispatch(executor, payload, {
|
|
810
|
+
a2aProtocolPolicy,
|
|
811
|
+
allowA2AProtocolFallback: configuredA2AProtocolFallback,
|
|
812
|
+
allowLegacyExecutorFallback: configuredLegacyExecutorFallback,
|
|
813
|
+
onA2AProtocolSelection: (info) => {
|
|
814
|
+
telemetryStore.ingest(createEvent('a2a.protocol.selected', sessionId, {
|
|
815
|
+
selected_version: info.selected,
|
|
816
|
+
policy: info.policy,
|
|
817
|
+
...(info.interface ? {
|
|
818
|
+
protocol_binding: info.interface.protocolBinding,
|
|
819
|
+
interface_url: info.interface.url,
|
|
820
|
+
} : {}),
|
|
821
|
+
}, missionId));
|
|
822
|
+
},
|
|
823
|
+
onA2AProtocolFallback: (info) => {
|
|
824
|
+
telemetryStore.ingest(createEvent('a2a.protocol.fallback', sessionId, {
|
|
825
|
+
from_version: info.from,
|
|
826
|
+
to_version: info.to,
|
|
827
|
+
reason: info.reason,
|
|
828
|
+
}, missionId));
|
|
829
|
+
},
|
|
765
830
|
onV1Fallback: (info) => {
|
|
766
831
|
logServeWarn('dispatch', `v1 fallback for executor ${info.executorId}: ${info.reason}`);
|
|
767
832
|
telemetryStore.ingest(createEvent('v1.dispatch.fallback', sessionId, info, missionId));
|
|
@@ -775,6 +840,9 @@ export async function startServer(opts) {
|
|
|
775
840
|
dispatchPath = result.dispatchPath;
|
|
776
841
|
a2aInstanceId = result.a2aInstanceId;
|
|
777
842
|
a2aTask = result.task;
|
|
843
|
+
a2aProtocolVersion = result.a2aProtocolVersion;
|
|
844
|
+
a2aInterface = result.a2aInterface;
|
|
845
|
+
a2aFallbackReason = result.a2aFallbackReason;
|
|
778
846
|
if (result.estimatedStart)
|
|
779
847
|
estimatedStart = result.estimatedStart;
|
|
780
848
|
}
|
|
@@ -796,12 +864,22 @@ export async function startServer(opts) {
|
|
|
796
864
|
return c.json({ error: errorTag, detail: msg }, status);
|
|
797
865
|
}
|
|
798
866
|
// 4. Record the mission and emit telemetry
|
|
867
|
+
if (a2aProtocolVersion && a2aInterface) {
|
|
868
|
+
executorRegistry.recordA2AProtocolSelection(executor.executorId, {
|
|
869
|
+
policy: a2aProtocolPolicy,
|
|
870
|
+
selectedVersion: a2aProtocolVersion,
|
|
871
|
+
interface: a2aInterface,
|
|
872
|
+
...(a2aFallbackReason ? { fallbackReason: a2aFallbackReason } : {}),
|
|
873
|
+
});
|
|
874
|
+
}
|
|
799
875
|
executorRegistry.assignMission(missionId, executor.executorId);
|
|
800
876
|
if (dispatchPath === 'v2' && a2aTask && a2aInstanceId) {
|
|
801
877
|
void observeA2ATerminalState(executorRegistry, executor, missionId, a2aInstanceId, a2aTask, {
|
|
802
878
|
onError: (err) => {
|
|
803
879
|
logServeWarn('dispatch', `A2A terminal observer failed for mission ${missionId}: ${err.message ?? String(err)}`);
|
|
804
880
|
},
|
|
881
|
+
...(a2aProtocolVersion ? { protocolVersion: a2aProtocolVersion } : {}),
|
|
882
|
+
...(a2aInterface ? { selectedInterface: a2aInterface } : {}),
|
|
805
883
|
});
|
|
806
884
|
}
|
|
807
885
|
telemetryStore.ingest(createEvent('mission.dispatch', sessionId, {
|
|
@@ -809,6 +887,8 @@ export async function startServer(opts) {
|
|
|
809
887
|
executorId: executor.executorId,
|
|
810
888
|
objective: payload.objective,
|
|
811
889
|
completion: payload.completion,
|
|
890
|
+
...(a2aProtocolVersion ? { a2a_protocol_version: a2aProtocolVersion } : {}),
|
|
891
|
+
...(a2aFallbackReason ? { a2a_fallback_reason: a2aFallbackReason } : {}),
|
|
812
892
|
}, missionId));
|
|
813
893
|
// 5. Return 202 Accepted
|
|
814
894
|
const dispatchResp = {
|
|
@@ -819,6 +899,14 @@ export async function startServer(opts) {
|
|
|
819
899
|
};
|
|
820
900
|
if (a2aInstanceId)
|
|
821
901
|
dispatchResp.a2a_instance_id = a2aInstanceId;
|
|
902
|
+
if (a2aProtocolVersion)
|
|
903
|
+
dispatchResp.a2a_protocol_version = a2aProtocolVersion;
|
|
904
|
+
if (a2aInterface) {
|
|
905
|
+
dispatchResp.a2a_protocol_binding = a2aInterface.protocolBinding;
|
|
906
|
+
dispatchResp.a2a_interface_url = a2aInterface.url;
|
|
907
|
+
}
|
|
908
|
+
if (a2aFallbackReason)
|
|
909
|
+
dispatchResp.a2a_fallback_reason = a2aFallbackReason;
|
|
822
910
|
if (estimatedStart)
|
|
823
911
|
dispatchResp.estimated_start = estimatedStart;
|
|
824
912
|
return c.json(dispatchResp, 202);
|
|
@@ -947,6 +1035,7 @@ export async function startServer(opts) {
|
|
|
947
1035
|
const result = await handleWebhook(configId, bodyBuf, signature, eventId, {
|
|
948
1036
|
registry: pushSecretRegistry,
|
|
949
1037
|
idempotency: webhookIdempotency,
|
|
1038
|
+
contentType: c.req.header('content-type') ?? undefined,
|
|
950
1039
|
route: async (entry, event) => {
|
|
951
1040
|
// Append to mission recentEvents via a synthesized envelope.
|
|
952
1041
|
// The 'mission.webhook' event type falls through the registry's
|
|
@@ -990,11 +1079,17 @@ export async function startServer(opts) {
|
|
|
990
1079
|
if (!p.secret || typeof p.secret !== 'string' || p.secret.length < 16) {
|
|
991
1080
|
return c.json({ error: 'secret is required and must be ≥16 chars' }, 400);
|
|
992
1081
|
}
|
|
1082
|
+
if (p.protocolVersion === '1.0' && !p.taskId) {
|
|
1083
|
+
return c.json({ error: 'taskId is required for A2A 1.0 push ownership scope' }, 400);
|
|
1084
|
+
}
|
|
993
1085
|
pushSecretRegistry.register({
|
|
994
1086
|
configId: p.configId,
|
|
995
1087
|
secret: p.secret,
|
|
996
1088
|
...(p.missionId ? { missionId: p.missionId } : {}),
|
|
997
1089
|
...(p.taskId ? { taskId: p.taskId } : {}),
|
|
1090
|
+
...(p.contextId ? { contextId: p.contextId } : {}),
|
|
1091
|
+
...(p.protocolVersion ? { protocolVersion: p.protocolVersion } : {}),
|
|
1092
|
+
...(p.taskOwner ? { taskOwner: p.taskOwner } : {}),
|
|
998
1093
|
...(p.metadata ? { metadata: p.metadata } : {}),
|
|
999
1094
|
});
|
|
1000
1095
|
return c.json({ ok: true, configId: p.configId }, 201);
|
|
@@ -1749,10 +1844,18 @@ export const serveHandler = {
|
|
|
1749
1844
|
category: 'project',
|
|
1750
1845
|
aliases: [],
|
|
1751
1846
|
async execute(ctx) {
|
|
1752
|
-
const { port, host, open, readOnly } = parseServeArgs(ctx.args);
|
|
1847
|
+
const { port, host, open, readOnly, a2aProtocolPolicy, allowA2AProtocolFallback, allowLegacyExecutorFallback, } = parseServeArgs(ctx.args);
|
|
1753
1848
|
let server;
|
|
1754
1849
|
try {
|
|
1755
|
-
server = await startServer({
|
|
1850
|
+
server = await startServer({
|
|
1851
|
+
port,
|
|
1852
|
+
host,
|
|
1853
|
+
readOnly,
|
|
1854
|
+
frameworkRoot: ctx.frameworkRoot,
|
|
1855
|
+
...(a2aProtocolPolicy ? { a2aProtocolPolicy } : {}),
|
|
1856
|
+
...(allowA2AProtocolFallback !== undefined ? { allowA2AProtocolFallback } : {}),
|
|
1857
|
+
...(allowLegacyExecutorFallback !== undefined ? { allowLegacyExecutorFallback } : {}),
|
|
1858
|
+
});
|
|
1756
1859
|
}
|
|
1757
1860
|
catch (error) {
|
|
1758
1861
|
const { handlerResultFromError } = await import('../errors.js');
|
|
@@ -21,6 +21,7 @@ import { spawnSync } from 'child_process';
|
|
|
21
21
|
import { ensureRuntimeHome, writeProfileConfig, launchWithProfile } from '../../mcp/adapters/codex-runtime.js';
|
|
22
22
|
import { getFrameworkRoot } from '../../channel/manager.mjs';
|
|
23
23
|
import { forceUpdateCheck } from '../../update/checker.mjs';
|
|
24
|
+
import { updateInstallation } from '../../update/service.mjs';
|
|
24
25
|
import { readAiwgConfig, getDeploymentSummary, VALID_PROVIDERS, } from '../../config/aiwg-config.js';
|
|
25
26
|
import { getProviderConfig, isSpawnableProvider, PROVIDER_CONFIGS, } from '../agent-spawn.js';
|
|
26
27
|
import { useHandler as useFrameworkHandler } from './use.js';
|
|
@@ -84,8 +85,11 @@ async function checkAndUpdateVersion(noRepair) {
|
|
|
84
85
|
debug('cli:session:update', 'forceUpdateCheck failed', err);
|
|
85
86
|
if (!noRepair) {
|
|
86
87
|
console.log(' Version check failed — attempting sync...');
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
try {
|
|
89
|
+
await updateInstallation();
|
|
90
|
+
}
|
|
91
|
+
catch (updateError) {
|
|
92
|
+
debug('cli:session:update', 'canonical installation update failed', updateError);
|
|
89
93
|
console.warn(' WARN Could not update aiwg — continuing with current version.');
|
|
90
94
|
return false;
|
|
91
95
|
}
|
|
@@ -103,10 +107,11 @@ function runDoctor(_frameworkRoot, cwd) {
|
|
|
103
107
|
}
|
|
104
108
|
/**
|
|
105
109
|
* Attempt to repair a failed doctor result.
|
|
106
|
-
* Strategy: `aiwg sync
|
|
110
|
+
* Strategy: `aiwg sync`; package repair remains bound to the canonical update
|
|
111
|
+
* strategy and never falls through to an arbitrary npm on PATH.
|
|
107
112
|
* Returns true if repair succeeded (doctor now passes).
|
|
108
113
|
*/
|
|
109
|
-
function repairInstallation(frameworkRoot, cwd, provider
|
|
114
|
+
function repairInstallation(frameworkRoot, cwd, provider) {
|
|
110
115
|
// Strategy 1: sync (update + redeploy)
|
|
111
116
|
console.log('\n Attempting auto-repair via `aiwg sync`...');
|
|
112
117
|
const syncResult = spawnSync(process.execPath, [process.argv[1], 'sync'], { stdio: 'inherit', cwd });
|
|
@@ -118,29 +123,13 @@ function repairInstallation(frameworkRoot, cwd, provider, installedFrameworks) {
|
|
|
118
123
|
return true;
|
|
119
124
|
}
|
|
120
125
|
}
|
|
121
|
-
// Strategy 2: full reinstall
|
|
122
|
-
console.log('\n Sync did not fully resolve the issue. Attempting full reinstall...');
|
|
123
|
-
const reinstallResult = spawnSync('npm', ['install', '-g', 'aiwg@latest'], { stdio: 'inherit' });
|
|
124
|
-
if (reinstallResult.status === 0 && installedFrameworks.length > 0) {
|
|
125
|
-
// Redeploy all installed frameworks for this provider
|
|
126
|
-
console.log(`\n Redeploying frameworks to ${provider}...`);
|
|
127
|
-
for (const fw of installedFrameworks) {
|
|
128
|
-
spawnSync(process.execPath, [process.argv[1], 'use', fw, '--provider', provider], { stdio: 'inherit', cwd });
|
|
129
|
-
}
|
|
130
|
-
// Final doctor check
|
|
131
|
-
const finalOk = runDoctor(frameworkRoot, cwd);
|
|
132
|
-
if (finalOk) {
|
|
133
|
-
console.log(' OK Full reinstall + redeploy succeeded.');
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
126
|
// Could not auto-repair
|
|
138
127
|
console.log(`
|
|
139
128
|
✗ Auto-repair could not resolve all issues.
|
|
140
129
|
|
|
141
130
|
Manual options:
|
|
142
|
-
aiwg
|
|
143
|
-
|
|
131
|
+
aiwg installation show — inspect canonical install drift
|
|
132
|
+
aiwg refresh — update and redeploy canonically
|
|
144
133
|
aiwg use all --provider ${provider.padEnd(10)} — redeploy all frameworks
|
|
145
134
|
|
|
146
135
|
Report this issue:
|
|
@@ -291,10 +280,7 @@ export const sessionHandler = {
|
|
|
291
280
|
console.log('\n Running health checks...');
|
|
292
281
|
const doctorOk = runDoctor(frameworkRoot, cwd);
|
|
293
282
|
if (!doctorOk && !noRepair) {
|
|
294
|
-
|
|
295
|
-
const config = await readAiwgConfig(cwd);
|
|
296
|
-
const installedFrameworks = Object.keys(config?.installed ?? {});
|
|
297
|
-
const repaired = repairInstallation(frameworkRoot, cwd, provider, installedFrameworks);
|
|
283
|
+
const repaired = repairInstallation(frameworkRoot, cwd, provider);
|
|
298
284
|
if (!repaired) {
|
|
299
285
|
// Repair failed — still continue (user was already informed)
|
|
300
286
|
}
|
|
@@ -52,7 +52,7 @@ import { generate as generateContextFiles, discoverDeployedArtifacts, } from '..
|
|
|
52
52
|
import { verifyModelWrapperDeployment } from '../../models/wrapper-deployment.js';
|
|
53
53
|
import { loadGraphIndexFile } from '../../artifacts/index-reader.js';
|
|
54
54
|
import { aggregateUseDeploymentResult, buildDryRunUseResult, renderUseDeploymentResult, verifyProviderDeployment, } from '../services/deployment-verification.js';
|
|
55
|
-
import { finalizeProviderTransformationReceipt, sourceVerificationsFromSignedWebRelease, } from '../../providers/transformation-receipt-integration.js';
|
|
55
|
+
import { finalizeProviderTransformationReceipt, providerReceiptHasLocalSources, sourceVerificationsFromSignedWebRelease, } from '../../providers/transformation-receipt-integration.js';
|
|
56
56
|
import { loadResourceTrustRootFile, resolveWebRelease, } from '../../resources/web-release.js';
|
|
57
57
|
import { createResourceCredentialProvider } from '../../auth/resource-credentials.js';
|
|
58
58
|
/**
|
|
@@ -75,10 +75,16 @@ function providerReceiptWebReleaseOptions() {
|
|
|
75
75
|
: {}),
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
function releaseResourceUnavailable(error) {
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return /fetch failed|request timed out|no fetch implementation/i.test(message);
|
|
81
|
+
}
|
|
82
|
+
export async function resolveProviderReceiptSource(options) {
|
|
83
|
+
if (await providerReceiptHasLocalSources(options))
|
|
84
|
+
return { sourceDisposition: 'local-source' };
|
|
79
85
|
const versionInfo = await getVersionInfo();
|
|
80
86
|
if (versionInfo.devMode)
|
|
81
|
-
return
|
|
87
|
+
return { sourceDisposition: 'local-source' };
|
|
82
88
|
const releaseOptions = providerReceiptWebReleaseOptions();
|
|
83
89
|
let release;
|
|
84
90
|
try {
|
|
@@ -90,15 +96,24 @@ async function signedProviderSourceVerifications(options) {
|
|
|
90
96
|
// Protected production resources require the authenticated release
|
|
91
97
|
// credential. A configured alternate endpoint may intentionally be public.
|
|
92
98
|
if (!token && releaseOptions.baseUrl === undefined)
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
return { sourceDisposition: 'source-unavailable' };
|
|
100
|
+
try {
|
|
101
|
+
release = await resolveWebRelease({
|
|
102
|
+
...releaseOptions,
|
|
103
|
+
selector: versionInfo.version,
|
|
104
|
+
credentialProvider: async () => token,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (releaseResourceUnavailable(error))
|
|
109
|
+
return { sourceDisposition: 'source-unavailable' };
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
99
112
|
}
|
|
100
113
|
const verifications = await sourceVerificationsFromSignedWebRelease(options, release);
|
|
101
|
-
return Object.keys(verifications).length > 0
|
|
114
|
+
return Object.keys(verifications).length > 0
|
|
115
|
+
? { sourceVerifications: verifications }
|
|
116
|
+
: { sourceDisposition: 'verification-failed' };
|
|
102
117
|
}
|
|
103
118
|
/**
|
|
104
119
|
* Framework name to deploy mode mapping.
|
|
@@ -1005,6 +1020,79 @@ async function countBundleDeployedArtifacts(bundlePath, target, provider) {
|
|
|
1005
1020
|
rules: await countDeployedBundleFiles(bundlePath, 'rules', target, paths.rules, ['.md', '.mdc']),
|
|
1006
1021
|
};
|
|
1007
1022
|
}
|
|
1023
|
+
const SKILL_SUPPORT_REFERENCE = /(?:^|[\s`('"\[])((?:templates|references|scripts|assets)\/[A-Za-z0-9._@/+\-]+)(?=$|[\s`)'"\],:;])/gm;
|
|
1024
|
+
/**
|
|
1025
|
+
* Project skill-relative support files may live beside the skill or at the
|
|
1026
|
+
* bundle root (plugin payloads commonly share report templates). Materialize
|
|
1027
|
+
* only paths explicitly named by SKILL.md, and fail closed on missing or
|
|
1028
|
+
* unsafe sources so a deployed instruction can never point at absent assets.
|
|
1029
|
+
*/
|
|
1030
|
+
async function reconcileProjectLocalSkillAssets(bundlePath, target, provider) {
|
|
1031
|
+
const skillsRoot = path.join(bundlePath, 'skills');
|
|
1032
|
+
let skillDirs;
|
|
1033
|
+
try {
|
|
1034
|
+
skillDirs = (await fs.readdir(skillsRoot, { withFileTypes: true }))
|
|
1035
|
+
.filter(entry => entry.isDirectory())
|
|
1036
|
+
.map(entry => entry.name);
|
|
1037
|
+
}
|
|
1038
|
+
catch {
|
|
1039
|
+
return;
|
|
1040
|
+
}
|
|
1041
|
+
const paths = getProviderPaths(provider);
|
|
1042
|
+
const kernelSkillsPath = getProviderKernelSkillsPath(provider);
|
|
1043
|
+
const deployRoots = [...new Set([
|
|
1044
|
+
paths.skills,
|
|
1045
|
+
kernelSkillsPath,
|
|
1046
|
+
].filter((value) => Boolean(value)).map(value => resolveDeployPath(target, value)))];
|
|
1047
|
+
for (const skillName of skillDirs) {
|
|
1048
|
+
const sourceSkillDir = path.join(skillsRoot, skillName);
|
|
1049
|
+
const sourceSkillMd = path.join(sourceSkillDir, 'SKILL.md');
|
|
1050
|
+
let content;
|
|
1051
|
+
try {
|
|
1052
|
+
content = await fs.readFile(sourceSkillMd, 'utf8');
|
|
1053
|
+
}
|
|
1054
|
+
catch {
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
const references = [...new Set([...content.matchAll(SKILL_SUPPORT_REFERENCE)].map(match => match[1]))];
|
|
1058
|
+
for (const relative of references) {
|
|
1059
|
+
const normalized = path.posix.normalize(relative);
|
|
1060
|
+
if (normalized !== relative || normalized.startsWith('../') || path.isAbsolute(normalized)) {
|
|
1061
|
+
throw new Error(`unsafe skill support reference '${relative}' in ${sourceSkillMd}`);
|
|
1062
|
+
}
|
|
1063
|
+
const candidates = [path.join(sourceSkillDir, normalized), path.join(bundlePath, normalized)];
|
|
1064
|
+
let source;
|
|
1065
|
+
for (const candidate of candidates) {
|
|
1066
|
+
try {
|
|
1067
|
+
const stat = await fs.lstat(candidate);
|
|
1068
|
+
if (stat.isFile() && !stat.isSymbolicLink()) {
|
|
1069
|
+
source = candidate;
|
|
1070
|
+
break;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
catch { /* try bundle-root fallback */ }
|
|
1074
|
+
}
|
|
1075
|
+
if (!source)
|
|
1076
|
+
throw new Error(`missing skill support asset '${relative}' referenced by ${sourceSkillMd}`);
|
|
1077
|
+
let deployedSkillRoot;
|
|
1078
|
+
for (const root of deployRoots) {
|
|
1079
|
+
// The deployer may select the bulk or kernel tier; use the tier that
|
|
1080
|
+
// actually contains this skill's transformed SKILL.md.
|
|
1081
|
+
if (await fileExists(path.join(root, skillName, 'SKILL.md'))) {
|
|
1082
|
+
deployedSkillRoot = root;
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (!deployedSkillRoot)
|
|
1087
|
+
throw new Error(`deployed skill '${skillName}' not found while reconciling support assets`);
|
|
1088
|
+
const destination = path.join(deployedSkillRoot, skillName, ...normalized.split('/'));
|
|
1089
|
+
await fs.mkdir(path.dirname(destination), { recursive: true });
|
|
1090
|
+
await fs.copyFile(source, destination);
|
|
1091
|
+
const mode = (await fs.stat(source)).mode & 0o777;
|
|
1092
|
+
await fs.chmod(destination, mode);
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1008
1096
|
/**
|
|
1009
1097
|
* Deploy a single project-local bundle to one provider via deploy-agents.mjs.
|
|
1010
1098
|
* Runs the same script and flags used for upstream addons, with the bundle
|
|
@@ -1072,6 +1160,15 @@ async function deployOneProjectLocalBundle(opts) {
|
|
|
1072
1160
|
env: { AIWG_ROOT: frameworkRoot },
|
|
1073
1161
|
});
|
|
1074
1162
|
exitCode = result.exitCode;
|
|
1163
|
+
if (exitCode === 0 && !dryRun) {
|
|
1164
|
+
try {
|
|
1165
|
+
await reconcileProjectLocalSkillAssets(bundle.artifactPath, target, provider);
|
|
1166
|
+
}
|
|
1167
|
+
catch (error) {
|
|
1168
|
+
ui.warn(`Project-local skill asset deployment failed for '${bundle.id}': ${error.message}`);
|
|
1169
|
+
exitCode = 1;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1075
1172
|
}
|
|
1076
1173
|
if (exitCode === 0 && cliCommandCount > 0) {
|
|
1077
1174
|
try {
|
|
@@ -2017,10 +2114,18 @@ export class UseHandler {
|
|
|
2017
2114
|
scope: effectiveScope,
|
|
2018
2115
|
requestedBundles: [requestedBundle],
|
|
2019
2116
|
};
|
|
2020
|
-
const
|
|
2021
|
-
await finalizeProviderTransformationReceipt({ ...receiptOptions,
|
|
2117
|
+
const sourceResolution = await resolveProviderReceiptSource(receiptOptions);
|
|
2118
|
+
await finalizeProviderTransformationReceipt({ ...receiptOptions, ...sourceResolution });
|
|
2022
2119
|
}
|
|
2023
2120
|
catch (error) {
|
|
2121
|
+
await finalizeProviderTransformationReceipt({
|
|
2122
|
+
projectRoot: projectDir,
|
|
2123
|
+
frameworkRoot,
|
|
2124
|
+
provider,
|
|
2125
|
+
scope: effectiveScope,
|
|
2126
|
+
requestedBundles: [requestedBundle],
|
|
2127
|
+
sourceDisposition: 'verification-failed',
|
|
2128
|
+
}).catch(() => undefined);
|
|
2024
2129
|
originalConsole.warn(`Provider receipt finalization failed for ${provider}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2025
2130
|
}
|
|
2026
2131
|
}
|
|
@@ -777,6 +777,10 @@ export const updateHandler = {
|
|
|
777
777
|
console.log(`${update.message}\n`);
|
|
778
778
|
}
|
|
779
779
|
catch (error) {
|
|
780
|
+
if (error.code === 'AIWG_INSTALLATION_DRIFT'
|
|
781
|
+
|| error.code === 'AIWG_INSTALLATION_INVALID') {
|
|
782
|
+
return { exitCode: 78, message: error instanceof Error ? error.message : String(error) };
|
|
783
|
+
}
|
|
780
784
|
console.error(`Warning: Update check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
781
785
|
console.log('Continuing with re-deployment...\n');
|
|
782
786
|
}
|