@workerdeck/server 0.6.0 → 0.7.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
@@ -39,7 +39,8 @@ import { createWorkerServer } from '@workerdeck/server'
39
39
 
40
40
  const worker = createWorkerServer({
41
41
  authenticate: async (req) => verifyMyAppToken(req.headers.authorization),
42
- allowedCwdRoots: ['/srv/checkouts'], // clamp where sessions may run
42
+ allowedCwdRoots: ['/srv/checkouts'], // where sessions may run — and what /fs serves
43
+ hostFiles: { write: true }, // /fs reads follow the roots above; writing opts in
43
44
  buildRunnerConfig: (req) => ({ ...req, env: { ...process.env } }),
44
45
  requireApiKey: true, // fail closed on subscription credentials
45
46
  })
@@ -57,6 +58,9 @@ Routes (default `basePath: '/v1'`):
57
58
  | `POST /v1/sessions/:id/permissions/:requestId` | Resolve a pending approval over REST |
58
59
  | `GET /v1/sdk-sessions?dir=…` | List the Agent SDK's on-disk sessions to offer resume |
59
60
  | `GET /v1/sessions/:id/files`, `…/files/<path>` | List and download a session's scratch-filesystem deliverables |
61
+ | `GET /v1/fs/roots`, `/fs/list?path=`, `/fs/read?path=` | Browse and read the **host's** real tree (the `allowedCwdRoots` trees, unless `hostFiles.roots` narrows them; 404 when neither is set) |
62
+ | `GET /v1/fs/find?path=&q=` | Recursive fuzzy file search under one directory — what backs `@file` completion |
63
+ | `PUT /v1/fs/write` | Save a host file — needs `hostFiles.write`, and always carries the hash it replaces |
60
64
  | `POST /v1/executions/:executionId/result` | Deliver a deferred execution's result, waking a parked session |
61
65
  | `GET /v1/profiles`, `GET /v1/profiles/:name` | What sessions may run as (+ a view-only config snapshot) |
62
66
  | `GET/POST /v1/jobs`, `GET/DELETE /v1/jobs/:id` | Job queue (when `queue` is configured) |
package/build/index.d.mts CHANGED
@@ -327,6 +327,48 @@ type WorkerServerOptions = {
327
327
  /** Required unless `allowUnauthenticated: true` — the worker must never be exposed bare. */authenticate?: Authenticator; /** Explicit opt-in to run without auth (local dev only). */
328
328
  allowUnauthenticated?: boolean; /** If set, session cwd must resolve inside one of these roots. Strongly recommended. */
329
329
  allowedCwdRoots?: string[];
330
+ /**
331
+ * The host filesystem routes (`{basePath}/fs/*`) — browse and read the
332
+ * operator's real project tree, and optionally write to it.
333
+ *
334
+ * **Reading follows {@link allowedCwdRoots} and needs no grant of its own.**
335
+ * A caller holding the auth key can already start a session in any allowed root
336
+ * and have the agent read whatever is in it, so serving those same trees over
337
+ * `/fs` adds no authority — it only removes the absurdity of going through a
338
+ * language model to `cat` a file. Set `roots` here only to *narrow* that (or to
339
+ * expose a tree sessions may not run in).
340
+ *
341
+ * With neither set the routes 404. That is not the same as inheriting
342
+ * `allowedCwdRoots`' permissive "unset means anywhere": no cwd policy means
343
+ * there is nothing to inherit, and "anywhere" is a statement about paths the
344
+ * operator types at a keyboard, not one about what a phone may read.
345
+ *
346
+ * **Writing is a separate opt-in**, because it is the one part that is not
347
+ * already implied. An agent's writes go through the permission flow; a `PUT` to
348
+ * `/fs/write` does not. These routes are operator-privileged by design — the
349
+ * caller is the operator — but that is a reason to make the bypass deliberate,
350
+ * not a reason to skip the switch.
351
+ *
352
+ * Containment is *not* `cwdAllowed`, whichever roots are in play: these routes
353
+ * walk paths the agent may have authored, so a symlink can escape a lexical
354
+ * prefix check. See `host-files.ts` — canonicalize, then re-check.
355
+ */
356
+ hostFiles?: {
357
+ /** Absolute paths. Unset inherits {@link allowedCwdRoots}; an explicit empty
358
+ * array disables the routes (a policy, not an absence). */
359
+ roots?: string[]; /** Enable `PUT {basePath}/fs/write`. Default false — read-only. */
360
+ write?: boolean;
361
+ /** Refuse reads above this (413) rather than streaming a gigabyte to a phone.
362
+ * Default 1 MiB. Writes are bounded by {@link maxBodyBytes} instead. */
363
+ maxFileBytes?: number;
364
+ /** Cap on entries returned per directory (the response says `truncated`).
365
+ * Default 5000. */
366
+ maxEntries?: number;
367
+ /** Directory names `GET /fs/find` will not descend into. Defaults to
368
+ * `DEFAULT_IGNORED_DIRS` (`.git`, `node_modules`, build output…) — the thing
369
+ * that keeps a per-keystroke search cheap on a real source tree. */
370
+ ignore?: string[];
371
+ };
330
372
  /**
331
373
  * Named Claude Code config directories sessions can run under (each becomes the
332
374
  * session's CLAUDE_CONFIG_DIR — settings, memory, skills, and the credentials the