@runneth/cli 0.0.0-sha.e9d64d0553e1.production → 0.0.0-sha.f1d89888b053.production

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,14 +1,18 @@
1
1
  # runneth-cli
2
2
 
3
- `runneth-cli` gives local coding agents a fast persistent shell session.
3
+ Runneth brings your AI brain for marketing to the terminal, by [Motion](http://motionapp.com/).
4
+ Use interactive chat, connect to a Runneth VM, or automate conversations and local shell sessions.
5
+ Looking for a web version? [Open Runneth](https://app.runneth.com/).
4
6
 
5
7
  ```bash
6
8
  npx @runneth/cli open
7
- npx @runneth/cli send 'cd ~/project && pnpm test'
8
- npx @runneth/cli send 'git status --short'
9
- npx @runneth/cli oauth login
10
- npx @runneth/cli ssh
11
- npx @runneth/cli close
9
+ runneth send 'cd ~/project && pnpm test'
10
+ runneth send 'git status --short'
11
+ runneth oauth login
12
+ runneth chat --workspace <workspace-id>
13
+ runneth conversation create --workspace <workspace-id> --json
14
+ runneth ssh
15
+ runneth close
12
16
  ```
13
17
 
14
18
  ## npm Usage
@@ -26,76 +30,273 @@ Use the npm `beta` channel to try the production build before it is promoted to
26
30
  npx @runneth/cli@beta ssh
27
31
  ```
28
32
 
29
- The first command starts a small local daemon for the current user. Later `send`
33
+ `runneth open` starts a small local daemon for the current user. Later `send`
30
34
  calls reuse the same shell process through a local socket, so `cd`, exported
31
35
  environment variables, and other shell state persist between commands.
32
36
 
33
- ## Commands
37
+ ## Find a command
38
+
39
+ Run `runneth` or `runneth --help` to see commands grouped by purpose. Each
40
+ description explains what the command does and who it is for. Subcommands are
41
+ nested beneath their parent, with descriptions. Use `runneth help --all` for
42
+ a flat list with full command paths.
34
43
 
35
44
  ```bash
36
- runneth-cli open [--name default] [--cwd <path>] [--shell <path>]
37
- runneth-cli send [--name default] [--timeout-ms 600000] [--stdin] -- <command...>
38
- runneth-cli status [--name default]
39
- runneth-cli list
40
- runneth-cli close [--name default]
41
- runneth-cli oauth login [--resource <url>] [--client-name "Runneth MCP"] [--scope <scope>] [--no-open]
42
- runneth-cli oauth status [--resource <url>]
43
- runneth-cli oauth logout [--resource <url>]
44
- runneth-cli ssh target add <name> (--host <host> | --ssh-url <url>) [--resource <url>] [--default]
45
- runneth-cli ssh target import <file>
46
- runneth-cli ssh target list
47
- runneth-cli ssh target use <name>
48
- runneth-cli ssh [--target <name>] [--unique-key | --identity-file <path>] [-- remote-command]
49
- runneth-cli ssh stdio [--target <name>] [--unique-key | --identity-file <path>]
50
- runneth-cli skills install [--agent claude|codex|all]
51
- runneth-cli shutdown
45
+ runneth help --all
46
+ runneth help ssh
47
+ runneth conversation send --help
48
+ runneth --version
52
49
  ```
53
50
 
51
+ Every command supports `--help` and `-h`. Help runs before sign-in, daemon startup,
52
+ or command execution. `runneth help --json` returns the public command catalog with
53
+ its schema version, package version, command paths, options, required inputs,
54
+ output formats, and effects. Use `runneth help conversation --json` for one group.
55
+
56
+ | Commands | Purpose | Audience |
57
+ | ---------------------------------------- | ---------------------------------------------- | ------------- |
58
+ | `chat` | Interactive Runneth conversation | Human |
59
+ | `conversation create/send/state/session` | Remote conversation API through JSON or JSONL | Agent |
60
+ | `ssh` | Remote shell or command on a Runneth VM | Both |
61
+ | `ssh stdio` | Persistent remote JSONL control process | Agent |
62
+ | `ssh target add/import/list/use/remove` | Saved VM connections on your computer | Both |
63
+ | `oauth login/status/logout` | Sign-in and locally stored credentials | Both |
64
+ | `update` | Install the current CLI update channel | Both |
65
+ | `skills install` | Runneth instructions for Claude Code and Codex | Human |
66
+ | `open/send/status/list/close/shutdown` | Persistent shells on your computer | Agent or both |
67
+
68
+ Local shell commands return JSON. They execute on your computer; use `ssh` or
69
+ `ssh stdio` to execute on a Runneth VM. Put shell or remote arguments after `--`,
70
+ including a command's own `--help`:
71
+
72
+ ```bash
73
+ runneth send -- pnpm --help
74
+ runneth ssh --target team -- node --help
75
+ ```
76
+
77
+ Interactive help and chat share a terminal logo. Small windows use a compact
78
+ header, `NO_COLOR=1` disables color, and pipes and `TERM=dumb` use plain text.
79
+ Terminals with hyperlink support can open the Motion and Runneth web links.
80
+
54
81
  Use `--stdin` for multi-line commands:
55
82
 
56
83
  ```bash
57
- cat <<'SCRIPT' | runneth-cli send --stdin
84
+ cat <<'SCRIPT' | runneth send --stdin
58
85
  cd ~/project
59
86
  pnpm check
60
87
  SCRIPT
61
88
  ```
62
89
 
63
- Runtime files live under `~/.runneth-cli` by default. Set `RUNNETH_CLI_HOME` to
64
- use a different state directory.
90
+ CLI state files live under `~/.runneth-cli` by default. Set `RUNNETH_CLI_HOME`
91
+ to use a different state directory. Update installation locks use a separate
92
+ per-user location so two CLI homes cannot update the same installation at the
93
+ same time.
94
+
95
+ ## CLI Updates
96
+
97
+ Each eligible CLI startup launches a small detached worker and immediately
98
+ continues the requested command. The worker verifies the active global npm or
99
+ pnpm installation, then claims at most one registry check every 20 hours for
100
+ that installation, package, and channel. Project-local installations cannot
101
+ claim or suppress that interval. The worker only caches the promoted `latest`
102
+ target; it never installs an update in the background. Installing another CLI
103
+ version does not reset the interval.
104
+
105
+ The cached result is scoped to the exact installation and installed version
106
+ that was checked. The worker compares registry publication times so a rolled
107
+ back channel or an older target is never presented as an update. A **Do not
108
+ remind me** choice is scoped to the installation, release channel, and target
109
+ version, so it remains effective after another version is installed and a
110
+ concurrent refresh cannot erase it. When a valid cached update is available, an
111
+ interactive `chat` command or interactive `ssh` shell shows three choices:
112
+ **Update now** (selected by default and showing the command that will run),
113
+ **Not now**, and **Do not remind me for this version**. Use the arrow keys or
114
+ `j`/`k` and press Enter. Help, one-shot SSH, other interactive terminal commands,
115
+ non-interactive commands, and machine-readable commands never resolve a cached
116
+ candidate or pause for update input. Eligible commands inspect only local
117
+ cached state in the foreground. They do not run a package manager or contact
118
+ the registry.
119
+
120
+ Background-check failures do not interrupt the requested command. The detached
121
+ worker writes the latest diagnostic to
122
+ `~/.runneth-cli/update-check-error.log` (or the configured
123
+ `RUNNETH_CLI_HOME`); the next attempt replaces it.
124
+
125
+ Choosing **Update now** installs the exact version shown in the selector.
126
+ `runneth update` instead follows `latest`, such as
127
+ `pnpm add --global @runneth/cli@latest`. Global npm and pnpm installations
128
+ update through their original package manager and the installation root
129
+ recorded by the background check. The pnpm executable directory is also recorded
130
+ and pinned during replacement, so changing `PNPM_HOME` cannot redirect the
131
+ installed commands. A package-manager failure exits with its
132
+ status. The CLI asks the user to rerun the original command afterward. Source
133
+ checkouts, project-local dependencies, and npm-exec or npx invocations are not
134
+ modified. For npx, rerun with `npx @runneth/cli@latest`.
135
+
136
+ Before the first manual package-manager upgrade that installs the updater, let
137
+ persistent sessions finish, close them, and run `runneth shutdown` with the
138
+ installed CLI in every CLI home or custom socket you use. Older daemons do not
139
+ publish registrations, so this one-time shutdown is required across all homes.
140
+ If you already upgraded with an old daemon running, `close` and `shutdown`
141
+ remain available. Other daemon-backed commands and updates refuse a reachable
142
+ unregistered daemon in the current home until you shut it down.
143
+
144
+ The updater does not interrupt a running local daemon or its persistent
145
+ sessions. It refuses to change the installation until the user closes those
146
+ sessions and runs `runneth shutdown`. A shared gate prevents normal CLI
147
+ commands from starting another daemon during installation. The next
148
+ daemon-backed command starts from the updated installation.
149
+
150
+ Daemon registrations and the transition lock live in
151
+ `.runneth-cli-daemon-gates` under the operating-system account home. Changing
152
+ `TMPDIR`, `TEMP`, `TMP`, or `RUNNETH_CLI_HOME` does not select a separate gate.
153
+
154
+ ### Interrupted-update recovery
155
+
156
+ Before npm or pnpm starts replacing files, the updater reserves
157
+ `replacement.json` under `.runneth-cli-daemon-gates` in the operating-system
158
+ account home. This record blocks new daemon startup and further updates across
159
+ CLI homes and package directories, even after an updater crash or `SIGKILL`
160
+ allows its heartbeat locks to expire. Existing daemons for other installations
161
+ can still be used and shut down. The record has no expiry. An incomplete or
162
+ unreadable record also blocks admission.
163
+
164
+ The updater removes its own record only after the package-manager child exits.
165
+ If the updater dies first, use this recovery procedure:
166
+
167
+ 1. Restart the computer. This stops orphaned npm/pnpm processes and their install
168
+ scripts. Keep the replacement record in place during recovery.
169
+ 2. Inspect the record at the exact path printed by the CLI. Its `command`, `args`,
170
+ `installationRoot`, and `packageName` identify the attempted replacement.
171
+ Run that package-manager installation command directly to repair the same
172
+ global installation, preserving its prefix or pnpm global directories.
173
+ If the record is incomplete, identify the affected installation and repair
174
+ it before continuing; do not infer that no installer ran.
175
+ 3. Require a successful install and verify the repaired CLI's `--version` and
176
+ `--help`. If either fails, keep the record and finish repairing the package.
177
+ 4. Remove only the `replacement.json` file at the reported path, then rerun the
178
+ intended command. Do not remove registration directories or heartbeat locks.
179
+
180
+ Do not clear the record because it is old or its updater PID no longer exists.
181
+ Those facts cannot prove that package-manager descendants stopped or that the
182
+ installation is complete.
183
+
184
+ `runneth shutdown` succeeds when the selected daemon is already stopped. It
185
+ does not start a daemon. After the daemon acknowledges shutdown, health-check
186
+ timeouts are retried for up to five seconds while it stops. A shutdown request
187
+ timeout, an expired stop deadline, or a permission or protocol failure remains
188
+ an error.
65
189
 
66
190
  ## OAuth
67
191
 
68
- `runneth-cli oauth login` performs OAuth protected-resource discovery, dynamic
69
- client registration as a public MCP-style client, PKCE authorization, and token
70
- exchange through a local loopback callback.
192
+ `runneth oauth login` performs OAuth protected-resource discovery, PKCE
193
+ authorization, and token exchange through a local loopback callback. By default
194
+ it uses dynamic client registration as a public MCP-style client. Provide
195
+ `--client-id`/`--clientid` and `--client-secret`/`--secret`, or set
196
+ `RUNNETH_OAUTH_CLIENT_ID` and `RUNNETH_OAUTH_CLIENT_SECRET`, to use a
197
+ pre-registered confidential client instead.
71
198
 
72
199
  ```bash
73
- runneth-cli oauth login --resource http://localhost:4100/mcp
74
- runneth-cli oauth status --resource http://localhost:4100/mcp
200
+ runneth oauth login --resource http://localhost:4100/mcp
201
+ RUNNETH_OAUTH_CLIENT_ID=client-id RUNNETH_OAUTH_CLIENT_SECRET=client-secret runneth oauth login --resource http://localhost:4100/mcp
202
+ runneth oauth status --resource http://localhost:4100/mcp
75
203
  ```
76
204
 
77
205
  OAuth credentials are stored under `~/.runneth-cli/oauth` with user-only file
78
206
  permissions on Unix-like systems. Commands that need an access token refresh it
79
207
  internally when the server issued a refresh token.
80
208
 
209
+ ## Chat
210
+
211
+ `runneth chat` starts an interactive terminal conversation against Builder's
212
+ canonical Runneth conversation API. Official environment builds carry the
213
+ correct Builder URL in the package; use `--api` only for local or custom Builder
214
+ deployments.
215
+
216
+ ```bash
217
+ runneth chat --workspace "$MONDRIAN_WORKSPACE_ID"
218
+ ```
219
+
220
+ If no stored OAuth credential exists, chat starts the same browser-based OAuth
221
+ flow as SSH and stores the credential under `~/.runneth-cli/oauth`. Use
222
+ `--token`, `RUNNETH_TOKEN`, `MONDRIAN_TOKEN`, or `BUILDER_AGENT_CHAT_TOKEN` only
223
+ for automation and local API mocks that should bypass OAuth.
224
+
225
+ Inside the terminal UI, use `/state` to redraw the current conversation and
226
+ `/exit` to quit.
227
+
228
+ ## Conversation Commands
229
+
230
+ `runneth conversation` is the machine-oriented conversation interface for
231
+ agents and scripts. It uses the same auth, workspace scoping, and conversation
232
+ API as `runneth chat`, but avoids terminal banners and ANSI UI output.
233
+
234
+ ```bash
235
+ runneth conversation create --workspace "$MONDRIAN_WORKSPACE_ID" --title "SSH routine setup" --json
236
+ runneth conversation send --workspace "$MONDRIAN_WORKSPACE_ID" --conversation "$CONVERSATION_ID" --message "Create a routine" --json
237
+ runneth conversation state --workspace "$MONDRIAN_WORKSPACE_ID" --conversation "$CONVERSATION_ID" --json
238
+ ```
239
+
240
+ `send` waits for the assistant response by default. `send` and `state` require an
241
+ explicit `--conversation`; the CLI does not track an implicit active
242
+ conversation for machine commands. State reads advertise Runneth stream V2, so
243
+ the same command can inspect read-only task-origin transcripts.
244
+
245
+ Long-lived agents can keep one authenticated process open with JSONL over
246
+ stdin/stdout:
247
+
248
+ ```bash
249
+ runneth conversation session --workspace "$MONDRIAN_WORKSPACE_ID" --jsonl
250
+ ```
251
+
252
+ The session `ready` frame reports the resolved client target context, not a
253
+ separate active conversation identity. Authoritative user and conversation
254
+ identity comes from the `conversation` object returned by `create` and `state`.
255
+
256
+ Typical requests:
257
+
258
+ ```jsonl
259
+ {"id":"1","method":"create","params":{"title":"SSH routine setup"}}
260
+ {"id":"2","method":"send","params":{"conversationId":"11111111-1111-4111-8111-111111111111","text":"Create a routine"}}
261
+ {"id":"3","method":"state","params":{"conversationId":"11111111-1111-4111-8111-111111111111"}}
262
+ {"id":"4","method":"close"}
263
+ ```
264
+
265
+ Typical responses:
266
+
267
+ ```jsonl
268
+ {"type":"ready","ok":true,"protocol":"runneth-conversation-stdio","version":1,"authMode":"mondrian","workspaceId":"65cbcb84095884aaf08dc76a"}
269
+ {"id":"1","type":"created","ok":true,"conversation":{"id":"11111111-1111-4111-8111-111111111111"}}
270
+ {"id":"2","type":"sent","ok":true,"send":{"assistantMessageId":"55555555-5555-4555-8555-555555555555"}}
271
+ {"id":"2","type":"state","ok":true,"state":{"conversation":{"id":"11111111-1111-4111-8111-111111111111"}}}
272
+ {"id":"2","type":"complete","ok":true,"assistantMessage":{"id":"55555555-5555-4555-8555-555555555555","status":"completed"}}
273
+ ```
274
+
81
275
  ## SSH
82
276
 
83
- `runneth-cli ssh` uses the stored OAuth credential for the resource. If no
84
- credential exists yet, it starts the OAuth login flow first. The first SSH
85
- connection for a resource/app pair generates an ed25519 keypair, sends the
86
- public key to the Runneth SSH app, writes an isolated OpenSSH config, and then
87
- starts `ssh` through the app tunnel.
277
+ `runneth ssh` uses the stored OAuth credential for the resource. If no
278
+ credential exists yet, it starts the OAuth login flow first. Pass a conversation
279
+ and workspace to resolve its public SSH app target from Builder, or pass a
280
+ named, host, or URL target directly. The first SSH connection for a resource/app
281
+ pair generates an ed25519 keypair, sends the public key to the Runneth SSH app,
282
+ writes an isolated OpenSSH config, and then starts `ssh` through the app tunnel.
88
283
 
89
284
  ```bash
90
- runneth-cli ssh \
285
+ runneth ssh \
286
+ --conversation 11111111-1111-4111-8111-111111111111 \
287
+ --workspace 22222222-2222-4222-8222-222222222222 \
91
288
  --resource https://projects.motionapp.com/mcp \
92
- --host 93c7ca56-debe-4b95-8be2-a873afe72234.app.runneth.com
289
+ --api https://projects.motionapp.com
93
290
  ```
94
291
 
95
292
  SSH keys, known hosts, and generated config files are stored under
96
293
  `~/.runneth-cli/ssh`. The generated OpenSSH config uses an internal
97
294
  `ProxyCommand` transport that attaches the OAuth bearer token to the SSH app
98
- HTTP tunnel.
295
+ tunnel. The CLI reads the target VM's authenticated `/runneth/ssh/api` metadata
296
+ before connecting, independently of app catalog health:
297
+ VMs that advertise `runneth-ssh-v1` use one full-duplex WebSocket, while older
298
+ VMs continue through the HTTPS tunnel. Transport selection is automatic. Capability
299
+ discovery allows 70 seconds for authorization and response delivery.
99
300
 
100
301
  ### SSH stdio
101
302
 
@@ -103,7 +304,7 @@ Use `ssh stdio` when an agent needs to keep one authenticated SSH connection
103
304
  open and run multiple commands or remote processes without reconnecting:
104
305
 
105
306
  ```bash
106
- runneth-cli ssh stdio --target primary-vm
307
+ runneth ssh stdio --target primary-vm
107
308
  ```
108
309
 
109
310
  The command writes JSONL events to stdout and reads JSONL requests from stdin.
@@ -1 +1,6 @@
1
- export declare const resolveBuildDefaultMcpResourceUrl: () => string | undefined;
1
+ //#region src/build-defaults.d.ts
2
+ declare const resolveBuildDefaultMcpResourceUrl: () => string | undefined;
3
+ declare const resolveBuildDefaultMondrianApiUrl: () => string | undefined;
4
+ declare const resolveBuildDefaultRunnethApiUrl: () => string | undefined;
5
+ //#endregion
6
+ export { resolveBuildDefaultMcpResourceUrl, resolveBuildDefaultMondrianApiUrl, resolveBuildDefaultRunnethApiUrl };
@@ -1,21 +1,36 @@
1
+ //#region src/build-defaults.ts
1
2
  const BUILD_DEFAULT_MONDRIAN_API_URL = "https://projects.motionapp.com/";
2
- const BUILD_DEFAULT_MONDRIAN_API_URL_PLACEHOLDER = "__RUNNETH_CLI_DEFAULT_MONDRIAN_API_URL__";
3
+ const BUILD_DEFAULT_RUNNETH_API_URL = "https://build-be.runneth.com/";
3
4
  const appendMcpPath = (url) => {
4
- const basePath = url.pathname === "/" ? "" : url.pathname.replace(/\/+$/u, "");
5
- url.pathname = `${basePath}/mcp`;
5
+ url.pathname = `${url.pathname === "/" ? "" : url.pathname.replace(/\/+$/u, "")}/mcp`;
6
6
  };
7
- export const resolveBuildDefaultMcpResourceUrl = () => {
8
- const rawApiUrl = BUILD_DEFAULT_MONDRIAN_API_URL.trim();
9
- if (rawApiUrl.length === 0 ||
10
- rawApiUrl === BUILD_DEFAULT_MONDRIAN_API_URL_PLACEHOLDER) {
11
- return undefined;
12
- }
13
- const url = new URL(rawApiUrl);
14
- if (url.protocol !== "http:" && url.protocol !== "https:") {
15
- throw new Error("Build default MONDRIAN_API_URL must use http or https");
16
- }
17
- url.hash = "";
18
- url.search = "";
19
- appendMcpPath(url);
20
- return url.toString();
7
+ const resolveBuildDefaultMcpResourceUrl = () => {
8
+ const apiUrl = resolveBuildDefaultMondrianApiUrl();
9
+ if (apiUrl === void 0) return;
10
+ const url = new URL(apiUrl);
11
+ appendMcpPath(url);
12
+ return url.toString();
21
13
  };
14
+ const normalizeBuildDefaultUrl = (input) => {
15
+ const rawApiUrl = input.value.trim();
16
+ if (rawApiUrl.length === 0 || rawApiUrl.startsWith("__RUNNETH_CLI_DEFAULT_") && rawApiUrl.endsWith("_API_URL__")) return;
17
+ const url = new URL(rawApiUrl);
18
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error(`Build default ${input.envName} must use http or https`);
19
+ url.hash = "";
20
+ url.search = "";
21
+ return url.toString().replace(/\/+$/u, "");
22
+ };
23
+ const resolveBuildDefaultMondrianApiUrl = () => {
24
+ return normalizeBuildDefaultUrl({
25
+ envName: "MONDRIAN_API_URL",
26
+ value: BUILD_DEFAULT_MONDRIAN_API_URL
27
+ });
28
+ };
29
+ const resolveBuildDefaultRunnethApiUrl = () => {
30
+ return normalizeBuildDefaultUrl({
31
+ envName: "BACKEND_URL",
32
+ value: BUILD_DEFAULT_RUNNETH_API_URL
33
+ });
34
+ };
35
+ //#endregion
36
+ export { resolveBuildDefaultMcpResourceUrl, resolveBuildDefaultMondrianApiUrl, resolveBuildDefaultRunnethApiUrl };
package/dist/cli.d.ts CHANGED
@@ -1,2 +1 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ export { };