aiwg 2026.2.8 → 2026.2.9

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.
@@ -0,0 +1,24 @@
1
+ {
2
+ "id": "research-complete",
3
+ "type": "framework",
4
+ "name": "Research Complete",
5
+ "version": "1.0.0",
6
+ "description": "Research workflow framework for discovery, acquisition, synthesis, citation, quality, and archival operations.",
7
+ "modeAliases": [
8
+ "research"
9
+ ],
10
+ "entry": {
11
+ "agents": "agents",
12
+ "commands": "commands",
13
+ "skills": "skills",
14
+ "templates": "templates"
15
+ },
16
+ "workspace": {
17
+ "subdirs": [
18
+ "repo",
19
+ "corpus",
20
+ "working",
21
+ "archive"
22
+ ]
23
+ }
24
+ }
@@ -57,6 +57,18 @@
57
57
  "references/REF-002-llm-failure-modes-agentic",
58
58
  "references/REF-003-mcp-specification-2025",
59
59
  "releases",
60
+ "releases/v2026.2.9-announcement",
61
+ "releases/v2026.2.8-announcement",
62
+ "releases/v2026.2.7-announcement",
63
+ "releases/v2026.2.5-announcement",
64
+ "releases/v2026.2.4-announcement",
65
+ "releases/v2026.2.3-announcement",
66
+ "releases/v2026.2.0-announcement",
67
+ "releases/v2026.1.7-announcement",
68
+ "releases/v2026.1.6-announcement",
69
+ "releases/v2026.1.5-announcement",
70
+ "releases/v2026.1.4-announcement",
71
+ "releases/v2026.1.3-announcement",
60
72
  "releases/v2024.12.5-announcement",
61
73
  "releases/v2024.12.4-announcement",
62
74
  "releases/v2024.12.3-announcement",
@@ -441,10 +453,94 @@
441
453
  "summary": "Release notes",
442
454
  "collapsed": true
443
455
  },
456
+ {
457
+ "id": "releases/v2026.2.9-announcement",
458
+ "title": "v2026.2.9",
459
+ "summary": "Latest release",
460
+ "file": "releases/v2026.2.9-announcement.md",
461
+ "parent": "releases"
462
+ },
463
+ {
464
+ "id": "releases/v2026.2.8-announcement",
465
+ "title": "v2026.2.8",
466
+ "summary": "Previous release",
467
+ "file": "releases/v2026.2.8-announcement.md",
468
+ "parent": "releases"
469
+ },
470
+ {
471
+ "id": "releases/v2026.2.7-announcement",
472
+ "title": "v2026.2.7",
473
+ "summary": "Previous release",
474
+ "file": "releases/v2026.2.7-announcement.md",
475
+ "parent": "releases"
476
+ },
477
+ {
478
+ "id": "releases/v2026.2.5-announcement",
479
+ "title": "v2026.2.5",
480
+ "summary": "Previous release",
481
+ "file": "releases/v2026.2.5-announcement.md",
482
+ "parent": "releases"
483
+ },
484
+ {
485
+ "id": "releases/v2026.2.4-announcement",
486
+ "title": "v2026.2.4",
487
+ "summary": "Previous release",
488
+ "file": "releases/v2026.2.4-announcement.md",
489
+ "parent": "releases"
490
+ },
491
+ {
492
+ "id": "releases/v2026.2.3-announcement",
493
+ "title": "v2026.2.3",
494
+ "summary": "Previous release",
495
+ "file": "releases/v2026.2.3-announcement.md",
496
+ "parent": "releases"
497
+ },
498
+ {
499
+ "id": "releases/v2026.2.0-announcement",
500
+ "title": "v2026.2.0",
501
+ "summary": "Previous release",
502
+ "file": "releases/v2026.2.0-announcement.md",
503
+ "parent": "releases"
504
+ },
505
+ {
506
+ "id": "releases/v2026.1.7-announcement",
507
+ "title": "v2026.1.7",
508
+ "summary": "Previous release",
509
+ "file": "releases/v2026.1.7-announcement.md",
510
+ "parent": "releases"
511
+ },
512
+ {
513
+ "id": "releases/v2026.1.6-announcement",
514
+ "title": "v2026.1.6",
515
+ "summary": "Previous release",
516
+ "file": "releases/v2026.1.6-announcement.md",
517
+ "parent": "releases"
518
+ },
519
+ {
520
+ "id": "releases/v2026.1.5-announcement",
521
+ "title": "v2026.1.5",
522
+ "summary": "Previous release",
523
+ "file": "releases/v2026.1.5-announcement.md",
524
+ "parent": "releases"
525
+ },
526
+ {
527
+ "id": "releases/v2026.1.4-announcement",
528
+ "title": "v2026.1.4",
529
+ "summary": "Previous release",
530
+ "file": "releases/v2026.1.4-announcement.md",
531
+ "parent": "releases"
532
+ },
533
+ {
534
+ "id": "releases/v2026.1.3-announcement",
535
+ "title": "v2026.1.3",
536
+ "summary": "Previous release",
537
+ "file": "releases/v2026.1.3-announcement.md",
538
+ "parent": "releases"
539
+ },
444
540
  {
445
541
  "id": "releases/v2024.12.5-announcement",
446
542
  "title": "v2024.12.5",
447
- "summary": "Latest release",
543
+ "summary": "Previous release",
448
544
  "file": "releases/v2024.12.5-announcement.md",
449
545
  "parent": "releases"
450
546
  },
