aios-core 4.2.9 → 4.2.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.
@@ -7,8 +7,8 @@
7
7
  # - SHA256 hashes for change detection
8
8
  # - File types for categorization
9
9
  #
10
- version: 4.2.9
11
- generated_at: "2026-02-16T15:01:11.763Z"
10
+ version: 4.2.11
11
+ generated_at: "2026-02-16T17:42:52.251Z"
12
12
  generator: scripts/generate-install-manifest.js
13
13
  file_count: 1004
14
14
  files:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aios-core",
3
- "version": "4.2.9",
3
+ "version": "4.2.11",
4
4
  "description": "Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework",
5
5
  "bin": {
6
6
  "aios": "bin/aios.js",
@@ -127,6 +127,16 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) {
127
127
  onProgress({ item: 'pro-config', status: 'done', message: 'Pro config merged into core-config.yaml' });
128
128
  }
129
129
 
130
+ // Install squad agent commands to IDEs
131
+ const commandsResult = await installSquadCommands(targetDir);
132
+ if (commandsResult.installed > 0) {
133
+ result.copiedFiles.push(...commandsResult.files);
134
+ if (onProgress) {
135
+ onProgress({ item: 'squad-commands', status: 'done',
136
+ message: `${commandsResult.installed} squad agent commands installed` });
137
+ }
138
+ }
139
+
130
140
  // Generate pro-version.json (AC4)
131
141
  const versionInfo = await generateProVersionJson(targetDir, proSourceDir, result.copiedFiles);
132
142
  result.versionInfo = versionInfo;
@@ -372,6 +382,59 @@ async function mergeProConfig(targetDir) {
372
382
  return true;
373
383
  }
374
384
 
