routstrd 0.4.8 → 0.4.10

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.
Files changed (37) hide show
  1. package/README.md +124 -5
  2. package/SKILL.md +341 -0
  3. package/dist/daemon/index.js +7995 -14602
  4. package/dist/index.js +155916 -14225
  5. package/package.json +9 -4
  6. package/src/cli.ts +279 -110
  7. package/src/daemon/args.ts +4 -5
  8. package/src/daemon/http/index.ts +37 -2
  9. package/src/daemon/index.ts +94 -33
  10. package/src/daemon/models.ts +13 -10
  11. package/src/daemon/wallet/auto-refill.ts +1 -1
  12. package/src/daemon/wallet/coco-client.ts +205 -3
  13. package/src/daemon/wallet/cocod-client.ts +19 -3
  14. package/src/daemon/wallet/index.ts +1 -1
  15. package/src/index.ts +9 -1
  16. package/src/runtime.ts +55 -0
  17. package/src/start-daemon.ts +4 -8
  18. package/src/tui/usage/app.ts +16 -2
  19. package/src/tui/usage/data.ts +110 -0
  20. package/src/tui/usage/render.ts +45 -20
  21. package/src/utils/clients.ts +74 -1
  22. package/src/utils/config.ts +14 -0
  23. package/src/utils/daemon-stop.ts +125 -0
  24. package/src/utils/standalone-update.ts +214 -0
  25. package/src/utils/update-checker.ts +81 -18
  26. package/src/version.ts +3 -0
  27. package/src/cli.test.ts +0 -192
  28. package/src/daemon/fatal-error.test.ts +0 -104
  29. package/src/daemon/http/usage-summary.test.ts +0 -272
  30. package/src/daemon/models.test.ts +0 -81
  31. package/src/daemon/wallet/cleanup.test.ts +0 -168
  32. package/src/daemon/wallet/coco-client.npc.test.ts +0 -252
  33. package/src/daemon/wallet/coco-client.test.ts +0 -669
  34. package/src/daemon/wallet/diagnostics.test.ts +0 -378
  35. package/src/daemon/wallet/fixtures/cocod-0.0.24-wallet.db.gz +0 -0
  36. package/src/daemon/wallet/migration.test.ts +0 -171
  37. package/src/daemon/wallet/receive-dedup.test.ts +0 -238
