@almyty/cli 0.1.3 → 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
@@ -1,43 +1,113 @@
1
1
  # @almyty/cli
2
2
 
3
- Umbrella CLI for almyty. One install, every command.
3
+ Umbrella CLI for almyty. One install, one login, every command.
4
4
 
5
5
  ## Quick start
6
6
 
7
7
  ```bash
8
8
  $ npm install -g @almyty/cli
9
+ $ almyty # a short tour
9
10
  $ almyty login
10
11
  $ almyty agents list
11
12
  ```
12
13
 
14
+ `almyty` on its own prints a five-line tour. `almyty help` prints the
15
+ full reference, and `almyty <command> --help` prints that command's own
16
+ options — the umbrella forwards `--help` to the package it delegates to.
17
+
13
18
  ## Commands
14
19
 
15
20
  | Command | Delegates to | Description |
16
21
  |---------|-------------|-------------|
17
- | `almyty login` | `@almyty/auth` | Browser-based login |
22
+ | `almyty login` | `@almyty/auth` | Browser-based login (writes `~/.almyty/credentials.json`) |
18
23
  | `almyty logout` | `@almyty/auth` | Remove stored credentials |
19
- | `almyty whoami` | `@almyty/auth` | Show current identity |
20
- | `almyty agents <cmd>` | `@almyty/agents` | List, run, inspect agents |
21
- | `almyty chat [name\|id]` | `@almyty/chat` | Interactive chat REPL |
22
- | `almyty skills <cmd>` | `@almyty/skills` | Install and manage skills |
23
- | `almyty mcp <args>` | `@almyty/mcp-server` | Start MCP server |
24
+ | `almyty whoami` | `@almyty/auth` | Show the current identity and when it expires |
25
+ | `almyty auth <cmd>` | `@almyty/auth` | The same three, spelled out |
26
+ | `almyty agents <cmd>` | `@almyty/agents` | List, run, inspect and trace agents |
27
+ | `almyty chat [ref]` | `@almyty/chat` | Interactive chat REPL |
28
+ | `almyty skills <cmd>` | `@almyty/skills` | Install API skills into AI coding agents |
29
+ | `almyty models <cmd>` | `@almyty/models` | Model catalog: cards, validation, deployments |
30
+ | `almyty connections <cmd>` | `@almyty/connections` | Connect third-party accounts, validate, grant |
31
+ | `almyty runner <cmd>` | `@almyty/runner` | Run agents on this machine as a daemon |
32
+ | `almyty mcp <args>` | `@almyty/mcp-server` | Serve your agents and tools over MCP |
33
+ | `almyty acp <args>` | `@almyty/acp-server` | Serve an agent over the Agent Client Protocol |
34
+
35
+ Handled by the umbrella itself:
36
+
37
+ | Command | Description |
38
+ |---------|-------------|
39
+ | `almyty help`, `--help` | The full command reference |
40
+ | `almyty version`, `--version` | The installed version |
41
+ | `almyty completion <shell>` | A completion script for `bash`, `zsh` or `fish` |
42
+
43
+ An unknown command exits `2` and suggests the nearest real one
44
+ (`almyty agent list` → "Did you mean `almyty agents`?").
45
+
46
+ ## Shell completion
47
+
48
+ ```bash
49
+ # bash — add to ~/.bashrc
50
+ eval "$(almyty completion bash)"
51
+
52
+ # zsh — add to ~/.zshrc
53
+ eval "$(almyty completion zsh)"
54
+
55
+ # fish
56
+ almyty completion fish > ~/.config/fish/completions/almyty.fish
57
+ ```
58
+
59
+ ## Exit codes
60
+
61
+ The same table in every almyty CLI, so `almyty <anything>` can be
62
+ scripted the same way:
63
+
64
+ | Code | Meaning |
65
+ |------|---------|
66
+ | `0` | success |
67
+ | `1` | unexpected error |
68
+ | `2` | usage error (bad flags, unknown command) |
69
+ | `3` | not authenticated — run `almyty login` |
70
+ | `4` | not found (agent, gateway, skill, or run) |
71
+ | `5` | the operation ran and failed |
72
+
73
+ ```bash
74
+ almyty agents run deploy-check --watch || case $? in
75
+ 3) almyty login ;;
76
+ 5) echo "the check failed"; exit 1 ;;
77
+ esac
78
+ ```
24
79
 
