@aiwg/cli 2026.8.17 → 2026.8.19
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/index-builder.js +63 -12
- package/dist/src/artifacts/index-files.js +26 -5
- package/dist/src/artifacts/query-engine.js +67 -67
- package/dist/src/artifacts/stats.js +6 -2
- package/dist/src/artifacts/types.js +1 -1
- package/dist/src/audit/operator-decision.js +15 -1
- package/dist/src/channel/manager.mjs +89 -17
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/installation.js +79 -0
- package/dist/src/cli/handlers/refresh.js +6 -2
- package/dist/src/cli/handlers/runtime-info.js +9 -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 +19 -4
- package/dist/src/cli/handlers/utilities.js +4 -0
- package/dist/src/cli/handlers/version.js +4 -0
- 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-command.mjs +31 -0
- package/dist/src/installation/manager.mjs +264 -0
- 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/stack-adapters.js +2 -1
- package/dist/src/serve/telemetry.js +5 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +8 -5
- package/dist/src/smiths/context-pipeline/line-endings.js +12 -0
- package/dist/src/smiths/context-pipeline/managed-hook.js +8 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +3 -1
- package/dist/src/update/checker.mjs +16 -15
- package/dist/src/update/notifier.mjs +8 -3
- package/dist/src/update/service.mjs +51 -5
- package/package.json +1 -1
- package/tools/agents/deploy-agents.mjs +28 -8
- package/tools/agents/providers/base.mjs +5 -3
|
@@ -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
|
}
|
|
@@ -1873,11 +1873,13 @@ async function deploySourceDirectory(opts) {
|
|
|
1873
1873
|
args.push('--force');
|
|
1874
1874
|
if (opts.copyAll)
|
|
1875
1875
|
args.push('--copy-all');
|
|
1876
|
+
if (opts.kernelOnly)
|
|
1877
|
+
args.push('--kernel-only');
|
|
1876
1878
|
if (opts.quiet)
|
|
1877
1879
|
args.unshift('--quiet');
|
|
1878
1880
|
const runner = createScriptRunner(opts.frameworkRoot);
|
|
1879
1881
|
const result = await runner.run('tools/agents/deploy-agents.mjs', args, opts.quiet ? { capture: true } : {});
|
|
1880
|
-
if (result.exitCode === 0) {
|
|
1882
|
+
if (result.exitCode === 0 && !opts.kernelOnly) {
|
|
1881
1883
|
try {
|
|
1882
1884
|
await registerSourceCliCommands({
|
|
1883
1885
|
source: opts.source,
|
|
@@ -2436,6 +2438,7 @@ export class UseHandler {
|
|
|
2436
2438
|
}
|
|
2437
2439
|
ui.dim(' Use `aiwg use all` for the full deployment.');
|
|
2438
2440
|
for (const providerName of providersForFiltered) {
|
|
2441
|
+
const kernelOnly = !copyAll;
|
|
2439
2442
|
for (const selected of selectedFrameworks) {
|
|
2440
2443
|
const frameworkDir = resolveFrameworkDir(selected);
|
|
2441
2444
|
if (!frameworkDir)
|
|
@@ -2450,6 +2453,7 @@ export class UseHandler {
|
|
|
2450
2453
|
verbose,
|
|
2451
2454
|
force,
|
|
2452
2455
|
copyAll,
|
|
2456
|
+
kernelOnly,
|
|
2453
2457
|
quiet,
|
|
2454
2458
|
modelArgs: modelDeployArgs,
|
|
2455
2459
|
});
|
|
@@ -2467,6 +2471,7 @@ export class UseHandler {
|
|
|
2467
2471
|
verbose,
|
|
2468
2472
|
force,
|
|
2469
2473
|
copyAll,
|
|
2474
|
+
kernelOnly,
|
|
2470
2475
|
quiet,
|
|
2471
2476
|
modelArgs: modelDeployArgs,
|
|
2472
2477
|
});
|
|
@@ -2484,6 +2489,7 @@ export class UseHandler {
|
|
|
2484
2489
|
verbose,
|
|
2485
2490
|
force,
|
|
2486
2491
|
copyAll,
|
|
2492
|
+
kernelOnly,
|
|
2487
2493
|
quiet,
|
|
2488
2494
|
modelArgs: modelDeployArgs,
|
|
2489
2495
|
});
|
|
@@ -2985,6 +2991,11 @@ export class UseHandler {
|
|
|
2985
2991
|
const providerDeployArgs = builtInProviderResolution.requestedProvider
|
|
2986
2992
|
? withProviderOverride(deployFilteredArgs, provider)
|
|
2987
2993
|
: deployFilteredArgs;
|
|
2994
|
+
const bulkKernelOnly = framework === 'all'
|
|
2995
|
+
&& !remainingArgs.includes('--copy-all')
|
|
2996
|
+
&& !remainingArgs.includes('--copy-standard-skills');
|
|
2997
|
+
if (bulkKernelOnly)
|
|
2998
|
+
providerDeployArgs.push('--kernel-only');
|
|
2988
2999
|
const targetIdx = remainingArgs.findIndex(a => a === '--target');
|
|
2989
3000
|
const target = targetIdx >= 0 && remainingArgs[targetIdx + 1] ? remainingArgs[targetIdx + 1] : process.cwd();
|
|
2990
3001
|
if ((verbose || dryRun) && projectLocalProviderResolution.requestedProvider) {
|
|
@@ -3084,11 +3095,15 @@ export class UseHandler {
|
|
|
3084
3095
|
}
|
|
3085
3096
|
// Build common args for addon deployments (inherit provider and target)
|
|
3086
3097
|
const addonBaseArgs = ['--deploy-commands', '--deploy-skills', '--deploy-rules'];
|
|
3098
|
+
if (bulkKernelOnly)
|
|
3099
|
+
addonBaseArgs.push('--kernel-only');
|
|
3087
3100
|
addonBaseArgs.push(...modelDeployArgs);
|
|
3088
3101
|
if (provider)
|
|
3089
3102
|
addonBaseArgs.push('--provider', provider);
|
|
3090
3103
|
if (target)
|
|
3091
3104
|
addonBaseArgs.push('--target', target);
|
|
3105
|
+
if (dryRun)
|
|
3106
|
+
addonBaseArgs.push('--dry-run');
|
|
3092
3107
|
if (verbose)
|
|
3093
3108
|
addonBaseArgs.push('--verbose');
|
|
3094
3109
|
// Forward --copy-all to addon deploys so the legacy mirror behavior
|
|
@@ -3182,7 +3197,7 @@ export class UseHandler {
|
|
|
3182
3197
|
}
|
|
3183
3198
|
await ensureProviderGeneratedDirsIgnored(target, provider, { dryRun, verbose });
|
|
3184
3199
|
const paths = getProviderPaths(provider);
|
|
3185
|
-
if (!dryRun && !skipUtils) {
|
|
3200
|
+
if (!dryRun && !skipUtils && !bulkKernelOnly) {
|
|
3186
3201
|
const wrapperValidation = await validateDeployedModelWrappers({
|
|
3187
3202
|
provider,
|
|
3188
3203
|
target,
|
|
@@ -3200,7 +3215,7 @@ export class UseHandler {
|
|
|
3200
3215
|
const targetKernelSkillsDir = kernelSkillsPath ? resolveProviderPath(target, kernelSkillsPath) : '';
|
|
3201
3216
|
// Translate deployed skills to commands for providers that require legacy command format.
|
|
3202
3217
|
// (#550) Skills are canonical; commands are generated deployment artifacts.
|
|
3203
|
-
if (providerNeedsCommands(provider) && targetCommandsDir) {
|
|
3218
|
+
if (!bulkKernelOnly && providerNeedsCommands(provider) && targetCommandsDir) {
|
|
3204
3219
|
try {
|
|
3205
3220
|
const translationResult = await translateSkillsToCommands(targetSkillsDir, {
|
|
3206
3221
|
provider,
|
|
@@ -3222,7 +3237,7 @@ export class UseHandler {
|
|
|
3222
3237
|
// provider loads skills natively: users still expect setup, update,
|
|
3223
3238
|
// status, intake, and flow workflows to show up in the provider's `/`
|
|
3224
3239
|
// command picker where supported.
|
|
3225
|
-
if (targetCommandsDir) {
|
|
3240
|
+
if (!bulkKernelOnly && targetCommandsDir) {
|
|
3226
3241
|
try {
|
|
3227
3242
|
const standardMirrored = await mirrorStandardCommandSkills({
|
|
3228
3243
|
provider,
|
|
@@ -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
|
}
|
|
@@ -53,6 +53,7 @@ function collectFingerprint(versionInfo) {
|
|
|
53
53
|
logFile: loggerInfo.logFile,
|
|
54
54
|
},
|
|
55
55
|
invocation_id: loggerInfo.provenance.invocation_id,
|
|
56
|
+
installation: versionInfo.installation,
|
|
56
57
|
};
|
|
57
58
|
if (versionInfo.gitHash) {
|
|
58
59
|
fp.git = {
|
|
@@ -115,6 +116,9 @@ async function displayVersion(opts) {
|
|
|
115
116
|
ui.dim(` path: ${fp.packageRoot}`);
|
|
116
117
|
}
|
|
117
118
|
ui.dim(` channel: ${fp.channel}`);
|
|
119
|
+
ui.dim(` install: ${fp.installation.identity?.method ?? 'unrecorded'} (${fp.installation.state})`);
|
|
120
|
+
ui.dim(` canonical: ${fp.installation.identity?.root ?? '(unrecorded)'}`);
|
|
121
|
+
ui.dim(` actual: ${fp.installation.actualRoot}`);
|
|
118
122
|
ui.dim(` node: ${fp.node}`);
|
|
119
123
|
ui.dim(` platform: ${fp.platform.os} ${fp.platform.arch} (${fp.platform.release})`);
|
|
120
124
|
ui.dim(` tty: stdin=${fp.tty.stdin} stdout=${fp.tty.stdout} stderr=${fp.tty.stderr}`);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolve AIWG's global, provider-neutral user configuration directory.
|
|
7
|
+
*
|
|
8
|
+
* Contract: explicit override > AIWG_CONFIG > existing ~/.aiwg > existing
|
|
9
|
+
* ~/.config/aiwg > ~/.aiwg. Keeping this in a dependency-free ESM module lets
|
|
10
|
+
* the launcher, channel manager, updater, and TypeScript config API share the
|
|
11
|
+
* exact same resolution rules.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveUserConfigDir(options = {}) {
|
|
14
|
+
if (options.configDir) return path.resolve(options.configDir);
|
|
15
|
+
const env = options.env ?? process.env;
|
|
16
|
+
if (env.AIWG_CONFIG) return path.resolve(env.AIWG_CONFIG);
|
|
17
|
+
|
|
18
|
+
const home = options.homeDir ?? os.homedir();
|
|
19
|
+
const legacy = path.join(home, '.aiwg');
|
|
20
|
+
const xdg = path.join(home, '.config', 'aiwg');
|
|
21
|
+
const pathExists = options.exists ?? existsSync;
|
|
22
|
+
if (pathExists(legacy)) return legacy;
|
|
23
|
+
if (pathExists(xdg)) return xdg;
|
|
24
|
+
return legacy;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function userConfigFile(name, options = {}) {
|
|
28
|
+
return path.join(resolveUserConfigDir(options), name);
|
|
29
|
+
}
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
* @implements #545
|
|
17
17
|
*/
|
|
18
18
|
import { readFile, writeFile, mkdir, access } from 'fs/promises';
|
|
19
|
-
import { resolve } from 'path';
|
|
20
|
-
import { homedir } from 'os';
|
|
21
19
|
import { existsSync } from 'fs';
|
|
20
|
+
import { resolve } from 'path';
|
|
21
|
+
import { resolveUserConfigDir } from './user-config-dir.mjs';
|
|
22
22
|
/**
|
|
23
23
|
* Known config files in the user config directory
|
|
24
24
|
*/
|
|
@@ -28,6 +28,7 @@ export const KNOWN_CONFIG_FILES = [
|
|
|
28
28
|
{ filename: 'ops.json', description: 'Ops workspace registry' },
|
|
29
29
|
{ filename: 'mcp-servers.json', description: 'MCP server registry (single source of truth)' },
|
|
30
30
|
{ filename: 'packages.yaml', description: 'Installed remote packages (aiwg install)' },
|
|
31
|
+
{ filename: 'installation.json', description: 'Canonical global installation identity' },
|
|
31
32
|
];
|
|
32
33
|
/**
|
|
33
34
|
* Default user config values
|
|
@@ -60,26 +61,7 @@ export const DEFAULT_USER_CONFIG = {
|
|
|
60
61
|
* 4. ~/.aiwg (default if neither exists)
|
|
61
62
|
*/
|
|
62
63
|
export function resolveConfigDir(overridePath) {
|
|
63
|
-
|
|
64
|
-
const envOverride = process.env.AIWG_CONFIG;
|
|
65
|
-
if (overridePath) {
|
|
66
|
-
return resolve(overridePath);
|
|
67
|
-
}
|
|
68
|
-
if (envOverride) {
|
|
69
|
-
return resolve(envOverride);
|
|
70
|
-
}
|
|
71
|
-
// 2. Check primary path: ~/.aiwg
|
|
72
|
-
const primaryPath = resolve(homedir(), '.aiwg');
|
|
73
|
-
if (existsSync(primaryPath)) {
|
|
74
|
-
return primaryPath;
|
|
75
|
-
}
|
|
76
|
-
// 3. Check fallback path: ~/.config/aiwg
|
|
77
|
-
const fallbackPath = resolve(homedir(), '.config/aiwg');
|
|
78
|
-
if (existsSync(fallbackPath)) {
|
|
79
|
-
return fallbackPath;
|
|
80
|
-
}
|
|
81
|
-
// 4. Default to primary if neither exists
|
|
82
|
-
return primaryPath;
|
|
64
|
+
return resolveUserConfigDir({ configDir: overridePath });
|
|
83
65
|
}
|
|
84
66
|
/**
|
|
85
67
|
* User-level configuration manager
|
|
@@ -164,6 +164,24 @@ export const updateCommand = {
|
|
|
164
164
|
},
|
|
165
165
|
},
|
|
166
166
|
};
|
|
167
|
+
export const installationCommand = {
|
|
168
|
+
id: 'installation',
|
|
169
|
+
type: 'command',
|
|
170
|
+
name: 'Installation Identity',
|
|
171
|
+
description: 'Inspect, adopt, or deliberately switch the canonical global AIWG installation',
|
|
172
|
+
version: '1.0.0',
|
|
173
|
+
capabilities: ['cli', 'installation', 'update', 'diagnostics', 'recovery'],
|
|
174
|
+
keywords: ['installation', 'canonical', 'adopt', 'switch', 'package-manager', 'drift'],
|
|
175
|
+
category: 'maintenance',
|
|
176
|
+
platforms: { claude: 'full', generic: 'full' },
|
|
177
|
+
deployment: { pathTemplate: '.{platform}/commands/{id}.md', core: true },
|
|
178
|
+
metadata: {
|
|
179
|
+
type: 'command',
|
|
180
|
+
template: 'utility',
|
|
181
|
+
argumentHint: '<show|adopt|switch> [--root <path>] [--method <npm|web|source>] [--manager <absolute-path>] [--json]',
|
|
182
|
+
allowedTools: ['Read', 'Write'],
|
|
183
|
+
},
|
|
184
|
+
};
|
|
167
185
|
// Renamed from `refreshCommand` as part of #694 (avoid collision with git sync
|
|
168
186
|
// semantics) and re-linked to `refreshHandler` in #919. Users who type
|
|
169
187
|
// `aiwg sync` still reach this handler via its 'sync' alias and see a
|
|
@@ -912,7 +930,7 @@ export const serveCommand = {
|
|
|
912
930
|
triggerPhrases: ['serve dashboard', 'start server', 'open dashboard', 'aiwg serve'],
|
|
913
931
|
commandHint: {
|
|
914
932
|
template: 'utility',
|
|
915
|
-
argumentHint: '[--port <n>] [--bind <host>] [--no-open] [--read-only]',
|
|
933
|
+
argumentHint: '[--port <n>] [--bind <host>] [--no-open] [--read-only] [--a2a-protocol <0.3|1.0|auto>] [--a2a-protocol-fallback] [--no-a2a-legacy-executor-fallback]',
|
|
916
934
|
allowedTools: ['Bash'],
|
|
917
935
|
},
|
|
918
936
|
},
|
|
@@ -3569,6 +3587,7 @@ export const commandDefinitions = [
|
|
|
3569
3587
|
doctorCommand,
|
|
3570
3588
|
contextFirewallCommand,
|
|
3571
3589
|
updateCommand,
|
|
3590
|
+
installationCommand,
|
|
3572
3591
|
refreshCommand,
|
|
3573
3592
|
regenerateCommand,
|
|
3574
3593
|
workspaceContextCommand,
|
|
@@ -72,7 +72,7 @@ export const FEATURE_CATALOG = [
|
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
name: 'graph',
|
|
75
|
-
description: 'Graphology backend for
|
|
75
|
+
description: 'Graphology backend for artifact-index traversal only; not Flow graph execution',
|
|
76
76
|
packages: ['graphology', 'graphology-operators', 'graphology-traversal'],
|
|
77
77
|
packageSpecs: {
|
|
78
78
|
graphology: '0.26.0',
|
|
@@ -82,6 +82,7 @@ export const FEATURE_CATALOG = [
|
|
|
82
82
|
enables: [
|
|
83
83
|
'index.graphBackend: graphology',
|
|
84
84
|
'in-memory attributed graph traversal and operator workflows',
|
|
85
|
+
'artifact graph data operations (use graph-pattern addon for Flow execution graphs)',
|
|
85
86
|
],
|
|
86
87
|
cost: '~2 MB — pure JS, no native deps',
|
|
87
88
|
},
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** A2A/telemetry metadata key reserved for the optional Flow graph profile. */
|
|
2
|
+
export const AIWG_GRAPH_METADATA_KEY = 'aiwg.flow.graph';
|
|
3
|
+
function nonEmpty(value) {
|
|
4
|
+
return typeof value === 'string' && value.length > 0;
|
|
5
|
+
}
|
|
6
|
+
export function isGraphExecutionMetadata(value) {
|
|
7
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
8
|
+
return false;
|
|
9
|
+
const item = value;
|
|
10
|
+
return item.schemaVersion === 'graph.flow.aiwg.io/v1'
|
|
11
|
+
&& nonEmpty(item.graphId)
|
|
12
|
+
&& nonEmpty(item.graphVersion)
|
|
13
|
+
&& nonEmpty(item.runId)
|
|
14
|
+
&& nonEmpty(item.nodeId)
|
|
15
|
+
&& nonEmpty(item.nodeRunId);
|
|
16
|
+
}
|
|
17
|
+
export function graphMetadataRecord(value) {
|
|
18
|
+
return { [AIWG_GRAPH_METADATA_KEY]: value };
|
|
19
|
+
}
|
|
20
|
+
export function extractGraphMetadata(metadata) {
|
|
21
|
+
const value = metadata?.[AIWG_GRAPH_METADATA_KEY];
|
|
22
|
+
return isGraphExecutionMetadata(value) ? value : undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Project graph metadata to an explicitly named audience. Public projection
|
|
26
|
+
* removes execution identifiers and decision evidence. Cockpit receives only
|
|
27
|
+
* the declared route-decision summary; arbitrary user/task context is never a
|
|
28
|
+
* member of this contract and is therefore dropped by construction.
|
|
29
|
+
*/
|
|
30
|
+
export function projectGraphMetadata(value, audience) {
|
|
31
|
+
if (!isGraphExecutionMetadata(value))
|
|
32
|
+
throw new Error('Invalid graph execution metadata.');
|
|
33
|
+
if (audience === 'internal')
|
|
34
|
+
return structuredClone(value);
|
|
35
|
+
const common = {
|
|
36
|
+
schemaVersion: value.schemaVersion,
|
|
37
|
+
graphVersion: value.graphVersion,
|
|
38
|
+
nodeId: value.nodeId,
|
|
39
|
+
...(value.edgeId ? { edgeId: value.edgeId } : {}),
|
|
40
|
+
...(value.routeName ? { routeName: value.routeName } : {}),
|
|
41
|
+
...(value.runtimeBinding ? { runtimeBinding: value.runtimeBinding } : {}),
|
|
42
|
+
...(value.nodeState ? { nodeState: value.nodeState } : {}),
|
|
43
|
+
};
|
|
44
|
+
if (audience === 'public')
|
|
45
|
+
return common;
|
|
46
|
+
return {
|
|
47
|
+
...common,
|
|
48
|
+
graphId: value.graphId,
|
|
49
|
+
runId: value.runId,
|
|
50
|
+
nodeRunId: value.nodeRunId,
|
|
51
|
+
...(value.checkpointId ? { checkpointId: value.checkpointId } : {}),
|
|
52
|
+
...(value.routeReason ? { routeReason: value.routeReason } : {}),
|
|
53
|
+
...(value.routeEvidence === undefined ? {} : { routeEvidence: structuredClone(value.routeEvidence) }),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=graph-metadata.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
function quoteCmdArgument(value) {
|
|
4
|
+
return `"${String(value).replace(/%/g, '%%').replace(/"/g, '""')}"`;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a package-manager invocation without asking Node to execute a
|
|
9
|
+
* Windows command script directly. Node rejects direct .cmd/.bat execution on
|
|
10
|
+
* current Windows releases; cmd.exe is the native interpreter for those files.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveManagerCommand(file, args, options = {}) {
|
|
13
|
+
const platform = options.platform ?? process.platform;
|
|
14
|
+
if (platform !== 'win32' || !/\.(?:cmd|bat)$/i.test(file)) {
|
|
15
|
+
return { file, args };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const env = options.env ?? process.env;
|
|
19
|
+
const commandInterpreter = env.ComSpec || env.COMSPEC || 'cmd.exe';
|
|
20
|
+
const command = `"${[file, ...args].map(quoteCmdArgument).join(' ')}"`;
|
|
21
|
+
return {
|
|
22
|
+
file: commandInterpreter,
|
|
23
|
+
args: ['/d', '/s', '/c', command],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function executeManagerCommand(file, args, options = {}) {
|
|
28
|
+
const invocation = resolveManagerCommand(file, args, options);
|
|
29
|
+
const execute = options.execute ?? execFileSync;
|
|
30
|
+
return execute(invocation.file, invocation.args, options.execOptions ?? { stdio: 'inherit' });
|
|
31
|
+
}
|