skydive-cli 0.1.0-beta.106
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 +259 -0
- package/dist/js/bin.mjs +2348 -0
- package/dist/js/boot-DRWra2vY.mjs +6222 -0
- package/dist/js/print-CQ8b7JUC.mjs +745 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# skydive-cli
|
|
2
|
+
|
|
3
|
+
The Skydive CLI — manage agents and chat with them from the terminal.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx skydive-cli --help
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
The CLI has two credentials, stored together in a single `config.json`. The
|
|
12
|
+
location is platform-conventional (resolved via `env-paths`), so it is **not**
|
|
13
|
+
`~/.config/skydive/` everywhere:
|
|
14
|
+
|
|
15
|
+
| Platform | Path |
|
|
16
|
+
| -------- | ---------------------------------------------------------------- |
|
|
17
|
+
| macOS | `~/Library/Preferences/skydive/config.json` |
|
|
18
|
+
| Linux | `~/.config/skydive/config.json` (or `$XDG_CONFIG_HOME/skydive/`) |
|
|
19
|
+
| Windows | `%APPDATA%\skydive\config.json` |
|
|
20
|
+
|
|
21
|
+
`skydive auth status` prints the real resolved path (`Config: …`) — trust that
|
|
22
|
+
over this table if they ever disagree.
|
|
23
|
+
|
|
24
|
+
- **API key** (`sky_live_…`). Mint one at `skydive.com/account`, then:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
skydive auth login # paste the key
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- **User session** for `skydive chat`. Chat is user-level and multi-agent,
|
|
31
|
+
so it signs you in via the browser (device flow) rather than a per-agent
|
|
32
|
+
API key. `skydive chat` does this automatically on first run; you can also
|
|
33
|
+
do it up front:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
skydive auth login --web # opens the browser, prompts for approval
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Either credential authenticates the management commands (`agents`, `keys`,
|
|
40
|
+
`secrets`): the CLI prefers the API key and falls back to the `--web` chat
|
|
41
|
+
session, so a `--web` login alone is enough to run them — you do **not** need a
|
|
42
|
+
separate API key. The API key is only required when you have no chat session
|
|
43
|
+
(e.g. CI). `skydive chat` requires the chat session specifically.
|
|
44
|
+
|
|
45
|
+
`skydive auth status` shows both; `skydive auth logout` clears them.
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
skydive agents list
|
|
51
|
+
skydive agents get <id>
|
|
52
|
+
skydive agents create --name "My Agent"
|
|
53
|
+
|
|
54
|
+
skydive keys list --agent-id <id>
|
|
55
|
+
skydive keys create <name> --agent-id <id>
|
|
56
|
+
skydive keys revoke <id> --agent-id <id>
|
|
57
|
+
|
|
58
|
+
skydive secrets list --agent-id <id>
|
|
59
|
+
skydive secrets set <KEY> --agent-id <id> # value from stdin
|
|
60
|
+
skydive secrets rm <KEY> --agent-id <id>
|
|
61
|
+
|
|
62
|
+
skydive chat # interactive chat TUI (Node; fetches Bun on first run)
|
|
63
|
+
skydive chat -p "<prompt>" # one-shot, non-interactive (runs under Node)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Global flags: `--json`, `--quiet`, `--api-url <url>`.
|
|
67
|
+
|
|
68
|
+
## `skydive secrets`
|
|
69
|
+
|
|
70
|
+
Manage the environment secrets injected into an agent's sandbox. All
|
|
71
|
+
subcommands are scoped to an agent with `--agent-id <id>` and require an
|
|
72
|
+
API key with edit access to that agent.
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
skydive secrets list --agent-id <id> # names only — values are never returned
|
|
76
|
+
skydive secrets set OPENAI_API_KEY --agent-id <id> # reads the value from stdin
|
|
77
|
+
printf '%s' "$TOKEN" | skydive secrets set MY_TOKEN --agent-id <id>
|
|
78
|
+
skydive secrets set MY_TOKEN "literal-value" --agent-id <id>
|
|
79
|
+
skydive secrets rm MY_TOKEN --agent-id <id>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- Keys must be env-var identifiers (uppercase letters, digits, underscores).
|
|
83
|
+
- `set` reads the value from **stdin** when no value argument is given, so the
|
|
84
|
+
secret stays out of shell history. Passing it inline is supported for
|
|
85
|
+
scripting but avoid it in an interactive shell.
|
|
86
|
+
- Use `printf '%s'` rather than `echo -n` when piping a value: `echo -n` is not
|
|
87
|
+
portable (some `sh` builtins emit `-n` literally instead of suppressing the
|
|
88
|
+
newline), which would silently store a corrupted value. Since values are
|
|
89
|
+
write-only and cannot be read back to verify, that failure stays invisible
|
|
90
|
+
until something downstream breaks.
|
|
91
|
+
- **Values are write-only over the API.** `list` returns key names, never
|
|
92
|
+
values — the same contract as the in-sandbox `platform secrets` surface.
|
|
93
|
+
- Setting a secret updates the agent's vault. If an outbound-proxy rule
|
|
94
|
+
references that key, the proxy picks up the new value on the next request.
|
|
95
|
+
Setting a secret does **not** by itself create a proxy rule — see below.
|
|
96
|
+
|
|
97
|
+
## `skydive chat`
|
|
98
|
+
|
|
99
|
+
An interactive terminal chat client (an OpenTUI app) that drives the same
|
|
100
|
+
agents, sandboxes, and streaming responses as the web app — over the
|
|
101
|
+
internal API. On launch it walks you through:
|
|
102
|
+
|
|
103
|
+
1. **Agent picker** — type to filter your agents by name; `↑/↓` to move,
|
|
104
|
+
`↵` to open, or `ctrl+n` to create one.
|
|
105
|
+
2. **Conversation picker** — resume an existing thread or start a new one
|
|
106
|
+
(also filterable).
|
|
107
|
+
3. **Chat** — send a message and watch the reply stream, with markdown
|
|
108
|
+
formatting, collapsed reasoning, and rich rendering of tool calls
|
|
109
|
+
(`bash`, `edit`/`write` diffs, `read`, `grep`/`glob`).
|
|
110
|
+
|
|
111
|
+
Runs under **Node** like every other command. The TUI renders through
|
|
112
|
+
OpenTUI, whose native core needs the [Bun](https://bun.sh) runtime, so the
|
|
113
|
+
first `chat` run downloads a private, pinned Bun and re-execs under it
|
|
114
|
+
automatically — no separate Bun install required:
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
npx skydive-cli chat
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The Bun binary is cached under the CLI config dir and reused after the first
|
|
121
|
+
run. Already have Bun and want to skip the download? Point `SKYDIVE_BUN_PATH`
|
|
122
|
+
at your `bun` binary, or just invoke the command under `bun`.
|
|
123
|
+
|
|
124
|
+
### Non-interactive: `chat -p`
|
|
125
|
+
|
|
126
|
+
For scripts, pipes, and CI, `-p`/`--print` sends a single prompt, streams the
|
|
127
|
+
reply to stdout, and exits — the `claude -p` convention. It has no TUI, so it
|
|
128
|
+
runs under plain **Node** (no Bun needed):
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
skydive chat -p "summarize my open PRs" --agent grace
|
|
132
|
+
echo "what changed today?" | skydive chat -p --agent grace # prompt from stdin
|
|
133
|
+
skydive chat -p "and the one before?" --agent grace --conversation <id>
|
|
134
|
+
skydive chat -p "status?" --agent grace --json # structured envelope
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- `--agent <id|slug|name>` targets the agent. Optional when the account has
|
|
138
|
+
exactly one agent; required (with the candidate list printed) otherwise.
|
|
139
|
+
- `--conversation <id>` continues an existing thread; omitted, it starts a new
|
|
140
|
+
one. The conversation id is included in `--json` output for chaining.
|
|
141
|
+
- `-p` needs a user session just like `chat`, but never opens the interactive
|
|
142
|
+
browser login — sign in first with `skydive auth login --web` or set
|
|
143
|
+
`SKYDIVE_SESSION_TOKEN`.
|
|
144
|
+
- `--json` prints `{ agentId, agentName, conversationId, isNewConversation,
|
|
145
|
+
runId, text }` instead of streaming the raw text.
|
|
146
|
+
- **Recovering a dropped run.** A long run's stream can be cut off at the edge
|
|
147
|
+
(a gateway 502/504) after the run was created. The run keeps going
|
|
148
|
+
server-side, so a blind retry would re-execute the agent. Instead, note the
|
|
149
|
+
`runId` (always in `--json` output) and fetch the result once it's done:
|
|
150
|
+
|
|
151
|
+
```sh
|
|
152
|
+
skydive runs get <runId> # prints the reply; --json for the envelope
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`runs get` re-attaches to the run and replays its full reply whether it's
|
|
156
|
+
still streaming or already finished.
|
|
157
|
+
|
|
158
|
+
It defaults to the production API (`https://api.skydive.com`). For local
|
|
159
|
+
dev, point it at your stack:
|
|
160
|
+
|
|
161
|
+
```sh
|
|
162
|
+
npx skydive-cli chat --api-url http://localhost:4500
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`--api-url` in chat overrides the **app/session** origin (where better-auth
|
|
166
|
+
and the internal tRPC API live), which is distinct from the public
|
|
167
|
+
management API used by `agents`/`keys`.
|
|
168
|
+
|
|
169
|
+
### Keybindings
|
|
170
|
+
|
|
171
|
+
| Context | Key | Action |
|
|
172
|
+
| ------------------- | ------------- | ------------------------------------- |
|
|
173
|
+
| Pickers | _type_ | filter the list |
|
|
174
|
+
| Pickers | `↑` / `↓` | move selection |
|
|
175
|
+
| Pickers | `↵` | open / select |
|
|
176
|
+
| Pickers | `esc` | back |
|
|
177
|
+
| Agent picker | `ctrl+n` | create an agent |
|
|
178
|
+
| Agent picker | `ctrl+w` | switch workspace |
|
|
179
|
+
| Agent picker | `tab` | toggle mine / whole-org agents |
|
|
180
|
+
| Conversation picker | `ctrl+d` | delete the highlighted conversation |
|
|
181
|
+
| Chat | `↵` | send (or queue, while streaming) |
|
|
182
|
+
| Chat | `pgup`/`pgdn` | scroll the transcript |
|
|
183
|
+
| Chat | `ctrl+c` | cancel the active run; again to quit |
|
|
184
|
+
| Chat | `esc` | back to the conversation picker |
|
|
185
|
+
| Chat | `ctrl+p` | switch model |
|
|
186
|
+
| Chat | `ctrl+o` | switch theme |
|
|
187
|
+
| Chat | `ctrl+t` | grant / revoke local machine access |
|
|
188
|
+
| Chat | `ctrl+l` | open this conversation in the browser |
|
|
189
|
+
| Chat | `ctrl+r` | run the newest pending connect card |
|
|
190
|
+
| Chat | `ctrl+v` | paste an image from the clipboard |
|
|
191
|
+
| Chat | `ctrl+x` | drop the most recently staged image |
|
|
192
|
+
| Chat | `?` | show the keybinding reference |
|
|
193
|
+
|
|
194
|
+
Messages typed while a response is streaming are **queued** and sent in
|
|
195
|
+
order as each run finishes; `ctrl+c` cancels the current run and clears the
|
|
196
|
+
queue.
|
|
197
|
+
|
|
198
|
+
### Local machine access (`--share-machine` / `ctrl+t`)
|
|
199
|
+
|
|
200
|
+
The chat TUI can grant the agent the ability to run commands **on your local
|
|
201
|
+
machine** so it can read the repo you launched from, run local tooling, etc.
|
|
202
|
+
This is off by default (default-deny) and you opt in explicitly:
|
|
203
|
+
|
|
204
|
+
- `skydive chat --share-machine` enables it at launch, or
|
|
205
|
+
- `ctrl+t` toggles it from the chat screen (the status bar shows `local access`
|
|
206
|
+
when on, `revoke access` when off).
|
|
207
|
+
|
|
208
|
+
What to know before enabling it:
|
|
209
|
+
|
|
210
|
+
- **Per-agent.** The grant is scoped to the agent you're chatting with; other
|
|
211
|
+
agents don't inherit it.
|
|
212
|
+
- **The working directory is a starting point, not a jail.** Commands run with
|
|
213
|
+
their working directory set to wherever you launched `skydive chat`, but this
|
|
214
|
+
is **not** a hard filesystem boundary. This is genuine remote command
|
|
215
|
+
execution (a WebSocket streaming stdin/stdout/stderr), so the agent runs
|
|
216
|
+
commands as your user and can reach anything your user can, including paths
|
|
217
|
+
outside the launch directory. Launch from a scoped directory, but treat the
|
|
218
|
+
grant as "this agent can act as me on this machine," not "this agent can only
|
|
219
|
+
see this folder."
|
|
220
|
+
- **Teardown is automatic.** Access is revoked when the TUI unmounts, so
|
|
221
|
+
quitting the chat drops the grant and reaps any processes the agent spawned.
|
|
222
|
+
- **Interactive only.** Machine sharing is **not** available in `-p`
|
|
223
|
+
(non-interactive) mode \u2014 `--share-machine` has no effect there and the
|
|
224
|
+
print path carries no portal code. You can have scripted (`-p`) or local
|
|
225
|
+
access, not both, in a single invocation.
|
|
226
|
+
|
|
227
|
+
## Environment variables
|
|
228
|
+
|
|
229
|
+
| Variable | Effect |
|
|
230
|
+
| ----------------------- | ------------------------------------------------ |
|
|
231
|
+
| `SKYDIVE_API_KEY` | Management API key (overrides stored key) |
|
|
232
|
+
| `SKYDIVE_API_URL` | Management API base URL |
|
|
233
|
+
| `SKYDIVE_SESSION_TOKEN` | Chat session token (for non-interactive use) |
|
|
234
|
+
| `SKYDIVE_APP_URL` | Chat app/session origin (overrides stored value) |
|
|
235
|
+
| `SKYDIVE_THEME` | Chat colorscheme id (flag `--theme` overrides) |
|
|
236
|
+
| `SKYDIVE_CONFIG_NAME` | On-disk config profile name (default `skydive`) |
|
|
237
|
+
|
|
238
|
+
## Testing the TUI
|
|
239
|
+
|
|
240
|
+
`yarn test:unit` runs both suites: unit tests (`*.test.ts`) under vitest,
|
|
241
|
+
then TUI tests (`*.tui.test.tsx`) under `bun test` (needs [Bun](https://bun.sh)
|
|
242
|
+
≥ 1.3.14 on your PATH — see `engines`).
|
|
243
|
+
|
|
244
|
+
TUI tests render the real OpenTUI screens headlessly — fixed terminal size,
|
|
245
|
+
mock keyboard input, frames captured as plain text — via
|
|
246
|
+
`@opentui/react/test-utils`. OpenTUI needs Bun's FFI, which is why they run
|
|
247
|
+
under `bun test`, not vitest:
|
|
248
|
+
|
|
249
|
+
```sh
|
|
250
|
+
bun test .tui.test # just the TUI suite
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Frame snapshots live in `__snapshots__/` next to each test; a diff there is
|
|
254
|
+
a visual diff of the screen. `yarn render:frames <dir>` writes true-color
|
|
255
|
+
ANSI captures of key screens — CI converts them to PNGs (textimg) and posts
|
|
256
|
+
them as a sticky screenshot comment on CLI PRs.
|
|
257
|
+
|
|
258
|
+
The pattern (stub `fetch`, seed the store, drive keys, assert on
|
|
259
|
+
`captureCharFrame()`) is in `src/chat/tui/screens/agent-picker.tui.test.tsx`.
|