aios-core 4.2.6 → 4.2.7

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 (26) hide show
  1. package/.aios-core/core/orchestration/context-manager.js +333 -5
  2. package/.aios-core/core/orchestration/dashboard-integration.js +17 -1
  3. package/.aios-core/core/orchestration/execution-profile-resolver.js +107 -0
  4. package/.aios-core/core/orchestration/index.js +3 -0
  5. package/.aios-core/core/orchestration/skill-dispatcher.js +2 -0
  6. package/.aios-core/core/orchestration/subagent-prompt-builder.js +2 -0
  7. package/.aios-core/core/orchestration/workflow-orchestrator.js +113 -5
  8. package/.aios-core/data/entity-registry.yaml +1114 -1336
  9. package/.aios-core/development/agents/ux-design-expert.md +1 -1
  10. package/.aios-core/development/checklists/brownfield-compatibility-checklist.md +114 -0
  11. package/.aios-core/development/scripts/workflow-state-manager.js +128 -1
  12. package/.aios-core/development/tasks/next.md +36 -5
  13. package/.aios-core/hooks/ids-post-commit.js +29 -1
  14. package/.aios-core/hooks/ids-pre-push.js +29 -1
  15. package/.aios-core/infrastructure/contracts/compatibility/aios-4.0.4.yaml +44 -0
  16. package/.aios-core/infrastructure/scripts/validate-parity.js +238 -2
  17. package/.aios-core/install-manifest.yaml +43 -27
  18. package/.aios-core/product/templates/brownfield-risk-report-tmpl.yaml +277 -0
  19. package/.aios-core/workflow-intelligence/engine/suggestion-engine.js +114 -5
  20. package/LICENSE +13 -1
  21. package/README.md +39 -9
  22. package/package.json +8 -6
  23. package/packages/installer/src/wizard/ide-config-generator.js +0 -117
  24. package/packages/installer/src/wizard/index.js +2 -118
  25. package/packages/installer/src/wizard/pro-setup.js +50 -5
  26. package/scripts/semantic-lint.js +190 -0
@@ -539,12 +539,6 @@ async function generateIDEConfigs(selectedIDEs, wizardState, options = {}) {
539
539
  } else {
540
540
  spinner.info('Skipped settings.local.json (no hooks to register)');
541
541
  }
542
-
543
- // Silent statusline setup (graceful skip if user already has one)
544
- const statuslineResult = await setupGlobalStatusline();
545
- if (statuslineResult.installed) {
546
- createdFiles.push(...statuslineResult.files);
547
- }
548
542
  }
549
543
 
550
544
  // Gemini parity with Claude Code: copy hooks and configure settings
@@ -764,7 +758,6 @@ async function createClaudeSettingsLocal(projectRoot) {
764
758
  }
765
759
 
766
760
  /**
767
- <<<<<<< HEAD
768
761
  * Copy .aios-core/hooks/gemini folder into .gemini/hooks during installation
769
762
  * @param {string} projectRoot - Project root directory
770
763
  * @returns {Promise<string[]>} List of copied files
@@ -982,115 +975,6 @@ async function linkGeminiExtension(projectRoot) {
982
975
  return { status: 'skipped', reason: 'link-failed' };
983
976
  }
984
977
 
985
- /**
986
- * Setup global statusline for Claude Code
987
- *
988
- * Copies statusline-script.js and track-agent.sh to ~/.claude/
989
- * and configures ~/.claude/settings.json with statusLine + hook entries.
990
- *
991
- * GRACEFUL SKIP: If user already has a statusLine configured, this function
992
- * returns silently without any output — the user never knows it was checked.
993
- *
994
- * @returns {Promise<{installed: boolean, files: string[]}>}
995
- */
996
- async function setupGlobalStatusline() {
997
- const homeDir = require('os').homedir();
998
- const globalSettingsPath = path.join(homeDir, '.claude', 'settings.json');
999
- const result = { installed: false, files: [] };
1000
-
1001
- // Read existing global settings
1002
- let settings = {};
1003
- try {
1004
- if (await fs.pathExists(globalSettingsPath)) {
1005
- const content = await fs.readFile(globalSettingsPath, 'utf8');
1006
- settings = JSON.parse(content);
1007
- }
1008
- } catch {
1009
- // Corrupted or unreadable — treat as empty
1010
- settings = {};
1011
- }
1012
-
1013
- // GRACEFUL SKIP: User already has a statusLine configured
1014
- if (settings.statusLine) {
1015
- return result;
1016
- }
1017
-
1018
- // Source templates
1019
- const templatesDir = path.join(__dirname, '..', '..', '..', '..', '.aios-core', 'product', 'templates', 'statusline');
1020
-
1021
- const scriptSource = path.join(templatesDir, 'statusline-script.js');
1022
- const hookSource = path.join(templatesDir, 'track-agent.sh');
1023
-
1024
- // Verify templates exist
1025
- if (!await fs.pathExists(scriptSource) || !await fs.pathExists(hookSource)) {
1026
- return result;
1027
- }
1028
-
1029
- // Target paths
1030
- const scriptTarget = path.join(homeDir, '.claude', 'statusline-script.js');
1031
- const hookTarget = path.join(homeDir, '.claude', 'hooks', 'track-agent.sh');
1032
- const cacheDir = path.join(homeDir, '.claude', 'session-cache');
1033
-
1034
- // Copy files
1035
- try {
1036
- await fs.ensureDir(path.join(homeDir, '.claude', 'hooks'));
1037
- await fs.ensureDir(cacheDir);
1038
- await fs.copy(scriptSource, scriptTarget);
1039
- await fs.copy(hookSource, hookTarget);
1040
- result.files.push(scriptTarget, hookTarget);
1041
- } catch {
1042
- return result;
1043
- }
1044
-
1045
- // Build the statusLine command with platform-appropriate path
1046
- const scriptPathEscaped = scriptTarget.replace(/\\/g, '\\\\');
1047
-
1048
- // Add statusLine to settings
1049
- settings.statusLine = {
1050
- type: 'command',
1051
- command: `node "${scriptPathEscaped}"`,
1052
- };
1053
-
1054
- // Add track-agent hook to UserPromptSubmit (if not already present)
1055
- if (!settings.hooks) {
1056
- settings.hooks = {};
1057
- }
1058
- if (!Array.isArray(settings.hooks.UserPromptSubmit)) {
1059
- settings.hooks.UserPromptSubmit = [];
1060
- }
1061
-
1062
- const hookPathEscaped = hookTarget.replace(/\\/g, '\\\\');
1063
- const alreadyHasTrackAgent = settings.hooks.UserPromptSubmit.some(entry => {
1064
- if (Array.isArray(entry.hooks)) {
1065
- return entry.hooks.some(h => h.command && h.command.includes('track-agent'));
1066
- }
1067
- return entry.command && entry.command.includes('track-agent');
1068
- });
1069
-
1070
- if (!alreadyHasTrackAgent) {
1071
- settings.hooks.UserPromptSubmit.push({
1072
- matcher: '',
1073
- hooks: [
1074
- {
1075
- type: 'command',
1076
- command: `bash "${hookPathEscaped}"`,
1077
- },
1078
- ],
1079
- });
1080
- }
1081
-
1082
- // Write settings back
1083
- try {
1084
- await fs.ensureDir(path.dirname(globalSettingsPath));
1085
- await fs.writeFile(globalSettingsPath, JSON.stringify(settings, null, 2), 'utf8');
1086
- result.installed = true;
1087
- } catch {
1088
- return result;
1089
- }
1090
-
1091
- return result;
1092
- }
1093
-
1094
978
  module.exports = {
1095
979
  generateIDEConfigs,
1096
980
  showSuccessSummary,
@@ -1104,5 +988,4 @@ module.exports = {
1104
988
  copyGeminiHooksFolder,
1105
989
  createGeminiSettings,
1106
990
  linkGeminiExtension,
1107
- setupGlobalStatusline,
1108
991
  };
@@ -461,67 +461,7 @@ async function runWizard(options = {}) {
461
461
  answers.techPresetResult = { preset: 'none', success: true };
462
462
  }
463
463
 
464
- // DISABLED: Legacy installation block superseded by squads flow (OSR-8)
465
- // Install Squads if selected
466
- // if (answers.selectedExpansionPacks && answers.selectedExpansionPacks.length > 0) {
467
- // console.log('\n🎁 Installing Squads...');
468
- //
469
- // // Detect source squads directory (npm package location)
470
- // const possibleSourceDirs = [
471
- // path.join(__dirname, '..', '..', 'squads'),
472
- // path.join(__dirname, '..', '..', '..', 'squads'),
473
- // path.join(process.cwd(), 'node_modules', '@synkra/aios-core', 'squads'),
474
- // ];
475
- //
476
- // let sourceExpansionDir = null;
477
- // for (const dir of possibleSourceDirs) {
478
- // if (fse.existsSync(dir)) {
479
- // sourceExpansionDir = dir;
480
- // break;
481
- // }
482
- // }
483
- //
484
- // if (sourceExpansionDir) {
485
- // const targetExpansionDir = path.join(process.cwd(), 'squads');
486
- // await fse.ensureDir(targetExpansionDir);
487
- //
488
- // const installedPacks = [];
489
- // const failedPacks = [];
490
- //
491
- // for (const pack of answers.selectedExpansionPacks) {
492
- // const sourcePack = path.join(sourceExpansionDir, pack);
493
- // const targetPack = path.join(targetExpansionDir, pack);
494
- //
495
- // try {
496
- // if (fse.existsSync(sourcePack)) {
497
- // await fse.copy(sourcePack, targetPack);
498
- // installedPacks.push(pack);
499
- // console.log(` ✅ ${pack}`);
500
- // } else {
501
- // failedPacks.push({ pack, reason: 'not found' });
502
- // console.log(` ⚠️ ${pack} - not found in source`);
503
- // }
504
- // } catch (packError) {
505
- // failedPacks.push({ pack, reason: packError.message });
506
- // console.log(` ⚠️ ${pack} - ${packError.message}`);
507
- // }
508
- // }
509
- //
510
- // answers.expansionPacksInstalled = installedPacks.length > 0;
511
- // answers.expansionPacksResult = {
512
- // installed: installedPacks,
513
- // failed: failedPacks,
514
- // targetDir: targetExpansionDir,
515
- // };
516
- //
517
- // if (installedPacks.length > 0) {
518
- // console.log(`\n✅ Squads installed (${installedPacks.length}/${answers.selectedExpansionPacks.length})`);
519
- // }
520
- // } else {
521
- // console.log(' ⚠️ Squads source directory not found');
522
- // answers.expansionPacksInstalled = false;
523
- // }
524
- // }
464
+ // Legacy squad installation path removed; unified squads flow is now the only supported path.
525
465
 
526
466
  // Story 1.4: Generate IDE configs if IDEs were selected
527
467
  let ideConfigResult = null;
@@ -545,63 +485,7 @@ async function runWizard(options = {}) {
545
485
  }
546
486
  }
547
487
 
548
- // DISABLED: Legacy installation block superseded by squads flow (OSR-8)
549
- // Install squad agents to each selected IDE
550
- // if (answers.expansionPacksResult && answers.expansionPacksResult.installed.length > 0) {
551
- // console.log('\n📦 Installing squad agents to IDEs...');
552
- //
553
- // for (const packName of answers.expansionPacksResult.installed) {
554
- // const packAgentsDir = path.join(answers.expansionPacksResult.targetDir, packName, 'agents');
555
- //
556
- // if (await fse.pathExists(packAgentsDir)) {
557
- // const agentFiles = (await fse.readdir(packAgentsDir)).filter(f => f.endsWith('.md'));
558
- //
559
- // if (agentFiles.length > 0) {
560
- // for (const ideKey of answers.selectedIDEs) {
561
- // const ideConfig = getIDEConfig(ideKey);
562
- // if (!ideConfig || !ideConfig.agentFolder) continue;
563
- //
564
- // const isAntiGravity = ideConfig.specialConfig && ideConfig.specialConfig.type === 'antigravity';
565
- //
566
- // // Determine target folder for this squad
567
- // let targetFolder;
568
- // if (isAntiGravity) {
569
- // // AntiGravity: workflows go to .agent/workflows/{packName}/
570
- // targetFolder = path.join(process.cwd(), ideConfig.agentFolder, packName);
571
- // // Also need to copy actual agents to .antigravity/agents/{packName}/
572
- // const agentsTargetFolder = path.join(process.cwd(), ideConfig.specialConfig.agentsFolder, packName);
573
- // await fse.ensureDir(agentsTargetFolder);
574
- //
575
- // for (const agentFile of agentFiles) {
576
- // const sourcePath = path.join(packAgentsDir, agentFile);
577
- // const agentName = agentFile.replace('.md', '');
578
- //
579
- // // Create workflow file
580
- // const workflowContent = generateExpansionPackWorkflow(agentName, packName);
581
- // await fse.ensureDir(targetFolder);
582
- // await fse.writeFile(path.join(targetFolder, agentFile), workflowContent, 'utf8');
583
- //
584
- // // Copy actual agent
585
- // await fse.copy(sourcePath, path.join(agentsTargetFolder, agentFile));
586
- // }
587
- // } else {
588
- // // Other IDEs: copy directly to agentFolder/{packName}/
589
- // targetFolder = path.join(process.cwd(), ideConfig.agentFolder, packName);
590
- // await fse.ensureDir(targetFolder);
591
- //
592
- // for (const agentFile of agentFiles) {
593
- // await fse.copy(
594
- // path.join(packAgentsDir, agentFile),
595
- // path.join(targetFolder, agentFile),
596
- // );
597
- // }
598
- // }
599
- // }
600
- // console.log(` ✅ ${packName}: ${agentFiles.length} agents installed to ${answers.selectedIDEs.length} IDE(s)`);
601
- // }
602
- // }
603
- // }
604
- // }
488
+ // Legacy per-squad IDE copy path removed; sync pipeline handles IDE propagation.
605
489
  }
606
490
 
607
491
  // Story 1.6: Environment Configuration
@@ -16,7 +16,7 @@
16
16
  'use strict';
17
17
 
18
18
  const { createSpinner, showSuccess, showError, showWarning, showInfo } = require('./feedback');
19
- const { colors, headings, status } = require('../utils/aios-colors');
19
+ const { colors, status } = require('../utils/aios-colors');
20
20
 
21
21
  /**
22
22
  * Gold color for Pro branding.
@@ -947,6 +947,55 @@ async function validateKeyWithApi(key) {
947
947
  async function stepInstallScaffold(targetDir, options = {}) {
948
948
  showStep(2, 3, 'Pro Content Installation');
949
949
 
950
+ const path = require('path');
951
+ const fs = require('fs');
952
+ const { execSync } = require('child_process');
953
+
954
+ const proSourceDir = path.join(targetDir, 'node_modules', '@aios-fullstack', 'pro');
955
+
956
+ // Step 2a: Ensure package.json exists (greenfield projects)
957
+ const packageJsonPath = path.join(targetDir, 'package.json');
958
+ if (!fs.existsSync(packageJsonPath)) {
959
+ const initSpinner = createSpinner('Initializing package.json...');
960
+ initSpinner.start();
961
+ try {
962
+ execSync('npm init -y', { cwd: targetDir, stdio: 'pipe' });
963
+ initSpinner.succeed('package.json created');
964
+ } catch (err) {
965
+ initSpinner.fail('Failed to create package.json');
966
+ return { success: false, error: `npm init failed: ${err.message}` };
967
+ }
968
+ }
969
+
970
+ // Step 2b: Install @aios-fullstack/pro if not present
971
+ if (!fs.existsSync(proSourceDir)) {
972
+ const installSpinner = createSpinner('Installing @aios-fullstack/pro...');
973
+ installSpinner.start();
974
+ try {
975
+ execSync('npm install @aios-fullstack/pro', {
976
+ cwd: targetDir,
977
+ stdio: 'pipe',
978
+ timeout: 120000,
979
+ });
980
+ installSpinner.succeed('Pro package installed');
981
+ } catch (err) {
982
+ installSpinner.fail('Failed to install Pro package');
983
+ return {
984
+ success: false,
985
+ error: `npm install @aios-fullstack/pro failed: ${err.message}. Try manually: npm install @aios-fullstack/pro`,
986
+ };
987
+ }
988
+
989
+ // Validate installation
990
+ if (!fs.existsSync(proSourceDir)) {
991
+ return {
992
+ success: false,
993
+ error: 'Pro package not found after npm install. Check npm output.',
994
+ };
995
+ }
996
+ }
997
+
998
+ // Step 2c: Scaffold pro content
950
999
  const scaffolderModule = loadProScaffolder();
951
1000
 
952
1001
  if (!scaffolderModule) {
@@ -955,10 +1004,6 @@ async function stepInstallScaffold(targetDir, options = {}) {
955
1004
  }
956
1005
 
957
1006
  const { scaffoldProContent } = scaffolderModule;
958
- const path = require('path');
959
-
960
- // Determine pro source directory
961
- const proSourceDir = path.join(targetDir, 'node_modules', '@aios-fullstack', 'pro');
962
1007
 
963
1008
  const spinner = createSpinner('Scaffolding pro content...');
964
1009
  spinner.start();
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const DEFAULT_TARGETS = [
8
+ 'README.md',
9
+ 'docs/getting-started.md',
10
+ 'docs/roadmap.md',
11
+ 'docs/strategy',
12
+ ];
13
+
14
+ const SEMANTIC_RULESET_VERSION = '1.0.0';
15
+
16
+ const RULES = [
17
+ {
18
+ id: 'deprecated-expansion-pack',
19
+ severity: 'error',
20
+ pattern: /\bexpansion pack(s)?\b/gi,
21
+ replacement: 'squad',
22
+ reason: 'Use AIOS-first taxonomy for domain agent sets.',
23
+ },
24
+ {
25
+ id: 'deprecated-permission-mode',
26
+ severity: 'error',
27
+ pattern: /\bpermission mode(s)?\b/gi,
28
+ replacement: 'execution profile',
29
+ reason: 'Use risk-oriented autonomy terminology.',
30
+ },
31
+ {
32
+ id: 'legacy-workflow-state-term',
33
+ severity: 'warn',
34
+ pattern: /\bworkflow state\b/gi,
35
+ replacement: 'flow-state',
36
+ reason: 'Prefer flow-state in product-facing differentiation messaging.',
37
+ },
38
+ ];
39
+
40
+ function parseArgs(argv = process.argv.slice(2)) {
41
+ const args = new Set(argv.filter((arg) => arg.startsWith('--')));
42
+ const files = argv.filter((arg) => !arg.startsWith('--'));
43
+ return {
44
+ staged: args.has('--staged'),
45
+ json: args.has('--json'),
46
+ files,
47
+ };
48
+ }
49
+
50
+ function collectFiles(inputPaths, projectRoot = process.cwd()) {
51
+ const selected = inputPaths && inputPaths.length > 0 ? inputPaths : DEFAULT_TARGETS;
52
+ const files = [];
53
+
54
+ for (const input of selected) {
55
+ const resolved = path.resolve(projectRoot, input);
56
+ if (!fs.existsSync(resolved)) {
57
+ continue;
58
+ }
59
+
60
+ const stat = fs.statSync(resolved);
61
+ if (stat.isFile()) {
62
+ files.push(resolved);
63
+ continue;
64
+ }
65
+
66
+ if (stat.isDirectory()) {
67
+ walkDirectory(resolved, files);
68
+ }
69
+ }
70
+
71
+ return files;
72
+ }
73
+
74
+ function walkDirectory(dir, files) {
75
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
76
+ for (const entry of entries) {
77
+ const full = path.join(dir, entry.name);
78
+ if (entry.isDirectory()) {
79
+ walkDirectory(full, files);
80
+ continue;
81
+ }
82
+ if (/\.(md|js|yaml|yml)$/i.test(entry.name)) {
83
+ files.push(full);
84
+ }
85
+ }
86
+ }
87
+
88
+ function lintContent(content, relativePath) {
89
+ const findings = [];
90
+
91
+ for (const rule of RULES) {
92
+ const regex = new RegExp(rule.pattern.source, rule.pattern.flags);
93
+ let match;
94
+ while ((match = regex.exec(content)) !== null) {
95
+ const line = 1 + content.slice(0, match.index).split('\n').length - 1;
96
+ findings.push({
97
+ ruleId: rule.id,
98
+ severity: rule.severity,
99
+ term: match[0],
100
+ replacement: rule.replacement,
101
+ file: relativePath,
102
+ line,
103
+ reason: rule.reason,
104
+ });
105
+ }
106
+ }
107
+
108
+ return findings;
109
+ }
110
+
111
+ function runSemanticLint(options = {}, deps = {}) {
112
+ const projectRoot = options.projectRoot || process.cwd();
113
+ const targets = options.targets || [];
114
+ const fileCollector = deps.collectFiles || collectFiles;
115
+ const fileReader = deps.readFile || ((filePath) => fs.readFileSync(filePath, 'utf8'));
116
+ const files = fileCollector(targets, projectRoot);
117
+
118
+ const findings = [];
119
+ for (const filePath of files) {
120
+ const content = fileReader(filePath);
121
+ const relativePath = path.relative(projectRoot, filePath);
122
+ findings.push(...lintContent(content, relativePath));
123
+ }
124
+
125
+ const errors = findings.filter((f) => f.severity === 'error');
126
+ const warnings = findings.filter((f) => f.severity === 'warn');
127
+ return {
128
+ ok: errors.length === 0,
129
+ version: SEMANTIC_RULESET_VERSION,
130
+ filesScanned: files.length,
131
+ findings,
132
+ errors,
133
+ warnings,
134
+ };
135
+ }
136
+
137
+ function formatHuman(result) {
138
+ const lines = [];
139
+ lines.push(`Semantic Lint v${result.version}`);
140
+ lines.push(`Files scanned: ${result.filesScanned}`);
141
+
142
+ if (result.findings.length === 0) {
143
+ lines.push('✅ No semantic term regressions found');
144
+ return lines.join('\n');
145
+ }
146
+
147
+ for (const finding of result.findings) {
148
+ lines.push(
149
+ `${finding.severity === 'error' ? '❌' : '⚠️'} ${finding.file}:${finding.line} ${finding.ruleId} -> "${finding.term}" (use "${finding.replacement}")`,
150
+ );
151
+ }
152
+
153
+ lines.push('');
154
+ lines.push(
155
+ result.ok
156
+ ? `✅ Completed with ${result.warnings.length} warning(s)`
157
+ : `❌ Failed with ${result.errors.length} error(s) and ${result.warnings.length} warning(s)`,
158
+ );
159
+ return lines.join('\n');
160
+ }
161
+
162
+ function main() {
163
+ const args = parseArgs();
164
+ const targets = args.files.length > 0
165
+ ? args.files
166
+ : (args.staged ? [] : DEFAULT_TARGETS);
167
+ const result = runSemanticLint({ targets });
168
+
169
+ if (args.json) {
170
+ console.log(JSON.stringify(result, null, 2));
171
+ } else {
172
+ console.log(formatHuman(result));
173
+ }
174
+
175
+ if (!result.ok) {
176
+ process.exitCode = 1;
177
+ }
178
+ }
179
+
180
+ if (require.main === module) {
181
+ main();
182
+ }
183
+
184
+ module.exports = {
185
+ parseArgs,
186
+ collectFiles,
187
+ lintContent,
188
+ runSemanticLint,
189
+ RULES,
190
+ };