@aiwg/cli 2026.7.20 → 2026.7.23
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 +18 -7
- package/dist/src/api/index.d.ts +2 -0
- package/dist/src/api/index.js +2 -0
- package/dist/src/artifacts/browser-export.js +7 -0
- package/dist/src/artifacts/citation-parser.js +96 -35
- package/dist/src/artifacts/index-builder.js +54 -17
- 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/index.js +3 -1
- package/dist/src/cli/handlers/sessions.js +1265 -0
- package/dist/src/cli/handlers/skill-lint.js +49 -45
- package/dist/src/cli/handlers/use.js +143 -60
- package/dist/src/cli/handlers/utilities.js +22 -8
- package/dist/src/cli/skill-usage.js +146 -24
- package/dist/src/config/aiwg-config.js +12 -0
- package/dist/src/config/cli.js +16 -3
- package/dist/src/extensions/commands/definitions.js +29 -0
- package/dist/src/extensions/manifest.js +29 -0
- package/dist/src/security/threat-assessment-config.js +296 -0
- package/dist/src/sessions/adapters/claude.js +385 -0
- package/dist/src/sessions/adapters/codex.js +548 -0
- package/dist/src/sessions/adapters/copilot.js +226 -0
- package/dist/src/sessions/adapters/cursor.js +528 -0
- package/dist/src/sessions/adapters/factory.js +386 -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/batch-contracts.js +121 -0
- package/dist/src/sessions/batch-import.js +265 -0
- package/dist/src/sessions/candidates.js +210 -0
- package/dist/src/sessions/contracts.js +337 -0
- package/dist/src/sessions/discovery.js +51 -0
- package/dist/src/sessions/fixtures.js +12 -0
- package/dist/src/sessions/import-lease.js +152 -0
- package/dist/src/sessions/importer.js +464 -0
- package/dist/src/sessions/index.js +31 -0
- package/dist/src/sessions/knowledge-shard.js +61 -0
- package/dist/src/sessions/optional-backends.js +238 -0
- package/dist/src/sessions/origin.js +117 -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 +1892 -0
- package/dist/src/sessions/timeline.js +148 -0
- package/dist/src/sessions/workspace-discovery.js +319 -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/package.json +2 -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
|
}
|
|
@@ -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)
|
|
@@ -777,54 +796,82 @@ async function deployOneProjectLocalBundle(opts) {
|
|
|
777
796
|
const { bundle, ctx, frameworkRoot, provider, target, dryRun, verbose, quiet, modelArgs } = opts;
|
|
778
797
|
const counts = await countBundleSourceArtifacts(bundle.artifactPath);
|
|
779
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
|
+
}
|
|
780
808
|
if (verbose || dryRun) {
|
|
781
|
-
ui.dim(` Artifacts: agents=${counts.agents} commands=${counts.commands} skills=${counts.skills} rules=${counts.rules}`);
|
|
809
|
+
ui.dim(` Artifacts: agents=${counts.agents} commands=${counts.commands} skills=${counts.skills} rules=${counts.rules} cli=${cliCommandCount}`);
|
|
782
810
|
}
|
|
783
|
-
if (artifactTotal === 0) {
|
|
784
|
-
ui.warn(`Project-local ${bundle.type} '${bundle.id}' has no deployable agents, commands, skills, or
|
|
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}`);
|
|
785
813
|
return { exitCode: 1, counts };
|
|
786
814
|
}
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
+
}
|
|
824
871
|
// Approximate counts from the bundle's source dirs (deploy-agents.mjs is
|
|
825
872
|
// idempotent and copies file-for-file from these dirs)
|
|
826
873
|
void ctx;
|
|
827
|
-
return { exitCode
|
|
874
|
+
return { exitCode, counts };
|
|
828
875
|
}
|
|
829
876
|
/**
|
|
830
877
|
* Discover and deploy artifact-bearing project-local bundles from
|
|
@@ -1461,7 +1508,25 @@ async function deploySourceDirectory(opts) {
|
|
|
1461
1508
|
if (opts.quiet)
|
|
1462
1509
|
args.unshift('--quiet');
|
|
1463
1510
|
const runner = createScriptRunner(opts.frameworkRoot);
|
|
1464
|
-
|
|
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;
|
|
1465
1530
|
}
|
|
1466
1531
|
/**
|
|
1467
1532
|
* Use command handler
|
|
@@ -1940,25 +2005,19 @@ export class UseHandler {
|
|
|
1940
2005
|
}
|
|
1941
2006
|
// Register CLI commands if addon declares them
|
|
1942
2007
|
try {
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
ui.success(`CLI namespace '${cmds.namespace}' registered (${Object.keys(cmds.subcommands).length} subcommands)`);
|
|
1951
|
-
// Register Claude Code hooks for subcommands with hook_event
|
|
1952
|
-
if (provider === 'claude') {
|
|
1953
|
-
const registeredHooks = await registerHooks(target, cmds.namespace, cmds.subcommands);
|
|
1954
|
-
for (const hook of registeredHooks) {
|
|
1955
|
-
ui.success(`Hook registered: ${hook}`);
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
2008
|
+
await registerSourceCliCommands({
|
|
2009
|
+
source: addonSource,
|
|
2010
|
+
target,
|
|
2011
|
+
provider,
|
|
2012
|
+
dryRun: false,
|
|
2013
|
+
fallbackDescription: `${framework} addon commands`,
|
|
2014
|
+
});
|
|
1959
2015
|
}
|
|
1960
2016
|
catch (error) {
|
|
1961
|
-
|
|
2017
|
+
return {
|
|
2018
|
+
exitCode: 1,
|
|
2019
|
+
message: `Failed to register CLI commands: ${error instanceof Error ? error.message : String(error)}`,
|
|
2020
|
+
};
|
|
1962
2021
|
}
|
|
1963
2022
|
// Profile picker for addons with memory topology and multiple templates
|
|
1964
2023
|
try {
|
|
@@ -2247,6 +2306,18 @@ export class UseHandler {
|
|
|
2247
2306
|
if (result.exitCode !== 0) {
|
|
2248
2307
|
return result;
|
|
2249
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
|
+
}
|
|
2250
2321
|
}
|
|
2251
2322
|
// Deploy all extensions from agentic/code/extensions/* (#1222).
|
|
2252
2323
|
// Extensions are addon-shaped bundles (manifest type: "addon") that live
|
|
@@ -2267,6 +2338,18 @@ export class UseHandler {
|
|
|
2267
2338
|
if (result.exitCode !== 0) {
|
|
2268
2339
|
return result;
|
|
2269
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
|
+
}
|
|
2270
2353
|
}
|
|
2271
2354
|
}
|
|
2272
2355
|
// Deploy project-local bundles (#1035). Auto-runs after upstream addons unless
|
|
@@ -130,8 +130,8 @@ function countSentences(s) {
|
|
|
130
130
|
return matches.length + (endsWithTerminator ? 0 : 1);
|
|
131
131
|
}
|
|
132
132
|
/**
|
|
133
|
-
* Scan source SKILL.md files in `agentic/code/` for
|
|
134
|
-
* - Missing `namespace: aiwg`
|
|
133
|
+
* Scan canonical AIWG source SKILL.md files in `agentic/code/` for policy issues:
|
|
134
|
+
* - Missing the AIWG-only `namespace: aiwg` source convention
|
|
135
135
|
* - Slug (`aiwg-{name}`) that would shadow an AIWG CLI command
|
|
136
136
|
*
|
|
137
137
|
* Returns lines suitable for console output, or empty array if clean.
|
|
@@ -263,12 +263,14 @@ export const validateMetadataHandler = {
|
|
|
263
263
|
const result = await runner.run('tools/cli/validate-metadata.mjs', scriptArgs, {
|
|
264
264
|
cwd: ctx.cwd,
|
|
265
265
|
});
|
|
266
|
-
// Append
|
|
266
|
+
// Append canonical AIWG source policy. `namespace` is an AIWG extension,
|
|
267
|
+
// not an Agent Skills standard requirement; shared conformance is emitted
|
|
268
|
+
// by validate-metadata.mjs before this source-only convention.
|
|
267
269
|
try {
|
|
268
270
|
const issues = await scanSourceNamespaceIssues(frameworkRoot);
|
|
269
271
|
if (issues.length > 0) {
|
|
270
|
-
console.log('\n──
|
|
271
|
-
console.log(` ${issues.length}
|
|
272
|
+
console.log('\n── AIWG source conventions ──');
|
|
273
|
+
console.log(` ${issues.length} canonical source convention issue(s):`);
|
|
272
274
|
// Show first 20 to avoid flooding output
|
|
273
275
|
issues.slice(0, 20).forEach(l => console.log(l));
|
|
274
276
|
if (issues.length > 20) {
|
|
@@ -276,11 +278,11 @@ export const validateMetadataHandler = {
|
|
|
276
278
|
}
|
|
277
279
|
// Non-zero exit only in strict mode
|
|
278
280
|
if (ctx.args.includes('--strict') && result.exitCode === 0) {
|
|
279
|
-
return { exitCode: 1, message: `
|
|
281
|
+
return { exitCode: 1, message: `AIWG source convention validation failed: ${issues.length} issue(s)` };
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
else {
|
|
283
|
-
console.log('\n──
|
|
285
|
+
console.log('\n── AIWG source conventions: all canonical skills include the AIWG namespace extension ✓');
|
|
284
286
|
}
|
|
285
287
|
}
|
|
286
288
|
catch {
|
|
@@ -460,6 +462,16 @@ export const doctorHandler = {
|
|
|
460
462
|
const runner = createScriptRunner(frameworkRoot);
|
|
461
463
|
// Run core doctor diagnostics
|
|
462
464
|
const result = await runner.run('tools/cli/doctor.mjs', ctx.args, { cwd: ctx.cwd });
|
|
465
|
+
let agentSkillsFailure = false;
|
|
466
|
+
try {
|
|
467
|
+
const { buildAgentSkillsDoctorSection } = await import('../../skills/doctor.js');
|
|
468
|
+
const section = buildAgentSkillsDoctorSection(ctx.cwd || process.cwd());
|
|
469
|
+
console.log(section.output);
|
|
470
|
+
agentSkillsFailure = section.hasFailures;
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
console.log(`\n── Agent Skills conformance ──\n ⚠ unable to audit: ${error instanceof Error ? error.message : String(error)}`);
|
|
474
|
+
}
|
|
463
475
|
// Surface feedback escape hatch when doctor finds issues
|
|
464
476
|
if (result.exitCode !== 0) {
|
|
465
477
|
console.log(`
|
|
@@ -567,7 +579,9 @@ export const doctorHandler = {
|
|
|
567
579
|
catch (error) {
|
|
568
580
|
console.log(`\n── Workspace context graph ──\n ⚠ unable to audit: ${error instanceof Error ? error.message : String(error)}`);
|
|
569
581
|
}
|
|
570
|
-
return
|
|
582
|
+
return agentSkillsFailure
|
|
583
|
+
? { exitCode: 1, message: '' }
|
|
584
|
+
: result;
|
|
571
585
|
},
|
|
572
586
|
};
|
|
573
587
|
/**
|