axinstall 1.1.0 → 1.3.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/README.md +59 -21
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +14 -8
- package/dist/detect-agent.js +2 -2
- package/dist/detect-installer.d.ts +7 -7
- package/dist/detect-installer.js +13 -14
- package/dist/execute-install.d.ts +2 -0
- package/dist/execute-install.js +25 -3
- package/dist/handle-install.d.ts +1 -0
- package/dist/handle-install.js +47 -30
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/installer-data.d.ts +12 -3
- package/dist/installer-data.js +23 -9
- package/dist/resolve-installer-command.js +2 -1
- package/dist/run-command.d.ts +1 -0
- package/dist/run-command.js +3 -3
- package/dist/types.d.ts +2 -0
- package/dist/validate-cli-options.js +6 -0
- package/package.json +11 -17
package/README.md
CHANGED
|
@@ -6,24 +6,37 @@ Install AI CLI agents (Claude Code, Codex, Gemini, etc.) in any environment.
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Install Claude Code globally
|
|
9
|
-
npx axinstall claude
|
|
9
|
+
npx -y axinstall "claude"
|
|
10
10
|
|
|
11
11
|
# Install with a specific package manager
|
|
12
|
-
npx axinstall claude --with npm
|
|
12
|
+
npx -y axinstall "claude" --with "npm"
|
|
13
13
|
|
|
14
14
|
# Preview what would be installed (dry run)
|
|
15
|
-
npx axinstall claude --dry-run
|
|
15
|
+
npx -y axinstall "claude" --dry-run
|
|
16
16
|
|
|
17
17
|
# List supported agents
|
|
18
|
-
npx axinstall --list-agents
|
|
18
|
+
npx -y axinstall --list-agents
|
|
19
19
|
|
|
20
20
|
# Check installed agents and available package managers
|
|
21
|
-
npx axinstall --status
|
|
21
|
+
npx -y axinstall --status
|
|
22
|
+
|
|
23
|
+
# Enable verbose output
|
|
24
|
+
npx -y axinstall "claude" --verbose
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
##
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
- Node.js >=22.14.0
|
|
30
|
+
- Use `pnpm dlx` (recommended) or `npx` (bundled with npm) for one-off runs
|
|
31
|
+
- Examples assume a POSIX shell (sh/bash/zsh); adjust for PowerShell or CMD
|
|
32
|
+
|
|
33
|
+
By default, `axinstall` installs agents using **npm**. This means `npm` must be
|
|
34
|
+
available unless you explicitly override the installer:
|
|
35
|
+
|
|
36
|
+
- `--with <installer>` (e.g., `--with "pnpm"`)
|
|
37
|
+
- `AXINSTALL_WITH=<installer>`
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
Supported installers:
|
|
27
40
|
|
|
28
41
|
- npm
|
|
29
42
|
- pnpm
|
|
@@ -31,6 +44,11 @@ axinstall needs at least one supported package manager available:
|
|
|
31
44
|
- yarn
|
|
32
45
|
- Homebrew (`brew`)
|
|
33
46
|
|
|
47
|
+
## Conventions
|
|
48
|
+
|
|
49
|
+
- Prefer long flags in scripts (`--verbose` instead of `-v`)
|
|
50
|
+
- Examples include explicit quoting for flag values and arguments
|
|
51
|
+
|
|
34
52
|
### Custom Paths
|
|
35
53
|
|
|
36
54
|
Override the default binary lookup by setting environment variables:
|
|
@@ -48,34 +66,54 @@ export AXINSTALL_BREW_PATH=/path/to/brew
|
|
|
48
66
|
### Install agents
|
|
49
67
|
|
|
50
68
|
```bash
|
|
51
|
-
# Install using
|
|
52
|
-
axinstall claude
|
|
53
|
-
axinstall codex
|
|
54
|
-
axinstall gemini
|
|
69
|
+
# Install using npm (default)
|
|
70
|
+
npx -y axinstall "claude"
|
|
71
|
+
npx -y axinstall "codex"
|
|
72
|
+
npx -y axinstall "gemini"
|
|
55
73
|
|
|
56
74
|
# Force a specific package manager
|
|
57
|
-
axinstall claude --with npm
|
|
58
|
-
axinstall opencode --with brew
|
|
75
|
+
npx -y axinstall "claude" --with "npm"
|
|
76
|
+
npx -y axinstall "opencode" --with "brew"
|
|
59
77
|
|
|
60
78
|
# Install locally (not globally)
|
|
61
|
-
axinstall claude --local
|
|
79
|
+
npx -y axinstall "claude" --local
|
|
62
80
|
```
|
|
63
81
|
|
|
64
82
|
### Pipeline examples
|
|
65
83
|
|
|
66
84
|
```bash
|
|
67
85
|
# Get list of agent CLI names
|
|
68
|
-
axinstall --list-agents | tail -n +2 | cut -f1
|
|
86
|
+
npx -y axinstall --list-agents | tail -n +2 | cut -f1
|
|
69
87
|
|
|
70
88
|
# Find agents from a specific provider
|
|
71
|
-
axinstall --list-agents | tail -n +2 | awk -F'\t' '$4 == "Anthropic" {print $1}'
|
|
89
|
+
npx -y axinstall --list-agents | tail -n +2 | awk -F'\t' '$4 == "Anthropic" {print $1}'
|
|
72
90
|
|
|
73
91
|
# Get available installers only
|
|
74
|
-
axinstall --status --only installers | tail -n +2 | awk -F'\t' '$4 == "available" {print $2}'
|
|
92
|
+
npx -y axinstall --status --only "installers" | tail -n +2 | awk -F'\t' '$4 == "available" {print $2}'
|
|
75
93
|
|
|
76
94
|
# Count installed vs not found agents
|
|
77
|
-
axinstall --status --only agents | tail -n +2 | cut -f4 | sort | uniq -c
|
|
95
|
+
npx -y axinstall --status --only "agents" | tail -n +2 | cut -f4 | sort | uniq -c
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Output
|
|
99
|
+
|
|
100
|
+
`--list-agents` prints a tab-separated header and rows with columns:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
CLI NAME PACKAGE PROVIDER
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`--status` prints a tab-separated header and rows with columns:
|
|
107
|
+
|
|
78
108
|
```
|
|
109
|
+
TYPE ID NAME STATUS VERSION PROVIDER PACKAGE
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- `TYPE` values: `AGENT` | `INSTALLER`
|
|
113
|
+
- `STATUS` values:
|
|
114
|
+
- for `AGENT`: `installed` | `not_found`
|
|
115
|
+
- for `INSTALLER`: `available` | `not_found`
|
|
116
|
+
- `--only` values: `"all"` | `"agents"` | `"installers"`
|
|
79
117
|
|
|
80
118
|
## Agent Rule
|
|
81
119
|
|
|
@@ -86,9 +124,9 @@ Add to your `CLAUDE.md` or `AGENTS.md`:
|
|
|
86
124
|
|
|
87
125
|
Run `npx -y axinstall --help` to learn available options.
|
|
88
126
|
|
|
89
|
-
Use `axinstall` to install AI CLI agents in any environment. It
|
|
90
|
-
|
|
91
|
-
|
|
127
|
+
Use `axinstall` to install AI CLI agents in any environment. It uses the
|
|
128
|
+
requested package manager (via `--with` / `AXINSTALL_WITH`) and uses npm
|
|
129
|
+
by default.
|
|
92
130
|
```
|
|
93
131
|
|
|
94
132
|
## License
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* axinstall - AI agent installation CLI.
|
|
4
4
|
*
|
|
5
5
|
* Installs CLI agents (Claude Code, Codex, Gemini, etc.) using
|
|
6
|
-
*
|
|
6
|
+
* npm by default (override via --with or AXINSTALL_WITH).
|
|
7
7
|
*/
|
|
8
8
|
import { Command } from "@commander-js/extra-typings";
|
|
9
9
|
import { AGENT_CLIS } from "axshared";
|
|
@@ -31,20 +31,25 @@ const program = new Command()
|
|
|
31
31
|
.showSuggestionAfterError()
|
|
32
32
|
.option("--list-agents", "List supported agents")
|
|
33
33
|
.option("--status", "Show installed agents and available package managers")
|
|
34
|
-
.option("--only <scope>", "Limit --status output (agents|installers). Default: all.")
|
|
34
|
+
.option("--only <scope>", "Limit --status output (all|agents|installers). Default: all.")
|
|
35
35
|
.option("-v, --verbose", "Enable verbose output")
|
|
36
36
|
.addHelpText("after", `
|
|
37
37
|
Examples:
|
|
38
|
-
$ axinstall claude Install Claude Code
|
|
39
|
-
$ axinstall claude --
|
|
40
|
-
$ axinstall claude --
|
|
38
|
+
$ axinstall "claude" Install Claude Code globally
|
|
39
|
+
$ axinstall "claude" --local Install to node_modules/.bin
|
|
40
|
+
$ axinstall "claude" --with "npm" Use specific package manager
|
|
41
|
+
$ axinstall "claude" --dry-run Preview installation command
|
|
41
42
|
$ axinstall --list-agents | tail -n +2 | cut -f1 List agent CLI names
|
|
42
|
-
$ axinstall --status --only installers | grep available Show available installers
|
|
43
|
+
$ axinstall --status --only "installers" | grep available Show available installers
|
|
43
44
|
|
|
44
45
|
Environment:
|
|
45
|
-
AXINSTALL_WITH
|
|
46
|
+
AXINSTALL_WITH Force package manager (${INSTALLER_NAMES})
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
Default:
|
|
49
|
+
npm (requires npm unless overridden)
|
|
50
|
+
To use pnpm/bun/yarn/brew, pass --with <installer> or set AXINSTALL_WITH=<installer>.
|
|
51
|
+
|
|
52
|
+
Supported installers:
|
|
48
53
|
${INSTALLER_NAMES}
|
|
49
54
|
Override paths: ${INSTALLER_ENV_VARS}`);
|
|
50
55
|
// =============================================================================
|
|
@@ -53,6 +58,7 @@ Requirements:
|
|
|
53
58
|
program
|
|
54
59
|
.argument("[agent]", `Agent to install (${AGENT_CLIS.join(", ")})`)
|
|
55
60
|
.option("--with <installer>", `Package manager to use (${INSTALLER_IDS.join(", ")})`)
|
|
61
|
+
.option("--local", "Install to node_modules/.bin (run via package runner)", false)
|
|
56
62
|
.option("--dry-run", "Show command without executing", false)
|
|
57
63
|
.action((agentCli, cliOptions) => {
|
|
58
64
|
runCommand(agentCli, cliOptions);
|
package/dist/detect-agent.js
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Detects which AI agents are installed in the current environment.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
7
|
import { getAllAgents } from "axshared";
|
|
8
8
|
/**
|
|
9
9
|
* Check if a single agent is installed by running `<cli> --version`.
|
|
10
10
|
*/
|
|
11
11
|
function checkAgent(agent) {
|
|
12
12
|
try {
|
|
13
|
-
const output =
|
|
13
|
+
const output = execFileSync(agent.cli, ["--version"], {
|
|
14
14
|
encoding: "utf8",
|
|
15
15
|
stdio: ["pipe", "pipe", "pipe"],
|
|
16
16
|
}).trim();
|
|
@@ -16,14 +16,14 @@ declare function checkAllInstallers(): InstallerCheckResult[];
|
|
|
16
16
|
* Get all available installers.
|
|
17
17
|
*/
|
|
18
18
|
declare function getAvailableInstallers(): Installer[];
|
|
19
|
-
/**
|
|
20
|
-
* Auto-detect the best available installer based on priority.
|
|
21
|
-
*
|
|
22
|
-
* Priority order: npm > pnpm > bun > yarn > brew
|
|
23
|
-
*/
|
|
24
|
-
declare function detectBestInstaller(): Installer | undefined;
|
|
25
19
|
/**
|
|
26
20
|
* Check if a specific installer is available.
|
|
27
21
|
*/
|
|
28
22
|
declare function isInstallerAvailable(id: InstallerId): boolean;
|
|
29
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Detect the best available installer based on `INSTALLER_PRIORITY`.
|
|
25
|
+
*
|
|
26
|
+
* Retained for library consumers; the CLI defaults to npm unless overridden.
|
|
27
|
+
*/
|
|
28
|
+
declare function detectBestInstaller(): Installer | undefined;
|
|
29
|
+
export { checkInstaller, checkAllInstallers, getAvailableInstallers, isInstallerAvailable, detectBestInstaller, };
|
package/dist/detect-installer.js
CHANGED
|
@@ -46,24 +46,23 @@ function getAvailableInstallers() {
|
|
|
46
46
|
.map((result) => result.installer);
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Check if a specific installer is available.
|
|
50
|
+
*/
|
|
51
|
+
function isInstallerAvailable(id) {
|
|
52
|
+
const installer = getInstaller(id);
|
|
53
|
+
return checkInstaller(installer).available;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect the best available installer based on `INSTALLER_PRIORITY`.
|
|
50
57
|
*
|
|
51
|
-
*
|
|
58
|
+
* Retained for library consumers; the CLI defaults to npm unless overridden.
|
|
52
59
|
*/
|
|
53
60
|
function detectBestInstaller() {
|
|
54
|
-
const available = new Set(getAvailableInstallers().map((installer) => installer.id));
|
|
55
61
|
for (const id of INSTALLER_PRIORITY) {
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
62
|
+
if (!isInstallerAvailable(id))
|
|
63
|
+
continue;
|
|
64
|
+
return getInstaller(id);
|
|
59
65
|
}
|
|
60
66
|
return undefined;
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
* Check if a specific installer is available.
|
|
64
|
-
*/
|
|
65
|
-
function isInstallerAvailable(id) {
|
|
66
|
-
const installer = getInstaller(id);
|
|
67
|
-
return checkInstaller(installer).available;
|
|
68
|
-
}
|
|
69
|
-
export { checkInstaller, checkAllInstallers, getAvailableInstallers, detectBestInstaller, isInstallerAvailable, };
|
|
68
|
+
export { checkInstaller, checkAllInstallers, getAvailableInstallers, isInstallerAvailable, detectBestInstaller, };
|
package/dist/execute-install.js
CHANGED
|
@@ -5,13 +5,23 @@ 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 } = options;
|
|
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
|
-
|
|
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;
|
|
24
|
+
return installArguments.map((argument) => argument.replace("{package}", packageName));
|
|
15
25
|
}
|
|
16
26
|
function formatCommand(command, arguments_) {
|
|
17
27
|
const parts = [command, ...arguments_];
|
|
@@ -29,7 +39,19 @@ function buildInstallCommand(options) {
|
|
|
29
39
|
*/
|
|
30
40
|
function executeInstall(options) {
|
|
31
41
|
const command = resolveInstallerCommand(options.installer);
|
|
32
|
-
|
|
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
|
+
}
|
|
33
55
|
const displayCommand = formatCommand(command, arguments_);
|
|
34
56
|
if (options.dryRun) {
|
|
35
57
|
return { ok: true, command: displayCommand };
|
package/dist/handle-install.d.ts
CHANGED
package/dist/handle-install.js
CHANGED
|
@@ -2,22 +2,24 @@
|
|
|
2
2
|
* Agent installation handler.
|
|
3
3
|
*/
|
|
4
4
|
import { AGENT_CLIS, getAgent, isValidAgentCli } from "axshared";
|
|
5
|
-
import {
|
|
5
|
+
import { 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);
|
|
11
11
|
const INSTALLER_NAMES = INSTALLER_IDS.join(", ");
|
|
12
|
-
const INSTALLER_ENV_VARS = INSTALLER_IDS.map((id) => getInstaller(id).envVar).join(", ");
|
|
13
12
|
function isInstallerId(value) {
|
|
14
13
|
return INSTALLER_ID_SET.has(value);
|
|
15
14
|
}
|
|
16
15
|
function reportMissingInstaller(installer) {
|
|
17
16
|
const command = resolveInstallerCommand(installer);
|
|
18
17
|
console.error(`Error: Installer '${installer.id}' not available`);
|
|
19
|
-
|
|
18
|
+
// Escape control characters/newlines from env-var-controlled paths without
|
|
19
|
+
// adding surrounding quotes.
|
|
20
|
+
console.error(`Looked for: ${JSON.stringify(command).slice(1, -1)}`);
|
|
20
21
|
console.error(`Install ${installer.name} and try again.`);
|
|
22
|
+
console.error(`To use a different installer, pass --with <installer> (${INSTALLER_NAMES}) or set AXINSTALL_WITH=<installer>.`);
|
|
21
23
|
console.error(`Override path: ${installer.envVar}=/path/to/${installer.command}`);
|
|
22
24
|
console.error(`Run 'axinstall --status --only installers' to verify availability.`);
|
|
23
25
|
process.exitCode = 1;
|
|
@@ -31,36 +33,35 @@ export function handleInstall(agentCli, options) {
|
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
35
|
const agent = getAgent(agentCli);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
if (requestedInstaller) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
installer = getInstaller(requestedInstaller);
|
|
45
|
-
if (!isInstallerAvailable(requestedInstaller)) {
|
|
46
|
-
reportMissingInstaller(installer);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
36
|
+
const rawInstallerInput = options.with ?? process.env["AXINSTALL_WITH"];
|
|
37
|
+
const requestedInstaller = rawInstallerInput?.trim() || "npm";
|
|
38
|
+
if (!isInstallerId(requestedInstaller)) {
|
|
39
|
+
console.error(`Error: Unknown installer '${requestedInstaller}'`);
|
|
40
|
+
console.error(`Available: ${INSTALLER_IDS.join(", ")}`);
|
|
41
|
+
console.error("Try 'axinstall --help' for usage information.");
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
return;
|
|
49
44
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
45
|
+
const installer = getInstaller(requestedInstaller);
|
|
46
|
+
if (!isInstallerAvailable(requestedInstaller)) {
|
|
47
|
+
reportMissingInstaller(installer);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Validate local installation support
|
|
51
|
+
if (options.local && !installer.localInstallArgs) {
|
|
52
|
+
const localInstallers = getAllInstallers()
|
|
53
|
+
.filter((installer_) => installer_.localInstallArgs)
|
|
54
|
+
.map((installer_) => installer_.id)
|
|
55
|
+
.join(", ");
|
|
56
|
+
console.error(`Error: Installer '${installer.id}' does not support local installation`);
|
|
57
|
+
console.error(`Use a different installer: ${localInstallers}`);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
return;
|
|
60
60
|
}
|
|
61
61
|
const result = executeInstall({
|
|
62
62
|
agent,
|
|
63
63
|
installer,
|
|
64
|
+
local: options.local,
|
|
64
65
|
dryRun: options.dryRun,
|
|
65
66
|
});
|
|
66
67
|
if (options.dryRun) {
|
|
@@ -70,11 +71,27 @@ export function handleInstall(agentCli, options) {
|
|
|
70
71
|
if (result.ok) {
|
|
71
72
|
if (options.verbose) {
|
|
72
73
|
console.error(`Successfully installed ${agent.name}.`);
|
|
73
|
-
|
|
74
|
+
if (options.local) {
|
|
75
|
+
// Suggest the appropriate runner for the installer used
|
|
76
|
+
const runnerCommands = {
|
|
77
|
+
npm: `npx ${agent.cli}`,
|
|
78
|
+
pnpm: `pnpm exec ${agent.cli}`,
|
|
79
|
+
bun: `bunx ${agent.cli}`,
|
|
80
|
+
yarn: `yarn run ${agent.cli}`,
|
|
81
|
+
brew: agent.cli, // brew installs globally
|
|
82
|
+
};
|
|
83
|
+
console.error(`Run '${runnerCommands[installer.id]}' to get started.`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.error(`Run '${agent.cli}' to get started.`);
|
|
87
|
+
}
|
|
74
88
|
}
|
|
75
89
|
return;
|
|
76
90
|
}
|
|
77
91
|
console.error(`Error: Failed to install ${agent.name}`);
|
|
78
92
|
console.error(`Command: ${result.command}`);
|
|
93
|
+
if (result.error.message) {
|
|
94
|
+
console.error(`Details: ${result.error.message}`);
|
|
95
|
+
}
|
|
79
96
|
process.exitCode = 1;
|
|
80
97
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export { INSTALLER_IDS } from "./types.js";
|
|
7
7
|
export type { Installer, InstallerId, InstallerCheckResult } from "./types.js";
|
|
8
|
-
export { getInstaller, getAllInstallers, INSTALLERS,
|
|
9
|
-
export { checkInstaller, checkAllInstallers,
|
|
8
|
+
export { getInstaller, getAllInstallers, INSTALLERS, } from "./installer-data.js";
|
|
9
|
+
export { checkInstaller, checkAllInstallers, detectBestInstaller, getAvailableInstallers, isInstallerAvailable, } from "./detect-installer.js";
|
|
10
|
+
export { INSTALLER_PRIORITY } from "./installer-data.js";
|
|
10
11
|
export { checkAgent, checkAllAgents, getInstalledAgents, } from "./detect-agent.js";
|
|
11
12
|
export type { AgentCheckResult } from "./detect-agent.js";
|
|
12
13
|
export { buildInstallCommand, executeInstall } from "./execute-install.js";
|
package/dist/index.js
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// Types
|
|
7
7
|
export { INSTALLER_IDS } from "./types.js";
|
|
8
8
|
// Installer data
|
|
9
|
-
export { getInstaller, getAllInstallers, INSTALLERS,
|
|
9
|
+
export { getInstaller, getAllInstallers, INSTALLERS, } from "./installer-data.js";
|
|
10
10
|
// Installer detection
|
|
11
|
-
export { checkInstaller, checkAllInstallers,
|
|
11
|
+
export { checkInstaller, checkAllInstallers, detectBestInstaller, getAvailableInstallers, isInstallerAvailable, } from "./detect-installer.js";
|
|
12
|
+
export { INSTALLER_PRIORITY } from "./installer-data.js";
|
|
12
13
|
// Agent detection
|
|
13
14
|
export { checkAgent, checkAllAgents, getInstalledAgents, } from "./detect-agent.js";
|
|
14
15
|
// Installation
|
package/dist/installer-data.d.ts
CHANGED
|
@@ -2,10 +2,19 @@
|
|
|
2
2
|
* Installer definitions and metadata.
|
|
3
3
|
*/
|
|
4
4
|
import type { Installer, InstallerId } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Installer preference order used by `detectBestInstaller()` (library API).
|
|
7
|
+
*
|
|
8
|
+
* The CLI defaults to npm by design; this list is retained for programmatic
|
|
9
|
+
* consumers who want auto-detection.
|
|
10
|
+
*
|
|
11
|
+
* Note: Keep this order stable unless intentionally making a behavior change
|
|
12
|
+
* for library consumers.
|
|
13
|
+
*/
|
|
14
|
+
declare const INSTALLER_PRIORITY: readonly InstallerId[];
|
|
5
15
|
/** All installers indexed by ID */
|
|
6
16
|
declare const INSTALLERS: Record<InstallerId, Installer>;
|
|
7
|
-
/** Default priority order for auto-detection */
|
|
8
|
-
declare const INSTALLER_PRIORITY: readonly InstallerId[];
|
|
9
17
|
declare function getInstaller(id: InstallerId): Installer;
|
|
10
18
|
declare function getAllInstallers(): Installer[];
|
|
11
|
-
export { getInstaller, getAllInstallers, INSTALLERS
|
|
19
|
+
export { getInstaller, getAllInstallers, INSTALLERS };
|
|
20
|
+
export { INSTALLER_PRIORITY };
|
package/dist/installer-data.js
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Installer definitions and metadata.
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Installer preference order used by `detectBestInstaller()` (library API).
|
|
6
|
+
*
|
|
7
|
+
* The CLI defaults to npm by design; this list is retained for programmatic
|
|
8
|
+
* consumers who want auto-detection.
|
|
9
|
+
*
|
|
10
|
+
* Note: Keep this order stable unless intentionally making a behavior change
|
|
11
|
+
* for library consumers.
|
|
12
|
+
*/
|
|
13
|
+
const INSTALLER_PRIORITY = [
|
|
14
|
+
"npm",
|
|
15
|
+
"pnpm",
|
|
16
|
+
"bun",
|
|
17
|
+
"yarn",
|
|
18
|
+
"brew",
|
|
19
|
+
];
|
|
4
20
|
const npm = {
|
|
5
21
|
id: "npm",
|
|
6
22
|
name: "npm",
|
|
@@ -8,6 +24,7 @@ const npm = {
|
|
|
8
24
|
envVar: "AXINSTALL_NPM_PATH",
|
|
9
25
|
checkArgs: ["--version"],
|
|
10
26
|
installArgs: ["install", "-g", "{package}"],
|
|
27
|
+
localInstallArgs: ["install", "{package}"],
|
|
11
28
|
};
|
|
12
29
|
const pnpm = {
|
|
13
30
|
id: "pnpm",
|
|
@@ -16,6 +33,7 @@ const pnpm = {
|
|
|
16
33
|
envVar: "AXINSTALL_PNPM_PATH",
|
|
17
34
|
checkArgs: ["--version"],
|
|
18
35
|
installArgs: ["add", "-g", "{package}"],
|
|
36
|
+
localInstallArgs: ["add", "{package}"],
|
|
19
37
|
};
|
|
20
38
|
const bun = {
|
|
21
39
|
id: "bun",
|
|
@@ -24,6 +42,7 @@ const bun = {
|
|
|
24
42
|
envVar: "AXINSTALL_BUN_PATH",
|
|
25
43
|
checkArgs: ["--version"],
|
|
26
44
|
installArgs: ["add", "-g", "{package}"],
|
|
45
|
+
localInstallArgs: ["add", "{package}"],
|
|
27
46
|
};
|
|
28
47
|
const yarn = {
|
|
29
48
|
id: "yarn",
|
|
@@ -32,6 +51,7 @@ const yarn = {
|
|
|
32
51
|
envVar: "AXINSTALL_YARN_PATH",
|
|
33
52
|
checkArgs: ["--version"],
|
|
34
53
|
installArgs: ["global", "add", "{package}"],
|
|
54
|
+
localInstallArgs: ["add", "{package}"],
|
|
35
55
|
};
|
|
36
56
|
const brew = {
|
|
37
57
|
id: "brew",
|
|
@@ -40,6 +60,7 @@ const brew = {
|
|
|
40
60
|
envVar: "AXINSTALL_BREW_PATH",
|
|
41
61
|
checkArgs: ["--version"],
|
|
42
62
|
installArgs: ["install", "{package}"],
|
|
63
|
+
// No localInstallArgs - brew only installs globally
|
|
43
64
|
};
|
|
44
65
|
/** All installers indexed by ID */
|
|
45
66
|
const INSTALLERS = {
|
|
@@ -49,18 +70,11 @@ const INSTALLERS = {
|
|
|
49
70
|
yarn,
|
|
50
71
|
brew,
|
|
51
72
|
};
|
|
52
|
-
/** Default priority order for auto-detection */
|
|
53
|
-
const INSTALLER_PRIORITY = [
|
|
54
|
-
"npm",
|
|
55
|
-
"pnpm",
|
|
56
|
-
"bun",
|
|
57
|
-
"yarn",
|
|
58
|
-
"brew",
|
|
59
|
-
];
|
|
60
73
|
function getInstaller(id) {
|
|
61
74
|
return INSTALLERS[id];
|
|
62
75
|
}
|
|
63
76
|
function getAllInstallers() {
|
|
64
77
|
return Object.values(INSTALLERS);
|
|
65
78
|
}
|
|
66
|
-
export { getInstaller, getAllInstallers, INSTALLERS
|
|
79
|
+
export { getInstaller, getAllInstallers, INSTALLERS };
|
|
80
|
+
export { INSTALLER_PRIORITY };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
function resolveInstallerCommand(installer) {
|
|
2
2
|
const override = process.env[installer.envVar];
|
|
3
|
-
|
|
3
|
+
const trimmedOverride = override?.trim();
|
|
4
|
+
return trimmedOverride || installer.command;
|
|
4
5
|
}
|
|
5
6
|
export { resolveInstallerCommand };
|
package/dist/run-command.d.ts
CHANGED
package/dist/run-command.js
CHANGED
|
@@ -6,7 +6,7 @@ import { isStatusScope, printStatus, printSupportedAgents, } from "./print-statu
|
|
|
6
6
|
import { validateOptions } from "./validate-cli-options.js";
|
|
7
7
|
function reportUsageError(message) {
|
|
8
8
|
console.error(`Error: ${message}`);
|
|
9
|
-
console.error("Usage: axinstall [options]
|
|
9
|
+
console.error("Usage: axinstall [options] [agent]");
|
|
10
10
|
console.error(" axinstall --list-agents");
|
|
11
11
|
console.error(" axinstall --status [--only <scope>]");
|
|
12
12
|
console.error("Try 'axinstall --help' for usage information.");
|
|
@@ -25,14 +25,14 @@ export function runCommand(agentCli, options) {
|
|
|
25
25
|
if (options.status) {
|
|
26
26
|
const scopeInput = options.only?.toLowerCase() ?? "all";
|
|
27
27
|
if (!isStatusScope(scopeInput)) {
|
|
28
|
-
reportUsageError(`Invalid --only value '${options.only}'. Use agents or installers.`);
|
|
28
|
+
reportUsageError(`Invalid --only value '${options.only}'. Use all, agents, or installers.`);
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
printStatus(scopeInput);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
if (!agentCli) {
|
|
35
|
-
reportUsageError("Missing required argument 'agent'.");
|
|
35
|
+
reportUsageError("Missing required argument 'agent' (or use --list-agents/--status).");
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
handleInstall(agentCli, options);
|
package/dist/types.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ interface Installer {
|
|
|
16
16
|
checkArgs: readonly string[];
|
|
17
17
|
/** Args for global install. Use {package} as placeholder. */
|
|
18
18
|
installArgs: readonly string[];
|
|
19
|
+
/** Args for local install. Use {package} as placeholder. Undefined if not supported. */
|
|
20
|
+
localInstallArgs?: readonly string[];
|
|
19
21
|
}
|
|
20
22
|
/** Result of checking installer availability */
|
|
21
23
|
interface InstallerCheckResult {
|
|
@@ -26,6 +26,12 @@ export function validateOptions(agentCli, options) {
|
|
|
26
26
|
message: "--dry-run is only valid when installing an agent.",
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
+
if ((options.listAgents || options.status) && options.local) {
|
|
30
|
+
return {
|
|
31
|
+
valid: false,
|
|
32
|
+
message: "--local is only valid when installing an agent.",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
29
35
|
if (options.only && !options.status) {
|
|
30
36
|
return { valid: false, message: "--only must be used with --status." };
|
|
31
37
|
}
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"name": "axinstall",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
6
|
-
"description": "Universal installer for AI CLI agents
|
|
5
|
+
"version": "1.3.0",
|
|
6
|
+
"description": "Universal installer for AI CLI agents (defaults to npm)",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/Jercik/axinstall.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.28.1",
|
|
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": "^
|
|
72
|
+
"axshared": "^4.0.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
|
-
"@types/node": "^25.0.
|
|
80
|
-
"@vitest/coverage-v8": "^4.0.
|
|
81
|
-
"@vitest/eslint-plugin": "^1.6.5",
|
|
77
|
+
"@types/node": "^25.0.10",
|
|
78
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
82
79
|
"eslint": "^9.39.2",
|
|
83
|
-
"eslint-config-
|
|
84
|
-
"eslint-plugin-unicorn": "^62.0.0",
|
|
80
|
+
"eslint-config-axkit": "^1.1.0",
|
|
85
81
|
"fta-check": "^1.5.1",
|
|
86
82
|
"fta-cli": "^3.0.0",
|
|
87
|
-
"
|
|
88
|
-
"
|
|
89
|
-
"prettier": "3.7.4",
|
|
83
|
+
"knip": "^5.82.1",
|
|
84
|
+
"prettier": "3.8.1",
|
|
90
85
|
"semantic-release": "^25.0.2",
|
|
91
86
|
"typescript": "^5.9.3",
|
|
92
|
-
"
|
|
93
|
-
"vitest": "^4.0.16"
|
|
87
|
+
"vitest": "^4.0.17"
|
|
94
88
|
}
|
|
95
89
|
}
|