@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,659 @@
1
+ /**
2
+ * GitHub Copilot Provider
3
+ *
4
+ * Deploys agents in GitHub Copilot .agent.md format (Markdown with YAML frontmatter).
5
+ * Commands deploy as prompt files (.prompt.md) in .github/prompts/.
6
+ * Rules deploy as path-scoped instructions (.instructions.md) in .github/instructions/.
7
+ *
8
+ * Deployment paths:
9
+ * - Agents: .github/agents/ (.agent.md)
10
+ * - Commands: .github/prompts/ (.prompt.md)
11
+ * - Skills: .github/skills/
12
+ * - Rules: .github/instructions/ (.instructions.md)
13
+ *
14
+ * Special features:
15
+ * - .agent.md format with YAML frontmatter + markdown body
16
+ * - .prompt.md format for commands (invocable as /command in Copilot Chat)
17
+ * - .instructions.md format with applyTo globs for path-scoped rules
18
+ * - Tool mapping to Copilot built-in tools
19
+ * - Creates copilot-instructions.md
20
+ */
21
+
22
+ import realFs from 'fs';
23
+ import { createRequire } from 'module';
24
+ const _require = createRequire(import.meta.url);
25
+ const staticModelCatalog = _require('../../../agentic/code/providers/model-catalog.v1.json');
26
+ let fs;
27
+ try { const gfs = _require('graceful-fs'); gfs.gracefulify(realFs); fs = realFs; } catch { fs = realFs; }
28
+ import path from 'path';
29
+ import {
30
+ ensureDir,
31
+ listMdFiles,
32
+ listMdFilesRecursive,
33
+ deployFiles,
34
+ inferAgentCategory,
35
+ toKebabCase,
36
+ initializeFrameworkWorkspace,
37
+ getAddonAgentFiles,
38
+ getAddonCommandFiles,
39
+ getAddonRuleFiles,
40
+ getAddonSkillDirs,
41
+ listSkillDirs,
42
+ deploySkillDir,
43
+ deploySkillsWithKernelRouting,
44
+ isKernelSkill,
45
+ pruneStaleAiwgSkills,
46
+ computeAllKernelNames,
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 = 'copilot';
63
+ export const aliases = [];
64
+
65
+ export const paths = {
66
+ agents: '.github/agents/',
67
+ commands: '.github/prompts/',
68
+ // Skills sequestered under .github/.aiwg/skills/ — index-driven discovery (#1212).
69
+ skills: '.github/.aiwg/skills/',
70
+ rules: '.github/instructions/'
71
+ };
72
+
73
+ // Kernel skills (always-loaded) deploy to the platform-native dir.
74
+ export const kernelSkillsPath = '.github/skills/';
75
+
76
+ export const support = {
77
+ agents: 'native',
78
+ commands: 'native',
79
+ skills: 'conventional',
80
+ rules: 'native'
81
+ };
82
+
83
+ export const capabilities = {
84
+ skills: true,
85
+ rules: true,
86
+ aggregatedOutput: false,
87
+ yamlFormat: false
88
+ };
89
+
90
+ // ============================================================================
91
+ // Model Mapping
92
+ // ============================================================================
93
+
94
+ /**
95
+ * Map model shorthand to GitHub Copilot format.
96
+ * Resolve semantic AIWG roles through the current provider catalog.
97
+ */
98
+ export function mapModel(originalModel, modelCfg, modelsConfig) {
99
+ const copilotModels = {
100
+ 'opus': modelCatalog.providers.copilot.roles.reasoning.id,
101
+ 'sonnet': modelCatalog.providers.copilot.roles.coding.id,
102
+ 'haiku': modelCatalog.providers.copilot.roles.efficiency.id
103
+ };
104
+
105
+ // Handle override models first
106
+ if (modelCfg.reasoningModel || modelCfg.codingModel || modelCfg.efficiencyModel) {
107
+ const clean = (originalModel || 'sonnet').toLowerCase().replace(/['"]/g, '');
108
+ if (/opus/i.test(clean)) return modelCfg.reasoningModel || copilotModels.opus;
109
+ if (/haiku/i.test(clean)) return modelCfg.efficiencyModel || copilotModels.haiku;
110
+ return modelCfg.codingModel || copilotModels.sonnet;
111
+ }
112
+
113
+ const clean = (originalModel || 'sonnet').toLowerCase().replace(/['"]/g, '');
114
+
115
+ for (const [key, value] of Object.entries(copilotModels)) {
116
+ if (clean.includes(key)) return value;
117
+ }
118
+
119
+ return copilotModels.sonnet; // default
120
+ }
121
+
122
+ // ============================================================================
123
+ // Tool Mapping
124
+ // ============================================================================
125
+
126
+ /**
127
+ * Get Copilot tools based on category and original tools.
128
+ * Uses Copilot's built-in tool names (search/codebase, edit, web/fetch, agent, terminal).
129
+ */
130
+ export function getTools(category, toolsString) {
131
+ // Map AIWG tools to GitHub Copilot built-in tools
132
+ const toolMap = {
133
+ 'Read': 'search/codebase',
134
+ 'Write': 'edit',
135
+ 'MultiEdit': 'edit',
136
+ 'Edit': 'edit',
137
+ 'Bash': 'terminal',
138
+ 'WebFetch': 'web/fetch',
139
+ 'Glob': 'search/codebase',
140
+ 'Grep': 'search/codebase',
141
+ 'Task': 'agent',
142
+ 'Agent': 'agent'
143
+ };
144
+
145
+ // Default tools by category
146
+ const categoryDefaults = {
147
+ analysis: ['search/codebase', 'web/fetch'],
148
+ documentation: ['search/codebase', 'edit', 'web/fetch'],
149
+ planning: ['search/codebase', 'web/fetch'],
150
+ implementation: ['search/codebase', 'edit', 'terminal', 'web/fetch', 'agent']
151
+ };
152
+
153
+ // If tools specified, map them
154
+ if (toolsString) {
155
+ let originalTools = [];
156
+ if (toolsString.startsWith('[')) {
157
+ try {
158
+ originalTools = JSON.parse(toolsString);
159
+ } catch (e) {
160
+ originalTools = toolsString.replace(/[\[\]"']/g, '').split(/[,\s]+/).filter(Boolean);
161
+ }
162
+ } else {
163
+ originalTools = toolsString.split(/[,\s]+/).filter(Boolean);
164
+ }
165
+
166
+ const mappedTools = new Set();
167
+ for (const tool of originalTools) {
168
+ const cleanTool = tool.replace(/\(.*\)/, '').trim();
169
+ const mapped = toolMap[cleanTool];
170
+ if (mapped) mappedTools.add(mapped);
171
+ }
172
+
173
+ if (mappedTools.size > 0) {
174
+ return Array.from(mappedTools);
175
+ }
176
+ }
177
+
178
+ // Fall back to category defaults
179
+ return categoryDefaults[category] || categoryDefaults.implementation;
180
+ }
181
+
182
+ // ============================================================================
183
+ // Content Transformation
184
+ // ============================================================================
185
+
186
+ /**
187
+ * Transform AIWG agent to GitHub Copilot .agent.md format.
188
+ * Output: YAML frontmatter with name, description, tools, model + markdown body (system prompt).
189
+ */
190
+ export function transformAgent(srcPath, content, opts) {
191
+ const { modelsConfig = {} } = opts;
192
+
193
+ // Parse existing frontmatter
194
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
195
+ if (!fmMatch) return content;
196
+
197
+ const [, frontmatter, body] = fmMatch;
198
+
199
+ // Extract metadata
200
+ const name = frontmatter.match(/name:\s*(.+)/)?.[1]?.trim();
201
+ const description = frontmatter.match(/description:\s*(.+)/)?.[1]?.trim();
202
+ const modelMatch = frontmatter.match(/model:\s*(.+)/)?.[1]?.trim();
203
+ const toolsMatch = frontmatter.match(/tools:\s*(.+)/)?.[1]?.trim();
204
+ const categoryMatch = frontmatter.match(/category:\s*(.+)/)?.[1]?.trim();
205
+
206
+ // Map model to Copilot format
207
+ const copilotModel = mapModel(modelMatch, opts, modelsConfig);
208
+
209
+ // Determine agent category
210
+ const category = categoryMatch || inferAgentCategory(name, body);
211
+
212
+ // Get Copilot-specific tools
213
+ const copilotTools = getTools(category, toolsMatch);
214
+
215
+ // Build YAML frontmatter
216
+ const fmLines = [
217
+ '---',
218
+ `name: ${name || 'aiwg-agent'}`,
219
+ `description: ${description || 'AIWG SDLC agent'}`
220
+ ];
221
+
222
+ if (copilotTools.length > 0) {
223
+ fmLines.push(`tools: [${copilotTools.map(t => `'${t}'`).join(', ')}]`);
224
+ }
225
+
226
+ fmLines.push(`model: ${copilotModel}`);
227
+ fmLines.push('---');
228
+
229
+ // Body is the system prompt (markdown)
230
+ const cleanBody = body.trim();
231
+ return fmLines.join('\n') + '\n\n' + cleanBody + '\n';
232
+ }
233
+
234
+ /**
235
+ * Transform AIWG command to GitHub Copilot .prompt.md format.
236
+ * Output: YAML frontmatter with name, description, model, tools + markdown body.
237
+ * Users invoke via /command-name in Copilot Chat.
238
+ */
239
+ export function transformCommand(srcPath, content, opts) {
240
+ const { modelsConfig = {} } = opts;
241
+
242
+ // Parse existing frontmatter
243
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
244
+ if (!fmMatch) {
245
+ // No frontmatter, create simple prompt format
246
+ const firstLine = content.split('\n')[0];
247
+ const description = firstLine.replace(/^#\s*/, '').trim() || 'AIWG command';
248
+ const cmdName = toKebabCase(description);
249
+
250
+ return `---\nname: ${cmdName}\ndescription: ${description}\nmodel: gpt-4o\n---\n\n${content.trim()}\n`;
251
+ }
252
+
253
+ const [, frontmatter, body] = fmMatch;
254
+
255
+ // Extract metadata
256
+ const description = frontmatter.match(/description:\s*(.+)/)?.[1]?.trim();
257
+ const argumentHint = frontmatter.match(/argument-hint:\s*(.+)/)?.[1]?.trim()?.replace(/^["']|["']$/g, '');
258
+ const modelMatch = frontmatter.match(/model:\s*(.+)/)?.[1]?.trim();
259
+ const toolsMatch = frontmatter.match(/(?:allowed-tools|tools):\s*(.+)/)?.[1]?.trim();
260
+ const cmdName = toKebabCase(description || 'aiwg-command');
261
+
262
+ // Map model
263
+ const copilotModel = mapModel(modelMatch, opts, modelsConfig);
264
+
265
+ // Map tools from allowed-tools
266
+ const copilotTools = getTools('implementation', toolsMatch);
267
+
268
+ // Build YAML frontmatter
269
+ const fmLines = [
270
+ '---',
271
+ `name: ${cmdName}`,
272
+ `description: ${description || 'AIWG command'}`
273
+ ];
274
+
275
+ if (copilotTools.length > 0) {
276
+ fmLines.push(`tools: [${copilotTools.map(t => `'${t}'`).join(', ')}]`);
277
+ }
278
+
279
+ fmLines.push(`model: ${copilotModel}`);
280
+
281
+ if (argumentHint) {
282
+ fmLines.push(`argument-hint: "${argumentHint}"`);
283
+ }
284
+
285
+ fmLines.push('---');
286
+
287
+ const cleanBody = body.trim();
288
+ return fmLines.join('\n') + '\n\n' + cleanBody + '\n';
289
+ }
290
+
291
+ /**
292
+ * Transform AIWG rule to GitHub Copilot .instructions.md format.
293
+ * Output: YAML frontmatter with name, description, applyTo + rule body.
294
+ */
295
+ export function transformRule(srcPath, content, opts) {
296
+ // Rules may have frontmatter or be plain markdown
297
+ let frontmatter = '';
298
+ let body = content;
299
+
300
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
301
+ if (fmMatch) {
302
+ frontmatter = fmMatch[1];
303
+ body = fmMatch[2];
304
+ }
305
+
306
+ // Extract name from frontmatter or first heading
307
+ let name = frontmatter && frontmatter.match(/name:\s*(.+)/)?.[1]?.trim();
308
+ if (!name) {
309
+ const headingMatch = body.match(/^#\s+(.+)/m);
310
+ name = headingMatch ? headingMatch[1].trim() : path.basename(srcPath, '.md');
311
+ }
312
+
313
+ // Extract description from frontmatter or first bold line
314
+ let description = frontmatter && frontmatter.match(/description:\s*(.+)/)?.[1]?.trim();
315
+ if (!description) {
316
+ const scopeMatch = body.match(/\*\*(?:Scope|Summary)\*\*:\s*(.+)/);
317
+ description = scopeMatch ? scopeMatch[1].trim() : name;
318
+ }
319
+
320
+ // Derive applyTo from rule content or filename
321
+ const applyTo = deriveApplyTo(srcPath, body);
322
+
323
+ // Build instructions format
324
+ const fmLines = [
325
+ '---',
326
+ `name: ${name}`,
327
+ `description: ${description}`
328
+ ];
329
+
330
+ if (applyTo) {
331
+ fmLines.push(`applyTo: '${applyTo}'`);
332
+ }
333
+
334
+ fmLines.push('---');
335
+
336
+ const cleanBody = body.trim();
337
+ return fmLines.join('\n') + '\n\n' + cleanBody + '\n';
338
+ }
339
+
340
+ /**
341
+ * Derive applyTo glob patterns from rule content and filename.
342
+ */
343
+ function deriveApplyTo(srcPath, body) {
344
+ const filename = path.basename(srcPath).toLowerCase();
345
+ const content = body.toLowerCase();
346
+
347
+ // Security rules apply to code files
348
+ if (filename.includes('security') || filename.includes('token') ||
349
+ content.includes('vulnerability') || content.includes('owasp')) {
350
+ return '**/*.{ts,js,mjs,cjs,py,go,java,rs}';
351
+ }
352
+
353
+ // Documentation rules apply to markdown
354
+ if (filename.includes('diagram') || filename.includes('documentation') ||
355
+ filename.includes('doc-') || content.includes('documentation artifact')) {
356
+ return '**/*.md';
357
+ }
358
+
359
+ // Agent/deployment rules apply to agent definitions
360
+ if (filename.includes('agent-deployment') || filename.includes('agent-')) {
361
+ return '**/*.{md,yaml,yml}';
362
+ }
363
+
364
+ // Code style/implementation rules
365
+ if (filename.includes('code') || filename.includes('implementation') ||
366
+ filename.includes('test') || filename.includes('lint')) {
367
+ return '**/*.{ts,js,mjs,cjs}';
368
+ }
369
+
370
+ // Default: apply to all files
371
+ return '**/*';
372
+ }
373
+
374
+ // ============================================================================
375
+ // Deployment Functions
376
+ // ============================================================================
377
+
378
+ /**
379
+ * Deploy agents to .github/agents/ as .agent.md files
380
+ */
381
+ export function deployAgents(agentFiles, targetDir, opts) {
382
+ const destDir = path.join(targetDir, paths.agents);
383
+ ensureDir(destDir, opts.dryRun);
384
+ return deployFiles(agentFiles, destDir, { ...opts, fileExtension: '.agent.md', injectPlatform: true }, transformAgent);
385
+ }
386
+
387
+ /**
388
+ * Deploy commands to .github/prompts/ as .prompt.md files
389
+ */
390
+ export function deployCommands(commandFiles, targetDir, opts) {
391
+ const destDir = path.join(targetDir, paths.commands);
392
+ ensureDir(destDir, opts.dryRun);
393
+ return deployFiles(commandFiles, destDir, { ...opts, fileExtension: '.prompt.md' }, transformCommand);
394
+ }
395
+
396
+ /**
397
+ * Deploy skills with kernel-vs-standard routing (#1212/#1216) plus
398
+ * .agents/skills/ cross-agent compatibility (PUW-012 #1113).
399
+ * - kernel skills → .github/skills/ (platform-native, always-loaded)
400
+ * - standard → .github/.aiwg/skills/ (index-discoverable)
401
+ * - cross-agent compatibility mirror is preserved at .agents/skills/.
402
+ */
403
+ export function deploySkills(skillDirs, targetDir, opts) {
404
+ const standardDestDir = path.join(targetDir, paths.skills);
405
+ const kernelDestDir = path.join(targetDir, kernelSkillsPath);
406
+ deploySkillsWithKernelRouting(skillDirs, standardDestDir, kernelDestDir, opts);
407
+
408
+ // Cross-agent compatibility: .agents/skills/ — honors #1217 no-copy
409
+ // default. Filter to kernel-only unless operator opts in via env var.
410
+ const copyStandardSkills = opts?.copyStandardSkills === true;
411
+ const crossAgentSkills = copyStandardSkills
412
+ ? skillDirs
413
+ : skillDirs.filter(d => isKernelSkill(d));
414
+ if (crossAgentSkills.length > 0) {
415
+ const crossAgentDir = path.join(targetDir, '.agents', 'skills');
416
+ ensureDir(crossAgentDir, opts.dryRun);
417
+ if (!opts.dryRun) {
418
+ console.log(`Deploying cross-agent skills to ${path.relative(process.cwd(), crossAgentDir)}...`);
419
+ } else {
420
+ console.log(`[dry-run] Would deploy cross-agent skills to .agents/skills/`);
421
+ }
422
+ for (const skillDir of crossAgentSkills) {
423
+ deploySkillDir(skillDir, crossAgentDir, opts);
424
+ }
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Deploy rules to .github/instructions/ as .instructions.md files
430
+ */
431
+ export function deployRules(ruleFiles, targetDir, opts) {
432
+ const destDir = path.join(targetDir, paths.rules);
433
+ ensureDir(destDir, opts.dryRun);
434
+ cleanupOldRuleFiles(destDir, opts);
435
+ return deployFiles(ruleFiles, destDir, { ...opts, fileExtension: '.instructions.md' }, transformRule);
436
+ }
437
+
438
+ // ============================================================================
439
+ // copilot-instructions.md
440
+ // ============================================================================
441
+
442
+ /**
443
+ * Create copilot-instructions.md from template
444
+ */
445
+ export function createCopilotInstructions(target, srcRoot, dryRun) {
446
+ const templatePath = path.join(srcRoot, 'agentic', 'code', 'frameworks', 'sdlc-complete', 'templates', 'copilot', 'copilot-instructions.md.aiwg-template');
447
+ const githubDir = path.join(target, '.github');
448
+ const destPath = path.join(githubDir, 'copilot-instructions.md');
449
+
450
+ if (!fs.existsSync(templatePath)) {
451
+ console.warn(`Copilot instructions template not found at ${templatePath}`);
452
+ return;
453
+ }
454
+
455
+ const template = fs.readFileSync(templatePath, 'utf8');
456
+
457
+ // Ensure .github directory exists
458
+ if (!dryRun && !fs.existsSync(githubDir)) {
459
+ fs.mkdirSync(githubDir, { recursive: true });
460
+ }
461
+
462
+ if (fs.existsSync(destPath)) {
463
+ const existing = fs.readFileSync(destPath, 'utf8');
464
+
465
+ if (existing.includes('<!-- AIWG SDLC Framework Integration -->') ||
466
+ existing.includes('## AIWG SDLC Framework')) {
467
+ console.log('copilot-instructions.md already contains AIWG section, skipping');
468
+ return;
469
+ }
470
+
471
+ const markerIndex = template.indexOf('<!-- AIWG SDLC Framework Integration -->');
472
+ const aiwgSection = markerIndex !== -1 ? template.slice(markerIndex) : template;
473
+ const combined = existing.trimEnd() + '\n\n---\n\n' + aiwgSection.trim() + '\n';
474
+
475
+ if (dryRun) {
476
+ console.log(`[dry-run] Would update existing copilot-instructions.md with AIWG section`);
477
+ } else {
478
+ fs.writeFileSync(destPath, combined, 'utf8');
479
+ console.log('Updated copilot-instructions.md with AIWG SDLC framework section');
480
+ }
481
+ } else {
482
+ if (dryRun) {
483
+ console.log(`[dry-run] Would create copilot-instructions.md from template`);
484
+ } else {
485
+ fs.writeFileSync(destPath, template, 'utf8');
486
+ console.log('Created copilot-instructions.md from template');
487
+ }
488
+ }
489
+ }
490
+
491
+ // ============================================================================
492
+ // Post-Deployment
493
+ // ============================================================================
494
+
495
+ export async function postDeploy(targetDir, opts) {
496
+ initializeFrameworkWorkspace(targetDir, opts.mode, opts.dryRun, opts.srcRoot);
497
+
498
+ // Create copilot-instructions.md
499
+ createCopilotInstructions(targetDir, opts.srcRoot, opts.dryRun);
500
+ }
501
+
502
+ // ============================================================================
503
+ // File Extension
504
+ // ============================================================================
505
+
506
+ export function getFileExtension(type) {
507
+ switch (type) {
508
+ case 'agent': return '.agent.md';
509
+ case 'command': return '.prompt.md';
510
+ case 'rule': return '.instructions.md';
511
+ default: return '.md';
512
+ }
513
+ }
514
+
515
+ // ============================================================================
516
+ // Main Deploy Function
517
+ // ============================================================================
518
+
519
+ export async function deploy(opts) {
520
+ const {
521
+ srcRoot,
522
+ target,
523
+ mode,
524
+ deployCommands: shouldDeployCommands,
525
+ deploySkills: shouldDeploySkills,
526
+ deployRules: shouldDeployRules,
527
+ commandsOnly,
528
+ skillsOnly,
529
+ rulesOnly,
530
+ dryRun
531
+ } = opts;
532
+
533
+ console.log(`\n=== GitHub Copilot Provider ===`);
534
+ console.log(`Target: ${target}`);
535
+ console.log(`Mode: ${mode}`);
536
+
537
+ const agentFiles = [];
538
+ const commandFiles = [];
539
+ const skillDirs = [];
540
+ const ruleFiles = [];
541
+ const normalizedMode = normalizeDeploymentMode(mode);
542
+
543
+ // All addons (dynamically discovered)
544
+ if (normalizedMode === 'general' || normalizedMode === 'sdlc' || normalizedMode === 'both' || normalizedMode === 'all') {
545
+ agentFiles.push(...getAddonAgentFiles(srcRoot));
546
+
547
+ if (shouldDeployCommands || commandsOnly) {
548
+ commandFiles.push(...getAddonCommandFiles(srcRoot));
549
+ }
550
+
551
+ if (shouldDeploySkills || skillsOnly) {
552
+ skillDirs.push(...getAddonSkillDirs(srcRoot));
553
+
554
+ // Holistic post-deploy cleanup of stale AIWG-managed kernel
555
+ // skills (renamed/removed sources). Uses the global kernel set
556
+ // (computeAllKernelNames walks all source frameworks/addons),
557
+ // not just this-call's skillDirs, because aiwg use invokes
558
+ // deploy-agents.mjs multiple times.
559
+ {
560
+ const _kernelDestDir = path.isAbsolute(kernelSkillsPath)
561
+ ? kernelSkillsPath
562
+ : path.join(target, kernelSkillsPath);
563
+ pruneStaleAiwgSkills(_kernelDestDir, computeAllKernelNames(srcRoot), opts);
564
+ }
565
+ }
566
+
567
+ if (shouldDeployRules || rulesOnly) {
568
+ ruleFiles.push(...getAddonRuleFiles(srcRoot));
569
+ }
570
+ }
571
+
572
+ const frameworkArtifacts = collectFrameworkArtifacts(srcRoot, normalizedMode, {
573
+ includeAgents: true,
574
+ includeCommands: shouldDeployCommands || commandsOnly,
575
+ includeSkills: shouldDeploySkills || skillsOnly,
576
+ includeRules: shouldDeployRules || rulesOnly,
577
+ recursiveCommands: true,
578
+ consolidatedSdlcRules: true
579
+ });
580
+ agentFiles.push(...frameworkArtifacts.agents);
581
+ const soulFiles = [...(frameworkArtifacts.souls || [])];
582
+ commandFiles.push(...frameworkArtifacts.commands);
583
+ skillDirs.push(...frameworkArtifacts.skills);
584
+ ruleFiles.push(...frameworkArtifacts.rules);
585
+
586
+ // Deploy
587
+ if (!commandsOnly && !skillsOnly && !rulesOnly) {
588
+ console.log(`\nDeploying ${agentFiles.length} agents (.agent.md format)...`);
589
+ deployAgents(agentFiles, target, opts);
590
+
591
+ // Deploy soul companion files alongside agents
592
+ if (soulFiles.length > 0) {
593
+ const destDir = path.join(target, paths.agents);
594
+ console.log(`\nDeploying ${soulFiles.length} soul files...`);
595
+ deploySoulCompanions(soulFiles, destDir, opts);
596
+ }
597
+ }
598
+
599
+ // Filter commands that collide with skills (skills take precedence)
600
+ const filteredCommands = (shouldDeploySkills || skillsOnly)
601
+ ? filterCommandsAgainstSkills(commandFiles, skillDirs)
602
+ : commandFiles;
603
+
604
+ if (shouldDeployCommands || commandsOnly) {
605
+ console.log(`\nDeploying ${filteredCommands.length} commands (.prompt.md format)...`);
606
+ deployCommands(filteredCommands, target, opts);
607
+ }
608
+
609
+ if (shouldDeploySkills || skillsOnly) {
610
+ console.log(`\nDeploying ${skillDirs.length} skills...`);
611
+ deploySkills(skillDirs, target, opts);
612
+ }
613
+
614
+ if (shouldDeployRules || rulesOnly) {
615
+ console.log(`\nDeploying ${ruleFiles.length} rules...`);
616
+ deployRules(ruleFiles, target, opts);
617
+
618
+ // On-demand index (#1675): list the MEDIUM/LOW rules tier-gated out of the
619
+ // always-on set so agents can fetch them via `aiwg show rule`.
620
+ const onDemandCount = writeOnDemandRuleIndex(
621
+ path.join(target, paths.rules),
622
+ listOnDemandRuleFiles(srcRoot),
623
+ opts,
624
+ );
625
+ if (onDemandCount > 0) {
626
+ console.log(` On-demand rules (not inlined): ${onDemandCount} → RULES-ONDEMAND.md`);
627
+ }
628
+ }
629
+
630
+ await postDeploy(target, opts);
631
+
632
+ console.log('\n=== Copilot deployment complete ===\n');
633
+ }
634
+
635
+ // ============================================================================
636
+ // Default Export
637
+ // ============================================================================
638
+
639
+ export default {
640
+ name,
641
+ aliases,
642
+ paths,
643
+ kernelSkillsPath,
644
+ support,
645
+ capabilities,
646
+ transformAgent,
647
+ transformCommand,
648
+ transformRule,
649
+ mapModel,
650
+ getTools,
651
+ deployAgents,
652
+ deployCommands,
653
+ deploySkills,
654
+ deployRules,
655
+ createCopilotInstructions,
656
+ postDeploy,
657
+ getFileExtension,
658
+ deploy
659
+ };