feat: Discard all, claude-style image pastes, large local drops, per-account / list
- Changes panel: **Discard all** beside Commit discards every non-conflicted file in one `discard`, after a dialog naming how many untracked files go. - Terminal: a `claude` pane gets dropped/pasted images as bare paths (shown as `[Image #n]`) and other files as `@` mentions (`claudePastes`); a local browser's copied `file://` paths and text-drag file lists paste by path. - `POST /api/run/drop-file`: a loopback browser outside server mode may drop up to 2 GB, streamed to disk; remote stays 20 MB. - cc-config skills/commands/plugins read the USER scope of the account the pane runs as (S3 member home by `cwd`), never another user's or the host's for a non-admin without an account; the run form passes its cwd to plugins.
This commit is contained in:
+3
-3
@@ -2787,7 +2787,7 @@ POST /api/cc-config/mcp/add Body: { name, scope, transport?, url?,
|
||||
POST /api/cc-config/mcp/remove Body: { name, scope? }
|
||||
```
|
||||
|
||||
The list reads take an optional `cwd` naming the project whose `.claude/` is read (default: the server's own cwd); the run console's `/` autocomplete passes the directory the run will start in, so a workspace's own project commands and skills are the ones offered. In server mode a non-admin's `cwd` (on `/api/cc-config/*` and `/api/codex-config/*`) must lie inside one of their own workspaces, else `403 EFOLDER`. `GET /api/cc-config/file` and `GET /api/codex-config/file` never serve a credential file (`.credentials.json`, `auth.json`, any non-Markdown name matching the AI Tools secret pattern, anything under `<CLAUDE_HOME>/agenthub-*`): `400 READ_DENIED`.
|
||||
The list reads take an optional `cwd` naming the project whose `.claude/` is read (default: the server's own cwd); the run console's `/` autocomplete passes the directory the run will start in, so a workspace's own project commands and skills are the ones offered. `skills`, `commands` and `plugins` read their USER scope from the account the pane will run as: under S3 the `cwd` folder's account (a member's `~/.claude`, where a Hub install puts a skill), a non-admin with no `cwd` their own, an admin otherwise the host's Claude home, and a non-admin with no account of their own NOTHING (never the host's or another member's) — so a skill a developer installed shows up in their `/` list, and an admin's install into the host's home no longer shows up in a member's. In server mode a non-admin's `cwd` (on `/api/cc-config/*` and `/api/codex-config/*`) must lie inside one of their own workspaces, else `403 EFOLDER`. `GET /api/cc-config/file` and `GET /api/codex-config/file` never serve a credential file (`.credentials.json`, `auth.json`, any non-Markdown name matching the AI Tools secret pattern, anything under `<CLAUDE_HOME>/agenthub-*`): `400 READ_DENIED`.
|
||||
|
||||
`scope` is `"user"`, `"project"`, or `"auto-memory"`. `type` is one of `skills`, `agents`, `commands`, `output-styles`, `memory`, `auto-memory`. `name` is required for everything except `memory` (which is `CLAUDE.md` itself). On `PUT`, `name` is validated against `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$` (for `auto-memory` it must instead be a flat `*.md` filename). Settings are returned with secret-like keys (matching `/token|secret|password|api[_-]?key|auth/i`) replaced by `"<redacted>"`.
|
||||
|
||||
@@ -2884,8 +2884,8 @@ GET /api/run/history?limit=&laneId=&tool= Persisted run history; laneId narr
|
||||
GET /api/run/interrupted {items} — sessions whose pane died under them (see below), newest per session, max 50
|
||||
POST /api/run/interrupted/dismiss {sessionIds: string[]} (≤ 100) → {dismissed}: stop offering them; resumes nothing. 400 EBADFIELD otherwise
|
||||
GET /api/run/files?cwd=&q=&dirs=1 Fuzzy file search inside cwd for the @-file autocomplete (dirs=1 adds folders as `dir/`, for the + menu)
|
||||
POST /api/run/drop-image Raw image body (png/jpeg/gif/webp, ≤20 MB) → {path}: saved 0600 under <data dir>/drops/ (0700; S3: the member's ~/.agenthub/handoff/drops/) with a random name, pruned after a day; the terminal pastes the path
|
||||
POST /api/run/drop-file?name=&laneId= Any raw file body (≤20 MB) → {path}: same dir (S3: the handoff dir of the account workspace `laneId`'s panes run as, else the requester's), 0600, named <random>-<name reduced to a [A-Za-z0-9._-] basename>; what the terminal (drop or paste, Ctrl+V included), the prompt box and its paste use for every dropped file or image — except a browser on a loopback host dropping or pasting a file manager's files, whose `file://` paths are attached as they are, uploading nothing, once `POST /api/run/local-paths` finds the same files here. Both drop routes answer 413 `ETOOBIG` (with `max_bytes`, the limit the UI shows) to a `Content-Length` over 20 MB before reading the body, and close the connection; of several files only the refused ones are lost
|
||||
POST /api/run/drop-image Raw image body (png/jpeg/gif/webp, ≤20 MB) → {path}: saved 0600 under <data dir>/drops/ (0700; S3: the member's ~/.agenthub/handoff/drops/) with a random name, pruned after a day; the terminal pastes the path (a `claude` pane: an image as its bare path, each in a paste of its own, which Claude Code shows as `[Image #n]`; any other file as an `@` mention)
|
||||
POST /api/run/drop-file?name=&laneId= Any raw file body (≤20 MB; ≤2 GB from a loopback browser outside server mode, streamed to disk — Chrome hands a dropped file no `file://` path) → {path}: same dir (S3: the handoff dir of the account workspace `laneId`'s panes run as, else the requester's), 0600, named <random>-<name reduced to a [A-Za-z0-9._-] basename>; what the terminal (drop or paste, Ctrl+V included), the prompt box and its paste use for every dropped file or image — except a browser on a loopback host dropping or pasting a file manager's files, whose `file://` paths are attached as they are, uploading nothing, once `POST /api/run/local-paths` finds the same files here. Both drop routes answer 413 `ETOOBIG` (with `max_bytes`, the limit the UI shows) to a `Content-Length` over their limit before reading the body, and close the connection; of several files only the refused ones are lost
|
||||
POST /api/run/local-paths {paths:[<absolute>…]} (1–100) → {sizes:[bytes|null…]}: each path's size when it is a regular file on this machine, else null. The composer and the terminal use a dropped file's own `file://` path only when every size matches the dropped bytes' — "localhost" in the address bar is no proof (an SSH tunnel's browser is on another machine). 403 EREMOTE in server mode (a pane runs as an account that cannot read the host's files) and to anything but a loopback socket without X-Forwarded-For/Forwarded; 400 EBADFIELD otherwise
|
||||
GET /api/run/drop/:name A dropped png/jpg/gif/webp, or txt/md/csv/tsv/log/json/xml/yaml as text/plain, served back (nosniff, sandbox CSP) from the requester's own drop dir (S3: their member account's, owner-checked — for an admin, then the host's, where their host-folder workspaces drop); only a name drop-image/drop-file made → 404 otherwise
|
||||
GET /api/run/:id/permission-mode A live claude pane's mode, read off its mode line → {mode} (null while a menu hides it)
|
||||
|
||||
Reference in New Issue
Block a user