fest-gateway 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -8,195 +8,112 @@ way they'd point at Bedrock, so one place can monitor requests, tokens and cost
8
8
  and route to different models without Claude Code knowing the difference.
9
9
 
10
10
  **The distinguishing goal: Claude Max / Team subscription support.** Each
11
- developer authenticates with their *own* subscription. Fest relays their own
11
+ developer authenticates with their *own* subscription. Fest relays that
12
12
  credential and never stores it. Per-user pass-through, never pooling.
13
13
 
14
- > **Status: feature complete for a team trial.** A real Claude Code session on a
15
- > Max subscription runs through Fest, is attributed to its developer, metered
16
- > into SQLite, and shown on a dashboard behind a login. Model routing and
17
- > substitution work and are visible. Phase 0 cleared both gates
18
- > ([results](docs/PHASE0-RESULTS.md)), and `npm run canary` re-checks them
19
- > against each new Claude Code release.
14
+ Three ways to read this, depending on what you want:
20
15
 
21
- ```bash
22
- docker compose run --rm fest admin create you@corp.test # password shown once
23
- docker compose up -d
24
- docker compose run --rm fest token create dev@corp.test laptop # shown once
25
- ```
16
+ | | |
17
+ | --- | --- |
18
+ | [**Use it**](#use-it) | Someone runs a Fest; you want Claude Code going through it. |
19
+ | [**Run it**](#run-it) | You are standing one up for a team. |
20
+ | [**How it works**](#how-it-works) | What it can see, what it keeps, and what will bite you. |
21
+ | [**Develop it**](#develop-it) | Changing Fest itself. |
26
22
 
27
- Each developer then points Claude Code at the printed URL:
23
+ ---
28
24
 
29
- ```bash
30
- env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
31
- ANTHROPIC_BASE_URL=http://fest.corp:8787/t/<token> claude
32
- ```
25
+ ## Use it
33
26
 
34
- Or, if the operator has configured Google/GitHub OAuth (see below), a developer
35
- can skip all of that and self-serve a token from their own machine:
27
+ Install the CLI. The package is `fest-gateway`; the command it installs is
28
+ `fest`, because plain `fest` was already taken on npm.
36
29
 
37
30
  ```bash
38
- npm install -g fest-gateway # the command it installs is `fest`
39
-
40
- fest login --server http://fest.corp:8787 # opens a browser, stores a token in ~/.fest
41
- fest claude # runs `claude`, env set up for you
42
- fest whoami # what's logged in, and whether it's still live
31
+ npm install -g fest-gateway
43
32
  ```
44
33
 
45
- The package is `fest-gateway` plain `fest` was already taken on npm — but the
46
- binary it installs is `fest`. Without installing anything, `npx fest-gateway
47
- login …` does the same job.
48
-
49
- From a clone of this repo the CLI runs straight off the TypeScript instead:
50
- `npm run cli -- login …` (note the `--`), or `node server/bin/fest.ts login …`.
51
-
52
- Or without Docker:
34
+ Sign in to your team's gateway, then start a session:
53
35
 
54
36
  ```bash
55
- node server/bin/fest.ts admin create you@corp.test
56
- node server/bin/fest.ts token create dev@corp.test laptop
57
- FEST_REQUIRE_IDENTITY=1 node server/bin/fest.ts serve
37
+ fest login --server https://fest.corp.test # opens a browser, stores a token in ~/.fest
38
+ fest claude # runs `claude`, environment set up for you
58
39
  ```
59
40
 
60
- ## Why this is possible
41
+ That's it. `fest claude` spawns the real `claude` binary with the environment
42
+ already pointed at the gateway, on **your own Anthropic subscription** — Fest
43
+ meters the usage and never sees your Anthropic credential at rest.
61
44
 
62
- Claude Code's inference client attaches the subscription OAuth bearer with **no
63
- host check** against `ANTHROPIC_BASE_URL`. Point it at Fest while logged in with
64
- Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both
65
- by reading the binary and by running it — see
66
- [docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
45
+ If your browser is already signed in to the dashboard, `fest login` is a single
46
+ approval click; otherwise it shows the gateway's login screen first.
67
47
 
68
- Token refresh happens client-side against `api.anthropic.com`, outside
69
- `ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
70
- refreshes or holds a subscription credential. That is a genuine security
71
- advantage over any "store the team's key" design, not just a side effect.
48
+ Other commands:
72
49
 
73
- ## Two things that will bite you
74
-
75
- **1. `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` silently kill the
76
- subscription.** Claude Code demotes off OAuth if *any* Anthropic-issued
77
- credential is present — including an `apiKeyHelper`. So Fest's identity token
78
- never goes in those variables; it rides in the URL path prefix or a custom
79
- header. A design that ignores this silently moves a whole team off their
80
- subscriptions onto a server-held key, and the failure is invisible.
81
-
82
- **2. This is supported-by-absence, not by design.** There is no *documented*
83
- path for relaying a subscription bearer through a third-party gateway. It works
84
- because no guard exists. Treat it as a version-pinned dependency, and settle the
85
- policy question with Anthropic before a team-wide rollout.
50
+ ```bash
51
+ fest whoami # what's logged in, and whether the token is still live
52
+ fest logout # forget the local token (does not revoke it server-side)
53
+ fest claude gw # force org credentials + the gateway's extra models
54
+ ```
86
55
 
87
- The version dependency is enforced rather than remembered: `npm run canary`
88
- re-runs both load-bearing Phase 0 experiments against the installed release and
89
- refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
90
- verdicts are recorded per version in `docs/canary-history.jsonl`.
56
+ Without installing anything, `npx fest-gateway login …` does the same job.
91
57
 
92
- Worth knowing: Anthropic ships its own self-hostable `claude gateway` (see
93
- `claude gateway --help`) with central metering, pricing and managed policies. It
94
- authenticates via OIDC and holds provider credentials itself, so it cannot do
95
- subscription pass-through — but if that requirement ever softens, it is the
96
- supported product.
58
+ ### If your operator hasn't set up OAuth
97
59
 
98
- ## Design commitments
60
+ They can mint you a token by hand instead, and you point Claude Code at it
61
+ directly:
99
62
 
100
- - **Byte-for-byte pass-through.** Subscription tokens are validated against
101
- request shape, so the body is relayed as opaque bytes — never parsed and
102
- re-serialised. No model rewriting or prompt shaping on that path.
103
- - **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
104
- caching and inflates every developer's token bill.
105
- - **Metadata only.** Token counts, models, latency, status — never prompt or
106
- completion content.
107
- - **No credential is persistable.** Not by policy, by construction: there is no
108
- store to put one in. Only fingerprints, enforced by tests.
109
-
110
- ## Layout
111
-
112
- ```
113
- server/bin/fest.ts CLI: serve | migrate | token | admin | seed |
114
- login | whoami | claude | logout
115
- server/pipeline/ passthrough (byte-for-byte) — the subscription path
116
- server/http/ sse parser, tee, header discipline, errors, routing
117
- server/store/ SQLite schema, write path, identity tokens
118
- server/usage/ accumulator, lean pricing, nullable cost algebra
119
- server/secret/ credential classification + redaction
120
- server/auth/oauth.ts Google/GitHub provider construction
121
- server/api/oauth.ts /api/auth/oauth/* and /api/auth/identity
122
- cli/ the developer half of the CLI — no DB access, ever.
123
- login (loopback OAuth flow) | whoami | claude | logout,
124
- and the ~/.fest config they share
125
- shared/types.ts the contracts both halves agree on
126
- shared/demotion-vars.ts env vars that silently kill subscription auth
127
- tools/capture-server.ts Phase 0 diagnostic (throwaway)
128
- docs/PHASE0.md the gating experiment runbook
129
- docs/CLI-AUTH.md OAuth setup and the fest login/whoami/claude flow
130
- test/ node --test
63
+ ```bash
64
+ env -u ANTHROPIC_API_KEY -u ANTHROPIC_AUTH_TOKEN \
65
+ ANTHROPIC_BASE_URL=https://fest.corp.test/t/<token> claude
131
66
  ```
132
67
 
133
- ## Accounting rules that are easy to get wrong
68
+ > **Never set `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` yourself.** Either
69
+ > one silently drops you off your own subscription onto whatever credential the
70
+ > server holds. `fest claude` clears them for you; the raw form above does it
71
+ > with `env -u`.
134
72
 
135
- - **The four token buckets are disjoint.** `input_tokens` excludes cache reads
136
- and cache writes; context size is the sum. Folding cache reads into input is
137
- an order-of-magnitude error on a cache-heavy agent workload — and Claude Code
138
- is one (a trivial `-p` call here showed ~16k cache reads and ~12k one-hour
139
- cache writes).
140
- - **`null` cost means unavailable, never zero.** A subscription request is real
141
- usage with *no org spend*; an unknown model is unpriced, not free. Rollups
142
- therefore carry a priced sum plus `unpriced_requests` and
143
- `subscription_requests` separately, so a total renders honestly as
144
- `$12.3456 (+3 n/a)`.
145
- - **For a subscription developer, quota is the scarce resource, not dollars.**
146
- Anthropic returns 5h/7d utilisation on every response, so that is what the
147
- dashboard shows rather than an invented dollar figure.
148
-
149
- ## What Fest can see, and what it keeps
73
+ ---
150
74
 
151
- This is a gateway every prompt a team writes passes through, so it is worth
152
- being exact about what that means rather than reassuring.
75
+ ## Run it
153
76
 
154
- **Fest sees everything, because it has to.** A request body arrives at this
155
- process in full: prompts, file contents you asked Claude about, tool results,
156
- the lot. That is unavoidable for anything sitting on the wire, and no wording
157
- changes it.
77
+ ### Getting started
158
78
 
159
- **Fest keeps none of it.** Request bodies are relayed as opaque bytes and never
160
- parsed for storage. What is written down is metadata: who, when, which model,
161
- how many tokens in each of the four buckets, latency, HTTP status, error type,
162
- and the session id Claude Code already sends. There is no column anywhere in
163
- the schema for prompt or completion text — not disabled, absent — so "turn off
164
- content capture" is not a setting that could be misconfigured.
79
+ An owner account must exist before Fest will serve on anything but loopback, so
80
+ that comes first:
165
81
 
166
- **No credential is persistable, by construction rather than by policy.** A
167
- subscription bearer is forwarded and forgotten; there is no table to put one in.
168
- What is stored of a Fest identity token or a dashboard password is a hash. The
169
- leak tests grep the entire database, every log line and every API response for
170
- secret-shaped strings.
82
+ ```bash
83
+ docker compose run --rm fest admin create you@corp.test # password shown once
84
+ docker compose up -d
85
+ ```
171
86
 
172
- **Raw per-request rows age out after 30 days**; the hourly rollups, which are
173
- aggregate, are kept for 400 so a year of trends does not require a year of
174
- per-developer detail.
87
+ Then either let developers self-serve with `fest login` (configure OAuth below),
88
+ or mint tokens for them:
175
89
 
176
- **An admin can see who used what, and when.** That is the point of a team
177
- gateway, and the developers pointing their editors at it should be told so
178
- plainly. They cannot see each other: a `member` account sees only its own
179
- traffic, enforced in the query layer rather than in the UI.
90
+ ```bash
91
+ docker compose run --rm fest token create dev@corp.test laptop # shown once
92
+ ```
180
93
 
181
- ## Deploying it
94
+ Put Fest behind your own TLS proxy and set `FEST_SECURE_COOKIES=1` when you do:
95
+ the server only ever sees plain HTTP and cannot detect this for itself.
182
96
 
183
- `docker compose up -d` after creating an owner account. The image has no runtime
184
- dependencies — Node runs the TypeScript directly — so it is Node plus this
185
- repository.
97
+ ### Accounts
186
98
 
187
- The dashboard needs a sign-in: scrypt passwords, an opaque session cookie
188
- hashed at rest, an origin check on the two endpoints that mutate anything, and
189
- an audit log of administrative actions. Accounts are granted from the host with
190
- `fest admin create`; there is no self-registration and no email reset, because a
191
- gateway should not need mail credentials to run.
99
+ The dashboard needs a sign-in: scrypt passwords, an opaque session cookie hashed
100
+ at rest, an origin check on every mutating endpoint, and an audit log of
101
+ administrative actions. Accounts are granted from the host with `fest admin
102
+ create` there is no self-registration and no email reset, because a gateway
103
+ should not need mail credentials to run.
192
104
 
193
105
  Before anyone has run `fest admin create`, Fest serves the dashboard **open on
194
106
  loopback and refuses to start on any other interface**. A single-developer trial
195
107
  needs no setup, and "bound it to 0.0.0.0 and forgot the password" cannot happen
196
108
  quietly.
197
109
 
198
- Put it behind your own TLS proxy and set `FEST_SECURE_COOKIES=1` when you do:
199
- the server only ever sees plain HTTP and cannot detect this for itself.
110
+ ```bash
111
+ docker compose run --rm fest admin create <email> [--role owner|admin|member]
112
+ docker compose run --rm fest admin list | admin passwd <email> | admin disable <email>
113
+ docker compose run --rm fest token list | token revoke <id>
114
+ ```
115
+
116
+ ### Configuration
200
117
 
201
118
  | | |
202
119
  | --- | --- |
@@ -204,29 +121,28 @@ the server only ever sees plain HTTP and cannot detect this for itself.
204
121
  | `FEST_DB`, `FEST_USAGE_LOG` | SQLite path, and the greppable JSONL trail. |
205
122
  | `FEST_REQUIRE_IDENTITY` | refuse unattributed requests. Off by default; **on** for a team. |
206
123
  | `FEST_SECURE_COOKIES` | set behind HTTPS. |
207
- | `FEST_ROUTES` | routing table path. Absent means everything passes through. |
124
+ | `FEST_ROUTES` | routing table path. Absent means everything passes through. See [docs/ROUTING.md](docs/ROUTING.md). |
208
125
  | `FEST_UPSTREAM_BASE_URL`, `FEST_LOG_LEVEL` | |
209
126
  | `FEST_PRICING_REFRESH` | set `0` to never fetch prices. Rates then come only from the vendored snapshot, which is always sufficient. |
210
127
  | `FEST_PRICING_URL` | internal mirror of litellm's price file. |
128
+ | `FEST_PUBLIC_URL` | base URL Fest is reachable at. Builds the OAuth redirect URI, and its path sets the mount point. Defaults to `http://<host>:<port>`. |
129
+ | `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
211
130
  | `FEST_GOOGLE_CLIENT_ID`, `FEST_GOOGLE_CLIENT_SECRET` | Google OAuth, for `fest login` and the dashboard. Absent means Google sign-in is off. |
212
131
  | `FEST_GITHUB_CLIENT_ID`, `FEST_GITHUB_CLIENT_SECRET` | GitHub OAuth, same idea. |
213
132
  | `FEST_ALLOWED_EMAIL_DOMAINS` | comma-separated. **Required to enable OAuth at all** — empty refuses every OAuth login rather than allowing any Google/GitHub account. |
214
- | `FEST_PUBLIC_URL` | base URL Fest is reachable at, for building the OAuth redirect URI. Defaults to `http://<host>:<port>`. |
215
- | `FEST_BASE_PATH` | mount path, if Fest is not at the root of its origin. Defaults to the path of `FEST_PUBLIC_URL`, so setting that is usually enough. |
133
+ | `FEST_DASHBOARD_URL` | **dev only.** Where the dashboard is when it isn't this server; `npm run dev` puts it on Vite's port. Leave unset in production. |
216
134
 
217
- See [docs/CLI-AUTH.md](docs/CLI-AUTH.md) for the full OAuth setup and how
218
- `fest login`'s loopback flow works.
135
+ For the full OAuth setup, see [docs/CLI-AUTH.md](docs/CLI-AUTH.md).
219
136
 
220
- ### Behind Caddy, on a path
137
+ ### Behind a reverse proxy, on a path
221
138
 
222
- Fest can be mounted under a path rather than on its own hostname
223
- `https://lastlight.nearform.dev/fest`. Set `FEST_PUBLIC_URL` to the full URL
224
- including that path and Fest takes the mount point from it: the dashboard's
225
- `<base href>` is rewritten to match, and the OAuth redirect URI is built
226
- against it.
139
+ Fest can be mounted under a path rather than on its own hostname. Set
140
+ `FEST_PUBLIC_URL` to the full URL including that path and Fest takes the mount
141
+ point from it: the dashboard's `<base href>` is rewritten to match, and the
142
+ OAuth redirect URI is built against it.
227
143
 
228
144
  ```caddyfile
229
- lastlight.nearform.dev {
145
+ fest.corp.test {
230
146
  handle_path /fest/* {
231
147
  reverse_proxy 127.0.0.1:8787 {
232
148
  # SSE: /api/live is a long-lived event stream, and a buffering
@@ -238,40 +154,172 @@ lastlight.nearform.dev {
238
154
  ```
239
155
 
240
156
  ```bash
241
- FEST_PUBLIC_URL=https://lastlight.nearform.dev/fest
157
+ FEST_PUBLIC_URL=https://fest.corp.test/fest
242
158
  FEST_SECURE_COOKIES=1
243
159
  ```
244
160
 
245
161
  `handle_path` strips the `/fest` prefix before proxying. A plain `handle` +
246
- `reverse_proxy`, which does not strip it, works too — Fest removes its own
247
- mount path from an incoming request when it is still there, so either spelling
248
- routes. Caddy passes the original `Host` upstream by default, which the CSRF
249
- origin check needs; on nginx that is `proxy_set_header Host $host`, and
162
+ `reverse_proxy`, which does not strip it, works too — Fest removes its own mount
163
+ path from an incoming request when it is still there, so either spelling routes.
164
+ Caddy passes the original `Host` upstream by default, which the CSRF origin
165
+ check needs; on nginx that is `proxy_set_header Host $host`, plus
250
166
  `proxy_buffering off` for the event stream.
251
167
 
252
168
  The registered OAuth redirect URI must include the path —
253
- `https://lastlight.nearform.dev/fest/api/auth/oauth/google/callback`. Developers
254
- point both Claude Code and the CLI at the full prefixed URL
255
- (`fest login --server https://lastlight.nearform.dev/fest`).
169
+ `https://fest.corp.test/fest/api/auth/oauth/google/callback`. Developers point
170
+ both Claude Code and the CLI at the full prefixed URL.
171
+
172
+ ---
173
+
174
+ ## How it works
175
+
176
+ ### Why this is possible
177
+
178
+ Claude Code's inference client attaches the subscription OAuth bearer with **no
179
+ host check** against `ANTHROPIC_BASE_URL`. Point it at Fest while logged in with
180
+ Max/Team and Fest receives `Authorization: Bearer sk-ant-oat…`. Confirmed both by
181
+ reading the binary and by running it — see
182
+ [docs/PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md).
183
+
184
+ Token refresh happens client-side against `api.anthropic.com`, outside
185
+ `ANTHROPIC_BASE_URL`. So Fest **forwards and forgets**: it never stores,
186
+ refreshes or holds a subscription credential. That is a genuine security
187
+ advantage over any "store the team's key" design, not a side effect.
188
+
189
+ ### Two things that will bite you
190
+
191
+ **1. `ANTHROPIC_API_KEY` and `ANTHROPIC_AUTH_TOKEN` silently kill the
192
+ subscription.** Claude Code demotes off OAuth if *any* Anthropic-issued
193
+ credential is present — including an `apiKeyHelper`. So Fest's identity token
194
+ never goes in those variables; it rides in the URL path prefix or a custom
195
+ header. A design that ignores this moves a whole team off their subscriptions
196
+ onto a server-held key, invisibly.
197
+
198
+ **2. This is supported-by-absence, not by design.** There is no *documented*
199
+ path for relaying a subscription bearer through a third-party gateway. It works
200
+ because no guard exists. Treat it as a version-pinned dependency, and settle the
201
+ policy question with Anthropic before a team-wide rollout.
202
+
203
+ That dependency is enforced rather than remembered: `npm run canary` re-runs both
204
+ load-bearing Phase 0 experiments against the installed Claude Code release and
205
+ refuses the rollout if either has changed. See [docs/CANARY.md](docs/CANARY.md);
206
+ verdicts are recorded per version in `docs/canary-history.jsonl`.
207
+
208
+ Worth knowing: Anthropic ships its own self-hostable `claude gateway` with
209
+ central metering, pricing and managed policies. It authenticates via OIDC and
210
+ holds provider credentials itself, so it cannot do subscription pass-through —
211
+ but if that requirement ever softens, it is the supported product.
212
+
213
+ ### What Fest can see, and what it keeps
214
+
215
+ This is a gateway every prompt a team writes passes through, so it is worth being
216
+ exact rather than reassuring.
217
+
218
+ **Fest sees everything, because it has to.** A request body arrives at this
219
+ process in full: prompts, file contents, tool results, the lot. That is
220
+ unavoidable for anything sitting on the wire.
221
+
222
+ **Fest keeps none of it.** Request bodies are relayed as opaque bytes and never
223
+ parsed for storage. What is written down is metadata: who, when, which model, how
224
+ many tokens in each of the four buckets, latency, HTTP status, error type, and
225
+ the session id Claude Code already sends. There is no column anywhere in the
226
+ schema for prompt or completion text — not disabled, *absent* — so "turn off
227
+ content capture" is not a setting that could be misconfigured.
228
+
229
+ **No credential is persistable, by construction rather than by policy.** A
230
+ subscription bearer is forwarded and forgotten; there is no table to put one in.
231
+ What is stored of a Fest identity token or a dashboard password is a hash. The
232
+ leak tests grep the entire database, every log line and every API response for
233
+ secret-shaped strings.
234
+
235
+ **An admin can see who used what, and when.** That is the point of a team
236
+ gateway, and developers pointing their editors at it should be told so plainly.
237
+ They cannot see each other: a `member` account sees only its own traffic,
238
+ enforced in the query layer rather than in the UI.
239
+
240
+ **Raw per-request rows age out after 30 days.** The hourly rollups, which are
241
+ aggregate, are kept for 400, so a year of trends does not require a year of
242
+ per-developer detail.
243
+
244
+ ### Design commitments
245
+
246
+ - **Byte-for-byte pass-through.** Subscription tokens are validated against
247
+ request shape, so the body is relayed as opaque bytes — never parsed and
248
+ re-serialised. No model rewriting or prompt shaping on that path.
249
+ - **`cache_control` forwarded verbatim.** Stripping it silently destroys prompt
250
+ caching and inflates every developer's token bill.
251
+ - **The four token buckets are disjoint.** `input_tokens` excludes cache reads
252
+ and cache writes; context size is the sum. Folding cache reads into input is an
253
+ order-of-magnitude error on a cache-heavy agent workload — and Claude Code is
254
+ one.
255
+ - **`null` cost means unavailable, never zero.** A subscription request is real
256
+ usage with *no org spend*; an unknown model is unpriced, not free. Totals
257
+ therefore render honestly as `$12.3456 (+3 n/a)`. See
258
+ [docs/PRICING.md](docs/PRICING.md).
259
+ - **For a subscription developer, quota is the scarce resource, not dollars.**
260
+ Anthropic returns 5h/7d utilisation on every response, so that is what the
261
+ dashboard shows rather than an invented dollar figure.
256
262
 
257
- ## Requirements
263
+ ---
258
264
 
259
- Node >= 22.18 (TypeScript runs directly via native type stripping — no build
260
- step for the server). Vite + React are used only for the dashboard, later.
265
+ ## Develop it
261
266
 
262
- ## Commands
267
+ Node >= 22.18. There is **no build step for the server** — Node runs the
268
+ TypeScript directly via native type stripping. Only the dashboard is built, and
269
+ only the published npm package is compiled (Node refuses to strip types under
270
+ `node_modules`).
263
271
 
264
272
  ```bash
265
- npm test # node --test
266
- npm run canary # version gate: re-run before rolling out a Claude Code release
267
- npm run capture # Phase 0 capture server
268
- npm run typecheck # tsc --noEmit (needs npm install first)
269
- npm run dev # gateway + dashboard with hot reload
270
- npm run demo # synthetic traffic in a scratch database, then both of the above
273
+ npm install
274
+ npm run dev # gateway (node --watch) + dashboard (Vite, HMR), one terminal
275
+ npm test # node --test
276
+ npm run typecheck # tsc --noEmit, root then web/
277
+ npm run demo # synthetic traffic in a scratch database, then dev
278
+ npm run canary # version gate: re-run before rolling out a Claude Code release
271
279
  ```
272
280
 
273
- ```bash
274
- node server/bin/fest.ts admin create <email> [--role R] [--password-stdin]
275
- node server/bin/fest.ts admin list | admin passwd <email> | admin disable <email>
276
- node server/bin/fest.ts token create <email> [name] | token list | token revoke <id>
281
+ Both `npm test` and `npm run typecheck` must be clean before committing. From a
282
+ clone the CLI runs straight off the TypeScript: `npm run cli -- login …` (note
283
+ the `--`).
284
+
285
+ ### Layout
286
+
287
+ ```
288
+ server/bin/fest.ts CLI entrypoint: serve | migrate | token | admin | seed |
289
+ login | whoami | claude | logout
290
+ server/pipeline/ passthrough (byte-for-byte) — the subscription path
291
+ server/http/ sse parser, tee, header discipline, errors, routing
292
+ server/store/ SQLite schema, write path, identity tokens
293
+ server/usage/ accumulator, pricing, nullable cost algebra
294
+ server/secret/ credential classification + redaction
295
+ server/auth/, server/api/ sessions, OAuth, the dashboard's JSON API
296
+ cli/ the developer half of the CLI — no DB access, ever
297
+ shared/ contracts both halves agree on, and the env vars that
298
+ silently kill subscription auth
299
+ web/ the dashboard (Vite + React) — the only build step
300
+ tools/ dev runner, canary, Phase 0 capture, price sync
301
+ test/ node --test, flat
277
302
  ```
303
+
304
+ There is one `CLAUDE.md` per top-level folder with the conventions that apply
305
+ inside it — read the relevant one before working there.
306
+
307
+ ### Docs
308
+
309
+ | | |
310
+ | --- | --- |
311
+ | [CLI-AUTH.md](docs/CLI-AUTH.md) | OAuth setup and the `fest login` flow end to end |
312
+ | [ROUTING.md](docs/ROUTING.md) | the routing table format and the substitute path |
313
+ | [PRICING.md](docs/PRICING.md) | where rates come from, and spend vs. value |
314
+ | [POSTURES.md](docs/POSTURES.md) | subscription vs. key posture |
315
+ | [CANARY.md](docs/CANARY.md) | the version-upgrade gate |
316
+ | [PHASE0.md](docs/PHASE0.md) · [PHASE0-RESULTS.md](docs/PHASE0-RESULTS.md) | the gating experiment, and what it found |
317
+ | [CLIENT-GATEWAY-PROTOCOL.md](docs/CLIENT-GATEWAY-PROTOCOL.md) | what Claude Code actually sends |
318
+ | [FRONTEND.md](docs/FRONTEND.md) | the dashboard's screens and data flow |
319
+
320
+ ### Releasing
321
+
322
+ Bump `version` in `package.json`, then publish a GitHub Release tagged
323
+ `v<version>`. CI publishes to npm over trusted publishing (OIDC) — there is no
324
+ token in the repository — and refuses to publish if the tag and `package.json`
325
+ disagree.
package/dist/cli/login.js CHANGED
@@ -100,8 +100,14 @@ export async function runLogin(opts) {
100
100
  });
101
101
  try {
102
102
  const callbackUrl = `http://127.0.0.1:${port}/callback`;
103
- const startUrl = `${serverUrl}/api/auth/oauth/${opts.provider}/start?cli_redirect_uri=${encodeURIComponent(callbackUrl)}`;
104
- process.stdout.write(`Opening your browser to sign in with ${opts.provider}...\n`);
103
+ // Not the provider's start URL directly. This asks the GATEWAY first, which
104
+ // can see the browser's session cookie where this process cannot: already
105
+ // signed in means one approval click instead of a provider round trip, and
106
+ // if there is no session it hands off to the dashboard's own login screen —
107
+ // which is why `--provider` is not passed here. It still records which
108
+ // provider was asked for in the stored config.
109
+ const startUrl = `${serverUrl}/api/auth/cli/authorize?cli_redirect_uri=${encodeURIComponent(callbackUrl)}`;
110
+ process.stdout.write("Opening your browser to authorise this CLI...\n");
105
111
  process.stdout.write(`If it doesn't open, visit:\n ${startUrl}\n`);
106
112
  (opts.openBrowser ?? open)(startUrl).catch(() => { });
107
113
  const timeout = new Promise((resolve) => {
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../cli/login.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import { originAllowed, clientIp, sessionFromRequest } from "../auth/guard.js";
11
11
  import { recordAudit } from "../store/audit.js";
12
12
  import { log } from "../log.js";
13
13
  import { handleOauth } from "./oauth.js";
14
+ import { handleCliAuth } from "./cli-auth.js";
14
15
  import { configuredProviders } from "../auth/oauth.js";
15
16
  const MAX_BODY_BYTES = 4 * 1024;
16
17
  function json(res, status, body, extra = {}) {
@@ -88,6 +89,11 @@ export async function handleAuth(req, res, path, deps, session) {
88
89
  if (await handleOauth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config })) {
89
90
  return true;
90
91
  }
92
+ // Before the method and origin gates below: `authorize` is a GET that renders
93
+ // a page, and `approve` applies both checks itself for its own reasons.
94
+ if (await handleCliAuth(req, res, path, { store: deps.store, orgId: deps.orgId, config: deps.config }, session)) {
95
+ return true;
96
+ }
91
97
  if (path === "/api/auth/me" && method === "GET") {
92
98
  json(res, 200, {
93
99
  // Not 401: "am I signed in" is a question an anonymous caller is allowed
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../server/api/auth.ts"],"names":[],"mappings":"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"}