@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,680 @@
1
+ /**
2
+ * OpenClaw Provider
3
+ *
4
+ * OpenClaw uses an MCP-based integration model similar to Hermes, but with
5
+ * native support for all 5 artifact types including behaviors.
6
+ *
7
+ * What this provider deploys (all user-global, home directory):
8
+ * - Agents: ~/.openclaw/agents/ (native agent definitions)
9
+ * - Commands: ~/.openclaw/commands/ (slash commands)
10
+ * - Skills: ~/.openclaw/skills/ (NLP-triggered capabilities)
11
+ * - Rules: ~/.openclaw/rules/ (context-loaded constraints)
12
+ * - Behaviors: ~/.openclaw/behaviors/ (reactive capabilities with hooks + scripts)
13
+ *
14
+ * OpenClaw is the first platform to support behaviors natively.
15
+ * Behaviors are a new AIWG artifact type: reactive capabilities with scripts
16
+ * and event hooks that fire automatically when system events occur.
17
+ *
18
+ * See: docs/openclaw-guide.md
19
+ */
20
+
21
+ import realFs from 'fs';
22
+ import { createRequire } from 'module';
23
+ const _require = createRequire(import.meta.url);
24
+ let fs;
25
+ try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
26
+ import path from 'path';
27
+ import os from 'os';
28
+ import {
29
+ ensureDir,
30
+ listMdFiles,
31
+ listMdFilesRecursive,
32
+ listSkillDirs,
33
+ deploySkillDir,
34
+ deploySkillsWithKernelRouting,
35
+ isKernelSkill,
36
+ pruneStaleAiwgSkills,
37
+ computeAllKernelNames,
38
+ deployFiles,
39
+ getAddonAgentFiles,
40
+ getAddonCommandFiles,
41
+ getAddonSkillDirs,
42
+ getAddonRuleFiles,
43
+ assembleRulesIndex,
44
+ normalizeDeploymentMode,
45
+ collectFrameworkArtifacts,
46
+ listOnDemandRuleFiles,
47
+ writeOnDemandRuleIndex,
48
+ cleanupOldRuleFiles,
49
+ filterAgentFiles,
50
+ filterCommandsAgainstSkills,
51
+ createAgentsMdFromTemplate,
52
+ createManagedMdFromTemplate,
53
+ } from './base.mjs';
54
+
55
+ // ============================================================================
56
+ // Provider Configuration
57
+ // ============================================================================
58
+
59
+ export const name = 'openclaw';
60
+ export const aliases = [];
61
+
62
+ const openclawHome = path.join(os.homedir(), '.openclaw');
63
+
64
+ export const paths = {
65
+ agents: path.join(openclawHome, 'agents'),
66
+ commands: path.join(openclawHome, 'commands'),
67
+ // Skills sequestered under ~/.openclaw/.aiwg/skills/ — index-driven discovery (#1212).
68
+ skills: path.join(openclawHome, '.aiwg', 'skills'),
69
+ rules: path.join(openclawHome, 'rules'),
70
+ behaviors: path.join(openclawHome, 'behaviors'),
71
+ // Per ADR-3 + PUW-008/009: native hook loader path.
72
+ // BEHAVIOR.md → HOOK.md + handler.js translation lands here.
73
+ hooks: path.join(openclawHome, 'hooks'),
74
+ };
75
+
76
+ // Kernel skills (always-loaded) deploy to the platform-native dir.
77
+ // Critical for OpenClaw: DEFAULT_MAX_SKILLS_IN_PROMPT = 150, so the
78
+ // kernel set must come in under that floor (~9 today, well under cap).
79
+ export const kernelSkillsPath = path.join(openclawHome, 'skills');
80
+
81
+ /**
82
+ * Resolve OpenClaw's active agent workspace directory — the dir whose `AGENTS.md`
83
+ * OpenClaw injects into every session's system prompt (docs/concepts/context.md,
84
+ * agent-workspace.md). Honors `agents.defaults.workspace` in
85
+ * `~/.openclaw/openclaw.json` and the `OPENCLAW_PROFILE` env var; defaults to
86
+ * `~/.openclaw/workspace`. The deployed agents/skills/rules under `~/.openclaw/`
87
+ * are inert until the Discover-First bridge lands in this workspace AGENTS.md. (#1562)
88
+ */
89
+ export function resolveOpenClawWorkspace() {
90
+ const profile = process.env.OPENCLAW_PROFILE;
91
+ let workspace = profile && profile !== 'default'
92
+ ? path.join(openclawHome, `workspace-${profile}`)
93
+ : path.join(openclawHome, 'workspace');
94
+ try {
95
+ const cfgPath = path.join(openclawHome, 'openclaw.json');
96
+ if (fs.existsSync(cfgPath)) {
97
+ const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
98
+ const ws = cfg?.agents?.defaults?.workspace;
99
+ if (typeof ws === 'string' && ws.trim()) {
100
+ workspace = ws.startsWith('~')
101
+ ? path.join(os.homedir(), ws.slice(1).replace(/^[/\\]/, ''))
102
+ : ws;
103
+ }
104
+ }
105
+ } catch { /* malformed config — fall back to the default workspace */ }
106
+ return workspace;
107
+ }
108
+
109
+ export const support = {
110
+ agents: 'native',
111
+ // OpenClaw slash commands are built-in + plugin/skill-registered (e.g. `/prose`);
112
+ // there is NO user `~/.openclaw/commands/*.md` slash-command scan (field-validated:
113
+ // AIWG-deployed command files never appear in `/commands`). AIWG commands surface
114
+ // via the AGENTS.md bridge + `aiwg discover --type command` / `aiwg show command`,
115
+ // exactly like Codex (static enum, ADR-1) and OpenHuman.
116
+ commands: 'aggregated',
117
+ skills: 'native',
118
+ rules: 'native',
119
+ behaviors: 'native',
120
+ };
121
+
122
+ export const capabilities = {
123
+ skills: true,
124
+ rules: true,
125
+ behaviors: true,
126
+ aggregatedOutput: false,
127
+ yamlFormat: false,
128
+ homeDirectoryDeploy: true,
129
+ };
130
+
131
+ // ============================================================================
132
+ // Model Mapping (global inheritance)
133
+ // ============================================================================
134
+
135
+ export function mapModel(shorthand, modelCfg, modelsConfig) {
136
+ return undefined;
137
+ }
138
+
139
+ // ============================================================================
140
+ // Content Transformation (passthrough — OpenClaw uses AIWG native format)
141
+ // ============================================================================
142
+
143
+ export function transformAgent(srcPath, content, opts) {
144
+ // AIWG's catalog intentionally records configured/<role> placeholders for
145
+ // OpenClaw because the exact provider/model namespace is installation
146
+ // specific. Omit the portable Markdown pin and inherit the configured
147
+ // OpenClaw subagent model rather than emitting a misleading Claude alias.
148
+ return content.replace(/^model:\s*.+\n/m, '');
149
+ }
150
+
151
+ export function transformCommand(srcPath, content, opts) {
152
+ return content;
153
+ }
154
+
155
+ // ============================================================================
156
+ // Deployment Functions
157
+ // ============================================================================
158
+
159
+ /**
160
+ * Deploy agents to ~/.openclaw/agents/
161
+ */
162
+ function deployAgents(agentFiles, opts) {
163
+ ensureDir(paths.agents, opts.dryRun);
164
+ return deployFiles(agentFiles, paths.agents, { ...opts, injectPlatform: true }, transformAgent);
165
+ }
166
+
167
+ /**
168
+ * Deploy commands to ~/.openclaw/commands/
169
+ */
170
+ function deployCommands(commandFiles, opts) {
171
+ ensureDir(paths.commands, opts.dryRun);
172
+ return deployFiles(commandFiles, paths.commands, opts, transformCommand);
173
+ }
174
+
175
+ /**
176
+ * Deploy skills with kernel-vs-standard routing (#1212/#1216).
177
+ *
178
+ * OpenClaw is the binding constraint for the kernel pivot:
179
+ * `DEFAULT_MAX_SKILLS_IN_PROMPT = 150` is the hard cap. The kernel set
180
+ * (one quickref per installed framework + core utility set, ~9 today)
181
+ * fits comfortably under that floor regardless of how many frameworks
182
+ * are installed.
183
+ *
184
+ * - kernel skills → ~/.openclaw/skills/aiwg/<name> (platform-native, always-loaded)
185
+ * - standard → ~/.openclaw/.aiwg/skills/<name> (index-discoverable, hidden from flat scan)
186
+ *
187
+ * The legacy `aiwg/` 2-level namespacing under the kernel path (PUW-025
188
+ * #1126) is preserved to avoid collision with non-AIWG ClaWHub installs.
189
+ */
190
+ function deploySkills(skillDirs, opts) {
191
+ // Standard: ~/.openclaw/.aiwg/skills/ (no extra aiwg/ — the .aiwg/ segment IS the namespace)
192
+ const standardDestDir = paths.skills;
193
+ // Kernel: ~/.openclaw/skills/aiwg/ (preserves legacy 2-level namespacing)
194
+ const kernelDestDir = path.join(kernelSkillsPath, 'aiwg');
195
+
196
+ deploySkillsWithKernelRouting(skillDirs, standardDestDir, kernelDestDir, opts);
197
+
198
+ // PUW-012 (#1113): also deploy to project-local .agents/skills/ as a
199
+ // cross-agent compatibility path. OpenClaw's primary deploy is the
200
+ // home-dir namespaced layout above; this secondary surface lets other
201
+ // tools running on the same project pick up the same skills via the
202
+ // universal `.agents/skills/<name>/SKILL.md` discovery convention.
203
+ //
204
+ // Honors #1217 no-copy default: filter to kernel-only unless the
205
+ // operator opts in via env var so standard skills stay at $AIWG_ROOT
206
+ // and are reached via `aiwg discover`.
207
+ const copyStandardSkills = opts?.copyStandardSkills === true;
208
+ const crossAgentSkills = copyStandardSkills
209
+ ? skillDirs
210
+ : skillDirs.filter(d => isKernelSkill(d));
211
+ if (crossAgentSkills.length > 0) {
212
+ const crossAgentDir = path.join(process.cwd(), '.agents', 'skills');
213
+ ensureDir(crossAgentDir, opts.dryRun);
214
+ if (!opts.dryRun) {
215
+ console.log(`Deploying cross-agent skills to ${path.relative(process.cwd(), crossAgentDir)}...`);
216
+ } else {
217
+ console.log(`[dry-run] Would deploy cross-agent skills to .agents/skills/`);
218
+ }
219
+ for (const skillDir of crossAgentSkills) {
220
+ deploySkillDir(skillDir, crossAgentDir, opts);
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Deploy rules to ~/.openclaw/rules/
227
+ */
228
+ function deployRules(ruleFiles, opts) {
229
+ ensureDir(paths.rules, opts.dryRun);
230
+ cleanupOldRuleFiles(paths.rules, opts);
231
+ return deployFiles(ruleFiles, paths.rules, opts, transformCommand);
232
+ }
233
+
234
+ /**
235
+ * Deploy behaviors to ~/.openclaw/behaviors/
236
+ *
237
+ * Behaviors are directories containing BEHAVIOR.md and a scripts/ subdirectory.
238
+ * Each behavior directory is copied wholesale to the target.
239
+ */
240
+ function deployBehaviors(behaviorDirs, opts) {
241
+ ensureDir(paths.behaviors, opts.dryRun);
242
+
243
+ let count = 0;
244
+ for (const behaviorDir of behaviorDirs) {
245
+ const behaviorName = path.basename(behaviorDir);
246
+ const destDir = path.join(paths.behaviors, behaviorName);
247
+
248
+ if (opts.dryRun) {
249
+ console.log(`[dry-run] Would deploy behavior: ${behaviorName} -> ${destDir}`);
250
+ count++;
251
+ continue;
252
+ }
253
+
254
+ ensureDir(destDir);
255
+
256
+ // Copy BEHAVIOR.md
257
+ const behaviorMd = path.join(behaviorDir, 'BEHAVIOR.md');
258
+ if (fs.existsSync(behaviorMd)) {
259
+ fs.copyFileSync(behaviorMd, path.join(destDir, 'BEHAVIOR.md'));
260
+ }
261
+
262
+ // Copy scripts/ directory if it exists
263
+ const scriptsDir = path.join(behaviorDir, 'scripts');
264
+ if (fs.existsSync(scriptsDir)) {
265
+ const destScriptsDir = path.join(destDir, 'scripts');
266
+ ensureDir(destScriptsDir);
267
+
268
+ for (const entry of fs.readdirSync(scriptsDir)) {
269
+ const srcFile = path.join(scriptsDir, entry);
270
+ const destFile = path.join(destScriptsDir, entry);
271
+ if (fs.statSync(srcFile).isFile()) {
272
+ fs.copyFileSync(srcFile, destFile);
273
+ // Preserve executable permission for scripts
274
+ try { fs.chmodSync(destFile, 0o755); } catch { /* ignore on platforms without chmod */ }
275
+ }
276
+ }
277
+ }
278
+
279
+ count++;
280
+ }
281
+
282
+ // PUW-008/PUW-009 (#1109/#1110) per ADR-3: also emit hook artifacts to
283
+ // ~/.openclaw/hooks/<name>/ so OpenClaw's native hook loader picks them
284
+ // up. The behaviors/ writes above keep happening per always-deploy
285
+ // invariant (operator visibility); hooks/ is the discovery bridge.
286
+ try {
287
+ ensureDir(paths.hooks, opts.dryRun);
288
+ if (!opts.dryRun) {
289
+ // Lazy import so this is only loaded when behaviors exist.
290
+ import('./openclaw-translator.mjs').then((mod) => {
291
+ let translated = 0;
292
+ const skipped = [];
293
+ for (const behaviorDir of behaviorDirs) {
294
+ const behaviorName = path.basename(behaviorDir);
295
+ const hookDir = path.join(paths.hooks, behaviorName);
296
+ const r = mod.translateBehaviorToHook(behaviorDir, hookDir, opts);
297
+ if (r.ok) translated++;
298
+ else skipped.push({ name: behaviorName, reason: r.reason });
299
+ }
300
+ if (translated > 0) {
301
+ console.log(`Translated ${translated} behavior(s) to OpenClaw hooks at ${paths.hooks}`);
302
+ }
303
+ if (skipped.length > 0 && opts.verbose) {
304
+ for (const s of skipped) {
305
+ console.log(`Skipped hook translation for ${s.name}: ${s.reason}`);
306
+ }
307
+ }
308
+ }).catch((err) => {
309
+ console.warn(`Warning: hook translation failed: ${err.message || err}`);
310
+ });
311
+ }
312
+ } catch (err) {
313
+ console.warn(`Warning: hook deployment skipped: ${err.message || err}`);
314
+ }
315
+
316
+ return count;
317
+ }
318
+
319
+ // ============================================================================
320
+ // Behavior Discovery
321
+ // ============================================================================
322
+
323
+ /**
324
+ * List behavior directories (directories containing BEHAVIOR.md)
325
+ */
326
+ function listBehaviorDirs(dir) {
327
+ if (!fs.existsSync(dir)) return [];
328
+ return fs
329
+ .readdirSync(dir, { withFileTypes: true })
330
+ .filter((e) => e.isDirectory() && fs.existsSync(path.join(dir, e.name, 'BEHAVIOR.md')))
331
+ .map((e) => path.join(dir, e.name));
332
+ }
333
+
334
+ /**
335
+ * Collect behavior directories from all sources:
336
+ * - Cross-framework: agentic/code/behaviors/
337
+ * - Per-addon: agentic/code/addons/<name>/behaviors/
338
+ * - Per-framework: agentic/code/frameworks/<name>/behaviors/
339
+ * - Direct component source: <srcRoot>/behaviors/
340
+ */
341
+ function collectBehaviorDirs(srcRoot, mode) {
342
+ const dirs = [];
343
+ const seen = new Set();
344
+ const addDirs = (items) => {
345
+ for (const dir of items) {
346
+ if (seen.has(dir)) continue;
347
+ seen.add(dir);
348
+ dirs.push(dir);
349
+ }
350
+ };
351
+
352
+ // Direct component source, used by addon-only deploys such as:
353
+ // aiwg use aiwg-fleet --provider openclaw
354
+ addDirs(listBehaviorDirs(path.join(srcRoot, 'behaviors')));
355
+
356
+ // Cross-framework behaviors
357
+ const globalBehaviorsDir = path.join(srcRoot, 'agentic', 'code', 'behaviors');
358
+ addDirs(listBehaviorDirs(globalBehaviorsDir));
359
+
360
+ // Addon behaviors
361
+ const addonsDir = path.join(srcRoot, 'agentic', 'code', 'addons');
362
+ if (fs.existsSync(addonsDir)) {
363
+ for (const entry of fs.readdirSync(addonsDir, { withFileTypes: true })) {
364
+ if (!entry.isDirectory()) continue;
365
+ const addonBehaviorsDir = path.join(addonsDir, entry.name, 'behaviors');
366
+ addDirs(listBehaviorDirs(addonBehaviorsDir));
367
+ }
368
+ }
369
+
370
+ // Per-framework behaviors
371
+ const frameworksDir = path.join(srcRoot, 'agentic', 'code', 'frameworks');
372
+ if (fs.existsSync(frameworksDir)) {
373
+ for (const entry of fs.readdirSync(frameworksDir, { withFileTypes: true })) {
374
+ if (!entry.isDirectory()) continue;
375
+ const fwBehaviorsDir = path.join(frameworksDir, entry.name, 'behaviors');
376
+ addDirs(listBehaviorDirs(fwBehaviorsDir));
377
+ }
378
+ }
379
+
380
+ return dirs;
381
+ }
382
+
383
+ // ============================================================================
384
+ // File Extension
385
+ // ============================================================================
386
+
387
+ export function getFileExtension(type) {
388
+ return '.md';
389
+ }
390
+
391
+ // ============================================================================
392
+ // Main Deploy Function
393
+ // ============================================================================
394
+
395
+ export async function deploy(opts) {
396
+ const {
397
+ srcRoot,
398
+ mode,
399
+ deployCommands: shouldDeployCommands,
400
+ deploySkills: shouldDeploySkills,
401
+ deployRules: shouldDeployRules,
402
+ commandsOnly,
403
+ skillsOnly,
404
+ rulesOnly,
405
+ dryRun,
406
+ } = opts;
407
+
408
+ const verbose = opts.verbose || false;
409
+
410
+ if (!opts.quiet) {
411
+ console.log(`\n=== OpenClaw Provider ===`);
412
+ console.log(`Deploy target: ${openclawHome}`);
413
+ console.log(`Mode: ${mode}`);
414
+ console.log(`Architecture: OpenClaw -> MCP -> AIWG`);
415
+ console.log('');
416
+ }
417
+
418
+ const normalizedMode = normalizeDeploymentMode(mode);
419
+
420
+ // ── Collect source artifacts ──────────────────────────────────────────────
421
+ const agentFiles = [];
422
+ const commandFiles = [];
423
+ const skillDirs = [];
424
+ const ruleFiles = [];
425
+
426
+ // Addon artifacts
427
+ if (normalizedMode === 'general' || normalizedMode === 'sdlc' || normalizedMode === 'both' || normalizedMode === 'all') {
428
+ agentFiles.push(...getAddonAgentFiles(srcRoot));
429
+ if (shouldDeployCommands || commandsOnly) commandFiles.push(...getAddonCommandFiles(srcRoot));
430
+ if (shouldDeploySkills || skillsOnly) skillDirs.push(...getAddonSkillDirs(srcRoot));
431
+ if (shouldDeployRules || rulesOnly) ruleFiles.push(...getAddonRuleFiles(srcRoot));
432
+ }
433
+
434
+ // Framework artifacts
435
+ const frameworkArtifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
436
+ includeAgents: true,
437
+ includeCommands: shouldDeployCommands || commandsOnly,
438
+ includeSkills: shouldDeploySkills || skillsOnly,
439
+ includeRules: shouldDeployRules || rulesOnly,
440
+ recursiveCommands: true,
441
+ consolidatedSdlcRules: true,
442
+ });
443
+ agentFiles.push(...frameworkArtifacts.agents);
444
+ commandFiles.push(...frameworkArtifacts.commands);
445
+ skillDirs.push(...frameworkArtifacts.skills);
446
+ ruleFiles.push(...frameworkArtifacts.rules);
447
+
448
+ // Behaviors (OpenClaw-specific — first provider to support this)
449
+ const behaviorDirs = collectBehaviorDirs(srcRoot, normalizedMode);
450
+
451
+ // ── Deploy ────────────────────────────────────────────────────────────────
452
+ const counts = { agents: 0, commands: 0, skills: 0, rules: 0, behaviors: 0 };
453
+
454
+ // Agents
455
+ if (!commandsOnly && !skillsOnly && !rulesOnly) {
456
+ const filteredAgents = filterAgentFiles(agentFiles, opts);
457
+ if (verbose) console.log(`\nDeploying ${filteredAgents.length} agents to ${paths.agents}...`);
458
+ deployAgents(filteredAgents, opts);
459
+ counts.agents = filteredAgents.length;
460
+ }
461
+
462
+ // Commands (filter collisions with skills)
463
+ const filteredCommands = (shouldDeploySkills || skillsOnly)
464
+ ? filterCommandsAgainstSkills(commandFiles, skillDirs)
465
+ : commandFiles;
466
+
467
+ if (shouldDeployCommands || commandsOnly) {
468
+ if (verbose) console.log(`\nDeploying ${filteredCommands.length} commands to ${paths.commands}...`);
469
+ deployCommands(filteredCommands, opts);
470
+ counts.commands = filteredCommands.length;
471
+ }
472
+
473
+ // Skills
474
+ if (shouldDeploySkills || skillsOnly) {
475
+ if (verbose) console.log(`\nDeploying ${skillDirs.length} skills to ${paths.skills}/aiwg/ (PUW-025 namespaced)...`);
476
+ deploySkills(skillDirs, opts);
477
+ counts.skills = skillDirs.length;
478
+
479
+ // Holistic post-deploy cleanup of stale AIWG-managed kernel
480
+ // skills (renamed/removed sources). Runs once per deploy with the
481
+ // global desired-kernel set so it survives multi-call orchestration
482
+ // (`aiwg use` invokes deploy-agents.mjs once per framework + addon
483
+ // batch).
484
+ {
485
+ const _kernelDestDir = path.isAbsolute(kernelSkillsPath)
486
+ ? kernelSkillsPath
487
+ : path.join(target, kernelSkillsPath);
488
+ pruneStaleAiwgSkills(_kernelDestDir, computeAllKernelNames(srcRoot), opts);
489
+ }
490
+ }
491
+
492
+ // Rules
493
+ if (shouldDeployRules || rulesOnly) {
494
+ const assembled = assembleRulesIndex(srcRoot);
495
+ if (assembled) {
496
+ const { tmpdir } = await import('os');
497
+ const tmpDir = fs.mkdtempSync(path.join(tmpdir(), 'aiwg-rules-assembly-'));
498
+ const assembledPath = path.join(tmpDir, 'RULES-INDEX.md');
499
+ fs.writeFileSync(assembledPath, assembled);
500
+
501
+ const finalRuleFiles = [
502
+ assembledPath,
503
+ ...ruleFiles.filter(f => path.basename(f) !== 'RULES-INDEX.md'),
504
+ ];
505
+
506
+ if (verbose) console.log(`\nDeploying assembled RULES-INDEX.md + ${finalRuleFiles.length - 1} additional rule files...`);
507
+ deployRules(finalRuleFiles, opts);
508
+ counts.rules = finalRuleFiles.length;
509
+
510
+ try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch { /* ignore */ }
511
+ } else {
512
+ if (verbose) console.log(`\nDeploying ${ruleFiles.length} rules to ${paths.rules}...`);
513
+ deployRules(ruleFiles, opts);
514
+ counts.rules = ruleFiles.length;
515
+ }
516
+
517
+ // On-demand index (#1675): list the MEDIUM/LOW rules tier-gated out of the
518
+ // always-on set so agents can fetch them via `aiwg show rule`. OpenClaw's
519
+ // rule dir is the (absolute) home path, so no target join.
520
+ const onDemandCount = writeOnDemandRuleIndex(paths.rules, listOnDemandRuleFiles(srcRoot), opts);
521
+ if (verbose && onDemandCount > 0) {
522
+ console.log(` On-demand rules (not inlined): ${onDemandCount} → RULES-ONDEMAND.md`);
523
+ }
524
+ }
525
+
526
+ // Behaviors (always deploy if available — OpenClaw is the first native behaviors platform)
527
+ if (!commandsOnly && !skillsOnly && !rulesOnly && behaviorDirs.length > 0) {
528
+ if (verbose) console.log(`\nDeploying ${behaviorDirs.length} behaviors to ${paths.behaviors}...`);
529
+ counts.behaviors = deployBehaviors(behaviorDirs, opts);
530
+ }
531
+
532
+ // ── Context bridge (#1562) ──────────────────────────────────────────────
533
+ // Inject the AIWG Discover-First bridge into OpenClaw's session-loaded
534
+ // workspace AGENTS.md. OpenClaw loads <workspace>/AGENTS.md into every
535
+ // session's system prompt; without this, the deployed agents/skills/rules
536
+ // sit inert on disk (no discover-first, no rule routing — the agent treats
537
+ // `address-issues` as a generic query). Preserves operator content outside
538
+ // the AIWG-managed section.
539
+ // Run once, only from the batch whose srcRoot actually contains the framework
540
+ // template (the repo/framework root). `aiwg use` invokes deploy() once per
541
+ // framework AND per addon with different srcRoots; addon batches would warn
542
+ // "template not found". The idempotent skip in createAgentsMdFromTemplate also
543
+ // guards against double-injection across batches.
544
+ if (!commandsOnly && !skillsOnly && !rulesOnly) {
545
+ const templatePath = path.join(
546
+ srcRoot, 'agentic', 'code', 'frameworks', 'sdlc-complete', 'templates', 'openclaw', 'AGENTS.md.aiwg-template',
547
+ );
548
+ if (fs.existsSync(templatePath)) {
549
+ const workspace = resolveOpenClawWorkspace();
550
+ ensureDir(workspace, dryRun);
551
+ if (verbose || !opts.quiet) {
552
+ console.log(`\nBridging AIWG context into ${path.join(workspace, 'AGENTS.md')} + SOUL.md (#1562/#1572)...`);
553
+ }
554
+ // AGENTS.md = methodology/rules; SOUL.md = the AIWG Steward identity (the
555
+ // discover-first reflex baked in as *who the agent is*, which a weak model
556
+ // adopts far more reliably than a rules appendix). Both update in place.
557
+ createAgentsMdFromTemplate(workspace, srcRoot, 'openclaw/AGENTS.md.aiwg-template', dryRun);
558
+ createManagedMdFromTemplate(workspace, 'SOUL.md', srcRoot, 'openclaw/SOUL.md.aiwg-template', dryRun, {
559
+ sectionMarker: '<!-- AIWG Steward Identity -->',
560
+ legacyHeading: '## AIWG Steward',
561
+ });
562
+ }
563
+ }
564
+
565
+ // ── Summary ───────────────────────────────────────────────────────────────
566
+ if (verbose) {
567
+ console.log('\n=== OpenClaw deployment complete ===\n');
568
+ } else {
569
+ const parts = [];
570
+ if (counts.agents > 0) parts.push(`${counts.agents} agents`);
571
+ if (counts.commands > 0) parts.push(`${counts.commands} commands`);
572
+ if (counts.skills > 0) parts.push(`${counts.skills} skills`);
573
+ if (counts.rules > 0) parts.push(`${counts.rules} rules`);
574
+ if (counts.behaviors > 0) parts.push(`${counts.behaviors} behaviors`);
575
+ if (parts.length > 0) {
576
+ console.log(` Deployed: ${parts.join(' ')}`);
577
+ }
578
+ }
579
+
580
+ // ── Post-deployment hint ──────────────────────────────────────────────────
581
+ if (!opts.quiet) {
582
+ console.log('');
583
+ console.log('All artifacts deployed to ~/.openclaw/ (user-global).');
584
+ console.log('Next: configure ~/.openclaw/config.yaml to connect AIWG MCP server.');
585
+ console.log('See: docs/openclaw-guide.md');
586
+ }
587
+ }
588
+
589
+ // ============================================================================
590
+ // Plugin Bundle Generation (OpenClaw / ClawHub)
591
+ // ============================================================================
592
+
593
+ /**
594
+ * Generate a `clawhub.json` manifest for the ClawHub registry.
595
+ *
596
+ * ClawHub is OpenClaw's central package registry. AIWG generates the manifest
597
+ * alongside file deployment; publishing to ClawHub is a separate workflow
598
+ * (not yet implemented — publish via ClawHub CLI manually for now).
599
+ *
600
+ * @param {string} targetDir - Where to write clawhub.json
601
+ * @param {{ dryRun?: boolean, srcRoot?: string, name?: string, version?: string, description?: string, tags?: string[] }} opts
602
+ */
603
+ export function generatePluginBundle(targetDir, opts = {}) {
604
+ const {
605
+ dryRun = false,
606
+ srcRoot = process.cwd(),
607
+ name: pluginName = 'aiwg-plugin',
608
+ version: overrideVersion,
609
+ description = 'AIWG plugin for OpenClaw',
610
+ tags = ['aiwg', 'multi-agent'],
611
+ } = opts;
612
+
613
+ // Resolve version
614
+ let version = overrideVersion;
615
+ if (!version) {
616
+ try {
617
+ const pkgPath = path.join(srcRoot, 'package.json');
618
+ if (fs.existsSync(pkgPath)) {
619
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
620
+ version = pkg.version || 'unknown';
621
+ } else {
622
+ version = 'unknown';
623
+ }
624
+ } catch {
625
+ version = 'unknown';
626
+ }
627
+ }
628
+
629
+ const manifest = {
630
+ name: pluginName,
631
+ version,
632
+ description,
633
+ author: 'AIWG Contributors',
634
+ license: 'MIT',
635
+ homepage: 'https://aiwg.io',
636
+ repository: 'https://github.com/jmagly/aiwg',
637
+ tags,
638
+ contents: {
639
+ agents: '~/.openclaw/agents/',
640
+ commands: '~/.openclaw/commands/',
641
+ skills: '~/.openclaw/skills/',
642
+ rules: '~/.openclaw/rules/',
643
+ behaviors: '~/.openclaw/behaviors/',
644
+ },
645
+ };
646
+
647
+ const manifestPath = path.join(targetDir, 'clawhub.json');
648
+
649
+ if (dryRun) {
650
+ console.log(`[dry-run] Would create ${manifestPath}`);
651
+ return { manifestPath, manifest };
652
+ }
653
+
654
+ if (!fs.existsSync(targetDir)) {
655
+ fs.mkdirSync(targetDir, { recursive: true });
656
+ }
657
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
658
+
659
+ console.log(`Generated OpenClaw ClawHub manifest: ${manifestPath}`);
660
+ return { manifestPath, manifest };
661
+ }
662
+
663
+ // ============================================================================
664
+ // Default Export
665
+ // ============================================================================
666
+
667
+ export default {
668
+ name,
669
+ aliases,
670
+ paths,
671
+ kernelSkillsPath,
672
+ support,
673
+ capabilities,
674
+ transformAgent,
675
+ transformCommand,
676
+ mapModel,
677
+ getFileExtension,
678
+ generatePluginBundle,
679
+ deploy,
680
+ };