25
80
  ## Standalone packages
26
81
 
27
- Every subcommand is also available as a standalone package via `npx`:
82
+ Every subcommand is also a standalone package, so the umbrella is a
83
+ convenience and not a requirement:
28
84
 
29
85
  ```bash
86
+ $ npx @almyty/auth login
30
87
  $ npx @almyty/agents list
31
- $ npx @almyty/chat my-bot
32
- $ npx @almyty/skills install @org/gateway
88
+ $ npx @almyty/chat myorg/my-bot
89
+ $ npx @almyty/skills install org/gateway
33
90
  ```
34
91
 
35
- All packages share the same credentials file (`~/.almyty/credentials.json`), so logging in once works everywhere.
92
+ They all read the same credentials file (`~/.almyty/credentials.json`),
93
+ so logging in once works everywhere.
94
+
95
+ ## Piping
96
+
97
+ Every read command takes `--json` and prints nothing but JSON on stdout.
98
+ No almyty CLI emits ANSI colour of its own, so `NO_COLOR` is honoured
99
+ and there is nothing to strip when you pipe.
100
+
101
+ ## About almyty
36
102
 
37
- ## Docs
103
+ almyty is the full-stack platform for AI agents, agnostic by design: any LLM, any
104
+ API turned into tools, served over MCP, A2A, UTCP, and Agent Skills. Open source,
105
+ no lock-in.
38
106
 
39
- https://almyty.com/docs
107
+ - Website: https://almyty.com
108
+ - Docs: https://docs.almyty.com
109
+ - Source: https://github.com/almyty-inc/almyty
40
110
 
41
- ## License
111
+ This CLI is part of the `@almyty/*` suite (versioned together at 1.x) and works with the almyty platform 0.1 and later.
42
112
 
