@aiwg/cli 2026.8.20 → 2026.8.25
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/dist/src/cli/handlers/artifact-verify.js +3 -0
- package/dist/src/cli/handlers/refresh.js +37 -2
- package/dist/src/cli/handlers/subcommands.js +26 -20
- package/dist/src/cli/handlers/utilities.js +3 -0
- package/dist/src/cli/router.js +27 -0
- package/dist/src/installation/manager-command.mjs +10 -1
- package/dist/src/update/service.mjs +2 -5
- package/package.json +1 -1
|
@@ -102,6 +102,9 @@ export const artifactVerifyHandler = {
|
|
|
102
102
|
description: 'Verify cross-asset DSSE provenance and manage trust roots',
|
|
103
103
|
category: 'utility',
|
|
104
104
|
aliases: [],
|
|
105
|
+
async help() {
|
|
106
|
+
return { exitCode: 0, message: usage() };
|
|
107
|
+
},
|
|
105
108
|
async execute(ctx) {
|
|
106
109
|
if (ctx.args.includes('--help') || ctx.args.includes('-h') || ctx.args.length === 0)
|
|
107
110
|
return { exitCode: 0, message: usage() };
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @implements @agentic/code/frameworks/sdlc-complete/rules/self-maintenance.md
|
|
12
12
|
* @source @src/cli/router.ts
|
|
13
|
-
* @issue #482, #557, #694
|
|
13
|
+
* @issue #173, #174, #482, #557, #694
|
|
14
14
|
*/
|
|
15
15
|
import { promises as fs } from 'fs';
|
|
16
16
|
import path from 'path';
|
|
@@ -151,6 +151,30 @@ export function collectModelDeployArgs(args) {
|
|
|
151
151
|
}
|
|
152
152
|
return forwarded;
|
|
153
153
|
}
|
|
154
|
+
const REFRESH_HELP = `Usage: aiwg refresh [options]
|
|
155
|
+
|
|
156
|
+
Update AIWG, re-deploy installed frameworks, and run health verification.
|
|
157
|
+
|
|
158
|
+
Options:
|
|
159
|
+
--dry-run Preview changes without updating or deploying
|
|
160
|
+
--quiet Suppress progress output
|
|
161
|
+
--skip-update Skip the installation update
|
|
162
|
+
--packages-only Refresh remote packages only
|
|
163
|
+
--provider <name> Override provider auto-detection
|
|
164
|
+
--channel <name> Select the update channel (stable or main)
|
|
165
|
+
--frameworks <list> Re-deploy a comma-separated installed subset
|
|
166
|
+
--model <name> Override all deployed agent model tiers
|
|
167
|
+
--reasoning-model <name> Override the reasoning model tier
|
|
168
|
+
--coding-model <name> Override the coding model tier
|
|
169
|
+
--efficiency-model <name> Override the efficiency model tier
|
|
170
|
+
--filter <pattern> Limit model deployment by agent name
|
|
171
|
+
--filter-role <role> Limit model deployment by role
|
|
172
|
+
--model-tier <tier> Limit model deployment by tier
|
|
173
|
+
--save Save model overrides to the project
|
|
174
|
+
--save-user Save model overrides to user configuration
|
|
175
|
+
-h, --help Show this help without running refresh
|
|
176
|
+
|
|
177
|
+
Alias: aiwg sync (deprecated)`;
|
|
154
178
|
/**
|
|
155
179
|
* Refresh command handler (formerly sync)
|
|
156
180
|
*/
|
|
@@ -160,6 +184,9 @@ export const refreshHandler = {
|
|
|
160
184
|
description: 'Refresh AIWG to latest version and re-deploy installed frameworks',
|
|
161
185
|
category: 'maintenance',
|
|
162
186
|
aliases: ['--refresh', 'sync', '--sync'],
|
|
187
|
+
async help() {
|
|
188
|
+
return { exitCode: 0, message: REFRESH_HELP, rawOutput: true };
|
|
189
|
+
},
|
|
163
190
|
async execute(ctx) {
|
|
164
191
|
const dryRun = hasFlag(ctx.args, '--dry-run');
|
|
165
192
|
const quiet = hasFlag(ctx.args, '--quiet');
|
|
@@ -451,6 +478,10 @@ export const refreshHandler = {
|
|
|
451
478
|
if (dryRun) {
|
|
452
479
|
ui.info('Dry run complete — no changes made');
|
|
453
480
|
}
|
|
481
|
+
else if (updateFailure) {
|
|
482
|
+
ui.warn(`Refresh completed with installation update failure (exit ${updateFailure.exitCode}); ` +
|
|
483
|
+
're-deployment continued, but AIWG may still be on the previous version.');
|
|
484
|
+
}
|
|
454
485
|
else {
|
|
455
486
|
ui.success('Refresh complete');
|
|
456
487
|
}
|
|
@@ -459,7 +490,11 @@ export const refreshHandler = {
|
|
|
459
490
|
// Quiet mode: JSON output
|
|
460
491
|
if (quiet) {
|
|
461
492
|
const output = JSON.stringify({
|
|
462
|
-
status: dryRun
|
|
493
|
+
status: dryRun
|
|
494
|
+
? 'dry-run'
|
|
495
|
+
: updateFailure
|
|
496
|
+
? 'refreshed-with-update-failure'
|
|
497
|
+
: 'refreshed',
|
|
463
498
|
provider: detectedProvider,
|
|
464
499
|
frameworks,
|
|
465
500
|
skipUpdate,
|
|
@@ -1139,34 +1139,40 @@ export const pluginStatusHandler = {
|
|
|
1139
1139
|
*
|
|
1140
1140
|
* Delegates to tools/plugin/package-plugins.mjs
|
|
1141
1141
|
*/
|
|
1142
|
+
function packagePluginHelp() {
|
|
1143
|
+
return {
|
|
1144
|
+
exitCode: 0,
|
|
1145
|
+
message: [
|
|
1146
|
+
"aiwg package-plugin — package a project-local or built-in marketplace wrapper",
|
|
1147
|
+
"",
|
|
1148
|
+
"Usage:",
|
|
1149
|
+
" aiwg package-plugin <name> [--source <path>] [--output <path>] [--provider <name>] [--clean] [--dry-run]",
|
|
1150
|
+
" aiwg package-plugin --plugin <name> [options] # compatibility form",
|
|
1151
|
+
"",
|
|
1152
|
+
"Options:",
|
|
1153
|
+
" --source <path> explicit project-local wrapper source (must stay inside the project)",
|
|
1154
|
+
" --output <path> standalone archive output (default: dist/plugins)",
|
|
1155
|
+
" --provider <name> claude, codex, or all for standalone wrappers; built-ins retain all formats",
|
|
1156
|
+
" --clean clean generated plugin output before packaging",
|
|
1157
|
+
" --dry-run, -n preview without writing",
|
|
1158
|
+
" --help, -h show this help",
|
|
1159
|
+
"",
|
|
1160
|
+
"Project-local wrappers are discovered under .aiwg/plugins and packaged as deterministic archives.",
|
|
1161
|
+
].join("\n"),
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1142
1164
|
export const packagePluginHandler = {
|
|
1143
1165
|
id: "package-plugin",
|
|
1144
1166
|
name: "Package Plugin",
|
|
1145
1167
|
description: "Package a plugin for distribution",
|
|
1146
1168
|
category: "plugin",
|
|
1147
1169
|
aliases: ["-package-plugin", "--package-plugin"],
|
|
1170
|
+
async help() {
|
|
1171
|
+
return packagePluginHelp();
|
|
1172
|
+
},
|
|
1148
1173
|
async execute(ctx) {
|
|
1149
1174
|
if (ctx.args.includes("--help") || ctx.args.includes("-h")) {
|
|
1150
|
-
return
|
|
1151
|
-
exitCode: 0,
|
|
1152
|
-
message: [
|
|
1153
|
-
"aiwg package-plugin — package a project-local or built-in marketplace wrapper",
|
|
1154
|
-
"",
|
|
1155
|
-
"Usage:",
|
|
1156
|
-
" aiwg package-plugin <name> [--source <path>] [--output <path>] [--provider <name>] [--clean] [--dry-run]",
|
|
1157
|
-
" aiwg package-plugin --plugin <name> [options] # compatibility form",
|
|
1158
|
-
"",
|
|
1159
|
-
"Options:",
|
|
1160
|
-
" --source <path> explicit project-local wrapper source (must stay inside the project)",
|
|
1161
|
-
" --output <path> standalone archive output (default: dist/plugins)",
|
|
1162
|
-
" --provider <name> claude, codex, or all for standalone wrappers; built-ins retain all formats",
|
|
1163
|
-
" --clean clean generated plugin output before packaging",
|
|
1164
|
-
" --dry-run, -n preview without writing",
|
|
1165
|
-
" --help, -h show this help",
|
|
1166
|
-
"",
|
|
1167
|
-
"Project-local wrappers are discovered under .aiwg/plugins and packaged as deterministic archives.",
|
|
1168
|
-
].join("\n"),
|
|
1169
|
-
};
|
|
1175
|
+
return packagePluginHelp();
|
|
1170
1176
|
}
|
|
1171
1177
|
const hasExplicitPlugin = ctx.args.includes("--plugin") || ctx.args.includes("-p");
|
|
1172
1178
|
const positional = ctx.args[0] && !ctx.args[0].startsWith("-")
|
|
@@ -466,6 +466,9 @@ export const doctorHandler = {
|
|
|
466
466
|
description: 'Run health diagnostics',
|
|
467
467
|
category: 'maintenance',
|
|
468
468
|
aliases: ['-doctor', '--doctor'],
|
|
469
|
+
async help() {
|
|
470
|
+
return { exitCode: 0, message: DOCTOR_HELP, rawOutput: true };
|
|
471
|
+
},
|
|
469
472
|
async execute(ctx) {
|
|
470
473
|
if (ctx.args.includes('--help') || ctx.args.includes('-h')) {
|
|
471
474
|
return { exitCode: 0, message: DOCTOR_HELP, rawOutput: true };
|
package/dist/src/cli/router.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* @tests @test/unit/cli/router.test.ts
|
|
11
11
|
* @issue #33
|
|
12
12
|
* @issue #58
|
|
13
|
+
* @issue #174
|
|
13
14
|
*/
|
|
14
15
|
import { loadRegistry } from '../extensions/loader.js';
|
|
15
16
|
import { getFrameworkRoot } from '../channel/manager.mjs';
|
|
@@ -134,6 +135,32 @@ export async function run(args, options = {}) {
|
|
|
134
135
|
ui.error(`No handler found for command: ${commandId}`);
|
|
135
136
|
process.exit(1);
|
|
136
137
|
}
|
|
138
|
+
// Help must be intercepted before hooks and the normal handler path. Some
|
|
139
|
+
// commands mutate project or installation state, so passing an unrecognised
|
|
140
|
+
// help flag through to execute() is unsafe (#174).
|
|
141
|
+
if (commandArgs.includes('--help') || commandArgs.includes('-h')) {
|
|
142
|
+
const ctx = await buildContext(commandArgs, args, options);
|
|
143
|
+
if (handler.help) {
|
|
144
|
+
const result = await handler.help(ctx);
|
|
145
|
+
if (result.message) {
|
|
146
|
+
if (result.rawOutput) {
|
|
147
|
+
process.stdout.write(result.message.endsWith('\n') ? result.message : `${result.message}\n`);
|
|
148
|
+
}
|
|
149
|
+
else if (result.exitCode !== 0) {
|
|
150
|
+
ui.error(result.message);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
ui.info(result.message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (result.exitCode !== 0)
|
|
157
|
+
process.exit(result.exitCode);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
ui.info(`No detailed help for \`aiwg ${commandId}\`. Run \`aiwg help\` for the command overview.`);
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
137
164
|
// Build context for handler and hooks
|
|
138
165
|
const ctx = await buildContext(commandArgs, args, options);
|
|
139
166
|
// Build hook context
|
|
@@ -21,11 +21,20 @@ export function resolveManagerCommand(file, args, options = {}) {
|
|
|
21
21
|
return {
|
|
22
22
|
file: commandInterpreter,
|
|
23
23
|
args: ['/d', '/s', '/c', command],
|
|
24
|
+
// The payload above already contains cmd.exe-native quoting. Instruct
|
|
25
|
+
// Node not to apply MSVCRT escaping to those embedded quotes (#173).
|
|
26
|
+
windowsVerbatimArguments: true,
|
|
24
27
|
};
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export function executeManagerCommand(file, args, options = {}) {
|
|
28
31
|
const invocation = resolveManagerCommand(file, args, options);
|
|
29
32
|
const execute = options.execute ?? execFileSync;
|
|
30
|
-
|
|
33
|
+
const execOptions = options.execOptions
|
|
34
|
+
? { ...options.execOptions }
|
|
35
|
+
: { stdio: 'inherit' };
|
|
36
|
+
if (invocation.windowsVerbatimArguments === true) {
|
|
37
|
+
execOptions.windowsVerbatimArguments = true;
|
|
38
|
+
}
|
|
39
|
+
return execute(invocation.file, invocation.args, execOptions);
|
|
31
40
|
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* the calling handlers.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { execFileSync } from 'node:child_process';
|
|
10
9
|
import { existsSync, readFileSync } from 'node:fs';
|
|
11
10
|
import path from 'node:path';
|
|
12
11
|
import { getPackageRoot, loadConfig } from '../channel/manager.mjs';
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
loadInstallationIdentity,
|
|
17
16
|
saveInstallationIdentity,
|
|
18
17
|
} from '../installation/manager.mjs';
|
|
19
|
-
import {
|
|
18
|
+
import { executeManagerCommand } from '../installation/manager-command.mjs';
|
|
20
19
|
|
|
21
20
|
const VALID_MODES = new Set(['npm', 'web', 'source']);
|
|
22
21
|
|
|
@@ -149,9 +148,7 @@ export async function updateInstallation(options = {}) {
|
|
|
149
148
|
throw new Error('Canonical npm installation has no package-manager executable. Run `aiwg installation adopt --manager <absolute-path-to-npm>`.');
|
|
150
149
|
}
|
|
151
150
|
if (!dryRun) {
|
|
152
|
-
|
|
153
|
-
const execute = options.execute ?? ((file, args) => execFileSync(file, args, { stdio: 'inherit' }));
|
|
154
|
-
execute(invocation.file, invocation.args);
|
|
151
|
+
executeManagerCommand(managerExecutable, command, options);
|
|
155
152
|
if (detected.identity && detected.identityPersistent && options.persistIdentity !== false) {
|
|
156
153
|
saveInstallationIdentity({ ...detected.identity, channel }, options);
|
|
157
154
|
}
|