@aiwg/cli 2026.8.8 → 2026.8.11

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 +23 -8
  2. package/THIRD_PARTY_NOTICES.md +35 -0
  3. package/agentic/code/providers/capability-matrix.yaml +3 -3
  4. package/bin/aiwg.mjs +125 -0
  5. package/dist/src/agents/packaged-agent-inventory.js +37 -1
  6. package/dist/src/artifacts/backends/graphology-backend.js +4 -3
  7. package/dist/src/artifacts/backends/sqlite-backend.js +4 -5
  8. package/dist/src/artifacts/cli.js +2 -2
  9. package/dist/src/artifacts/corpus-tools/cli.js +27 -0
  10. package/dist/src/artifacts/corpus-tools/profile-embed.js +3 -2
  11. package/dist/src/artifacts/corpus-tools/retrieval-lab.js +356 -0
  12. package/dist/src/artifacts/discover-facets.js +2 -2
  13. package/dist/src/artifacts/embedding-index.js +9 -8
  14. package/dist/src/artifacts/fortemi-core-sync.js +23 -8
  15. package/dist/src/artifacts/graph-backend.js +2 -2
  16. package/dist/src/artifacts/query-engine.js +21 -7
  17. package/dist/src/artifacts/repair.js +47 -0
  18. package/dist/src/artifacts/types.js +3 -3
  19. package/dist/src/cli/command-log.js +2 -2
  20. package/dist/src/cli/handlers/artifacts.js +50 -1
  21. package/dist/src/cli/handlers/cost-report.js +71 -0
  22. package/dist/src/cli/handlers/evidence.js +78 -0
  23. package/dist/src/cli/handlers/help.js +9 -0
  24. package/dist/src/cli/handlers/index.js +8 -3
  25. package/dist/src/cli/handlers/local-executor.js +4 -3
  26. package/dist/src/cli/handlers/refresh.js +63 -17
  27. package/dist/src/cli/handlers/regenerate.js +3 -3
  28. package/dist/src/cli/handlers/serve.js +15 -36
  29. package/dist/src/cli/handlers/setup-manifest.js +8 -1
  30. package/dist/src/cli/handlers/use.js +272 -70
  31. package/dist/src/cli/handlers/utilities.js +149 -0
  32. package/dist/src/cli/handlers/workspace.js +10 -0
  33. package/dist/src/cli/help-generator.js +2 -1
  34. package/dist/src/cli/router.js +4 -1
  35. package/dist/src/cli/services/deployment-verification.js +596 -0
  36. package/dist/src/cli/skill-usage.js +2 -2
  37. package/dist/src/cli/workflow-orchestrator.js +1 -1
  38. package/dist/src/cli/workspace-signals.js +2 -2
  39. package/dist/src/config/aiwg-config.js +54 -27
  40. package/dist/src/config/cli.js +3 -3
  41. package/dist/src/config/project-artifacts-health.js +2 -0
  42. package/dist/src/config/project-artifacts-health.mjs +123 -0
  43. package/dist/src/config/project-artifacts-runtime.mjs +16 -0
  44. package/dist/src/config/project-artifacts.js +2 -1
  45. package/dist/src/cost/fleet-report.js +329 -0
  46. package/dist/src/evidence/bundle.js +256 -0
  47. package/dist/src/extensions/commands/definitions.js +77 -25
  48. package/dist/src/extensions/deployment-registration.js +6 -4
  49. package/dist/src/features/catalog.js +26 -0
  50. package/dist/src/features/cli.js +1 -3
  51. package/dist/src/features/runtime.js +17 -1
  52. package/dist/src/issues/cli.js +91 -7
  53. package/dist/src/mcp/server.mjs +1 -1
  54. package/dist/src/ops/registry.js +2 -2
  55. package/dist/src/policy/authorization.js +2 -2
  56. package/dist/src/providers/capability-matrix.yaml +3 -3
  57. package/dist/src/providers/provider-definitions.js +7 -5
  58. package/dist/src/providers/provider-definitions.mjs +1 -1
  59. package/dist/src/serve/pty-bridge.js +2 -8
  60. package/dist/src/serve/screen-reader.js +3 -6
  61. package/dist/src/smiths/context-pipeline/aiwg-md.js +2 -2
  62. package/dist/src/smiths/context-pipeline/finalization.js +18 -5
  63. package/dist/src/smiths/context-pipeline/generator.js +2 -2
  64. package/dist/src/smiths/context-pipeline/workspace-context.js +16 -17
  65. package/package.json +2 -1
  66. package/tools/agents/deploy-agents.mjs +10 -11
  67. package/tools/agents/providers/base.mjs +61 -7
  68. package/tools/agents/providers/openclaw.mjs +5 -2
  69. package/tools/agents/providers/windsurf.mjs +13 -24
  70. package/tools/skills/deploy-skills-codex.mjs +21 -5
