@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.
Files changed (50) hide show
  1. package/bin/aiwg.mjs +24 -2
  2. package/dist/src/a2a/agent-card.js +4 -1
  3. package/dist/src/a2a/client.js +148 -68
  4. package/dist/src/a2a/codecs.js +480 -0
  5. package/dist/src/a2a/events.js +226 -0
  6. package/dist/src/a2a/hitl-driver.js +8 -6
  7. package/dist/src/a2a/hitl.js +2 -1
  8. package/dist/src/a2a/http.js +85 -5
  9. package/dist/src/a2a/protocol.js +136 -0
  10. package/dist/src/a2a/types.js +4 -14
  11. package/dist/src/a2a/webhook.js +101 -4
  12. package/dist/src/artifacts/index-builder.js +63 -12
  13. package/dist/src/artifacts/index-files.js +26 -5
  14. package/dist/src/artifacts/query-engine.js +67 -67
  15. package/dist/src/artifacts/stats.js +6 -2
  16. package/dist/src/artifacts/types.js +1 -1
  17. package/dist/src/audit/operator-decision.js +15 -1
  18. package/dist/src/channel/manager.mjs +89 -17
  19. package/dist/src/cli/handlers/index.js +3 -1
  20. package/dist/src/cli/handlers/installation.js +79 -0
  21. package/dist/src/cli/handlers/refresh.js +6 -2
  22. package/dist/src/cli/handlers/runtime-info.js +9 -1
  23. package/dist/src/cli/handlers/serve.js +107 -4
  24. package/dist/src/cli/handlers/session.js +12 -26
  25. package/dist/src/cli/handlers/use.js +19 -4
  26. package/dist/src/cli/handlers/utilities.js +4 -0
  27. package/dist/src/cli/handlers/version.js +4 -0
  28. package/dist/src/config/user-config-dir.mjs +29 -0
  29. package/dist/src/config/user-config.js +4 -22
  30. package/dist/src/extensions/commands/definitions.js +20 -1
  31. package/dist/src/features/catalog.js +2 -1
  32. package/dist/src/flow/graph-metadata.js +56 -0
  33. package/dist/src/installation/manager-command.mjs +31 -0
  34. package/dist/src/installation/manager.mjs +264 -0
  35. package/dist/src/serve/a2a-terminal-observer.js +28 -5
  36. package/dist/src/serve/dispatch-router.js +32 -4
  37. package/dist/src/serve/executor-registry.js +29 -0
  38. package/dist/src/serve/mission-conductor.js +15 -1
  39. package/dist/src/serve/stack-adapters.js +2 -1
  40. package/dist/src/serve/telemetry.js +5 -1
  41. package/dist/src/smiths/context-pipeline/claude-hook.js +8 -5
  42. package/dist/src/smiths/context-pipeline/line-endings.js +12 -0
  43. package/dist/src/smiths/context-pipeline/managed-hook.js +8 -5
  44. package/dist/src/smiths/context-pipeline/workspace-context.js +3 -1
  45. package/dist/src/update/checker.mjs +16 -15
  46. package/dist/src/update/notifier.mjs +8 -3
  47. package/dist/src/update/service.mjs +51 -5
  48. package/package.json +1 -1
  49. package/tools/agents/deploy-agents.mjs +28 -8
  50. 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
- const r = spawnSync('npm', ['install', '-g', 'aiwg@latest'], { stdio: 'inherit' });
88
- if (r.status !== 0) {
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` first; if that fails, offer full reinstall.
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, installedFrameworks) {
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 sync sync and redeploy
143
- npm install -g aiwg@latest — reinstall package
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
- // Read installed frameworks before attempting repair (needed for redeploy)
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
- // 1. Explicit override from env or CLI flag
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 rich artifact traversal and graph operators',
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
+ }