@aiwg/cli 2026.8.11 → 2026.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aiwg.mjs +2 -0
- package/dist/src/api/index.d.ts +6 -0
- package/dist/src/api/index.js +6 -0
- package/dist/src/cli/handlers/artifact-verify.js +171 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/setup-manifest.js +52 -3
- package/dist/src/cli/handlers/setup.js +15 -2
- package/dist/src/cli/handlers/use.js +71 -6
- package/dist/src/cli/scope-resolver.js +6 -1
- package/dist/src/cli/services/deployment-verification.js +65 -7
- package/dist/src/config/aiwg-config.js +4 -3
- package/dist/src/config/cli.js +3 -1
- package/dist/src/config/gitignore.js +67 -21
- package/dist/src/config/workspace.js +8 -1
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-quickref.js +9 -0
- package/dist/src/marketplace/artifact-attestation.js +195 -0
- package/dist/src/marketplace/exchange.js +437 -79
- package/dist/src/marketplace/provenance-types.js +1 -0
- package/dist/src/marketplace/provenance.js +7 -1
- package/dist/src/providers/hermes-home.js +20 -0
- package/dist/src/providers/provider-definitions.js +5 -4
- package/dist/src/providers/transformation-receipt-integration.js +448 -0
- package/dist/src/providers/transformation-receipt.js +215 -0
- package/dist/src/resources/web-release.d.ts +11 -0
- package/dist/src/resources/web-release.js +61 -6
- package/dist/src/security/artifact-attestation.js +117 -0
- package/dist/src/security/artifact-trust.js +557 -0
- package/dist/src/security/artifact-verifier.js +478 -0
- package/dist/src/skills/deployer.js +5 -1
- package/dist/src/tracker/capability-protocol.js +7 -2
- package/package.json +5 -1
- package/schemas/security/aiwg-artifact-attestation.v1.schema.json +106 -0
- package/schemas/security/aiwg-artifact-provenance.v1.schema.json +204 -0
- package/schemas/security/aiwg-artifact-trust-root.v1.schema.json +59 -0
- package/schemas/security/aiwg-artifact-trust-state.v1.schema.json +32 -0
- package/schemas/security/aiwg-artifact-verification-result.v1.schema.json +46 -0
- package/schemas/security/threat-assessment-input.v1.schema.json +57 -0
- package/schemas/security/threat-assessment-report.v1.schema.json +104 -0
- package/tools/agents/deploy-agents.mjs +8 -2
- package/tools/agents/providers/base.mjs +29 -2
- package/tools/agents/providers/hermes.mjs +163 -19
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* server is an optional enrichment hook that Hermes can call when configured.
|
|
6
6
|
*
|
|
7
7
|
* What this provider DOES deploy:
|
|
8
|
-
* - Skills:
|
|
9
|
-
* - AGENTS.md: project root (
|
|
8
|
+
* - Skills: $HERMES_HOME/skills/ (user-global, for agentic skills callable by Hermes)
|
|
9
|
+
* - AGENTS.md: project root (full AIWG routing guide referenced by .hermes.md)
|
|
10
10
|
*
|
|
11
11
|
* What this provider SKIPS:
|
|
12
12
|
* - Commands: Hermes has no AIWG slash-command file surface
|
|
@@ -22,6 +22,7 @@ let fs;
|
|
|
22
22
|
try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
|
|
23
23
|
import path from 'path';
|
|
24
24
|
import os from 'os';
|
|
25
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
25
26
|
import {
|
|
26
27
|
ensureDir,
|
|
27
28
|
listMdFiles,
|
|
@@ -37,8 +38,61 @@ import {
|
|
|
37
38
|
collectFrameworkArtifacts,
|
|
38
39
|
listOnDemandRuleFiles,
|
|
39
40
|
renderOnDemandRuleSection,
|
|
41
|
+
stripPlatformsFromContent,
|
|
40
42
|
} from './base.mjs';
|
|
41
43
|
|
|
44
|
+
// ============================================================================
|
|
45
|
+
// Hermes home resolution (HERMES_HOME) — #2119
|
|
46
|
+
// ============================================================================
|
|
47
|
+
//
|
|
48
|
+
// Mirrors `hermes_constants.get_hermes_home()` in the Hermes Agent runtime.
|
|
49
|
+
// Resolution order (upstream, hermes_constants.py:114-):
|
|
50
|
+
// 1. A context-local override installed in-process via
|
|
51
|
+
// set_hermes_home_override() — AIWG runs in a separate node process and
|
|
52
|
+
// cannot observe that token, so step 1 is intentionally NOT part of the
|
|
53
|
+
// cross-process contract.
|
|
54
|
+
// 2. The process `HERMES_HOME` env var.
|
|
55
|
+
// 3. The platform-native default:
|
|
56
|
+
// win32 → %LOCALAPPDATA%/hermes (falls back to %USERPROFILE%/AppData/
|
|
57
|
+
// Local/hermes when LOCALAPPDATA is unset)
|
|
58
|
+
// other → $HOME/.hermes
|
|
59
|
+
//
|
|
60
|
+
// AIWG reads the env var when `getHermesHome()` is invoked; the module-level
|
|
61
|
+
// constants below lock in the value captured at first use so every consumer
|
|
62
|
+
// (paths, kernels, orchestrate, legacy migration) sees the same resolved root
|
|
63
|
+
// for the life of the process.
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the Hermes home directory.
|
|
67
|
+
*
|
|
68
|
+
* Honors HERMES_HOME the way the running Hermes runtime does, so that
|
|
69
|
+
* `aiwg use --provider hermes` writes skills under the same root the live
|
|
70
|
+
* session scans. See #2119 — before this helper, the provider hardcoded
|
|
71
|
+
* `os.homedir()/.hermes` and any operator running Hermes under a non-default
|
|
72
|
+
* HERMES_HOME (multi-profile, hermes-role wrappers, dev containers) got a
|
|
73
|
+
* silently divergent deployment.
|
|
74
|
+
*/
|
|
75
|
+
export function getHermesHome() {
|
|
76
|
+
const env = (process.env.HERMES_HOME || '').trim();
|
|
77
|
+
if (env) {
|
|
78
|
+
// Match upstream's Path(env) contract exactly. Hermes does not expand a
|
|
79
|
+
// leading `~` or resolve relative values here; both remain relative to the
|
|
80
|
+
// process working directory when the path is consumed.
|
|
81
|
+
return env;
|
|
82
|
+
}
|
|
83
|
+
if (process.platform === 'win32') {
|
|
84
|
+
const localAppData = (process.env.LOCALAPPDATA || '').trim();
|
|
85
|
+
return localAppData
|
|
86
|
+
? path.join(localAppData, 'hermes')
|
|
87
|
+
: path.join(os.homedir(), 'AppData', 'Local', 'hermes');
|
|
88
|
+
}
|
|
89
|
+
return path.join(os.homedir(), '.hermes');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The value captured below is the target any running Hermes session with the
|
|
93
|
+
// same environ would use as its scan root.
|
|
94
|
+
const HERMES_HOME = getHermesHome();
|
|
95
|
+
|
|
42
96
|
// ============================================================================
|
|
43
97
|
// Provider Configuration
|
|
44
98
|
// ============================================================================
|
|
@@ -49,10 +103,15 @@ export const aliases = [];
|
|
|
49
103
|
export const paths = {
|
|
50
104
|
agents: 'AGENTS.md', // Aggregated routing guide at project root
|
|
51
105
|
commands: '', // Not applicable — no AIWG slash-command file surface
|
|
52
|
-
// Standard skills under
|
|
53
|
-
// recursively discovered (verified `agent/skill_utils.py:478-489`,
|
|
54
|
-
// subdirs except .git/.github/.hub/.archive).
|
|
55
|
-
|
|
106
|
+
// Standard skills under <HERMES_HOME>/skills/.aiwg/ — child of Hermes's
|
|
107
|
+
// scanned root, recursively discovered (verified `agent/skill_utils.py:478-489`,
|
|
108
|
+
// os.walk follows subdirs except .git/.github/.hub/.archive).
|
|
109
|
+
//
|
|
110
|
+
// HERMES_HOME honors the process env var and falls back to $HOME/.hermes
|
|
111
|
+
// (win32: %LOCALAPPDATA%/hermes), matching hermes_constants.get_hermes_home().
|
|
112
|
+
// #2119: previously hardcoded os.homedir() — wrong for any operator running
|
|
113
|
+
// Hermes under a non-default HERMES_HOME (multi-profile, hermes-role, etc.).
|
|
114
|
+
skills: path.resolve(HERMES_HOME, 'skills', '.aiwg'),
|
|
56
115
|
rules: '', // Inlined into AGENTS.md + reachable via `aiwg show rule`
|
|
57
116
|
};
|
|
58
117
|
|
|
@@ -60,12 +119,17 @@ export const paths = {
|
|
|
60
119
|
// Standard skills land in the .aiwg/ subdirectory under the same root —
|
|
61
120
|
// Hermes recursively walks the skill root (verified against upstream v0.13.0,
|
|
62
121
|
// `agent/skill_utils.py:478-489`).
|
|
63
|
-
export const kernelSkillsPath = path.
|
|
122
|
+
export const kernelSkillsPath = path.resolve(HERMES_HOME, 'skills');
|
|
123
|
+
|
|
124
|
+
// Resolved home directory this provider's paths were computed against.
|
|
125
|
+
// Consumers (deploy verification, doctor, status) should use this rather than
|
|
126
|
+
// re-reading os.homedir() to stay consistent with the deploy target.
|
|
127
|
+
export const hermesHome = HERMES_HOME;
|
|
64
128
|
|
|
65
129
|
export const support = {
|
|
66
130
|
agents: 'aggregated', // Agents aggregated into lean AGENTS.md
|
|
67
131
|
commands: 'none', // Hermes has no AIWG slash-command file surface
|
|
68
|
-
skills: 'native', //
|
|
132
|
+
skills: 'native', // $HERMES_HOME/skills/ is the native skill location
|
|
69
133
|
rules: 'agents-md+cli', // compressed in AGENTS.md; full bodies via CLI/MCP
|
|
70
134
|
};
|
|
71
135
|
|
|
@@ -77,6 +141,43 @@ export const capabilities = {
|
|
|
77
141
|
homeDirectoryDeploy: true, // Skills deploy to home dir
|
|
78
142
|
};
|
|
79
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Project portable Agent Skills metadata into Hermes's native frontmatter.
|
|
146
|
+
*
|
|
147
|
+
* The portable Agent Skills contract restricts `metadata` values to strings,
|
|
148
|
+
* while Hermes expects tags at `metadata.hermes.tags`. AIWG stores the tag
|
|
149
|
+
* list as a comma-separated `metadata.hermes-tags` string in source and
|
|
150
|
+
* performs the provider-specific projection only in the deployed copy.
|
|
151
|
+
*/
|
|
152
|
+
export function transformHermesSkillContent(content) {
|
|
153
|
+
const stripped = stripPlatformsFromContent(content);
|
|
154
|
+
const match = stripped.match(/^---\r?\n([\s\S]*?)\r?\n---(\r?\n|$)/);
|
|
155
|
+
if (!match) return stripped;
|
|
156
|
+
|
|
157
|
+
let frontmatter;
|
|
158
|
+
try {
|
|
159
|
+
frontmatter = parseYaml(match[1]);
|
|
160
|
+
} catch {
|
|
161
|
+
return stripped;
|
|
162
|
+
}
|
|
163
|
+
if (!frontmatter || typeof frontmatter !== 'object' || Array.isArray(frontmatter)) {
|
|
164
|
+
return stripped;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const metadata = frontmatter.metadata;
|
|
168
|
+
const encodedTags = metadata && typeof metadata === 'object' && !Array.isArray(metadata)
|
|
169
|
+
? metadata['hermes-tags']
|
|
170
|
+
: undefined;
|
|
171
|
+
if (typeof encodedTags !== 'string') return stripped;
|
|
172
|
+
|
|
173
|
+
const tags = encodedTags.split(',').map((tag) => tag.trim()).filter(Boolean);
|
|
174
|
+
delete metadata['hermes-tags'];
|
|
175
|
+
metadata.hermes = { tags };
|
|
176
|
+
|
|
177
|
+
const body = stripped.slice(match[0].length);
|
|
178
|
+
return `---\n${stringifyYaml(frontmatter).trimEnd()}\n---\n${body}`;
|
|
179
|
+
}
|
|
180
|
+
|
|
80
181
|
// ============================================================================
|
|
81
182
|
// Model Mapping (not applicable — Hermes uses local Ollama models)
|
|
82
183
|
// ============================================================================
|
|
@@ -203,7 +304,8 @@ export function generateAgentsMd(agentCount, skillCount, targetDir, opts) {
|
|
|
203
304
|
const header = `# AIWG Integration
|
|
204
305
|
|
|
205
306
|
AIWG connected through file-based deployment. Native Hermes skills are available
|
|
206
|
-
at
|
|
307
|
+
at \`$HERMES_HOME/skills/\` (kernel) and \`$HERMES_HOME/skills/.aiwg/\` (standard).
|
|
308
|
+
When unset, \`HERMES_HOME\` defaults to the platform-native Hermes home.
|
|
207
309
|
Use \`aiwg discover\` and \`aiwg show <type> <name>\` for the on-demand catalog.
|
|
208
310
|
The MCP sidecar (\`aiwg mcp serve\`) is optional.
|
|
209
311
|
|
|
@@ -285,10 +387,12 @@ AIWG project context lives in \`AGENTS.md\` (this file is a thin Hermes pointer)
|
|
|
285
387
|
|
|
286
388
|
**Routing**: see \`AGENTS.md\` in this directory.
|
|
287
389
|
**MCP**: AIWG is reachable via \`mcp_aiwg_*\` tools.
|
|
288
|
-
**Skills**: kernel skills at
|
|
390
|
+
**Skills**: kernel skills at \`$HERMES_HOME/skills/\`; standard skills at \`$HERMES_HOME/skills/.aiwg/\`.
|
|
391
|
+
When unset, \`HERMES_HOME\` defaults to the platform-native Hermes home.
|
|
289
392
|
|
|
290
|
-
Hermes loads \`.hermes.md\`
|
|
291
|
-
file minimal
|
|
393
|
+
Hermes loads only \`.hermes.md\` when it is present (first-match-wins). Keep
|
|
394
|
+
this file minimal; its routing instruction tells the agent to read \`AGENTS.md\`
|
|
395
|
+
when the full AIWG project context is needed.
|
|
292
396
|
`;
|
|
293
397
|
const destPath = path.join(targetDir, '.hermes.md');
|
|
294
398
|
if (dryRun) {
|
|
@@ -309,8 +413,8 @@ file minimal — Hermes will load AGENTS.md content next via the routing chain.
|
|
|
309
413
|
*
|
|
310
414
|
* Skills are user-global in Hermes, deployed once, available in all
|
|
311
415
|
* projects. Kernel routing per the cross-provider pattern:
|
|
312
|
-
* - kernel skills →
|
|
313
|
-
* - standard →
|
|
416
|
+
* - kernel skills → $HERMES_HOME/skills/ (platform-native, always-loaded)
|
|
417
|
+
* - standard → $HERMES_HOME/skills/.aiwg/ (recursively walked by Hermes)
|
|
314
418
|
*/
|
|
315
419
|
export function deploySkills(skillDirs, opts) {
|
|
316
420
|
const standardDestDir = paths.skills;
|
|
@@ -375,7 +479,18 @@ export async function deploy(opts) {
|
|
|
375
479
|
allSkillDirs.push(...(artifacts.skills || []));
|
|
376
480
|
|
|
377
481
|
if (allSkillDirs.length > 0) {
|
|
378
|
-
|
|
482
|
+
// Hermes's skill loader reads `platforms:` as an OS gate
|
|
483
|
+
// (linux / macos / windows). AIWG's shared deploy path injects
|
|
484
|
+
// `[hermes]` into that field, which then filters every skill out
|
|
485
|
+
// on Linux. Strip the field post-injection — hermes documents
|
|
486
|
+
// "absent field = all platforms" as its default. This leaves the
|
|
487
|
+
// other providers' `transformSkillMd` pipeline untouched.
|
|
488
|
+
const skillOpts = {
|
|
489
|
+
...opts,
|
|
490
|
+
provider: 'hermes', // ensure deploySkillDir's injectPlatform branch runs
|
|
491
|
+
transformSkillMd: transformHermesSkillContent,
|
|
492
|
+
};
|
|
493
|
+
deploySkills(allSkillDirs, skillOpts);
|
|
379
494
|
} else if (!opts.quiet) {
|
|
380
495
|
console.log(' No skills found to deploy');
|
|
381
496
|
}
|
|
@@ -424,7 +539,7 @@ export async function deploy(opts) {
|
|
|
424
539
|
|
|
425
540
|
// ── aiwg-orchestrate convenience skill (#1242) ──────────────────────────────
|
|
426
541
|
// First-deploy-only copy: lays down the delegate_task wrapper at
|
|
427
|
-
//
|
|
542
|
+
// $HERMES_HOME/skills/aiwg-orchestrate/SKILL.md if it isn't already present.
|
|
428
543
|
// The skill provides ~95% per-workflow context reduction by routing AIWG
|
|
429
544
|
// calls through Hermes's `delegate_task` instead of inline MCP. Idempotent
|
|
430
545
|
// on re-run — operator edits are preserved across `aiwg use` invocations.
|
|
@@ -435,10 +550,35 @@ export async function deploy(opts) {
|
|
|
435
550
|
// ── Post-deployment hint ───────────────────────────────────────────────────
|
|
436
551
|
if (!opts.quiet) {
|
|
437
552
|
console.log('');
|
|
553
|
+
console.log(`Skills root: ${kernelSkillsPath}`);
|
|
438
554
|
console.log('Rules are in AGENTS.md as compressed directives; full bodies via `aiwg show rule <name>`.');
|
|
439
|
-
console.log('Optional: configure
|
|
555
|
+
console.log('Optional: configure config.yaml to connect AIWG MCP server.');
|
|
440
556
|
console.log('See: docs/integrations/hermes-quickstart.md (optional MCP setup)');
|
|
441
557
|
}
|
|
558
|
+
|
|
559
|
+
// ── Consumer visibility check (#2119) ──────────────────────────────────────
|
|
560
|
+
// The running Hermes runtime reads skills from get_skills_dir(), which is
|
|
561
|
+
// HERMES_HOME/skills (hermes_constants.get_hermes_home: context-local
|
|
562
|
+
// override → HERMES_HOME env → $HOME/.hermes). AIWG can observe only ITS
|
|
563
|
+
// own process environment, so this check reports which root AIWG resolved
|
|
564
|
+
// and warns when that root may be invisible to a Hermes session the
|
|
565
|
+
// operator launched elsewhere (custom HERMES_HOME, hermes-role wrapper).
|
|
566
|
+
//
|
|
567
|
+
// Before #2119 this was a silent failure: AIWG wrote to $HOME/.hermes/skills
|
|
568
|
+
// unconditionally and `aiwg status --probe` reported healthy even when the
|
|
569
|
+
// live session scanned a different HERMES_HOME.
|
|
570
|
+
if (!dryRun && !opts.quiet) {
|
|
571
|
+
const envHome = (process.env.HERMES_HOME || '').trim();
|
|
572
|
+
const hermesActive = Boolean(
|
|
573
|
+
process.env.HERMES_SESSION_ID ||
|
|
574
|
+
(process.env.AI_AGENT || '').includes('hermes')
|
|
575
|
+
);
|
|
576
|
+
if (hermesActive && !envHome) {
|
|
577
|
+
console.warn(`Warning: HERMES_HOME is not set in this AIWG process — deployed skills landed under \`${kernelSkillsPath}\` (default $HOME/.hermes).`);
|
|
578
|
+
console.warn(' If your running Hermes session uses a non-default HERMES_HOME, it CANNOT see these skills.');
|
|
579
|
+
console.warn(' Re-run with the matching value: HERMES_HOME=<that value> aiwg use --provider hermes');
|
|
580
|
+
}
|
|
581
|
+
}
|
|
442
582
|
}
|
|
443
583
|
|
|
444
584
|
// ============================================================================
|
|
@@ -584,7 +724,7 @@ export function migrateLegacySkillPath(opts) {
|
|
|
584
724
|
// ============================================================================
|
|
585
725
|
|
|
586
726
|
/**
|
|
587
|
-
* Copy the aiwg-orchestrate skill template to
|
|
727
|
+
* Copy the aiwg-orchestrate skill template to $HERMES_HOME/skills/ on first
|
|
588
728
|
* deploy. Skip if a SKILL.md already exists — preserves operator edits and
|
|
589
729
|
* any prior version they're running. Errors during the copy are non-fatal:
|
|
590
730
|
* the rest of the deploy must succeed even if the home dir is read-only or
|
|
@@ -631,7 +771,11 @@ function deployAiwgOrchestrateSkill(srcRoot, opts) {
|
|
|
631
771
|
try {
|
|
632
772
|
ensureDir(destDir);
|
|
633
773
|
const content = fs.readFileSync(templatePath, 'utf8');
|
|
634
|
-
|
|
774
|
+
// Defensive: the template is hermes-specific and should not carry a
|
|
775
|
+
// `platforms:` field (hermes reads that as an OS gate). Strip it if a
|
|
776
|
+
// future template regression reintroduces one so this orphan path
|
|
777
|
+
// stays consistent with the main deploy pipeline.
|
|
778
|
+
fs.writeFileSync(destPath, transformHermesSkillContent(content), 'utf8');
|
|
635
779
|
if (!opts.quiet) {
|
|
636
780
|
console.log(` Installed aiwg-orchestrate to ${destPath} (delegate_task wrapper, 95% context reduction)`);
|
|
637
781
|
}
|