@@ -44,6 +44,48 @@ export function ensureDir(d, dryRun = false) {
44
44
  if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true });
45
45
  }
46
46
 
47
+ const PROJECT_ARTIFACT_ENV_KEYS = [
48
+ 'AIWG_ARTIFACTS_PATH',
49
+ 'AIWG_PROJECT_ARTIFACTS_PATH',
50
+ 'AIWG_PROJECT_AIWG_DIR',
51
+ ];
52
+
53
+ function expandProjectArtifactPath(value, projectDir) {
54
+ const trimmed = value.trim();
55
+ if (trimmed === '~') return os.homedir();
56
+ if (trimmed.startsWith('~/')) return path.resolve(os.homedir(), trimmed.slice(2));
57
+ return path.isAbsolute(trimmed) ? trimmed : path.resolve(projectDir, trimmed);
58
+ }
59
+
60
+ function parseProjectArtifactLocation(contents) {
61
+ for (const rawLine of contents.split(/\r?\n/)) {
62
+ let line = rawLine.trim();
63
+ if (!line || line.startsWith('#')) continue;
64
+ if (line.startsWith('export ')) line = line.slice('export '.length).trim();
65
+ const assignment = line.match(/^AIWG_ARTIFACTS_PATH\s*=\s*(.+)$/);
66
+ if (assignment) line = assignment[1].trim();
67
+ if ((line.startsWith('"') && line.endsWith('"')) || (line.startsWith("'") && line.endsWith("'"))) {
68
+ line = line.slice(1, -1);
69
+ }
70
+ return line || null;
71
+ }
72
+ return null;
73
+ }
74
+
75
+ /** Resolve the artifact corpus root used for framework-generated workspace data. */
76
+ export function resolveFrameworkWorkspaceRoot(projectDir, env = process.env) {
77
+ for (const key of PROJECT_ARTIFACT_ENV_KEYS) {
78
+ const value = env[key];
79
+ if (typeof value === 'string' && value.trim()) return expandProjectArtifactPath(value, projectDir);
80
+ }
81
+ const pointer = path.join(projectDir, '.aiwg-location');
82
+ if (fs.existsSync(pointer)) {
83
+ const configured = parseProjectArtifactLocation(fs.readFileSync(pointer, 'utf8'));
84
+ if (configured) return expandProjectArtifactPath(configured, projectDir);
85
+ }
86
+ return path.join(projectDir, '.aiwg');
87
+ }
88
+
47
89
  /**
48
90
  * List markdown files in a directory (non-recursive)
49
91
  */
@@ -138,8 +180,11 @@ const MANIFEST_FILENAME = '.aiwg-manifest.json';
138
180
  *
139
181
  * Idempotent — skips if either form of the marker is already present.
140
182
  */