385
+ /**
386
+ * Install squad agent commands into active IDE directories.
387
+ * Detects which IDEs are configured and copies agent .md files accordingly.
388
+ *
389
+ * @param {string} targetDir - Project root directory
390
+ * @returns {Promise<Object>} Result with installed count and file list
391
+ */
392
+ async function installSquadCommands(targetDir) {
393
+ const squadsDir = path.join(targetDir, 'squads');
394
+ if (!await fs.pathExists(squadsDir)) return { installed: 0, files: [] };
395
+
396
+ const ideTargets = [
397
+ { check: path.join('.claude', 'commands'), dest: (squad) => path.join('.claude', 'commands', squad) },
398
+ { check: path.join('.codex', 'agents'), dest: () => path.join('.codex', 'agents') },
399
+ { check: path.join('.gemini', 'rules'), dest: (squad) => path.join('.gemini', 'rules', squad) },
400
+ { check: path.join('.cursor', 'rules'), dest: () => path.join('.cursor', 'rules') },
401
+ ];
402
+
403
+ const activeIDEs = [];
404
+ for (const ide of ideTargets) {
405
+ if (await fs.pathExists(path.join(targetDir, ide.check))) {
406
+ activeIDEs.push(ide);
407
+ }
408
+ }
409
+ if (activeIDEs.length === 0) return { installed: 0, files: [] };
410
+
411
+ const files = [];
412
+ const items = await fs.readdir(squadsDir, { withFileTypes: true });
413
+
414
+ for (const item of items) {
415
+ if (!item.isDirectory()) continue;
416
+ const agentsDir = path.join(squadsDir, item.name, 'agents');
417
+ if (!await fs.pathExists(agentsDir)) continue;
418
+
419
+ const agentFiles = (await fs.readdir(agentsDir))
420
+ .filter(f => f.endsWith('.md') && !f.startsWith('test-'));
421
+
422
+ for (const ide of activeIDEs) {
423
+ const destDir = path.join(targetDir, ide.dest(item.name));
424
+ await fs.ensureDir(destDir);
425
+ for (const agentFile of agentFiles) {
426
+ await fs.copy(
427
+ path.join(agentsDir, agentFile),
428
+ path.join(destDir, agentFile)
429
+ );
430
+ files.push(path.relative(targetDir, path.join(destDir, agentFile)).replace(/\\/g, '/'));
431
+ }
432
+ }
433
+ }
434
+
435
+ return { installed: files.length, files };
436
+ }
437
+
375
438
  module.exports = {
376
439
  scaffoldProContent,
377
440
  scaffoldDirectory,
@@ -380,6 +443,7 @@ module.exports = {
380
443
  generateInstalledManifest,
381
444
  rollbackScaffold,
382
445
  mergeProConfig,
446
+ installSquadCommands,
383
447
  SCAFFOLD_ITEMS,
384
448
  SCAFFOLD_EXCLUDES,
385
449
  };
@@ -772,6 +772,11 @@ async function activateProByAuth(client, sessionToken) {
772
772
  showInfo('Deactivate another device or upgrade your license.');
773
773
  return { success: false, error: error.message };
774
774
  }
775
+ if (error.code === 'ALREADY_ACTIVATED') {
776
+ // License already exists — treat as success (re-install scenario)
777
+ spinner.succeed('Pro license already activated for this account.');
778
+ return { success: true, key: 'existing', activationResult: { reactivation: true } };
779
+ }
775
780
 
776
781
  spinner.fail(`Activation failed: ${error.message}`);
777
782
  return { success: false, error: error.message };
@@ -132,14 +132,20 @@ class LicenseApiClient {
132
132
  return;
133
133
  }
134
134
 
135
+ // Normalize server error envelope: { error: { code, message, details } } → flat
136
+ const err = response.error || response;
137
+ const code = err.code;
138
+ const message = err.message;
139
+ const details = err.details;
140
+
135
141
  // Client errors
136
142
  switch (statusCode) {
137
143
  case 400:
138
144
  reject(
139
145
  new LicenseActivationError(
140
- response.message || 'Invalid request',
141
- response.code || 'BAD_REQUEST',
142
- response.details,
146
+ message || 'Invalid request',
147
+ code || 'BAD_REQUEST',
148
+ details,
143
149
  ),
144
150
  );
145
151
  break;
@@ -149,28 +155,28 @@ class LicenseApiClient {
149
155
  break;
150
156
 
151
157
  case 403:
152
- if (response.code === 'EXPIRED_KEY') {
158
+ if (code === 'EXPIRED_KEY') {
153
159
  reject(LicenseActivationError.expiredKey());
154
- } else if (response.code === 'SEAT_LIMIT_EXCEEDED') {
160
+ } else if (code === 'SEAT_LIMIT_EXCEEDED') {
155
161
  reject(
156
162
  LicenseActivationError.seatLimitExceeded(
157
- response.details?.used || 0,
158
- response.details?.max || 0,
163
+ details?.used || 0,
164
+ details?.max || 0,
159
165
  ),
160
166
  );
161
167
  } else {
162
168
  reject(
163
169
  new LicenseActivationError(
164
- response.message || 'Access forbidden',
165
- response.code || 'FORBIDDEN',
166
- response.details,
170
+ message || 'Access forbidden',
171
+ code || 'FORBIDDEN',
172
+ details,
167
173
  ),
168
174
  );
169
175
  }
170
176
  break;
171
177
 
172
178
  case 429:
173
- reject(LicenseActivationError.rateLimited(response.retryAfter));
179
+ reject(LicenseActivationError.rateLimited(err.retryAfter || response.retryAfter));
174
180
  break;
175
181
 
176
182
  case 500:
@@ -178,12 +184,12 @@ class LicenseApiClient {
178
184
  case 503:
179
185
  case 504:
180
186
  // Preserve server error code if provided (e.g., BUYER_SERVICE_UNAVAILABLE)
181
- if (response.code) {
187
+ if (code) {
182
188
  reject(
183
189
  new LicenseActivationError(
184
- response.message || 'Server error',
185
- response.code,
186
- response.details,
190
+ message || 'Server error',
191
+ code,
192
+ details,
187
193
  ),
188
194
  );
189
195
  } else {