From 0bf552b793771c25ef25d134dc5503cd9d70aa26 Mon Sep 17 00:00:00 2001 From: nntrivi2001 Date: Fri, 6 Nov 2026 10:43:16 +0700 Subject: [PATCH] chore(openapi): regenerate openapi.yaml (stale since 11-02) --- openapi.yaml | 1096 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1048 insertions(+), 48 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index 5f2d69b9..26bbd764 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3,7 +3,7 @@ openapi: 3.0.3 info: title: Agent Dashboard for Claude Code API - version: 2.8.51 + version: 2.8.77 description: HTTP API for real-time Claude Code session monitoring, agent lifecycle tracking, analytics, pricing, hooks ingestion, and workflow intelligence. contact: name: Nguyễn Ngọc Trí Vĩ @@ -90,6 +90,8 @@ tags: description: The mascot's custom pets (uploads and fixed featured ids) - name: Query description: 'Query Explorer: filtered, sorted pages and exports' + - name: Remote clients + description: 'Company hub ↔ local AgentHub. On the hub (server mode): a machine enrolls with its user''s password and gets ONE device token (shown once, 90 days, revocable); it registers each Company-account session at start (id + folder, no content) and uploads the new lines of its transcripts hourly. Its Claude Code reaches Anthropic only through `/api/remote/gw/v1/*`, which checks the device token and the registered session id (`x-claude-code-session-id`), swaps in a pool account''s OAuth token and relays the answer — the pool credential never leaves the hub. On a local install, `/api/remote-client` shows and manages this machine''s enrollment; the device token is never returned.' components: parameters: SessionIdPath: @@ -4956,6 +4958,19 @@ components: sharedAt: type: string nullable: true + sharedWith: + type: array + items: + type: object + properties: + id: + type: integer + name: + type: string + description: The people it is shared with by name — listed only to its owner or an admin, else empty. + sharedWithMe: + type: boolean + description: Shared with the caller by name. installs: type: integer createdAt: @@ -5151,6 +5166,79 @@ components: type: boolean enum: - true + RemoteDevice: + type: object + description: An enrolled machine. Never carries its token or token hash. + properties: + id: + type: integer + userId: + type: integer + name: + type: string + createdAt: + type: string + format: date-time + expiresAt: + type: string + format: date-time + lastSeenAt: + type: string + format: date-time + nullable: true + lastIp: + type: string + nullable: true + revokedAt: + type: string + format: date-time + nullable: true + active: + type: boolean + RemoteUploadFile: + type: object + required: + - path + - from + - to + - data + properties: + path: + type: string + description: '`.jsonl` or `/subagents/agent-.jsonl` — nothing else.' + from: + type: integer + description: Local byte offset this chunk starts at; must equal the hub's `consumed`. + to: + type: integer + description: Local byte offset after the chunk. + data: + type: string + description: Whole JSONL lines, secret-shaped strings already replaced. + RemoteClientStatus: + type: object + properties: + enrolled: + type: boolean + expired: + type: boolean + hub: + type: string + user: + type: object + nullable: true + device: + $ref: '#/components/schemas/RemoteDevice' + enrolledAt: + type: string + nullable: true + retainDays: + type: integer + nullable: true + uploads: + type: array + items: + type: object paths: /api/health: get: @@ -5200,6 +5288,14 @@ paths: - '1' description: '`1` = only sessions blocked on the user (`awaiting_input_since IS NOT NULL AND status = ''active''`), the UI''s Waiting filter. Applied before `limit`/`offset`, so `total` stays exact.' example: '1' + - name: mine + in: query + schema: + type: string + enum: + - '1' + description: 'Server mode: `1` = only the caller''s OWN sessions, even for an admin or analyst (the pet''s count). No-op in local mode.' + example: '1' - name: from in: query schema: @@ -12424,7 +12520,7 @@ paths: tags: - Lanes summary: One git write on the lane's working copy - description: 'fetch (--all --prune), pull (ALWAYS --ff-only — a diverged branch is reported, never merged), push (-u HEAD, so only the branch the lane is on; remote = the branch''s upstream remote, else the only remote, else origin, else 400 ENOREMOTE), stage/unstage (per file; staging a conflicted file that still has conflict markers is 400 EMARKERS), discard (per file; irreversible, so it REQUIRES confirm:true), stage-hunk / discard-hunk (ONE hunk of a tracked file''s `git diff HEAD`, named by its `@@` line and re-read server-side at the given context — the applied patch is always git''s own text, never one from the request; discard-hunk REQUIRES confirm:true; 400 EUNTRACKED for an untracked file, 409 EHUNKGONE when the hunk is no longer in the diff), commit (git add -A then commit -m , or only:"staged" to take the index as it stands), switch (git switch, -c to create; refuses a dirty tree (400 EDIRTY) unless changes names what happens to the changes: "carry" = a plain git switch that brings them along, 409 ECARRYCONFLICT with files:[...] when git would overwrite one; "shelve" = shelve them first, then switch, and the shelf is restored at once if the switch fails. Never --force/--merge/--discard-changes. A successful switch answers shelves:[...] — the TARGET branch''s shelves — and shelved:{...} when it made one), branch-create / branch-delete (create never switches unless switch:true, which runs git switch -c [] and carries the uncommitted changes; delete is `git branch -d`, refuses main/master/development/develop, the current branch and one held by another worktree), publish (the ONE write whose destination comes from the request: `git remote add origin -- ` then `git push -u origin HEAD`, only in a repo with a commit and NO remote — it never re-points one; the url must be https:// without userinfo, ssh:// or scp-like user@host:path, and origin is removed again if the push fails), and merge / resolve / merge-commit / merge-abort (issue #45: merge a local or remote-tracking branch that exists — clean tree and a repo-root lane only, 400 ESUBDIR otherwise — answering conflicts:[paths] when it stops on conflicts; resolve {path, side: ours|theirs|done} a conflicted path, done refusing leftover markers with 400 EMARKERS; merge-commit is 409 ECONFLICTS while anything is unmerged; merge-abort REQUIRES confirm:true; pull/switch/merge/hunk actions are 409 EMERGING mid-merge). fetch/pull/push/publish needing a login answer 409 EGITAUTH with auth:{protocol,host,username,rejected}; resend with credentials:{protocol,host,username,password,remember} (a repo remote''s host only, else 400 EBADHOST). A path in the body must be one `git status` is reporting as changed, so no path outside the lane is reachable. Guarded and serialized per git index (the lane lock keyed on the worktree''s git dir, so two lanes sharing one index cannot collide on index.lock). shelve {note?, paths?} (git stash push --include-untracked of everything or of the ticked changed paths, under an `agenthub-shelf: · · ` message; 400 ENOCHANGES on a clean tree), unshelve {sha} (git stash apply --index, retried without --index when only the index cannot be rebuilt; refuses a dirty tree, 400 EDIRTY; a clean apply drops the entry, a conflicted one keeps it and answers conflicts:[...] with kept:true — resolve them with resolve), shelf-drop {sha, confirm:true} (irreversible, REQUIRES confirm:true). Shelves are repo-wide: repo-root lane only (400 ESUBDIR), 409 EMERGING mid-merge/cherry-pick/revert/rebase, 409 ENOSHELF for a sha no AgentHub shelf has. When an agent of the lane is working, shelve, unshelve and a switch moving uncommitted changes answer 409 EAGENTRUNNING until resent with confirm:true. History rewrites and remote writes (server/lib/git-rewrite.js; repo-root lane only — ESUBDIR —, never during another operation — EMERGING —, and naming the HEAD the plan showed — head, else 409 ESTALE): rebase {onto, head, force?} (a looked-up branch, clean tree; commits a remote-tracking branch already holds are 409 EPUSHED unless force:true; stops answer conflicts:[…], stopped:true); rebase-continue (409 ECONFLICTS while unmerged), rebase-skip, rebase-abort {confirm:true} — merge-commit / merge-abort do the same while a rebase is open, and every other write except fetch, stage, unstage, discard, ignore, resolve and conflict-save is 409 EMERGING during one; rebase-interactive {head, base?, todo:[{sha, action: pick|reword|squash|fixup|drop, message?}], force?, confirm:true} (the todo must list exactly the commits of base..HEAD, full shas, no merge commit — 400 EBADTODO / EMERGECOMMIT; run with no editor: todo and messages are files in the repo''s own git dir); reset {target, mode: soft|mixed|keep|hard, head, confirm:true, force?, confirmBranch?} (target an ancestor or descendant of HEAD, else 400 ENOTRELATED; hard only on a clean tree — EDIRTY — and with confirmBranch = the current branch name); undo-rewrite {to, head, confirm:true} (`reset --keep `; every rewrite answers before/after for it); force-push {expect, confirm:true} (HEAD to its upstream branch with --force-with-lease=:; 409 ESTALE when the remote moved; main/master/development/develop are 400 EPROTECTED unless the server sets AGENTHUB_GIT_FORCE_PUSH_PROTECTED=1); remote-branch-delete {branch:"origin/x", confirm:true} (a fetched remote branch, never protected — EPROTECTED — nor the remote''s default — EDEFAULTBRANCH); remote-add {name, url} (url through publish''s allowlist, 400 EBADURL; name 400 EBADREMOTE; 400 EREMOTEEXISTS), remote-rename {name, to}, remote-remove {name, confirm:true}; conflict-save {path, content, baseSha, resolve?} (the 3-way merge editor''s result written through PUT /git/file''s guards — 409 ESTALE, 403 ESECRET — then staged; a result with a marker left is 400 EMARKERS before anything is written unless resolve:false). Network actions are killed after 60s. Branch & tag tools (server/lib/git-refs.js; every ref named in the body is LOOKED UP in refs/heads, refs/remotes or refs/tags — or a hex sha verified as a commit — and git gets the full refname, never the request''s text; every write here except branch-create runs only from a repo-root lane (400 ESUBDIR) and never while a merge, cherry-pick, revert or rebase is open (409 EMERGING)): branch-create also takes {from} (a local/remote branch, a tag, or a commit sha; 400 EBADREF, 400 EAMBIGUOUS when a branch and a tag share the name — spell out refs/tags/x) and {switch:true} (clean tree only, 400 EDIRTY); branch-rename {branch, name} (`git branch -m`; refuses main/master/development/develop 400 EPROTECTED, an existing name 400 EBRANCHEXISTS, a name `check-ref-format --branch` rejects 400 EBADBRANCH); branch-upstream {branch, upstream} sets it to a fetched remote branch (`origin/x`, 400 ENOBRANCH otherwise) and {branch} with no upstream unsets it (400 ENOUPSTREAM when none); tag-create {tag, message?, from?} (annotated when a message is given; on HEAD or a looked-up start point; 400 EBADTAG / ETAGEXISTS / ENOCOMMITS); tag-delete {tag, confirm:true} (irreversible: 400 ECONFIRM without it, 400 ENOTAG); tag-push {tag, credentials?} pushes ONE tag `refs/tags/:refs/tags/` to origin (else the only remote, 400 ENOREMOTE) — no --tags, no force, so a remote tag at another commit is a 409 in git''s words.' + description: 'fetch (--all --prune), pull (ALWAYS --ff-only — a diverged branch is reported, never merged), push (-u HEAD, so only the branch the lane is on; remote = the branch''s upstream remote, else the only remote, else origin, else 400 ENOREMOTE), stage/unstage (per file; staging a conflicted file that still has conflict markers is 400 EMARKERS), discard (per file; irreversible, so it REQUIRES confirm:true), stage-hunk / discard-hunk (ONE hunk of a tracked file''s `git diff HEAD`, named by its `@@` line and re-read server-side at the given context — the applied patch is always git''s own text, never one from the request; discard-hunk REQUIRES confirm:true; 400 EUNTRACKED for an untracked file, 409 EHUNKGONE when the hunk is no longer in the diff), commit (git add -A then commit -m , or only:"staged" to take the index as it stands), switch (git switch, -c to create; refuses a dirty tree (400 EDIRTY) unless changes names what happens to the changes: "carry" = a plain git switch that brings them along, 409 ECARRYCONFLICT with files:[...] when git would overwrite one; "shelve" = shelve them first, then switch, and the shelf is restored at once if the switch fails. Never --force/--merge/--discard-changes. A successful switch answers shelves:[...] — the TARGET branch''s shelves — and shelved:{...} when it made one), branch-create / branch-delete (create never switches unless switch:true, which runs git switch -c [] and carries the uncommitted changes; delete is `git branch -d`, refuses main/master/development/develop, the current branch and one held by another worktree), publish (the ONE write whose destination comes from the request: `git remote add origin -- ` then `git push -u origin HEAD`, only in a repo with a commit and NO remote — it never re-points one; the url must be https:// without userinfo, ssh:// or scp-like user@host:path, and origin is removed again if the push fails), and merge / resolve / merge-commit / merge-abort (issue #45: merge a local or remote-tracking branch that exists — clean tree and a repo-root lane only, 400 ESUBDIR otherwise — answering conflicts:[paths] when it stops on conflicts; resolve {path, side: ours|theirs|done} a conflicted path, done refusing leftover markers with 400 EMARKERS; merge-commit is 409 ECONFLICTS while anything is unmerged; merge-abort REQUIRES confirm:true; pull/switch/merge/hunk actions are 409 EMERGING mid-merge). fetch/pull/push/publish needing a login answer 409 EGITAUTH with auth:{protocol,host,username,rejected}; resend with credentials:{protocol,host,username,password,remember} (a repo remote''s host only, else 400 EBADHOST). A path in the body must be one `git status` is reporting as changed, so no path outside the lane is reachable. Guarded and serialized per git index (the lane lock keyed on the worktree''s git dir, so two lanes sharing one index cannot collide on index.lock). shelve {note?, paths?} (git stash push --include-untracked of everything or of the ticked changed paths, under an `agenthub-shelf: · · ` message; 400 ENOCHANGES on a clean tree), unshelve {sha} (git stash apply --index, retried without --index when only the index cannot be rebuilt; refuses while anything is staged or one of the shelf''s own files changed, 400 EDIRTY with paths:[...] — changes in other files stay; a clean apply drops the entry, a conflicted one keeps it and answers conflicts:[...] with kept:true — resolve them with resolve), shelf-drop {sha, confirm:true} (irreversible, REQUIRES confirm:true). Shelves are repo-wide: repo-root lane only (400 ESUBDIR), 409 EMERGING mid-merge/cherry-pick/revert/rebase, 409 ENOSHELF for a sha no AgentHub shelf has. When an agent of the lane is working, shelve, unshelve and a switch moving uncommitted changes answer 409 EAGENTRUNNING until resent with confirm:true. History rewrites and remote writes (server/lib/git-rewrite.js; repo-root lane only — ESUBDIR —, never during another operation — EMERGING —, and naming the HEAD the plan showed — head, else 409 ESTALE): rebase {onto, head, force?} (a looked-up branch, clean tree; commits a remote-tracking branch already holds are 409 EPUSHED unless force:true; stops answer conflicts:[…], stopped:true); rebase-continue (409 ECONFLICTS while unmerged), rebase-skip, rebase-abort {confirm:true} — merge-commit / merge-abort do the same while a rebase is open, and every other write except fetch, stage, unstage, discard, ignore, resolve and conflict-save is 409 EMERGING during one; rebase-interactive {head, base?, todo:[{sha, action: pick|reword|squash|fixup|drop, message?}], force?, confirm:true} (the todo must list exactly the commits of base..HEAD, full shas, no merge commit — 400 EBADTODO / EMERGECOMMIT; run with no editor: todo and messages are files in the repo''s own git dir); reset {target, mode: soft|mixed|keep|hard, head, confirm:true, force?, confirmBranch?} (target an ancestor or descendant of HEAD, else 400 ENOTRELATED; hard only on a clean tree — EDIRTY — and with confirmBranch = the current branch name); undo-rewrite {to, head, confirm:true} (`reset --keep `; every rewrite answers before/after for it); force-push {expect, confirm:true} (HEAD to its upstream branch with --force-with-lease=:; 409 ESTALE when the remote moved; main/master/development/develop are 400 EPROTECTED unless the server sets AGENTHUB_GIT_FORCE_PUSH_PROTECTED=1); remote-branch-delete {branch:"origin/x", confirm:true} (a fetched remote branch, never protected — EPROTECTED — nor the remote''s default — EDEFAULTBRANCH); remote-add {name, url} (url through publish''s allowlist, 400 EBADURL; name 400 EBADREMOTE; 400 EREMOTEEXISTS), remote-rename {name, to}, remote-remove {name, confirm:true}; conflict-save {path, content, baseSha, resolve?} (the 3-way merge editor''s result written through PUT /git/file''s guards — 409 ESTALE, 403 ESECRET — then staged; a result with a marker left is 400 EMARKERS before anything is written unless resolve:false). Network actions are killed after 60s. Branch & tag tools (server/lib/git-refs.js; every ref named in the body is LOOKED UP in refs/heads, refs/remotes or refs/tags — or a hex sha verified as a commit — and git gets the full refname, never the request''s text; every write here except branch-create runs only from a repo-root lane (400 ESUBDIR) and never while a merge, cherry-pick, revert or rebase is open (409 EMERGING)): branch-create also takes {from} (a local/remote branch, a tag, or a commit sha; 400 EBADREF, 400 EAMBIGUOUS when a branch and a tag share the name — spell out refs/tags/x) and {switch:true} (clean tree only, 400 EDIRTY); branch-rename {branch, name} (`git branch -m`; refuses main/master/development/develop 400 EPROTECTED, an existing name 400 EBRANCHEXISTS, a name `check-ref-format --branch` rejects 400 EBADBRANCH); branch-upstream {branch, upstream} sets it to a fetched remote branch (`origin/x`, 400 ENOBRANCH otherwise) and {branch} with no upstream unsets it (400 ENOUPSTREAM when none); tag-create {tag, message?, from?} (annotated when a message is given; on HEAD or a looked-up start point; 400 EBADTAG / ETAGEXISTS / ENOCOMMITS); tag-delete {tag, confirm:true} (irreversible: 400 ECONFIRM without it, 400 ENOTAG); tag-push {tag, credentials?} pushes ONE tag `refs/tags/:refs/tags/` to origin (else the only remote, 400 ENOREMOTE) — no --tags, no force, so a remote tag at another commit is a 409 in git''s words.' operationId: runLaneGitAction parameters: - name: id @@ -13199,6 +13295,42 @@ paths: description: Not an admin '409': description: ENOS3 — not server mode with per-user accounts + /api/ai-tools/member-policy: + get: + tags: + - AI Tools + summary: What members' Claude may run on this server + description: 'Server mode with per-user accounts (S3): whether members'' Claude may run test runners and container commands (`allowTests`, off by default). Kept in `/opt/agenthub/app/member-policy.json` and enforced by the members'' synchronous PreToolUse hook (scripts/member-guard.js).' + operationId: aiToolsMemberPolicy + responses: + '200': + description: '`{available, allowTests}`.' + put: + tags: + - AI Tools + summary: Allow or block members' test runs + description: An admin's switch. Takes effect at the next Bash call of every member's Claude, no restart. Same-origin only; audited. + operationId: aiToolsSetMemberPolicy + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - allowTests + properties: + allowTests: + type: boolean + responses: + '200': + description: The new state, as GET. + '400': + description: EBADFIELD + '403': + description: Not an admin + '409': + description: ENOS3 — not server mode with per-user accounts /api/ai-tools/{id}: put: tags: @@ -15792,7 +15924,7 @@ paths: tags: - Auth operationId: getUserAvatar - summary: One account's picture, for the sidebar's owner groups (admin/analyst) + summary: One account's picture, for owner groups and System Health (every signed-in account) parameters: - name: id in: path @@ -15804,12 +15936,6 @@ paths: description: The image (PNG, JPEG, GIF or WebP) '302': description: Redirect to that account's avatar link - '403': - description: EADMIN — a developer - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' '404': description: ENOAVATAR content: @@ -16920,7 +17046,7 @@ paths: tags: - Files summary: List a folder (folders first) - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsList parameters: - name: id @@ -16945,7 +17071,7 @@ paths: tags: - Files summary: Make a folder - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsMkdir parameters: - name: id @@ -16972,7 +17098,7 @@ paths: tags: - Files summary: Make an empty file - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsNewfile parameters: - name: id @@ -16999,7 +17125,7 @@ paths: tags: - Files summary: Rename in place - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsRename parameters: - name: id @@ -17029,7 +17155,7 @@ paths: tags: - Files summary: Move items into a folder - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsMove parameters: - name: id @@ -17063,7 +17189,7 @@ paths: tags: - Files summary: Copy items into a folder — from here, another workspace (`fromLane`) or a home (`fromHome`) of the same account - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsCopy parameters: - name: id @@ -17101,7 +17227,7 @@ paths: tags: - Files summary: Move items into the account's trash (restorable for 7 days) - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsDelete parameters: - name: id @@ -17130,7 +17256,7 @@ paths: tags: - Files summary: The trash, newest first (entries older than 7 days are dropped) - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsTrash parameters: - name: id @@ -17146,7 +17272,7 @@ paths: tags: - Files summary: Put a trash item back where it was - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsTrashRestore parameters: - name: id @@ -17173,7 +17299,7 @@ paths: tags: - Files summary: Delete a trash item (or `all`) for good - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsTrashPurge parameters: - name: id @@ -17200,7 +17326,7 @@ paths: tags: - Files summary: Upload one file, streamed, making missing sub-folders (≤ 500 MB) - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsUpload parameters: - name: id @@ -17217,8 +17343,13 @@ paths: in: query schema: $ref: '#/components/schemas/FsConflict' + - name: staged + in: query + schema: + type: string + description: Write the bytes sent before through `/upload-part` under this upload id instead of a body. A commit made before answers its stored answer again; a failed one keeps the bytes for a retry. requestBody: - required: true + required: false content: application/octet-stream: schema: @@ -17227,12 +17358,123 @@ paths: responses: '201': description: Done. + /api/lanes/{id}/fs/upload-part: + get: + tags: + - Files + summary: How much of a resumable upload arrived + description: 'On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). `{received, total, done}` for the caller''s own upload id (`received: 0, total: null` when unknown). The browser asks this after the dashboard came back, then sends the rest. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' + operationId: laneFsUploadPartStatus + parameters: + - name: id + in: path + required: true + schema: + type: integer + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + responses: + '200': + description: '`{received, total, done}`' + content: + application/json: + schema: + type: object + properties: + received: + type: integer + total: + type: integer + nullable: true + done: + type: boolean + post: + tags: + - Files + summary: Send one part of a resumable upload (≤ 16 MB a part, 512 MB in all) + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). Raw bytes appended at `offset` to the caller's upload `upload` of `total` bytes, staged on the host (`/upload-staging/`) until `/upload` or `/upload-batch` names it with `?staged=`. A part must start where the staged bytes end (409 EOFFSET with `error.received`), one at a time per id (409 EBUSY); a part cut short keeps what arrived. At most 8 unfinished uploads per user (429 ETOOMANY); one untouched for a day is swept. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. + operationId: laneFsUploadPart + parameters: + - name: id + in: path + required: true + schema: + type: integer + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + - name: offset + in: query + required: true + schema: + type: integer + minimum: 0 + - name: total + in: query + required: true + schema: + type: integer + minimum: 0 + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + '200': + description: '`{received, total}`' + content: + application/json: + schema: + type: object + properties: + received: + type: integer + total: + type: integer + delete: + tags: + - Files + summary: Forget a resumable upload's staged bytes + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. + operationId: laneFsUploadPartDrop + parameters: + - name: id + in: path + required: true + schema: + type: integer + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + responses: + '200': + description: '`{dropped: true}`' + content: + application/json: + schema: + type: object + properties: + dropped: + type: boolean /api/lanes/{id}/fs/upload-check: post: tags: - Files summary: 'Before a batch: the names already taken, and whether a batch can go there' - description: 'On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). `taken`: which of `paths` (relative to `dir`) exist; `batch: false` = send the files one by one (a member''s folder whose `write-as` predates `extract`). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG.' + description: 'On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). `taken`: which of `paths` (relative to `dir`) exist; `batch: false` = send the files one by one (a member''s folder whose `write-as` predates `extract`). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' operationId: laneFsUploadCheck parameters: - name: id @@ -17275,7 +17517,7 @@ paths: tags: - Files summary: Upload many small files in one request (≤ 5,000 files, 16 MB each, 256 MB in all) - description: 'On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). Body: a 4-byte big-endian length, that many bytes of JSON `{files: [{path, size, mtime?}]}` (paths relative to `dir`), then each file''s bytes in that order. Planned whole before the first write — a taken name under `conflict=fail` is ONE 409 naming them all; a member''s batch is one `write-as extract` (409 EUPGRADE until `agenthub server install-system` is re-run). 400 EBADBODY for a malformed or short body. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG.' + description: 'On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). Body: a 4-byte big-endian length, that many bytes of JSON `{files: [{path, size, mtime?}]}` (paths relative to `dir`), then each file''s bytes in that order. Planned whole before the first write — a taken name under `conflict=fail` is ONE 409 naming them all; a member''s batch is one `write-as extract` (409 EUPGRADE until `agenthub server install-system` is re-run). 400 EBADBODY for a malformed or short body. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' operationId: laneFsUploadBatch parameters: - name: id @@ -17292,8 +17534,13 @@ paths: in: query schema: $ref: '#/components/schemas/FsConflict' + - name: staged + in: query + schema: + type: string + description: Write the bytes sent before through `/upload-part` under this upload id instead of a body. A commit made before answers its stored answer again; a failed one keeps the bytes for a retry. requestBody: - required: true + required: false content: application/octet-stream: schema: @@ -17320,7 +17567,7 @@ paths: tags: - Files summary: Files and folders as one streamed zip (≤ 2 GB, 50,000 files) - description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a workspace (`?session=` / `?source=` pick the session worktree / extra folder, like the git reads). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: laneFsZip parameters: - name: id @@ -17350,7 +17597,7 @@ paths: tags: - Files summary: List a folder (folders first) - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsList parameters: - name: who @@ -17376,7 +17623,7 @@ paths: tags: - Files summary: Make a folder - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsMkdir parameters: - name: who @@ -17404,7 +17651,7 @@ paths: tags: - Files summary: Make an empty file - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsNewfile parameters: - name: who @@ -17432,7 +17679,7 @@ paths: tags: - Files summary: Rename in place - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsRename parameters: - name: who @@ -17463,7 +17710,7 @@ paths: tags: - Files summary: Move items into a folder - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsMove parameters: - name: who @@ -17498,7 +17745,7 @@ paths: tags: - Files summary: Copy items into a folder — from here, another workspace (`fromLane`) or a home (`fromHome`) of the same account - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsCopy parameters: - name: who @@ -17537,7 +17784,7 @@ paths: tags: - Files summary: Move items into the account's trash (restorable for 7 days) - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsDelete parameters: - name: who @@ -17567,7 +17814,7 @@ paths: tags: - Files summary: The trash, newest first (entries older than 7 days are dropped) - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsTrash parameters: - name: who @@ -17584,7 +17831,7 @@ paths: tags: - Files summary: Put a trash item back where it was - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsTrashRestore parameters: - name: who @@ -17612,7 +17859,7 @@ paths: tags: - Files summary: Delete a trash item (or `all`) for good - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsTrashPurge parameters: - name: who @@ -17640,7 +17887,7 @@ paths: tags: - Files summary: Upload one file, streamed, making missing sub-folders (≤ 500 MB) - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsUpload parameters: - name: who @@ -17658,8 +17905,13 @@ paths: in: query schema: $ref: '#/components/schemas/FsConflict' + - name: staged + in: query + schema: + type: string + description: Write the bytes sent before through `/upload-part` under this upload id instead of a body. A commit made before answers its stored answer again; a failed one keeps the bytes for a retry. requestBody: - required: true + required: false content: application/octet-stream: schema: @@ -17668,12 +17920,126 @@ paths: responses: '201': description: Done. + /api/homes/{who}/fs/upload-part: + get: + tags: + - Files + summary: How much of a resumable upload arrived + description: 'On a user''s home. Every dot entry at the top of the home is hidden and refused. `{received, total, done}` for the caller''s own upload id (`received: 0, total: null` when unknown). The browser asks this after the dashboard came back, then sends the rest. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' + operationId: homeFsUploadPartStatus + parameters: + - name: who + in: path + required: true + schema: + type: string + description: '`me`, or another user''s name (an admin''s read-only view).' + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + responses: + '200': + description: '`{received, total, done}`' + content: + application/json: + schema: + type: object + properties: + received: + type: integer + total: + type: integer + nullable: true + done: + type: boolean + post: + tags: + - Files + summary: Send one part of a resumable upload (≤ 16 MB a part, 512 MB in all) + description: On a user's home. Every dot entry at the top of the home is hidden and refused. Raw bytes appended at `offset` to the caller's upload `upload` of `total` bytes, staged on the host (`/upload-staging/`) until `/upload` or `/upload-batch` names it with `?staged=`. A part must start where the staged bytes end (409 EOFFSET with `error.received`), one at a time per id (409 EBUSY); a part cut short keeps what arrived. At most 8 unfinished uploads per user (429 ETOOMANY); one untouched for a day is swept. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. + operationId: homeFsUploadPart + parameters: + - name: who + in: path + required: true + schema: + type: string + description: '`me`, or another user''s name (an admin''s read-only view).' + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + - name: offset + in: query + required: true + schema: + type: integer + minimum: 0 + - name: total + in: query + required: true + schema: + type: integer + minimum: 0 + requestBody: + required: true + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + '200': + description: '`{received, total}`' + content: + application/json: + schema: + type: object + properties: + received: + type: integer + total: + type: integer + delete: + tags: + - Files + summary: Forget a resumable upload's staged bytes + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. + operationId: homeFsUploadPartDrop + parameters: + - name: who + in: path + required: true + schema: + type: string + description: '`me`, or another user''s name (an admin''s read-only view).' + - name: upload + in: query + required: true + schema: + type: string + pattern: ^[A-Za-z0-9_-]{16,64}$ + responses: + '200': + description: '`{dropped: true}`' + content: + application/json: + schema: + type: object + properties: + dropped: + type: boolean /api/homes/{who}/fs/upload-check: post: tags: - Files summary: 'Before a batch: the names already taken, and whether a batch can go there' - description: 'On a user''s home. Every dot entry at the top of the home is hidden and refused. `taken`: which of `paths` (relative to `dir`) exist; `batch: false` = send the files one by one (a member''s folder whose `write-as` predates `extract`). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG.' + description: 'On a user''s home. Every dot entry at the top of the home is hidden and refused. `taken`: which of `paths` (relative to `dir`) exist; `batch: false` = send the files one by one (a member''s folder whose `write-as` predates `extract`). 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' operationId: homeFsUploadCheck parameters: - name: who @@ -17717,7 +18083,7 @@ paths: tags: - Files summary: Upload many small files in one request (≤ 5,000 files, 16 MB each, 256 MB in all) - description: 'On a user''s home. Every dot entry at the top of the home is hidden and refused. Body: a 4-byte big-endian length, that many bytes of JSON `{files: [{path, size, mtime?}]}` (paths relative to `dir`), then each file''s bytes in that order. Planned whole before the first write — a taken name under `conflict=fail` is ONE 409 naming them all; a member''s batch is one `write-as extract` (409 EUPGRADE until `agenthub server install-system` is re-run). 400 EBADBODY for a malformed or short body. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG.' + description: 'On a user''s home. Every dot entry at the top of the home is hidden and refused. Body: a 4-byte big-endian length, that many bytes of JSON `{files: [{path, size, mtime?}]}` (paths relative to `dir`), then each file''s bytes in that order. Planned whole before the first write — a taken name under `conflict=fail` is ONE 409 naming them all; a member''s batch is one `write-as extract` (409 EUPGRADE until `agenthub server install-system` is re-run). 400 EBADBODY for a malformed or short body. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user''s home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY.' operationId: homeFsUploadBatch parameters: - name: who @@ -17735,8 +18101,13 @@ paths: in: query schema: $ref: '#/components/schemas/FsConflict' + - name: staged + in: query + schema: + type: string + description: Write the bytes sent before through `/upload-part` under this upload id instead of a body. A commit made before answers its stored answer again; a failed one keeps the bytes for a retry. requestBody: - required: true + required: false content: application/octet-stream: schema: @@ -17763,7 +18134,7 @@ paths: tags: - Files summary: Files and folders as one streamed zip (≤ 2 GB, 50,000 files) - description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG. + description: On a user's home. Every dot entry at the top of the home is hidden and refused. 400 EBADPATH/EBADNAME, 403 ESECRET/EFOREIGN/EREADONLY (another user's home)/EBADORIGIN, 404 ENOFILE/ENOHOME, 409 EEXISTS (with `error.names`)/EUPGRADE/EMEMBERGONE, 413 ETOOBIG; a resumable upload adds 409 EOFFSET/EINCOMPLETE (with `error.received`)/EBUSY and 429 ETOOMANY. operationId: homeFsZip parameters: - name: who @@ -18037,6 +18408,99 @@ paths: responses: '200': description: The identity. + /api/me/git/ssh-key/import: + post: + tags: + - Git identity + summary: Import a private key the user already has as a named key; with `sign`, sign commits with it at once + operationId: importSshKey + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - privateKey + properties: + privateKey: + type: string + description: The key file's text (OpenSSH or PEM). + name: + type: string + pattern: ^[a-z0-9][a-z0-9-]{0,31}$ + sign: + type: boolean + replace: + type: boolean + responses: + '201': + description: The identity, plus `imported` (the key's public half) and `signError` (a refused `sign`, else null). + '400': + description: EBADKEY / EKEYPASSPHRASE / EBADKEYTYPE / EBADKEYNAME + '409': + description: EEXISTS (the same key, or the name is taken) / ETOOMANYKEYS + /api/me/git/signing: + put: + tags: + - Git identity + summary: 'Sign every commit with one of the account''s keys (`key`: its id), or stop (`key: null`)' + operationId: setCommitSigning + description: 'The account-wide setting (every repository of the account). `clearForeign: true` with `key: null` also takes out a signing setup the user made themselves — the three settings only, never their key file. Per workspace: `PUT /api/me/git/signing/lane`.' + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [] + properties: + key: + type: string + nullable: true + replace: + type: boolean + clearForeign: + type: boolean + responses: + '200': + description: The identity; `signing.state` is on, off or foreign. + '400': + description: ENOKEY + '409': + description: EFOREIGNSIGN — ~/.gitconfig already signs with a key of its own. + /api/me/git/signing/lane: + put: + tags: + - Git identity + summary: 'Sign ONE workspace''s commits with one of the account''s keys (`key`: its id), or stop (`key: null`)' + description: 'Writes a small file of AgentHub''s (`lane-.gitconfig`: gpg.format ssh, user.signingkey, commit.gpgsign) and includes it from the account''s `~/.gitconfig` with `includeIf "gitdir:"` and `gitdir:/worktrees/ah--*` (its sessions'' worktrees) — nothing is written into the repository. The workspace must be one the caller may see whose folder runs as this same account. `GET /api/me/git` answers `laneSigning: [{laneId, key}]`; deleting a key stops every workspace that signs with it.' + operationId: setLaneCommitSigning + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - laneId + properties: + laneId: + type: integer + key: + type: string + nullable: true + responses: + '200': + description: The identity, with `laneSigning`. + '400': + description: ENOKEY + '403': + description: EFOREIGN — the workspace runs as another account; EHOSTIDENTITY. + '404': + description: ENOTFOUND — no such workspace (or not the caller's). + '409': + description: ENOREPO — the workspace's folder is not a git repository. /api/me/git/ssh-terminal: put: tags: @@ -18179,7 +18643,7 @@ paths: - Artifacts summary: List artifacts operationId: listArtifacts - description: A developer sees their own rows plus shared ones; staff see every row in `hub` scope. + description: 'A developer sees their own rows plus shared ones (to everyone, or to them by name); staff see every row in `hub` scope. `withme`: the rows shared with the caller by name (server mode).' parameters: - name: scope in: query @@ -18189,6 +18653,7 @@ paths: - all - mine - hub + - withme - unowned - name: kind in: query @@ -18232,7 +18697,7 @@ paths: operationId: getArtifactSettings responses: '200': - description: '`{serverMode, canShare, installsEnabled, canManage}`.' + description: '`{serverMode, canShare, installsEnabled, exportsEnabled, canManage}`.' content: application/json: schema: @@ -18244,32 +18709,71 @@ paths: type: boolean installsEnabled: type: boolean + exportsEnabled: + type: boolean + description: Claude panes are asked to save a viewable copy of a Doc / Slides / Design they publish (scripts/artifact-export-hint.js). canManage: type: boolean put: tags: - Artifacts - summary: Turn installs on or off (admin; any caller in local mode) + summary: Turn installs, or the copy hint for Docs/Slides, on or off (admin; any caller in local mode) operationId: setArtifactSettings - description: Audited in server mode (Settings → AI tools → Artifacts Hub). + description: Audited in server mode (Settings → AI tools → Artifacts Hub). Send either or both; the export switch reaches panes started afterwards. requestBody: required: true content: application/json: schema: type: object - required: - - installsEnabled + required: [] properties: installsEnabled: type: boolean + exportsEnabled: + type: boolean responses: '200': - description: '`{installsEnabled}`.' + description: '`{installsEnabled, exportsEnabled}`.' '400': description: EBADFIELD '403': description: EADMIN / EBADORIGIN + /api/artifacts/{id}/copy: + post: + tags: + - Artifacts + summary: Take a page's viewable copy from the file it was published from + operationId: copyArtifactPage + description: 'A `page` captured before pages kept a copy: if the HTML file it was published from is still in its workspace, it is snapshotted (read under the pinned-file guards) and the row''s `files` name it. Once per row per server run; any viewer may ask and gets only the copy. A row that already has one, or is not a page, is answered as it is.' + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: '`{item}`.' + content: + application/json: + schema: + type: object + properties: + item: + $ref: '#/components/schemas/Artifact' + '404': + description: 'Error `{error:{code,message}}`: 400 EBADURL/EBADPATH/EBADNAME/ENOSKILLMD/ENODESCRIPTION/EBADFIELD/EBADUPLOAD, 403 EFORBIDDEN/ESECRET/EFOREIGN/EINSTALLSOFF/EADMIN, 404 ENOTFOUND/ENOLANE/ENOFILE, 409 EEXISTS/ENOTSHARED/ENOACCOUNT/EUPGRADE, 413 ETOOBIG, 502 EPLUGIN/EMARKETFETCH/ENEEDLOGIN.' + /api/artifacts/people: + get: + tags: + - Artifacts + summary: The people the caller may share an artifact with + operationId: listArtifactPeople + description: 'Server mode: every enabled account but the caller, by name only (`{people: [{id, username, name}]}`); empty in local mode.' + responses: + '200': + description: '`{people: [{id, username, name}]}`.' /api/artifacts/candidates: get: tags: @@ -18638,6 +19142,12 @@ paths: type: string shared: type: boolean + description: Share with everyone (the Hub). + sharedWith: + type: array + items: + type: integer + description: 'Server mode: the user ids it is shared with by name (replaces the list; up to 100 enabled users; the owner is dropped). Out of its owner''s library and shared with nobody, the row is deleted (`removed`).' source: type: string description: Plugin only. @@ -19906,6 +20416,68 @@ paths: description: EBADORIGIN (not same-origin) or EFOLDER (outside the caller's own folder). '404': description: ENOLANE, or ENOSOURCE for an unknown source id. + /api/lanes/{id}/shares: + get: + tags: + - Lanes + summary: The users a workspace is shared with + description: 'Server mode (local mode: `{shares: [], canManage: false}`). `{shares:[{id, username, name, sharedAt}], canManage}` — names only; `canManage` is whether this caller (the owner or an admin) may change the list. A user it is shared with may read it too.' + operationId: getLaneShares + parameters: + - name: id + in: path + required: true + schema: + type: integer + responses: + '200': + description: '`{shares, canManage}`.' + content: + application/json: + schema: + type: object + additionalProperties: true + '404': + description: ENOLANE — workspace not found. + put: + tags: + - Lanes + summary: Set the users a workspace is shared with + description: '`{userIds:[…]}` is the WHOLE list (≤ 200 enabled users, never the owner). The owner or an admin only (`403 ENOTOWNER`); same-origin; each user added or taken off is written to the audit log. A user it is shared with sees it and works in it like its owner — under S3 as the owner''s Linux account — except rename, reset, remove, delete and sharing (`ENOTOWNER`), and starts no AI session in it yet (`ECOLLABSTART`). Users taken off get `lane_access` and lose access at once.' + operationId: setLaneShares + parameters: + - name: id + in: path + required: true + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - userIds + properties: + userIds: + type: array + items: + type: integer + responses: + '200': + description: '`{shares}`.' + content: + application/json: + schema: + type: object + additionalProperties: true + '400': + description: EBADUSER or ELOCALMODE. + '403': + description: ENOTOWNER. + '404': + description: ENOLANE — workspace not found. /api/lanes/{id}/memory: get: tags: @@ -23944,4 +24516,432 @@ paths: description: '{available, current, head, local[], remotes[{remote, branches[]}], tags[], truncated}.' '404': description: Lane not found, ENOSOURCE, ENOREPO or ENOWORKTREE. + /api/remote/device/login: + post: + tags: + - Remote clients + operationId: remoteDeviceLogin + summary: Enroll a machine (hub, server mode) + description: The user's hub password, throttled like a login. Answers the device token ONCE. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - username + - password + properties: + username: + type: string + password: + type: string + deviceName: + type: string + responses: + '200': + description: Enrolled + content: + application/json: + schema: + type: object + properties: + token: + type: string + example: ahdev_… + device: + $ref: '#/components/schemas/RemoteDevice' + user: + type: object + retainDays: + type: integer + '401': + description: Wrong username or password + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '429': + description: Too many failed logins + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/device/me: + get: + tags: + - Remote clients + operationId: remoteDeviceMe + summary: This device and its user (device token) + responses: + '200': + description: The device + content: + application/json: + schema: + type: object + '401': + description: Token missing, expired or revoked + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/device/logout: + post: + tags: + - Remote clients + operationId: remoteDeviceLogout + summary: Revoke this device's own token + responses: + '200': + description: Revoked + content: + application/json: + schema: + type: object + '401': + description: Token missing, expired or revoked + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/device/sessions: + post: + tags: + - Remote clients + operationId: remoteDeviceRegisterSession + summary: Register a Company-account session at its start (id + folder, no content) + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - sessionId + - cwd + properties: + sessionId: + type: string + format: uuid + cwd: + type: string + tool: + type: string + enum: + - claude + responses: + '200': + description: Registered (again, on a resume) + content: + application/json: + schema: + type: object + '400': + description: Not a UUID, not an absolute folder, not Claude + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '409': + description: EFOREIGN — the session belongs to another device or is already known + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/device/sessions/{id}/end: + post: + tags: + - Remote clients + operationId: remoteDeviceEndSession + summary: Mark a registered session ended + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Done + content: + application/json: + schema: + type: object + /api/remote/device/sessions/{id}/files: + get: + tags: + - Remote clients + operationId: remoteDeviceSessionFiles + summary: How far the hub holds each file of a registered session + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Files and offsets + content: + application/json: + schema: + type: object + '404': + description: Not this device's session + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/device/upload: + post: + tags: + - Remote clients + operationId: remoteDeviceUpload + summary: Upload new transcript lines of a registered session (hourly) + description: Each chunk must start where the hub stopped; the hub then imports its copy with the local-history importer and stamps the session as this device's user's. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - sessionId + properties: + sessionId: + type: string + format: uuid + files: + type: array + items: + $ref: '#/components/schemas/RemoteUploadFile' + ended: + type: boolean + responses: + '200': + description: Taken + content: + application/json: + schema: + type: object + '400': + description: A path outside the two file shapes, a bad range, half a line + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Not this device's session + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '409': + description: EOFFSET — `error.expected.consumed` says where to resume + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '410': + description: EPURGED — the conversation passed its retention + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/devices: + get: + tags: + - Remote clients + operationId: remoteListDevices + summary: Enrolled machines — your own; staff may pass ?user= + parameters: + - name: user + in: query + schema: + type: integer + responses: + '200': + description: Devices + content: + application/json: + schema: + type: object + properties: + devices: + type: array + items: + $ref: '#/components/schemas/RemoteDevice' + /api/remote/devices/{id}/revoke: + post: + tags: + - Remote clients + operationId: remoteRevokeDevice + summary: Revoke a device — its owner or an admin, with their own password again (audited) + parameters: + - name: id + in: path + required: true + schema: + type: integer + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - password + properties: + password: + type: string + responses: + '200': + description: Revoked + content: + application/json: + schema: + type: object + '403': + description: Wrong password + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: No such device of yours + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote/sessions: + get: + tags: + - Remote clients + operationId: remoteListSessions + summary: Registered Company-account sessions (device › folder) — your own; staff may pass ?user= + parameters: + - name: user + in: query + schema: + type: integer + responses: + '200': + description: Sessions + content: + application/json: + schema: + type: object + /api/remote/audit: + get: + tags: + - Remote clients + operationId: remoteMyAudit + summary: Who (admin/analyst) opened your sessions + responses: + '200': + description: Audit entries + content: + application/json: + schema: + type: object + /api/remote-client: + get: + tags: + - Remote clients + operationId: remoteClientStatus + summary: This local machine's enrollment and what it sent (local AgentHub) + responses: + '200': + description: Status + content: + application/json: + schema: + $ref: '#/components/schemas/RemoteClientStatus' + /api/remote-client/login: + post: + tags: + - Remote clients + operationId: remoteClientLogin + summary: Enroll this machine with a hub — the password goes to the hub once and is not kept + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - hub + - username + - password + properties: + hub: + type: string + example: http://10.1.13.7:4820 + username: + type: string + password: + type: string + deviceName: + type: string + responses: + '200': + description: Enrolled + content: + application/json: + schema: + $ref: '#/components/schemas/RemoteClientStatus' + '400': + description: Bad hub address + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Wrong username or password + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '503': + description: EHUBDOWN — the hub cannot be reached + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /api/remote-client/logout: + post: + tags: + - Remote clients + operationId: remoteClientLogout + summary: Revoke this machine on the hub (best effort) and forget its token + responses: + '200': + description: Logged out + content: + application/json: + schema: + type: object + /api/remote-client/upload: + post: + tags: + - Remote clients + operationId: remoteClientUpload + summary: Send the Company-account sessions' new lines now + responses: + '200': + description: Round result + content: + application/json: + schema: + type: object + '400': + description: ENOHUB — not enrolled + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' x-issues-url: https://git.smartgift.io.vn/Smartgift-AI/AgentHub/issues