@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,714 @@
1
+ /**
2
+ * Cursor IDE Provider
3
+ *
4
+ * Deploys agents, commands, skills, and rules for Cursor IDE.
5
+ * Rules use native .cursor/rules/ support with MDC format.
6
+ * Other artifacts use conventional .cursor/ subdirectories.
7
+ *
8
+ * Deployment paths:
9
+ * - Agents: .cursor/agents/
10
+ * - Commands: .cursor/commands/
11
+ * - Skills: .cursor/skills/
12
+ * - Rules: .cursor/rules/
13
+ *
14
+ * Special features:
15
+ * - MDC format (.mdc extension) for rules
16
+ * - Glob pattern attachment for rules
17
+ * - $ARGUMENTS -> [arguments] conversion for rules
18
+ * - Delegates rules deployment to deploy-rules-cursor.mjs
19
+ */
20
+
21
+ import realFs from 'fs';
22
+ import { createRequire } from 'module';
23
+ const _require = createRequire(import.meta.url);
24
+ const staticModelCatalog = _require('../../../agentic/code/providers/model-catalog.v1.json');
25
+ let fs;
26
+ try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
27
+ import path from 'path';
28
+ import { spawn } from 'child_process';
29
+ import {
30
+ ensureDir,
31
+ listMdFiles,
32
+ listMdFilesRecursive,
33
+ listSkillDirs,
34
+ deployFiles,
35
+ deploySkillDir,
36
+ deploySkillsWithKernelRouting,
37
+ isKernelSkill,
38
+ pruneStaleAiwgSkills,
39
+ computeAllKernelNames,
40
+ filterAgentFiles,
41
+ getAddonAgentFiles,
42
+ getAddonCommandFiles,
43
+ getAddonSkillDirs,
44
+ getAddonRuleFiles,
45
+ createAgentsMdFromTemplate,
46
+ initializeFrameworkWorkspace,
47
+ normalizeDeploymentMode,
48
+ collectFrameworkArtifacts,
49
+ listOnDemandRuleFiles,
50
+ writeOnDemandRuleIndex,
51
+ cleanupOldRuleFiles,
52
+ filterCommandsAgainstSkills,
53
+ deploySoulCompanions,
54
+ loadRuntimeModelCatalog
55
+ } from './base.mjs';
56
+ const modelCatalog = loadRuntimeModelCatalog(staticModelCatalog);
57
+
58
+ // ============================================================================
59
+ // Provider Configuration
60
+ // ============================================================================
61
+
62
+ export const name = 'cursor';
63
+ export const aliases = [];
64
+
65
+ export const paths = {
66
+ agents: '.cursor/agents/',
67
+ commands: '.cursor/commands/',
68
+ // Skills sequestered under .cursor/.aiwg/skills/ — index-driven discovery (#1212).
69
+ skills: '.cursor/.aiwg/skills/',
70
+ rules: '.cursor/rules/'
71
+ };
72
+
73
+ // Kernel skills (always-loaded) deploy to the platform-native dir.
74
+ export const kernelSkillsPath = '.cursor/skills/';
75
+
76
+ export const support = {
77
+ agents: 'conventional',
78
+ commands: 'conventional',
79
+ skills: 'conventional',
80
+ rules: 'native'
81
+ };
82
+
83
+ export const capabilities = {
84
+ agents: true,
85
+ commands: true,
86
+ skills: true,
87
+ rules: true, // Rules-focused provider with native support
88
+ aggregatedOutput: false,
89
+ yamlFormat: false
90
+ };
91
+
92
+ // ============================================================================
93
+ // Content Transformation
94
+ // ============================================================================
95
+
96
+ /**
97
+ * Transform agent content for Cursor
98
+ * Cursor uses conventional deployment - minimal transformation needed
99
+ */
100
+ export function transformAgent(srcPath, content, opts) {
101
+ const model = content.match(/^model:\s*(.+)$/m)?.[1]?.trim().replace(/['"]/g, '');
102
+ if (!model) return content;
103
+ const roles = modelCatalog.providers.cursor.roles;
104
+ const mapped = /opus/i.test(model)
105
+ ? roles.reasoning.id
106
+ : /haiku/i.test(model)
107
+ ? roles.efficiency.id
108
+ : roles.coding.id;
109
+ return content.replace(/^model:\s*.+$/m, `model: ${mapped}`);
110
+ }
111
+
112
+ /**
113
+ * Transform command content for Cursor
114
+ * Cursor uses conventional deployment - minimal transformation needed
115
+ */
116
+ export function transformCommand(srcPath, content, opts) {
117
+ return content;
118
+ }
119
+
120
+ /**
121
+ * Transform rule content for Cursor — inject MDC frontmatter with the
122
+ * activation mode mapping per ADR-2 (rule activation mode schema).
123
+ *
124
+ * Reads the source rule's `activation:` field (or defaults to alwaysApply
125
+ * per ADR-2 §2 default-preservation) and emits the corresponding MDC
126
+ * frontmatter fields:
127
+ * - alwaysApply (true): activation === 'alwaysApply' (default)
128
+ * - alwaysApply (false), no globs: activation === 'auto'
129
+ * - globs: activation === 'glob' + globs: '<pattern>'
130
+ * - alwaysApply (false), description: activation === 'manual'
131
+ *
132
+ * Per ADR-2 §5: until the live-Cursor smoke test gate is in CI, all rules
133
+ * deploy with alwaysApply: true regardless of source `activation` value
134
+ * (with a deploy-time warning when the source declared a non-alwaysApply
135
+ * mode). The deploy-time warning is emitted by the deployer, not this
136
+ * transform.
137
+ */
138
+ export function transformRule(srcPath, content, opts) {
139
+ // Detect proper YAML frontmatter — must close within the first 30 lines.
140
+ // Files with `---` horizontal rules deeper in markdown content (like
141
+ // RULES-INDEX.md) can have multiple `---` lines without being frontmatter;
142
+ // the line-budget keeps us from misidentifying horizontal rules as frontmatter
143
+ // delimiters.
144
+ const lines = content.split('\n');
145
+ let fmEnd = -1;
146
+ if (lines[0]?.trim() === '---') {
147
+ for (let i = 1; i < Math.min(lines.length, 30); i++) {
148
+ if (lines[i].trim() === '---') {
149
+ fmEnd = i;
150
+ break;
151
+ }
152
+ // YAML frontmatter is key:value pairs. If we see a markdown heading or
153
+ // bold/italic markers in what would be frontmatter, this is not YAML.
154
+ if (/^(#{1,6}\s|\*\*|^\* )/.test(lines[i])) {
155
+ fmEnd = -1;
156
+ break;
157
+ }
158
+ }
159
+ }
160
+
161
+ if (fmEnd > 0) {
162
+ const existingFm = lines.slice(1, fmEnd).join('\n');
163
+ const body = lines.slice(fmEnd + 1).join('\n');
164
+
165
+ // If the operator already set alwaysApply, leave it alone.
166
+ if (/^\s*alwaysApply\s*:\s*\w+/m.test(existingFm)) {
167
+ return content;
168
+ }
169
+
170
+ // PUW-021 (#1122): if source frontmatter declares `globs:` (or
171
+ // `applyTo:` for Copilot-style rules), emit Cursor MDC `globs:` plus
172
+ // `alwaysApply: false`. The activation mode is implicitly `glob`.
173
+ const globsMatch = /^\s*globs?\s*:\s*(.+)$/m.exec(existingFm);
174
+ const applyToMatch = /^\s*applyTo\s*:\s*(.+)$/m.exec(existingFm);
175
+ if (globsMatch || applyToMatch) {
176
+ const globValue = (globsMatch?.[1] || applyToMatch?.[1] || '').trim().replace(/^['"]|['"]$/g, '');
177
+ let mergedFm = existingFm.trimEnd();
178
+ // Add globs field if absent (operator already set globs would have matched).
179
+ if (!globsMatch) {
180
+ mergedFm += `\nglobs: '${globValue}'`;
181
+ }
182
+ mergedFm += '\nalwaysApply: false';
183
+ return `---\n${mergedFm}\n---\n${body}`;
184
+ }
185
+
186
+ const updatedFm = existingFm.trimEnd() + '\nalwaysApply: true';
187
+ return `---\n${updatedFm}\n---\n${body}`;
188
+ }
189
+
190
+ // No (proper) frontmatter — prepend a minimal MDC block.
191
+ return `---\nalwaysApply: true\n---\n${content}`;
192
+ }
193
+
194
+ // ============================================================================
195
+ // Model Mapping (not applicable for Cursor)
196
+ // ============================================================================
197
+
198
+ export function mapModel(shorthand, modelCfg, modelsConfig) {
199
+ return shorthand;
200
+ }
201
+
202
+ // ============================================================================
203
+ // Deployment Functions
204
+ // ============================================================================
205
+
206
+ /**
207
+ * Deploy agents to .cursor/agents/
208
+ */
209
+ export function deployAgents(agentFiles, targetDir, opts) {
210
+ const destDir = path.join(targetDir, paths.agents);
211
+ ensureDir(destDir, opts.dryRun);
212
+ return deployFiles(agentFiles, destDir, { ...opts, injectPlatform: true }, transformAgent);
213
+ }
214
+
215
+ /**
216
+ * Deploy commands to .cursor/commands/
217
+ */
218
+ export function deployCommands(commandFiles, targetDir, opts) {
219
+ const destDir = path.join(targetDir, paths.commands);
220
+ ensureDir(destDir, opts.dryRun);
221
+ return deployFiles(commandFiles, destDir, opts, transformCommand);
222
+ }
223
+
224
+ /**
225
+ * Deploy skills with kernel-vs-standard routing (#1212/#1216).
226
+ * - kernel skills → .cursor/skills/ (platform-native, always-loaded)
227
+ * - standard → .cursor/.aiwg/skills/ (index-discoverable)
228
+ */
229
+ export function deploySkills(skillDirs, targetDir, opts) {
230
+ const standardDestDir = path.join(targetDir, paths.skills);
231
+ const kernelDestDir = path.join(targetDir, kernelSkillsPath);
232
+ deploySkillsWithKernelRouting(skillDirs, standardDestDir, kernelDestDir, opts);
233
+ }
234
+
235
+ /**
236
+ * Deploy rules via external script (native MDC support)
237
+ * Falls back to inline deployment if script not found
238
+ */
239
+ export async function deployRulesViaScript(targetDir, srcRoot, opts) {
240
+ const scriptPath = path.join(srcRoot, 'tools', 'rules', 'deploy-rules-cursor.mjs');
241
+
242
+ if (!fs.existsSync(scriptPath)) {
243
+ console.warn(`Cursor rules deployment script not found at ${scriptPath}`);
244
+ return false;
245
+ }
246
+
247
+ console.log('Delegating rules deployment to deploy-rules-cursor.mjs...');
248
+
249
+ return new Promise((resolve, reject) => {
250
+ const args = ['--target', targetDir, '--source', srcRoot];
251
+ if (opts.dryRun) args.push('--dry-run');
252
+ if (opts.force) args.push('--force');
253
+ if (opts.mode) args.push('--mode', opts.mode);
254
+
255
+ const child = spawn('node', [scriptPath, ...args], {
256
+ stdio: 'inherit',
257
+ cwd: srcRoot
258
+ });
259
+
260
+ child.on('close', (code) => {
261
+ if (code === 0) resolve(true);
262
+ else reject(new Error(`deploy-rules-cursor.mjs exited with code ${code}`));
263
+ });
264
+
265
+ child.on('error', reject);
266
+ });
267
+ }
268
+
269
+ /**
270
+ * Deploy rules to .cursor/rules/ (inline deployment)
271
+ * Used as fallback when external script is not available
272
+ */
273
+ export function deployRulesInline(ruleFiles, targetDir, opts) {
274
+ const destDir = path.join(targetDir, paths.rules);
275
+ ensureDir(destDir, opts.dryRun);
276
+ // Migrate legacy AIWG `.md` rules → `.mdc`. Cursor's rules engine only loads
277
+ // `.mdc` files, so AIWG-managed `.md` rules from an older deploy are inert and
278
+ // would linger (cleanup matches by stem, keeping them). Remove the marker-
279
+ // bearing `.md` leftovers so the `.mdc` we emit below is the live copy.
280
+ if (!opts.dryRun && fs.existsSync(destDir)) {
281
+ for (const name of fs.readdirSync(destDir)) {
282
+ if (!name.endsWith('.md') || name === 'RULES-INDEX.md') continue;
283
+ const p = path.join(destDir, name);
284
+ try {
285
+ if (fs.readFileSync(p, 'utf8').includes('aiwg:managed')) {
286
+ fs.unlinkSync(p);
287
+ console.log(` migrated legacy rule to .mdc (removed ${name})`);
288
+ }
289
+ } catch { /* ignore unreadable file */ }
290
+ }
291
+ }
292
+ // #1143: skip cleanup when this deploy has 0 rules.
293
+ cleanupOldRuleFiles(destDir, { ...opts, incomingFiles: ruleFiles });
294
+ // transformRule injects native MDC frontmatter (globs → alwaysApply:false when
295
+ // the source declares them; else alwaysApply:true). Emit with the `.mdc`
296
+ // extension Cursor actually loads — getFileExtension('rule') === '.mdc'.
297
+ return deployFiles(ruleFiles, destDir, { ...opts, fileExtension: '.mdc' }, transformRule);
298
+ }
299
+
300
+ /**
301
+ * Deploy rules - tries external script first, falls back to inline
302
+ */
303
+ export async function deployRules(ruleFilesOrTarget, targetDirOrSrcRoot, optsOrUndefined) {
304
+ // Handle both call signatures:
305
+ // 1. deployRules(targetDir, srcRoot, opts) - from old code
306
+ // 2. deployRules(ruleFiles, targetDir, opts) - from new code
307
+
308
+ // Check if first arg is array (new signature) or string (old signature)
309
+ if (Array.isArray(ruleFilesOrTarget)) {
310
+ // New signature: deployRules(ruleFiles, targetDir, opts)
311
+ return deployRulesInline(ruleFilesOrTarget, targetDirOrSrcRoot, optsOrUndefined);
312
+ } else {
313
+ // Old signature: deployRules(targetDir, srcRoot, opts)
314
+ // Try external script first
315
+ try {
316
+ const success = await deployRulesViaScript(ruleFilesOrTarget, targetDirOrSrcRoot, optsOrUndefined);
317
+ if (success) return;
318
+ } catch (err) {
319
+ console.warn('External rules script failed, using inline deployment');
320
+ }
321
+
322
+ // Fallback to inline - need to collect rule files
323
+ console.log('Using inline rules deployment...');
324
+ const ruleFiles = [];
325
+ const srcRoot = targetDirOrSrcRoot;
326
+ const opts = optsOrUndefined;
327
+
328
+ // Use consolidated index if available
329
+ const indexPath = getRulesIndexPath(srcRoot);
330
+ if (indexPath) {
331
+ ruleFiles.push(indexPath);
332
+ } else {
333
+ const sdlcRulesDir = path.join(srcRoot, 'agentic', 'code', 'frameworks', 'sdlc-complete', 'rules');
334
+ if (fs.existsSync(sdlcRulesDir)) {
335
+ ruleFiles.push(...listMdFiles(sdlcRulesDir));
336
+ }
337
+ }
338
+
339
+ deployRulesInline(ruleFiles, ruleFilesOrTarget, opts);
340
+ }
341
+ }
342
+
343
+ // ============================================================================
344
+ // AGENTS.md
345
+ // ============================================================================
346
+
347
+ export function createAgentsMd(target, srcRoot, dryRun) {
348
+ createAgentsMdFromTemplate(target, srcRoot, 'cursor/AGENTS.md.aiwg-template', dryRun);
349
+ }
350
+
351
+ // ============================================================================
352
+ // Cloud agent + worktree configuration (PUW-019 #1120)
353
+ // ============================================================================
354
+
355
+ /**
356
+ * Deploy Cursor cloud-agent + worktree config templates.
357
+ *
358
+ * Per PUW-019: AIWG ships templates at
359
+ * agentic/code/frameworks/sdlc-complete/templates/cursor/environment.json.aiwg-template
360
+ * agentic/code/frameworks/sdlc-complete/templates/cursor/worktrees.json.aiwg-template
361
+ * but they were never wired into the deployer. This emits them at
362
+ * .cursor/environment.json
363
+ * .cursor/worktrees.json
364
+ * only when the operator-provided file is absent (always-deploy invariant
365
+ * §0.6 — we don't overwrite operator-authored config). When the file
366
+ * exists, deploy is skipped with a verbose-only note.
367
+ */
368
+ export function deployCursorConfigTemplates(targetDir, srcRoot, opts) {
369
+ const cursorDir = path.join(targetDir, '.cursor');
370
+ ensureDir(cursorDir, opts?.dryRun);
371
+
372
+ const templates = [
373
+ { src: 'cursor/environment.json.aiwg-template', dest: 'environment.json' },
374
+ { src: 'cursor/worktrees.json.aiwg-template', dest: 'worktrees.json' },
375
+ ];
376
+
377
+ for (const t of templates) {
378
+ const srcPath = path.join(
379
+ srcRoot,
380
+ 'agentic',
381
+ 'code',
382
+ 'frameworks',
383
+ 'sdlc-complete',
384
+ 'templates',
385
+ t.src,
386
+ );
387
+ const destPath = path.join(cursorDir, t.dest);
388
+
389
+ if (!fs.existsSync(srcPath)) {
390
+ if (opts?.verbose) {
391
+ console.log(` cursor template not found, skipping: ${t.src}`);
392
+ }
393
+ continue;
394
+ }
395
+ if (fs.existsSync(destPath)) {
396
+ if (opts?.verbose) {
397
+ console.log(` ${t.dest} exists, preserving operator content`);
398
+ }
399
+ continue;
400
+ }
401
+ if (opts?.dryRun) {
402
+ console.log(`[dry-run] Would deploy cursor template ${t.src} -> .cursor/${t.dest}`);
403
+ continue;
404
+ }
405
+ fs.copyFileSync(srcPath, destPath);
406
+ if (opts?.verbose) {
407
+ console.log(`deployed cursor template: .cursor/${t.dest}`);
408
+ }
409
+ }
410
+ }
411
+
412
+ // ============================================================================
413
+ // Post-Deployment
414
+ // ============================================================================
415
+
416
+ export async function postDeploy(targetDir, opts) {
417
+ initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
418
+
419
+ if (opts.createAgentsMd) {
420
+ createAgentsMd(targetDir, opts.srcRoot, opts.dryRun);
421
+ }
422
+
423
+ // PUW-019 (#1120): wire environment.json + worktrees.json templates.
424
+ try {
425
+ deployCursorConfigTemplates(targetDir, opts.srcRoot, opts);
426
+ } catch (err) {
427
+ console.warn(
428
+ `Warning: cursor template deploy failed: ${err && err.message ? err.message : err}`,
429
+ );
430
+ }
431
+ }
432
+
433
+ // ============================================================================
434
+ // File Extension
435
+ // ============================================================================
436
+
437
+ export function getFileExtension(type) {
438
+ // Rules use .mdc for native Cursor support, everything else uses .md
439
+ if (type === 'rule' || type === 'rules') {
440
+ return '.mdc';
441
+ }
442
+ return '.md';
443
+ }
444
+
445
+ // ============================================================================
446
+ // Main Deploy Function
447
+ // ============================================================================
448
+
449
+ /**
450
+ * Main deployment function for Cursor provider
451
+ * Orchestrates deployment of agents, commands, skills, and rules
452
+ */
453
+ export async function deploy(opts) {
454
+ const {
455
+ srcRoot,
456
+ target,
457
+ mode,
458
+ deployCommands: shouldDeployCommands,
459
+ deploySkills: shouldDeploySkills,
460
+ deployRules: shouldDeployRules,
461
+ commandsOnly,
462
+ skillsOnly,
463
+ rulesOnly,
464
+ dryRun,
465
+ createAgentsMd: shouldCreateAgentsMd
466
+ } = opts;
467
+
468
+ console.log(`\n=== Cursor IDE Provider ===`);
469
+ console.log(`Target: ${target}`);
470
+ console.log(`Mode: ${mode}`);
471
+
472
+ // Collect source files based on mode
473
+ const agentFiles = [];
474
+ const commandFiles = [];
475
+ const skillDirs = [];
476
+ const ruleFiles = [];
477
+
478
+ // Check for addon-style directory structure (direct agents/, commands/, skills/ subdirs)
479
+ // This handles deployment when --source points to an addon directory
480
+ const isAddonSource = fs.existsSync(path.join(srcRoot, 'agents')) ||
481
+ fs.existsSync(path.join(srcRoot, 'commands')) ||
482
+ fs.existsSync(path.join(srcRoot, 'skills'));
483
+
484
+ if (isAddonSource) {
485
+ // Deploy from addon-style directory structure
486
+ const addonAgentsDir = path.join(srcRoot, 'agents');
487
+ if (fs.existsSync(addonAgentsDir)) {
488
+ agentFiles.push(...listMdFiles(addonAgentsDir));
489
+ }
490
+
491
+ if (shouldDeployCommands || commandsOnly) {
492
+ const addonCommandsDir = path.join(srcRoot, 'commands');
493
+ if (fs.existsSync(addonCommandsDir)) {
494
+ commandFiles.push(...listMdFiles(addonCommandsDir));
495
+ }
496
+ }
497
+
498
+ if (shouldDeploySkills || skillsOnly) {
499
+ const addonSkillsDir = path.join(srcRoot, 'skills');
500
+ if (fs.existsSync(addonSkillsDir)) {
501
+ skillDirs.push(...listSkillDirs(addonSkillsDir));
502
+
503
+ // Holistic post-deploy cleanup of stale AIWG-managed kernel
504
+ // skills (renamed/removed sources). Uses the global kernel set
505
+ // (computeAllKernelNames walks all source frameworks/addons),
506
+ // not just this-call's skillDirs, because aiwg use invokes
507
+ // deploy-agents.mjs multiple times.
508
+ {
509
+ const _kernelDestDir = path.isAbsolute(kernelSkillsPath)
510
+ ? kernelSkillsPath
511
+ : path.join(target, kernelSkillsPath);
512
+ pruneStaleAiwgSkills(_kernelDestDir, computeAllKernelNames(srcRoot), opts);
513
+ }
514
+ }
515
+ }
516
+
517
+ if (shouldDeployRules || rulesOnly) {
518
+ const addonRulesDir = path.join(srcRoot, 'rules');
519
+ if (fs.existsSync(addonRulesDir)) {
520
+ ruleFiles.push(...listMdFiles(addonRulesDir));
521
+ }
522
+ }
523
+ }
524
+
525
+ // All addons (dynamically discovered)
526
+ const normalizedMode = normalizeDeploymentMode(mode);
527
+ if (normalizedMode === 'general' || normalizedMode === 'sdlc' || normalizedMode === 'both' || normalizedMode === 'all') {
528
+ agentFiles.push(...getAddonAgentFiles(srcRoot));
529
+
530
+ if (shouldDeployCommands || commandsOnly) {
531
+ commandFiles.push(...getAddonCommandFiles(srcRoot));
532
+ }
533
+
534
+ if (shouldDeploySkills || skillsOnly) {
535
+ skillDirs.push(...getAddonSkillDirs(srcRoot));
536
+ }
537
+
538
+ if (shouldDeployRules || rulesOnly) {
539
+ ruleFiles.push(...getAddonRuleFiles(srcRoot));
540
+ }
541
+ }
542
+
543
+ const frameworkArtifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
544
+ includeAgents: true,
545
+ includeCommands: shouldDeployCommands || commandsOnly,
546
+ includeSkills: shouldDeploySkills || skillsOnly,
547
+ includeRules: shouldDeployRules || rulesOnly,
548
+ recursiveCommands: true,
549
+ consolidatedSdlcRules: true
550
+ });
551
+ agentFiles.push(...frameworkArtifacts.agents);
552
+ const soulFiles = [...(frameworkArtifacts.souls || [])];
553
+ commandFiles.push(...frameworkArtifacts.commands);
554
+ skillDirs.push(...frameworkArtifacts.skills);
555
+ ruleFiles.push(...frameworkArtifacts.rules);
556
+
557
+ // Deploy based on flags
558
+ if (!commandsOnly && !skillsOnly && !rulesOnly) {
559
+ // Apply filters if specified
560
+ const filteredAgents = filterAgentFiles(agentFiles, opts);
561
+ if (opts.filter || opts.filterRole) {
562
+ console.log(`\nFiltered from ${agentFiles.length} to ${filteredAgents.length} agents`);
563
+ }
564
+ console.log(`\nDeploying ${filteredAgents.length} agents...`);
565
+ deployAgents(filteredAgents, target, opts);
566
+
567
+ // Deploy soul companion files alongside agents
568
+ if (soulFiles.length > 0) {
569
+ const destDir = path.join(target, paths.agents);
570
+ console.log(`\nDeploying ${soulFiles.length} soul files...`);
571
+ deploySoulCompanions(soulFiles, destDir, opts);
572
+ }
573
+ }
574
+
575
+ // Filter commands that collide with skills (skills take precedence)
576
+ const filteredCommands = (shouldDeploySkills || skillsOnly)
577
+ ? filterCommandsAgainstSkills(commandFiles, skillDirs)
578
+ : commandFiles;
579
+
580
+ if (shouldDeployCommands || commandsOnly) {
581
+ console.log(`\nDeploying ${filteredCommands.length} commands...`);
582
+ deployCommands(filteredCommands, target, opts);
583
+ }
584
+
585
+ if (shouldDeploySkills || skillsOnly) {
586
+ console.log(`\nDeploying ${skillDirs.length} skills...`);
587
+ deploySkills(skillDirs, target, opts);
588
+ }
589
+
590
+ if (shouldDeployRules || rulesOnly) {
591
+ console.log(`\nDeploying ${ruleFiles.length} rules...`);
592
+ // Use inline deployment (external script relied on commands/ dirs which are now skills)
593
+ deployRulesInline(ruleFiles, target, opts);
594
+
595
+ // On-demand index (#1675): list the MEDIUM/LOW rules tier-gated out of the
596
+ // always-on set so agents can fetch them via `aiwg show rule`.
597
+ const onDemandCount = writeOnDemandRuleIndex(
598
+ path.join(target, paths.rules),
599
+ listOnDemandRuleFiles(srcRoot),
600
+ opts,
601
+ );
602
+ if (onDemandCount > 0) {
603
+ console.log(` On-demand rules (not inlined): ${onDemandCount} → RULES-ONDEMAND.md`);
604
+ }
605
+ }
606
+
607
+ // Post-deployment
608
+ await postDeploy(target, { ...opts, createAgentsMd: shouldCreateAgentsMd });
609
+
610
+ console.log('\n=== Cursor deployment complete ===\n');
611
+ }
612
+
613
+ // ============================================================================
614
+ // Default Export
615
+ // ============================================================================
616
+
617
+ // ============================================================================
618
+ // Plugin Bundle Generation (Cursor)
619
+ // ============================================================================
620
+
621
+ /**
622
+ * Generate a `.cursor-plugin/plugin.json` manifest for distributing AIWG as a
623
+ * Cursor plugin. Cursor's cursor.com/marketplace is centralized and partner-
624
+ * oriented; this manifest enables manual/local installation and future
625
+ * submission if the marketplace opens third-party submissions.
626
+ *
627
+ * Layout produced:
628
+ * <targetDir>/.cursor-plugin/plugin.json — the plugin manifest
629
+ *
630
+ * @param {string} targetDir - Plugin bundle root (typically agentic/code/plugins/<name>/)
631
+ * @param {{ dryRun?: boolean, srcRoot?: string, name?: string, version?: string, description?: string, contents?: object }} opts
632
+ */
633
+ export function generatePluginBundle(targetDir, opts = {}) {
634
+ const {
635
+ dryRun = false,
636
+ srcRoot = process.cwd(),
637
+ name: pluginName = 'aiwg-plugin',
638
+ version: overrideVersion,
639
+ description = 'AIWG plugin for Cursor',
640
+ contents = {
641
+ agents: 'agents/',
642
+ commands: 'commands/',
643
+ skills: 'skills/',
644
+ rules: 'rules/',
645
+ },
646
+ } = opts;
647
+
648
+ // Resolve version: opts.version > package.json > 'unknown'
649
+ let version = overrideVersion;
650
+ if (!version) {
651
+ try {
652
+ const pkgPath = path.join(srcRoot, 'package.json');
653
+ if (fs.existsSync(pkgPath)) {
654
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
655
+ version = pkg.version || 'unknown';
656
+ } else {
657
+ version = 'unknown';
658
+ }
659
+ } catch {
660
+ version = 'unknown';
661
+ }
662
+ }
663
+
664
+ const pluginDir = path.join(targetDir, '.cursor-plugin');
665
+ const manifest = {
666
+ name: pluginName,
667
+ version,
668
+ displayName: pluginName.replace(/^aiwg-/, 'AIWG ').replace(/-/g, ' '),
669
+ description,
670
+ publisher: 'aiwg',
671
+ homepage: 'https://aiwg.io',
672
+ repository: 'https://github.com/jmagly/aiwg',
673
+ license: 'MIT',
674
+ contents,
675
+ };
676
+
677
+ if (dryRun) {
678
+ console.log(`[dry-run] Would create ${pluginDir}/plugin.json`);
679
+ return { pluginDir, manifest };
680
+ }
681
+
682
+ if (!fs.existsSync(pluginDir)) {
683
+ fs.mkdirSync(pluginDir, { recursive: true });
684
+ }
685
+ fs.writeFileSync(
686
+ path.join(pluginDir, 'plugin.json'),
687
+ JSON.stringify(manifest, null, 2) + '\n',
688
+ 'utf-8'
689
+ );
690
+
691
+ console.log(`Generated Cursor plugin manifest: ${pluginDir}/plugin.json`);
692
+ return { pluginDir, manifest };
693
+ }
694
+
695
+ export default {
696
+ name,
697
+ aliases,
698
+ paths,
699
+ kernelSkillsPath,
700
+ support,
701
+ capabilities,
702
+ transformAgent,
703
+ transformCommand,
704
+ mapModel,
705
+ deployAgents,
706
+ deployCommands,
707
+ deploySkills,
708
+ deployRules,
709
+ createAgentsMd,
710
+ postDeploy,
711
+ getFileExtension,
712
+ generatePluginBundle,
713
+ deploy
714
+ };