aios-core 3.11.0 → 3.11.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.
@@ -35,7 +35,7 @@ const ExitCode = {
35
35
  };
36
36
 
37
37
  // Resolve validator module path
38
- const validatorPath = path.resolve(__dirname, '../../../../src/installer/post-install-validator');
38
+ const validatorPath = path.resolve(__dirname, '../../../../packages/installer/src/installer/post-install-validator');
39
39
  let PostInstallValidator, formatReport;
40
40
 
41
41
  let validatorLoadError = null;
@@ -7,8 +7,8 @@
7
7
  # - SHA256 hashes for change detection
8
8
  # - File types for categorization
9
9
  #
10
- version: 3.11.0
11
- generated_at: "2026-02-03T13:59:53.457Z"
10
+ version: 3.11.2
11
+ generated_at: "2026-02-03T14:51:52.983Z"
12
12
  generator: scripts/generate-install-manifest.js
13
13
  file_count: 839
14
14
  files:
@@ -109,9 +109,9 @@ files:
109
109
  type: cli
110
110
  size: 5320
111
111
  - path: cli/commands/validate/index.js
112
- hash: sha256:18901c95898b8d6d25b2fd8b8f91bd0bdcb421bcc92bba457a8a3836af28f36b
112
+ hash: sha256:dece3a1a8d3ed4ef7dbd8f1ac840c6ec69fb9c759fc43d5813a71ac59479d3a0
113
113
  type: cli
114
- size: 12882
114
+ size: 12901
115
115
  - path: cli/commands/workers/formatters/info-formatter.js
116
116
  hash: sha256:6f0d25f4033828616656178c55e50d1eeec9457279807c1b06e111d9dd79c53e
117
117
  type: cli
package/bin/aios-init.js CHANGED
@@ -1,10 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * AIOS-FullStack Installation Wizard v5
4
+ * AIOS-FullStack Installation Wizard v5 (LEGACY)
5
5
  * Based on the original beautiful visual design with ASCII art
6
6
  * Version: 2.1.0
7
7
  *
8
+ * ⚠️ DEPRECATION NOTICE (v3.11.2):
9
+ * This file is the LEGACY installer and will be removed in v4.0.0.
10
+ * The new modular wizard is located at: packages/installer/src/wizard/index.js
11
+ *
12
+ * This file is kept as a fallback for edge cases where the new wizard
13
+ * is not available. All new development should use the new wizard.
14
+ *
15
+ * Migration path:
16
+ * - Use `npx aios-core` which routes through bin/aios.js to the new wizard
17
+ * - Do NOT call this file directly
18
+ *
8
19
  * Supported IDEs (8 total):
9
20
  * - Claude Code, Cursor, Windsurf, Trae, Roo Code, Cline, Gemini CLI, GitHub Copilot
10
21
  */
@@ -2,25 +2,41 @@
2
2
 
3
3
  /**
4
4
  * AIOS-FullStack Minimal Installation
5
- * Wrapper that launches aios-init.js in minimal mode
6
5
  *
7
- * Minimal mode only shows expansion-creator pack,
8
- * which provides tools to install other expansion packs manually.
6
+ * DEPRECATION NOTICE (v3.11.1):
7
+ * The --minimal mode was designed for expansion-packs which have been
8
+ * replaced by the Squads system (OSR-8). This command now runs the
9
+ * standard wizard through the main router.
10
+ *
11
+ * This file is kept for backwards compatibility but will be removed
12
+ * in a future major version.
9
13
  */
10
14
 
11
- const { execSync } = require('child_process');
15
+ const { spawn } = require('child_process');
12
16
  const path = require('path');
13
17
 
14
- // Get the path to aios-init.js
15
- const initScriptPath = path.join(__dirname, 'aios-init.js');
16
-
17
- try {
18
- // Execute aios-init.js with --minimal flag
19
- execSync(`node "${initScriptPath}" --minimal`, {
20
- stdio: 'inherit',
21
- cwd: process.cwd(),
22
- });
23
- } catch (error) {
24
- // Error is already displayed by child process
25
- process.exit(error.status || 1);
26
- }
18
+ // Show deprecation warning
19
+ console.log('\n⚠️ DEPRECATION WARNING: aios-minimal is deprecated.');
20
+ console.log(' The --minimal mode (expansion-packs) was replaced by Squads.');
21
+ console.log(' Running standard installation wizard instead.\n');
22
+
23
+ // Get the path to the main router (aios.js)
24
+ const routerPath = path.join(__dirname, 'aios.js');
25
+
26
+ // Forward all arguments to the main router
27
+ const args = process.argv.slice(2);
28
+
29
+ // Spawn the main router
30
+ const child = spawn('node', [routerPath, ...args], {
31
+ stdio: 'inherit',
32
+ cwd: process.cwd(),
33
+ });
34
+
35
+ child.on('close', (code) => {
36
+ process.exit(code || 0);
37
+ });
38
+
39
+ child.on('error', (error) => {
40
+ console.error('❌ Failed to start AIOS:', error.message);
41
+ process.exit(1);
42
+ });
package/bin/aios.js CHANGED
@@ -20,8 +20,8 @@ const command = args[0];
20
20
 
21
21
  // Helper: Run initialization wizard
