@aiwg/cli 2026.8.0 → 2026.8.2

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 (70) hide show
  1. package/README.md +33 -0
  2. package/agentic/code/providers/capability-matrix.yaml +511 -0
  3. package/agentic/code/providers/model-capabilities.v1.json +120 -0
  4. package/agentic/code/providers/model-catalog.v1.json +96 -0
  5. package/agentic/code/providers/model-policy-evaluations.v1.json +50 -0
  6. package/agentic/code/providers/premium-model-allowlist.v1.json +36 -0
  7. package/bin/aiwg.mjs +14 -10
  8. package/dist/src/api/index.d.ts +1 -0
  9. package/dist/src/api/index.js +1 -0
  10. package/dist/src/artifacts/cli.js +2 -0
  11. package/dist/src/artifacts/types.js +4 -0
  12. package/dist/src/auth/client.js +209 -0
  13. package/dist/src/auth/config.js +38 -0
  14. package/dist/src/auth/credential-store.js +141 -0
  15. package/dist/src/auth/resource-credentials.js +25 -0
  16. package/dist/src/auth/types.js +2 -0
  17. package/dist/src/channel/manager.mjs +5 -5
  18. package/dist/src/cli/handlers/auth.js +125 -0
  19. package/dist/src/cli/handlers/help.js +1 -0
  20. package/dist/src/cli/handlers/index.js +3 -1
  21. package/dist/src/cli/handlers/install.js +42 -4
  22. package/dist/src/cli/handlers/marketplace.js +375 -122
  23. package/dist/src/cli/handlers/resource-versions.js +2 -0
  24. package/dist/src/cli/handlers/sessions.js +23 -5
  25. package/dist/src/cli/handlers/subcommands.js +10 -1
  26. package/dist/src/cli/handlers/use.js +342 -43
  27. package/dist/src/config/gitignore.js +1 -0
  28. package/dist/src/extensions/commands/definitions.js +19 -0
  29. package/dist/src/marketplace/exchange.js +602 -0
  30. package/dist/src/marketplace/provenance-types.js +19 -0
  31. package/dist/src/marketplace/provenance.js +834 -0
  32. package/dist/src/memory/canonical-context.js +342 -0
  33. package/dist/src/memory/context-pack.js +282 -0
  34. package/dist/src/memory/index.js +4 -0
  35. package/dist/src/memory/intake.js +118 -0
  36. package/dist/src/packages/adapters/git.js +79 -29
  37. package/dist/src/packages/package-discovery.js +81 -0
  38. package/dist/src/packages/package-registry.js +2 -0
  39. package/dist/src/packages/registry.js +119 -20
  40. package/dist/src/resources/resolver.js +1 -0
  41. package/dist/src/resources/web-release.d.ts +3 -1
  42. package/dist/src/resources/web-release.js +14 -6
  43. package/dist/src/serve/agentic-sandbox-fleet-client.js +213 -0
  44. package/dist/src/serve/fleet-mission-conductor.js +293 -0
  45. package/dist/src/sessions/index.js +1 -0
  46. package/dist/src/sessions/output-registration.js +338 -0
  47. package/dist/src/sessions/promotion.js +73 -2
  48. package/dist/src/sessions/repository.js +2 -1
  49. package/dist/src/update/notifier.mjs +13 -2
  50. package/package.json +8 -1
  51. package/tools/_resolve-impl.mjs +74 -0
  52. package/tools/agents/deploy-agents.mjs +962 -0
  53. package/tools/agents/providers/base.mjs +2954 -0
  54. package/tools/agents/providers/claude.mjs +711 -0
  55. package/tools/agents/providers/codex.mjs +699 -0
  56. package/tools/agents/providers/copilot.mjs +659 -0
  57. package/tools/agents/providers/cursor.mjs +714 -0
  58. package/tools/agents/providers/factory.mjs +1130 -0
  59. package/tools/agents/providers/hermes.mjs +663 -0
  60. package/tools/agents/providers/hook-capabilities.mjs +85 -0
  61. package/tools/agents/providers/model-role.mjs +56 -0
  62. package/tools/agents/providers/openclaw-translator.mjs +348 -0
  63. package/tools/agents/providers/openclaw.mjs +680 -0
  64. package/tools/agents/providers/opencode.mjs +675 -0
  65. package/tools/agents/providers/openhuman.mjs +292 -0
  66. package/tools/agents/providers/warp.mjs +413 -0
  67. package/tools/agents/providers/windsurf.mjs +748 -0
  68. package/tools/commands/deploy-prompts-codex.mjs +336 -0
  69. package/tools/plugin/package-plugins.mjs +1013 -0
  70. package/tools/skills/deploy-skills-codex.mjs +571 -0
