axinstall 1.0.0 → 1.2.0
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/dist/cli.js +3 -2
- package/dist/detect-installer.d.ts +1 -1
- package/dist/detect-installer.js +1 -1
- package/dist/execute-install.d.ts +2 -1
- package/dist/execute-install.js +24 -5
- package/dist/handle-install.d.ts +1 -1
- package/dist/handle-install.js +30 -4
- package/dist/installer-data.js +7 -7
- package/dist/run-command.d.ts +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/validate-cli-options.js +4 -4
- package/package.json +6 -12
package/dist/cli.js
CHANGED
|
@@ -35,7 +35,8 @@ const program = new Command()
|
|
|
35
35
|
.option("-v, --verbose", "Enable verbose output")
|
|
36
36
|
.addHelpText("after", `
|
|
37
37
|
Examples:
|
|
38
|
-
$ axinstall claude Install Claude Code
|
|
38
|
+
$ axinstall claude Install Claude Code globally
|
|
39
|
+
$ axinstall claude --local Install to node_modules/.bin
|
|
39
40
|
$ axinstall claude --with npm Use specific package manager
|
|
40
41
|
$ axinstall claude --dry-run Preview installation command
|
|
41
42
|
$ axinstall --list-agents | tail -n +2 | cut -f1 List agent CLI names
|
|
@@ -53,8 +54,8 @@ Requirements:
|
|
|
53
54
|
program
|
|
54
55
|
.argument("[agent]", `Agent to install (${AGENT_CLIS.join(", ")})`)
|
|
55
56
|
.option("--with <installer>", `Package manager to use (${INSTALLER_IDS.join(", ")})`)
|
|
57
|
+
.option("--local", "Install to node_modules/.bin (run via package runner)", false)
|
|
56
58
|
.option("--dry-run", "Show command without executing", false)
|
|
57
|
-
.option("--local", "Install locally instead of globally", false)
|
|
58
59
|
.action((agentCli, cliOptions) => {
|
|
59
60
|
runCommand(agentCli, cliOptions);
|
|
60
61
|
});
|
|
@@ -19,7 +19,7 @@ declare function getAvailableInstallers(): Installer[];
|
|
|
19
19
|
/**
|
|
20
20
|
* Auto-detect the best available installer based on priority.
|
|
21
21
|
*
|
|
22
|
-
* Priority order: pnpm > bun > yarn >
|
|
22
|
+
* Priority order: npm > pnpm > bun > yarn > brew
|
|
23
23
|
*/
|
|
24
24
|
declare function detectBestInstaller(): Installer | undefined;
|
|
25
25
|
/**
|
package/dist/detect-installer.js
CHANGED
|
@@ -48,7 +48,7 @@ function getAvailableInstallers() {
|
|
|
48
48
|
/**
|
|
49
49
|
* Auto-detect the best available installer based on priority.
|
|
50
50
|
*
|
|
51
|
-
* Priority order: pnpm > bun > yarn >
|
|
51
|
+
* Priority order: npm > pnpm > bun > yarn > brew
|
|
52
52
|
*/
|
|
53
53
|
function detectBestInstaller() {
|
|
54
54
|
const available = new Set(getAvailableInstallers().map((installer) => installer.id));
|
|
@@ -6,7 +6,8 @@ import type { Installer } from "./types.js";
|
|
|
6
6
|
interface InstallOptions {
|
|
7
7
|
agent: Agent;
|
|
8
8
|
installer: Installer;
|
|
9
|
-
|
|
9
|
+
/** Install locally instead of globally. Defaults to false. */
|
|
10
|
+
local?: boolean;
|
|
10
11
|
dryRun: boolean;
|
|
11
12
|
}
|
|
12
13
|
interface InstallResult {
|
package/dist/execute-install.js
CHANGED
|
@@ -5,15 +5,22 @@ import { execFileSync } from "node:child_process";
|
|
|
5
5
|
import { resolveInstallerCommand } from "./resolve-installer-command.js";
|
|
6
6
|
/**
|
|
7
7
|
* Build the installation arguments for an agent.
|
|
8
|
+
*
|
|
9
|
+
* @throws {Error} If local install is requested but the installer doesn't support it.
|
|
8
10
|
*/
|
|
9
11
|
function buildInstallArguments(options) {
|
|
10
|
-
const { agent, installer,
|
|
12
|
+
const { agent, installer, local } = options;
|
|
11
13
|
// For brew, use the CLI name as the package name (formula name)
|
|
12
14
|
// For npm-based installers, use the npm package name
|
|
13
15
|
const packageName = installer.id === "brew" ? agent.cli : agent.package;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
// Reject local installs when the installer doesn't support them
|
|
17
|
+
if (local) {
|
|
18
|
+
if (!installer.localInstallArgs) {
|
|
19
|
+
throw new Error(`Installer '${installer.id}' does not support local installation`);
|
|
20
|
+
}
|
|
21
|
+
return installer.localInstallArgs.map((argument) => argument.replace("{package}", packageName));
|
|
22
|
+
}
|
|
23
|
+
const installArguments = installer.installArgs;
|
|
17
24
|
return installArguments.map((argument) => argument.replace("{package}", packageName));
|
|
18
25
|
}
|
|
19
26
|
function formatCommand(command, arguments_) {
|
|
@@ -32,7 +39,19 @@ function buildInstallCommand(options) {
|
|
|
32
39
|
*/
|
|
33
40
|
function executeInstall(options) {
|
|
34
41
|
const command = resolveInstallerCommand(options.installer);
|
|
35
|
-
|
|
42
|
+
// Wrap argument building to catch validation errors and return InstallOutcome
|
|
43
|
+
let arguments_;
|
|
44
|
+
try {
|
|
45
|
+
arguments_ = buildInstallArguments(options);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const localFlag = options.local ? " (local)" : "";
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
command: `${options.installer.id}${localFlag}: ${command} ...`,
|
|
52
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
36
55
|
const displayCommand = formatCommand(command, arguments_);
|
|
37
56
|
if (options.dryRun) {
|
|
38
57
|
return { ok: true, command: displayCommand };
|
package/dist/handle-install.d.ts
CHANGED
package/dist/handle-install.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { AGENT_CLIS, getAgent, isValidAgentCli } from "axshared";
|
|
5
5
|
import { detectBestInstaller, isInstallerAvailable, } from "./detect-installer.js";
|
|
6
6
|
import { executeInstall } from "./execute-install.js";
|
|
7
|
-
import { getInstaller } from "./installer-data.js";
|
|
7
|
+
import { getAllInstallers, getInstaller } from "./installer-data.js";
|
|
8
8
|
import { resolveInstallerCommand } from "./resolve-installer-command.js";
|
|
9
9
|
import { INSTALLER_IDS } from "./types.js";
|
|
10
10
|
const INSTALLER_ID_SET = new Set(INSTALLER_IDS);
|
|
@@ -58,11 +58,21 @@ export function handleInstall(agentCli, options) {
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
// Validate local installation support
|
|
62
|
+
if (options.local && !installer.localInstallArgs) {
|
|
63
|
+
const localInstallers = getAllInstallers()
|
|
64
|
+
.filter((installer_) => installer_.localInstallArgs)
|
|
65
|
+
.map((installer_) => installer_.id)
|
|
66
|
+
.join(", ");
|
|
67
|
+
console.error(`Error: Installer '${installer.id}' does not support local installation`);
|
|
68
|
+
console.error(`Use a different installer: ${localInstallers}`);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
62
72
|
const result = executeInstall({
|
|
63
73
|
agent,
|
|
64
74
|
installer,
|
|
65
|
-
|
|
75
|
+
local: options.local,
|
|
66
76
|
dryRun: options.dryRun,
|
|
67
77
|
});
|
|
68
78
|
if (options.dryRun) {
|
|
@@ -72,11 +82,27 @@ export function handleInstall(agentCli, options) {
|
|
|
72
82
|
if (result.ok) {
|
|
73
83
|
if (options.verbose) {
|
|
74
84
|
console.error(`Successfully installed ${agent.name}.`);
|
|
75
|
-
|
|
85
|
+
if (options.local) {
|
|
86
|
+
// Suggest the appropriate runner for the installer used
|
|
87
|
+
const runnerCommands = {
|
|
88
|
+
npm: `npx ${agent.cli}`,
|
|
89
|
+
pnpm: `pnpm exec ${agent.cli}`,
|
|
90
|
+
bun: `bunx ${agent.cli}`,
|
|
91
|
+
yarn: `yarn run ${agent.cli}`,
|
|
92
|
+
brew: agent.cli, // brew installs globally
|
|
93
|
+
};
|
|
94
|
+
console.error(`Run '${runnerCommands[installer.id]}' to get started.`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.error(`Run '${agent.cli}' to get started.`);
|
|
98
|
+
}
|
|
76
99
|
}
|
|
77
100
|
return;
|
|
78
101
|
}
|
|
79
102
|
console.error(`Error: Failed to install ${agent.name}`);
|
|
80
103
|
console.error(`Command: ${result.command}`);
|
|
104
|
+
if (result.error.message) {
|
|
105
|
+
console.error(`Details: ${result.error.message}`);
|
|
106
|
+
}
|
|
81
107
|
process.exitCode = 1;
|
|
82
108
|
}
|
package/dist/installer-data.js
CHANGED
|
@@ -7,7 +7,7 @@ const npm = {
|
|
|
7
7
|
command: "npm",
|
|
8
8
|
envVar: "AXINSTALL_NPM_PATH",
|
|
9
9
|
checkArgs: ["--version"],
|
|
10
|
-
|
|
10
|
+
installArgs: ["install", "-g", "{package}"],
|
|
11
11
|
localInstallArgs: ["install", "{package}"],
|
|
12
12
|
};
|
|
13
13
|
const pnpm = {
|
|
@@ -16,7 +16,7 @@ const pnpm = {
|
|
|
16
16
|
command: "pnpm",
|
|
17
17
|
envVar: "AXINSTALL_PNPM_PATH",
|
|
18
18
|
checkArgs: ["--version"],
|
|
19
|
-
|
|
19
|
+
installArgs: ["add", "-g", "{package}"],
|
|
20
20
|
localInstallArgs: ["add", "{package}"],
|
|
21
21
|
};
|
|
22
22
|
const bun = {
|
|
@@ -25,7 +25,7 @@ const bun = {
|
|
|
25
25
|
command: "bun",
|
|
26
26
|
envVar: "AXINSTALL_BUN_PATH",
|
|
27
27
|
checkArgs: ["--version"],
|
|
28
|
-
|
|
28
|
+
installArgs: ["add", "-g", "{package}"],
|
|
29
29
|
localInstallArgs: ["add", "{package}"],
|
|
30
30
|
};
|
|
31
31
|
const yarn = {
|
|
@@ -34,7 +34,7 @@ const yarn = {
|
|
|
34
34
|
command: "yarn",
|
|
35
35
|
envVar: "AXINSTALL_YARN_PATH",
|
|
36
36
|
checkArgs: ["--version"],
|
|
37
|
-
|
|
37
|
+
installArgs: ["global", "add", "{package}"],
|
|
38
38
|
localInstallArgs: ["add", "{package}"],
|
|
39
39
|
};
|
|
40
40
|
const brew = {
|
|
@@ -43,8 +43,8 @@ const brew = {
|
|
|
43
43
|
command: "brew",
|
|
44
44
|
envVar: "AXINSTALL_BREW_PATH",
|
|
45
45
|
checkArgs: ["--version"],
|
|
46
|
-
|
|
47
|
-
localInstallArgs
|
|
46
|
+
installArgs: ["install", "{package}"],
|
|
47
|
+
// No localInstallArgs - brew only installs globally
|
|
48
48
|
};
|
|
49
49
|
/** All installers indexed by ID */
|
|
50
50
|
const INSTALLERS = {
|
|
@@ -56,10 +56,10 @@ const INSTALLERS = {
|
|
|
56
56
|
};
|
|
57
57
|
/** Default priority order for auto-detection */
|
|
58
58
|
const INSTALLER_PRIORITY = [
|
|
59
|
+
"npm",
|
|
59
60
|
"pnpm",
|
|
60
61
|
"bun",
|
|
61
62
|
"yarn",
|
|
62
|
-
"npm",
|
|
63
63
|
"brew",
|
|
64
64
|
];
|
|
65
65
|
function getInstaller(id) {
|
package/dist/run-command.d.ts
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -15,9 +15,9 @@ interface Installer {
|
|
|
15
15
|
/** Args for a version check. */
|
|
16
16
|
checkArgs: readonly string[];
|
|
17
17
|
/** Args for global install. Use {package} as placeholder. */
|
|
18
|
-
|
|
19
|
-
/** Args for local install. Use {package} as placeholder. */
|
|
20
|
-
localInstallArgs
|
|
18
|
+
installArgs: readonly string[];
|
|
19
|
+
/** Args for local install. Use {package} as placeholder. Undefined if not supported. */
|
|
20
|
+
localInstallArgs?: readonly string[];
|
|
21
21
|
}
|
|
22
22
|
/** Result of checking installer availability */
|
|
23
23
|
interface InstallerCheckResult {
|
|
@@ -20,16 +20,16 @@ export function validateOptions(agentCli, options) {
|
|
|
20
20
|
message: "--with is only valid when installing an agent.",
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
if ((options.listAgents || options.status) && options.
|
|
23
|
+
if ((options.listAgents || options.status) && options.dryRun) {
|
|
24
24
|
return {
|
|
25
25
|
valid: false,
|
|
26
|
-
message: "--
|
|
26
|
+
message: "--dry-run is only valid when installing an agent.",
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
if ((options.listAgents || options.status) && options.
|
|
29
|
+
if ((options.listAgents || options.status) && options.local) {
|
|
30
30
|
return {
|
|
31
31
|
valid: false,
|
|
32
|
-
message: "--
|
|
32
|
+
message: "--local is only valid when installing an agent.",
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
if (options.only && !options.status) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "axinstall",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.2.0",
|
|
6
6
|
"description": "Universal installer for AI CLI agents with automatic package manager detection",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"rebuild": "pnpm run clean && pnpm run build",
|
|
44
44
|
"start": "pnpm -s run rebuild && node bin/axinstall",
|
|
45
45
|
"test": "vitest run --exclude '**/*.integration.test.ts'",
|
|
46
|
+
"test:all": "vitest run --testTimeout=300000",
|
|
46
47
|
"test:coverage": "vitest run --coverage --exclude '**/*.integration.test.ts'",
|
|
47
48
|
"test:integration": "vitest run --testTimeout=300000 src/docker-install.integration.test.ts",
|
|
48
|
-
"test:all": "vitest run --testTimeout=300000",
|
|
49
49
|
"test:watch": "vitest --exclude '**/*.integration.test.ts'",
|
|
50
50
|
"typecheck": "tsc -b --noEmit"
|
|
51
51
|
},
|
|
@@ -63,33 +63,27 @@
|
|
|
63
63
|
"automation",
|
|
64
64
|
"coding-assistant"
|
|
65
65
|
],
|
|
66
|
-
"packageManager": "pnpm@10.
|
|
66
|
+
"packageManager": "pnpm@10.27.0",
|
|
67
67
|
"engines": {
|
|
68
68
|
"node": ">=22.14.0"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@commander-js/extra-typings": "^14.0.0",
|
|
72
|
-
"axshared": "^1.
|
|
72
|
+
"axshared": "^1.8.0",
|
|
73
73
|
"commander": "^14.0.2"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@eslint/compat": "^2.0.0",
|
|
77
|
-
"@eslint/js": "^9.39.2",
|
|
78
76
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
79
77
|
"@types/node": "^25.0.3",
|
|
80
78
|
"@vitest/coverage-v8": "^4.0.16",
|
|
81
|
-
"@vitest/eslint-plugin": "^1.5.4",
|
|
82
79
|
"eslint": "^9.39.2",
|
|
83
|
-
"eslint-config-
|
|
84
|
-
"eslint-plugin-unicorn": "^62.0.0",
|
|
80
|
+
"eslint-config-axkit": "^1.0.0",
|
|
85
81
|
"fta-check": "^1.5.1",
|
|
86
82
|
"fta-cli": "^3.0.0",
|
|
87
|
-
"
|
|
88
|
-
"knip": "^5.76.1",
|
|
83
|
+
"knip": "^5.80.0",
|
|
89
84
|
"prettier": "3.7.4",
|
|
90
85
|
"semantic-release": "^25.0.2",
|
|
91
86
|
"typescript": "^5.9.3",
|
|
92
|
-
"typescript-eslint": "^8.50.0",
|
|
93
87
|
"vitest": "^4.0.16"
|
|
94
88
|
}
|
|
95
89
|
}
|