@@ -3,6 +3,18 @@
3
3
  "summary": "Release notes",
4
4
  "collapsed": true,
5
5
  "order": [
6
+ "v2026.2.9-announcement",
7
+ "v2026.2.8-announcement",
8
+ "v2026.2.7-announcement",
9
+ "v2026.2.5-announcement",
10
+ "v2026.2.4-announcement",
11
+ "v2026.2.3-announcement",
12
+ "v2026.2.0-announcement",
13
+ "v2026.1.7-announcement",
14
+ "v2026.1.6-announcement",
15
+ "v2026.1.5-announcement",
16
+ "v2026.1.4-announcement",
17
+ "v2026.1.3-announcement",
6
18
  "v2024.12.5-announcement",
7
19
  "v2024.12.4-announcement",
8
20
  "v2024.12.3-announcement",
@@ -0,0 +1,60 @@
1
+ # AIWG v2026.2.9 — "Manifest Native" Release
2
+
3
+ **Released**: 2026-02-15
4
+
5
+ This release completes provider normalization around manifest-driven discovery so framework/addon deployment no longer depends on scattered provider-specific curation. Codex now receives the same research and media-curator deployment coverage as the other providers.
6
+
7
+ ## Highlights
8
+
9
+ | What changed | Why you care |
10
+ |--------------|--------------|
11
+ | Manifest-native provider deployment | Framework artifacts are discovered from manifests/shared utilities instead of hardcoded per-provider lists |
12
+ | Codex framework parity | Research and Media Curator components are now included through the same mode-aware discovery path |
13
+ | Lower maintenance overhead | Adding new frameworks/components is significantly more automatic once manifests are present |
14
+ | Test coverage updates | Integration and smoke tests now assert normalized provider behavior for framework deployment |
15
+
16
+ ## Provider Normalization
17
+
18
+ All 8 providers now align on shared discovery behavior:
19
+
20
+ - Claude
21
+ - Codex (OpenAI)
22
+ - Copilot
23
+ - Cursor
24
+ - Factory
25
+ - OpenCode
26
+ - Warp
27
+ - Windsurf
28
+
29
+ Instead of each provider manually curating framework directories, deployment now uses centralized manifest-aware helpers to resolve frameworks and artifacts by mode.
30
+
31
+ ## Codex: Research + Media Curator Coverage
32
+
33
+ Codex deployment scripts now use framework discovery for command and skill selection, which closes gaps where newly added frameworks could be missed in Codex-specific install paths.
34
+
35
+ ### What this enables
36
+
37
+ ```bash
38
+ # These now deploy consistently for Codex via the normalized discovery path
39
+ aiwg use research --provider codex
40
+ aiwg use media-curator --provider codex
41
+ ```
42
+
43
+ ## Manifest-Driven Extensibility
44
+
45
+ A framework with a valid `manifest.json` and standard component layout is now discoverable by provider deployment without requiring one-off changes in each provider module.
46
+
47
+ This release also adds explicit manifest metadata for `research-complete` to support that flow.
48
+
49
+ ## Install / Update
50
+
51
+ ```bash
52
+ npm install -g aiwg@2026.2.9
53
+
54
+ # Or update existing installation
55
+ aiwg update
56
+ ```
57
+
58
+ ## Full Changelog
59
+
60
+ See [CHANGELOG.md](../../CHANGELOG.md) for complete details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiwg",
3
- "version": "2026.2.8",
3
+ "version": "2026.2.9",
4
4
  "description": "Cognitive architecture for AI-augmented software development with structured memory, ensemble validation, and closed-loop correction. FAIR-aligned artifacts, 84% cost reduction via human-in-the-loop, standards adopted by 100+ organizations.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -17,10 +17,11 @@
17
17
  "package-plugins": "node tools/plugin/package-plugins.mjs --all",
18
18
  "package-plugins:clean": "node tools/plugin/package-plugins.mjs --all --clean",
19
19
  "build": "tsc",
20
- "test": "vitest",
20
+ "test": "vitest run",
21
+ "test:ci": "vitest run --exclude \"test/integration/**\" --exclude \"test/characterization/**\" --exclude \"test/smoke/**\" --exclude \"test/unit/intake/git-history-analyzer.test.ts\" --exclude \"test/unit/ralph-external/snapshot-manager.test.ts\" --exclude \"test/unit/smiths/toolsmith/runtime-discovery.test.ts\"",
21
22
  "test:coverage": "vitest --coverage",
22
23
  "test:ui": "vitest --ui",
23
- "test:watch": "vitest --watch",
24
+ "test:watch": "vitest",
24
25
  "typecheck": "tsc --noEmit",
25
26
  "clean": "rm -rf dist coverage"
26
27
  },
