@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.
- package/README.md +33 -0
- package/agentic/code/providers/capability-matrix.yaml +511 -0
- package/agentic/code/providers/model-capabilities.v1.json +120 -0
- package/agentic/code/providers/model-catalog.v1.json +96 -0
- package/agentic/code/providers/model-policy-evaluations.v1.json +50 -0
- package/agentic/code/providers/premium-model-allowlist.v1.json +36 -0
- package/bin/aiwg.mjs +14 -10
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/cli.js +2 -0
- package/dist/src/artifacts/types.js +4 -0
- package/dist/src/auth/client.js +209 -0
- package/dist/src/auth/config.js +38 -0
- package/dist/src/auth/credential-store.js +141 -0
- package/dist/src/auth/resource-credentials.js +25 -0
- package/dist/src/auth/types.js +2 -0
- package/dist/src/channel/manager.mjs +5 -5
- package/dist/src/cli/handlers/auth.js +125 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/install.js +42 -4
- package/dist/src/cli/handlers/marketplace.js +375 -122
- package/dist/src/cli/handlers/resource-versions.js +2 -0
- package/dist/src/cli/handlers/sessions.js +23 -5
- package/dist/src/cli/handlers/subcommands.js +10 -1
- package/dist/src/cli/handlers/use.js +342 -43
- package/dist/src/config/gitignore.js +1 -0
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/marketplace/exchange.js +602 -0
- package/dist/src/marketplace/provenance-types.js +19 -0
- package/dist/src/marketplace/provenance.js +834 -0
- package/dist/src/memory/canonical-context.js +342 -0
- package/dist/src/memory/context-pack.js +282 -0
- package/dist/src/memory/index.js +4 -0
- package/dist/src/memory/intake.js +118 -0
- package/dist/src/packages/adapters/git.js +79 -29
- package/dist/src/packages/package-discovery.js +81 -0
- package/dist/src/packages/package-registry.js +2 -0
- package/dist/src/packages/registry.js +119 -20
- package/dist/src/resources/resolver.js +1 -0
- package/dist/src/resources/web-release.d.ts +3 -1
- package/dist/src/resources/web-release.js +14 -6
- package/dist/src/serve/agentic-sandbox-fleet-client.js +213 -0
- package/dist/src/serve/fleet-mission-conductor.js +293 -0
- package/dist/src/sessions/index.js +1 -0
- package/dist/src/sessions/output-registration.js +338 -0
- package/dist/src/sessions/promotion.js +73 -2
- package/dist/src/sessions/repository.js +2 -1
- package/dist/src/update/notifier.mjs +13 -2
- package/package.json +8 -1
- package/tools/_resolve-impl.mjs +74 -0
- package/tools/agents/deploy-agents.mjs +962 -0
- package/tools/agents/providers/base.mjs +2954 -0
- package/tools/agents/providers/claude.mjs +711 -0
- package/tools/agents/providers/codex.mjs +699 -0
- package/tools/agents/providers/copilot.mjs +659 -0
- package/tools/agents/providers/cursor.mjs +714 -0
- package/tools/agents/providers/factory.mjs +1130 -0
- package/tools/agents/providers/hermes.mjs +663 -0
- package/tools/agents/providers/hook-capabilities.mjs +85 -0
- package/tools/agents/providers/model-role.mjs +56 -0
- package/tools/agents/providers/openclaw-translator.mjs +348 -0
- package/tools/agents/providers/openclaw.mjs +680 -0
- package/tools/agents/providers/opencode.mjs +675 -0
- package/tools/agents/providers/openhuman.mjs +292 -0
- package/tools/agents/providers/warp.mjs +413 -0
- package/tools/agents/providers/windsurf.mjs +748 -0
- package/tools/commands/deploy-prompts-codex.mjs +336 -0
- package/tools/plugin/package-plugins.mjs +1013 -0
- 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
|
+
}
|