feat: right-click menus in Files/Users/Artifacts; several SSH keys and accounts per host

- Files: right-click a sidebar workspace (Open, Copy path) or home (Open,
  Open Trash), a path crumb (Open, Download as zip, Paste into, Copy path),
  a Trash row (Restore, Copy path, Delete forever), the Trash area (Refresh,
  Empty Trash) and an admin's per-user Trash folder (Open, Empty Trash).
- Users: row menu (Edit + Open home in Files for an admin, Copy username/email).
- Artifacts: card menu repeating its buttons, plus Copy link for a page.
- Git identity: named SSH keys beside the default ones (id_<type>_<name>,
  max 10, DELETE ?id=); SSH logins per alias (`ssh://<alias>/` →
  `ssh://<user>@<host>/`, so several AWS CodeCommit accounts share a host),
  each optionally tied to one key (`agenthub.<from>.sshKey`) — a clone of
  that URL offers only that key and persists it. Terminal sshCommand follows
  the keys. Settings → Git: "More SSH keys" + account name/key in the AWS and
  other-host forms. Docs/API.md, OpenAPI updated.
This commit is contained in:
2026-10-15 16:42:47 +07:00
parent 758609775f
commit b058179177
24 changed files with 1510 additions and 126 deletions
+323 -4
View File
@@ -3,7 +3,7 @@
openapi: 3.0.3
info:
title: Agent Dashboard for Claude Code API
version: 2.7.7
version: 2.8.5
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ĩ
@@ -3952,6 +3952,10 @@ components:
enum:
- true
example: true
archived:
type: string
nullable: true
description: 'Only with `?archive=1`: the id of the session the pane held, now archived, or null when the pane had no known session (a shell).'
LaneWorktreeCreateRequest:
type: object
required:
@@ -4819,6 +4823,10 @@ components:
email:
type: string
nullable: true
avatarAt:
type: string
nullable: true
description: When the avatar was last set (null = none)
createdAt:
type: string
nullable: true
@@ -11205,6 +11213,14 @@ paths:
format: uuid
description: Run id (RunHandle.id).
example: 3f2c9a1e-7b4d-4e21-9b6a-1d2e3f4a5b6c
- name: archive
in: query
required: false
schema:
type: string
enum:
- '1'
description: '`1` (the UI''s Stop) also archives the session the pane held, so it leaves its workspace''s lists. Omitted (the UI''s Sleep, the CLI) the session stays listed, to be resumed later.'
responses:
'200':
description: Kill issued (or run already terminated).
@@ -14282,6 +14298,94 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/me/avatar:
get:
tags:
- Auth
operationId: getMyAvatar
summary: The account's own picture (nosniff, sandbox CSP)
responses:
'200':
description: The image (PNG, JPEG, GIF or WebP)
'401':
description: EAUTH
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: ENOAVATAR
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
tags:
- Auth
operationId: setMyAvatar
summary: Set the account's picture from the raw image bytes (PNG/JPEG/GIF/WebP, at most 1 MB). Login cookie only, audited
requestBody:
required: true
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
'200':
description: Set
content:
application/json:
schema:
$ref: '#/components/schemas/MyAccount'
'400':
description: EBADIMAGE
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: EAUTH — no login cookie (a pane token is refused)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ELOCALMODE
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'413':
description: ETOOBIG
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
tags:
- Auth
operationId: removeMyAvatar
summary: Remove the account's picture
responses:
'200':
description: Removed
content:
application/json:
schema:
$ref: '#/components/schemas/MyAccount'
'401':
description: EAUTH — no login cookie (a pane token is refused)
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ELOCALMODE
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users:
get:
tags:
@@ -14391,6 +14495,118 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/tmux:
get:
tags:
- Auth
operationId: listMemberTmux
summary: 'Each member''s own tmux server (one Linux user per account): its version beside the installed one, sessions, agents working (admin/analyst)'
responses:
'200':
description: '{available, installed, matched, users: [{id, username, running, stuck?, version, pid, startedAt, sessions, busy, outdated}]} — available false without S3'
'403':
description: EADMIN — a developer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{id}/tmux-restart:
post:
tags:
- Auth
operationId: restartMemberTmux
summary: End one member's tmux server — every pane of theirs closes; the next start runs the installed tmux (admin, own password again, audited)
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- currentPassword
properties:
currentPassword:
type: string
responses:
'200':
description: '{user}'
'403':
description: EREAUTH (own password wrong) / EADMIN / ELOCALMODE
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: ENOUSER
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: ETMUXSTUCK — the server did not stop (the message names the pid for root) / ENOS3
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/tmux-restart-idle:
post:
tags:
- Auth
operationId: restartIdleMemberTmux
summary: Restart every member server older than the installed tmux while no agent of theirs works (admin, own password again, audited per member)
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- currentPassword
properties:
currentPassword:
type: string
responses:
'200':
description: '{restarted: [username], skipped: [username — an agent working], failed: [{username, message}]}'
'403':
description: EREAUTH / EADMIN / ELOCALMODE
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{id}/avatar:
get:
tags:
- Auth
operationId: getUserAvatar
summary: One account's picture, for the sidebar's owner groups (admin/analyst)
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: The image (PNG, JPEG, GIF or WebP)
'403':
description: EADMIN — a developer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: ENOAVATAR
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/users/{id}:
get:
tags:
@@ -14741,6 +14957,10 @@ paths:
type: number
spend7d:
type: number
tokens5h:
type: integer
tokens7d:
type: integer
quota:
type: object
nullable: true
@@ -14770,6 +14990,10 @@ paths:
type: number
spend7d:
type: number
tokens5h:
type: integer
tokens7d:
type: integer
quota:
type: object
nullable: true
@@ -15761,12 +15985,12 @@ paths:
operationId: getGitIdentity
responses:
'200':
description: '{account, writable, ssh: {publicKey, fingerprint} | null, https: [...], author: {name, email}}'
description: '{account, writable, ssh: {type, publicKey, fingerprint, terminal} | null, https: [...], author: {name, email}}'
/api/me/git/ssh-key:
post:
tags:
- Git identity
summary: Make (or with `replace`, replace) the SSH key
summary: Make (or with `replace`, replace) the default SSH key of `type`, or with `name` one more beside it
operationId: generateSshKey
requestBody:
required: true
@@ -15778,17 +16002,112 @@ paths:
properties:
replace:
type: boolean
type:
type: string
enum:
- ed25519
- rsa
name:
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,31}$
responses:
'201':
description: The identity.
'400':
description: EBADKEYNAME
'409':
description: EEXISTS (without replace, or the name is taken) / ETOOMANYKEYS
delete:
tags:
- Git identity
summary: Delete the SSH key
summary: Delete one SSH key (?id=, or the default of ?type=ed25519|rsa), or every key
operationId: deleteSshKey
parameters:
- name: type
in: query
required: false
schema:
type: string
enum:
- ed25519
- rsa
- name: id
in: query
required: false
schema:
type: string
responses:
'200':
description: The identity.
/api/me/git/ssh-terminal:
put:
tags:
- Git identity
summary: Use the SSH key for git in the account's own terminal (core.sshCommand)
operationId: setTerminalSsh
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- 'on'
properties:
'on':
type: boolean
responses:
'200':
description: The identity; `ssh.terminal` is on, off or foreign.
'409':
description: EFOREIGNSSH — ~/.gitconfig already sets its own core.sshCommand.
/api/me/git/ssh-user:
put:
tags:
- Git identity
summary: 'An SSH login: url.<ssh://user@host/>.insteadOf ssh://<alias or host>/, optionally tied to one key'
operationId: setSshUser
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- host
- user
properties:
host:
type: string
user:
type: string
alias:
type: string
pattern: ^[a-z0-9][a-z0-9-]{0,62}$
key:
type: string
responses:
'200':
description: 'The identity; `sshUsers: [{host, user, alias, key}]`.'
'400':
description: EBADHOST / EBADSSHUSER / EBADALIAS / ENOKEY
/api/me/git/ssh-user/{from}:
delete:
tags:
- Git identity
summary: Drop the SSH login of a host or alias (and its key link)
operationId: deleteSshUser
parameters:
- name: from
in: path
required: true
schema:
type: string
responses:
'200':
description: The identity.
'404':
description: ENOTFOUND
/api/me/git/https:
post:
tags: