axinstall 1.2.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 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
- ## Requirements
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
- axinstall needs at least one supported package manager available:
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 auto-detected package manager (pnpm > bun > yarn > npm > brew)
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 auto-detects
90
- the best available package manager (pnpm, bun, yarn, npm, brew) and handles
91
- the installation with a single command.
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
@@ -3,6 +3,6 @@
3
3
  * axinstall - AI agent installation CLI.
4
4
  *
5
5
  * Installs CLI agents (Claude Code, Codex, Gemini, etc.) using
6
- * the best available package manager in the environment.
6
+ * npm by default (override via --with or AXINSTALL_WITH).
7
7
  */
8
8
  export {};
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
- * the best available package manager in the environment.
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,21 +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 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
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
42
42
  $ axinstall --list-agents | tail -n +2 | cut -f1 List agent CLI names
43
- $ axinstall --status --only installers | grep available Show available installers
43
+ $ axinstall --status --only "installers" | grep available Show available installers
44
44
 
45
45
  Environment:
46
- AXINSTALL_WITH Default package manager (${INSTALLER_NAMES})
46
+ AXINSTALL_WITH Force package manager (${INSTALLER_NAMES})
47
47
 
48
- Requirements:
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:
49
53
  ${INSTALLER_NAMES}
50
54
  Override paths: ${INSTALLER_ENV_VARS}`);
51
55
  // =============================================================================
@@ -3,14 +3,14 @@
3
3
  *
4
4
  * Detects which AI agents are installed in the current environment.
5
5
  */
6
- import { execSync } from "node:child_process";
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 = execSync(`${agent.cli} --version`, {
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
- export { checkInstaller, checkAllInstallers, getAvailableInstallers, detectBestInstaller, isInstallerAvailable, };
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, };
@@ -46,24 +46,23 @@ function getAvailableInstallers() {
46
46
  .map((result) => result.installer);
47
47
  }
48
48
  /**
49
- * Auto-detect the best available installer based on priority.
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
- * Priority order: npm > pnpm > bun > yarn > brew
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 (available.has(id)) {
57
- return getInstaller(id);
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, };
@@ -2,22 +2,24 @@
2
2
  * Agent installation handler.
3
3
  */
4
4
  import { AGENT_CLIS, getAgent, isValidAgentCli } from "axshared";
5
- import { detectBestInstaller, isInstallerAvailable, } from "./detect-installer.js";
5
+ import { isInstallerAvailable } from "./detect-installer.js";
6
6
  import { executeInstall } from "./execute-install.js";
7
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
- console.error(`Looked for: ${command}`);
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,32 +33,19 @@ export function handleInstall(agentCli, options) {
31
33
  return;
32
34
  }
33
35
  const agent = getAgent(agentCli);
34
- const requestedInstaller = options.with ?? process.env["AXINSTALL_WITH"];
35
- let installer;
36
- if (requestedInstaller) {
37
- if (!isInstallerId(requestedInstaller)) {
38
- console.error(`Error: Unknown installer '${requestedInstaller}'`);
39
- console.error(`Available: ${INSTALLER_IDS.join(", ")}`);
40
- console.error("Try 'axinstall --help' for usage information.");
41
- process.exitCode = 1;
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
- else {
51
- installer = detectBestInstaller();
52
- if (!installer) {
53
- console.error("Error: No package manager found");
54
- console.error(`Install ${INSTALLER_NAMES} and try again.`);
55
- console.error(`Override paths: ${INSTALLER_ENV_VARS}`);
56
- console.error("Run 'axinstall --status --only installers' to verify availability.");
57
- process.exitCode = 1;
58
- return;
59
- }
45
+ const installer = getInstaller(requestedInstaller);
46
+ if (!isInstallerAvailable(requestedInstaller)) {
47
+ reportMissingInstaller(installer);
48
+ return;
60
49
  }
61
50
  // Validate local installation support
62
51
  if (options.local && !installer.localInstallArgs) {
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, INSTALLER_PRIORITY, } from "./installer-data.js";
9
- export { checkInstaller, checkAllInstallers, getAvailableInstallers, detectBestInstaller, isInstallerAvailable, } from "./detect-installer.js";
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, INSTALLER_PRIORITY, } from "./installer-data.js";
9
+ export { getInstaller, getAllInstallers, INSTALLERS, } from "./installer-data.js";
10
10
  // Installer detection
11
- export { checkInstaller, checkAllInstallers, getAvailableInstallers, detectBestInstaller, isInstallerAvailable, } from "./detect-installer.js";
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
@@ -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, INSTALLER_PRIORITY };
19
+ export { getInstaller, getAllInstallers, INSTALLERS };
20
+ export { INSTALLER_PRIORITY };
@@ -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",
@@ -54,18 +70,11 @@ const INSTALLERS = {
54
70
  yarn,
55
71
  brew,
56
72
  };
57
- /** Default priority order for auto-detection */
58
- const INSTALLER_PRIORITY = [
59
- "npm",
60
- "pnpm",
61
- "bun",
62
- "yarn",
63
- "brew",
64
- ];
65
73
  function getInstaller(id) {
66
74
  return INSTALLERS[id];
67
75
  }
68
76
  function getAllInstallers() {
69
77
  return Object.values(INSTALLERS);
70
78
  }
71
- export { getInstaller, getAllInstallers, INSTALLERS, INSTALLER_PRIORITY };
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
- return override && override.length > 0 ? override : installer.command;
3
+ const trimmedOverride = override?.trim();
4
+ return trimmedOverride || installer.command;
4
5
  }
5
6
  export { resolveInstallerCommand };
@@ -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] <agent>");
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/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "name": "axinstall",
3
3
  "author": "Łukasz Jerciński",
4
4
  "license": "MIT",
5
- "version": "1.2.0",
6
- "description": "Universal installer for AI CLI agents with automatic package manager detection",
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"
@@ -63,27 +63,27 @@
63
63
  "automation",
64
64
  "coding-assistant"
65
65
  ],
66
- "packageManager": "pnpm@10.27.0",
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": "^1.8.0",
72
+ "axshared": "^4.0.0",
73
73
  "commander": "^14.0.2"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@total-typescript/ts-reset": "^0.6.1",
77
- "@types/node": "^25.0.3",
78
- "@vitest/coverage-v8": "^4.0.16",
77
+ "@types/node": "^25.0.10",
78
+ "@vitest/coverage-v8": "^4.0.17",
79
79
  "eslint": "^9.39.2",
80
- "eslint-config-axkit": "^1.0.0",
80
+ "eslint-config-axkit": "^1.1.0",
81
81
  "fta-check": "^1.5.1",
82
82
  "fta-cli": "^3.0.0",
83
- "knip": "^5.80.0",
84
- "prettier": "3.7.4",
83
+ "knip": "^5.82.1",
84
+ "prettier": "3.8.1",
85
85
  "semantic-release": "^25.0.2",
86
86
  "typescript": "^5.9.3",
87
- "vitest": "^4.0.16"
87
+ "vitest": "^4.0.17"
88
88
  }
89
89
  }