pylot-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +133 -0
  2. package/dist/index.mjs +15799 -0
  3. package/package.json +46 -0
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # pylot — the Pylot gateway CLI
2
+
3
+ First-class CLI for the Pylot gateway API (epic #1802). Replaces every curl
4
+ workflow — dispatching missions, tailing logs, crew/admin/secrets management —
5
+ for both AI operators (`claude -p` sessions, subagents) and humans.
6
+
7
+ ```
8
+ pylot dispatch "fix the flaky gateway-cache test" --agent infra.lead --repo fellowship-dev/pylot --wait
9
+ pylot ps
10
+ pylot missions logs <job-id> --follow
11
+ pylot deploy --wait --env staging
12
+ ```
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm install -g pylot-cli
18
+ ```
19
+
20
+ Published on npm as [`pylot-cli`](https://www.npmjs.com/package/pylot-cli)
21
+ (Node 20+). The package ships a single self-contained bundle and **no
22
+ credentials**: it only talks to the gateway URL you configure, and every
23
+ request is authorized by a token your own gateway deployment mints. There is
24
+ no hosted signup or OAuth flow — if you don't hold a token for a gateway, the
25
+ CLI can't do anything ("closed by default"). Self-hosters: see
26
+ [SELF-HOSTING.md](../../SELF-HOSTING.md) for deploying a gateway and minting
27
+ the dispatch token.
28
+
29
+ Inside Pylot's own containers no install is needed — the operator image bakes
30
+ the bundle in at `/usr/local/bin/pylot`.
31
+
32
+ ## Design contract
33
+
34
+ - **JSON on non-TTY stdout** (or `--json`): exactly one JSON document per
35
+ command — the *verbatim* gateway response body — newline-terminated. All
36
+ progress notes, hints, and errors go to stderr. `pylot missions list | jq .`
37
+ always works. While following logs, entries stream as NDJSON.
38
+ - **Tables on TTY** for list commands; pretty-printed JSON otherwise.
39
+ - **Exit codes**: `0` success, `1` API/runtime error, `2` usage error.
40
+ `missions wait` / `dispatch --wait` exit `0` only when the mission ends `done`.
41
+ - **Destructive commands** (`kill`, `cancel`, `delete`, `revoke`, …) require
42
+ `--force` and send nothing without it.
43
+ - Single-file bundle (`dist/index.mjs`, esbuild) — no runtime `node_modules`.
44
+ Runtime deps are `commander` + `conf` only; no interactive/prompt libraries.
45
+
46
+ ## Configuration
47
+
48
+ Everything resolves from flags, then environment, then the config file
49
+ (`pylot config set …`, stored via `conf`; env vars always win).
50
+
51
+ | | resolution order |
52
+ |---|---|
53
+ | URL | `--url` → `PYLOT_DISPATCH_URL`¹ → `PYLOT_API_URL` → `PYLOT_GATEWAY_URL` → `PYLOT_API` → config file |
54
+ | Token | `--token` → `PYLOT_API_TOKEN` → `PYLOT_SESSION_JWT` → `PYLOT_BROKER_TOKEN` → `PYLOT_DISPATCH_TOKEN` → config file |
55
+
56
+ ¹ historically holds the full `…/dispatch` endpoint URL — the CLI strips the
57
+ suffix automatically.
58
+
59
+ `--env staging` switches to `PYLOT_STAGING_URL` + `PYLOT_STAGING_DISPATCH_TOKEN`
60
+ (config keys `staging-url` / `staging-token`).
61
+
62
+ Inside Pylot containers the right credential is already injected (token plane
63
+ #1884): chat sessions get a session JWT (`PYLOT_API_TOKEN`), mission workers a
64
+ broker JWT (`PYLOT_BROKER_TOKEN`, scoped to git-token + heartbeat — it cannot
65
+ dispatch), operators the master token. `pylot auth status` shows which source
66
+ won and what the gateway thinks of it. On a `403 insufficient_scope` the CLI
67
+ tells you which scope is missing and how to get it.
68
+
69
+ ## Command groups
70
+
71
+ Run `pylot --help` (or `pylot <group> --help`) for the full tree.
72
+
73
+ | Group | Covers |
74
+ |---|---|
75
+ | `health` `stats` `events` | liveness, metrics, event ledger |
76
+ | `dispatch` | POST /dispatch with `--wait` / `--follow` |
77
+ | `missions` (`ps`) | list/view/wait/logs/session/deps/audit/report/complete/heartbeat/wake/update/cancel/kill |
78
+ | `costs` `executor` `audits` `pricing` `logs` | cost reporting, executor sweeps, audit corpus, model pricing, infra logs |
79
+ | `workers` `devboxes` | devbox workers and standalone devboxes |
80
+ | `conversations` (`convo`) | full conversation surface: messages, wakes, subscriptions, resources, devboxes, analytics |
81
+ | `crew` `route` | team config, operator instructions, role skills, crons, ledger, playbooks, goals |
82
+ | `admin` | config, audit, org caps, migrations |
83
+ | `deploy` | POST /admin/deploy + CodeBuild polling (`--wait`), image builds |
84
+ | `secrets` | path-based ASM bundle/key operations |
85
+ | `skills` `automations` `providers` `orgs` `assets` | skills catalog/sync, automation rules, provider chains, repo enablement, asset presign/publish |
86
+ | `auth` `config` `login` | identity (`auth status`), scoped tokens, git tokens, local config |
87
+
88
+ Notes on log streaming: SSE endpoints return 501 on the deployed (Lambda)
89
+ gateway, so `missions logs --follow` polls
90
+ `GET /missions/:id/logs/cloudwatch?since_time=<cursor>` — including 206
91
+ partial-fetch draining — and stops when the mission goes terminal. Identical
92
+ boundary timestamps can rarely duplicate a line (CloudWatch ms resolution).
93
+
94
+ Deliberately not covered (internal plumbing): `POST /webhook`, `/internal/*`,
95
+ `POST /admin/skills/commit`, `POST /cost-report`, worker-daemon turn routes
96
+ (`workers/poll|heartbeat|report`), `/admin/worker-keys`, `/admin/test/*`.
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ cd modules/cli
102
+ npm ci
103
+ npm run typecheck # tsc --noEmit (strict)
104
+ npm run build # esbuild → dist/index.mjs (executable)
105
+ node dist/index.mjs --help
106
+ ```
107
+
108
+ Integration tests live at the repo root (`tests/gateway-cli-*.test.mts`) and
109
+ run in the corpus gate (`./scripts/test.sh corpus`): they spawn a real hermetic
110
+ gateway (PGlite) and execute the **built** CLI against it — no mocked fetch.
111
+ `scripts/test.sh` builds the bundle before the test pass.
112
+
113
+ The operator image bakes the bundle in as `/usr/local/bin/pylot`
114
+ (see `Dockerfile.operator`); rebuild via `/image-builder operator`.
115
+
116
+ ## Publishing to npm (maintainers)
117
+
118
+ The package is public on npm as `pylot-cli`. To cut a release:
119
+
120
+ 1. Bump `version` in `modules/cli/package.json` (semver — the bundle embeds it
121
+ via `__CLI_VERSION__`, so `pylot --version` reports whatever you publish).
122
+ 2. From `modules/cli/`: `npm publish --access public`. The `prepublishOnly`
123
+ hook runs the typecheck and a fresh build, and the `files` allowlist keeps
124
+ the tarball to `dist/index.mjs` + README only — no source, no lockfile.
125
+ 3. Publishing requires an npm token with publish rights on `pylot-cli` — use
126
+ an **Automation** token (or a granular token with 2FA bypass) in CI;
127
+ interactive publishes prompt for the account OTP.
128
+ 4. Verify: `npm view pylot-cli version` and
129
+ `npx -y pylot-cli@latest --version`.
130
+
131
+ Version discipline: any change to gateway routes that the CLI wraps should
132
+ land with a CLI bump in the same PR train, so the published CLI never lags
133
+ the deployed API surface.