aiox-core 5.0.7 → 5.0.8

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 (191) hide show
  1. package/.aiox-core/cli/commands/pro/buyer.js +379 -0
  2. package/.aiox-core/cli/commands/pro/index.js +191 -52
  3. package/.aiox-core/cli/commands/validate/index.js +2 -0
  4. package/.aiox-core/core/code-intel/helpers/dev-helper.js +1 -1
  5. package/.aiox-core/core/code-intel/helpers/devops-helper.js +0 -1
  6. package/.aiox-core/core/code-intel/helpers/planning-helper.js +1 -1
  7. package/.aiox-core/core/code-intel/helpers/qa-helper.js +2 -2
  8. package/.aiox-core/core/config/schemas/framework-config.schema.json +1 -0
  9. package/.aiox-core/core/config/template-overrides.js +1 -1
  10. package/.aiox-core/core/doctor/checks/ide-sync.js +81 -25
  11. package/.aiox-core/core/doctor/checks/rules-files.js +0 -1
  12. package/.aiox-core/core/doctor/checks/skills-count.js +83 -15
  13. package/.aiox-core/core/graph-dashboard/cli.js +1 -2
  14. package/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
  15. package/.aiox-core/core/ids/layer-classifier.js +1 -1
  16. package/.aiox-core/core/pro/pro-updater.js +578 -0
  17. package/.aiox-core/core/synapse/context/context-tracker.js +107 -9
  18. package/.aiox-core/core/synapse/layers/layer-processor.js +1 -1
  19. package/.aiox-core/core-config.yaml +15 -1
  20. package/.aiox-core/data/capability-detection.js +15 -15
  21. package/.aiox-core/data/entity-registry.yaml +18 -2
  22. package/.aiox-core/data/registry-update-log.jsonl +5 -0
  23. package/.aiox-core/data/tok3-token-comparison.js +0 -4
  24. package/.aiox-core/data/tool-search-validation.js +1 -1
  25. package/.aiox-core/development/agents/aiox-master.md +44 -6
  26. package/.aiox-core/development/agents/data-engineer.md +4 -4
  27. package/.aiox-core/development/agents/devops.md +52 -2
  28. package/.aiox-core/development/agents/po.md +1 -1
  29. package/.aiox-core/development/agents/qa.md +5 -11
  30. package/.aiox-core/development/agents/sm.md +3 -3
  31. package/.aiox-core/development/agents/ux-design-expert.md +1 -1
  32. package/.aiox-core/development/scripts/unified-activation-pipeline.js +29 -3
  33. package/.aiox-core/development/tasks/dev-develop-story.md +46 -7
  34. package/.aiox-core/development/tasks/devops-pro-access-grant.md +93 -0
  35. package/.aiox-core/development/tasks/devops-pro-activate.md +42 -0
  36. package/.aiox-core/development/tasks/devops-pro-check-access.md +34 -0
  37. package/.aiox-core/development/tasks/devops-pro-request-reset.md +34 -0
  38. package/.aiox-core/development/tasks/devops-pro-resend-verification.md +32 -0
  39. package/.aiox-core/development/tasks/devops-pro-reset-password.md +36 -0
  40. package/.aiox-core/development/tasks/devops-pro-validate-login.md +36 -0
  41. package/.aiox-core/development/tasks/devops-pro-verify-status.md +33 -0
  42. package/.aiox-core/development/tasks/qa-gate.md +54 -4
  43. package/.aiox-core/development/tasks/validate-next-story.md +39 -2
  44. package/.aiox-core/framework-config.yaml +1 -0
  45. package/.aiox-core/infrastructure/scripts/codex-skills-sync/README.md +69 -0
  46. package/.aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js +727 -0
  47. package/.aiox-core/infrastructure/scripts/codex-skills-sync/index.js +10 -0
  48. package/.aiox-core/infrastructure/scripts/codex-skills-sync/validate.js +65 -4
  49. package/.aiox-core/infrastructure/scripts/generate-settings-json.js +29 -4
  50. package/.aiox-core/infrastructure/scripts/ide-sync/agent-parser.js +4 -0
  51. package/.aiox-core/infrastructure/scripts/ide-sync/index.js +67 -7
  52. package/.aiox-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +145 -3
  53. package/.aiox-core/infrastructure/scripts/repair-agent-references.js +263 -0
  54. package/.aiox-core/infrastructure/scripts/validate-claude-integration.js +60 -8
  55. package/.aiox-core/infrastructure/scripts/validate-paths.js +13 -0
  56. package/.aiox-core/install-manifest.yaml +134 -82
  57. package/.aiox-core/utils/filters/index.js +2 -1
  58. package/.claude/commands/AIOX/agents/aiox-master.md +21 -0
  59. package/.claude/commands/AIOX/agents/analyst.md +21 -0
  60. package/.claude/commands/AIOX/agents/architect.md +21 -0
  61. package/.claude/commands/AIOX/agents/data-engineer.md +21 -0
  62. package/.claude/commands/AIOX/agents/dev.md +21 -0
  63. package/.claude/commands/AIOX/agents/devops.md +21 -0
  64. package/.claude/commands/AIOX/agents/pm.md +21 -0
  65. package/.claude/commands/AIOX/agents/po.md +21 -0
  66. package/.claude/commands/AIOX/agents/qa.md +21 -0
  67. package/.claude/commands/AIOX/agents/sm.md +21 -0
  68. package/.claude/commands/AIOX/agents/squad-creator.md +21 -0
  69. package/.claude/commands/AIOX/agents/ux-design-expert.md +21 -0
  70. package/.claude/commands/AIOX/scripts/agent-config-loader.js +624 -0
  71. package/.claude/commands/AIOX/scripts/generate-greeting.js +160 -0
  72. package/.claude/commands/AIOX/scripts/greeting-builder.js +866 -0
  73. package/.claude/commands/AIOX/scripts/session-context-loader.js +286 -0
  74. package/.claude/commands/AIOX/stories/story-6.1.4.md +1404 -0
  75. package/.claude/commands/cohort-squad/agents/cohort-manager.md +156 -0
  76. package/.claude/commands/design-system/agents/brad-frost.md +1097 -0
  77. package/.claude/commands/design-system/agents/dan-mall.md +857 -0
  78. package/.claude/commands/design-system/agents/dave-malouf.md +2272 -0
  79. package/.claude/commands/design-system/agents/design-chief.md +102 -0
  80. package/.claude/commands/design-system/agents/nano-banana-generator.md +162 -0
  81. package/.claude/commands/greet.md +101 -0
  82. package/.claude/commands/synapse/manager.md +75 -0
  83. package/.claude/commands/synapse/tasks/add-rule.md +94 -0
  84. package/.claude/commands/synapse/tasks/create-command.md +109 -0
  85. package/.claude/commands/synapse/tasks/create-domain.md +127 -0
  86. package/.claude/commands/synapse/tasks/diagnose-synapse.md +245 -0
  87. package/.claude/commands/synapse/tasks/edit-rule.md +109 -0
  88. package/.claude/commands/synapse/tasks/suggest-domain.md +116 -0
  89. package/.claude/commands/synapse/tasks/toggle-domain.md +83 -0
  90. package/.claude/commands/synapse/templates/domain-template +8 -0
  91. package/.claude/commands/synapse/templates/manifest-entry-template +4 -0
  92. package/.claude/commands/synapse/utils/manifest-parser-reference.md +134 -0
  93. package/.claude/hooks/precompact-session-digest.cjs +2 -2
  94. package/.claude/skills/AIOX/agents/aiox-master/SKILL.md +511 -0
  95. package/.claude/skills/AIOX/agents/analyst/SKILL.md +281 -0
  96. package/.claude/skills/AIOX/agents/architect/SKILL.md +482 -0
  97. package/.claude/skills/AIOX/agents/data-engineer/SKILL.md +503 -0
  98. package/.claude/skills/AIOX/agents/dev/SKILL.md +568 -0
  99. package/.claude/skills/AIOX/agents/devops/SKILL.md +597 -0
  100. package/.claude/skills/AIOX/agents/pm/SKILL.md +385 -0
  101. package/.claude/skills/AIOX/agents/po/SKILL.md +343 -0
  102. package/.claude/skills/AIOX/agents/qa/SKILL.md +451 -0
  103. package/.claude/skills/AIOX/agents/sm/SKILL.md +295 -0
  104. package/.claude/skills/AIOX/agents/squad-creator/SKILL.md +352 -0
  105. package/.claude/skills/AIOX/agents/ux-design-expert/SKILL.md +503 -0
  106. package/.claude/skills/architect-first/SKILL.md +275 -0
  107. package/.claude/skills/architect-first/assets/architecture-template.md +505 -0
  108. package/.claude/skills/architect-first/assets/config-template.yaml +351 -0
  109. package/.claude/skills/architect-first/references/architecture-checklist.md +216 -0
  110. package/.claude/skills/architect-first/references/pre-implementation-checklist.md +119 -0
  111. package/.claude/skills/architect-first/references/stop-rules-guide.md +291 -0
  112. package/.claude/skills/architect-first/references/testing-strategy-guide.md +477 -0
  113. package/.claude/skills/architect-first/scripts/architecture_validator.py +490 -0
  114. package/.claude/skills/architect-first/scripts/check_coupling.py +306 -0
  115. package/.claude/skills/architect-first/scripts/validate_risk_mitigation.py +382 -0
  116. package/.claude/skills/checklist-runner/SKILL.md +113 -0
  117. package/.claude/skills/clone-mind.md +329 -0
  118. package/.claude/skills/coderabbit-review/SKILL.md +106 -0
  119. package/.claude/skills/course-generation-workflow.md +76 -0
  120. package/.claude/skills/enhance-workflow.md +466 -0
  121. package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
  122. package/.claude/skills/mcp-builder/SKILL.md +328 -0
  123. package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
  124. package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
  125. package/.claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
  126. package/.claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
  127. package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
  128. package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
  129. package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  130. package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
  131. package/.claude/skills/ralph.md +181 -0
  132. package/.claude/skills/skill-creator/LICENSE.txt +202 -0
  133. package/.claude/skills/skill-creator/SKILL.md +209 -0
  134. package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
  135. package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
  136. package/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
  137. package/.claude/skills/squad.md +301 -0
  138. package/.claude/skills/synapse/SKILL.md +132 -0
  139. package/.claude/skills/synapse/assets/README.md +50 -0
  140. package/.claude/skills/synapse/references/brackets.md +100 -0
  141. package/.claude/skills/synapse/references/commands.md +118 -0
  142. package/.claude/skills/synapse/references/domains.md +126 -0
  143. package/.claude/skills/synapse/references/layers.md +186 -0
  144. package/.claude/skills/synapse/references/manifest.md +142 -0
  145. package/.claude/skills/tech-search/SKILL.md +431 -0
  146. package/.claude/skills/tech-search/prompts/page-extract.md +133 -0
  147. package/README.en.md +2 -2
  148. package/README.md +8 -2
  149. package/bin/aiox.js +55 -4
  150. package/bin/utils/framework-guard.js +4 -2
  151. package/bin/utils/pro-detector.js +119 -28
  152. package/bin/utils/validate-publish.js +6 -6
  153. package/docs/aiox-agent-flows/devops-system.md +18 -0
  154. package/docs/aiox-workflows/README.md +1 -0
  155. package/docs/aiox-workflows/pro-access-grant-workflow.md +218 -0
  156. package/docs/guides/pro/access-grant-ops-playbook.md +370 -0
  157. package/docs/guides/pro/install-gate-setup.md +12 -6
  158. package/docs/guides/pro/squad-creator-handoff-pro-access-ops.md +134 -0
  159. package/docs/guides/supabase-ops-handoff.md +768 -0
  160. package/package.json +12 -1
  161. package/packages/aiox-pro-cli/bin/aiox-pro.js +33 -12
  162. package/packages/installer/src/config/configure-environment.js +118 -50
  163. package/packages/installer/src/installer/aiox-core-installer.js +124 -27
  164. package/packages/installer/src/installer/brownfield-upgrader.js +66 -9
  165. package/packages/installer/src/installer/dependency-installer.js +4 -0
  166. package/packages/installer/src/pro/pro-scaffolder.js +5 -5
  167. package/packages/installer/src/updater/index.js +151 -10
  168. package/packages/installer/src/wizard/ide-config-generator.js +73 -7
  169. package/packages/installer/src/wizard/index.js +119 -31
  170. package/packages/installer/src/wizard/pro-setup.js +118 -47
  171. package/packages/installer/src/wizard/validation/validators/dependency-validator.js +32 -25
  172. package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +26 -0
  173. package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +84 -1
  174. package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +1 -1
  175. package/packages/installer/tests/unit/doctor/doctor-checks.test.js +85 -19
  176. package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +4 -4
  177. package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +5 -5
  178. package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +4 -4
  179. package/packages/installer/tests/unit/merger/yaml-merger.test.js +11 -11
  180. package/pro/README.md +12 -1
  181. package/pro/license/index.js +3 -11
  182. package/pro/license/license-api.js +25 -0
  183. package/pro/license/license-cache.js +135 -31
  184. package/pro/license/license-crypto.js +59 -3
  185. package/pro/package.json +5 -4
  186. package/pro/squads/README.md +16 -16
  187. package/pro/squads/index.js +1 -1
  188. package/scripts/e2e/installed-skills-smoke.js +264 -0
  189. package/scripts/package-synapse.js +3 -3
  190. package/scripts/validate-package-completeness.js +8 -11
  191. package/.aiox-core/lib/build.json +0 -1
