@aiwg/cli 2026.7.19 → 2026.7.21
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/README.md +397 -385
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/browser-export.js +7 -0
- package/dist/src/artifacts/citation-parser.js +96 -35
- package/dist/src/artifacts/cli.js +59 -5
- package/dist/src/artifacts/discover-facets.js +15 -0
- package/dist/src/artifacts/discovery-eval.js +290 -0
- package/dist/src/artifacts/fortemi-core-query-adapter.js +1 -1
- package/dist/src/artifacts/fortemi-shard-export.js +1 -1
- package/dist/src/artifacts/index-builder.js +54 -17
- package/dist/src/artifacts/query-engine.js +10 -6
- package/dist/src/artifacts/state-transfer.js +27 -0
- package/dist/src/artifacts/stats.js +8 -0
- package/dist/src/cli/cli-extension-loader.js +73 -0
- package/dist/src/cli/handlers/help.js +2 -1
- package/dist/src/cli/handlers/index.js +6 -2
- package/dist/src/cli/handlers/resource-versions.js +247 -0
- package/dist/src/cli/handlers/sessions.js +966 -0
- package/dist/src/cli/handlers/skill-lint.js +49 -45
- package/dist/src/cli/handlers/subcommands.js +55 -3
- package/dist/src/cli/handlers/use.js +154 -59
- package/dist/src/cli/handlers/utilities.js +49 -34
- package/dist/src/cli/skill-usage.js +146 -24
- package/dist/src/config/cli.js +13 -9
- package/dist/src/config/project-artifacts-runtime.mjs +68 -0
- package/dist/src/config/project-artifacts.js +1 -68
- package/dist/src/extensions/commands/definitions.js +65 -2
- package/dist/src/extensions/manifest.js +29 -0
- package/dist/src/extensions/project-local-discovery.js +86 -2
- package/dist/src/extensions/project-local-remove.js +52 -56
- package/dist/src/extensions/shadow-resolver.js +3 -1
- package/dist/src/plugins/standalone-packager.js +143 -0
- package/dist/src/resources/cache-cleanup.js +67 -0
- package/dist/src/resources/doctor.js +107 -0
- package/dist/src/resources/lockfile.js +125 -0
- package/dist/src/resources/resolver.js +133 -0
- package/dist/src/resources/web-release.d.ts +8 -0
- package/dist/src/resources/web-release.js +159 -1
- package/dist/src/sessions/adapters/claude.js +357 -0
- package/dist/src/sessions/adapters/codex.js +521 -0
- package/dist/src/sessions/adapters/copilot.js +226 -0
- package/dist/src/sessions/adapters/cursor.js +372 -0
- package/dist/src/sessions/adapters/factory.js +345 -0
- package/dist/src/sessions/adapters/generic.js +225 -0
- package/dist/src/sessions/adapters/hermes.js +341 -0
- package/dist/src/sessions/adapters/openclaw.js +381 -0
- package/dist/src/sessions/adapters/opencode.js +454 -0
- package/dist/src/sessions/adapters/openhuman.js +315 -0
- package/dist/src/sessions/adapters/warp.js +160 -0
- package/dist/src/sessions/adapters/windsurf.js +212 -0
- package/dist/src/sessions/candidates.js +210 -0
- package/dist/src/sessions/contracts.js +310 -0
- package/dist/src/sessions/discovery.js +51 -0
- package/dist/src/sessions/fixtures.js +12 -0
- package/dist/src/sessions/importer.js +315 -0
- package/dist/src/sessions/index.js +25 -0
- package/dist/src/sessions/knowledge-shard.js +61 -0
- package/dist/src/sessions/optional-backends.js +238 -0
- package/dist/src/sessions/policy.js +192 -0
- package/dist/src/sessions/ports.js +2 -0
- package/dist/src/sessions/promotion.js +367 -0
- package/dist/src/sessions/readers.js +176 -0
- package/dist/src/sessions/repository.js +1551 -0
- package/dist/src/skills/adapters/agent-skills.js +59 -0
- package/dist/src/skills/adapters/local.js +19 -1
- package/dist/src/skills/agent-skills.js +249 -0
- package/dist/src/skills/cli.js +463 -7
- package/dist/src/skills/deployer.js +554 -0
- package/dist/src/skills/doctor.js +105 -0
- package/dist/src/skills/exporter.js +382 -0
- package/dist/src/skills/importer.js +921 -0
- package/dist/src/skills/registry.js +19 -0
- package/dist/src/skills/validator.js +323 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +5 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +21 -1
- package/dist/src/smiths/context-pipeline/finalization.js +5 -3
- package/dist/src/smiths/context-pipeline/generator.js +4 -1
- package/dist/src/smiths/context-pipeline/parallelism-section.js +34 -1
- package/dist/src/smiths/context-pipeline/workspace-context.js +15 -3
- package/dist/src/smiths/mcpsmith/example.js +3 -1
- package/dist/src/smiths/mcpsmith/generator.js +3 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +2 -1
- package/dist/src/storage/cli.js +3 -2
- package/dist/src/storage/subsystem-cli.js +7 -2
- package/dist/src/update/notifier.mjs +1 -1
- package/dist/src/update/service.mjs +123 -0
- package/package.json +3 -2
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import * as fs from 'fs/promises';
|
|
13
13
|
import * as path from 'path';
|
|
14
|
-
import * as yaml from 'js-yaml';
|
|
15
14
|
import { validateSkillFrontmatter } from '../../extensions/validation.js';
|
|
15
|
+
import { validateAgentSkillFile } from '../../skills/validator.js';
|
|
16
16
|
const THRESHOLDS = {
|
|
17
17
|
strict: 80,
|
|
18
18
|
standard: 60,
|
|
@@ -36,7 +36,14 @@ function partialDimension(score, notes) {
|
|
|
36
36
|
* because the cleanup work in #1015 made schema correctness a baseline
|
|
37
37
|
* expectation across the corpus.
|
|
38
38
|
*/
|
|
39
|
-
function scoreSchema(frontmatter) {
|
|
39
|
+
function scoreSchema(frontmatter, diagnostics) {
|
|
40
|
+
const conformanceErrors = diagnostics.filter((item) => item.severity === 'error');
|
|
41
|
+
if (conformanceErrors.length > 0) {
|
|
42
|
+
const notes = conformanceErrors.map((item) => (item.code === 'AS_YAML_PARSE'
|
|
43
|
+
? `YAML parse error: ${item.message}`
|
|
44
|
+
: `${item.yamlPath}: ${item.message} [${item.code}]`));
|
|
45
|
+
return scoreDimension(false, notes);
|
|
46
|
+
}
|
|
40
47
|
const result = validateSkillFrontmatter(frontmatter);
|
|
41
48
|
if (result.success)
|
|
42
49
|
return scoreDimension(true);
|
|
@@ -190,38 +197,12 @@ function inventoryCompanionCli(filePath, body) {
|
|
|
190
197
|
* @param filePath - Absolute or relative path to the SKILL.md
|
|
191
198
|
* @param rubric - Strictness level (drives the pass threshold)
|
|
192
199
|
*/
|
|
193
|
-
export async function lintSkillFile(filePath, rubric = 'standard') {
|
|
194
|
-
const
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
return {
|
|
198
|
-
file: filePath,
|
|
199
|
-
score: 0,
|
|
200
|
-
passes: false,
|
|
201
|
-
dimensions: {
|
|
202
|
-
schema: scoreDimension(false, ['no YAML frontmatter found']),
|
|
203
|
-
description: scoreDimension(false, ['no frontmatter to derive description from']),
|
|
204
|
-
discoverability: scoreDimension(false, ['no frontmatter']),
|
|
205
|
-
body: scoreBody(content),
|
|
206
|
-
},
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
const [, fmText, body = ''] = fmMatch;
|
|
210
|
-
let frontmatter = {};
|
|
211
|
-
let yamlError = null;
|
|
212
|
-
try {
|
|
213
|
-
const parsed = yaml.load(fmText);
|
|
214
|
-
if (parsed && typeof parsed === 'object') {
|
|
215
|
-
frontmatter = parsed;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
catch (e) {
|
|
219
|
-
yamlError = e.message.split('\n')[0];
|
|
220
|
-
}
|
|
200
|
+
export async function lintSkillFile(filePath, rubric = 'standard', profile = 'compatible') {
|
|
201
|
+
const validation = validateAgentSkillFile(filePath, { profile });
|
|
202
|
+
const frontmatter = validation.frontmatter ?? {};
|
|
203
|
+
const body = validation.body;
|
|
221
204
|
const dimensions = {
|
|
222
|
-
schema:
|
|
223
|
-
? scoreDimension(false, [`YAML parse error: ${yamlError}`])
|
|
224
|
-
: scoreSchema(frontmatter),
|
|
205
|
+
schema: scoreSchema(frontmatter, validation.diagnostics),
|
|
225
206
|
description: scoreDescription(frontmatter),
|
|
226
207
|
discoverability: scoreDiscoverability(frontmatter),
|
|
227
208
|
body: scoreBody(body),
|
|
@@ -230,7 +211,12 @@ export async function lintSkillFile(filePath, rubric = 'standard') {
|
|
|
230
211
|
return {
|
|
231
212
|
file: filePath,
|
|
232
213
|
score,
|
|
233
|
-
|
|
214
|
+
conformance: {
|
|
215
|
+
profile,
|
|
216
|
+
state: validation.state,
|
|
217
|
+
diagnostics: validation.diagnostics,
|
|
218
|
+
},
|
|
219
|
+
passes: validation.valid && score >= THRESHOLDS[rubric],
|
|
234
220
|
dimensions,
|
|
235
221
|
};
|
|
236
222
|
}
|
|
@@ -243,7 +229,8 @@ async function* walkSkillFiles(rootPath) {
|
|
|
243
229
|
}
|
|
244
230
|
if (!stat.isDirectory())
|
|
245
231
|
return;
|
|
246
|
-
const entries = await fs.readdir(rootPath, { withFileTypes: true })
|
|
232
|
+
const entries = (await fs.readdir(rootPath, { withFileTypes: true }))
|
|
233
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
247
234
|
for (const e of entries) {
|
|
248
235
|
if (e.name.startsWith('.') || e.name === 'node_modules')
|
|
249
236
|
continue;
|
|
@@ -265,7 +252,7 @@ async function* walkSkillFiles(rootPath) {
|
|
|
265
252
|
* Pure function — does not print or exit. The CLI handler renders
|
|
266
253
|
* output and translates the report into an exit code.
|
|
267
254
|
*/
|
|
268
|
-
export async function lintSkills(targetPaths, rubric = 'standard') {
|
|
255
|
+
export async function lintSkills(targetPaths, rubric = 'standard', profile = 'compatible') {
|
|
269
256
|
const targets = Array.isArray(targetPaths) ? targetPaths : [targetPaths];
|
|
270
257
|
const seen = new Set();
|
|
271
258
|
const files = [];
|
|
@@ -275,7 +262,7 @@ export async function lintSkills(targetPaths, rubric = 'standard') {
|
|
|
275
262
|
if (seen.has(resolved))
|
|
276
263
|
continue;
|
|
277
264
|
seen.add(resolved);
|
|
278
|
-
files.push(await lintSkillFile(f, rubric));
|
|
265
|
+
files.push(await lintSkillFile(f, rubric, profile));
|
|
279
266
|
}
|
|
280
267
|
}
|
|
281
268
|
const total = files.reduce((sum, f) => sum + f.score, 0);
|
|
@@ -289,6 +276,7 @@ export async function lintSkills(targetPaths, rubric = 'standard') {
|
|
|
289
276
|
}
|
|
290
277
|
return {
|
|
291
278
|
rubric,
|
|
279
|
+
profile,
|
|
292
280
|
threshold: THRESHOLDS[rubric],
|
|
293
281
|
files,
|
|
294
282
|
averageScore: files.length > 0 ? Math.round(total / files.length) : 0,
|
|
@@ -303,6 +291,7 @@ export async function lintSkills(targetPaths, rubric = 'standard') {
|
|
|
303
291
|
function parseArgs(args) {
|
|
304
292
|
const targets = [];
|
|
305
293
|
let rubric = 'standard';
|
|
294
|
+
let profile = 'compatible';
|
|
306
295
|
let json = false;
|
|
307
296
|
for (let i = 0; i < args.length; i++) {
|
|
308
297
|
const a = args[i];
|
|
@@ -315,27 +304,42 @@ function parseArgs(args) {
|
|
|
315
304
|
rubric = next;
|
|
316
305
|
}
|
|
317
306
|
}
|
|
307
|
+
else if (a === '--profile' && i + 1 < args.length) {
|
|
308
|
+
const next = args[++i];
|
|
309
|
+
if (next === 'strict' || next === 'compatible' || next === 'discovery') {
|
|
310
|
+
profile = next;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
318
313
|
else if (!a.startsWith('-')) {
|
|
319
314
|
targets.push(a);
|
|
320
315
|
}
|
|
321
316
|
}
|
|
322
317
|
if (targets.length === 0)
|
|
323
318
|
targets.push('agentic/code');
|
|
324
|
-
return { targets, rubric, json };
|
|
319
|
+
return { targets, rubric, profile, json };
|
|
325
320
|
}
|
|
326
321
|
function renderTextReport(report) {
|
|
327
|
-
const { files, threshold, rubric, averageScore, failedCount } = report;
|
|
322
|
+
const { files, threshold, rubric, profile, averageScore, failedCount } = report;
|
|
328
323
|
for (const f of files) {
|
|
329
|
-
if (f.passes)
|
|
324
|
+
if (f.passes && f.conformance.diagnostics.length === 0)
|
|
330
325
|
continue;
|
|
331
|
-
|
|
326
|
+
const mark = !f.passes
|
|
327
|
+
? '✗'
|
|
328
|
+
: f.conformance.diagnostics.some((item) => item.severity === 'warning')
|
|
329
|
+
? '⚠'
|
|
330
|
+
: '✓';
|
|
331
|
+
console.log(`${mark} ${f.file} (${f.score}/100, conformance=${f.conformance.state})`);
|
|
332
|
+
for (const item of f.conformance.diagnostics) {
|
|
333
|
+
console.log(` ${item.severity} ${item.code} ${item.yamlPath}: ${item.message}; `
|
|
334
|
+
+ `fix: ${item.remediation}`);
|
|
335
|
+
}
|
|
332
336
|
for (const [name, dim] of Object.entries(f.dimensions)) {
|
|
333
|
-
if (dim.score < 100) {
|
|
337
|
+
if (!f.passes && dim.score < 100) {
|
|
334
338
|
console.log(` ${name} (${dim.score}): ${dim.notes.join('; ')}`);
|
|
335
339
|
}
|
|
336
340
|
}
|
|
337
341
|
}
|
|
338
|
-
console.log(`\nskill-lint (rubric=${rubric}, threshold=${threshold}):`);
|
|
342
|
+
console.log(`\nskill-lint (rubric=${rubric}, profile=${profile}, threshold=${threshold}):`);
|
|
339
343
|
console.log(` ${files.length} file(s) scanned`);
|
|
340
344
|
console.log(` ${failedCount} below threshold`);
|
|
341
345
|
console.log(` average score: ${averageScore}/100`);
|
|
@@ -351,8 +355,8 @@ export const skillLintHandler = {
|
|
|
351
355
|
category: 'utility',
|
|
352
356
|
aliases: ['-skill-lint', '--skill-lint'],
|
|
353
357
|
async execute(ctx) {
|
|
354
|
-
const { targets, rubric, json } = parseArgs(ctx.args);
|
|
355
|
-
const report = await lintSkills(targets, rubric);
|
|
358
|
+
const { targets, rubric, profile, json } = parseArgs(ctx.args);
|
|
359
|
+
const report = await lintSkills(targets, rubric, profile);
|
|
356
360
|
if (json) {
|
|
357
361
|
console.log(JSON.stringify(report, null, 2));
|
|
358
362
|
}
|
|
@@ -1115,9 +1115,44 @@ export const packagePluginHandler = {
|
|
|
1115
1115
|
category: "plugin",
|
|
1116
1116
|
aliases: ["-package-plugin", "--package-plugin"],
|
|
1117
1117
|
async execute(ctx) {
|
|
1118
|
+
if (ctx.args.includes("--help") || ctx.args.includes("-h")) {
|
|
1119
|
+
return {
|
|
1120
|
+
exitCode: 0,
|
|
1121
|
+
message: [
|
|
1122
|
+
"aiwg package-plugin — package a project-local or built-in marketplace wrapper",
|
|
1123
|
+
"",
|
|
1124
|
+
"Usage:",
|
|
1125
|
+
" aiwg package-plugin <name> [--source <path>] [--output <path>] [--provider <name>] [--clean] [--dry-run]",
|
|
1126
|
+
" aiwg package-plugin --plugin <name> [options] # compatibility form",
|
|
1127
|
+
"",
|
|
1128
|
+
"Options:",
|
|
1129
|
+
" --source <path> explicit project-local wrapper source (must stay inside the project)",
|
|
1130
|
+
" --output <path> standalone archive output (default: dist/plugins)",
|
|
1131
|
+
" --provider <name> claude, codex, or all for standalone wrappers; built-ins retain all formats",
|
|
1132
|
+
" --clean clean generated plugin output before packaging",
|
|
1133
|
+
" --dry-run, -n preview without writing",
|
|
1134
|
+
" --help, -h show this help",
|
|
1135
|
+
"",
|
|
1136
|
+
"Project-local wrappers are discovered under .aiwg/plugins and packaged as deterministic archives.",
|
|
1137
|
+
].join("\n"),
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
const hasExplicitPlugin = ctx.args.includes("--plugin") || ctx.args.includes("-p");
|
|
1141
|
+
const positional = ctx.args[0] && !ctx.args[0].startsWith("-")
|
|
1142
|
+
? ctx.args[0]
|
|
1143
|
+
: undefined;
|
|
1144
|
+
if (!hasExplicitPlugin && !positional) {
|
|
1145
|
+
return {
|
|
1146
|
+
exitCode: 1,
|
|
1147
|
+
message: "Error: plugin name is required.\n\nRun `aiwg package-plugin --help` for usage.",
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
const normalizedArgs = hasExplicitPlugin
|
|
1151
|
+
? ctx.args
|
|
1152
|
+
: ["--plugin", positional, ...ctx.args.slice(1)];
|
|
1118
1153
|
const frameworkRoot = await getFrameworkRoot();
|
|
1119
1154
|
const runner = createScriptRunner(frameworkRoot);
|
|
1120
|
-
return runner.run("tools/plugin/package-plugins.mjs",
|
|
1155
|
+
return runner.run("tools/plugin/package-plugins.mjs", normalizedArgs, {
|
|
1121
1156
|
cwd: ctx.cwd,
|
|
1122
1157
|
});
|
|
1123
1158
|
},
|
|
@@ -1134,6 +1169,23 @@ export const packageAllPluginsHandler = {
|
|
|
1134
1169
|
category: "plugin",
|
|
1135
1170
|
aliases: ["-package-all-plugins", "--package-all-plugins"],
|
|
1136
1171
|
async execute(ctx) {
|
|
1172
|
+
if (ctx.args.includes("--help") || ctx.args.includes("-h")) {
|
|
1173
|
+
return {
|
|
1174
|
+
exitCode: 0,
|
|
1175
|
+
message: [
|
|
1176
|
+
"aiwg package-all-plugins — package every built-in marketplace wrapper",
|
|
1177
|
+
"",
|
|
1178
|
+
"Usage:",
|
|
1179
|
+
" aiwg package-all-plugins [--provider <name>] [--clean] [--dry-run]",
|
|
1180
|
+
"",
|
|
1181
|
+
"Options:",
|
|
1182
|
+
" --provider <name> claude, codex, cursor, factory, openclaw, or all",
|
|
1183
|
+
" --clean clean generated plugin output before packaging",
|
|
1184
|
+
" --dry-run, -n preview without writing",
|
|
1185
|
+
" --help, -h show this help",
|
|
1186
|
+
].join("\n"),
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1137
1189
|
const frameworkRoot = await getFrameworkRoot();
|
|
1138
1190
|
const runner = createScriptRunner(frameworkRoot);
|
|
1139
1191
|
return runner.run("tools/plugin/package-plugins.mjs", ["--all", ...ctx.args], {
|
|
@@ -1199,7 +1251,7 @@ export const corpusHandler = {
|
|
|
1199
1251
|
* with the project's general-purpose artifact graph indices.
|
|
1200
1252
|
*
|
|
1201
1253
|
* aiwg discover "<phrase>" [--limit N] [--type skill,agent,...] [--json]
|
|
1202
|
-
* [--resource-source local|web|auto] [--aiwg-version <
|
|
1254
|
+
* [--resource-source local|web|auto] [--aiwg-version <version|range|digest|channel>] [--offline]
|
|
1203
1255
|
*/
|
|
1204
1256
|
export const discoverHandler = {
|
|
1205
1257
|
id: "discover",
|
|
@@ -1254,7 +1306,7 @@ export const featuresHandler = {
|
|
|
1254
1306
|
* so consumers don't need to navigate AIWG's storage paths themselves.
|
|
1255
1307
|
*
|
|
1256
1308
|
* aiwg show <name> [--type skill,agent,...] [--json] [--first]
|
|
1257
|
-
* [--resource-source local|web|auto] [--aiwg-version <
|
|
1309
|
+
* [--resource-source local|web|auto] [--aiwg-version <version|range|digest|channel>] [--offline]
|
|
1258
1310
|
*/
|
|
1259
1311
|
export const showHandler = {
|
|
1260
1312
|
id: "show",
|
|
@@ -17,7 +17,7 @@ import { createScriptRunner } from './script-runner.js';
|
|
|
17
17
|
import { getFrameworkRoot, getVersionInfo } from '../../channel/manager.mjs';
|
|
18
18
|
import { getRegistry } from '../../extensions/registry.js';
|
|
19
19
|
import { registerDeployedExtensions } from '../../extensions/deployment-registration.js';
|
|
20
|
-
import { registerCliCommands, registerHooks } from '../cli-extension-loader.js';
|
|
20
|
+
import { loadCliCommandsContribution, registerCliCommands, registerHooks, } from '../cli-extension-loader.js';
|
|
21
21
|
import { translateSkillsToCommands, providerNeedsCommands } from '../../plugin/skill-command-translator.js';
|
|
22
22
|
import * as ui from '../ui.js';
|
|
23
23
|
import { readAiwgConfig, writeAiwgConfig, updateInstalled, hashManifest, emptyConfig, getProjectDir } from '../../config/aiwg-config.js';
|
|
@@ -270,6 +270,25 @@ export function addonPath(frameworkRoot, name) {
|
|
|
270
270
|
const folderName = resolveAddonFolderName(name);
|
|
271
271
|
return path.join(frameworkRoot, 'agentic/code/addons', folderName);
|
|
272
272
|
}
|
|
273
|
+
async function registerSourceCliCommands(opts) {
|
|
274
|
+
const contribution = await loadCliCommandsContribution(opts.source);
|
|
275
|
+
if (!contribution)
|
|
276
|
+
return 0;
|
|
277
|
+
const { manifest, commandsSource } = contribution;
|
|
278
|
+
const count = Object.keys(manifest.subcommands).length;
|
|
279
|
+
if (opts.dryRun) {
|
|
280
|
+
ui.dim(` [dry-run] Would register CLI namespace '${manifest.namespace}' (${count} subcommands)`);
|
|
281
|
+
return count;
|
|
282
|
+
}
|
|
283
|
+
await registerCliCommands(opts.target, manifest.namespace, manifest.description || opts.fallbackDescription, commandsSource, manifest.subcommands);
|
|
284
|
+
ui.success(`CLI namespace '${manifest.namespace}' registered (${count} subcommands)`);
|
|
285
|
+
if (opts.provider === 'claude') {
|
|
286
|
+
const registeredHooks = await registerHooks(opts.target, manifest.namespace, manifest.subcommands);
|
|
287
|
+
for (const hook of registeredHooks)
|
|
288
|
+
ui.success(`Hook registered: ${hook}`);
|
|
289
|
+
}
|
|
290
|
+
return count;
|
|
291
|
+
}
|
|
273
292
|
function getProviderPaths(provider) {
|
|
274
293
|
const paths = getProviderArtifactPathStrings(provider) ?? getProviderArtifactPathStrings('claude');
|
|
275
294
|
if (!paths)
|
|
@@ -775,48 +794,84 @@ async function countBundleSourceArtifacts(bundlePath) {
|
|
|
775
794
|
*/
|
|
776
795
|
async function deployOneProjectLocalBundle(opts) {
|
|
777
796
|
const { bundle, ctx, frameworkRoot, provider, target, dryRun, verbose, quiet, modelArgs } = opts;
|
|
778
|
-
const
|
|
779
|
-
const
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
if (
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
797
|
+
const counts = await countBundleSourceArtifacts(bundle.artifactPath);
|
|
798
|
+
const artifactTotal = counts.agents + counts.commands + counts.skills + counts.rules;
|
|
799
|
+
let cliCommandCount = 0;
|
|
800
|
+
try {
|
|
801
|
+
const contribution = await loadCliCommandsContribution(bundle.artifactPath);
|
|
802
|
+
cliCommandCount = contribution ? Object.keys(contribution.manifest.subcommands).length : 0;
|
|
803
|
+
}
|
|
804
|
+
catch (error) {
|
|
805
|
+
ui.warn(`Invalid CLI contribution for project-local '${bundle.id}': ${error.message}`);
|
|
806
|
+
return { exitCode: 1, counts };
|
|
807
|
+
}
|
|
808
|
+
if (verbose || dryRun) {
|
|
809
|
+
ui.dim(` Artifacts: agents=${counts.agents} commands=${counts.commands} skills=${counts.skills} rules=${counts.rules} cli=${cliCommandCount}`);
|
|
810
|
+
}
|
|
811
|
+
if (artifactTotal === 0 && cliCommandCount === 0) {
|
|
812
|
+
ui.warn(`Project-local ${bundle.type} '${bundle.id}' has no deployable agents, commands, skills, rules, or CLI commands at ${bundle.artifactPath}`);
|
|
813
|
+
return { exitCode: 1, counts };
|
|
814
|
+
}
|
|
815
|
+
let exitCode = 0;
|
|
816
|
+
if (artifactTotal > 0) {
|
|
817
|
+
const runner = createScriptRunner(frameworkRoot);
|
|
818
|
+
const args = [
|
|
819
|
+
'--source', bundle.artifactPath,
|
|
820
|
+
'--deploy-commands', '--deploy-skills', '--deploy-rules',
|
|
821
|
+
'--provider', provider,
|
|
822
|
+
'--target', target,
|
|
823
|
+
// Project-local skills MUST land in the per-project skills tier
|
|
824
|
+
// (#1228 follow-up). Default deploy mode after #1217 is no-copy +
|
|
825
|
+
// index-driven discovery, but that model assumes upstream skills at
|
|
826
|
+
// $AIWG_ROOT — project-local bundles live under the project's .aiwg/
|
|
827
|
+
// tree and aren't reachable via `aiwg discover` of the framework
|
|
828
|
+
// graph. Without --copy-all, the bundle's rules deploy but its skills
|
|
829
|
+
// never reach <provider>/.aiwg/skills/, leaving them invisible to
|
|
830
|
+
// both the platform and the index.
|
|
831
|
+
'--copy-all',
|
|
832
|
+
...modelArgs,
|
|
833
|
+
];
|
|
834
|
+
if (dryRun)
|
|
835
|
+
args.push('--dry-run');
|
|
836
|
+
if (verbose)
|
|
837
|
+
args.push('--verbose');
|
|
838
|
+
if (quiet && !verbose)
|
|
839
|
+
args.push('--quiet');
|
|
840
|
+
// Project-local bundles are addon-shaped — never trigger the legacy commands
|
|
841
|
+
// migration prompt (which is only relevant for full-framework deploys).
|
|
842
|
+
args.push('--skip-commands-migration');
|
|
843
|
+
const captureOpts = quiet && !verbose ? { capture: true } : {};
|
|
844
|
+
// Inject AIWG_ROOT so the deploy subprocess can resolve the upstream AIWG
|
|
845
|
+
// install root. The bundle's `--source` is its project-local path, so
|
|
846
|
+
// `computeAllKernelNames`/`computeAllArtifactBasenames` (which walk up from
|
|
847
|
+
// srcRoot looking for agentic/code/{frameworks,addons}) would otherwise fail
|
|
848
|
+
// and prune the provider's kernel skill directory with an empty desired set
|
|
849
|
+
// (#123). `frameworkRoot` is the AIWG install root that owns these trees.
|
|
850
|
+
const result = await runner.run('tools/agents/deploy-agents.mjs', args, {
|
|
851
|
+
...captureOpts,
|
|
852
|
+
env: { AIWG_ROOT: frameworkRoot },
|
|
853
|
+
});
|
|
854
|
+
exitCode = result.exitCode;
|
|
855
|
+
}
|
|
856
|
+
if (exitCode === 0 && cliCommandCount > 0) {
|
|
857
|
+
try {
|
|
858
|
+
await registerSourceCliCommands({
|
|
859
|
+
source: bundle.artifactPath,
|
|
860
|
+
target,
|
|
861
|
+
provider,
|
|
862
|
+
dryRun,
|
|
863
|
+
fallbackDescription: `${bundle.id} project-local commands`,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
catch (error) {
|
|
867
|
+
ui.warn(`Failed to register CLI commands for project-local '${bundle.id}': ${error.message}`);
|
|
868
|
+
exitCode = 1;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
815
871
|
// Approximate counts from the bundle's source dirs (deploy-agents.mjs is
|
|
816
872
|
// idempotent and copies file-for-file from these dirs)
|
|
817
|
-
const counts = await countBundleSourceArtifacts(bundle.bundlePath);
|
|
818
873
|
void ctx;
|
|
819
|
-
return { exitCode
|
|
874
|
+
return { exitCode, counts };
|
|
820
875
|
}
|
|
821
876
|
/**
|
|
822
877
|
* Discover and deploy artifact-bearing project-local bundles from
|
|
@@ -903,6 +958,10 @@ async function deployProjectLocalBundles(opts) {
|
|
|
903
958
|
if (verbose || dryRun) {
|
|
904
959
|
const action = dryRun ? '[dry-run] Would deploy' : 'Deploying';
|
|
905
960
|
console.log(`${action} project-local ${bundle.type} '${bundle.id}' from ${bundle.localPath} → ${provider}`);
|
|
961
|
+
if (bundle.artifactPath !== bundle.bundlePath) {
|
|
962
|
+
const payloadDisplay = path.relative(projectDir, bundle.artifactPath) || '.';
|
|
963
|
+
ui.dim(` Resolved plugin payload: ${payloadDisplay}`);
|
|
964
|
+
}
|
|
906
965
|
}
|
|
907
966
|
const result = await deployOneProjectLocalBundle({
|
|
908
967
|
bundle, ctx, frameworkRoot, provider, target, dryRun, verbose, quiet, modelArgs,
|
|
@@ -941,7 +1000,7 @@ async function deployProjectLocalBundles(opts) {
|
|
|
941
1000
|
const mHash = await hashManifest(manifestAbsPath);
|
|
942
1001
|
// #1037 — record per-artifact source hashes so `aiwg remove` can
|
|
943
1002
|
// detect pristine vs mutated vs replaced deployed files.
|
|
944
|
-
const artifactHashes = await hashBundleArtifacts(bundle.
|
|
1003
|
+
const artifactHashes = await hashBundleArtifacts(bundle.artifactPath);
|
|
945
1004
|
const updated = updateInstalled(config, bundle.id, provider, result.counts, {
|
|
946
1005
|
version: bundle.manifest.version,
|
|
947
1006
|
source: 'project-local',
|
|
@@ -1449,7 +1508,25 @@ async function deploySourceDirectory(opts) {
|
|
|
1449
1508
|
if (opts.quiet)
|
|
1450
1509
|
args.unshift('--quiet');
|
|
1451
1510
|
const runner = createScriptRunner(opts.frameworkRoot);
|
|
1452
|
-
|
|
1511
|
+
const result = await runner.run('tools/agents/deploy-agents.mjs', args, opts.quiet ? { capture: true } : {});
|
|
1512
|
+
if (result.exitCode === 0) {
|
|
1513
|
+
try {
|
|
1514
|
+
await registerSourceCliCommands({
|
|
1515
|
+
source: opts.source,
|
|
1516
|
+
target: opts.target,
|
|
1517
|
+
provider: opts.provider,
|
|
1518
|
+
dryRun: opts.dryRun,
|
|
1519
|
+
fallbackDescription: `${path.basename(opts.source)} addon commands`,
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
catch (error) {
|
|
1523
|
+
return {
|
|
1524
|
+
exitCode: 1,
|
|
1525
|
+
message: `Failed to register addon CLI commands: ${error.message}`,
|
|
1526
|
+
};
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return result;
|
|
1453
1530
|
}
|
|
1454
1531
|
/**
|
|
1455
1532
|
* Use command handler
|
|
@@ -1928,25 +2005,19 @@ export class UseHandler {
|
|
|
1928
2005
|
}
|
|
1929
2006
|
// Register CLI commands if addon declares them
|
|
1930
2007
|
try {
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
ui.success(`CLI namespace '${cmds.namespace}' registered (${Object.keys(cmds.subcommands).length} subcommands)`);
|
|
1939
|
-
// Register Claude Code hooks for subcommands with hook_event
|
|
1940
|
-
if (provider === 'claude') {
|
|
1941
|
-
const registeredHooks = await registerHooks(target, cmds.namespace, cmds.subcommands);
|
|
1942
|
-
for (const hook of registeredHooks) {
|
|
1943
|
-
ui.success(`Hook registered: ${hook}`);
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
2008
|
+
await registerSourceCliCommands({
|
|
2009
|
+
source: addonSource,
|
|
2010
|
+
target,
|
|
2011
|
+
provider,
|
|
2012
|
+
dryRun: false,
|
|
2013
|
+
fallbackDescription: `${framework} addon commands`,
|
|
2014
|
+
});
|
|
1947
2015
|
}
|
|
1948
2016
|
catch (error) {
|
|
1949
|
-
|
|
2017
|
+
return {
|
|
2018
|
+
exitCode: 1,
|
|
2019
|
+
message: `Failed to register CLI commands: ${error instanceof Error ? error.message : String(error)}`,
|
|
2020
|
+
};
|
|
1950
2021
|
}
|
|
1951
2022
|
// Profile picker for addons with memory topology and multiple templates
|
|
1952
2023
|
try {
|
|
@@ -2235,6 +2306,18 @@ export class UseHandler {
|
|
|
2235
2306
|
if (result.exitCode !== 0) {
|
|
2236
2307
|
return result;
|
|
2237
2308
|
}
|
|
2309
|
+
try {
|
|
2310
|
+
await registerSourceCliCommands({
|
|
2311
|
+
source,
|
|
2312
|
+
target,
|
|
2313
|
+
provider,
|
|
2314
|
+
dryRun,
|
|
2315
|
+
fallbackDescription: `${addon} addon commands`,
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
catch (error) {
|
|
2319
|
+
ui.warn(`Failed to register CLI commands for '${addon}': ${error.message}`);
|
|
2320
|
+
}
|
|
2238
2321
|
}
|
|
2239
2322
|
// Deploy all extensions from agentic/code/extensions/* (#1222).
|
|
2240
2323
|
// Extensions are addon-shaped bundles (manifest type: "addon") that live
|
|
@@ -2255,6 +2338,18 @@ export class UseHandler {
|
|
|
2255
2338
|
if (result.exitCode !== 0) {
|
|
2256
2339
|
return result;
|
|
2257
2340
|
}
|
|
2341
|
+
try {
|
|
2342
|
+
await registerSourceCliCommands({
|
|
2343
|
+
source,
|
|
2344
|
+
target,
|
|
2345
|
+
provider,
|
|
2346
|
+
dryRun,
|
|
2347
|
+
fallbackDescription: `${ext} extension commands`,
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
catch (error) {
|
|
2351
|
+
ui.warn(`Failed to register CLI commands for '${ext}': ${error.message}`);
|
|
2352
|
+
}
|
|
2258
2353
|
}
|
|
2259
2354
|
}
|
|
2260
2355
|
// Deploy project-local bundles (#1035). Auto-runs after upstream addons unless
|