@@ -11,7 +11,7 @@
11
11
  * Options:
12
12
  * --source <path> Source directory (defaults to repo root)
13
13
  * --target <path> Target directory (defaults to cwd)
14
- * --mode <type> Deployment mode: general, sdlc, marketing, media-curator, research, both, or all (default)
14
+ * --mode <type> Deployment mode: general, sdlc, marketing (alias: mmk), media-curator, research, both, or all (default)
15
15
  * --deploy-commands Deploy commands in addition to agents
16
16
  * --deploy-skills Deploy skills in addition to agents
17
17
  * --deploy-rules Deploy rules in addition to agents
@@ -31,7 +31,7 @@
31
31
  * general - Deploy only writing-quality addon agents and commands (alias: writing)
32
32
  * writing - Deploy only writing-quality addon agents (alias for general)
33
33
  * sdlc - Deploy only SDLC Complete framework agents and commands
34
- * marketing - Deploy only Media/Marketing Kit framework agents and commands
34
+ * marketing - Deploy only Media/Marketing Kit framework agents and commands (alias: mmk)
35
35
  * media-curator - Deploy only Media Curator framework agents and commands
36
36
  * research - Deploy only Research Complete framework agents and commands
37
37
  * both - Deploy writing + SDLC (legacy compatibility)
@@ -140,7 +140,7 @@ Usage:
140
140
  Options:
141
141
  --source <path> Source directory (defaults to repo root)
142
142
  --target <path> Target directory (defaults to cwd)
143
- --mode <type> Deployment mode: general, sdlc, marketing, media-curator, research, both, or all (default)
143
+ --mode <type> Deployment mode: general, sdlc, marketing (alias: mmk), media-curator, research, both, or all (default)
144
144
  --deploy-commands Deploy commands in addition to agents
145
145
  --deploy-skills Deploy skills in addition to agents
146
146
  --deploy-rules Deploy rules in addition to agents
@@ -181,7 +181,7 @@ Providers (all deploy agents, commands, skills, and rules):
181
181
  Modes:
182
182
  general - Writing-quality addon agents and commands (alias: writing)
183
183
  sdlc - SDLC Complete framework agents and commands
184
- marketing - Media/Marketing Kit framework agents and commands
184
+ marketing - Media/Marketing Kit framework agents and commands (alias: mmk)
185
185
  media-curator - Media Curator framework agents and commands
186
186
  research - Research Complete framework agents and commands