43
- BSL-1.1
113
+ Apache-2.0 © Almyty Inc.
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The umbrella's routing table, help text, and shell completion.
3
+ *
4
+ * Kept out of index.ts so it can be unit-tested without spawning a
5
+ * child process: every entry here must be listed in the help text and
6
+ * must name a package the umbrella actually depends on, and there are
7
+ * tests that assert both.
8
+ */
9
+ export interface Subcommand {
10
+ /** Package name to delegate to. */
11
+ pkg: string;
12
+ /**
13
+ * Optional argv prefix injected before the user-supplied args.
14
+ * Used for top-level shortcuts like `almyty login` -> `@almyty/auth login`.
15
+ */
16
+ prefixArgs?: string[];
17
+ /** Short help line shown by `almyty help`. */
18
+ help: string;
19
+ /** Section heading this command is grouped under in the help output. */
20
+ group: string;
21
+ /** Subcommand names, for shell completion. Empty when it takes free-form args. */
22
+ subcommands?: string[];
23
+ }
24
+ /**
25
+ * Top-level subcommand routing table. Order = display order in help.
26
+ *
27
+ * Every `pkg` here must be a dependency of @almyty/cli. `models` and
28
+ * `connections` were listed in the help text while the umbrella did
29
+ * not depend on them, so `almyty models list` answered "package
30
+ * @almyty/models is not installed" for a command its own --help
31
+ * advertised.
32
+ */
33
+ export declare const SUBCOMMANDS: Record<string, Subcommand>;
34
+ /** Commands the umbrella answers itself, rather than delegating. */
35
+ export declare const BUILTIN_COMMANDS: readonly ["help", "version", "completion"];
36
+ /** Every name `almyty <x>` accepts, for completion and suggestions. */
37
+ export declare function allCommandNames(): string[];
38
+ /**
39
+ * A short tour, printed when `almyty` is run with no arguments.
40
+ *
41
+ * A bare `almyty` used to print the entire command reference, which is
42
+ * the least useful thing to show someone who has just installed it and
43
+ * does not yet know what the product does.
44
+ */
45
+ export declare function tourText(version: string): string;
46
+ /** The full command reference, printed by `almyty help` / `--help`. */
47
+ export declare function helpText(version: string): string;
48
+ /**
49
+ * The closest command name to what the user typed, or null.
50
+ * `almyty agent list` (singular) should not just say "unknown command".
51
+ */
52
+ export declare function suggestCommand(input: string): string | null;
53
+ export declare const COMPLETION_SHELLS: readonly ["bash", "zsh", "fish"];
54
+ export type CompletionShell = (typeof COMPLETION_SHELLS)[number];
55
+ export declare function isCompletionShell(value: string): value is CompletionShell;
56
+ /**
57
+ * A completion script for one shell. Static — it lists the top-level
58
+ * commands and each one's own subcommands from the table above, so it
59
+ * never has to shell out to the sub-CLIs to build a candidate list.
60
+ */
61
+ export declare function completionScript(shell: CompletionShell): string;
@@ -0,0 +1,204 @@
1
+ /**
2
+ * The umbrella's routing table, help text, and shell completion.
3
+ *
4
+ * Kept out of index.ts so it can be unit-tested without spawning a
5
+ * child process: every entry here must be listed in the help text and
6
+ * must name a package the umbrella actually depends on, and there are
7
+ * tests that assert both.
8
+ */
9
+ /**
10
+ * Top-level subcommand routing table. Order = display order in help.
11
+ *
12
+ * Every `pkg` here must be a dependency of @almyty/cli. `models` and
13
+ * `connections` were listed in the help text while the umbrella did
14
+ * not depend on them, so `almyty models list` answered "package
15
+ * @almyty/models is not installed" for a command its own --help
16
+ * advertised.
17
+ */
18
+ export const SUBCOMMANDS = {
19
+ // Auth shortcuts at top level (gh-style: `almyty login` not `almyty auth login`)
20
+ login: { pkg: '@almyty/auth', prefixArgs: ['login'], group: 'Auth', help: 'Browser-based login (writes ~/.almyty/credentials.json)' },
21
+ logout: { pkg: '@almyty/auth', prefixArgs: ['logout'], group: 'Auth', help: 'Remove stored credentials' },
22
+ whoami: { pkg: '@almyty/auth', prefixArgs: ['whoami'], group: 'Auth', help: 'Show the current identity' },
23
+ auth: { pkg: '@almyty/auth', group: 'Auth', help: 'Auth subcommands', subcommands: ['login', 'logout', 'whoami'] },
24
+ // Domain CLIs
25
+ agents: { pkg: '@almyty/agents', group: 'Agents', help: 'List, run, and inspect agents', subcommands: ['list', 'get', 'run', 'runs', 'inspect', 'executions', 'trace', 'cancel'] },
26
+ chat: { pkg: '@almyty/chat', group: 'Agents', help: 'Interactive chat REPL with an agent' },
27
+ skills: { pkg: '@almyty/skills', group: 'Skills', help: 'Install API skills into AI coding agents', subcommands: ['install', 'list', 'search', 'run', 'installed', 'remove', 'gateways', 'daemon', 'watch'] },
28
+ models: { pkg: '@almyty/models', group: 'Platform', help: 'Model catalog: cards, validation, deployments' },
29
+ connections: { pkg: '@almyty/connections', group: 'Platform', help: 'Connect third-party accounts: connectors, validate, grants' },
30
+ runner: { pkg: '@almyty/runner', group: 'Serving', help: 'Run agents on this machine as a daemon' },
31
+ mcp: { pkg: '@almyty/mcp-server', group: 'Serving', help: 'Serve your agents and tools over MCP' },
32
+ acp: { pkg: '@almyty/acp-server', group: 'Serving', help: 'Serve an agent over the Agent Client Protocol' },
33
+ };
34
+ /** Commands the umbrella answers itself, rather than delegating. */
35
+ export const BUILTIN_COMMANDS = ['help', 'version', 'completion'];
36
+ /** Every name `almyty <x>` accepts, for completion and suggestions. */
37
+ export function allCommandNames() {
38
+ return [...Object.keys(SUBCOMMANDS), ...BUILTIN_COMMANDS];
39
+ }
40
+ /**
41
+ * A short tour, printed when `almyty` is run with no arguments.
42
+ *
43
+ * A bare `almyty` used to print the entire command reference, which is
44
+ * the least useful thing to show someone who has just installed it and
45
+ * does not yet know what the product does.
46
+ */
47
+ export function tourText(version) {
48
+ return `almyty v${version} — build, run, and serve AI agents.
49
+
50
+ Start here:
51
+ almyty login Authenticate this machine
52
+ almyty agents list See the agents in your organization
53
+ almyty agents run <agent> Run one and print its output
54
+ almyty chat <agent> Talk to one in your terminal
55
+ almyty skills install <ref> Teach your coding agent an API
56
+
57
+ almyty help Every command, grouped
58
+ almyty <command> --help Detail for one command
59
+
60
+ Docs: https://docs.almyty.com`;
61
+ }
62
+ /** The full command reference, printed by `almyty help` / `--help`. */
63
+ export function helpText(version) {
64
+ const groups = new Map();
65
+ const width = Math.max(...Object.keys(SUBCOMMANDS).map((n) => n.length), 'completion <shell>'.length);
66
+ for (const [name, sub] of Object.entries(SUBCOMMANDS)) {
67
+ const lines = groups.get(sub.group) ?? [];
68
+ lines.push(` ${name.padEnd(width)} ${sub.help}`);
69
+ groups.set(sub.group, lines);
70
+ }
71
+ const sections = [...groups.entries()]
72
+ .map(([group, lines]) => `${group}:\n${lines.join('\n')}`)
73
+ .join('\n\n');
74
+ return `almyty CLI v${version}
75
+
76
+ Usage:
77
+ almyty <command> [args]
78
+ almyty <command> --help Full options for that command
79
+
80
+ ${sections}
81
+
82
+ Other:
83
+ ${'help'.padEnd(width)} Show this help
84
+ ${'version'.padEnd(width)} Print the version
85
+ ${'completion <shell>'.padEnd(width)} Print a completion script (bash, zsh, fish)
86
+
87
+ Exit codes (the same in every almyty CLI):
88
+ 0 success
89
+ 1 unexpected error
90
+ 2 usage error (bad flags, unknown command)
91
+ 3 not authenticated — run \`almyty login\`
92
+ 4 not found (agent, gateway, skill, or run)
93
+ 5 the operation ran and failed
94
+
95
+ Every subcommand is also a standalone package, so nothing here is
96
+ required in order to use one of them:
97
+
98
+ npx @almyty/auth login
99
+ npx @almyty/agents list
100
+ npx @almyty/chat my-research-bot
101
+ npx @almyty/skills install org/gateway
102
+
103
+ They all read the same credentials file (~/.almyty/credentials.json),
104
+ so \`almyty login\` logs all of them in at once.`;
105
+ }
106
+ /** Levenshtein distance, capped — only used to suggest a command name. */
107
+ function distance(a, b) {
108
+ const rows = a.length + 1;
109
+ const cols = b.length + 1;
110
+ let prev = Array.from({ length: cols }, (_, j) => j);
111
+ for (let i = 1; i < rows; i++) {
112
+ const curr = [i];
113
+ for (let j = 1; j < cols; j++) {
114
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
115
+ }
116
+ prev = curr;
117
+ }
118
+ return prev[cols - 1];
119
+ }
120
+ /**
121
+ * The closest command name to what the user typed, or null.
122
+ * `almyty agent list` (singular) should not just say "unknown command".
123
+ */
124
+ export function suggestCommand(input) {
125
+ const typed = input.toLowerCase();
126
+ let best = null;
127
+ let bestScore = Infinity;
128
+ for (const name of allCommandNames()) {
129
+ const d = distance(typed, name);
130
+ if (d < bestScore) {
131
+ bestScore = d;
132
+ best = name;
133
+ }
134
+ }
135
+ const tolerance = typed.length <= 4 ? 1 : 2;
136
+ return best !== null && bestScore <= tolerance ? best : null;
137
+ }
138
+ export const COMPLETION_SHELLS = ['bash', 'zsh', 'fish'];
139
+ export function isCompletionShell(value) {
140
+ return COMPLETION_SHELLS.includes(value);
141
+ }
142
+ /**
143
+ * A completion script for one shell. Static — it lists the top-level
144
+ * commands and each one's own subcommands from the table above, so it
145
+ * never has to shell out to the sub-CLIs to build a candidate list.
146
+ */
147
+ export function completionScript(shell) {
148
+ const top = allCommandNames().join(' ');
149
+ if (shell === 'bash') {
150
+ const cases = Object.entries(SUBCOMMANDS)
151
+ .filter(([, s]) => s.subcommands?.length)
152
+ .map(([name, s]) => ` ${name}) subs="${s.subcommands.join(' ')}" ;;`)
153
+ .join('\n');
154
+ return `# almyty bash completion — add to ~/.bashrc:
155
+ # eval "$(almyty completion bash)"
156
+ _almyty_complete() {
157
+ local cur prev subs
158
+ cur="\${COMP_WORDS[COMP_CWORD]}"
159
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
160
+ if [ "$COMP_CWORD" -eq 1 ]; then
161
+ COMPREPLY=( $(compgen -W "${top}" -- "$cur") )
162
+ return
163
+ fi
164
+ subs=""
165
+ case "\${COMP_WORDS[1]}" in
166
+ ${cases}
167
+ completion) subs="bash zsh fish" ;;
168
+ esac
169
+ if [ -n "$subs" ] && [ "$COMP_CWORD" -eq 2 ]; then
170
+ COMPREPLY=( $(compgen -W "$subs" -- "$cur") )
171
+ fi
172
+ }
173
+ complete -F _almyty_complete almyty`;
174
+ }
175
+ if (shell === 'zsh') {
176
+ const descs = Object.entries(SUBCOMMANDS)
177
+ .map(([name, s]) => ` '${name}:${s.help.replace(/'/g, '')}'`)
178
+ .join('\n');
179
+ return `# almyty zsh completion — add to ~/.zshrc:
180
+ # eval "$(almyty completion zsh)"
181
+ _almyty() {
182
+ local -a commands
183
+ commands=(
184
+ ${descs}
185
+ 'help:Show help'
186
+ 'version:Print the version'
187
+ 'completion:Print a shell completion script'
188
+ )
189
+ if (( CURRENT == 2 )); then
190
+ _describe -t commands 'almyty command' commands
191
+ fi
192
+ }
193
+ compdef _almyty almyty`;
194
+ }
195
+ const fishLines = Object.entries(SUBCOMMANDS)
196
+ .map(([name, s]) => `complete -c almyty -n __fish_use_subcommand -a ${name} -d '${s.help.replace(/'/g, '')}'`)
197
+ .join('\n');
198
+ return `# almyty fish completion — save as ~/.config/fish/completions/almyty.fish:
199
+ # almyty completion fish > ~/.config/fish/completions/almyty.fish
200
+ ${fishLines}
201
+ complete -c almyty -n __fish_use_subcommand -a help -d 'Show help'
202
+ complete -c almyty -n __fish_use_subcommand -a version -d 'Print the version'
203
+ complete -c almyty -n __fish_use_subcommand -a completion -d 'Print a shell completion script'`;
204
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Exit codes shared by every almyty CLI.
3
+ *
4
+ * Scripts need to tell "you are not logged in" apart from "that agent
5
+ * does not exist" apart from "the run you asked for failed" without
6
+ * grepping stderr. Every almyty CLI uses this same table, so
7
+ * `almyty agents run x || case $? in 3) almyty login;; esac` behaves
8
+ * the same whichever binary produced the code.
9
+ */
10
+ export declare const EXIT: {
11
+ /** Success. */
12
+ readonly OK: 0;
13
+ /** Unexpected failure (a thrown error with no better classification). */
14
+ readonly ERROR: 1;
15
+ /** Bad or missing arguments, or an unknown command. */
16
+ readonly USAGE: 2;
17
+ /** No stored credential, or the API rejected the one we had. */
18
+ readonly AUTH: 3;
19
+ /** The named agent / gateway / skill / run does not exist. */
20
+ readonly NOT_FOUND: 4;
21
+ /** The command ran; the operation it asked for failed. */
22
+ readonly FAILED: 5;
23
+ };
24
+ export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
25
+ /** One line per code, for `--help` output and READMEs. */
26
+ export declare const EXIT_CODE_HELP: string;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Exit codes shared by every almyty CLI.
3
+ *
4
+ * Scripts need to tell "you are not logged in" apart from "that agent
5
+ * does not exist" apart from "the run you asked for failed" without
6
+ * grepping stderr. Every almyty CLI uses this same table, so
7
+ * `almyty agents run x || case $? in 3) almyty login;; esac` behaves
8
+ * the same whichever binary produced the code.
9
+ */
10
+ export const EXIT = {
11
+ /** Success. */
12
+ OK: 0,
13
+ /** Unexpected failure (a thrown error with no better classification). */
14
+ ERROR: 1,
15
+ /** Bad or missing arguments, or an unknown command. */
16
+ USAGE: 2,
17
+ /** No stored credential, or the API rejected the one we had. */
18
+ AUTH: 3,
19
+ /** The named agent / gateway / skill / run does not exist. */
20
+ NOT_FOUND: 4,
21
+ /** The command ran; the operation it asked for failed. */
22
+ FAILED: 5,
23
+ };
24
+ /** One line per code, for `--help` output and READMEs. */
25
+ export const EXIT_CODE_HELP = [
26
+ ' 0 success',
27
+ ' 1 unexpected error',
28
+ ' 2 usage error (bad flags, unknown command)',
29
+ ' 3 not authenticated — run `almyty login`',
30
+ ' 4 not found (agent, gateway, skill, or run)',
31
+ ' 5 the operation ran and failed',
32
+ ].join('\n');
package/dist/index.d.ts CHANGED
@@ -6,8 +6,7 @@
6
6
  * almyty login
7
7
  * almyty agents list
8
8
  * almyty chat my-research-bot
9
- * almyty skills install @org/gateway
10
- * almyty mcp <args>
9
+ * almyty skills install org/gateway
11
10
  *
12
11
  * The umbrella delegates each subcommand to a standalone @almyty/<thing>
13
12
  * package by spawning its bin. Each package can ALSO be invoked directly:
@@ -15,7 +14,6 @@
15
14
  * npx @almyty/auth login
16
15
  * npx @almyty/agents list
17
16
  * npx @almyty/chat my-research-bot
18
- * …
19
17
  *
20
18
  * The standalone packages and the umbrella stay in sync because they
21
19
  * share the same on-disk credentials store at ~/.almyty/credentials.json.
package/dist/index.js CHANGED
@@ -6,8 +6,7 @@
6
6
  * almyty login
7
7
  * almyty agents list
8
8
  * almyty chat my-research-bot
9
- * almyty skills install @org/gateway
10
- * almyty mcp <args>
9
+ * almyty skills install org/gateway
11
10
  *
12
11
  * The umbrella delegates each subcommand to a standalone @almyty/<thing>
13
12
  * package by spawning its bin. Each package can ALSO be invoked directly:
@@ -15,79 +14,18 @@
15
14
  * npx @almyty/auth login
16
15
  * npx @almyty/agents list
17
16
  * npx @almyty/chat my-research-bot
18
- * …
19
17
  *
20
18
  * The standalone packages and the umbrella stay in sync because they
21
19
  * share the same on-disk credentials store at ~/.almyty/credentials.json.
22
20
  */
23
- import { spawn } from 'child_process';
24
- import { createRequire } from 'module';
25
- import { dirname, join } from 'path';
26
- import { existsSync } from 'fs';
21
+ import { spawn } from 'node:child_process';
22
+ import { createRequire } from 'node:module';
23
+ import { dirname, join } from 'node:path';
24
+ import { existsSync } from 'node:fs';
25
+ import { VERSION } from './version.js';
26
+ import { EXIT } from './exit-codes.js';
27
+ import { SUBCOMMANDS, completionScript, helpText, isCompletionShell, suggestCommand, tourText, COMPLETION_SHELLS, } from './commands.js';
27
28
  const require = createRequire(import.meta.url);
28
- const VERSION = '0.1.0';
29
- /**
30
- * Top-level subcommand routing table. Order = display order in help.
31
- */
32
- const SUBCOMMANDS = {
33
- // Auth shortcuts at top level (gh-style: `almyty login` not `almyty auth login`)
34
- login: { pkg: '@almyty/auth', prefixArgs: ['login'], help: 'Browser-based login' },
35
- logout: { pkg: '@almyty/auth', prefixArgs: ['logout'], help: 'Remove stored credentials' },
36
- whoami: { pkg: '@almyty/auth', prefixArgs: ['whoami'], help: 'Show the current identity' },
37
- auth: { pkg: '@almyty/auth', help: 'Auth subcommands (login/logout/whoami)' },
38
- // Domain CLIs
39
- agents: { pkg: '@almyty/agents', help: 'List, run, and inspect agents' },
40
- chat: { pkg: '@almyty/chat', help: 'Interactive chat REPL with an agent' },
41
- skills: { pkg: '@almyty/skills', help: 'Install API skills into AI coding agents' },
42
- mcp: { pkg: '@almyty/mcp-server', help: 'Run the MCP server proxy' },
43
- acp: { pkg: '@almyty/acp-server', help: 'Run the ACP agent server' },
44
- };
45
- function printHelp() {
46
- console.log(`
47
- almyty CLI v${VERSION}
48
-
49
- Usage:
50
- almyty <command> [args]
51
-
52
- Auth:
53
- login Browser-based login (writes ~/.almyty/credentials.json)
54
- logout Remove stored credentials
55
- whoami Show the currently logged-in identity
56
- auth <subcommand> Pass-through to @almyty/auth
57
-
58
- Agents:
59
- agents list List agents in your organization
60
- agents get <ref> Show details for one agent
61
- agents run <ref> [--input ...] Invoke / start a run
62
- agents runs <ref> List recent runs
63
- agents cancel <ref> <runId> Cancel an in-flight run
64
-
65
- Chat:
66
- chat Interactive REPL — pick an agent from a menu
67
- chat <ref> Start chatting with that agent
68
-
69
- Skills:
70
- skills install <ref> Install skills into local AI coding agents
71
- skills list [ref] List available skills
72
- skills daemon Sync skills on a schedule
73
- skills run <ref> Execute a skill once
74
-
75
- MCP:
76
- mcp <args> Run the MCP server proxy
77
-
78
- Other:
79
- help, --help Show this help
80
- version, --version Show version
81
-
82
- Each subcommand maps to a standalone npm package. You can invoke any
83
- of them directly with npx:
84
-
85
- npx @almyty/auth login
86
- npx @almyty/agents list
87
- npx @almyty/chat my-research-bot
88
- npx @almyty/skills install @org/gateway
89
- `);
90
- }
91
29
  function resolveBinPath(packageName) {
92
30
  // Resolve the package's package.json to find its installation root,
93
31
  // then read the "bin" entry to find the actual script path.
@@ -128,8 +66,8 @@ function delegate(packageName, args) {
128
66
  if (!binPath) {
129
67
  console.error(`Error: package ${packageName} is not installed.`);
130
68
  console.error(` Install it with: npm install -g ${packageName}`);
131
- console.error(` Or use: npx ${packageName} ${args.join(' ')}`);
132
- return Promise.resolve(1);
69
+ console.error(` Or use: npx ${packageName} ${args.join(' ')}`);
70
+ return Promise.resolve(EXIT.ERROR);
133
71
  }
134
72
  return new Promise((resolve) => {
135
73
  const child = spawn(process.execPath, [binPath, ...args], {
@@ -157,30 +95,49 @@ function delegate(packageName, args) {
157
95
  process.kill(process.pid, signal);
158
96
  return;
159
97
  }
160
- resolve(code ?? 0);
98
+ resolve(code ?? EXIT.OK);
161
99
  });
162
100
  child.on('error', (err) => {
163
101
  console.error(`Failed to launch ${packageName}: ${err.message}`);
164
- resolve(1);
102
+ resolve(EXIT.ERROR);
165
103
  });
166
104
  });
167
105
  }
168
106
  async function main() {
169
107
  const argv = process.argv.slice(2);
170
- if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h' || argv[0] === 'help') {
171
- printHelp();
108
+ // Bare `almyty` shows a short tour, not the full reference.
109
+ if (argv.length === 0) {
110
+ console.log(tourText(VERSION));
111
+ return;
112
+ }
113
+ if (argv[0] === '--help' || argv[0] === '-h' || argv[0] === 'help') {
114
+ console.log(helpText(VERSION));
172
115
  return;
173
116
  }
174
117
  if (argv[0] === '--version' || argv[0] === '-v' || argv[0] === 'version') {
175
118
  console.log(VERSION);
176
119
  return;
177
120
  }
121
+ if (argv[0] === 'completion') {
122
+ const shell = argv[1];
123
+ if (!shell || !isCompletionShell(shell)) {
124
+ console.error(`Usage: almyty completion <${COMPLETION_SHELLS.join('|')}>`);
125
+ process.exit(EXIT.USAGE);
126
+ }
127
+ console.log(completionScript(shell));
128
+ return;
129
+ }
178
130
  const cmd = argv[0];
179
131
  const sub = SUBCOMMANDS[cmd];
180
132
  if (!sub) {
181
133
  console.error(`Unknown command: ${cmd}`);
182
- console.error(`Run \`almyty help\` for the list of commands.`);
183
- process.exit(1);
134
+ const suggestion = suggestCommand(cmd);
135
+ if (suggestion)
136
+ console.error(`Did you mean \`almyty ${suggestion}\`?`);
137
+ console.error('Run `almyty help` for the list of commands.');
138
+ // Usage error, not a generic failure: a script can tell a typo
139
+ // apart from a command that ran and failed.
140
+ process.exit(EXIT.USAGE);
184
141
  }
185
142
  const passthroughArgs = [...(sub.prefixArgs ?? []), ...argv.slice(1)];
186
143
  const code = await delegate(sub.pkg, passthroughArgs);
@@ -188,5 +145,5 @@ async function main() {
188
145
  }
189
146
  main().catch((err) => {
190
147
  console.error(`Error: ${err.message}`);
191
- process.exit(1);
148
+ process.exit(EXIT.ERROR);
192
149
  });
@@ -0,0 +1,2 @@
1
+ export declare function readVersion(fallback?: string): string;
2
+ export declare const VERSION: string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The CLI's own version, read from its package.json at startup.
3
+ *
4
+ * It used to be a hardcoded string, which drifted: `--version`
5
+ * answered 0.1.0 while the published package was 1.2.0, so a bug
6
+ * report never identified the build it came from. Both `dist/index.js`
7
+ * and `src/index.ts` sit one directory below the package root, so the
8
+ * same relative path resolves for the built bin and for `tsx src/index.ts`.
9
+ */
10
+ import { readFileSync } from 'node:fs';
11
+ export function readVersion(fallback = '0.0.0') {
12
+ try {
13
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
14
+ return typeof pkg.version === 'string' && pkg.version.length > 0
15
+ ? pkg.version
16
+ : fallback;
17
+ }
18
+ catch {
19
+ return fallback;
20
+ }
21
+ }
22
+ export const VERSION = readVersion();
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@almyty/cli",
3
- "version": "0.1.3",
4
- "description": "Single installable almyty CLI — login, agents, chat, skills, mcp under one binary",
3
+ "version": "1.3.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "The almyty CLI — one login for agents, chat, skills, an MCP server, and a machine runner. Part of almyty, the full-stack platform for AI agents.",
5
8
  "type": "module",
6
9
  "main": "dist/index.js",
7
10
  "bin": {
@@ -26,19 +29,37 @@
26
29
  "mcp"
27
30
  ],
28
31
  "author": "almyty",
29
- "license": "BSL-1.1",
32
+ "license": "Apache-2.0",
30
33
  "dependencies": {
31
- "@almyty/auth": "^0.1.0",
32
- "@almyty/agents": "^0.1.0",
33
- "@almyty/chat": "^0.1.0",
34
- "@almyty/skills": "^1.0.2",
35
- "@almyty/mcp-server": "^1.0.0",
36
- "@almyty/acp-server": "^1.0.0"
34
+ "@almyty/auth": "^1.2.0",
35
+ "@almyty/agents": "^1.2.0",
36
+ "@almyty/chat": "^1.2.0",
37
+ "@almyty/skills": "^1.2.0",
38
+ "@almyty/models": "^1.2.0",
39
+ "@almyty/connections": "^1.2.0",
40
+ "@almyty/mcp-server": "^1.2.0",
41
+ "@almyty/acp-server": "^1.2.0",
42
+ "@almyty/runner": "^1.2.0"
37
43
  },
38
44
  "devDependencies": {
39
45
  "@types/node": "^25.4.0",
40
46
  "tsx": "^4.7.0",
41
47
  "typescript": "^5.3.0",
42
48
  "vitest": "^4.1.0"
49
+ },
50
+ "overrides": {
51
+ "@hono/node-server": "^2.0.5",
52
+ "fast-uri": "^3.1.5",
53
+ "ip-address": "^10.4.0",
54
+ "postcss": "^8.5.23"
55
+ },
56
+ "homepage": "https://almyty.com",
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/almyty-inc/almyty.git",
60
+ "directory": "packages/almyty-cli"
61
+ },
62
+ "bugs": {
63
+ "url": "https://github.com/almyty-inc/almyty/issues"
43
64
  }
44
65
  }