141
- export function addManagedMarker(content, version, source) {
183
+ export function addManagedMarker(content, version, source, style = 'markdown') {
142
184
  if (MANAGED_MARKER_RE.test(content)) return content;
185
+ if (style === 'line-comment') {
186
+ return `# aiwg:managed v${version} ${source}\n${content}`;
187
+ }
143
188
  // Frontmatter present → inject as YAML comment after the opening `---\n`.
144
189
  if (content.startsWith('---\n')) {
145
190
  return content.replace(
@@ -638,9 +683,18 @@ export function deployFiles(files, destDir, opts, transformFn) {
638
683
  transformedContent = injectPlatformInContent(transformedContent, platformName);
639
684
  }
640
685
 
641
- // Add managed marker for .md / .mdc files (#749; .mdc for Cursor native rules)
686
+ // Add managed marker for provider artifacts (#749). TOML accepts `#`
687
+ // comments, which lets doctor attribute transformed Codex agents even
688
+ // though their YAML frontmatter is removed during serialization.
642
689
  if (base.endsWith('.md') || base.endsWith('.mdc')) {
643
690
  transformedContent = addManagedMarker(transformedContent, deployVersion, deploySource);
691
+ } else if (base.endsWith('.toml')) {
692
+ transformedContent = addManagedMarker(
693
+ transformedContent,
694
+ deployVersion,
695
+ deploySource,
696
+ 'line-comment',
697
+ );
644
698
  }
645
699
 
646
700
  // Compute content hash for sidecar comparison
@@ -1441,7 +1495,7 @@ export function deploySkillDir(skillDir, destDir, opts) {
1441
1495
  * Creates .aiwg/frameworks/{framework-id}/ directories
1442
1496
  */
1443
1497
  export function initializeFrameworkWorkspace(target, mode, dryRun, srcRoot = null) {
1444
- const aiwgBase = path.join(target, '.aiwg');
1498
+ const aiwgBase = resolveFrameworkWorkspaceRoot(target);
1445
1499
  const frameworksDir = path.join(aiwgBase, 'frameworks');
1446
1500
  const sharedDir = path.join(aiwgBase, 'shared');
1447
1501
 
@@ -1498,7 +1552,7 @@ export function initializeFrameworkWorkspace(target, mode, dryRun, srcRoot = nul
1498
1552
  }
1499
1553
  for (const entry of fw.memoryCreates || []) {
1500
1554
  if (entry && typeof entry.path === 'string') {
1501
- console.log(`[dry-run] ${path.join(target, entry.path)}${entry.path.endsWith('/') ? '/' : ''}`);
1555
+ console.log(`[dry-run] ${path.join(aiwgBase, entry.path.slice('.aiwg/'.length))}${entry.path.endsWith('/') ? '/' : ''}`);
1502
1556
  }
1503
1557
  }
1504
1558
  }
@@ -1515,7 +1569,7 @@ export function initializeFrameworkWorkspace(target, mode, dryRun, srcRoot = nul
1515
1569
  for (const subdir of fw.subdirs) {
1516
1570
  ensureDir(path.join(fwBase, subdir));
1517
1571
  }
1518
- initializeMemoryCreates(target, fw.path, fw.memoryCreates);
1572
+ initializeMemoryCreates(aiwgBase, fw.path, fw.memoryCreates);
1519
1573
  }
1520
1574
 
1521
1575
  // Initialize registry.json if it doesn't exist
@@ -1536,12 +1590,12 @@ export function initializeFrameworkWorkspace(target, mode, dryRun, srcRoot = nul
1536
1590
  }
1537
1591
 
1538
1592
 
1539
- function initializeMemoryCreates(target, frameworkPath, creates) {
1593
+ function initializeMemoryCreates(aiwgBase, frameworkPath, creates) {
1540
1594
  for (const entry of creates || []) {
1541
1595
  if (!entry || typeof entry.path !== 'string') continue;
1542
1596
  if (!entry.path.startsWith('.aiwg/')) continue;
1543
1597
 
1544
- const targetPath = path.join(target, entry.path);
1598
+ const targetPath = path.join(aiwgBase, entry.path.slice('.aiwg/'.length));
1545
1599
  const isDirectory = entry.path.endsWith('/') || path.extname(entry.path) === '';
1546
1600
  if (isDirectory) {
1547
1601
  ensureDir(targetPath);
@@ -209,10 +209,13 @@ function deploySkills(skillDirs, opts) {
209
209
  ? skillDirs
210
210
  : skillDirs.filter(d => isKernelSkill(d));
211
211
  if (crossAgentSkills.length > 0) {
212
- const crossAgentDir = path.join(process.cwd(), '.agents', 'skills');
212
+ // Honor the deployment target selected by `aiwg use --target`. Provider
213
+ // subprocesses execute from AIWG_ROOT so process.cwd() would otherwise
214
+ // mutate the framework checkout during isolated/project-targeted deploys.
215
+ const crossAgentDir = path.join(opts.target || process.cwd(), '.agents', 'skills');
213
216
  ensureDir(crossAgentDir, opts.dryRun);
214
217
  if (!opts.dryRun) {
215
- console.log(`Deploying cross-agent skills to ${path.relative(process.cwd(), crossAgentDir)}...`);
218
+ console.log(`Deploying cross-agent skills to ${path.relative(opts.target || process.cwd(), crossAgentDir)}...`);
216
219
  } else {
217
220
  console.log(`[dry-run] Would deploy cross-agent skills to .agents/skills/`);
218
221
  }
@@ -1,7 +1,9 @@
1
1
  /**
2
- * Windsurf Provider (EXPERIMENTAL)
2
+ * Devin Desktop Provider (Windsurf compatibility adapter)
3
3
  *
4
- * Deploys agents to Windsurf format with aggregated AGENTS.md and trigger-frontmatter rules.
4
+ * Deploys agents to the Devin Desktop/Windsurf compatibility surface with
5
+ * aggregated AGENTS.md and trigger-frontmatter rules. The provider id and
6
+ * generated `.windsurf/` paths remain stable for backward compatibility.
5
7
  *
6
8
  * Deployment paths:
7
9
  * - Output: AGENTS.md (aggregated agents)
@@ -18,7 +20,7 @@
18
20
  * - Capabilities tags for tools
19
21
  * - Workflow format for commands
20
22
  * - Conventional skills and rules deployment
21
- * - EXPERIMENTAL: Untested, may require adjustments
23
+ * - Devin Desktop selectors resolve to the stable `windsurf` provider id
22
24
  */
23
25
 
24
26
  import realFs from 'fs';
@@ -57,7 +59,7 @@ import {
57
59
  // ============================================================================
58
60
 
59
61
  export const name = 'windsurf';
60
- export const aliases = [];
62
+ export const aliases = ['devin', 'devin-desktop', 'devin-local', 'cascade'];
61
63
 
62
64
  export const paths = {
63
65
  agents: '.windsurf/agents/', // Discrete mirrors alongside AGENTS.md
@@ -85,17 +87,6 @@ export const capabilities = {
85
87
  yamlFormat: false
86
88
  };
87
89
 
88
- // ============================================================================
89
- // Warning Display
90
- // ============================================================================
91
-
92
- function displayWarning() {
93
- console.log('\n' + '='.repeat(70));
94
- console.log('[EXPERIMENTAL] Windsurf provider support is experimental and untested.');
95
- console.log('Please report issues: https://github.com/jmagly/aiwg/issues');
96
- console.log('='.repeat(70) + '\n');
97
- }
98
-
99
90
  // ============================================================================
100
91
  // Content Transformation
101
92
  // ============================================================================
@@ -253,12 +244,12 @@ export function generateAgentsMd(files, destPath, opts) {
253
244
  // refuses to replace the legacy 2MB+ aggregate writer's output.
254
245
  lines.push('<!-- aiwg-managed -->');
255
246
  lines.push('');
256
- lines.push('> AIWG Agent Directory for Windsurf');
247
+ lines.push('> AIWG Agent Directory for Devin Desktop');
257
248
  lines.push('');
258
249
  lines.push('<!--');
259
- lines.push(' [EXPERIMENTAL] Generated by AIWG for Windsurf');
260
- lines.push(' Windsurf reads this file for directory-scoped AI instructions.');
261
- lines.push(' See: https://docs.windsurf.com/windsurf/cascade/agents-md');
250
+ lines.push(' Generated by AIWG for Devin Desktop using the Windsurf compatibility adapter.');
251
+ lines.push(' Devin Desktop reads this file for directory-scoped AI instructions.');
252
+ lines.push(' See: https://docs.devin.ai/onboard-devin/agents-md');
262
253
  lines.push('-->');
263
254
  lines.push('');
264
255
  lines.push('## Table of Contents');
@@ -316,10 +307,10 @@ export function generateWindsurfRules(srcRoot, target, opts) {
316
307
  lines.push('trigger: always_on');
317
308
  lines.push('---');
318
309
  lines.push('');
319
- lines.push('# AIWG Orchestration for Windsurf');
310
+ lines.push('# AIWG Orchestration for Devin Desktop');
320
311
  lines.push('');
321
312
  lines.push('<!--');
322
- lines.push(' [EXPERIMENTAL] Generated by AIWG for Windsurf');
313
+ lines.push(' Generated by AIWG for Devin Desktop using the Windsurf compatibility adapter.');
323
314
  lines.push(' This file provides orchestration context for AIWG SDLC workflows.');
324
315
  lines.push(' trigger: always_on — included in system prompt on every message.');
325
316
  lines.push('-->');
@@ -556,9 +547,7 @@ export async function deploy(opts) {
556
547
  dryRun
557
548
  } = opts;
558
549
 
559
- displayWarning();
560
-
561
- console.log(`\n=== Windsurf Provider (EXPERIMENTAL) ===`);
550
+ console.log(`\n=== Devin Desktop Provider (windsurf compatibility adapter) ===`);
562
551
  console.log(`Target: ${target}`);
563
552
  console.log(`Mode: ${mode}`);
564
553
  const normalizedMode = normalizeDeploymentMode(mode);
@@ -417,6 +417,17 @@ function isFullAiwgSourceRoot(srcRoot) {
417
417
  const repoRoot = path.resolve(scriptDir, '..', '..');
418
418
  const srcRoot = source || repoRoot;
419
419
  const fullAiwgSourceRoot = isFullAiwgSourceRoot(srcRoot);
420
+ const copyStandardSkills = cfg.copyStandardSkills === true;
421
+ // Component-scoped deploys (the way `aiwg use all` installs selected
422
+ // frameworks/addons) still need a complete inventory for stale-skill
423
+ // reconciliation. AIWG_ROOT is supplied by the orchestrator for exactly
424
+ // this purpose; fall back to the script checkout for standalone use.
425
+ const configuredAiwgRoot = process.env.AIWG_ROOT
426
+ ? path.resolve(process.env.AIWG_ROOT)
427
+ : repoRoot;
428
+ const inventoryRoot = fullAiwgSourceRoot
429
+ ? srcRoot
430
+ : (!copyStandardSkills && isFullAiwgSourceRoot(configuredAiwgRoot) ? configuredAiwgRoot : null);
420
431
 
421
432
  console.log(`Deploying skills to Codex`);
422
433
  console.log(` Source: ${srcRoot}`);
@@ -440,8 +451,6 @@ function isFullAiwgSourceRoot(srcRoot) {
440
451
  // Codex normally deploys to the project `.agents/skills/` target, so the
441
452
  // kernel/standard split is enforced at filter time rather than via separate
442
453
  // destination directories. The standalone legacy default remains supported.
443
- const copyStandardSkills = cfg.copyStandardSkills === true;
444
-
445
454
  // Track every AIWG-managed source skill name so we can scope post-deploy
446
455
  // cleanup to skills AIWG ships — never delete user-authored or
447
456
  // third-party skills sitting alongside.
@@ -457,10 +466,13 @@ function isFullAiwgSourceRoot(srcRoot) {
457
466
  // so full-root cleanup can remove stale AIWG skills. Component-scoped
458
467
  // cleanup is limited below to names owned by that component, preserving
459
468
  // user-authored skills alongside the generated set.
460
- for (const { dir } of getSkillDirectories(srcRoot, 'all')) {
469
+ for (const { dir } of getSkillDirectories(inventoryRoot || srcRoot, 'all')) {
461
470
  const allSkills = findSkillDirs(dir);
462
471
  for (const s of allSkills) {
463
472
  allManagedNames.add(path.basename(s));
473
+ if (!copyStandardSkills && isKernelSkill(s)) {
474
+ desiredNames.add(path.basename(s));
475
+ }
464
476
  // Also record the frontmatter `name:` since Codex uses that as the
465
477
  // target dir. Best-effort — ignore parse errors.
466
478
  try {
@@ -469,7 +481,11 @@ function isFullAiwgSourceRoot(srcRoot) {
469
481
  if (fmMatch) {
470
482
  const nameMatch = fmMatch[1].match(/^\s*name:\s*(.+?)\s*$/m);
471
483
  if (nameMatch) {
472
- allManagedNames.add(stripWrappingQuotes(nameMatch[1]));
484
+ const deployedName = stripWrappingQuotes(nameMatch[1]);
485
+ allManagedNames.add(deployedName);
486
+ if (!copyStandardSkills && isKernelSkill(s)) {
487
+ desiredNames.add(deployedName);
488
+ }
473
489
  }
474
490
  }
475
491
  } catch { /* ignore */ }
@@ -528,7 +544,7 @@ function isFullAiwgSourceRoot(srcRoot) {
528
544
  // the .aiwg-managed marker. Treat only the exact historical names as
529
545
  // managed so malformed legacy frontmatter cannot survive an upgrade.
530
546
  let isAiwgManaged = allManagedNames.has(name) || LEGACY_RENAMED_SKILLS.has(name);
531
- if (!isAiwgManaged && fullAiwgSourceRoot) {
547
+ if (!isAiwgManaged && (fullAiwgSourceRoot || inventoryRoot)) {
532
548
  // Check for the .aiwg-managed marker file (preferred — survives
533
549
  // frontmatter transforms) or fall back to namespace check.
534
550
  const markerFile = path.join(target, name, '.aiwg-managed');