Skip to content

Commit 441b090

Browse files
committed
fix(installer): resolve npm cli when launched via npx
1 parent c3b839a commit 441b090

9 files changed

Lines changed: 81 additions & 13 deletions

File tree

.aiox-core/install-manifest.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
# - SHA256 hashes for change detection
88
# - File types for categorization
99
#
10-
version: 5.2.8
11-
generated_at: "2026-05-21T00:21:31.048Z"
10+
version: 5.2.9
11+
generated_at: "2026-05-21T01:42:24.351Z"
1212
generator: scripts/generate-install-manifest.js
1313
file_count: 1129
1414
files:
@@ -3701,7 +3701,7 @@ files:
37013701
type: monitor
37023702
size: 818
37033703
- path: package.json
3704-
hash: sha256:bc1bd0eae7c04feb1d1659fb9715a7c908e1cf2bb146341ed3b0d24f630cc9a9
3704+
hash: sha256:d8dbe037240a366d545ca4259d2059e705b709706dcf2a18a5a52d9b543b7ed9
37053705
type: other
37063706
size: 1445
37073707
- path: product/checklists/accessibility-wcag-checklist.md

.aiox-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aiox-squads/core-internal",
3-
"version": "5.2.8",
3+
"version": "5.2.9",
44
"description": "Internal package manifest for AIOX framework — declares runtime dependencies consumed by scripts under .aiox-core/. This is NOT published independently; it ships inside @aiox-squads/core (the top-level package). Kept name-distinct from the parent (`-internal` suffix) to avoid npm registry confusion. Version follows the parent package.",
55
"private": true,
66
"main": "index.js",

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ All notable changes to Synkra AIOX will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [5.2.9] - 2026-05-21
9+
10+
### Fixed
11+
12+
- **Pro artifact install no longer invokes `npx install` when the installer itself runs through `npx`**.
13+
- Root cause: `npm_execpath` can point at `npx-cli.js` during `npx -p @aiox-squads/core aiox install`.
14+
- Fix: the installer now derives the sibling `npm-cli.js` when available and otherwise falls back to `npm`, so Pro artifact extraction keeps running `npm install <tgz> --prefix <target>`.
15+
- This targets Linux installs that authenticated and activated Pro successfully, then failed at content installation with `unexpected argument '--prefix' found`.
16+
17+
### Changed
18+
19+
- `@aiox-squads/installer` bumped to `3.3.8` to ship the Pro artifact extraction fix.
20+
821
## [5.2.8] - 2026-05-21
922

1023
### Fixed

compat/aiox-core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "aiox-core",
3-
"version": "5.2.8",
3+
"version": "5.2.9",
44
"description": "Compatibility wrapper for @aiox-squads/core.",
55
"license": "MIT",
66
"bin": {
@@ -15,7 +15,7 @@
1515
"README.md"
1616
],
1717
"dependencies": {
18-
"@aiox-squads/core": "5.2.8"
18+
"@aiox-squads/core": "5.2.9"
1919
},
2020
"engines": {
2121
"node": ">=18"

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aiox-squads/core",
3-
"version": "5.2.8",
3+
"version": "5.2.9",
44
"description": "Synkra AIOX: AI-Orchestrated System for Full Stack Development - Core Framework",
55
"bin": {
66
"aiox": "bin/aiox.js",

packages/installer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aiox-squads/installer",
3-
"version": "3.3.7",
3+
"version": "3.3.8",
44
"description": "AIOX Installer - Automated setup wizard for AIOX projects (greenfield & brownfield)",
55
"main": "src/index.js",
66
"bin": {

packages/installer/src/wizard/pro-setup.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,39 @@ function stripWrappingQuotes(value) {
3232
return String(value || '').trim().replace(/^"(.*)"$/, '$1');
3333
}
3434

35+
function resolveNpmExecPath(npmExecPath, fileExists = fs.existsSync) {
36+
if (!npmExecPath || !/\.js$/i.test(npmExecPath)) {
37+
return null;
38+
}
39+
40+
const pathApi = npmExecPath.includes('\\') ? path.win32 : path;
41+
const basename = pathApi.basename(npmExecPath).toLowerCase();
42+
if (basename === 'npm-cli.js' && fileExists(npmExecPath)) {
43+
return npmExecPath;
44+
}
45+
46+
if (basename === 'npx-cli.js') {
47+
const npmCliPath = pathApi.join(pathApi.dirname(npmExecPath), 'npm-cli.js');
48+
if (fileExists(npmCliPath)) {
49+
return npmCliPath;
50+
}
51+
}
52+
53+
return null;
54+
}
55+
3556
function resolveNpmInvocation(options = {}) {
3657
const platform = options.platform || process.platform;
3758
const env = options.env || process.env;
3859
const execPath = options.execPath || process.execPath;
3960
const fileExists = options.fileExists || fs.existsSync;
4061
const npmExecPath = stripWrappingQuotes(env.npm_execpath);
62+
const npmCliPath = resolveNpmExecPath(npmExecPath, fileExists);
4163

42-
if (npmExecPath && /\.js$/i.test(npmExecPath) && fileExists(npmExecPath)) {
64+
if (npmCliPath) {
4365
return {
4466
command: execPath,
45-
prefixArgs: [npmExecPath],
67+
prefixArgs: [npmCliPath],
4668
execOptions: {},
4769
};
4870
}

tests/installer/pro-setup-auth.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,39 @@ describe('pro-setup npm invocation', () => {
187187
});
188188
});
189189

190+
it('derives npm-cli.js when invoked through npx-cli.js', () => {
191+
const invocation = proSetup._testing.resolveNpmInvocation({
192+
platform: 'linux',
193+
execPath: '/usr/bin/node',
194+
env: {
195+
npm_execpath: '/usr/lib/node_modules/npm/bin/npx-cli.js',
196+
},
197+
fileExists: (candidate) => candidate.endsWith('/npm-cli.js'),
198+
});
199+
200+
expect(invocation).toEqual({
201+
command: '/usr/bin/node',
202+
prefixArgs: ['/usr/lib/node_modules/npm/bin/npm-cli.js'],
203+
execOptions: {},
204+
});
205+
});
206+
207+
it('does not execute npx-cli.js as npm when npm-cli.js cannot be found', () => {
208+
const invocation = proSetup._testing.resolveNpmInvocation({
209+
platform: 'linux',
210+
env: {
211+
npm_execpath: '/usr/lib/node_modules/npm/bin/npx-cli.js',
212+
},
213+
fileExists: () => false,
214+
});
215+
216+
expect(invocation).toEqual({
217+
command: 'npm',
218+
prefixArgs: [],
219+
execOptions: {},
220+
});
221+
});
222+
190223
it('falls back to shell execution for npm.cmd on Windows', () => {
191224
const invocation = proSetup._testing.resolveNpmInvocation({
192225
platform: 'win32',

0 commit comments

Comments
 (0)