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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiox-core",
3
- "version": "5.0.7",
3
+ "version": "5.0.8",
4
4
  "description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework",
5
5
  "bin": {
6
6
  "aiox": "bin/aiox.js",
@@ -18,6 +18,8 @@
18
18
  "packages/",
19
19
  ".aiox-core/",
20
20
  ".claude/CLAUDE.md",
21
+ ".claude/commands/",
22
+ ".claude/skills/",
21
23
  ".claude/rules/",
22
24
  ".claude/hooks/",
23
25
  "pro/license/",
@@ -43,11 +45,16 @@
43
45
  "README.md",
44
46
  "LICENSE"
45
47
  ],
48
+ "exports": {
49
+ "./installer/pro-scaffolder": "./packages/installer/src/pro/pro-scaffolder.js",
50
+ "./package.json": "./package.json"
51
+ },
46
52
  "scripts": {
47
53
  "format": "prettier --write \"**/*.md\"",
48
54
  "test": "jest",
49
55
  "test:watch": "jest --watch",
50
56
  "test:coverage": "jest --coverage",
57
+ "test:e2e:installed-skills": "node scripts/e2e/installed-skills-smoke.js",
51
58
  "test:health-check": "mocha tests/health-check/**/*.test.js --timeout 30000",
52
59
  "lint": "eslint . --cache --cache-location .eslintcache",
53
60
  "typecheck": "tsc --noEmit",
@@ -75,7 +82,10 @@
75
82
  "validate:gemini-integration": "node .aiox-core/infrastructure/scripts/validate-gemini-integration.js",
76
83
  "sync:skills:codex": "node .aiox-core/infrastructure/scripts/codex-skills-sync/index.js",
77
84
  "sync:skills:codex:global": "node .aiox-core/infrastructure/scripts/codex-skills-sync/index.js --global --global-only",
85
+ "setup:codex-skills": "node .aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js",
86
+ "setup:codex-skills:dry": "node .aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js --dry-run",
78
87
  "validate:codex-skills": "node .aiox-core/infrastructure/scripts/codex-skills-sync/validate.js --strict",
88
+ "repair:agent-references": "node .aiox-core/infrastructure/scripts/repair-agent-references.js",
79
89
  "validate:paths": "node .aiox-core/infrastructure/scripts/validate-paths.js",
80
90
  "validate:parity": "node .aiox-core/infrastructure/scripts/validate-parity.js",
81
91
  "validate:semantic-lint": "node scripts/semantic-lint.js",
@@ -103,6 +113,7 @@
103
113
  "handlebars": "^4.7.8",
104
114
  "inquirer": "^8.2.6",
105
115
  "js-yaml": "^4.1.0",
116
+ "node-machine-id": "^1.1.12",
106
117
  "ora": "^5.4.1",
107
118
  "picocolors": "^1.1.1",
108
119
  "proper-lockfile": "^4.1.2",
@@ -3,11 +3,12 @@
3
3
  /**
4
4
  * aiox-pro CLI
5
5
  *
6
- * Thin CLI wrapper for @aiox-fullstack/pro.
6
+ * Thin CLI wrapper for AIOX Pro packages.
7
7
  * Provides a clean npx interface: npx aiox-pro install
8
8
  *
9
9
  * Commands:
10
- * install Install @aiox-fullstack/pro in the current project
10
+ * install Install AIOX Pro in the current project
11
+ * update Update AIOX Pro and re-sync assets
11
12
  * activate --key X Activate a license key
12
13
  * deactivate Deactivate the current license
13
14
  * status Show license status
@@ -22,7 +23,10 @@ const path = require('path');
22
23
  const fs = require('fs');
23
24
  const { recoverLicense } = require('../src/recover');
24
25
 
25
- const PRO_PACKAGE = '@aiox-fullstack/pro';
26
+ const PRO_PACKAGE_CANONICAL = '@aiox-squads/pro';
27
+ const PRO_PACKAGE_FALLBACK = '@aiox-fullstack/pro';
28
+ const PRO_PACKAGE_LEGACY = '@aios-fullstack/pro';
29
+ const PRO_PACKAGES = [PRO_PACKAGE_CANONICAL, PRO_PACKAGE_FALLBACK, PRO_PACKAGE_LEGACY];
26
30
  const VERSION = require('../package.json').version;
27
31
 
28
32
  const args = process.argv.slice(2);
@@ -42,8 +46,11 @@ function run(cmd, options = {}) {
42
46
 
43
47
  function isProInstalled() {
44
48
  try {
45
- const pkgPath = path.join(process.cwd(), 'node_modules', '@aiox-fullstack', 'pro', 'package.json');
46
- return fs.existsSync(pkgPath);
49
+ return PRO_PACKAGES.some((packageName) => {
50
+ const scopeDir = packageName.split('/')[0];
51
+ const packageJson = path.join(process.cwd(), 'node_modules', scopeDir, 'pro', 'package.json');
52
+ return fs.existsSync(packageJson);
53
+ });
47
54
  } catch {
48
55
  return false;
49
56
  }
@@ -133,7 +140,8 @@ Usage:
133
140
  npx aiox-pro <command> [options]
134
141
 
135
142
  Commands:
136
- install Install ${PRO_PACKAGE} in the current project
143
+ install Install AIOX Pro in the current project
144
+ update Update AIOX Pro and re-sync assets
137
145
  install --wizard Install and run the setup wizard
138
146
  setup, wizard Run Pro setup wizard (license gate + scaffold + verify)
139
147
  activate --key KEY Activate a license key
@@ -147,6 +155,7 @@ Commands:
147
155
 
148
156
  Examples:
149
157
  npx aiox-pro install
158
+ npx aiox-pro update
150
159
  npx aiox-pro setup
151
160
  npx aiox-pro wizard --key PRO-XXXX-XXXX-XXXX-XXXX
152
161
  npx aiox-pro activate --key PRO-XXXX-XXXX-XXXX-XXXX
@@ -158,16 +167,27 @@ Documentation: https://synkra.ai/pro/docs
158
167
  }
159
168
 
160
169
  function installPro() {
161
- console.log(`\nInstalling ${PRO_PACKAGE}...\n`);
170
+ console.log('\nInstalling AIOX Pro...\n');
171
+
172
+ let installedPackage = null;
162
173
 
163
- const exitCode = run(`npm install ${PRO_PACKAGE}`);
174
+ for (const packageName of PRO_PACKAGES) {
175
+ console.log(`Trying ${packageName}...`);
176
+ const exitCode = run(`npm install ${packageName}`);
177
+ if (exitCode === 0) {
178
+ installedPackage = packageName;
179
+ break;
180
+ }
181
+ console.log('');
182
+ }
164
183
 
165
- if (exitCode !== 0) {
166
- console.error(`\nFailed to install ${PRO_PACKAGE}`);
184
+ if (!installedPackage) {
185
+ console.error('\nFailed to install AIOX Pro.');
186
+ console.error(`Tried: ${PRO_PACKAGES.join(', ')}`);
167
187
  process.exit(1);
168
188
  }
169
189
 
170
- console.log(`\n✅ ${PRO_PACKAGE} installed successfully!\n`);
190
+ console.log(`\n✅ ${installedPackage} installed successfully!\n`);
171
191
  console.log('Next steps:');
172
192
  console.log(' npx aiox-pro activate --key PRO-XXXX-XXXX-XXXX-XXXX');
173
193
  console.log(' npx aiox-pro status');
@@ -218,8 +238,9 @@ switch (command) {
218
238
  case 'status':
219
239
  case 'features':
220
240
  case 'validate':
241
+ case 'update':
221
242
  if (!isProInstalled()) {
222
- console.error(`${PRO_PACKAGE} is not installed.`);
243
+ console.error('AIOX Pro is not installed.');
223
244
  console.error('Run first: npx aiox-pro install\n');
224
245
  process.exit(1);
225
246
  }
@@ -24,6 +24,68 @@ const {
24
24
  } = require('./validation/config-validator');
25
25
  const { getMergeStrategy, hasMergeStrategy } = require('../merger/index.js');
26
26
 
27
+ function isBrownfieldProjectType(projectType) {
28
+ const normalized = String(projectType || '').toLowerCase();
29
+ return normalized === 'brownfield' || normalized === 'existing_aiox' || normalized === 'existing-aiox';
30
+ }
31
+
32
+ async function resolveFileAction(filePath, options = {}) {
33
+ const {
34
+ skipPrompts = false,
35
+ forceMerge = false,
36
+ noMerge = false,
37
+ projectType = 'greenfield',
38
+ message,
39
+ } = options;
40
+
41
+ const exists = await fs.pathExists(filePath);
42
+ if (!exists) {
43
+ return 'create';
44
+ }
45
+
46
+ const isBrownfield = isBrownfieldProjectType(projectType);
47
+ const canMerge = !noMerge && hasMergeStrategy(filePath);
48
+
49
+ if (forceMerge && canMerge) {
50
+ return 'merge';
51
+ }
52
+
53
+ if (skipPrompts) {
54
+ return isBrownfield && canMerge ? 'merge' : 'overwrite';
55
+ }
56
+
57
+ const choices = [];
58
+
59
+ if (canMerge) {
60
+ choices.push({
61
+ value: 'merge',
62
+ label: 'Merge (preserve existing customizations)',
63
+ hint: isBrownfield ? 'recommended' : '',
64
+ });
65
+ }
66
+
67
+ choices.push(
68
+ { value: 'backup', label: 'Backup and overwrite' },
69
+ { value: 'overwrite', label: 'Overwrite completely' },
70
+ { value: 'skip', label: 'Skip (keep existing)' },
71
+ );
72
+
73
+ let action = await select({
74
+ message,
75
+ options: choices,
76
+ initialValue: isBrownfield && canMerge ? 'merge' : 'backup',
77
+ });
78
+
79
+ if (action === 'backup') {
80
+ const backupPath = `${filePath}.backup.${Date.now()}`;
81
+ await fs.copy(filePath, backupPath);
82
+ console.log(`✅ Backup created: ${backupPath}`);
83
+ action = 'overwrite';
84
+ }
85
+
86
+ return action;
87
+ }
88
+
27
89
  /**
28
90
  * Configure environment files (.env and core-config.yaml)
29
91
  *
@@ -62,50 +124,16 @@ async function configureEnvironment(options = {}) {
62
124
  // Step 1: Check for existing .env and handle with merge/backup/overwrite
63
125
  const envPath = path.join(targetDir, '.env');
64
126
  const envExists = await fs.pathExists(envPath);
65
- let envAction = 'create'; // 'create', 'merge', 'overwrite', 'skip'
66
- const isBrownfield = projectType === 'BROWNFIELD' || projectType === 'EXISTING_AIOX';
67
- const canMerge = !noMerge && hasMergeStrategy(envPath);
68
-
69
- if (envExists) {
70
- // Story 9.4: Handle CLI flags for merge behavior
71
- if (forceMerge && canMerge) {
72
- // --merge flag: Force merge without prompting
73
- envAction = 'merge';
74
- console.log('🔀 Using merge mode (--merge flag)');
75
- } else if (skipPrompts) {
76
- // Quiet mode: default to merge for brownfield, overwrite for greenfield
77
- envAction = isBrownfield && canMerge ? 'merge' : 'overwrite';
78
- } else {
79
- // Interactive mode: Offer merge option for brownfield projects
80
- const choices = [];
81
-
82
- if (canMerge) {
83
- choices.push({
84
- value: 'merge',
85
- label: 'Merge (add new variables, keep existing)',
86
- hint: isBrownfield ? 'recommended' : '',
87
- });
88
- }
89
-
90
- choices.push(
91
- { value: 'backup', label: 'Backup and overwrite' },
92
- { value: 'overwrite', label: 'Overwrite completely' },
93
- { value: 'skip', label: 'Skip (keep existing)' },
94
- );
95
-
96
- envAction = await select({
97
- message: 'Found existing .env file. What would you like to do?',
98
- options: choices,
99
- initialValue: isBrownfield && canMerge ? 'merge' : 'backup',
100
- });
101
-
102
- if (envAction === 'backup') {
103
- const backupPath = path.join(targetDir, `.env.backup.${Date.now()}`);
104
- await fs.copy(envPath, backupPath);
105
- console.log(`✅ Backup created: ${backupPath}`);
106
- envAction = 'overwrite';
107
- }
108
- }
127
+ const envAction = await resolveFileAction(envPath, {
128
+ skipPrompts,
129
+ forceMerge,
130
+ noMerge,
131
+ projectType,
132
+ message: 'Found existing .env file. What would you like to do?',
133
+ });
134
+
135
+ if (envAction === 'merge' && envExists && forceMerge) {
136
+ console.log('🔀 Using merge mode (--merge flag)');
109
137
  }
110
138
 
111
139
  // Step 2: API keys are configured later via .env or aiox-master
@@ -158,9 +186,29 @@ async function configureEnvironment(options = {}) {
158
186
  // Step 4: Generate and write .env.example
159
187
  const envExamplePath = path.join(targetDir, '.env.example');
160
188
  const envExampleContent = generateEnvExample();
161
- await fs.writeFile(envExamplePath, envExampleContent, { encoding: 'utf8' });
162
- results.envExampleCreated = true;
163
- console.log('✅ Created .env.example file');
189
+ const envExampleAction = await resolveFileAction(envExamplePath, {
190
+ skipPrompts,
191
+ forceMerge,
192
+ noMerge,
193
+ projectType,
194
+ message: 'Found existing .env.example file. What would you like to do?',
195
+ });
196
+
197
+ if (envExampleAction === 'skip') {
198
+ console.log('⏭️ Skipped .env.example file (keeping existing)');
199
+ } else if (envExampleAction === 'merge' && await fs.pathExists(envExamplePath)) {
200
+ const existingContent = await fs.readFile(envExamplePath, 'utf8');
201
+ const merger = getMergeStrategy(envExamplePath);
202
+ const mergeResult = await merger.merge(existingContent, envExampleContent);
203
+
204
+ await fs.writeFile(envExamplePath, mergeResult.content, { encoding: 'utf8' });
205
+ results.envExampleCreated = true;
206
+ console.log('✅ Merged .env.example file');
207
+ } else {
208
+ await fs.writeFile(envExamplePath, envExampleContent, { encoding: 'utf8' });
209
+ results.envExampleCreated = true;
210
+ console.log('✅ Created .env.example file');
211
+ }
164
212
 
165
213
  // Step 5: Update .gitignore
166
214
  await updateGitignore(targetDir);
@@ -194,9 +242,29 @@ async function configureEnvironment(options = {}) {
194
242
  }
195
243
 
196
244
  const coreConfigPath = path.join(coreConfigDir, 'core-config.yaml');
197
- await fs.writeFile(coreConfigPath, coreConfigContent, { encoding: 'utf8' });
198
- results.coreConfigCreated = true;
199
- console.log('✅ Created .aiox-core/core-config.yaml');
245
+ const coreConfigAction = await resolveFileAction(coreConfigPath, {
246
+ skipPrompts,
247
+ forceMerge,
248
+ noMerge,
249
+ projectType,
250
+ message: 'Found existing .aiox-core/core-config.yaml. What would you like to do?',
251
+ });
252
+
253
+ if (coreConfigAction === 'skip') {
254
+ console.log('⏭️ Skipped .aiox-core/core-config.yaml (keeping existing)');
255
+ } else if (coreConfigAction === 'merge' && await fs.pathExists(coreConfigPath)) {
256
+ const existingContent = await fs.readFile(coreConfigPath, 'utf8');
257
+ const merger = getMergeStrategy(coreConfigPath);
258
+ const mergeResult = await merger.merge(coreConfigContent, existingContent);
259
+
260
+ await fs.writeFile(coreConfigPath, mergeResult.content, { encoding: 'utf8' });
261
+ results.coreConfigCreated = true;
262
+ console.log('✅ Merged .aiox-core/core-config.yaml');
263
+ } else {
264
+ await fs.writeFile(coreConfigPath, coreConfigContent, { encoding: 'utf8' });
265
+ results.coreConfigCreated = true;
266
+ console.log('✅ Created .aiox-core/core-config.yaml');
267
+ }
200
268
 
201
269
  return results;
202
270
  } catch (error) {
@@ -12,6 +12,7 @@ const fs = require('fs-extra');
12
12
  const path = require('path');
13
13
  const ora = require('ora');
14
14
  const { hashFile } = require('./file-hasher');
15
+ const { loadSourceManifest, updateInstalledManifest } = require('./brownfield-upgrader');
15
16
 
16
17
  /**
17
18
  * Get the path to the source .aiox-core directory in the package
@@ -70,6 +71,59 @@ const ROOT_FILES_TO_COPY = [
70
71
  'working-in-the-brownfield.md',
71
72
  ];
72
73
 
74
+ const BROWNFIELD_PRESERVE_PATTERNS = [
75
+ /^core-config\.yaml$/,
76
+ /^development\/agents\/[^/]+\/MEMORY\.md$/,
77
+ ];
78
+
79
+ function isBrownfieldProjectType(projectType = '') {
80
+ const normalized = String(projectType).toLowerCase();
81
+ return normalized === 'brownfield' || normalized === 'existing_aiox' || normalized === 'existing-aiox';
82
+ }
83
+
84
+ function shouldPreserveExistingFile(relativePath, options = {}) {
85
+ if (!options.preserveExisting) {
86
+ return false;
87
+ }
88
+
89
+ return BROWNFIELD_PRESERVE_PATTERNS.some((pattern) => pattern.test(relativePath));
90
+ }
91
+
92
+ function extractManifestFileHashes(manifest) {
93
+ if (!manifest || !Array.isArray(manifest.files)) {
94
+ return {};
95
+ }
96
+
97
+ const fileHashes = {};
98
+ for (const entry of manifest.files) {
99
+ if (entry && entry.path && entry.hash) {
100
+ fileHashes[entry.path] = entry.hash;
101
+ }
102
+ }
103
+
104
+ return fileHashes;
105
+ }
106
+
107
+ async function copyManifestArtifacts(sourceDir, targetAioxCore) {
108
+ const manifestPath = path.join(sourceDir, 'install-manifest.yaml');
109
+ const signaturePath = manifestPath + '.minisig';
110
+ const targetSignaturePath = path.join(targetAioxCore, 'install-manifest.yaml.minisig');
111
+
112
+ if (await fs.pathExists(manifestPath)) {
113
+ await fs.copy(manifestPath, path.join(targetAioxCore, 'install-manifest.yaml'), {
114
+ overwrite: true,
115
+ });
116
+ }
117
+
118
+ if (await fs.pathExists(signaturePath)) {
119
+ await fs.copy(signaturePath, targetSignaturePath, {
120
+ overwrite: true,
121
+ });
122
+ } else if (await fs.pathExists(targetSignaturePath)) {
123
+ await fs.remove(targetSignaturePath);
124
+ }
125
+ }
126
+
73
127
  /**
74
128
  * Replace {root} placeholder in file content
75
129
  * @param {string} content - File content
@@ -128,9 +182,10 @@ async function generateVersionJson(options) {
128
182
  version,
129
183
  installedFiles,
130
184
  mode = 'project-development',
185
+ fileHashes: providedFileHashes = null,
131
186
  } = options;
132
187
 
133
- const fileHashes = await generateFileHashes(targetAioxCore, installedFiles);
188
+ const fileHashes = providedFileHashes || await generateFileHashes(targetAioxCore, installedFiles);
134
189
 
135
190
  const versionJson = {
136
191
  version,
@@ -153,8 +208,14 @@ async function generateVersionJson(options) {
153
208
  * @param {boolean} replaceRoot - Whether to replace {root} placeholders
154
209
  * @returns {Promise<boolean>} Success status
155
210
  */
156
- async function copyFileWithRootReplacement(sourcePath, destPath, replaceRoot = true) {
211
+ async function copyFileWithRootReplacement(sourcePath, destPath, replaceRoot = true, options = {}) {
157
212
  try {
213
+ if (options.relativePath && shouldPreserveExistingFile(options.relativePath, options)) {
214
+ if (await fs.pathExists(destPath)) {
215
+ return { copied: false, preserved: true, relativePath: options.relativePath };
216
+ }
217
+ }
218
+
158
219
  await fs.ensureDir(path.dirname(destPath));
159
220
 
160
221
  // Check if file needs {root} replacement (.md, .yaml, .yml)
@@ -169,10 +230,10 @@ async function copyFileWithRootReplacement(sourcePath, destPath, replaceRoot = t
169
230
  await fs.copy(sourcePath, destPath);
170
231
  }
171
232
 
172
- return true;
233
+ return { copied: true, preserved: false, relativePath: options.relativePath || null };
173
234
  } catch (error) {
174
235
  console.error(`Failed to copy ${sourcePath}: ${error.message}`);
175
- return false;
236
+ return { copied: false, preserved: false, relativePath: options.relativePath || null };
176
237
  }
177
238
  }
178
239
 
@@ -183,7 +244,7 @@ async function copyFileWithRootReplacement(sourcePath, destPath, replaceRoot = t
183
244
  * @param {Function} onProgress - Progress callback
184
245
  * @returns {Promise<string[]>} List of copied files (relative paths)
185
246
  */
186
- async function copyDirectoryWithRootReplacement(sourceDir, destDir, onProgress = null) {
247
+ async function copyDirectoryWithRootReplacement(sourceDir, destDir, onProgress = null, options = {}) {
187
248
  const copiedFiles = [];
188
249
 
189
250
  if (!await fs.pathExists(sourceDir)) {
@@ -205,15 +266,28 @@ async function copyDirectoryWithRootReplacement(sourceDir, destDir, onProgress =
205
266
  }
206
267
 
207
268
  if (item.isDirectory()) {
208
- const subFiles = await copyDirectoryWithRootReplacement(sourcePath, destPath, onProgress);
269
+ const subFiles = await copyDirectoryWithRootReplacement(sourcePath, destPath, onProgress, {
270
+ ...options,
271
+ baseDir: options.baseDir || destDir,
272
+ });
209
273
  copiedFiles.push(...subFiles);
210
274
  } else {
211
- const success = await copyFileWithRootReplacement(sourcePath, destPath);
212
- if (success) {
213
- copiedFiles.push(path.relative(destDir, destPath));
275
+ const baseDir = options.baseDir || destDir;
276
+ const relativePath = path.relative(baseDir, destPath).replace(/\\/g, '/');
277
+ const fullRelativePath = options.pathPrefix
278
+ ? path.posix.join(options.pathPrefix, relativePath)
279
+ : relativePath;
280
+ const result = await copyFileWithRootReplacement(sourcePath, destPath, true, {
281
+ ...options,
282
+ relativePath: fullRelativePath,
283
+ });
284
+ if (result.copied) {
285
+ copiedFiles.push(relativePath);
214
286
  if (onProgress) {
215
287
  onProgress({ file: item.name, copied: true });
216
288
  }
289
+ } else if (result.preserved && onProgress) {
290
+ onProgress({ file: item.name, copied: false, preserved: true });
217
291
  }
218
292
  }
219
293
  }
@@ -237,6 +311,9 @@ async function installAioxCore(options = {}) {
237
311
  const {
238
312
  targetDir = process.cwd(),
239
313
  onProgress = null,
314
+ projectType = 'greenfield',
315
+ sourceDir: providedSourceDir = null,
316
+ packageVersion: providedPackageVersion = null,
240
317
  } = options;
241
318
 
242
319
  const result = {
@@ -249,8 +326,9 @@ async function installAioxCore(options = {}) {
249
326
  const spinner = ora('Installing AIOX core framework...').start();
250
327
 
251
328
  try {
252
- const sourceDir = getAioxCoreSourcePath();
329
+ const sourceDir = providedSourceDir || getAioxCoreSourcePath();
253
330
  const targetAioxCore = path.join(targetDir, '.aiox-core');
331
+ const preserveExisting = isBrownfieldProjectType(projectType);
254
332
 
255
333
  // Check if source exists
256
334
  if (!await fs.pathExists(sourceDir)) {
@@ -272,6 +350,11 @@ async function installAioxCore(options = {}) {
272
350
  folderSource,
273
351
  folderDest,
274
352
  onProgress,
353
+ {
354
+ baseDir: folderDest,
355
+ pathPrefix: folder,
356
+ preserveExisting,
357
+ },
275
358
  );
276
359
 
277
360
  if (copiedFiles.length > 0) {
@@ -288,28 +371,37 @@ async function installAioxCore(options = {}) {
288
371
 
289
372
  if (await fs.pathExists(fileSource)) {
290
373
  spinner.text = `Copying ${file}...`;
291
- const success = await copyFileWithRootReplacement(fileSource, fileDest);
292
- if (success) {
374
+ const relativePath = file;
375
+ const copyResult = await copyFileWithRootReplacement(fileSource, fileDest, true, {
376
+ relativePath,
377
+ preserveExisting,
378
+ });
379
+ if (copyResult.copied) {
293
380
  result.installedFiles.push(file);
294
381
  }
295
382
  }
296
383
  }
297
384
 
298
- // Create install manifest
299
- spinner.text = 'Creating installation manifest...';
300
- const packageVersion = require('../../../../package.json').version;
301
- const manifest = {
302
- version: packageVersion,
303
- installed_at: new Date().toISOString(),
304
- install_type: 'full',
305
- files: result.installedFiles,
306
- };
307
-
308
- await fs.writeFile(
309
- path.join(targetAioxCore, 'install-manifest.yaml'),
310
- require('js-yaml').dump(manifest),
311
- 'utf8',
312
- );
385
+ const sourceManifest = loadSourceManifest(sourceDir);
386
+ const manifestFileHashes = extractManifestFileHashes(sourceManifest);
387
+ const packageVersion = providedPackageVersion || require('../../../../package.json').version;
388
+
389
+ spinner.text = 'Copying installation manifest...';
390
+ await copyManifestArtifacts(sourceDir, targetAioxCore);
391
+ if (!sourceManifest) {
392
+ const manifest = {
393
+ version: packageVersion,
394
+ installed_at: new Date().toISOString(),
395
+ install_type: 'full',
396
+ files: result.installedFiles,
397
+ };
398
+
399
+ await fs.writeFile(
400
+ path.join(targetAioxCore, 'install-manifest.yaml'),
401
+ require('js-yaml').dump(manifest),
402
+ 'utf8',
403
+ );
404
+ }
313
405
 
314
406
  // Story 7.2: Create version.json with file hashes for update tracking
315
407
  spinner.text = 'Generating version tracking info...';
@@ -318,9 +410,14 @@ async function installAioxCore(options = {}) {
318
410
  version: packageVersion,
319
411
  installedFiles: result.installedFiles,
320
412
  mode: 'project-development',
413
+ fileHashes: Object.keys(manifestFileHashes).length > 0 ? manifestFileHashes : null,
321
414
  });
322
415
  result.versionInfo = versionInfo;
323
416
 
417
+ if (sourceManifest) {
418
+ updateInstalledManifest(targetDir, sourceManifest, `aiox-core@${packageVersion}`);
419
+ }
420
+
324
421
  // BUG-2 fix (INS-1): Install .aiox-core dependencies after copy
325
422
  // The copied .aiox-core/package.json has dependencies (js-yaml, execa, etc.)
326
423
  // that must be installed for the activation pipeline to work