22
22
  async function runWizard() {
23
- // Use the new v2.1 wizard from src/wizard/index.js
24
- const wizardPath = path.join(__dirname, '..', 'src', 'wizard', 'index.js');
23
+ // Use the new v2.1 wizard from packages/installer/src/wizard/index.js
24
+ const wizardPath = path.join(__dirname, '..', 'packages', 'installer', 'src', 'wizard', 'index.js');
25
25
 
26
26
  if (!fs.existsSync(wizardPath)) {
27
27
  // Fallback to legacy wizard if new wizard not found
@@ -56,12 +56,21 @@ USAGE:
56
56
  npx @synkra/aios-core@latest # Run installation wizard
57
57
  npx @synkra/aios-core@latest install # Install in current project
58
58
  npx @synkra/aios-core@latest init <name> # Create new project
59
+ npx @synkra/aios-core@latest update # Update to latest version
59
60
  npx @synkra/aios-core@latest validate # Validate installation integrity
60
61
  npx @synkra/aios-core@latest info # Show system info
61
62
  npx @synkra/aios-core@latest doctor # Run diagnostics
62
63
  npx @synkra/aios-core@latest --version # Show version
64
+ npx @synkra/aios-core@latest --version -d # Show detailed version info
63
65
  npx @synkra/aios-core@latest --help # Show this help
64
66
 
67
+ UPDATE:
68
+ aios update # Update to latest version
69
+ aios update --check # Check for updates without applying
70
+ aios update --dry-run # Preview what would be updated
71
+ aios update --force # Force update even if up-to-date
72
+ aios update --verbose # Show detailed output
73
+
65
74
  VALIDATION:
66
75
  aios validate # Validate installation integrity
67
76
  aios validate --repair # Repair missing/corrupted files
@@ -92,8 +101,64 @@ For more information, visit: https://github.com/SynkraAI/aios-core
92
101
  }
93
102
 
94
103
  // Helper: Show version
95
- function showVersion() {
96
- console.log(packageJson.version);
104
+ async function showVersion() {
105
+ const isDetailed = args.includes('--detailed') || args.includes('-d');
106
+
107
+ if (!isDetailed) {
108
+ // Simple version output (backwards compatible)
109
+ console.log(packageJson.version);
110
+ return;
111
+ }
112
+
113
+ // Detailed version output (Story 7.2: Version Tracking)
114
+ console.log(`AIOS-FullStack v${packageJson.version}`);
115
+ console.log('Package: @synkra/aios-core');
116
+
117
+ // Check for local installation
118
+ const localVersionPath = path.join(process.cwd(), '.aios-core', 'version.json');
119
+
120
+ if (fs.existsSync(localVersionPath)) {
121
+ try {
122
+ const versionInfo = JSON.parse(fs.readFileSync(localVersionPath, 'utf8'));
123
+ console.log('\n📦 Local Installation:');
124
+ console.log(` Version: ${versionInfo.version}`);
125
+ console.log(` Mode: ${versionInfo.mode || 'unknown'}`);
126
+
127
+ if (versionInfo.installedAt) {
128
+ const installedDate = new Date(versionInfo.installedAt);
129
+ console.log(` Installed: ${installedDate.toLocaleDateString()}`);
130
+ }
131
+
132
+ if (versionInfo.updatedAt) {
133
+ const updatedDate = new Date(versionInfo.updatedAt);
134
+ console.log(` Updated: ${updatedDate.toLocaleDateString()}`);
135
+ }
136
+
137
+ if (versionInfo.fileHashes) {
138
+ const fileCount = Object.keys(versionInfo.fileHashes).length;
139
+ console.log(` Files: ${fileCount} tracked`);
140
+ }
141
+
142
+ if (versionInfo.customized && versionInfo.customized.length > 0) {
143
+ console.log(` Customized: ${versionInfo.customized.length} files`);
144
+ }
145
+
146
+ // Version comparison
147
+ if (versionInfo.version !== packageJson.version) {
148
+ console.log('\n⚠️ Version mismatch!');
149
+ console.log(` Local: ${versionInfo.version}`);
150
+ console.log(` Latest: ${packageJson.version}`);
151
+ console.log(' Run \'npx aios-core update\' to update.');
152
+ } else {
153
+ console.log('\n✅ Up to date');
154
+ }
155
+ } catch (error) {
156
+ console.log(`\n⚠️ Could not read version.json: ${error.message}`);
157
+ }
158
+ } else {
159
+ console.log('\n📭 No local installation found');
160
+ console.log(' Run \'npx aios-core install\' to install AIOS in this project.');
161
+ }
97
162
  }
98
163
 
99
164
  // Helper: Show system info
@@ -138,8 +203,8 @@ async function runValidate() {
138
203
  const { createValidateCommand } = require('../.aios-core/cli/commands/validate/index.js');
139
204
  const validateCmd = createValidateCommand();
140
205
 
141
- // Parse and execute
142
- await validateCmd.parseAsync(['node', 'aios', 'validate', ...validateArgs]);
206
+ // Parse and execute (Note: don't include 'validate' as it's the command name, not an argument)
207
+ await validateCmd.parseAsync(['node', 'aios', ...validateArgs]);
143
208
  } catch (_error) {
144
209
  // Fallback: Run quick validation inline
145
210
  console.log('Running installation validation...\n');
@@ -177,6 +242,67 @@ async function runValidate() {
177
242
  }
178
243
  }
179
244
 
245
+ // Helper: Run update command
246
+ async function runUpdate() {
247
+ const updateArgs = args.slice(1);
248
+ const isCheck = updateArgs.includes('--check');
249
+ const isDryRun = updateArgs.includes('--dry-run');
250
+ const isForce = updateArgs.includes('--force');
251
+ const isVerbose = updateArgs.includes('--verbose') || updateArgs.includes('-v');
252
+
253
+ try {
254
+ const updaterPath = path.join(__dirname, '..', 'packages', 'installer', 'src', 'updater', 'index.js');
255
+
256
+ if (!fs.existsSync(updaterPath)) {
257
+ console.error('❌ Updater module not found');
258
+ console.error('Please ensure AIOS-FullStack is installed correctly.');
259
+ process.exit(1);
260
+ }
261
+
262
+ const { AIOSUpdater, formatCheckResult, formatUpdateResult } = require(updaterPath);
263
+
264
+ const updater = new AIOSUpdater(process.cwd(), {
265
+ verbose: isVerbose,
266
+ force: isForce,
267
+ });
268
+
269
+ if (isCheck) {
270
+ // Check only mode
271
+ console.log('🔍 Checking for updates...\n');
272
+ const result = await updater.checkForUpdates();
273
+ console.log(formatCheckResult(result, { colors: true }));
274
+
275
+ if (result.status === 'check_failed') {
276
+ process.exit(1);
277
+ }
278
+ } else {
279
+ // Update mode
280
+ console.log('🔄 AIOS Update\n');
281
+
282
+ const result = await updater.update({
283
+ dryRun: isDryRun,
284
+ onProgress: (phase, message) => {
285
+ if (isVerbose) {
286
+ console.log(`[${phase}] ${message}`);
287
+ }
288
+ },
289
+ });
290
+
291
+ console.log(formatUpdateResult(result, { colors: true }));
292
+
293
+ if (!result.success && result.error !== 'Already up to date') {
294
+ process.exit(1);
295
+ }
296
+ }
297
+ } catch (error) {
298
+ console.error(`❌ Update error: ${error.message}`);
299
+ if (args.includes('--verbose') || args.includes('-v')) {
300
+ console.error(error.stack);
301
+ }
302
+ process.exit(1);
303
+ }
304
+ }
305
+
180
306
  // Helper: Run doctor diagnostics
181
307
  function runDoctor() {
182
308
  console.log('🏥 AIOS System Diagnostics\n');
@@ -242,46 +368,126 @@ function runDoctor() {
242
368
  }
243
369
 
244
370
  // Helper: Create new project
245
- async function initProject(projectName) {
371
+ // Helper: Show init help
372
+ function showInitHelp() {
373
+ console.log(`
374
+ Usage: npx aios-core init <project-name> [options]
375
+
376
+ Create a new AIOS project with the specified name.
377
+
378
+ Options:
379
+ --force Force creation in non-empty directory
380
+ --skip-install Skip npm dependency installation
381
+ --template <name> Use specific template (default: default)
382
+ -t <name> Shorthand for --template
383
+ -h, --help Show this help message
384
+
385
+ Available Templates:
386
+ default Full installation with all agents, tasks, and workflows
387
+ minimal Essential files only (dev agent + basic tasks)
388
+ enterprise Everything + dashboards + team integrations
389
+
390
+ Examples:
391
+ npx aios-core init my-project
392
+ npx aios-core init my-project --template minimal
393
+ npx aios-core init my-project --force --skip-install
394
+ npx aios-core init . --template enterprise
395
+ `);
396
+ }
397
+
398
+ async function initProject() {
399
+ // 1. Parse ALL args after 'init'
400
+ const initArgs = args.slice(1);
401
+
402
+ // 2. Handle --help FIRST (before creating any directories)
403
+ if (initArgs.includes('--help') || initArgs.includes('-h')) {
404
+ showInitHelp();
405
+ return;
406
+ }
407
+
408
+ // 3. Parse flags
409
+ const isForce = initArgs.includes('--force');
410
+ const skipInstall = initArgs.includes('--skip-install');
411
+
412
+ // Template with argument
413
+ const templateIndex = initArgs.findIndex((a) => a === '--template' || a === '-t');
414
+ let template = 'default';
415
+ if (templateIndex !== -1) {
416
+ template = initArgs[templateIndex + 1];
417
+ if (!template || template.startsWith('-')) {
418
+ console.error('❌ --template requires a template name');
419
+ console.error('Available templates: default, minimal, enterprise');
420
+ process.exit(1);
421
+ }
422
+ }
423
+
424
+ // Validate template
425
+ const validTemplates = ['default', 'minimal', 'enterprise'];
426
+ if (!validTemplates.includes(template)) {
427
+ console.error(`❌ Unknown template: ${template}`);
428
+ console.error(`Available templates: ${validTemplates.join(', ')}`);
429
+ process.exit(1);
430
+ }
431
+
432
+ // 4. Extract project name (anything that doesn't start with - and isn't a template value)
433
+ const projectName = initArgs.find((arg, i) => {
434
+ if (arg.startsWith('-')) return false;
435
+ // Skip if it's the value after --template
436
+ const prevArg = initArgs[i - 1];
437
+ if (prevArg === '--template' || prevArg === '-t') return false;
438
+ return true;
439
+ });
440
+
246
441
  if (!projectName) {
247
442
  console.error('❌ Project name is required');
248
- console.log('\nUsage: npx @synkra/aios-core@latest init <project-name>');
443
+ console.log('\nUsage: npx aios-core init <project-name> [options]');
444
+ console.log('Run with --help for more information.');
249
445
  process.exit(1);
250
446
  }
251
447
 
252
- // Handle "." to install in current directory
448
+ // 5. Handle "." to install in current directory
253
449
  const isCurrentDir = projectName === '.';
254
450
  const targetPath = isCurrentDir ? process.cwd() : path.join(process.cwd(), projectName);
255
451
  const displayName = isCurrentDir ? path.basename(process.cwd()) : projectName;
256
452
 
257
- console.log(`Creating new AIOS project: ${displayName}\n`);
258
-
259
- // Check if directory exists
260
- if (fs.existsSync(targetPath)) {
261
- // Allow if directory is empty or only has hidden files
453
+ // 6. Check if directory exists
454
+ if (fs.existsSync(targetPath) && !isCurrentDir) {
262
455
  const contents = fs.readdirSync(targetPath).filter((f) => !f.startsWith('.'));
263
- if (contents.length > 0 && !isCurrentDir) {
456
+ if (contents.length > 0 && !isForce) {
264
457
  console.error(`❌ Directory already exists and is not empty: ${projectName}`);
265
- console.log('Use a different name or remove the existing directory.');
458
+ console.error('Use --force to overwrite.');
266
459
  process.exit(1);
267
460
  }
268
- // Directory exists but is empty or is current dir - proceed
269
- if (!isCurrentDir) {
461
+ if (contents.length > 0 && isForce) {
462
+ console.log(`⚠️ Using --force: overwriting existing directory: ${projectName}`);
463
+ } else {
270
464
  console.log(`✓ Using existing empty directory: ${projectName}`);
271
465
  }
272
- } else {
273
- // Create project directory
466
+ } else if (!fs.existsSync(targetPath)) {
274
467
  fs.mkdirSync(targetPath, { recursive: true });
275
468
  console.log(`✓ Created directory: ${projectName}`);
276
469
  }
277
470
 
278
- // Change to project directory (if not already there)
471
+ console.log(`Creating new AIOS project: ${displayName}`);
472
+ if (template !== 'default') {
473
+ console.log(`Template: ${template}`);
474
+ }
475
+ if (skipInstall) {
476
+ console.log('Skip install: enabled');
477
+ }
478
+ console.log('');
479
+
480
+ // 7. Change to project directory (if not already there)
279
481
  if (!isCurrentDir) {
280
482
  process.chdir(targetPath);
281
483
  }
282
484
 
283
- // Run the initialization wizard
284
- await runWizard();
485
+ // 8. Run the initialization wizard with options
486
+ await runWizard({
487
+ template,
488
+ skipInstall,
489
+ force: isForce,
490
+ });
285
491
  }
286
492
 
287
493
  // Command routing (async main function)
@@ -305,9 +511,8 @@ async function main() {
305
511
  break;
306
512
 
307
513
  case 'init': {
308
- // Create new project
309
- const projectName = args[1];
310
- await initProject(projectName);
514
+ // Create new project (flags parsed inside initProject)
515
+ await initProject();
311
516
  break;
312
517
  }
313
518
 
@@ -324,10 +529,15 @@ async function main() {
324
529
  await runValidate();
325
530
  break;
326
531
 
532
+ case 'update':
533
+ // Update to latest version - Epic 7
534
+ await runUpdate();
535
+ break;
536
+
327
537
  case '--version':
328
538
  case '-v':
329
539
  case '-V':
330
- showVersion();
540
+ await showVersion();
331
541
  break;
332
542
 
333
543
  case '--help':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aios-core",
3
- "version": "3.11.0",
3
+ "version": "3.11.2",
4
4
  "description": "Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework",
5
5
  "bin": {
6
6
  "aios": "bin/aios.js",
@@ -11,6 +11,7 @@
11
11
  const fs = require('fs-extra');
12
12
  const path = require('path');
13
13
  const ora = require('ora');
14
+ const { hashFile } = require('./file-hasher');
14
15
 
15
16
  /**
16
17
  * Get the path to the source .aios-core directory in the package
@@ -75,6 +76,72 @@ function replaceRootPlaceholder(content, rootPath = '.aios-core') {
75
76
  return content.replace(/\{root\}/g, rootPath);
76
77
  }
77
78
 
79
+ /**
80
+ * Generate file hashes for installed files
81
+ * Story 7.2: Version Tracking
82
+ *
83
+ * @param {string} targetAiosCore - Path to .aios-core directory
84
+ * @param {string[]} installedFiles - List of installed files (relative to .aios-core)
85
+ * @returns {Promise<Object>} Object mapping file paths to their sha256 hashes
86
+ */
87
+ async function generateFileHashes(targetAiosCore, installedFiles) {
88
+ const fileHashes = {};
89
+
90
+ for (const filePath of installedFiles) {
91
+ const absolutePath = path.join(targetAiosCore, filePath);
92
+
93
+ try {
94
+ if (await fs.pathExists(absolutePath)) {
95
+ const stats = await fs.stat(absolutePath);
96
+ if (stats.isFile()) {
97
+ const hash = hashFile(absolutePath);
98
+ fileHashes[filePath] = `sha256:${hash}`;
99
+ }
100
+ }
101
+ } catch (_error) {
102
+ // Skip files that can't be hashed (permissions, etc.)
103
+ continue;
104
+ }
105
+ }
106
+
107
+ return fileHashes;
108
+ }
109
+
110
+ /**
111
+ * Generate version.json for installation tracking
112
+ * Story 7.2: Version Tracking - Enables update command to detect changes
113
+ *
114
+ * @param {Object} options - Options
115
+ * @param {string} options.targetAiosCore - Path to .aios-core directory
116
+ * @param {string} options.version - Package version
117
+ * @param {string[]} options.installedFiles - List of installed files
118
+ * @param {string} [options.mode='project-development'] - Installation mode
119
+ * @returns {Promise<Object>} version.json content
120
+ */
121
+ async function generateVersionJson(options) {
122
+ const {
123
+ targetAiosCore,
124
+ version,
125
+ installedFiles,
126
+ mode = 'project-development',
127
+ } = options;
128
+
129
+ const fileHashes = await generateFileHashes(targetAiosCore, installedFiles);
130
+
131
+ const versionJson = {
132
+ version,
133
+ installedAt: new Date().toISOString(),
134
+ mode,
135
+ fileHashes,
136
+ customized: [],
137
+ };
138
+
139
+ const versionJsonPath = path.join(targetAiosCore, 'version.json');
140
+ await fs.writeJson(versionJsonPath, versionJson, { spaces: 2 });
141
+
142
+ return versionJson;
143
+ }
144
+
78
145
  /**
79
146
  * Copy a single file with optional {root} replacement
80
147
  * @param {string} sourcePath - Source file path
@@ -226,8 +293,9 @@ async function installAiosCore(options = {}) {
226
293
 
227
294
  // Create install manifest
228
295
  spinner.text = 'Creating installation manifest...';
296
+ const packageVersion = require('../../../../package.json').version;
229
297
  const manifest = {
230
- version: require('../../../../package.json').version,
298
+ version: packageVersion,
231
299
  installed_at: new Date().toISOString(),
232
300
  install_type: 'full',
233
301
  files: result.installedFiles,
@@ -239,6 +307,16 @@ async function installAiosCore(options = {}) {
239
307
  'utf8',
240
308
  );
241
309
 
310
+ // Story 7.2: Create version.json with file hashes for update tracking
311
+ spinner.text = 'Generating version tracking info...';
312
+ const versionInfo = await generateVersionJson({
313
+ targetAiosCore,
314
+ version: packageVersion,
315
+ installedFiles: result.installedFiles,
316
+ mode: 'project-development',
317
+ });
318
+ result.versionInfo = versionInfo;
319
+
242
320
  result.success = true;
243
321
  spinner.succeed(`AIOS core installed (${result.installedFiles.length} files)`);
244
322
 
@@ -314,6 +392,8 @@ module.exports = {
314
392
  getAiosCoreSourcePath,
315
393
  copyFileWithRootReplacement,
316
394
  copyDirectoryWithRootReplacement,
395
+ generateVersionJson,
396
+ generateFileHashes,
317
397
  FOLDERS_TO_COPY,
318
398
  ROOT_FILES_TO_COPY,
319
399
  };