ghostdock 0.0.0-stage → 0.0.8
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/dist/cli-reference.md +1448 -0
- package/dist/cli.md +690 -0
- package/dist/index.js +11427 -0
- package/package.json +32 -4
- package/README.md +0 -3
package/dist/cli.md
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
# Ghostdock CLI
|
|
2
|
+
|
|
3
|
+
Command-line access to your Ghostdock account — built for agents, but usable by humans too.
|
|
4
|
+
Authenticate once, then call Ghostdock's tools without leaving the terminal.
|
|
5
|
+
|
|
6
|
+
This document is written for an agent (or human) driving the CLI directly. It is also published at
|
|
7
|
+
`https://ghostdock.brainchimps.com/cli.md` so an agent can `curl`/fetch it without cloning this repo.
|
|
8
|
+
|
|
9
|
+
## Install / run
|
|
10
|
+
|
|
11
|
+
No install required — run it with `npx`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx ghostdock --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or install it globally:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g ghostdock
|
|
21
|
+
ghostdock --help
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
A global install also gives you `gdock`, a short name for the same CLI. Help
|
|
25
|
+
and hints use whichever name you typed. With `npx`, use `npx ghostdock`:
|
|
26
|
+
`npx gdock` does not work.
|
|
27
|
+
|
|
28
|
+
Inside this monorepo (for development), run from the repo root or `packages/cli`:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bun run --cwd packages/cli build # bundles src/index.ts -> dist/index.js
|
|
32
|
+
bun run --cwd packages/cli dev -- --help # run from source without building
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Output: for people, and `--json` for scripts and agents
|
|
36
|
+
|
|
37
|
+
Every command prints for people by default: one line per event, a symbol, then the message.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
$ ghostdock sandboxes list
|
|
41
|
+
⚓ Marketing site quiet-harbor running
|
|
42
|
+
◌ teal-jetty stopped
|
|
43
|
+
$ ghostdock sites publish ./dist
|
|
44
|
+
↗ https://foggy-teal-bollard.static.ghostdock.app
|
|
45
|
+
✓ Published site foggy-teal-bollard.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`⚓` ready, `✓` done, `↗` a URL, `◌` stopped or gone, `✗` failed, `▂▄▆` in progress. Every line
|
|
49
|
+
carries the name and id the next command needs.
|
|
50
|
+
|
|
51
|
+
Commands that wait show a progress line on stderr while they run. Starting a sandbox
|
|
52
|
+
(`sandboxes create`, `sandboxes wake`) prints how long each step took, measured on the server, each
|
|
53
|
+
step with its own time:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
$ ghostdock sandboxes wake quiet-harbor
|
|
57
|
+
⚓ quiet-harbor running
|
|
58
|
+
⚓ sandbox started in 125ms
|
|
59
|
+
✓ container started in 3.0s
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The container line is missing when no container was started, or when the host is older and did
|
|
63
|
+
not report it. `sandboxes status` prints the same lines for the last start. With `--json` they are
|
|
64
|
+
the `boot` field: `{ trigger, sandbox: { startedAt, readyAt, ms }, container: { … } | null }`, or
|
|
65
|
+
`null` when the command started nothing.
|
|
66
|
+
|
|
67
|
+
**Scripts and agents pass `--json`.** It prints the result as one JSON document on stdout, with
|
|
68
|
+
every field, and nothing else there. It works on every command and anywhere on the line:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
ghostdock sandboxes list --json | jq -r '.sandboxes[].name'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- **stdout is the result, stderr is everything else**: notices (`Using organization acme …`),
|
|
75
|
+
hints and errors. Piping stdout never picks up a notice.
|
|
76
|
+
- **Errors** print as `✗ <what went wrong and what to try>` on stderr and exit non-zero, with or
|
|
77
|
+
without `--json`.
|
|
78
|
+
- **Colour** only on a terminal: piped output and `NO_COLOR=1` get the same text without colour
|
|
79
|
+
codes. `FORCE_COLOR=1` turns it back on.
|
|
80
|
+
|
|
81
|
+
## Global flags
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
ghostdock --version
|
|
85
|
+
ghostdock --base-url <url> <command>
|
|
86
|
+
ghostdock <command> --json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- `--version` / `-v` — print CLI version and exit
|
|
90
|
+
- `--base-url <url>` — API origin for this invocation (wins over `GHOSTDOCK_BASE_URL`)
|
|
91
|
+
- `--json` — print the result as one JSON document on stdout (see Output above)
|
|
92
|
+
|
|
93
|
+
## Commands
|
|
94
|
+
|
|
95
|
+
Commands are grouped by resource, like `gh` or `kubectl`: `ghostdock <resource> <action>`.
|
|
96
|
+
|
|
97
|
+
<!-- generated:command-groups:start (bun run sync:cli-reference; do not edit) -->
|
|
98
|
+
```
|
|
99
|
+
ghostdock apps Published apps of an organization.
|
|
100
|
+
ghostdock env Manage organization environment variables and secrets.
|
|
101
|
+
ghostdock images Organization image catalog: OCI bookmarks, Dockerfiles and Compose files.
|
|
102
|
+
ghostdock login Sign in and store a device access token for this CLI.
|
|
103
|
+
ghostdock logout Revoke the device session and remove stored credentials.
|
|
104
|
+
ghostdock organizations Organizations you belong to.
|
|
105
|
+
ghostdock projects Deployable projects, their deployments and environment.
|
|
106
|
+
ghostdock providers Sandbox providers of an organization.
|
|
107
|
+
ghostdock registry Log in to the organization container registry.
|
|
108
|
+
ghostdock sandboxes Create, run and manage sandboxes.
|
|
109
|
+
ghostdock sites Static sites on the CDN.
|
|
110
|
+
ghostdock skills List and read Agent Skills (same catalog as MCP skill://index.json).
|
|
111
|
+
ghostdock snapshots Sandbox snapshots.
|
|
112
|
+
ghostdock tools List available agent tools.
|
|
113
|
+
ghostdock whoami Show the account this CLI is currently authenticated as.
|
|
114
|
+
```
|
|
115
|
+
<!-- generated:command-groups:end -->
|
|
116
|
+
|
|
117
|
+
Run `ghostdock <command> --help` at any level for its subcommands or flags, e.g.
|
|
118
|
+
`ghostdock sandboxes --help` or `ghostdock sandboxes urls create --help`.
|
|
119
|
+
|
|
120
|
+
Most commands are generated from the tool catalog — see **Invoking a tool** below. Every command
|
|
121
|
+
is listed in the [command index](#command-index); [`cli-reference.md`](cli-reference.md) has each
|
|
122
|
+
one's full description and flags.
|
|
123
|
+
|
|
124
|
+
### Choosing an organization
|
|
125
|
+
|
|
126
|
+
Every organization-scoped command acts on one organization, taken from the first of:
|
|
127
|
+
|
|
128
|
+
1. `--org <id-or-slug>` on the command
|
|
129
|
+
2. the `GHOSTDOCK_ORG` environment variable
|
|
130
|
+
3. the default set with `ghostdock organizations use <id-or-slug>`
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
ghostdock organizations use acme # default for this directory (login sets one when it can)
|
|
134
|
+
ghostdock sandboxes list # stderr: Using organization acme (default, …)
|
|
135
|
+
ghostdock sandboxes list --org beta # --org always wins
|
|
136
|
+
ghostdock organizations current # which organization, and where it comes from
|
|
137
|
+
ghostdock organizations use --clear
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
When the organization does not come from `--org`, the command says which one it uses on stderr,
|
|
141
|
+
so a default never acts silently. The default is stored next to the credentials
|
|
142
|
+
(`./.ghostdock/settings.json`), so it belongs to that directory's login. **Scripts and CI should
|
|
143
|
+
pass `--org` or set `GHOSTDOCK_ORG`** rather than depend on (or change) a stored default, and use
|
|
144
|
+
the organization id: renaming an organization changes its slug, not its id.
|
|
145
|
+
|
|
146
|
+
### `ghostdock login`
|
|
147
|
+
|
|
148
|
+
Ghostdock uses a device-authorization flow: no password is ever typed into the terminal.
|
|
149
|
+
|
|
150
|
+
**Default (print-and-exit) — best when a human is present to click the link:**
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
ghostdock login
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This prints a URL to open in a browser and exits `0` immediately — it does not prompt for input or
|
|
157
|
+
poll for approval. Approve the request in the browser, then complete login with
|
|
158
|
+
**`ghostdock login --code <paste-code>`**, redeeming the one-time code from the browser's
|
|
159
|
+
"Having trouble? Show code" link (see below).
|
|
160
|
+
|
|
161
|
+
Each `login` invocation starts a **new** device session. A later `login --wait` does **not** resume
|
|
162
|
+
polling for a prior plain `login`. To block until approval, run **`ghostdock login --wait` up
|
|
163
|
+
front** instead of plain `login`.
|
|
164
|
+
|
|
165
|
+
**`--wait` — poll until approved:**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
ghostdock login --wait
|
|
169
|
+
# or with a custom timeout (seconds, default 300):
|
|
170
|
+
ghostdock login --wait --timeout 120
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Prints the same URL, then polls the server every few seconds until the login is approved, denied,
|
|
174
|
+
or the timeout elapses. Exits `0` on success, non-zero otherwise.
|
|
175
|
+
|
|
176
|
+
**`--code` — paste-code fallback:**
|
|
177
|
+
|
|
178
|
+
If the CLI can't poll (e.g. it's running in a sandbox with no long-lived process, or the browser
|
|
179
|
+
approval happened on a different machine), the browser's "Having trouble? Show code" link reveals a
|
|
180
|
+
short one-time code. Redeem it directly:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
ghostdock login --code <paste-code>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
On success, credentials are written and the command exits `0`. If the code hasn't been approved
|
|
187
|
+
yet, it exits `1` — approve it in the browser first.
|
|
188
|
+
|
|
189
|
+
**Default organization after login.** Once logged in (with `--wait` or `--code`), `login` sets the
|
|
190
|
+
default organization when that is unambiguous:
|
|
191
|
+
|
|
192
|
+
- `--org <id-or-slug>` sets that one, e.g. `ghostdock login --wait --org acme`. If you are not a
|
|
193
|
+
member of it, no default is set and `login` exits `1`.
|
|
194
|
+
- A default that is still one of your organizations stays as it is.
|
|
195
|
+
- With exactly one organization, that one becomes the default.
|
|
196
|
+
- With several, a person at a terminal picks one from a numbered list (Enter skips). Without a
|
|
197
|
+
terminal (agents, CI) nothing is asked: `login` lists them and points to
|
|
198
|
+
`ghostdock organizations use`.
|
|
199
|
+
|
|
200
|
+
See [Choosing an organization](#choosing-an-organization) for how commands pick it up.
|
|
201
|
+
|
|
202
|
+
### `ghostdock logout`
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
ghostdock logout
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Revokes the device session on the server (best-effort — still clears local credentials even if the
|
|
209
|
+
server call fails, e.g. when offline) and deletes the local credentials file.
|
|
210
|
+
|
|
211
|
+
### `ghostdock whoami`
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
ghostdock whoami
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Prints who the stored access token belongs to and which server it talks to (`--json`:
|
|
218
|
+
`{ "userId": ..., "baseUrl": ... }`).
|
|
219
|
+
Transparently refreshes an expired access token using the stored refresh token before failing.
|
|
220
|
+
Exits `1` with a message if not logged in or the session can't be refreshed.
|
|
221
|
+
|
|
222
|
+
### `ghostdock tools`
|
|
223
|
+
|
|
224
|
+
Lists the tool catalog for the authenticated account:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
ghostdock tools # name + description, one per line
|
|
228
|
+
ghostdock tools --json # the full catalog (including each tool's JSON Schema) as JSON
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Requires login — prints a hint and exits `1` if there's no valid session.
|
|
232
|
+
|
|
233
|
+
### `ghostdock skills`
|
|
234
|
+
|
|
235
|
+
Lists and reads **Agent Skills** for the authenticated account — the same catalog MCP
|
|
236
|
+
clients discover at `skill://index.json` (SEP-2640 / Agent Skills discovery 0.2.0).
|
|
237
|
+
Prefer resources. The MCP tools `skills_list` and `skills_get` are fallbacks for clients that
|
|
238
|
+
cannot use `resources/list` and `resources/read` — skip them if those work.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
ghostdock skills list # name, description, and skill:// URI per skill
|
|
242
|
+
ghostdock skills list --json # official discovery index ($schema + skills[])
|
|
243
|
+
ghostdock skills get skill://github/SKILL.md # print SKILL.md
|
|
244
|
+
ghostdock skills get github # same, by name
|
|
245
|
+
ghostdock skills get org_1/release-notes # organization skill
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`--json` on `get` prints `{ uri, name, description, markdown }`. If the same name exists
|
|
249
|
+
in more than one organization, pass the `skill://` URI from the index.
|
|
250
|
+
|
|
251
|
+
Requires login — prints a hint and exits `1` if there's no valid session.
|
|
252
|
+
|
|
253
|
+
### Invoking a tool
|
|
254
|
+
|
|
255
|
+
Every catalog tool is a command at its own path, with one `--flag` per schema property
|
|
256
|
+
(`sandboxProviderId` -> `--sandbox-provider-id`). The one thing a command acts on is positional instead:
|
|
257
|
+
`ghostdock sandboxes stop <sandbox-id>`, `ghostdock sandboxes urls delete <url-id>`,
|
|
258
|
+
`ghostdock env get <name>`. The organization is always the `--org` flag, by id or slug: a slug is easier to type, an id keeps
|
|
259
|
+
working after the organization is renamed (renaming changes the slug). The MCP tool name is the same path joined with
|
|
260
|
+
underscores: `ghostdock sandboxes urls create` calls the `sandboxes_urls_create` tool. Run
|
|
261
|
+
`ghostdock <command> --help` to see a command's full description, its flags and which are
|
|
262
|
+
required; a group's `--help` lists its commands with one line each. Output is a line per item
|
|
263
|
+
for people; `--json` prints the tool's result as it comes back over MCP.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
ghostdock organizations list
|
|
267
|
+
# • Acme org_123
|
|
268
|
+
ghostdock organizations list --json
|
|
269
|
+
# {"organizations": [{"id": "org_123", "name": "Acme", "slug": "acme"}]}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Number/boolean flags are parsed from their string form; array/object flags take a raw JSON string
|
|
273
|
+
(e.g. `--tags '["a","b"]'`). Requires login — prints a hint and exits `1` if there's no valid
|
|
274
|
+
session, or the server's error message (e.g. "Not a member of this organization") on a `4xx`.
|
|
275
|
+
|
|
276
|
+
The tool list embedded in the CLI binary is generated at build time from the server's tool catalog
|
|
277
|
+
(`bun run sync-catalog` in `packages/cli`), so `--help` and flag parsing work offline; invoking a
|
|
278
|
+
tool still requires a network call and a valid session.
|
|
279
|
+
|
|
280
|
+
Command descriptions are short on purpose. Concepts and workflows live in the built-in Agent
|
|
281
|
+
Skills, the same documents MCP agents read:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
ghostdock skills get sandboxes # sources, manifests, lifecycle, providers, URLs and TCP
|
|
285
|
+
ghostdock skills get sandbox-boot # processes that must come back after idle-stop
|
|
286
|
+
ghostdock skills get environment # organization entries, bindings, local entries, secrets
|
|
287
|
+
ghostdock skills get publishing # sites publish vs projects publish, outcomes, redeploys
|
|
288
|
+
ghostdock skills get incus-setup # connecting your own Incus host
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Sandboxes
|
|
292
|
+
|
|
293
|
+
Read `ghostdock skills get sandboxes` before your first sandbox: what it can boot from, manifests,
|
|
294
|
+
idle-stop and auto-delete, providers, URLs.
|
|
295
|
+
|
|
296
|
+
Every sandbox has a name like `quiet-harbor`, unique within its organization, and every command
|
|
297
|
+
that takes a sandbox accepts it with the organization (`--org`, `GHOSTDOCK_ORG` or the default).
|
|
298
|
+
The long `sandboxId` in `--json` output works too, in the same organization. A name never changes
|
|
299
|
+
while the sandbox exists, so scripts can keep it; once a sandbox is deleted, its name may be given to
|
|
300
|
+
a new one later. The display name is a separate label you can edit. For example, create a sandbox,
|
|
301
|
+
then expose a URL:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
ghostdock sandboxes create --org org_123 --display-name "Marketing site"
|
|
305
|
+
ghostdock sandboxes urls create quiet-harbor --port 8080 --auto-wake true --public true
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### Environment in a sandbox
|
|
309
|
+
|
|
310
|
+
A sandbox exports **nothing** by default (unless you boot from an organization snapshot or catalog
|
|
311
|
+
image whose manifest supplies defaults). `environment` has three parts: `organization` (plain same-name opt-ins from the
|
|
312
|
+
catalogue, see [`ghostdock env`](#ghostdock-env)), `bindings` (slot ← org entry remaps), and `local` (sandbox-only variables/secrets). A local entry overrides an
|
|
313
|
+
organization export of the same name. Prefer the CLI when setting secret values so they are not
|
|
314
|
+
pasted into the agent conversation.
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# At create time, in one call:
|
|
318
|
+
ghostdock sandboxes create --org org_123 \
|
|
319
|
+
--environment '{"organization":["VITE_API_URL","BUILD_TOKEN"],"bindings":[{"name":"DATABASE_URL","organization":"PROD_DATABASE_URL"}],"local":[{"name":"API_KEY","value":"sk_live","kind":"secret"}]}'
|
|
320
|
+
|
|
321
|
+
# Afterwards:
|
|
322
|
+
ghostdock sandboxes env get quiet-harbor
|
|
323
|
+
ghostdock sandboxes env select quiet-harbor --environment '["VITE_API_URL"]' \
|
|
324
|
+
--bindings '[{"name":"DATABASE_URL","organization":"PROD_DATABASE_URL"}]'
|
|
325
|
+
ghostdock sandboxes env select quiet-harbor --environment '[]' # clears plain + remaps (omit bindings)
|
|
326
|
+
ghostdock sandboxes env set API_KEY --sandbox-id quiet-harbor --value sk_live --kind secret
|
|
327
|
+
ghostdock sandboxes env delete API_KEY --sandbox-id quiet-harbor
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Values arrive as real environment variables, so read them with `process.env` / `$VAR` inside the
|
|
331
|
+
sandbox. **Do not pass secrets in `sandboxes commands run` strings** — the command text is retained and
|
|
332
|
+
readable through `sandboxes commands logs`. `sandboxes env get` reports every organization entry
|
|
333
|
+
(selected + overriddenByLocal) and the sandbox's own local entries; `sandboxes status` reports
|
|
334
|
+
just the resolved names.
|
|
335
|
+
|
|
336
|
+
New shell commands and SSH sessions see a change immediately. Processes already running keep the
|
|
337
|
+
values they booted with until restarted (pass `--restart` to `sandboxes env select` /
|
|
338
|
+
`sandboxes env set` / `sandboxes env delete` to restart a running sandbox
|
|
339
|
+
instead).
|
|
340
|
+
|
|
341
|
+
### Images
|
|
342
|
+
|
|
343
|
+
Organization image catalog: OCI bookmarks (`images add`), stored Dockerfiles
|
|
344
|
+
(`images add-dockerfile`), and refs currently in use on sandboxes. `images list` and `images get`
|
|
345
|
+
cover the same catalog family as those add tools — each org row includes `kind`, a redacted
|
|
346
|
+
`manifest` (from `ghostdock.*` Docker/OCI labels), `requiredEnvironment`, and `requiredUrls` (same
|
|
347
|
+
shape as snapshots). `sandboxes create` with `--source '{"type":"image","id":"..."}'` boots a catalog
|
|
348
|
+
row by id and applies its manifest (URLs + env) like an organization snapshot.
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
ghostdock images list --org org_123
|
|
352
|
+
ghostdock images get img_abc --org org_123
|
|
353
|
+
ghostdock images add --org org_123 --ref ghcr.io/acme/app:latest --label "Acme app"
|
|
354
|
+
ghostdock images add-dockerfile --org org_123 --name my-stack --dockerfile "$(cat Dockerfile)"
|
|
355
|
+
ghostdock sandboxes create --org org_123 \
|
|
356
|
+
--source '{"type":"image","id":"img_abc"}' \
|
|
357
|
+
--environment '{"local":[{"name":"API_KEY","kind":"secret","value":"sk_test"}]}'
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Booting with `--source '{"type":"dockerfile","content":"..."}'` parses labels inline without
|
|
361
|
+
persisting a catalog row. That JSON source is Dockerfile text only: COPY/ADD of local files fails.
|
|
362
|
+
`--source '{"type":"compose","files":{"compose.yaml":"..."}}'` boots Docker-in-Docker from those
|
|
363
|
+
inline files (must include `docker-compose.yml`/`yaml` or `compose.yml`/`yaml`) and runs
|
|
364
|
+
`docker compose up`; `ghostdock.*` service labels become the create-time manifest. A directory or
|
|
365
|
+
ZIP — Dockerfile build context, or a Compose project with extra files — is
|
|
366
|
+
[`ghostdock sandboxes build`](#ghostdock-sandboxes-build), not this command. Any OCI ref may still
|
|
367
|
+
be passed as `{ type: "image", ref }` even when it does not appear in `images list`. Catalog compose
|
|
368
|
+
rows still boot via `{ type: "image", id }`.
|
|
369
|
+
|
|
370
|
+
### `ghostdock sites publish`
|
|
371
|
+
|
|
372
|
+
Publish a local directory or ZIP to the CDN (durable public URL, no sandbox):
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
ghostdock sites publish --org org_123 ./dist
|
|
376
|
+
ghostdock sites publish --org org_123 --zip ./site.zip
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
MCP `sites publish` is for small inline payloads. Use this command for a real directory or large ZIP.
|
|
380
|
+
|
|
381
|
+
### `ghostdock projects publish`
|
|
382
|
+
|
|
383
|
+
Inspect a local source tree and publish (CDN when pre-built static, otherwise Compose from a DeploymentSpec).
|
|
384
|
+
Required secrets without values return `awaiting_configuration` instead of a live URL.
|
|
385
|
+
Re-invoke with `--environment` (same JSON shape as `sandboxes create`) after configuring.
|
|
386
|
+
On `build_failed`, `start_failed`, or `verify_failed`, inspect the kept sandbox (unless verification tore it down), then re-invoke with `--spec` (JSON `DeploymentSpec`). The spec is executed on a fresh sandbox and stored for later replay. Do not pass `--spec` with `--replan`. Every terminal outcome stores the upload and returns authenticated `fileUrls`. Detected tests always run after the stack is up; pass `--require-verify` to refuse a deploy when they fail.
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
ghostdock projects publish --org org_123 ./app
|
|
390
|
+
ghostdock projects publish --org org_123 --auto-stop-interval-minutes -1 --zip ./app.zip
|
|
391
|
+
ghostdock projects publish --org org_123 --project-id proj_123 ./app
|
|
392
|
+
ghostdock projects publish --org org_123 ./app \
|
|
393
|
+
--environment '{"organization":["DATABASE_URL"],"local":[{"name":"API_KEY","value":"sk_live","kind":"secret"}]}'
|
|
394
|
+
ghostdock projects publish --org org_123 ./app --spec '{"version":1,"run":{"kind":"static","outputDir":"."},"env":[]}'
|
|
395
|
+
ghostdock projects publish --org org_123 --require-verify ./app
|
|
396
|
+
ghostdock projects publish --org org_123 --sandbox-provider-id prov_123 ./app
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
MCP `projects publish` is for small inline payloads. Use this command for a real directory or large ZIP.
|
|
400
|
+
|
|
401
|
+
### `ghostdock sandboxes build`
|
|
402
|
+
|
|
403
|
+
Create a sandbox from a local Dockerfile or Compose directory. The CLI zips the directory (or sends
|
|
404
|
+
`--zip`) and the server builds it. MCP `sandboxes create` stays inline text only.
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
ghostdock sandboxes build --org org_123 --kind dockerfile ./app
|
|
408
|
+
ghostdock sandboxes build --org org_123 --kind compose --zip ./stack.zip
|
|
409
|
+
ghostdock sandboxes build --org org_123 --kind dockerfile \
|
|
410
|
+
--sandbox-provider-id prov_123 --display-name "API" ./app
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
The Dockerfile (`Dockerfile` or `dockerfile`) or a compose file (`docker-compose.yml`/`yaml`,
|
|
414
|
+
`compose.yml`/`yaml`) must sit at the directory root, or at the root of the ZIP. A ZIP that wraps
|
|
415
|
+
the project in one folder is unwrapped. Pass one directory or `--zip`, not both.
|
|
416
|
+
|
|
417
|
+
### `ghostdock sandboxes files upload`
|
|
418
|
+
|
|
419
|
+
`sandboxes files upload` is convenient for small payloads. For a local directory,
|
|
420
|
+
multiple files, or a large ZIP, use the dedicated multipart upload command instead:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
ghostdock sandboxes files upload quiet-harbor ./dist
|
|
424
|
+
ghostdock sandboxes files upload quiet-harbor ./index.html ./assets
|
|
425
|
+
ghostdock sandboxes files upload quiet-harbor --zip ./site.zip
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Each positional path may be a file or directory. Directory contents are uploaded recursively,
|
|
429
|
+
preserving their relative paths; a file is uploaded by its basename. A `sandboxes files upload` call needs
|
|
430
|
+
at least one path or `--zip`. Uploading to a stopped sandbox resumes it automatically.
|
|
431
|
+
|
|
432
|
+
### `ghostdock env`
|
|
433
|
+
|
|
434
|
+
Manage the environment variables and secrets an organization offers to its sandboxes and projects.
|
|
435
|
+
A sandbox inherits nothing automatically — select the entries it needs on that sandbox.
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
ghostdock env list --org org_123
|
|
439
|
+
ghostdock env get VITE_API_URL --org org_123
|
|
440
|
+
ghostdock env set VITE_API_URL --org org_123 --value https://api.example.com
|
|
441
|
+
ghostdock env delete VITE_API_URL --org org_123
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Variables vs secrets.** A variable is readable by anyone who can see the organization; `env list`
|
|
445
|
+
prints its value inline. A secret can be set and replaced but never read back — it shows as
|
|
446
|
+
`<secret>` in `env list` and `env get` refuses it. Pass `--secret` to create one:
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
# Keeps the value out of shell history and the process list
|
|
450
|
+
printf %s "$STRIPE_KEY" | ghostdock env set STRIPE_SECRET_KEY --org org_123 --secret --value-stdin
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
`--secret` is only required when creating; updating an existing entry keeps its kind. To convert one,
|
|
454
|
+
pass `--kind variable` or `--kind secret` explicitly along with the new value:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
ghostdock env set STRIPE_SECRET_KEY --org org_123 --kind variable --value not-secret-anymore
|
|
458
|
+
# Warning: STRIPE_SECRET_KEY was a secret and is now a variable — its value is readable by everyone in the organization.
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
Converting never reveals the old secret: `set` always replaces the value, so the value you supply in
|
|
462
|
+
that call is the one that becomes readable. The command prints what changed either way.
|
|
463
|
+
|
|
464
|
+
`env get` prints the bare value so it can be captured in a shell (`API=$(ghostdock env get
|
|
465
|
+
VITE_API_URL --org org_123)`). It also returns values too large for `env list`, which
|
|
466
|
+
withholds anything over 1024 characters rather than truncating it — a printed value is always the
|
|
467
|
+
complete value.
|
|
468
|
+
|
|
469
|
+
With `--json`, `list`, `get` and `set` print the tool's result instead. These commands wrap the
|
|
470
|
+
`env list`, `env get`, `env set` and
|
|
471
|
+
`env delete` tools, which are also available directly (and over MCP).
|
|
472
|
+
|
|
473
|
+
Names must be valid environment variable names, and names the sandbox runtime owns (`PATH`,
|
|
474
|
+
`HOME`, anything starting with `GHOSTDOCK_`, …) are rejected. Prefix a name with `VITE_`
|
|
475
|
+
only when browser code must read it: Vite inlines those into the published bundle, so a `VITE_`
|
|
476
|
+
secret is public.
|
|
477
|
+
|
|
478
|
+
## Command index
|
|
479
|
+
|
|
480
|
+
Every command with its arguments and what it does. Run `ghostdock <command> --help` for its flags,
|
|
481
|
+
or read [`cli-reference.md`](cli-reference.md) for every command's full description and flags.
|
|
482
|
+
|
|
483
|
+
<!-- generated:command-index:start (bun run sync:cli-reference; do not edit) -->
|
|
484
|
+
#### apps
|
|
485
|
+
|
|
486
|
+
| Command | What it does |
|
|
487
|
+
| --- | --- |
|
|
488
|
+
| `ghostdock apps list [flags]` | List the live published apps (sites) of an organization, with their URLs. |
|
|
489
|
+
|
|
490
|
+
#### env
|
|
491
|
+
|
|
492
|
+
| Command | What it does |
|
|
493
|
+
| --- | --- |
|
|
494
|
+
| `ghostdock env delete <name> [flags]` | Delete a variable or secret. |
|
|
495
|
+
| `ghostdock env get <name> [flags]` | Print one variable value in full (secrets cannot be read). |
|
|
496
|
+
| `ghostdock env list [flags]` | List variables and secrets. |
|
|
497
|
+
| `ghostdock env set <name> [flags]` | Create or replace a variable or secret. |
|
|
498
|
+
|
|
499
|
+
#### images
|
|
500
|
+
|
|
501
|
+
| Command | What it does |
|
|
502
|
+
| --- | --- |
|
|
503
|
+
| `ghostdock images add --ref <string> [flags]` | Bookmark an OCI image ref in the organization’s image catalog. |
|
|
504
|
+
| `ghostdock images add-compose --name <string> --files <object> [flags]` | Add Compose files to the organization’s image catalog. |
|
|
505
|
+
| `ghostdock images add-dockerfile --name <string> --dockerfile <string> [flags]` | Add a Dockerfile to the organization’s image catalog. |
|
|
506
|
+
| `ghostdock images get <image-id> [flags]` | Get one catalog image with its spec, manifest and requirements. |
|
|
507
|
+
| `ghostdock images list [flags]` | List the images an organization can boot sandboxes from. |
|
|
508
|
+
| `ghostdock images remove <image-id> [flags]` | Remove an image from the organization’s catalog. |
|
|
509
|
+
| `ghostdock images update-compose <image-id> [flags]` | Replace a catalog Compose image’s files and/or name. |
|
|
510
|
+
| `ghostdock images update-dockerfile <image-id> --dockerfile <string> [flags]` | Replace a catalog Dockerfile, optionally renaming it. |
|
|
511
|
+
|
|
512
|
+
#### login
|
|
513
|
+
|
|
514
|
+
| Command | What it does |
|
|
515
|
+
| --- | --- |
|
|
516
|
+
| `ghostdock login [flags]` | Sign in and store a device access token for this CLI. |
|
|
517
|
+
|
|
518
|
+
#### logout
|
|
519
|
+
|
|
520
|
+
| Command | What it does |
|
|
521
|
+
| --- | --- |
|
|
522
|
+
| `ghostdock logout` | Revoke the device session and remove stored credentials. |
|
|
523
|
+
|
|
524
|
+
#### organizations
|
|
525
|
+
|
|
526
|
+
| Command | What it does |
|
|
527
|
+
| --- | --- |
|
|
528
|
+
| `ghostdock organizations current [flags]` | Show which organization commands use, and where it comes from. |
|
|
529
|
+
| `ghostdock organizations list` | List the organizations you belong to, with their ids and slugs. |
|
|
530
|
+
| `ghostdock organizations use [org] [flags]` | Set the default organization for commands run in this directory. |
|
|
531
|
+
|
|
532
|
+
#### projects
|
|
533
|
+
|
|
534
|
+
| Command | What it does |
|
|
535
|
+
| --- | --- |
|
|
536
|
+
| `ghostdock projects create --display-name <string> [flags]` | Create an empty project. |
|
|
537
|
+
| `ghostdock projects deployments get <deployment-id> --project-id <string> [flags]` | Get one deploy attempt, with links to its stored files. |
|
|
538
|
+
| `ghostdock projects deployments list <project-id> [flags]` | List a project’s deploy attempts, newest first. |
|
|
539
|
+
| `ghostdock projects env delete <name> --project-id <string> [flags]` | Delete one of a project’s own variables or secrets. |
|
|
540
|
+
| `ghostdock projects env get <project-id> [flags]` | Get a project’s stored environment. |
|
|
541
|
+
| `ghostdock projects env select <project-id> --environment <array> [flags]` | Replace the organization entries a project exports. |
|
|
542
|
+
| `ghostdock projects env set <name> --project-id <string> --value <string> --kind <string> [flags]` | Create or replace one of a project’s own variables or secrets. |
|
|
543
|
+
| `ghostdock projects get <project-id> [flags]` | Get a project with its latest attempt and live deployment. |
|
|
544
|
+
| `ghostdock projects list [flags]` | List an organization’s projects. |
|
|
545
|
+
| `ghostdock projects publish [path] [flags]` | Inspect local source with the deploy agent and publish to the CDN or a sandbox. |
|
|
546
|
+
| `ghostdock projects redeploy <project-id> [flags]` | Deploy a project’s stored source again, with its current environment. |
|
|
547
|
+
| `ghostdock projects update <project-id> --display-name <string> [flags]` | Rename a project. |
|
|
548
|
+
|
|
549
|
+
#### providers
|
|
550
|
+
|
|
551
|
+
| Command | What it does |
|
|
552
|
+
| --- | --- |
|
|
553
|
+
| `ghostdock providers disconnect <sandbox-provider-id> [flags]` | Disconnect one of the organization’s own sandbox providers. |
|
|
554
|
+
| `ghostdock providers list [flags]` | List the sandbox providers an organization can create sandboxes on. |
|
|
555
|
+
| `ghostdock providers rename <sandbox-provider-id> --name <string> [flags]` | Rename one of the organization’s own sandbox providers. |
|
|
556
|
+
| `ghostdock providers set-default <sandbox-provider-id> [flags]` | Set the provider used when a create omits sandboxProviderId. |
|
|
557
|
+
| `ghostdock providers start-incus [flags]` | Start connecting an Incus host as a sandbox provider. |
|
|
558
|
+
| `ghostdock providers verify-incus <sandbox-provider-id> [flags]` | Check or finish connecting an Incus host. |
|
|
559
|
+
|
|
560
|
+
#### registry
|
|
561
|
+
|
|
562
|
+
| Command | What it does |
|
|
563
|
+
| --- | --- |
|
|
564
|
+
| `ghostdock registry credentials [flags]` | Print registry host, username, and the one-hour password. |
|
|
565
|
+
| `ghostdock registry login [flags]` | Fetch a one-hour password and run docker login --password-stdin. |
|
|
566
|
+
|
|
567
|
+
#### sandboxes
|
|
568
|
+
|
|
569
|
+
| Command | What it does |
|
|
570
|
+
| --- | --- |
|
|
571
|
+
| `ghostdock sandboxes build [path] --kind <value> [flags]` | Create a sandbox from a local Dockerfile or Compose directory. |
|
|
572
|
+
| `ghostdock sandboxes commands get <command-id> --sandbox-id <string> --session-id <string> [flags]` | Get a shell command’s status and exit code. |
|
|
573
|
+
| `ghostdock sandboxes commands kill <command-id> --sandbox-id <string> --session-id <string> [flags]` | Interrupt a running shell command. |
|
|
574
|
+
| `ghostdock sandboxes commands logs <command-id> --sandbox-id <string> --session-id <string> [flags]` | Get a page of a shell command’s stdout and stderr. |
|
|
575
|
+
| `ghostdock sandboxes commands run <sandbox-id> --command <string> [flags]` | Run a shell command in a sandbox. |
|
|
576
|
+
| `ghostdock sandboxes create --source <object> [flags]` | Create a sandbox from a snapshot, OCI image, Dockerfile or Compose files. |
|
|
577
|
+
| `ghostdock sandboxes delete <sandbox-id> [flags]` | Permanently delete a sandbox and its files. |
|
|
578
|
+
| `ghostdock sandboxes env delete <name> --sandbox-id <string> [flags]` | Delete one of a sandbox’s own variables or secrets. |
|
|
579
|
+
| `ghostdock sandboxes env get <sandbox-id> [flags]` | Get a sandbox’s environment: selections, bindings and local entries. |
|
|
580
|
+
| `ghostdock sandboxes env select <sandbox-id> --environment <array> [flags]` | Replace the organization entries a sandbox exports. |
|
|
581
|
+
| `ghostdock sandboxes env set <name> --sandbox-id <string> --value <string> [flags]` | Create or replace one of a sandbox’s own variables or secrets. |
|
|
582
|
+
| `ghostdock sandboxes files list <sandbox-id> [flags]` | List the files in a sandbox directory (default /workspace). |
|
|
583
|
+
| `ghostdock sandboxes files read <path> --sandbox-id <string> [flags]` | Read a file from a sandbox: utf8 text, or base64 for small binaries. |
|
|
584
|
+
| `ghostdock sandboxes files upload <sandbox-id> [path] [flags]` | Upload local files or directories to a sandbox using multipart form data. |
|
|
585
|
+
| `ghostdock sandboxes list [flags]` | List the sandboxes of an organization, including whether each is ephemeral. |
|
|
586
|
+
| `ghostdock sandboxes mcps create <sandbox-id> --name <string> --port <integer> [flags]` | Expose an MCP server running in a sandbox. |
|
|
587
|
+
| `ghostdock sandboxes mcps delete <mcp-id>` | Delete an MCP endpoint of a sandbox. |
|
|
588
|
+
| `ghostdock sandboxes mcps list <sandbox-id> [flags]` | List the MCP endpoints a sandbox exposes (name, port, path, autoWake). |
|
|
589
|
+
| `ghostdock sandboxes mcps update <mcp-id> [flags]` | Change an MCP endpoint’s name, port, path or autoWake setting. |
|
|
590
|
+
| `ghostdock sandboxes resize <sandbox-id> [flags]` | Change a sandbox’s CPU and/or memory. |
|
|
591
|
+
| `ghostdock sandboxes resize-disk <sandbox-id> --disk-gib <number> [flags]` | Grow a sandbox’s disk. |
|
|
592
|
+
| `ghostdock sandboxes set-boot <sandbox-id> --command <string> [flags]` | Register a command that starts now and again after every restart. |
|
|
593
|
+
| `ghostdock sandboxes shells close <session-id> --sandbox-id <string> [flags]` | Close a shell session. |
|
|
594
|
+
| `ghostdock sandboxes shells create <sandbox-id> [flags]` | Open a shell session that keeps cwd and environment between commands. |
|
|
595
|
+
| `ghostdock sandboxes ssh get <sandbox-id> [flags]` | Get temporary SSH access to a sandbox (command and token, 60 minutes). |
|
|
596
|
+
| `ghostdock sandboxes ssh revoke <sandbox-id> [flags]` | Revoke a sandbox’s active SSH access. |
|
|
597
|
+
| `ghostdock sandboxes status <sandbox-id> [flags]` | Get a sandbox’s status and lifecycle deadlines without waking it. |
|
|
598
|
+
| `ghostdock sandboxes stop <sandbox-id> [flags]` | Stop a running sandbox without deleting its files. |
|
|
599
|
+
| `ghostdock sandboxes tools call <name> --sandbox-id <string> --arguments <object> [flags]` | Call a tool on an MCP server inside a sandbox. |
|
|
600
|
+
| `ghostdock sandboxes tools list <sandbox-id> [flags]` | List the tools of the MCP servers a sandbox exposes. |
|
|
601
|
+
| `ghostdock sandboxes update <sandbox-id> [flags]` | Change a sandbox’s display name, idle-stop or auto-delete interval. |
|
|
602
|
+
| `ghostdock sandboxes urls create <sandbox-id> --port <integer> [flags]` | Expose a sandbox port as a URL. |
|
|
603
|
+
| `ghostdock sandboxes urls delete <url-id>` | Delete a sandbox URL. |
|
|
604
|
+
| `ghostdock sandboxes urls list <sandbox-id> [flags]` | List the URLs that expose a sandbox’s ports, with protocol and access. |
|
|
605
|
+
| `ghostdock sandboxes urls update <url-id> [flags]` | Change a sandbox URL’s port, protocol, autoWake or public setting. |
|
|
606
|
+
| `ghostdock sandboxes wake <sandbox-id> [flags]` | Start a stopped sandbox, or reset the idle-stop countdown of a running one. |
|
|
607
|
+
|
|
608
|
+
#### sites
|
|
609
|
+
|
|
610
|
+
| Command | What it does |
|
|
611
|
+
| --- | --- |
|
|
612
|
+
| `ghostdock sites publish [path] [flags]` | Publish a local directory or ZIP to the CDN. |
|
|
613
|
+
| `ghostdock sites unpublish <site-id> [flags]` | Take a published static site offline. |
|
|
614
|
+
|
|
615
|
+
#### skills
|
|
616
|
+
|
|
617
|
+
| Command | What it does |
|
|
618
|
+
| --- | --- |
|
|
619
|
+
| `ghostdock skills get <uri>` | Print one SKILL.md (URI from the discovery index, or a skill name). |
|
|
620
|
+
| `ghostdock skills list` | List the Agent Skills discovery index. |
|
|
621
|
+
|
|
622
|
+
#### snapshots
|
|
623
|
+
|
|
624
|
+
| Command | What it does |
|
|
625
|
+
| --- | --- |
|
|
626
|
+
| `ghostdock snapshots create <sandbox-id> --name <string> [flags]` | Save a sandbox’s filesystem as a reusable organization snapshot. |
|
|
627
|
+
| `ghostdock snapshots delete <snapshot-id> [flags]` | Permanently delete an organization snapshot (provider artifact and record). |
|
|
628
|
+
| `ghostdock snapshots get <snapshot-id> [flags]` | Get one snapshot with its manifest and required environment, URLs and MCPs. |
|
|
629
|
+
| `ghostdock snapshots list [flags]` | List the snapshots an organization can boot sandboxes from. |
|
|
630
|
+
| `ghostdock snapshots update-manifest <snapshot-id> --manifest <object> [flags]` | Replace a snapshot’s manifest (URLs, environment, MCPs). |
|
|
631
|
+
|
|
632
|
+
#### tools
|
|
633
|
+
|
|
634
|
+
| Command | What it does |
|
|
635
|
+
| --- | --- |
|
|
636
|
+
| `ghostdock tools` | List available agent tools. |
|
|
637
|
+
|
|
638
|
+
#### whoami
|
|
639
|
+
|
|
640
|
+
| Command | What it does |
|
|
641
|
+
| --- | --- |
|
|
642
|
+
| `ghostdock whoami` | Show the account this CLI is currently authenticated as. |
|
|
643
|
+
<!-- generated:command-index:end -->
|
|
644
|
+
|
|
645
|
+
## CLI settings
|
|
646
|
+
|
|
647
|
+
Environment variables read by the CLI process itself. For an organization's environment variables
|
|
648
|
+
and secrets, see [`ghostdock env`](#ghostdock-env).
|
|
649
|
+
|
|
650
|
+
| Variable | Purpose | Default |
|
|
651
|
+
| ------------------------------- | ------------------------------------------------------------- | --------------------------------- |
|
|
652
|
+
| `GHOSTDOCK_BASE_URL` | API origin the CLI talks to. Override for local dev / self-hosted instances. | Local/dev builds default to `http://localhost:3000`. npm-published builds default to the production API origin baked at publish time. Override with `--base-url` or this env var. |
|
|
653
|
+
| `GHOSTDOCK_ORG` | Organization (id or slug) for commands run without `--org`. Takes precedence over the default from `organizations use`. | unset |
|
|
654
|
+
| `GHOSTDOCK_CREDENTIALS_PATH` | Absolute path to the credentials file, overriding the default. `settings.json` (the default organization) sits in the same directory. | `./.ghostdock/credentials.json` (relative to the current working directory) |
|
|
655
|
+
|
|
656
|
+
Example for local development against a Nuxt dev server:
|
|
657
|
+
|
|
658
|
+
```bash
|
|
659
|
+
ghostdock --base-url http://localhost:3000 login --wait
|
|
660
|
+
# or
|
|
661
|
+
GHOSTDOCK_BASE_URL=http://localhost:3000 ghostdock login --wait
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
## Credentials file
|
|
665
|
+
|
|
666
|
+
Credentials are stored as JSON at `./.ghostdock/credentials.json` (relative to the directory the
|
|
667
|
+
CLI is run from), with file permissions restricted to the owner (`0600`):
|
|
668
|
+
|
|
669
|
+
```json
|
|
670
|
+
{
|
|
671
|
+
"accessToken": "ext_at_...",
|
|
672
|
+
"refreshToken": "ext_rt_...",
|
|
673
|
+
"accessExpiresAt": "2026-07-30T12:00:00.000Z"
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
**Add `.ghostdock/` to your project's `.gitignore`.** These are live tokens — never commit them.
|
|
678
|
+
This repository's own `.gitignore` already ignores `.ghostdock/` for local development/testing of
|
|
679
|
+
the CLI itself.
|
|
680
|
+
|
|
681
|
+
Access tokens are short-lived (1 hour); the CLI refreshes them automatically using the refresh token
|
|
682
|
+
(30-day rolling expiry) whenever a request gets a `401`. If both tokens are invalid or revoked (e.g.
|
|
683
|
+
after `ghostdock logout` from another session), re-run `ghostdock login`.
|
|
684
|
+
|
|
685
|
+
## Exit codes
|
|
686
|
+
|
|
687
|
+
- `0` — success (including the default `login` after only printing the URL — approval is still
|
|
688
|
+
pending, that's expected).
|
|
689
|
+
- `1` — failure: not logged in, session expired and unrefreshable, login denied/expired/timed out,
|
|
690
|
+
a missing/invalid tool flag, or a tool invocation error (e.g. not a member of the organization).
|