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
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Pro Updater — update @aiox-squads/pro with legacy package fallbacks.
3
+ *
4
+ * Handles:
5
+ * - Detecting installed Pro version and source
6
+ * - Querying npm for latest version
7
+ * - Checking compatibility with installed aiox-core
8
+ * - Updating the package via the project's package manager
9
+ * - Re-scaffolding Pro assets after update
10
+ *
11
+ * @module .aiox-core/core/pro/pro-updater
12
+ * @story 122.3 — Implementar aiox pro update
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ const path = require('path');
18
+ const fs = require('fs');
19
+ const https = require('https');
20
+ const { createRequire } = require('module');
21
+ const semver = require('semver');
22
+ const { execSync } = require('child_process');
23
+
24
+ const PRO_PACKAGES = ['@aiox-squads/pro', '@aiox-fullstack/pro', '@aios-fullstack/pro'];
25
+ const CORE_PACKAGES = ['@synkra/aiox-core', 'aiox-core'];
26
+ const DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
27
+ const CORE_PACKAGE_ROOT = path.resolve(__dirname, '..', '..', '..');
28
+ const CORE_PACKAGE_REQUIRE = createRequire(path.join(CORE_PACKAGE_ROOT, 'package.json'));
29
+ const INSTALLER_SCAFFOLDER_EXPORT = 'aiox-core/installer/pro-scaffolder';
30
+
31
+ /**
32
+ * Detect which package manager the project uses.
33
+ * @param {string} projectRoot
34
+ * @returns {'bun'|'pnpm'|'yarn'|'npm'}
35
+ */
36
+ function detectPackageManager(projectRoot) {
37
+ if (fs.existsSync(path.join(projectRoot, 'bun.lockb'))) return 'bun';
38
+ if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
39
+ if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) return 'yarn';
40
+ return 'npm';
41
+ }
42
+
43
+ /**
44
+ * Fetch latest version of a package from npm registry.
45
+ * @param {string} packageName
46
+ * @param {number} [timeout=15000]
47
+ * @returns {Promise<{version:string, peerDependencies:Object}|null>}
48
+ */
49
+ function fetchLatestFromNpm(packageName, timeout = 15000) {
50
+ return new Promise((resolve) => {
51
+ const encoded = encodeURIComponent(packageName).replace('%40', '@');
52
+ const url = `https://registry.npmjs.org/${encoded}/latest`;
53
+
54
+ const req = https.get(url, { timeout }, (res) => {
55
+ if (res.statusCode < 200 || res.statusCode >= 300) {
56
+ res.resume();
57
+ resolve(null);
58
+ return;
59
+ }
60
+
61
+ let data = '';
62
+ res.on('data', (c) => { data += c; });
63
+ res.on('end', () => {
64
+ try {
65
+ const json = JSON.parse(data);
66
+ resolve({
67
+ version: json.version || null,
68
+ peerDependencies: json.peerDependencies || {},
69
+ });
70
+ } catch {
71
+ resolve(null);
72
+ }
73
+ });
74
+ });
75
+
76
+ req.on('error', () => resolve(null));
77
+ req.on('timeout', () => { req.destroy(); resolve(null); });
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Resolve which Pro package is installed and where.
83
+ * @param {string} projectRoot
84
+ * @returns {{ packageName:string, packagePath:string, version:string }|null}
85
+ */
86
+ function resolveInstalledPro(projectRoot) {
87
+ for (const pkg of PRO_PACKAGES) {
88
+ const scope = pkg.split('/')[0].replace('@', '');
89
+ const pkgPath = path.join(projectRoot, 'node_modules', `@${scope}`, 'pro');
90
+ const pkgJson = path.join(pkgPath, 'package.json');
91
+
92
+ if (fs.existsSync(pkgJson)) {
93
+ try {
94
+ const data = JSON.parse(fs.readFileSync(pkgJson, 'utf8'));
95
+ return { packageName: pkg, packagePath: pkgPath, version: data.version || '0.0.0' };
96
+ } catch { /* corrupt, try next */ }
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ function readProjectPackageJson(projectRoot) {
103
+ const packageJsonPath = path.join(projectRoot, 'package.json');
104
+ if (!fs.existsSync(packageJsonPath)) {
105
+ return null;
106
+ }
107
+
108
+ try {
109
+ return JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
114
+
115
+ function buildNodeModulesPackageJsonPath(projectRoot, packageName) {
116
+ if (packageName.startsWith('@')) {
117
+ const [scope, name] = packageName.slice(1).split('/');
118
+ return path.join(projectRoot, 'node_modules', scope, name, 'package.json');
119
+ }
120
+
121
+ return path.join(projectRoot, 'node_modules', packageName, 'package.json');
122
+ }
123
+
124
+ function detectCorePackageName(projectRoot) {
125
+ const packageJson = readProjectPackageJson(projectRoot);
126
+ if (!packageJson) {
127
+ return null;
128
+ }
129
+
130
+ if (CORE_PACKAGES.includes(packageJson.name)) {
131
+ return packageJson.name;
132
+ }
133
+
134
+ for (const field of DEPENDENCY_FIELDS) {
135
+ const dependencies = packageJson[field] || {};
136
+ for (const packageName of CORE_PACKAGES) {
137
+ if (typeof dependencies[packageName] === 'string') {
138
+ return packageName;
139
+ }
140
+ }
141
+ }
142
+
143
+ return null;
144
+ }
145
+
146
+ function assertValidProjectRoot(projectRoot) {
147
+ if (!projectRoot || typeof projectRoot !== 'string') {
148
+ throw new TypeError('updatePro(projectRoot): projectRoot must be a non-empty string.');
149
+ }
150
+
151
+ const resolvedProjectRoot = path.resolve(projectRoot);
152
+
153
+ let stats;
154
+ try {
155
+ stats = fs.statSync(resolvedProjectRoot);
156
+ } catch {
157
+ throw new Error(`updatePro(projectRoot): projectRoot does not exist or is not a directory: ${resolvedProjectRoot}`);
158
+ }
159
+
160
+ if (!stats.isDirectory()) {
161
+ throw new Error(`updatePro(projectRoot): projectRoot does not exist or is not a directory: ${resolvedProjectRoot}`);
162
+ }
163
+
164
+ return resolvedProjectRoot;
165
+ }
166
+
167
+ /**
168
+ * Get the installed aiox-core version.
169
+ * @param {string} projectRoot
170
+ * @returns {string|null}
171
+ */
172
+ function getCoreVersion(projectRoot) {
173
+ const versionJsonPath = path.join(projectRoot, '.aiox-core', 'version.json');
174
+ if (fs.existsSync(versionJsonPath)) {
175
+ try {
176
+ const versionInfo = JSON.parse(fs.readFileSync(versionJsonPath, 'utf8'));
177
+ if (versionInfo.version) {
178
+ return versionInfo.version;
179
+ }
180
+ } catch { /* skip */ }
181
+ }
182
+
183
+ for (const packageName of CORE_PACKAGES) {
184
+ const packageJsonPath = buildNodeModulesPackageJsonPath(projectRoot, packageName);
185
+ if (fs.existsSync(packageJsonPath)) {
186
+ try {
187
+ const data = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
188
+ return data.version || null;
189
+ } catch { /* skip */ }
190
+ }
191
+ }
192
+
193
+ const projectPackageJson = readProjectPackageJson(projectRoot);
194
+ if (projectPackageJson) {
195
+ if (CORE_PACKAGES.includes(projectPackageJson.name)) {
196
+ return projectPackageJson.version || null;
197
+ }
198
+
199
+ const declaredCorePackage = detectCorePackageName(projectRoot);
200
+ if (declaredCorePackage) {
201
+ for (const field of DEPENDENCY_FIELDS) {
202
+ const declaredVersion = projectPackageJson[field]?.[declaredCorePackage];
203
+ if (typeof declaredVersion === 'string') {
204
+ const parsed = semver.coerce(declaredVersion);
205
+ if (parsed) {
206
+ return parsed.version;
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+
213
+ return null;
214
+ }
215
+
216
+ /**
217
+ * Simple semver satisfies check: does installed >= required minimum?
218
+ * @param {string} installed - e.g. '5.0.4'
219
+ * @param {string} range - e.g. '>=5.0.0'
220
+ * @returns {boolean}
221
+ */
222
+ function satisfiesPeer(installed, range) {
223
+ if (!installed || !range) return true;
224
+
225
+ const installedVersion = semver.coerce(installed);
226
+ if (!installedVersion) {
227
+ return false;
228
+ }
229
+
230
+ try {
231
+ return semver.satisfies(installedVersion, range, { includePrerelease: true });
232
+ } catch {
233
+ return true;
234
+ }
235
+ }
236
+
237
+ function loadInstallerScaffolder() {
238
+ return CORE_PACKAGE_REQUIRE(INSTALLER_SCAFFOLDER_EXPORT);
239
+ }
240
+
241
+ async function applyScaffoldStep(projectRoot, proPath, result, onProgress, errorMessage) {
242
+ try {
243
+ const scaffoldResult = await runScaffold(projectRoot, proPath, onProgress);
244
+ result.scaffoldResult = scaffoldResult;
245
+ result.actions.push({ action: 'scaffold', status: scaffoldResult.success ? 'done' : 'failed' });
246
+
247
+ if (!scaffoldResult.success) {
248
+ result.success = false;
249
+ result.error = errorMessage;
250
+ return false;
251
+ }
252
+
253
+ return true;
254
+ } catch (error) {
255
+ result.scaffoldResult = {
256
+ success: false,
257
+ errors: [error.message],
258
+ copiedFiles: [],
259
+ skippedFiles: [],
260
+ warnings: [],
261
+ };
262
+ result.actions.push({ action: 'scaffold', status: 'failed', error: error.message });
263
+ result.success = false;
264
+ result.error = errorMessage;
265
+ return false;
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Build the install command for the detected package manager.
271
+ * @param {'npm'|'pnpm'|'yarn'|'bun'} pm
272
+ * @param {string} packageName
273
+ * @returns {string}
274
+ */
275
+ function buildInstallCmd(pm, packageName) {
276
+ const spec = `${packageName}@latest`;
277
+ switch (pm) {
278
+ case 'pnpm': return `pnpm add ${spec}`;
279
+ case 'yarn': return `yarn add ${spec}`;
280
+ case 'bun': return `bun add ${spec}`;
281
+ default: return `npm install ${spec}`;
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Run the Pro update flow.
287
+ *
288
+ * @param {string} projectRoot
289
+ * @param {Object} [options]
290
+ * @param {boolean} [options.check=false] - Only check, don't update
291
+ * @param {boolean} [options.dryRun=false] - Show plan without executing
292
+ * @param {boolean} [options.force=false] - Force reinstall even if up-to-date
293
+ * @param {boolean} [options.includeCoreUpdate=false] - Also update aiox-core
294
+ * @param {boolean} [options.skipScaffold=false] - Skip re-scaffold after update
295
+ * @param {Function} [options.onProgress] - Progress callback
296
+ * @returns {Promise<Object>} Update result
297
+ */
298
+ async function updatePro(projectRoot, options = {}) {
299
+ const resolvedProjectRoot = assertValidProjectRoot(projectRoot);
300
+ const {
301
+ check = false,
302
+ dryRun = false,
303
+ force = false,
304
+ includeCoreUpdate = false,
305
+ skipScaffold = false,
306
+ onProgress = () => {},
307
+ } = options;
308
+
309
+ const result = {
310
+ success: false,
311
+ previousVersion: null,
312
+ newVersion: null,
313
+ packageName: null,
314
+ packageManager: null,
315
+ coreUpdated: false,
316
+ scaffoldResult: null,
317
+ actions: [],
318
+ error: null,
319
+ };
320
+
321
+ // 1. Detect installed Pro
322
+ onProgress('detect', 'Detecting installed Pro...');
323
+ const installed = resolveInstalledPro(resolvedProjectRoot);
324
+
325
+ if (!installed) {
326
+ result.error = 'AIOX Pro is not installed. Run: aiox pro setup';
327
+ result.actions.push({ action: 'detect', status: 'not_found' });
328
+ return result;
329
+ }
330
+
331
+ result.previousVersion = installed.version;
332
+ result.packageName = installed.packageName;
333
+
334
+ // 2. Detect package manager
335
+ const pm = detectPackageManager(resolvedProjectRoot);
336
+ result.packageManager = pm;
337
+
338
+ // 3. Query npm for latest version
339
+ onProgress('check', `Checking latest version of ${installed.packageName}...`);
340
+ const latest = await fetchLatestFromNpm(installed.packageName);
341
+
342
+ if (!latest || !latest.version) {
343
+ result.error = `Could not reach npm registry for ${installed.packageName}. Check your internet connection.`;
344
+ result.actions.push({ action: 'check', status: 'offline' });
345
+ return result;
346
+ }
347
+
348
+ result.newVersion = latest.version;
349
+
350
+ // 4. Check if update is needed
351
+ const isUpToDate = installed.version === latest.version;
352
+
353
+ if (isUpToDate && !force) {
354
+ result.success = true;
355
+ result.actions.push({ action: 'check', status: 'up_to_date', version: installed.version });
356
+
357
+ if (check) {
358
+ return result;
359
+ }
360
+
361
+ // Even if up to date, re-scaffold if not skipped (new assets might exist)
362
+ if (!skipScaffold && !dryRun) {
363
+ const scaffolded = await applyScaffoldStep(
364
+ resolvedProjectRoot,
365
+ installed.packagePath,
366
+ result,
367
+ onProgress,
368
+ 'AIOX Pro is up to date, but re-scaffolding failed.',
369
+ );
370
+ if (!scaffolded) {
371
+ return result;
372
+ }
373
+ }
374
+
375
+ return result;
376
+ }
377
+
378
+ result.actions.push({
379
+ action: 'check',
380
+ status: 'update_available',
381
+ from: installed.version,
382
+ to: latest.version,
383
+ });
384
+
385
+ // 5. Check compatibility with aiox-core
386
+ const coreVersion = getCoreVersion(resolvedProjectRoot);
387
+ const requiredCore = CORE_PACKAGES
388
+ .map((packageName) => latest.peerDependencies?.[packageName])
389
+ .find(Boolean);
390
+
391
+ if (requiredCore && coreVersion && !satisfiesPeer(coreVersion, requiredCore)) {
392
+ if (!includeCoreUpdate) {
393
+ result.error = `Pro ${latest.version} requires aiox-core ${requiredCore}, but ${coreVersion} is installed. Run: aiox pro update --include-core`;
394
+ result.actions.push({ action: 'compat', status: 'incompatible', required: requiredCore, installed: coreVersion });
395
+ return result;
396
+ }
397
+ }
398
+
399
+ if (check) {
400
+ result.success = true;
401
+ return result;
402
+ }
403
+
404
+ if (dryRun) {
405
+ result.success = true;
406
+ result.actions.push({ action: 'update', status: 'dry_run', command: buildInstallCmd(pm, installed.packageName) });
407
+ if (includeCoreUpdate) {
408
+ const corePackageName = detectCorePackageName(resolvedProjectRoot) || 'aiox-core';
409
+ result.actions.push({ action: 'core_update', status: 'dry_run', command: buildInstallCmd(pm, corePackageName) });
410
+ }
411
+ if (!skipScaffold) {
412
+ result.actions.push({ action: 'scaffold', status: 'dry_run' });
413
+ }
414
+ return result;
415
+ }
416
+
417
+ // 6. Update core first if requested
418
+ if (includeCoreUpdate) {
419
+ onProgress('core', 'Updating aiox-core...');
420
+ try {
421
+ const corePackageName = detectCorePackageName(resolvedProjectRoot) || 'aiox-core';
422
+ const coreCmd = buildInstallCmd(pm, corePackageName);
423
+ execSync(coreCmd, { cwd: resolvedProjectRoot, stdio: 'pipe', timeout: 120000 });
424
+ result.coreUpdated = true;
425
+ result.actions.push({ action: 'core_update', status: 'done' });
426
+ } catch (err) {
427
+ result.error = `Failed to update aiox-core: ${err.message}`;
428
+ result.actions.push({ action: 'core_update', status: 'failed', error: err.message });
429
+ return result;
430
+ }
431
+ }
432
+
433
+ // 7. Update Pro package
434
+ onProgress('update', `Updating ${installed.packageName} to ${latest.version}...`);
435
+ try {
436
+ const cmd = buildInstallCmd(pm, installed.packageName);
437
+ execSync(cmd, { cwd: resolvedProjectRoot, stdio: 'pipe', timeout: 120000 });
438
+ result.actions.push({ action: 'update', status: 'done', from: installed.version, to: latest.version });
439
+ } catch (err) {
440
+ result.error = `Failed to update ${installed.packageName}: ${err.message}`;
441
+ result.actions.push({ action: 'update', status: 'failed', error: err.message });
442
+ return result;
443
+ }
444
+
445
+ // Re-read version after update
446
+ const updatedPro = resolveInstalledPro(resolvedProjectRoot);
447
+ if (updatedPro) {
448
+ result.newVersion = updatedPro.version;
449
+ }
450
+
451
+ // 8. Re-scaffold assets
452
+ if (!skipScaffold) {
453
+ const proPath = updatedPro ? updatedPro.packagePath : installed.packagePath;
454
+ const scaffolded = await applyScaffoldStep(
455
+ resolvedProjectRoot,
456
+ proPath,
457
+ result,
458
+ onProgress,
459
+ 'AIOX Pro package updated, but re-scaffolding failed.',
460
+ );
461
+ if (!scaffolded) {
462
+ return result;
463
+ }
464
+ }
465
+
466
+ result.success = true;
467
+ return result;
468
+ }
469
+
470
+ /**
471
+ * Run the Pro scaffolder after update.
472
+ * @param {string} projectRoot
473
+ * @param {string} proSourceDir
474
+ * @param {Function} onProgress
475
+ * @returns {Promise<Object>}
476
+ */
477
+ async function runScaffold(projectRoot, proSourceDir, onProgress) {
478
+ onProgress('scaffold', 'Scaffolding Pro content...');
479
+
480
+ try {
481
+ const { scaffoldProContent } = loadInstallerScaffolder();
482
+
483
+ return await scaffoldProContent(projectRoot, proSourceDir, {
484
+ onProgress: (progress) => {
485
+ onProgress('scaffold', progress.message);
486
+ },
487
+ });
488
+ } catch (err) {
489
+ return { success: false, errors: [err.message], copiedFiles: [], skippedFiles: [], warnings: [] };
490
+ }
491
+ }
492
+
493
+ /**
494
+ * Format update result for CLI output.
495
+ * @param {Object} result - from updatePro()
496
+ * @returns {string}
497
+ */
498
+ function formatUpdateResult(result) {
499
+ const lines = [];
500
+
501
+ if (result.error) {
502
+ lines.push(`\n ❌ ${result.error}\n`);
503
+ return lines.join('\n');
504
+ }
505
+
506
+ const checkAction = result.actions.find(a => a.action === 'check');
507
+
508
+ if (checkAction?.status === 'up_to_date') {
509
+ lines.push(`\n ✅ AIOX Pro is up to date (v${result.previousVersion})`);
510
+
511
+ if (result.scaffoldResult) {
512
+ const sr = result.scaffoldResult;
513
+ if (sr.copiedFiles?.length > 0) {
514
+ lines.push(` 📦 ${sr.copiedFiles.length} files synced`);
515
+ }
516
+ if (sr.skippedFiles?.length > 0) {
517
+ lines.push(` ⏭️ ${sr.skippedFiles.length} files unchanged`);
518
+ }
519
+ }
520
+
521
+ lines.push('');
522
+ return lines.join('\n');
523
+ }
524
+
525
+ lines.push('\n 🔄 AIOX Pro Update Summary');
526
+ lines.push(' ─────────────────────────');
527
+ lines.push(` Package: ${result.packageName}`);
528
+ lines.push(` Previous: v${result.previousVersion}`);
529
+ lines.push(` Updated to: v${result.newVersion}`);
530
+ lines.push(` PM: ${result.packageManager}`);
531
+
532
+ if (result.coreUpdated) {
533
+ lines.push(' Core: Updated');
534
+ }
535
+
536
+ if (result.scaffoldResult) {
537
+ const sr = result.scaffoldResult;
538
+ if (sr.copiedFiles?.length > 0) {
539
+ lines.push(` Files synced: ${sr.copiedFiles.length}`);
540
+ }
541
+ if (sr.skippedFiles?.length > 0) {
542
+ lines.push(` Unchanged: ${sr.skippedFiles.length}`);
543
+ }
544
+ if (sr.warnings?.length > 0) {
545
+ for (const w of sr.warnings) {
546
+ lines.push(` ⚠️ ${w}`);
547
+ }
548
+ }
549
+ }
550
+
551
+ // Dry-run summary
552
+ const dryActions = result.actions.filter(a => a.status === 'dry_run');
553
+ if (dryActions.length > 0) {
554
+ lines.push('\n 📋 Dry-run plan:');
555
+ for (const a of dryActions) {
556
+ if (a.command) {
557
+ lines.push(` ${a.action}: ${a.command}`);
558
+ } else {
559
+ lines.push(` ${a.action}: would execute`);
560
+ }
561
+ }
562
+ }
563
+
564
+ lines.push('');
565
+ return lines.join('\n');
566
+ }
567
+
568
+ module.exports = {
569
+ updatePro,
570
+ formatUpdateResult,
571
+ resolveInstalledPro,
572
+ detectPackageManager,
573
+ fetchLatestFromNpm,
574
+ getCoreVersion,
575
+ detectCorePackageName,
576
+ satisfiesPeer,
577
+ PRO_PACKAGES,
578
+ };