package/README.md CHANGED
@@ -19,15 +19,56 @@ For team-based routing, see [routstrd-auth](https://github.com/Routstr/routstrd-
19
19
 
20
20
  ## Requirements
21
21
 
22
- - [Bun](https://bun.sh) runtime
22
+ The standalone release does not require Bun, Node.js, or npm. Installing from
23
+ npm or running from source requires the [Bun](https://bun.sh) runtime.
24
+
25
+ ## Installation
26
+
27
+ ### Step 1: Install
28
+
29
+ **Standalone binary (recommended):**
30
+
31
+ Installs the standalone executable for Linux or macOS (x64 or arm64) into
32
+ `$HOME/.local/bin`. No Bun, Node.js, or npm required.
23
33
 
24
34
  ```sh
25
- curl -fsSL https://bun.com/install | bash
35
+ curl -fsSL https://github.com/Routstr/routstrd/releases/latest/download/install.sh | sh
26
36
  ```
27
37
 
28
- ## Installation
38
+ Pin a version, change the install directory, or print the resolved asset without
39
+ installing anything:
29
40
 
30
- ### Step 1: Install
41
+ ```sh
42
+ curl -fsSL https://github.com/Routstr/routstrd/releases/latest/download/install.sh \
43
+ | sh -s -- --version 0.4.9 --dir /usr/local/bin
44
+ ```
45
+
46
+ The installer downloads the release archive, verifies it against the release
47
+ `SHA256SUMS`, and only replaces an existing `routstrd` once the checksum matches
48
+ and the extracted binary reports the expected version.
49
+
50
+ <details>
51
+ <summary>Manual install</summary>
52
+
53
+ Download the archive for your operating system and architecture from the
54
+ [latest GitHub Release](https://github.com/Routstr/routstrd/releases/latest).
55
+ Release archives are available for Linux and macOS on x64 and arm64.
56
+
57
+ ```sh
58
+ grep "routstrd-v0.4.9-linux-x64.tar.gz" SHA256SUMS | shasum -a 256 -c -
59
+ tar -xzf routstrd-v0.4.9-linux-x64.tar.gz
60
+ mkdir -p "$HOME/.local/bin"
61
+ install -m 755 routstrd "$HOME/.local/bin/routstrd"
62
+ ```
63
+
64
+ Substitute the version, platform, and architecture for the archive you
65
+ downloaded, and ensure `$HOME/.local/bin` is on `PATH`.
66
+
67
+ </details>
68
+
69
+ Installing the standalone binary is preferred over the npm package: the npm
70
+ package runs through the Bun runtime, while the standalone executable has no
71
+ runtime dependency.
31
72
 
32
73
  **Global with bun:**
33
74
  ```sh
@@ -103,6 +144,17 @@ Test connection:
103
144
  routstrd ping
104
145
  ```
105
146
 
147
+ Refresh models and client integrations on demand:
148
+ ```sh
149
+ routstrd clients --manual-refresh # same as `routstrd refresh`
150
+ ```
151
+
152
+ Turn the daemon's scheduled refresh on or off (no restart needed):
153
+ ```sh
154
+ routstrd clients --disable-automatic-refresh
155
+ routstrd clients --enable-automatic-refresh
156
+ ```
157
+
106
158
  Stop the daemon:
107
159
  ```sh
108
160
  routstrd stop
@@ -139,6 +191,20 @@ The daemon exposes an HTTP server (default port 8008) with the following endpoin
139
191
  GET /health
140
192
  ```
141
193
 
194
+ #### Automatic Refresh Settings
195
+ ```
196
+ POST /settings/auto-refresh
197
+ ```
198
+
199
+ Request body:
200
+ ```json
201
+ { "enabled": false }
202
+ ```
203
+
204
+ Enables or disables the scheduled refresh job. Persisted to the daemon's
205
+ `config.json` as `autoRefresh.enabled` and picked up on the next tick, so no
206
+ daemon restart is required.
207
+
142
208
  #### Route Request
143
209
  ```
144
210
  POST /
@@ -186,10 +252,18 @@ Configuration is stored in `~/.routstrd/config.json`:
186
252
  "port": 8008,
187
253
  "host": "127.0.0.1",
188
254
  "provider": null,
189
- "cocodPath": null
255
+ "cocodPath": null,
256
+ "autoRefresh": { "enabled": true }
190
257
  }
191
258
  ```
192
259
 
260
+ `autoRefresh.enabled` (default `true`) controls the daemon's scheduled refresh
261
+ job, which re-fetches Nostr events, routstr21 models, and client integrations
262
+ every 21 minutes. Set it to `false` (or run
263
+ `routstrd clients --disable-automatic-refresh`) to turn the schedule off and
264
+ refresh manually with `routstrd clients --manual-refresh`. `autoRefresh.intervalMs`
265
+ overrides the 21-minute interval.
266
+
193
267
  ### Environment Variables
194
268
 
195
269
  - `ROUTSTRD_DIR` - Config directory (default: `~/.routstrd`)
@@ -213,6 +287,33 @@ Run daemon:
213
287
  bun run start
214
288
  ```
215
289
 
290
+ Build a standalone executable for the current platform:
291
+
292
+ ```sh
293
+ bun run build:binary
294
+ ./dist/routstrd --version
295
+ ```
296
+
297
+ Standalone installations update directly from GitHub Releases with
298
+ `routstrd update`. npm installations continue to update through Bun. PM2 is an
299
+ optional external dependency used only by `routstrd service`; normal daemon
300
+ operation does not require it.
301
+
302
+ When an update finds a process on the configured daemon port, it only stops that
303
+ process if the wallet PID file confirms a live daemon owned by the same routstrd
304
+ configuration. Otherwise the update remains installed, but automatic restart is
305
+ refused so an unrelated daemon is not interrupted.
306
+
307
+ Existing PM2 registrations created by routstrd 0.4.x continue to work through a
308
+ compatibility daemon entrypoint. Recreate the registration to use the unified
309
+ CLI entrypoint and remove its legacy path dependency:
310
+
311
+ ```sh
312
+ routstrd service uninstall
313
+ routstrd service install
314
+ pm2 save
315
+ ```
316
+
216
317
  Typecheck:
217
318
  ```sh
218
319
  bun run lint
@@ -232,6 +333,24 @@ Set `ROUTSTRD_BASE_URL` to test a daemon at a different address. The script
232
333
  makes live provider requests that may spend wallet funds, so it is intentionally
233
334
  not part of `bun test`.
234
335
 
336
+ ### Publishing a standalone release
337
+
338
+ 1. Set a new `package.json` version and commit it. The release tag must be the
339
+ same version prefixed with `v`, and the tag must not already exist.
340
+ 2. Push the tag. The release workflow runs lint and tests, builds Linux and
341
+ macOS executables for x64 and arm64, smoke-tests them, verifies the archives
342
+ through `install.sh` itself, and publishes the archives with `SHA256SUMS` and
343
+ `install.sh`.
344
+ 3. Verify all four archives and `install.sh` appear in the GitHub Release and
345
+ validate each checksum before announcing it.
346
+ 4. In disposable environments for each platform, test `--version`, `--help`,
347
+ foreground startup failure, and background `start`, `status`, and `stop`
348
+ without Bun on `PATH`.
349
+ 5. Test `routstrd service install` and restart behavior with PM2 in a disposable
350
+ environment. Never run release/update lifecycle tests against a production
351
+ daemon. When isolation is needed, use both a separate `ROUTSTRD_DIR` and a
352
+ non-production port in that configuration.
353
+
235
354
  ## Project Structure
236
355
 
237
356
  ```
package/SKILL.md ADDED
@@ -0,0 +1,341 @@
1
+ # routstrd CLI Reference
2
+
3
+ Routstr daemon — a Bun-based CLI tool that runs a background HTTP server for the Routstr protocol. It integrates with `cocod` for Cashu wallet management and routes LLM requests to available providers.
4
+
5
+ ## Quick Start
6
+
7
+ ```sh
8
+ routstrd onboard # Initialize (creates config, sets up cocod)
9
+ routstrd start # Start the daemon
10
+ routstrd stop # Stop the daemon
11
+ ```
12
+
13
+ After onboarding, the daemon listens at `http://localhost:8008` and exposes an OpenAI-compatible API.
14
+
15
+ ## Commands
16
+
17
+ ### `routstrd onboard`
18
+
19
+ Initialize routstrd for the first time:
20
+ - Creates `~/.routstrd/` config directory
21
+ - Creates `~/.routstrd/config.json` with defaults (port 8008, apikeys mode)
22
+ - Installs `cocod` globally via bun if not present
23
+ - Runs `cocod init` to set up the wallet
24
+ - Starts the daemon and configures integrations
25
+
26
+ ### `routstrd start`
27
+
28
+ Start the background daemon process.
29
+
30
+ | Option | Description |
31
+ |--------|-------------|
32
+ | `--port <port>` | Port to listen on (default: 8008) |
33
+ | `-p, --provider <provider>` | Default provider to use |
34
+
35
+ ### `routstrd stop`
36
+
37
+ Stop the background daemon.
38
+
39
+ ### `routstrd restart`
40
+
41
+ Restart the daemon (stops if running, then starts).
42
+
43
+ | Option | Description |
44
+ |--------|-------------|
45
+ | `--port <port>` | Port to listen on |
46
+ | `-p, --provider <provider>` | Default provider to use |
47
+
48
+ ### `routstrd status`
49
+
50
+ Check daemon and wallet status. Returns JSON with current state.
51
+
52
+ ### `routstrd balance`
53
+
54
+ Get wallet and API key balances. Shows per-mint wallet balances, per-key API balances, and a grand total (all in sats).
55
+
56
+ ### `routstrd models`
57
+
58
+ List available routstr21 models (discovered via Nostr).
59
+
60
+ | Option | Description |
61
+ |--------|-------------|
62
+ | `-r, --refresh` | Force refresh models from Nostr |
63
+
64
+ ### `routstrd usage`
65
+
66
+ Show recent usage logs and total sats cost.
67
+
68
+ | Option | Default | Description |
69
+ |--------|---------|-------------|
70
+ | `-n, --limit <number>` | 10 | Number of recent entries (max 1000) |
71
+
72
+ Shows timestamp, model, provider, sats cost, token counts, and request ID for each entry.
73
+
74
+ ### `routstrd providers`
75
+
76
+ List and manage providers (subcommand required).
77
+
78
+ #### `routstrd providers list`
79
+
80
+ List all providers with their enabled/disabled status. Shows index, status, and base URL.
81
+
82
+ ```
83
+ Providers (12 total, 2 disabled):
84
+
85
+ [0] enabled https://provider1.example.com
86
+ [1] enabled https://provider2.example.com
87
+ [2] DISABLED https://provider3.example.com
88
+ ```
89
+
90
+ #### `routstrd providers disable <indices...>`
91
+
92
+ Disable providers by their index numbers.
93
+
94
+ ```sh
95
+ routstrd providers disable 0 2 5
96
+ ```
97
+
98
+ #### `routstrd providers enable <indices...>`
99
+
100
+ Enable providers by their index numbers.
101
+
102
+ ```sh
103
+ routstrd providers enable 0 2 5
104
+ ```
105
+
106
+ ### `routstrd clients`
107
+
108
+ List and manage API clients (subcommand required).
109
+
110
+ | Option | Description |
111
+ |--------|-------------|
112
+ | `--manual-refresh` | Refresh routstr21 models and all client integrations now |
113
+ | `--disable-automatic-refresh` | Disable the daemon's scheduled refresh job |
114
+ | `--enable-automatic-refresh` | Re-enable the daemon's scheduled refresh job |
115
+
116
+ The daemon refreshes models and client integrations on a schedule (every 21 minutes by default). Use `--manual-refresh` to do it on demand, and `--disable-automatic-refresh` to stop the scheduled job — the setting is stored in the daemon's `config.json` (`autoRefresh.enabled`) and takes effect without a restart.
117
+
118
+ ```sh
119
+ routstrd clients --manual-refresh # refresh models + integrations now
120
+ routstrd clients --disable-automatic-refresh # no scheduled refresh
121
+ routstrd clients --enable-automatic-refresh # scheduled refresh back on
122
+ ```
123
+
124
+ #### `routstrd clients list`
125
+
126
+ List all registered clients with their ID, name, API key, and creation date.
127
+
128
+
129
+ #### `routstrd clients add`
130
+
131
+ Add a new client or set up a client integration.
132
+
133
+ | Option | Description |
134
+ |--------|-------------|
135
+ | `-n, --name <name>` | Client name (required when not using integration flags) |
136
+ | `--opencode` | Set up OpenCode integration |
137
+ | `--openclaw` | Set up OpenClaw integration |
138
+ | `--pi-agent` | Set up Pi Agent integration |
139
+ | `--claude-code` | Set up Claude Code integration |
140
+
141
+ ```sh
142
+ routstrd clients add --opencode --pi-agent --claude-code # multiple integrations
143
+ routstrd clients add -n "My App" # generic client
144
+ ```
145
+
146
+ Returns the client ID and API key for use with the OpenAI-compatible API.
147
+
148
+ #### `routstrd clients delete <id>`
149
+
150
+ Delete a registered client by its ID.
151
+
152
+ ### `routstrd npubs`
153
+
154
+ Manage registered npubs and their roles/names (subcommand required). Management commands route through the auth proxy (`--auth-url`) and use NIP-98 auth.
155
+
156
+ | Command | Description |
157
+ |---------|-------------|
158
+ | `routstrd npubs list` | List registered npubs with role and display name |
159
+ | `routstrd npubs register [--name <name>]` | Register yourself as the first admin (bootstrap only) |
160
+ | `routstrd npubs add <npub> [--role <role>] [--name <name>]` | Add an npub (accepts hex or npub1...) |
161
+ | `routstrd npubs update <npub> [--role <role>] [--name <name>]` | Update role and/or name (admin only) |
162
+ | `routstrd npubs delete <npub>` | Delete an npub |
163
+
164
+ ### `routstrd remote <url>`
165
+
166
+ Configure a remote daemon URL. Generates a Nostr identity (nsec/npub) for NIP-98 authentication automatically.
167
+
168
+ ```sh
169
+ routstrd remote https://your-remote-daemon.com
170
+ ```
171
+
172
+ ### `routstrd refresh`
173
+
174
+ Refresh routstr21 models from Nostr and re-run integrations for all registered clients. Equivalent to `routstrd clients --manual-refresh`.
175
+
176
+ | Field | Type | Default | Description |
177
+ |-------|------|---------|-------------|
178
+ | `port` | number | 8008 | Daemon HTTP port |
179
+ | `provider` | string\|null | null | Default provider URL |
180
+ | `daemonUrl` | string\|null | null | Remote daemon URL |
181
+ | `nsec` | string\|null | null | Nostr secret key for NIP-98 auth |
182
+ | `cocodPath` | string\|null | null | Custom path to cocod executable |
183
+ | `mode` | string | `"apikeys"` | Client mode (`apikeys` or `xcashu`) |
184
+ | `autoRefresh` | object | `{ enabled: true }` | Scheduled refresh job settings (`enabled`, `intervalMs`) |
185
+
186
+ | Variable | Default | Description |
187
+ |----------|---------|-------------|
188
+ | `ROUTSTRD_DIR` | `~/.routstrd` | Config directory |
189
+ | `ROUTSTRD_WALLET_DIR` | `~/.routstrd/wallet` | In-process Cashu wallet data directory |
190
+ | `ROUTSTRD_WALLET_PID` | `<wallet>/wallet.pid` | In-process wallet lock path |
191
+ | `COCOD_DIR` | `~/.cocod` | Legacy external cocod compatibility directory |
192
+
193
+ ### `routstrd mode`
194
+
195
+ Interactive prompt to set the client mode:
196
+ 1. **lazyrefund/apikeys** (default) — Pseudonymous accounts kept with Routstr nodes, refunded after 5 mins if unused.
197
+ 2. **xcashu** (coming soon) — Balances never kept with nodes, all refunded in response.
198
+
199
+ Changing mode restarts the daemon automatically.
200
+
201
+ ### `routstrd monitor`
202
+
203
+ Open an interactive TUI (htop-like) for usage monitoring.
204
+
205
+ ### `routstrd logs`
206
+
207
+ View daemon logs.
208
+
209
+ | Option | Default | Description |
210
+ |--------|---------|-------------|
211
+ | `-f, --follow` | false | Follow log output (like `tail -f`) |
212
+ | `-c, --coco` | false | Show Cashu wallet-engine (coco) logs instead of daemon logs |
213
+ | `-n, --lines <number>` | 50 | Number of lines to show |
214
+
215
+ Log files are stored at `~/.routstrd/logs/YYYY-MM-DD.log`. Wallet-engine (Cashu/coco) diagnostics go to a separate `~/.routstrd/coco-logs/YYYY-MM-DD.log` so they don't pollute the main daemon logs.
216
+
217
+ ## Wallet Commands
218
+
219
+ New wallets automatically trust `https://mint.cubabitcoin.org` as their default mint. The default is used when a wallet command does not include `--mint-url`.
220
+
221
+ ### `routstrd wallet status`
222
+
223
+ Check wallet status.
224
+
225
+ ### `routstrd wallet unlock <passphrase>`
226
+
227
+ Unlock the wallet with a passphrase.
228
+
229
+ ### `routstrd wallet balance`
230
+
231
+ Get wallet balance.
232
+
233
+ ### `routstrd wallet receive cashu <token>`
234
+
235
+ Receive funds via a Cashu token.
236
+
237
+ ### `routstrd wallet receive bolt11 <amount>`
238
+
239
+ Create a Lightning invoice to receive funds. Displays a QR code.
240
+
241
+ | Option | Description |
242
+ |--------|-------------|
243
+ | `--mint-url <url>` | Mint URL to use |
244
+
245
+ ### `routstrd wallet send cashu <amount>`
246
+
247
+ Create a Cashu token to send.
248
+
249
+ | Option | Description |
250
+ |--------|-------------|
251
+ | `--mint-url <url>` | Mint URL to use |
252
+
253
+ ### `routstrd wallet send bolt11 <invoice>`
254
+
255
+ Pay a Lightning invoice.
256
+
257
+ | Option | Description |
258
+ |--------|-------------|
259
+ | `--mint-url <url>` | Mint URL to use |
260
+
261
+ ### `routstrd wallet mints list`
262
+
263
+ List configured wallet mints.
264
+
265
+ ### `routstrd wallet mints add <url>`
266
+
267
+ Add a new mint by URL.
268
+
269
+ ### `routstrd wallet mints set-default <url>`
270
+
271
+ Set the persistent default mint. If necessary, the mint is added as trusted first.
272
+
273
+ ### `routstrd wallet mints info <url>`
274
+
275
+ Get info about a specific mint.
276
+
277
+ ## Daemon API
278
+
279
+ The daemon exposes an OpenAI-compatible HTTP API at `http://localhost:8008`:
280
+
281
+ ### `GET /health`
282
+
283
+ Health check endpoint.
284
+
285
+ ### `GET /v1/models`
286
+
287
+ List available models (OpenAI-compatible).
288
+
289
+ ### `POST /v1/chat/completions`
290
+
291
+ Route a chat completion request.
292
+
293
+ ```json
294
+ {
295
+ "model": "model-id",
296
+ "messages": [{ "role": "user", "content": "Hello" }],
297
+ "stream": false
298
+ }
299
+ ```
300
+
301
+ ## Configuration
302
+
303
+ Config file: `~/.routstrd/config.json`
304
+
305
+ | Field | Type | Default | Description |
306
+ |-------|------|---------|-------------|
307
+ | `port` | number | 8008 | Daemon HTTP port |
308
+ | `provider` | string\|null | null | Default provider URL |
309
+ | `cocodPath` | string\|null | null | Custom path to cocod executable |
310
+ | `mode` | string | `"apikeys"` | Client mode (`apikeys` or `xcashu`) |
311
+ | `autoRefresh` | object | `{ enabled: true }` | Scheduled refresh job settings (`enabled`, `intervalMs`) |
312
+
313
+ ### Environment Variables
314
+
315
+ | Variable | Default | Description |
316
+ |----------|---------|-------------|
317
+ | `ROUTSTRD_DIR` | `~/.routstrd` | Config directory |
318
+ | `ROUTSTRD_SOCKET` | `~/.routstrd/routstrd.sock` | IPC socket path |
319
+ | `ROUTSTRD_PID` | `~/.routstrd/routstrd.pid` | PID file path |
320
+
321
+ ## Remote Mode
322
+
323
+ When `daemonUrl` is configured, commands connect to a remote daemon instead of a local one:
324
+ - Client names are suffixed with the last 7 chars of your npub
325
+ - All requests are automatically NIP-98 signed using your local nsec
326
+ - Local-only commands (`onboard`, `start`, `restart`, `mode`, `logs`, `service`) are disabled
327
+
328
+ ## Pi Integration
329
+
330
+ When `routstrd onboard` runs, it automatically configures a `routstr` provider in `pi`'s `models.json` with an OpenAI-compatible base URL and API key. This allows pi (the AI coding agent) to use Routstr providers seamlessly.
331
+
332
+ ## File Locations
333
+
334
+ | Path | Description |
335
+ |------|-------------|
336
+ | `~/.routstrd/config.json` | Configuration |
337
+ | `~/.routstrd/routstr.db` | SQLite database |
338
+ | `~/.routstrd/routstrd.sock` | IPC socket |
339
+ | `~/.routstrd/routstrd.pid` | PID file |
340
+ | `~/.routstrd/logs/YYYY-MM-DD.log` | Daily daemon log files |
341
+ | `~/.routstrd/coco-logs/YYYY-MM-DD.log` | Daily Cashu wallet-engine (coco) log files |