@@ -0,0 +1,663 @@
1
+ /**
2
+ * Hermes Agent Provider
3
+ *
4
+ * Hermes Agent uses file-based deployment for context and skills. AIWG's MCP
5
+ * server is an optional enrichment hook that Hermes can call when configured.
6
+ *
7
+ * What this provider DOES deploy:
8
+ * - Skills: ~/.hermes/skills/ (user-global, for agentic skills callable by Hermes)
9
+ * - AGENTS.md: project root (lean routing guide that Hermes loads on every turn)
10
+ *
11
+ * What this provider SKIPS:
12
+ * - Commands: Hermes has no AIWG slash-command file surface
13
+ * - Rules: compressed directives are in AGENTS.md; full bodies via `aiwg show rule`
14
+ *
15
+ * See: docs/integrations/hermes-quickstart.md
16
+ */
17
+
18
+ import realFs from 'fs';
19
+ import { createRequire } from 'module';
20
+ const _require = createRequire(import.meta.url);
21
+ let fs;
22
+ try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
23
+ import path from 'path';
24
+ import os from 'os';
25
+ import {
26
+ ensureDir,
27
+ listMdFiles,
28
+ listSkillDirs,
29
+ deploySkillDir,
30
+ deploySkillsWithKernelRouting,
31
+ isKernelSkill,
32
+ pruneStaleAiwgSkills,
33
+ computeAllKernelNames,
34
+ deployFiles,
35
+ getAddonSkillDirs,
36
+ normalizeDeploymentMode,
37
+ collectFrameworkArtifacts,
38
+ listOnDemandRuleFiles,
39
+ renderOnDemandRuleSection,
40
+ } from './base.mjs';
41
+
42
+ // ============================================================================
43
+ // Provider Configuration
44
+ // ============================================================================
45
+
46
+ export const name = 'hermes';
47
+ export const aliases = [];
48
+
49
+ export const paths = {
50
+ agents: 'AGENTS.md', // Aggregated routing guide at project root
51
+ commands: '', // Not applicable — no AIWG slash-command file surface
52
+ // Standard skills under ~/.hermes/skills/.aiwg/ — child of Hermes's scanned root,
53
+ // recursively discovered (verified `agent/skill_utils.py:478-489`, os.walk follows
54
+ // subdirs except .git/.github/.hub/.archive). Kernel skills land in the parent.
55
+ skills: path.join(os.homedir(), '.hermes', 'skills', '.aiwg'),
56
+ rules: '', // Inlined into AGENTS.md + reachable via `aiwg show rule`
57
+ };
58
+
59
+ // Kernel skills (always-loaded) deploy to the platform-native dir.
60
+ // Standard skills land in the .aiwg/ subdirectory under the same root —
61
+ // Hermes recursively walks the skill root (verified against upstream v0.13.0,
62
+ // `agent/skill_utils.py:478-489`).
63
+ export const kernelSkillsPath = path.join(os.homedir(), '.hermes', 'skills');
64
+
65
+ export const support = {
66
+ agents: 'aggregated', // Agents aggregated into lean AGENTS.md
67
+ commands: 'none', // Hermes has no AIWG slash-command file surface
68
+ skills: 'native', // ~/.hermes/skills/ is native Hermes skill location
69
+ rules: 'agents-md+cli', // compressed in AGENTS.md; full bodies via CLI/MCP
70
+ };
71
+
72
+ export const capabilities = {
73
+ skills: true,
74
+ rules: false,
75
+ aggregatedOutput: true,
76
+ yamlFormat: false,
77
+ homeDirectoryDeploy: true, // Skills deploy to home dir
78
+ };
79
+
80
+ // ============================================================================
81
+ // Model Mapping (not applicable — Hermes uses local Ollama models)
82
+ // ============================================================================
83
+
84
+ export function mapModel(shorthand, modelCfg, modelsConfig) {
85
+ return shorthand;
86
+ }
87
+
88
+ // ============================================================================
89
+ // AGENTS.md Generation
90
+ // ============================================================================
91
+
92
+ /**
93
+ * Generate a lean AGENTS.md for Hermes
94
+ *
95
+ * Hermes loads AGENTS.md on every turn — keep it under 1,000 characters
96
+ * to preserve context budget on 12GB VRAM setups.
97
+ * See: docs/integrations/hermes-quickstart.md (Part 3)
98
+ */
99
+ // Hermes context cap is 20K chars (head-tail truncated above). Hard limit
100
+ // to leave headroom for project-specific additions and skill-discovery.
101
+ const HERMES_AGENTS_MD_HARD_CAP = 19_000;
102
+ const HERMES_AGENTS_MD_SOFT_WARN = 15_000;
103
+
104
+ /**
105
+ * Top-7 CRITICAL rule directives, inlined into AGENTS.md for guaranteed
106
+ * priming on every Hermes turn (#1318 / S7; skill-discovery added #1347).
107
+ *
108
+ * The full rule bodies are reachable without MCP via `aiwg discover` and
109
+ * `aiwg show rule <name>`; MCP exposes the same path through `rule-list` and
110
+ * `rule-show` when configured (#1320). The bodies exceed Hermes's 20K context
111
+ * cap if inlined verbatim (anti-laziness alone is 32K chars), so we inline
112
+ * compressed directives only and point to CLI/MCP for the full text.
113
+ *
114
+ * Selection criteria: rules tagged CRITICAL/HIGH enforcement level whose
115
+ * violations are silent or destructive (cost of remembering to query
116
+ * rule-show > cost of inlining the directive). skill-discovery is HIGH
117
+ * but is the linchpin of the discover-first architecture across all
118
+ * providers and is therefore inlined alongside the CRITICAL set.
119
+ */
120
+ const CRITICAL_RULE_DIRECTIVES = `## CRITICAL Rules (always apply)
121
+
122
+ These are the highest-enforcement AIWG rules. Full bodies are reachable without
123
+ MCP:
124
+ - Find rules: \`aiwg discover "rule <topic>" --type rule\`
125
+ - Fetch a rule: \`aiwg show rule <name>\`
126
+
127
+ If the optional MCP sidecar is configured, the same surface is available through
128
+ \`mcp_aiwg_rule_list\` and \`mcp_aiwg_rule_show\`.
129
+
130
+ ### Rule: skill-discovery (discover-first protocol)
131
+ Before declining a user request as "outside AIWG's scope" or improvising a
132
+ workflow from training data, you MUST run \`aiwg discover "<user need>"\`
133
+ against the user's need. Most AIWG skills are not in your context; they reach
134
+ you through \`aiwg discover\` + \`aiwg show <type> <name>\`. If MCP is available,
135
+ \`mcp_aiwg_discover\` and type-specific show tools are equivalent. Run discover
136
+ whenever the user mentions AIWG, a framework name (sdlc, research, forensics,
137
+ ops, marketing, security-engineering, media-curator, knowledge-base), or
138
+ capability keywords (skill, agent, command, rule, workflow).
139
+
140
+ ### Rule: no-attribution
141
+ Never add AI-tool attribution to commits, PRs, code, or docs. No \`Co-Authored-By:\`,
142
+ no "Generated with", no "Written by [AI tool]". The AI is a tool; tools don't sign
143
+ their output. Applies to ALL platforms (Claude, Codex, Copilot, Cursor, etc.).
144
+
145
+ ### Rule: anti-laziness
146
+ Never delete tests to make them pass. Never skip/disable tests. Never remove
147
+ features instead of fixing them. Never weaken assertions to be meaningless.
148
+ Never suppress CI/pipeline signals (\`continue-on-error\`, \`|| true\`, \`set +e\`).
149
+ If stuck after 3 honest attempts: escalate with full context, don't shortcut.
150
+ Within scope: leave nothing half-done — code + tests + docs + verification.
151
+
152
+ ### Rule: citation-policy
153
+ Never fabricate citations, DOIs, URLs, or page numbers. Only cite sources that
154
+ exist in the research corpus (.aiwg/research/sources/). Match claim strength
155
+ to evidence quality (GRADE): HIGH = "demonstrates"; MODERATE = "suggests";
156
+ LOW = "limited evidence"; VERY LOW = "anecdotal". Document research gaps in
157
+ .aiwg/research/TODO.md when no source supports a claim.
158
+
159
+ ### Rule: token-security
160
+ Never hard-code tokens, API keys, or secrets in source files or commit messages.
161
+ Never pass tokens as CLI arguments (visible in process list). Never echo or log
162
+ token values. Load from secure files (mode 600) or environment variables. Use
163
+ heredoc scope for multi-step operations so tokens don't persist beyond use.
164
+ Token files must NEVER be tracked in git (.gitignore enforced).
165
+
166
+ ### Rule: versioning
167
+ CalVer format: \`YYYY.M.PATCH\` (e.g., \`2026.5.3\`). NEVER use leading zeros
168
+ (\`2026.01.5\` is broken — npm semver rejects it). Tags use \`v\` prefix.
169
+ CHANGELOG must use same format. PATCH resets each month.
170
+
171
+ ### Rule: ops-safety
172
+ Detect interactive commands and flag for human execution (passwords, LUKS
173
+ passphrases, MFA — agents cannot type these). Gate destructive operations
174
+ (\`rm -rf\`, \`fdisk\`, \`mkfs\`, partition table changes) behind explicit
175
+ human confirmation. Assess blast radius before execution (CRITICAL = multi-host
176
+ / data loss; HIGH = single-host outage). Dry-run first when the tool supports it.
177
+ Never cross host boundaries without confirmation.`;
178
+
179
+ const HERMES_AGENTS_MD_FOOTER = `## Optional MCP Server Surface (\`aiwg mcp serve\`)
180
+
181
+ MCP is optional. The baseline path is file deploy + \`aiwg discover\` /
182
+ \`aiwg show\` from the CLI. MCP exposes the same AIWG catalog and execution
183
+ surface as provider-agnostic tools when configured.
184
+
185
+ **Discovery** (read-only, no project required):
186
+ - \`mcp_aiwg_discover\` — semantic search across skills/agents/commands/rules
187
+ - \`mcp_aiwg_skill_list\` / \`mcp_aiwg_skill_show\`
188
+ - \`mcp_aiwg_command_list\` / \`mcp_aiwg_command_show\`
189
+ - \`mcp_aiwg_rule_list\` / \`mcp_aiwg_rule_show\`
190
+ - \`mcp_aiwg_agent_list\` / \`mcp_aiwg_agent_show\`
191
+ - \`mcp_aiwg_template_list\` / \`mcp_aiwg_template_show\` / \`mcp_aiwg_template_render\`
192
+
193
+ **Execution** (allow-listed):
194
+ - \`mcp_aiwg_command_run\` — dispatches to any of 94 AIWG CLI commands. Destructive
195
+ commands require \`confirmed: true\`.
196
+
197
+ **Artifacts** (project-required, .aiwg/ directory):
198
+ - \`mcp_aiwg_artifact_read\` / \`mcp_aiwg_artifact_write\``;
199
+
200
+ export function generateAgentsMd(agentCount, skillCount, targetDir, opts) {
201
+ const { dryRun } = opts;
202
+
203
+ const header = `# AIWG Integration
204
+
205
+ AIWG connected through file-based deployment. Native Hermes skills are available
206
+ at \`~/.hermes/skills/\` (kernel) and \`~/.hermes/skills/.aiwg/\` (standard).
207
+ Use \`aiwg discover\` and \`aiwg show <type> <name>\` for the on-demand catalog.
208
+ The MCP sidecar (\`aiwg mcp serve\`) is optional.
209
+
210
+ ## Route to AIWG When
211
+
212
+ - Structured artifacts needed (requirements, architecture, test plans, risk registers)
213
+ - Multi-step workflows with phase gates or checkpoints
214
+ - Template-driven output that persists across sessions
215
+
216
+ Handle in Hermes directly: one-off questions, short tasks, conversation.
217
+
218
+ ## Memory Boundary
219
+
220
+ When AIWG returns an artifact: store path + one-sentence summary in MEMORY.md.
221
+ Do NOT copy artifact body text into memory. Reference, don't replicate.
222
+
223
+ Use \`delegate_task(goal="...", context="...")\` for AIWG workflows.
224
+ Child agents automatically exclude context files and memory.
225
+
226
+ ## Artifact Store (.aiwg/)
227
+
228
+ Fetch on demand via \`mcp_aiwg_artifact_read\`:
229
+ - \`requirements/\` — use cases, user stories
230
+ - \`architecture/\` — SAD, ADRs
231
+ - \`planning/\` — phase plans
232
+ - \`testing/\` — test strategy
233
+ - \`security/\` — threat models
234
+ `;
235
+
236
+ // On-demand tier (#1675): the MEDIUM/LOW rules not inlined above. Hermes has
237
+ // no scanned rule dir, so the bridge file notes the tier with fetch hints.
238
+ const onDemandSection = opts.srcRoot
239
+ ? renderOnDemandRuleSection(listOnDemandRuleFiles(opts.srcRoot))
240
+ : '';
241
+ const sections = [header, CRITICAL_RULE_DIRECTIVES];
242
+ if (onDemandSection) sections.push(onDemandSection);
243
+ sections.push(HERMES_AGENTS_MD_FOOTER);
244
+ const output = sections.join('\n\n');
245
+ const destPath = path.join(targetDir, 'AGENTS.md');
246
+
247
+ if (output.length > HERMES_AGENTS_MD_HARD_CAP) {
248
+ throw new Error(
249
+ `Hermes AGENTS.md (${output.length} chars) exceeds hard cap of ${HERMES_AGENTS_MD_HARD_CAP}. ` +
250
+ `Hermes truncates above 20K. Trim the priming block or split rule bodies further.`
251
+ );
252
+ }
253
+
254
+ if (dryRun) {
255
+ console.log(`[dry-run] Would write AGENTS.md (${output.length} chars, ${Math.round(output.length / 4)} tokens estimated)`);
256
+ } else {
257
+ fs.writeFileSync(destPath, output, 'utf8');
258
+ const charCount = output.length;
259
+ const tokenEstimate = Math.round(charCount / 4);
260
+ let budgetNote;
261
+ if (charCount > HERMES_AGENTS_MD_SOFT_WARN) {
262
+ budgetNote = `⚠ ${charCount} chars — above soft warn (${HERMES_AGENTS_MD_SOFT_WARN}); below hard cap (${HERMES_AGENTS_MD_HARD_CAP})`;
263
+ } else {
264
+ budgetNote = `✓ within budget (cap: ${HERMES_AGENTS_MD_HARD_CAP})`;
265
+ }
266
+ console.log(` Created AGENTS.md (${charCount} chars, ~${tokenEstimate} tokens, ${budgetNote})`);
267
+ }
268
+
269
+ return 1;
270
+ }
271
+
272
+ /**
273
+ * Generate `.hermes.md` thin pointer at the project root (#1319 / S8).
274
+ *
275
+ * Hermes loads `.hermes.md` with priority over `AGENTS.md` (first-match-wins
276
+ * at `agent/prompt_builder.py:1417-1456`). The pointer is short so the
277
+ * actual context payload remains in AGENTS.md which is shared with other
278
+ * tools (Claude Code, Codex, etc.).
279
+ */
280
+ export function generateHermesMd(targetDir, opts) {
281
+ const { dryRun } = opts;
282
+ const body = `# Hermes Routing
283
+
284
+ AIWG project context lives in \`AGENTS.md\` (this file is a thin Hermes pointer).
285
+
286
+ **Routing**: see \`AGENTS.md\` in this directory.
287
+ **MCP**: AIWG is reachable via \`mcp_aiwg_*\` tools.
288
+ **Skills**: kernel skills at \`~/.hermes/skills/\`; standard skills at \`~/.hermes/skills/.aiwg/\`.
289
+
290
+ Hermes loads \`.hermes.md\` before \`AGENTS.md\` (first-match-wins). Keep this
291
+ file minimal — Hermes will load AGENTS.md content next via the routing chain.
292
+ `;
293
+ const destPath = path.join(targetDir, '.hermes.md');
294
+ if (dryRun) {
295
+ console.log(`[dry-run] Would write .hermes.md (${body.length} chars)`);
296
+ } else {
297
+ fs.writeFileSync(destPath, body, 'utf8');
298
+ console.log(` Created .hermes.md (${body.length} chars)`);
299
+ }
300
+ return 1;
301
+ }
302
+
303
+ // ============================================================================
304
+ // Skills Deployment
305
+ // ============================================================================
306
+
307
+ /**
308
+ * Deploy skills with kernel-vs-standard routing (#1212/#1216).
309
+ *
310
+ * Skills are user-global in Hermes, deployed once, available in all
311
+ * projects. Kernel routing per the cross-provider pattern:
312
+ * - kernel skills → ~/.hermes/skills/ (platform-native, always-loaded)
313
+ * - standard → ~/.hermes/skills/.aiwg/ (recursively walked by Hermes)
314
+ */
315
+ export function deploySkills(skillDirs, opts) {
316
+ const standardDestDir = paths.skills;
317
+ const kernelDestDir = kernelSkillsPath;
318
+
319
+ if (!opts.dryRun) {
320
+ console.log(` Deploying ${skillDirs.length} skills (kernel + standard split)...`);
321
+ }
322
+
323
+ deploySkillsWithKernelRouting(skillDirs, standardDestDir, kernelDestDir, opts);
324
+ }
325
+
326
+ // ============================================================================
327
+ // Main Deploy Function
328
+ // ============================================================================
329
+
330
+ export async function deploy(opts) {
331
+ const {
332
+ srcRoot,
333
+ target,
334
+ mode,
335
+ deploySkills: shouldDeploySkills,
336
+ skillsOnly,
337
+ dryRun,
338
+ } = opts;
339
+
340
+ const normalizedMode = normalizeDeploymentMode(mode);
341
+
342
+ if (!opts.quiet) {
343
+ console.log(`\n=== Hermes Agent Provider ===`);
344
+ console.log(`Target: ${target}`);
345
+ console.log(`Skills: ${paths.skills}`);
346
+ console.log(`Mode: ${mode}`);
347
+ console.log(`Architecture: Hermes → MCP → AIWG`);
348
+ console.log('');
349
+ }
350
+
351
+ // ── Legacy skill path migration (#1316 / S5) ───────────────────────────────
352
+ // Earlier AIWG versions deployed standard skills to ~/.hermes/.aiwg/skills/
353
+ // (sibling of Hermes's scanned root — invisible to Hermes). #1314 moved
354
+ // them to ~/.hermes/skills/.aiwg/ (recursively scanned). This helper
355
+ // detects the legacy path and removes it after the new path is populated,
356
+ // preventing operator confusion and curator-bait.
357
+ if (!skillsOnly || shouldDeploySkills) {
358
+ migrateLegacySkillPath(opts);
359
+ }
360
+
361
+ // ── Skills ─────────────────────────────────────────────────────────────────
362
+ if ((shouldDeploySkills || skillsOnly) && !opts.commandsOnly && !opts.rulesOnly) {
363
+ const allSkillDirs = [];
364
+
365
+ // Addon skills (aiwg-utils, ralph, etc.)
366
+ allSkillDirs.push(...getAddonSkillDirs(srcRoot));
367
+
368
+ // Framework skills
369
+ const artifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
370
+ includeAgents: false,
371
+ includeCommands: false,
372
+ includeSkills: true,
373
+ includeRules: false,
374
+ });
375
+ allSkillDirs.push(...(artifacts.skills || []));
376
+
377
+ if (allSkillDirs.length > 0) {
378
+ deploySkills(allSkillDirs, opts);
379
+ } else if (!opts.quiet) {
380
+ console.log(' No skills found to deploy');
381
+ }
382
+
383
+ // Holistic post-deploy cleanup of stale AIWG-managed kernel skills.
384
+ // Uses the global kernel set (walks all source frameworks/addons),
385
+ // not just this-call's skillDirs, because aiwg use invokes
386
+ // deploy-agents.mjs multiple times. Hermes augments the canonical
387
+ // set with `aiwg-orchestrate` (#1242) — the orchestrate skill is a
388
+ // template-driven convenience install (not part of any framework's
389
+ // skills/), so without this exemption the prune would delete it
390
+ // every time it's auto-installed.
391
+ // `computeAllKernelNames` returns null when no AIWG framework/addon tree
392
+ // can be located (e.g. project-local bundle deploy without AIWG_ROOT).
393
+ // Skip both the prune and the manifest update in that case rather than
394
+ // operate on an empty desired set (#123).
395
+ const kernelNames = computeAllKernelNames(srcRoot);
396
+ if (kernelNames != null) {
397
+ const desiredKernel = [...kernelNames, 'aiwg-orchestrate'];
398
+ pruneStaleAiwgSkills(kernelSkillsPath, desiredKernel, opts);
399
+
400
+ // Register kernel skills in Hermes's bundled manifest so the Curator
401
+ // (v0.12.0+, 7-day archival cycle) does not archive them. Standard
402
+ // skills under `.aiwg/` are already protected by the dot-prefix rule
403
+ // in tools/skill_usage.py:241-243. (#1317 / S6)
404
+ updateBundledManifest(desiredKernel, opts);
405
+ }
406
+ }
407
+
408
+ // ── AGENTS.md + .hermes.md ─────────────────────────────────────────────────
409
+ // Generate AGENTS.md (with inlined CRITICAL rule priming, #1318/#1532)
410
+ // AND .hermes.md thin pointer (resolves #1319 doc-debt, was claimed in
411
+ // CHANGELOG but not previously implemented).
412
+ if (!skillsOnly && !opts.commandsOnly && !opts.rulesOnly) {
413
+ const artifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
414
+ includeAgents: true,
415
+ includeCommands: false,
416
+ includeSkills: true,
417
+ includeRules: false,
418
+ });
419
+ const agentCount = (artifacts.agents || []).length;
420
+ const skillCount = (artifacts.skills || []).length;
421
+ generateAgentsMd(agentCount, skillCount, target, opts);
422
+ generateHermesMd(target, opts);
423
+ }
424
+
425
+ // ── aiwg-orchestrate convenience skill (#1242) ──────────────────────────────
426
+ // First-deploy-only copy: lays down the delegate_task wrapper at
427
+ // ~/.hermes/skills/aiwg-orchestrate/SKILL.md if it isn't already present.
428
+ // The skill provides ~95% per-workflow context reduction by routing AIWG
429
+ // calls through Hermes's `delegate_task` instead of inline MCP. Idempotent
430
+ // on re-run — operator edits are preserved across `aiwg use` invocations.
431
+ if (!skillsOnly && !opts.commandsOnly && !opts.rulesOnly) {
432
+ deployAiwgOrchestrateSkill(srcRoot, opts);
433
+ }
434
+
435
+ // ── Post-deployment hint ───────────────────────────────────────────────────
436
+ if (!opts.quiet) {
437
+ console.log('');
438
+ console.log('Rules are in AGENTS.md as compressed directives; full bodies via `aiwg show rule <name>`.');
439
+ console.log('Optional: configure ~/.hermes/config.yaml to connect AIWG MCP server.');
440
+ console.log('See: docs/integrations/hermes-quickstart.md (optional MCP setup)');
441
+ }
442
+ }
443
+
444
+ // ============================================================================
445
+ // Curator protection (#1317 / S6)
446
+ // ============================================================================
447
+
448
+ /**
449
+ * Hermes v0.12.0+ ships an autonomous Curator (`agent/curator.py`) that
450
+ * grades and archives skills on a 7-day cycle. Skills are excluded from
451
+ * archival if either:
452
+ * (a) they appear in `~/.hermes/skills/.bundled_manifest` (one name per
453
+ * line, format `name:tag`), or
454
+ * (b) their path's first component starts with `.` (verified at
455
+ * `tools/skill_usage.py:241-243`).
456
+ *
457
+ * AIWG standard skills under `~/.hermes/skills/.aiwg/...` are protected
458
+ * by (b) automatically. AIWG kernel skills land at the top level
459
+ * (`~/.hermes/skills/<name>/SKILL.md`) and need explicit (a) registration.
460
+ *
461
+ * This function writes/updates the bundled manifest with the kernel-skill
462
+ * names AIWG owns. Idempotent: existing entries (from Hermes's own bundle
463
+ * or other tools) are preserved.
464
+ */
465
+ export function updateBundledManifest(kernelSkillNames, opts) {
466
+ const { dryRun, quiet } = opts;
467
+ const manifestPath = path.join(kernelSkillsPath, '.bundled_manifest');
468
+ const aiwgTag = 'aiwg-managed';
469
+
470
+ // Read existing manifest (if any) and split into "ours" vs "theirs"
471
+ let existing = '';
472
+ try {
473
+ existing = fs.readFileSync(manifestPath, 'utf-8');
474
+ } catch {
475
+ existing = '';
476
+ }
477
+ const theirs = [];
478
+ for (const rawLine of existing.split('\n')) {
479
+ const line = rawLine.trim();
480
+ if (!line) continue;
481
+ if (line.endsWith(`:${aiwgTag}`)) continue; // ours — drop, will re-add below
482
+ theirs.push(line);
483
+ }
484
+ const ours = kernelSkillNames.map((n) => `${n}:${aiwgTag}`);
485
+
486
+ // Stable order: theirs first (preserve operator/Hermes-bundled order), then ours
487
+ const merged = [...theirs, ...ours].join('\n') + '\n';
488
+
489
+ if (dryRun) {
490
+ if (!quiet) {
491
+ console.log(` [curator] [dry-run] Would write ${manifestPath} with ${ours.length} AIWG kernel + ${theirs.length} preserved entries`);
492
+ }
493
+ return;
494
+ }
495
+
496
+ try {
497
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
498
+ fs.writeFileSync(manifestPath, merged, 'utf-8');
499
+ if (!quiet) {
500
+ console.log(` [curator] Bundled manifest updated: ${ours.length} AIWG kernel skills protected (preserved ${theirs.length} pre-existing entries)`);
501
+ }
502
+ } catch (err) {
503
+ if (!quiet) {
504
+ console.log(` [curator] Warning: could not write bundled manifest: ${err.message}`);
505
+ }
506
+ }
507
+ }
508
+
509
+ // ============================================================================
510
+ // Legacy skill path migration (#1316 / S5)
511
+ // ============================================================================
512
+
513
+ /**
514
+ * Remove the legacy `~/.hermes/.aiwg/skills/` directory if it exists and the
515
+ * new path `~/.hermes/skills/.aiwg/` is populated with AIWG content.
516
+ *
517
+ * Idempotent: re-running after migration is a no-op.
518
+ *
519
+ * Safety:
520
+ * - Only removes when the new path exists and contains files
521
+ * - Skips removal if the new path is empty (avoids losing skills during
522
+ * an in-progress deploy where the new path hasn't been written yet)
523
+ * - Operates only on the documented legacy path — never touches user-managed
524
+ * directories under ~/.hermes/
525
+ */
526
+ export function migrateLegacySkillPath(opts) {
527
+ const { dryRun, quiet } = opts;
528
+ const legacyPath = path.join(os.homedir(), '.hermes', '.aiwg', 'skills');
529
+ const newPath = paths.skills;
530
+
531
+ let legacyExists = false;
532
+ try {
533
+ legacyExists = fs.statSync(legacyPath).isDirectory();
534
+ } catch {
535
+ return; // no legacy path — nothing to migrate
536
+ }
537
+ if (!legacyExists) return;
538
+
539
+ // Sanity: new path must exist and be non-empty before we remove the legacy one
540
+ let newPopulated = false;
541
+ try {
542
+ const entries = fs.readdirSync(newPath);
543
+ newPopulated = entries.length > 0;
544
+ } catch {
545
+ newPopulated = false;
546
+ }
547
+
548
+ if (!newPopulated) {
549
+ if (!quiet) {
550
+ console.log(` [migrate] Legacy skills detected at ${legacyPath}; new path not yet populated. Skipping cleanup until next deploy.`);
551
+ }
552
+ return;
553
+ }
554
+
555
+ if (dryRun) {
556
+ console.log(` [migrate] [dry-run] Would remove legacy skill path: ${legacyPath}`);
557
+ return;
558
+ }
559
+
560
+ try {
561
+ fs.rmSync(legacyPath, { recursive: true, force: true });
562
+ // Also remove the empty parent if it's now empty
563
+ const parent = path.dirname(legacyPath);
564
+ try {
565
+ const remaining = fs.readdirSync(parent);
566
+ if (remaining.length === 0) {
567
+ fs.rmdirSync(parent);
568
+ }
569
+ } catch {
570
+ // parent removal is best-effort
571
+ }
572
+ if (!quiet) {
573
+ console.log(` [migrate] Removed legacy skill path: ${legacyPath}`);
574
+ }
575
+ } catch (err) {
576
+ if (!quiet) {
577
+ console.log(` [migrate] Warning: could not remove legacy path ${legacyPath}: ${err.message}`);
578
+ }
579
+ }
580
+ }
581
+
582
+ // ============================================================================
583
+ // aiwg-orchestrate auto-install (#1242)
584
+ // ============================================================================
585
+
586
+ /**
587
+ * Copy the aiwg-orchestrate skill template to ~/.hermes/skills/ on first
588
+ * deploy. Skip if a SKILL.md already exists — preserves operator edits and
589
+ * any prior version they're running. Errors during the copy are non-fatal:
590
+ * the rest of the deploy must succeed even if the home dir is read-only or
591
+ * the template is missing in this checkout.
592
+ */
593
+ function deployAiwgOrchestrateSkill(srcRoot, opts) {
594
+ const templatePath = path.join(
595
+ srcRoot,
596
+ 'agentic',
597
+ 'code',
598
+ 'frameworks',
599
+ 'sdlc-complete',
600
+ 'templates',
601
+ 'hermes',
602
+ 'skills',
603
+ 'aiwg-orchestrate',
604
+ 'SKILL.md',
605
+ );
606
+
607
+ if (!fs.existsSync(templatePath)) {
608
+ if (!opts.quiet) {
609
+ console.log(' aiwg-orchestrate template not present in this build — skipping auto-install');
610
+ }
611
+ return;
612
+ }
613
+
614
+ const destDir = path.join(kernelSkillsPath, 'aiwg-orchestrate');
615
+ const destPath = path.join(destDir, 'SKILL.md');
616
+
617
+ if (fs.existsSync(destPath)) {
618
+ if (!opts.quiet) {
619
+ console.log(` aiwg-orchestrate already present at ${destPath} — operator copy preserved`);
620
+ }
621
+ return;
622
+ }
623
+
624
+ if (opts.dryRun) {
625
+ if (!opts.quiet) {
626
+ console.log(` [dry-run] Would install aiwg-orchestrate to ${destPath}`);
627
+ }
628
+ return;
629
+ }
630
+
631
+ try {
632
+ ensureDir(destDir);
633
+ const content = fs.readFileSync(templatePath, 'utf8');
634
+ fs.writeFileSync(destPath, content, 'utf8');
635
+ if (!opts.quiet) {
636
+ console.log(` Installed aiwg-orchestrate to ${destPath} (delegate_task wrapper, 95% context reduction)`);
637
+ }
638
+ } catch (err) {
639
+ if (!opts.quiet) {
640
+ console.log(` aiwg-orchestrate auto-install skipped: ${err.message}`);
641
+ }
642
+ }
643
+ }
644
+
645
+ // ============================================================================
646
+ // File Extension
647
+ // ============================================================================
648
+
649
+ export function getFileExtension(type) {
650
+ return '.md';
651
+ }
652
+
653
+ // ============================================================================
654
+ // Content Transformation (passthrough for Hermes — skills use their own format)
655
+ // ============================================================================
656
+
657
+ export function transformAgent(srcPath, content, opts) {
658
+ return content;
659
+ }
660
+
661
+ export function transformCommand(srcPath, content, opts) {
662
+ return content;
663
+ }