187
187
  both - writing + SDLC (legacy compatibility)
@@ -342,6 +342,7 @@ function deepMerge(target, source) {
342
342
 
343
343
  // Normalize mode aliases
344
344
  if (cfg.mode === 'writing') cfg.mode = 'general';
345
+ if (cfg.mode === 'mmk') cfg.mode = 'marketing';
345
346
 
346
347
  console.log(`\n=== AIWG Agent Deployment ===`);
347
348
  console.log(`Provider: ${cfg.provider}`);
@@ -371,39 +371,47 @@ export function deploySkillDir(skillDir, destDir, opts) {
371
371
  * Initialize framework-scoped workspace structure
372
372
  * Creates .aiwg/frameworks/{framework-id}/ directories
373
373
  */
374
- export function initializeFrameworkWorkspace(target, mode, dryRun) {
374
+ export function initializeFrameworkWorkspace(target, mode, dryRun, srcRoot = null) {
375
375
  const aiwgBase = path.join(target, '.aiwg');
376
376
  const frameworksDir = path.join(aiwgBase, 'frameworks');
377
377
  const sharedDir = path.join(aiwgBase, 'shared');
378
378
 
379
- const frameworkDirs = [];
380
-
381
- if (mode === 'sdlc' || mode === 'both' || mode === 'all') {
382
- frameworkDirs.push({
383
- id: 'sdlc-complete',
384
- subdirs: ['repo', 'projects', 'working', 'archive']
385
- });
386
- }
379
+ const frameworkDirs = srcRoot
380
+ ? getFrameworksForMode(srcRoot, mode).map(fw => ({
381
+ id: fw.id,
382
+ subdirs: fw.workspaceSubdirs
383
+ }))
384
+ : [];
385
+
386
+ // Backward-compatible fallback when source root isn't provided.
387
+ if (frameworkDirs.length === 0) {
388
+ if (mode === 'sdlc' || mode === 'both' || mode === 'all') {
389
+ frameworkDirs.push({
390
+ id: 'sdlc-complete',
391
+ subdirs: ['repo', 'projects', 'working', 'archive']
392
+ });
393
+ }
387
394
 
388
- if (mode === 'marketing' || mode === 'all') {
389
- frameworkDirs.push({
390
- id: 'media-marketing-kit',
391
- subdirs: ['repo', 'campaigns', 'working', 'archive']
392
- });
393
- }
395
+ if (mode === 'marketing' || mode === 'all') {
396
+ frameworkDirs.push({
397
+ id: 'media-marketing-kit',
398
+ subdirs: ['repo', 'campaigns', 'working', 'archive']
399
+ });
400
+ }
394
401
 
395
- if (mode === 'media-curator' || mode === 'all') {
396
- frameworkDirs.push({
397
- id: 'media-curator',
398
- subdirs: ['repo', 'library', 'working', 'archive']
399
- });
400
- }
402
+ if (mode === 'media-curator' || mode === 'all') {
403
+ frameworkDirs.push({
404
+ id: 'media-curator',
405
+ subdirs: ['repo', 'library', 'working', 'archive']
406
+ });
407
+ }
401
408
 
402
- if (mode === 'research' || mode === 'all') {
403
- frameworkDirs.push({
404
- id: 'research-complete',
405
- subdirs: ['repo', 'corpus', 'working', 'archive']
406
- });
409
+ if (mode === 'research' || mode === 'all') {
410
+ frameworkDirs.push({
411
+ id: 'research-complete',
412
+ subdirs: ['repo', 'corpus', 'working', 'archive']
413
+ });
414
+ }
407
415
  }
408
416
 
409
417
  if (frameworkDirs.length === 0) return;
@@ -582,6 +590,209 @@ export function filterAgentFiles(files, opts) {
582
590
  });
583
591
  }
584
592
 
593
+ // ============================================================================
594
+ // Framework Discovery
595
+ // ============================================================================
596
+
597
+ const MODE_ALIASES = {
598
+ writing: 'general',
599
+ mmk: 'marketing'
600
+ };
601
+
602
+ const LEGACY_FRAMEWORK_MODE_ALIASES = {
603
+ 'sdlc-complete': ['sdlc'],
604
+ 'media-marketing-kit': ['marketing', 'mmk'],
605
+ 'media-curator': ['media-curator'],
606
+ 'research-complete': ['research']
607
+ };
608
+
609
+ const DEFAULT_FRAMEWORK_SUBDIRS = {
610
+ 'sdlc-complete': ['repo', 'projects', 'working', 'archive'],
611
+ 'media-marketing-kit': ['repo', 'campaigns', 'working', 'archive'],
612
+ 'media-curator': ['repo', 'library', 'working', 'archive'],
613
+ 'research-complete': ['repo', 'corpus', 'working', 'archive']
614
+ };
615
+
616
+ function normalizePathSegment(segment) {
617
+ return String(segment || '')
618
+ .replace(/^\/+/, '')
619
+ .replace(/\/+$/, '');
620
+ }
621
+
622
+ function ensureStringArray(value) {
623
+ if (!value) return [];
624
+ return Array.isArray(value) ? value.map(v => String(v)) : [String(value)];
625
+ }
626
+
627
+ function uniqueLower(values) {
628
+ const seen = new Set();
629
+ const out = [];
630
+ for (const raw of values) {
631
+ const v = String(raw || '').trim().toLowerCase();
632
+ if (!v || seen.has(v)) continue;
633
+ seen.add(v);
634
+ out.push(v);
635
+ }
636
+ return out;
637
+ }
638
+
639
+ export function normalizeDeploymentMode(mode = 'all') {
640
+ const normalized = String(mode || 'all').toLowerCase();
641
+ return MODE_ALIASES[normalized] || normalized;
642
+ }
643
+
644
+ function resolveFrameworkComponentDir(frameworkPath, manifest, component) {
645
+ const entry = manifest?.entry?.[component];
646
+ const relPath = normalizePathSegment(entry || component);
647
+ return path.join(frameworkPath, relPath);
648
+ }
649
+
650
+ /**
651
+ * Discover framework roots under agentic/code/frameworks.
652
+ * Framework metadata is loaded from root manifest.json when present.
653
+ */
654
+ export function discoverFrameworks(srcRoot) {
655
+ const frameworksRoot = path.join(srcRoot, 'agentic', 'code', 'frameworks');
656
+ if (!fs.existsSync(frameworksRoot)) return [];
657
+
658
+ const frameworks = [];
659
+ const entries = fs.readdirSync(frameworksRoot, { withFileTypes: true })
660
+ .filter(e => e.isDirectory())
661
+ .sort((a, b) => a.name.localeCompare(b.name));
662
+
663
+ for (const entry of entries) {
664
+ const frameworkPath = path.join(frameworksRoot, entry.name);
665
+ const manifestPath = path.join(frameworkPath, 'manifest.json');
666
+ let manifest = {};
667
+
668
+ if (fs.existsSync(manifestPath)) {
669
+ try {
670
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
671
+ } catch (e) {
672
+ console.warn(`Warning: Could not parse framework manifest for ${entry.name}: ${e.message}`);
673
+ }
674
+ }
675
+
676
+ const id = String(manifest.id || manifest.framework || entry.name);
677
+ const aliases = uniqueLower([
678
+ id,
679
+ entry.name,
680
+ ...ensureStringArray(manifest.modeAliases),
681
+ ...ensureStringArray(manifest.aliases),
682
+ ...(LEGACY_FRAMEWORK_MODE_ALIASES[id] || [])
683
+ ]);
684
+
685
+ const workspaceSubdirs = ensureStringArray(
686
+ manifest.workspace?.subdirs || manifest.workspace?.directories
687
+ );
688
+
689
+ const agentsDir = resolveFrameworkComponentDir(frameworkPath, manifest, 'agents');
690
+ const commandsDir = resolveFrameworkComponentDir(frameworkPath, manifest, 'commands');
691
+ const skillsDir = resolveFrameworkComponentDir(frameworkPath, manifest, 'skills');
692
+ const rulesDir = resolveFrameworkComponentDir(frameworkPath, manifest, 'rules');
693
+
694
+ frameworks.push({
695
+ id,
696
+ name: manifest.name || entry.name,
697
+ path: frameworkPath,
698
+ manifest,
699
+ aliases,
700
+ workspaceSubdirs: workspaceSubdirs.length > 0
701
+ ? workspaceSubdirs
702
+ : (DEFAULT_FRAMEWORK_SUBDIRS[id] || ['repo', 'working', 'archive']),
703
+ components: {
704
+ agents: { path: agentsDir, exists: fs.existsSync(agentsDir) },
705
+ commands: { path: commandsDir, exists: fs.existsSync(commandsDir) },
706
+ skills: { path: skillsDir, exists: fs.existsSync(skillsDir) },
707
+ rules: { path: rulesDir, exists: fs.existsSync(rulesDir) }
708
+ }
709
+ });
710
+ }
711
+
712
+ return frameworks;
713
+ }
714
+
715
+ /**
716
+ * Select frameworks for a deployment mode.
717
+ */
718
+ export function getFrameworksForMode(srcRoot, mode) {
719
+ const normalizedMode = normalizeDeploymentMode(mode);
720
+ const frameworks = discoverFrameworks(srcRoot);
721
+
722
+ if (normalizedMode === 'all') return frameworks;
723
+ if (normalizedMode === 'general') return [];
724
+ if (normalizedMode === 'both') {
725
+ return frameworks.filter(fw => fw.aliases.includes('sdlc'));
726
+ }
727
+
728
+ return frameworks.filter(fw =>
729
+ fw.id.toLowerCase() === normalizedMode || fw.aliases.includes(normalizedMode)
730
+ );
731
+ }
732
+
733
+ /**
734
+ * Collect framework artifacts for a deployment mode.
735
+ * @param {string} srcRoot - Source root directory
736
+ * @param {string} mode - Deployment mode
737
+ * @param {object} options - Collection options
738
+ * @param {boolean} options.includeAgents - Include agents
739
+ * @param {boolean} options.includeCommands - Include commands
740
+ * @param {boolean} options.includeSkills - Include skills
741
+ * @param {boolean} options.includeRules - Include rules
742
+ * @param {boolean} options.recursiveCommands - Use recursive command listing
743
+ * @param {boolean} options.consolidatedSdlcRules - Use RULES-INDEX for SDLC when available
744
+ * @returns {{frameworks: Array, agents: string[], commands: string[], skills: string[], rules: string[]}}
745
+ */
746
+ export function collectFrameworkArtifacts(srcRoot, mode, options = {}) {
747
+ const {
748
+ includeAgents = true,
749
+ includeCommands = true,
750
+ includeSkills = true,
751
+ includeRules = true,
752
+ recursiveCommands = true,
753
+ consolidatedSdlcRules = true
754
+ } = options;
755
+
756
+ const frameworks = getFrameworksForMode(srcRoot, mode);
757
+ const artifacts = {
758
+ frameworks,
759
+ agents: [],
760
+ commands: [],
761
+ skills: [],
762
+ rules: []
763
+ };
764
+
765
+ for (const framework of frameworks) {
766
+ if (includeAgents && framework.components.agents.exists) {
767
+ artifacts.agents.push(...listMdFiles(framework.components.agents.path));
768
+ }
769
+
770
+ if (includeCommands && framework.components.commands.exists) {
771
+ const commandFiles = recursiveCommands
772
+ ? listMdFilesRecursive(framework.components.commands.path)
773
+ : listMdFiles(framework.components.commands.path);
774
+ artifacts.commands.push(...commandFiles);
775
+ }
776
+
777
+ if (includeSkills && framework.components.skills.exists) {
778
+ artifacts.skills.push(...listSkillDirs(framework.components.skills.path));
779
+ }
780
+
781
+ if (includeRules && framework.components.rules.exists) {
782
+ if (consolidatedSdlcRules && framework.id === 'sdlc-complete') {
783
+ const indexPath = getRulesIndexPath(srcRoot);
784
+ if (indexPath) {
785
+ artifacts.rules.push(indexPath);
786
+ continue;
787
+ }
788
+ }
789
+ artifacts.rules.push(...listMdFiles(framework.components.rules.path));
790
+ }
791
+ }
792
+
793
+ return artifacts;
794
+ }
795
+
585
796
  // ============================================================================
586
797
  // Addon Discovery
587
798
  // ============================================================================