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.
- package/.aiox-core/cli/commands/pro/buyer.js +379 -0
- package/.aiox-core/cli/commands/pro/index.js +191 -52
- package/.aiox-core/cli/commands/validate/index.js +2 -0
- package/.aiox-core/core/code-intel/helpers/dev-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/devops-helper.js +0 -1
- package/.aiox-core/core/code-intel/helpers/planning-helper.js +1 -1
- package/.aiox-core/core/code-intel/helpers/qa-helper.js +2 -2
- package/.aiox-core/core/config/schemas/framework-config.schema.json +1 -0
- package/.aiox-core/core/config/template-overrides.js +1 -1
- package/.aiox-core/core/doctor/checks/ide-sync.js +81 -25
- package/.aiox-core/core/doctor/checks/rules-files.js +0 -1
- package/.aiox-core/core/doctor/checks/skills-count.js +83 -15
- package/.aiox-core/core/graph-dashboard/cli.js +1 -2
- package/.aiox-core/core/graph-dashboard/data-sources/code-intel-source.js +1 -1
- package/.aiox-core/core/ids/layer-classifier.js +1 -1
- package/.aiox-core/core/pro/pro-updater.js +578 -0
- package/.aiox-core/core/synapse/context/context-tracker.js +107 -9
- package/.aiox-core/core/synapse/layers/layer-processor.js +1 -1
- package/.aiox-core/core-config.yaml +15 -1
- package/.aiox-core/data/capability-detection.js +15 -15
- package/.aiox-core/data/entity-registry.yaml +18 -2
- package/.aiox-core/data/registry-update-log.jsonl +5 -0
- package/.aiox-core/data/tok3-token-comparison.js +0 -4
- package/.aiox-core/data/tool-search-validation.js +1 -1
- package/.aiox-core/development/agents/aiox-master.md +44 -6
- package/.aiox-core/development/agents/data-engineer.md +4 -4
- package/.aiox-core/development/agents/devops.md +52 -2
- package/.aiox-core/development/agents/po.md +1 -1
- package/.aiox-core/development/agents/qa.md +5 -11
- package/.aiox-core/development/agents/sm.md +3 -3
- package/.aiox-core/development/agents/ux-design-expert.md +1 -1
- package/.aiox-core/development/scripts/unified-activation-pipeline.js +29 -3
- package/.aiox-core/development/tasks/dev-develop-story.md +46 -7
- package/.aiox-core/development/tasks/devops-pro-access-grant.md +93 -0
- package/.aiox-core/development/tasks/devops-pro-activate.md +42 -0
- package/.aiox-core/development/tasks/devops-pro-check-access.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-request-reset.md +34 -0
- package/.aiox-core/development/tasks/devops-pro-resend-verification.md +32 -0
- package/.aiox-core/development/tasks/devops-pro-reset-password.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-validate-login.md +36 -0
- package/.aiox-core/development/tasks/devops-pro-verify-status.md +33 -0
- package/.aiox-core/development/tasks/qa-gate.md +54 -4
- package/.aiox-core/development/tasks/validate-next-story.md +39 -2
- package/.aiox-core/framework-config.yaml +1 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/README.md +69 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/bootstrap.js +727 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/index.js +10 -0
- package/.aiox-core/infrastructure/scripts/codex-skills-sync/validate.js +65 -4
- package/.aiox-core/infrastructure/scripts/generate-settings-json.js +29 -4
- package/.aiox-core/infrastructure/scripts/ide-sync/agent-parser.js +4 -0
- package/.aiox-core/infrastructure/scripts/ide-sync/index.js +67 -7
- package/.aiox-core/infrastructure/scripts/ide-sync/transformers/claude-code.js +145 -3
- package/.aiox-core/infrastructure/scripts/repair-agent-references.js +263 -0
- package/.aiox-core/infrastructure/scripts/validate-claude-integration.js +60 -8
- package/.aiox-core/infrastructure/scripts/validate-paths.js +13 -0
- package/.aiox-core/install-manifest.yaml +134 -82
- package/.aiox-core/utils/filters/index.js +2 -1
- package/.claude/commands/AIOX/agents/aiox-master.md +21 -0
- package/.claude/commands/AIOX/agents/analyst.md +21 -0
- package/.claude/commands/AIOX/agents/architect.md +21 -0
- package/.claude/commands/AIOX/agents/data-engineer.md +21 -0
- package/.claude/commands/AIOX/agents/dev.md +21 -0
- package/.claude/commands/AIOX/agents/devops.md +21 -0
- package/.claude/commands/AIOX/agents/pm.md +21 -0
- package/.claude/commands/AIOX/agents/po.md +21 -0
- package/.claude/commands/AIOX/agents/qa.md +21 -0
- package/.claude/commands/AIOX/agents/sm.md +21 -0
- package/.claude/commands/AIOX/agents/squad-creator.md +21 -0
- package/.claude/commands/AIOX/agents/ux-design-expert.md +21 -0
- package/.claude/commands/AIOX/scripts/agent-config-loader.js +624 -0
- package/.claude/commands/AIOX/scripts/generate-greeting.js +160 -0
- package/.claude/commands/AIOX/scripts/greeting-builder.js +866 -0
- package/.claude/commands/AIOX/scripts/session-context-loader.js +286 -0
- package/.claude/commands/AIOX/stories/story-6.1.4.md +1404 -0
- package/.claude/commands/cohort-squad/agents/cohort-manager.md +156 -0
- package/.claude/commands/design-system/agents/brad-frost.md +1097 -0
- package/.claude/commands/design-system/agents/dan-mall.md +857 -0
- package/.claude/commands/design-system/agents/dave-malouf.md +2272 -0
- package/.claude/commands/design-system/agents/design-chief.md +102 -0
- package/.claude/commands/design-system/agents/nano-banana-generator.md +162 -0
- package/.claude/commands/greet.md +101 -0
- package/.claude/commands/synapse/manager.md +75 -0
- package/.claude/commands/synapse/tasks/add-rule.md +94 -0
- package/.claude/commands/synapse/tasks/create-command.md +109 -0
- package/.claude/commands/synapse/tasks/create-domain.md +127 -0
- package/.claude/commands/synapse/tasks/diagnose-synapse.md +245 -0
- package/.claude/commands/synapse/tasks/edit-rule.md +109 -0
- package/.claude/commands/synapse/tasks/suggest-domain.md +116 -0
- package/.claude/commands/synapse/tasks/toggle-domain.md +83 -0
- package/.claude/commands/synapse/templates/domain-template +8 -0
- package/.claude/commands/synapse/templates/manifest-entry-template +4 -0
- package/.claude/commands/synapse/utils/manifest-parser-reference.md +134 -0
- package/.claude/hooks/precompact-session-digest.cjs +2 -2
- package/.claude/skills/AIOX/agents/aiox-master/SKILL.md +511 -0
- package/.claude/skills/AIOX/agents/analyst/SKILL.md +281 -0
- package/.claude/skills/AIOX/agents/architect/SKILL.md +482 -0
- package/.claude/skills/AIOX/agents/data-engineer/SKILL.md +503 -0
- package/.claude/skills/AIOX/agents/dev/SKILL.md +568 -0
- package/.claude/skills/AIOX/agents/devops/SKILL.md +597 -0
- package/.claude/skills/AIOX/agents/pm/SKILL.md +385 -0
- package/.claude/skills/AIOX/agents/po/SKILL.md +343 -0
- package/.claude/skills/AIOX/agents/qa/SKILL.md +451 -0
- package/.claude/skills/AIOX/agents/sm/SKILL.md +295 -0
- package/.claude/skills/AIOX/agents/squad-creator/SKILL.md +352 -0
- package/.claude/skills/AIOX/agents/ux-design-expert/SKILL.md +503 -0
- package/.claude/skills/architect-first/SKILL.md +275 -0
- package/.claude/skills/architect-first/assets/architecture-template.md +505 -0
- package/.claude/skills/architect-first/assets/config-template.yaml +351 -0
- package/.claude/skills/architect-first/references/architecture-checklist.md +216 -0
- package/.claude/skills/architect-first/references/pre-implementation-checklist.md +119 -0
- package/.claude/skills/architect-first/references/stop-rules-guide.md +291 -0
- package/.claude/skills/architect-first/references/testing-strategy-guide.md +477 -0
- package/.claude/skills/architect-first/scripts/architecture_validator.py +490 -0
- package/.claude/skills/architect-first/scripts/check_coupling.py +306 -0
- package/.claude/skills/architect-first/scripts/validate_risk_mitigation.py +382 -0
- package/.claude/skills/checklist-runner/SKILL.md +113 -0
- package/.claude/skills/clone-mind.md +329 -0
- package/.claude/skills/coderabbit-review/SKILL.md +106 -0
- package/.claude/skills/course-generation-workflow.md +76 -0
- package/.claude/skills/enhance-workflow.md +466 -0
- package/.claude/skills/mcp-builder/LICENSE.txt +202 -0
- package/.claude/skills/mcp-builder/SKILL.md +328 -0
- package/.claude/skills/mcp-builder/reference/evaluation.md +602 -0
- package/.claude/skills/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/.claude/skills/mcp-builder/reference/node_mcp_server.md +916 -0
- package/.claude/skills/mcp-builder/reference/python_mcp_server.md +752 -0
- package/.claude/skills/mcp-builder/scripts/connections.py +151 -0
- package/.claude/skills/mcp-builder/scripts/evaluation.py +373 -0
- package/.claude/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/.claude/skills/mcp-builder/scripts/requirements.txt +2 -0
- package/.claude/skills/ralph.md +181 -0
- package/.claude/skills/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/skill-creator/SKILL.md +209 -0
- package/.claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/.claude/skills/squad.md +301 -0
- package/.claude/skills/synapse/SKILL.md +132 -0
- package/.claude/skills/synapse/assets/README.md +50 -0
- package/.claude/skills/synapse/references/brackets.md +100 -0
- package/.claude/skills/synapse/references/commands.md +118 -0
- package/.claude/skills/synapse/references/domains.md +126 -0
- package/.claude/skills/synapse/references/layers.md +186 -0
- package/.claude/skills/synapse/references/manifest.md +142 -0
- package/.claude/skills/tech-search/SKILL.md +431 -0
- package/.claude/skills/tech-search/prompts/page-extract.md +133 -0
- package/README.en.md +2 -2
- package/README.md +8 -2
- package/bin/aiox.js +55 -4
- package/bin/utils/framework-guard.js +4 -2
- package/bin/utils/pro-detector.js +119 -28
- package/bin/utils/validate-publish.js +6 -6
- package/docs/aiox-agent-flows/devops-system.md +18 -0
- package/docs/aiox-workflows/README.md +1 -0
- package/docs/aiox-workflows/pro-access-grant-workflow.md +218 -0
- package/docs/guides/pro/access-grant-ops-playbook.md +370 -0
- package/docs/guides/pro/install-gate-setup.md +12 -6
- package/docs/guides/pro/squad-creator-handoff-pro-access-ops.md +134 -0
- package/docs/guides/supabase-ops-handoff.md +768 -0
- package/package.json +12 -1
- package/packages/aiox-pro-cli/bin/aiox-pro.js +33 -12
- package/packages/installer/src/config/configure-environment.js +118 -50
- package/packages/installer/src/installer/aiox-core-installer.js +124 -27
- package/packages/installer/src/installer/brownfield-upgrader.js +66 -9
- package/packages/installer/src/installer/dependency-installer.js +4 -0
- package/packages/installer/src/pro/pro-scaffolder.js +5 -5
- package/packages/installer/src/updater/index.js +151 -10
- package/packages/installer/src/wizard/ide-config-generator.js +73 -7
- package/packages/installer/src/wizard/index.js +119 -31
- package/packages/installer/src/wizard/pro-setup.js +118 -47
- package/packages/installer/src/wizard/validation/validators/dependency-validator.js +32 -25
- package/packages/installer/src/wizard/validation/validators/file-structure-validator.js +26 -0
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +84 -1
- package/packages/installer/tests/unit/claude-md-template-v5/claude-md-template-v5.test.js +1 -1
- package/packages/installer/tests/unit/doctor/doctor-checks.test.js +85 -19
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +4 -4
- package/packages/installer/tests/unit/generate-settings-json/generate-settings-json.test.js +5 -5
- package/packages/installer/tests/unit/ide-sync-integration/ide-sync-integration.test.js +4 -4
- package/packages/installer/tests/unit/merger/yaml-merger.test.js +11 -11
- package/pro/README.md +12 -1
- package/pro/license/index.js +3 -11
- package/pro/license/license-api.js +25 -0
- package/pro/license/license-cache.js +135 -31
- package/pro/license/license-crypto.js +59 -3
- package/pro/package.json +5 -4
- package/pro/squads/README.md +16 -16
- package/pro/squads/index.js +1 -1
- package/scripts/e2e/installed-skills-smoke.js +264 -0
- package/scripts/package-synapse.js +3 -3
- package/scripts/validate-package-completeness.js +8 -11
- 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
|
+
};
|