@@ -53,10 +53,38 @@ function loadManifest(basePath, manifestName = 'install-manifest.yaml') {
53
53
  * @returns {Object|null} - Installed manifest or null if not found
54
54
  */
55
55
  function loadInstalledManifest(targetDir) {
56
- return loadManifest(
56
+ const installedManifest = loadManifest(
57
57
  path.join(targetDir, '.aiox-core'),
58
58
  '.installed-manifest.yaml',
59
59
  );
60
+
61
+ if (installedManifest) {
62
+ return installedManifest;
63
+ }
64
+
65
+ const versionJsonPath = path.join(targetDir, '.aiox-core', 'version.json');
66
+ if (!fs.existsSync(versionJsonPath)) {
67
+ return null;
68
+ }
69
+
70
+ try {
71
+ const versionInfo = fs.readJsonSync(versionJsonPath);
72
+ if (!versionInfo || !versionInfo.version || !versionInfo.fileHashes) {
73
+ return null;
74
+ }
75
+
76
+ return {
77
+ installed_version: versionInfo.version,
78
+ files: Object.entries(versionInfo.fileHashes).map(([filePath, hash]) => ({
79
+ path: filePath,
80
+ hash,
81
+ modified_by_user: false,
82
+ })),
83
+ };
84
+ } catch (error) {
85
+ console.warn(`Error loading version.json from ${versionJsonPath}:`, error.message);
86
+ return null;
87
+ }
60
88
  }
61
89
 
62
90
  /**
@@ -150,13 +178,42 @@ function generateUpgradeReport(sourceManifest, installedManifest, targetDir) {
150
178
  const absolutePath = path.join(aioxCoreDir, filePath);
151
179
 
152
180
  if (!installedEntry) {
153
- // New file in source
154
- report.newFiles.push({
155
- path: filePath,
156
- type: sourceEntry.type,
157
- hash: sourceEntry.hash,
158
- size: sourceEntry.size,
159
- });
181
+ // File is not tracked by the installed manifest.
182
+ // In older releases some files existed on disk without being recorded
183
+ // in version metadata. Preserve those local files instead of
184
+ // overwriting them as "new" framework files.
185
+ if (fs.existsSync(absolutePath)) {
186
+ try {
187
+ const currentHash = `sha256:${hashFile(absolutePath)}`;
188
+ if (hashesMatch(currentHash, sourceEntry.hash)) {
189
+ report.unchangedFiles++;
190
+ } else {
191
+ report.userModifiedFiles.push({
192
+ path: filePath,
193
+ type: sourceEntry.type,
194
+ sourceHash: sourceEntry.hash,
195
+ installedHash: null,
196
+ reason: 'Local file exists but is not tracked by installed manifest',
197
+ });
198
+ }
199
+ } catch {
200
+ report.userModifiedFiles.push({
201
+ path: filePath,
202
+ type: sourceEntry.type,
203
+ sourceHash: sourceEntry.hash,
204
+ installedHash: null,
205
+ reason: 'Local file exists but could not be hashed',
206
+ });
207
+ }
208
+ } else {
209
+ // New file in source
210
+ report.newFiles.push({
211
+ path: filePath,
212
+ type: sourceEntry.type,
213
+ hash: sourceEntry.hash,
214
+ size: sourceEntry.size,
215
+ });
216
+ }
160
217
  } else if (!hashesMatch(sourceEntry.hash, installedEntry.hash)) {
161
218
  // File changed in source
162
219
  // Check if user modified the local copy
@@ -287,7 +344,7 @@ async function applyUpgrade(report, sourceDir, targetDir, options = {}) {
287
344
  result.mergeWarnings = result.mergeWarnings || [];
288
345
  for (const conflict of conflicts) {
289
346
  result.mergeWarnings.push(
290
- `core-config.yaml: ${conflict.identifier} — ${conflict.reason}`
347
+ `core-config.yaml: ${conflict.identifier} — ${conflict.reason}`,
291
348
  );
292
349
  }
293
350
  }
@@ -271,6 +271,7 @@ async function installDependencies(options = {}) {
271
271
  success: true,
272
272
  offlineMode: true,
273
273
  packageManager,
274
+ projectPath,
274
275
  };
275
276
  }
276
277
 
@@ -290,6 +291,7 @@ async function installDependencies(options = {}) {
290
291
  return {
291
292
  success: true,
292
293
  packageManager,
294
+ projectPath,
293
295
  };
294
296
  } else {
295
297
  spinner.fail('Installation failed');
@@ -300,6 +302,7 @@ async function installDependencies(options = {}) {
300
302
  return {
301
303
  success: false,
302
304
  packageManager,
305
+ projectPath,
303
306
  error: result.error,
304
307
  errorCategory: errorInfo.category,
305
308
  errorMessage: errorInfo.message,
@@ -315,6 +318,7 @@ async function installDependencies(options = {}) {
315
318
 
316
319
  return {
317
320
  success: false,
321
+ projectPath,
318
322
  error: error.message,
319
323
  errorCategory: errorInfo.category,
320
324
  errorMessage: errorInfo.message,
@@ -2,7 +2,7 @@
2
2
  * Pro Content Scaffolder
3
3
  *
4
4
  * Copies premium content (squads, configs, feature registry) from
5
- * node_modules/@aiox-fullstack/pro/ into the user's project after
5
+ * node_modules/@aiox-squads/pro/ (or a legacy Pro scope) into the user's project after
6
6
  * license activation.
7
7
  *
8
8
  * @module packages/installer/src/pro/pro-scaffolder
@@ -55,7 +55,7 @@ const SCAFFOLD_ITEMS = [
55
55
  * Scaffold pro content into user project.
56
56
  *
57
57
  * @param {string} targetDir - Project root directory
58
- * @param {string} proSourceDir - Path to pro package content (node_modules/@aiox-fullstack/pro)
58
+ * @param {string} proSourceDir - Path to pro package content (node_modules/@aiox-squads/pro or legacy scopes)
59
59
  * @param {Object} [options={}] - Scaffold options
60
60
  * @param {Function} [options.onProgress] - Progress callback ({item, status, message})
61
61
  * @param {boolean} [options.force=false] - Force overwrite even if content exists
@@ -80,7 +80,7 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) {
80
80
  // Validate pro source exists
81
81
  if (!await fs.pathExists(proSourceDir)) {
82
82
  result.errors.push(
83
- `Pro package not found at ${proSourceDir}. Run "npm install @aiox-fullstack/pro" first.`
83
+ `Pro package not found at ${proSourceDir}. Run "npx aiox-pro install" or "aiox pro setup" first.`,
84
84
  );
85
85
  return result;
86
86
  }
@@ -160,7 +160,7 @@ async function scaffoldProContent(targetDir, proSourceDir, options = {}) {
160
160
  result.errors.push(`Rollback errors: ${rollbackResult.errors.join(', ')}`);
161
161
  }
162
162
  result.warnings.push(
163
- `Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up.`
163
+ `Scaffolding failed: ${error.message}. ${rollbackResult.removed} files cleaned up.`,
164
164
  );
165
165
  }
166
166
 
@@ -425,7 +425,7 @@ async function installSquadCommands(targetDir) {
425
425
  for (const agentFile of agentFiles) {
426
426
  await fs.copy(
427
427
  path.join(agentsDir, agentFile),
428
- path.join(destDir, agentFile)
428
+ path.join(destDir, agentFile),
429
429
  );
430
430
  files.push(path.relative(targetDir, path.join(destDir, agentFile)).replace(/\\/g, '/'));
431
431
  }
@@ -22,6 +22,91 @@ const https = require('https');
22
22
  const { execSync } = require('child_process');
23
23
  const { hashFile, hashesMatch } = require('../installer/file-hasher');
24
24
  const { PostInstallValidator, formatReport: formatValidationReport } = require('../installer/post-install-validator');
25
+ const {
26
+ loadSourceManifest,
27
+ loadInstalledManifest,
28
+ generateUpgradeReport,
29
+ applyUpgrade,
30
+ updateInstalledManifest,
31
+ } = require('../installer/brownfield-upgrader');
32
+
33
+ function manifestToInstalledManifest(manifest) {
34
+ if (!manifest || !Array.isArray(manifest.files)) {
35
+ return null;
36
+ }
37
+
38
+ return {
39
+ installed_version: manifest.version || 'unknown',
40
+ files: manifest.files
41
+ .filter((entry) => entry && entry.path && entry.hash)
42
+ .map((entry) => ({
43
+ path: entry.path,
44
+ hash: entry.hash,
45
+ type: entry.type,
46
+ modified_by_user: false,
47
+ })),
48
+ };
49
+ }
50
+
51
+ function extractManifestFileHashes(manifest) {
52
+ if (!manifest || !Array.isArray(manifest.files)) {
53
+ return {};
54
+ }
55
+
56
+ const fileHashes = {};
57
+ for (const entry of manifest.files) {
58
+ if (entry && entry.path && entry.hash) {
59
+ fileHashes[entry.path] = entry.hash;
60
+ }
61
+ }
62
+
63
+ return fileHashes;
64
+ }
65
+
66
+ function selectInstalledManifest(projectManifest, packageManifest) {
67
+ if (!projectManifest) {
68
+ return packageManifest;
69
+ }
70
+
71
+ if (!packageManifest) {
72
+ return projectManifest;
73
+ }
74
+
75
+ const projectFiles = Array.isArray(projectManifest.files) ? projectManifest.files : [];
76
+ const packageFiles = Array.isArray(packageManifest.files) ? packageManifest.files : [];
77
+
78
+ if (packageFiles.length === 0) {
79
+ return projectManifest;
80
+ }
81
+
82
+ if (projectFiles.length === 0) {
83
+ return packageManifest;
84
+ }
85
+
86
+ const mergedFiles = new Map();
87
+
88
+ for (const entry of packageFiles) {
89
+ if (entry && entry.path) {
90
+ mergedFiles.set(entry.path, entry);
91
+ }
92
+ }
93
+
94
+ for (const entry of projectFiles) {
95
+ if (entry && entry.path && !mergedFiles.has(entry.path)) {
96
+ mergedFiles.set(entry.path, entry);
97
+ }
98
+ }
99
+
100
+ return {
101
+ ...projectManifest,
102
+ installed_version:
103
+ packageManifest.installed_version ||
104
+ packageManifest.version ||
105
+ projectManifest.installed_version ||
106
+ projectManifest.version,
107
+ files: Array.from(mergedFiles.values()),
108
+ };
109
+ }
25
110
 
26
111
  /**
27
112
  * Update status types
@@ -78,6 +163,8 @@ class AIOXUpdater {
78
163
  this.versionInfo = null;
79
164
  this.changelog = null;
80
165
  this.backupDir = null;
166
+ this.lastSourcePackageRoot = null;
167
+ this.lastSourceManifest = null;
81
168
  }
82
169
 
83
170
  /**
@@ -467,15 +554,21 @@ class AIOXUpdater {
467
554
  }
468
555
 
469
556
  result.filesUpdated = updateApplied.filesUpdated;
470
- result.filesPreserved = customizations.customized.length;
557
+ result.filesPreserved = updateApplied.filesSkipped?.length || customizations.customized.length;
558
+ this.lastSourcePackageRoot = updateApplied.sourcePackageRoot || this.lastSourcePackageRoot;
559
+ this.lastSourceManifest = updateApplied.sourceManifest || this.lastSourceManifest;
471
560
 
472
561
  // Update version.json
473
562
  onProgress('finalizing', 'Updating version info...');
474
- await this.updateVersionInfo(checkResult.latest);
563
+ await this.updateVersionInfo(checkResult.latest, {
564
+ fileHashes: extractManifestFileHashes(this.lastSourceManifest),
565
+ });
475
566
 
476
567
  // Validate installation after update
477
568
  onProgress('validating', 'Validating installation...');
478
- const validationResult = await this.validateAfterUpdate();
569
+ const validationResult = await this.validateAfterUpdate({
570
+ sourceDir: this.lastSourcePackageRoot,
571
+ });
479
572
  result.validationPassed = validationResult.success;
480
573
  result.integrityScore = validationResult.integrityScore;
481
574
 
@@ -525,6 +618,7 @@ class AIOXUpdater {
525
618
  const filesToBackup = [
526
619
  'version.json',
527
620
  'install-manifest.yaml',
621
+ 'install-manifest.yaml.minisig',
528
622
  ];
529
623
 
530
624
  for (const file of filesToBackup) {
@@ -586,6 +680,9 @@ class AIOXUpdater {
586
680
  };
587
681
 
588
682
  try {
683
+ const previousPackageRoot = path.join(this.projectRoot, 'node_modules', 'aiox-core');
684
+ const previousSourceManifest = loadSourceManifest(path.join(previousPackageRoot, '.aiox-core'));
685
+
589
686
  // Use npm to update the package
590
687
  const cmd = `npm install aiox-core@${targetVersion} --save-exact`;
591
688
  this.log(`Running: ${cmd}`);
@@ -596,11 +693,54 @@ class AIOXUpdater {
596
693
  timeout: 120000, // 2 minutes
597
694
  });
598
695
 
599
- result.success = true;
600
- result.filesUpdated = 1; // At least package updated
696
+ const sourcePackageRoot = path.join(this.projectRoot, 'node_modules', 'aiox-core');
697
+ const sourceAioxCore = path.join(sourcePackageRoot, '.aiox-core');
698
+ const sourceManifest = loadSourceManifest(sourceAioxCore);
699
+
700
+ if (!sourceManifest) {
701
+ result.error = 'Updated package does not contain install-manifest.yaml';
702
+ return result;
703
+ }
601
704
 
602
- // TODO: Copy new files from node_modules to .aiox-core
603
- // preserving customizedFiles
705
+ const installedManifest = selectInstalledManifest(
706
+ loadInstalledManifest(this.projectRoot),
707
+ manifestToInstalledManifest(previousSourceManifest),
708
+ );
709
+ const report = generateUpgradeReport(sourceManifest, installedManifest, this.projectRoot);
710
+ const applyResult = await applyUpgrade(report, sourceAioxCore, this.projectRoot, {
711
+ includeModified: true,
712
+ });
713
+
714
+ if (!applyResult.success) {
715
+ result.error = applyResult.errors.map((entry) => `${entry.path}: ${entry.error}`).join('; ');
716
+ return result;
717
+ }
718
+
719
+ await fs.copy(
720
+ path.join(sourceAioxCore, 'install-manifest.yaml'),
721
+ path.join(this.aioxCoreDir, 'install-manifest.yaml'),
722
+ { overwrite: true },
723
+ );
724
+
725
+ const sourceSignaturePath = path.join(sourceAioxCore, 'install-manifest.yaml.minisig');
726
+ const targetSignaturePath = path.join(this.aioxCoreDir, 'install-manifest.yaml.minisig');
727
+ if (await fs.pathExists(sourceSignaturePath)) {
728
+ await fs.copy(
729
+ sourceSignaturePath,
730
+ targetSignaturePath,
731
+ { overwrite: true },
732
+ );
733
+ } else if (await fs.pathExists(targetSignaturePath)) {
734
+ await fs.remove(targetSignaturePath);
735
+ }
736
+
737
+ updateInstalledManifest(this.projectRoot, sourceManifest, `aiox-core@${targetVersion}`);
738
+
739
+ result.success = true;
740
+ result.filesUpdated = applyResult.filesInstalled.length;
741
+ result.filesSkipped = applyResult.filesSkipped;
742
+ result.sourceManifest = sourceManifest;
743
+ result.sourcePackageRoot = sourcePackageRoot;
604
744
 
605
745
  return result;
606
746
  } catch (error) {
@@ -615,7 +755,7 @@ class AIOXUpdater {
615
755
  * @param {string} newVersion - New version
616
756
  * @returns {Promise<void>}
617
757
  */
618
- async updateVersionInfo(newVersion) {
758
+ async updateVersionInfo(newVersion, options = {}) {
619
759
  const versionJsonPath = path.join(this.aioxCoreDir, 'version.json');
620
760
 
621
761
  const versionInfo = {
@@ -623,7 +763,7 @@ class AIOXUpdater {
623
763
  installedAt: new Date().toISOString(),
624
764
  updatedAt: new Date().toISOString(),
625
765
  mode: this.versionInfo?.mode || 'project-development',
626
- fileHashes: {}, // Will be populated by file copy
766
+ fileHashes: options.fileHashes || {},
627
767
  };
628
768
 
629
769
  await fs.writeJson(versionJsonPath, versionInfo, { spaces: 2 });
@@ -646,7 +786,7 @@ class AIOXUpdater {
646
786
  };
647
787
 
648
788
  try {
649
- const validator = new PostInstallValidator(this.projectRoot, null, {
789
+ const validator = new PostInstallValidator(this.projectRoot, options.sourceDir || null, {
650
790
  verifyHashes: true,
651
791
  detectExtras: false,
652
792
  verbose: options.verbose || this.options.verbose,
@@ -809,4 +949,5 @@ module.exports = {
809
949
  FileAction,
810
950
  formatCheckResult,
811
951
  formatUpdateResult,
952
+ selectInstalledManifest,
812
953
  };
@@ -16,6 +16,7 @@ const { spawnSync } = require('child_process');
16
16
  const { getIDEConfig } = require('../config/ide-configs');
17
17
  const { validateProjectName } = require('./validators');
18
18
  const { getMergeStrategy, hasMergeStrategy } = require('../merger/index.js');
19
+ const { syncSkills } = require('../../../../.aiox-core/infrastructure/scripts/codex-skills-sync/index');
19
20
 
20
21
  /**
21
22
  * Render template with variables
@@ -83,7 +84,11 @@ async function backupFile(filePath) {
83
84
  async function promptFileExists(filePath, options = {}) {
84
85
  const { projectType, forceMerge, noMerge } = options;
85
86
  const canMerge = !noMerge && hasMergeStrategy(filePath);
86
- const isBrownfield = projectType === 'BROWNFIELD' || projectType === 'EXISTING_AIOX';
87
+ const normalizedProjectType = String(projectType || '').toLowerCase();
88
+ const isBrownfield =
89
+ normalizedProjectType === 'brownfield' ||
90
+ normalizedProjectType === 'existing_aiox' ||
91
+ normalizedProjectType === 'existing-aiox';
87
92
 
88
93
  // If force merge is set and merge is available, return merge directly
89
94
  if (forceMerge && canMerge) {
@@ -264,7 +269,7 @@ async function copyAgentFiles(projectRoot, agentFolder, ideConfig = null) {
264
269
  const targetPath = path.join(targetDir, filename);
265
270
  await fs.writeFile(targetPath, content, 'utf8');
266
271
  copiedFiles.push(targetPath);
267
- } catch (transformError) {
272
+ } catch (_transformError) {
268
273
  // Fallback: copy raw file with .agent.md extension
269
274
  const targetPath = path.join(targetDir, `${agentName}.agent.md`);
270
275
  await fs.copy(sourcePath, targetPath);
@@ -538,7 +543,7 @@ async function generateIDEConfigs(selectedIDEs, wizardState, options = {}) {
538
543
 
539
544
  // BUG-3 fix (INS-1): Copy .claude/hooks/ folder (SYNAPSE engine + precompact)
540
545
  spinner.start('Copying Claude Code hooks...');
541
- const hookFiles = await copyClaudeHooksFolder(projectRoot);
546
+ const hookFiles = await copyClaudeHooksFolder(projectRoot, wizardState);
542
547
  createdFiles.push(...hookFiles);
543
548
  if (hookFiles.length > 0) {
544
549
  createdFolders.push(path.join(projectRoot, '.claude', 'hooks'));
@@ -656,9 +661,10 @@ function showSuccessSummary(result) {
656
661
  * BUG-3 fix (INS-1): Copy .claude/hooks/ folder during installation
657
662
  * Only copies JS hooks that work without external dependencies (Python, etc.)
658
663
  * @param {string} projectRoot - Project root directory
664
+ * @param {Object} [wizardState={}] - Current wizard state
659
665
  * @returns {Promise<string[]>} List of copied files
660
666
  */
661
- async function copyClaudeHooksFolder(projectRoot) {
667
+ async function copyClaudeHooksFolder(projectRoot, wizardState = {}) {
662
668
  const sourceDir = path.join(__dirname, '..', '..', '..', '..', '.claude', 'hooks');
663
669
  const targetDir = path.join(projectRoot, '.claude', 'hooks');
664
670
  const copiedFiles = [];
@@ -674,13 +680,17 @@ async function copyClaudeHooksFolder(projectRoot) {
674
680
 
675
681
  await fs.ensureDir(targetDir);
676
682
 
677
- // Only copy JS hooks that work standalone (no Python/shell deps)
678
- const HOOKS_TO_COPY = [
683
+ const HOOKS_FREE = [
679
684
  'synapse-engine.cjs',
680
685
  'code-intel-pretool.cjs',
681
- 'precompact-session-digest.cjs',
682
686
  'README.md',
683
687
  ];
688
+ const HOOKS_PRO_ONLY = [
689
+ 'precompact-session-digest.cjs',
690
+ ];
691
+ const HOOKS_TO_COPY = shouldCopyProHooks(wizardState)
692
+ ? [...HOOKS_FREE, ...HOOKS_PRO_ONLY]
693
+ : HOOKS_FREE;
684
694
 
685
695
  const files = await fs.readdir(sourceDir);
686
696
 
@@ -702,6 +712,31 @@ async function copyClaudeHooksFolder(projectRoot) {
702
712
  return copiedFiles;
703
713
  }
704
714
 
715
+ /**
716
+ * Decide whether Pro-only hooks should be copied.
717
+ * Explicit wizard tier wins; otherwise fall back to runtime Pro detection.
718
+ * Supports wizardState.proTier as a legacy alias from older Pro setup state.
719
+ *
720
+ * @param {Object} [wizardState={}] - Current wizard state
721
+ * @returns {boolean} true when Pro-only hooks should be installed
722
+ */
723
+ function shouldCopyProHooks(wizardState = {}) {
724
+ const tier = String(wizardState.tier || wizardState.proTier || '').toLowerCase();
725
+ if (tier === 'pro') return true;
726
+ if (['free', 'community', 'core'].includes(tier)) return false;
727
+
728
+ if (wizardState.pro && typeof wizardState.pro.enabled === 'boolean') {
729
+ return wizardState.pro.enabled;
730
+ }
731
+
732
+ try {
733
+ const { isProAvailable } = require('../../../../bin/utils/pro-detector');
734
+ return isProAvailable();
735
+ } catch {
736
+ return false;
737
+ }
738
+ }
739
+
705
740
  /**
706
741
  * Hook event mapping: fileName → { event, matcher, timeout }
707
742
  * Maps each .cjs hook file to its correct Claude Code event.
@@ -1090,6 +1125,35 @@ async function copySkillFiles(projectRoot, _sourceRoot) {
1090
1125
  return { count, skipped: false };
1091
1126
  }
1092
1127
 
1128
+ /**
1129
+ * Generate project-local Codex skills from canonical agent definitions.
1130
+ * This repo uses local-first Codex activation, so installed projects must
1131
+ * include `.codex/skills` without requiring a manual post-install sync.
1132
+ * @param {string} projectRoot - Project root directory
1133
+ * @returns {{count: number, skipped: boolean}} Generation result
1134
+ */
1135
+ function generateCodexSkills(projectRoot) {
1136
+ const sourceDir = path.join(projectRoot, '.aiox-core', 'development', 'agents');
1137
+ const localSkillsDir = path.join(projectRoot, '.codex', 'skills');
1138
+
1139
+ if (!fs.existsSync(sourceDir)) {
1140
+ return { count: 0, skipped: true };
1141
+ }
1142
+
1143
+ const result = syncSkills({
1144
+ projectRoot,
1145
+ sourceDir,
1146
+ localSkillsDir,
1147
+ dryRun: false,
1148
+ quiet: true,
1149
+ });
1150
+
1151
+ return {
1152
+ count: result.generated || 0,
1153
+ skipped: false,
1154
+ };
1155
+ }
1156
+
1093
1157
  /**
1094
1158
  * Copy extra .claude/commands/ files during installation (Story INS-4.3, Gap #12)
1095
1159
  * Uses an allowlist of distributable top-level directories to prevent leaking
@@ -1174,8 +1238,10 @@ module.exports = {
1174
1238
  promptFileExists,
1175
1239
  generateTemplateVariables,
1176
1240
  copyClaudeHooksFolder,
1241
+ shouldCopyProHooks,
1177
1242
  createClaudeSettingsLocal,
1178
1243
  copySkillFiles,
1244
+ generateCodexSkills,
1179
1245
  copyExtraCommandFiles,
1180
1246
  copyGeminiHooksFolder,
1181
1247
  createGeminiSettings,