feat: v2.7.6 — edit users in one form, Settings → Account, display names, copy over plain HTTP
- Users page: one Edit user form (display name, email, role, active, a new or generated password, workspaces given or taken back, sign out everywhere), validated as a whole before anything is written (PATCH /api/users/:id, GET /api/users/:id); users.display_name/email added migration-safe. - Settings → Account for every signed-in user: profile, own password (the current one required, this login kept), sign out other devices (/api/me/account, /api/me/password, /api/me/sign-out-others; login cookie only, never a pane token). - Display names wherever a person is named (sidebar, workspace owner groups, Users page and audit log); owner_display_name / reader_display additive. - Users page: admins add and remove Claude/Codex pool accounts. - Folder browser: an admin with their own Linux account opens in their home; the "Server folder" tick opens the host's (never remembered). - AI Proxy: "Config 9router" beside Add profile when 9router is installed, opened on the dashboard's own host (GET /api/ai-proxies/9router). - Terminal: a tmux selection reaches the clipboard over plain HTTP too (writeClipboard's textarea fallback, focus handed back). - Chat: a file the session touched outside the workspace previews (GET /api/sessions/:id/file). - install-system: `!requiretty` only when visudo accepts it (sudo-rs on Ubuntu 25.10+ rejects the setting). - openapi.yaml regenerated; docs (API, SERVER-MODE, LANES) updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+388
-6
@@ -3,7 +3,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Agent Dashboard for Claude Code API
|
||||
version: 2.7.5
|
||||
version: 2.7.6
|
||||
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ĩ
|
||||
@@ -4803,6 +4803,37 @@ components:
|
||||
- developer
|
||||
disabled:
|
||||
type: boolean
|
||||
displayName:
|
||||
type: string
|
||||
nullable: true
|
||||
email:
|
||||
type: string
|
||||
nullable: true
|
||||
createdAt:
|
||||
type: string
|
||||
nullable: true
|
||||
MyAccount:
|
||||
type: object
|
||||
required:
|
||||
- mode
|
||||
properties:
|
||||
mode:
|
||||
type: string
|
||||
enum:
|
||||
- local
|
||||
- server
|
||||
user:
|
||||
$ref: '#/components/schemas/AuthUser'
|
||||
workspaces:
|
||||
type: integer
|
||||
sessions:
|
||||
type: integer
|
||||
logins:
|
||||
type: integer
|
||||
description: Unexpired logins of the account
|
||||
lastLoginAt:
|
||||
type: string
|
||||
nullable: true
|
||||
AuthMe:
|
||||
type: object
|
||||
required:
|
||||
@@ -11182,6 +11213,43 @@ paths:
|
||||
description: EDIALOG — the dialog program failed.
|
||||
'501':
|
||||
description: ENODIALOG — no desktop session or no dialog program.
|
||||
/api/lanes/browse/mkdir:
|
||||
post:
|
||||
tags:
|
||||
- Lanes
|
||||
summary: New folder, from the in-app folder browser
|
||||
description: Makes ONE folder `name` (no `/`, `\`, NUL, `.` or `..`; ≤ 255 bytes) inside the existing folder `parent` — never `-p`, never over an existing entry. A non-admin makes one only inside their own folder, by real path (`EFOLDER`), and in server mode a non-admin with no folder of their own makes none. Under S3 a folder in a member's home is made as that member.
|
||||
operationId: makeBrowseFolder
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- parent
|
||||
- name
|
||||
properties:
|
||||
parent:
|
||||
type: string
|
||||
description: Absolute path of an existing folder.
|
||||
name:
|
||||
type: string
|
||||
responses:
|
||||
'201':
|
||||
description: '`{path}` — the folder made.'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
'400':
|
||||
description: EBADNAME, EBADPATH, or ENOTFOUND (no such parent folder).
|
||||
'403':
|
||||
description: EBADORIGIN, or EFOLDER (outside the caller's own folder).
|
||||
'409':
|
||||
description: EEXISTS (the name is taken) or EMEMBERGONE.
|
||||
/api/lanes/ensure:
|
||||
post:
|
||||
tags:
|
||||
@@ -13927,6 +13995,139 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/me/account:
|
||||
get:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: getMyAccount
|
||||
summary: 'Settings → Account: the signed-in account (local mode: {mode: "local"})'
|
||||
responses:
|
||||
'200':
|
||||
description: Account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MyAccount'
|
||||
'401':
|
||||
description: EAUTH
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
patch:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: updateMyAccount
|
||||
summary: The account's own display name and email (""/null clears). Login cookie only, audited
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
nullable: true
|
||||
maxLength: 100
|
||||
email:
|
||||
type: string
|
||||
nullable: true
|
||||
maxLength: 254
|
||||
responses:
|
||||
'200':
|
||||
description: Updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MyAccount'
|
||||
'400':
|
||||
description: EBADFIELD / EBADEMAIL
|
||||
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'
|
||||
/api/me/password:
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: changeMyPassword
|
||||
summary: 'Change the account''s own password: the current one required (throttled); this login stays, every other ends'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- currentPassword
|
||||
- newPassword
|
||||
properties:
|
||||
currentPassword:
|
||||
type: string
|
||||
newPassword:
|
||||
type: string
|
||||
minLength: 1
|
||||
responses:
|
||||
'200':
|
||||
description: 'Changed ({ok: true})'
|
||||
'400':
|
||||
description: EBADPASSWORD
|
||||
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: EREAUTH (current password wrong) / ELOCALMODE
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — 10 wrong passwords in 15 minutes
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/me/sign-out-others:
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: signOutMyOtherLogins
|
||||
summary: End every login of the account but this one; answers {ended}
|
||||
responses:
|
||||
'200':
|
||||
description: Ended
|
||||
'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:
|
||||
@@ -13992,7 +14193,7 @@ paths:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
minLength: 1
|
||||
role:
|
||||
type: string
|
||||
enum:
|
||||
@@ -14037,11 +14238,37 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/users/{id}:
|
||||
get:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: getServerUser
|
||||
summary: One account with its logins and the workspaces it owns (admin/analyst)
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
'200':
|
||||
description: Account
|
||||
'403':
|
||||
description: EADMIN — a developer
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: ENOUSER
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
patch:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: updateServerUser
|
||||
summary: 'Admin: change a role and/or disable (ending every login) or enable. Never your own (ESELF)'
|
||||
summary: 'Admin (Edit user): display name, email, role, disabled, a new password, workspaces given or taken back, sign out everywhere — every field validated before any is written. Never your own role or disable (ESELF)'
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
@@ -14057,6 +14284,14 @@ paths:
|
||||
required:
|
||||
- currentPassword
|
||||
properties:
|
||||
displayName:
|
||||
type: string
|
||||
nullable: true
|
||||
maxLength: 100
|
||||
email:
|
||||
type: string
|
||||
nullable: true
|
||||
maxLength: 254
|
||||
role:
|
||||
type: string
|
||||
enum:
|
||||
@@ -14065,6 +14300,21 @@ paths:
|
||||
- developer
|
||||
disabled:
|
||||
type: boolean
|
||||
password:
|
||||
type: string
|
||||
minLength: 1
|
||||
addWorkspaces:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
removeWorkspaces:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
signOut:
|
||||
type: boolean
|
||||
enum:
|
||||
- true
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
@@ -14078,7 +14328,7 @@ paths:
|
||||
user:
|
||||
$ref: '#/components/schemas/AuthUser'
|
||||
'400':
|
||||
description: EBADPASSWORD / EBADROLE / EBADFIELD
|
||||
description: EBADPASSWORD / EBADROLE / EBADFIELD / EBADEMAIL
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -14096,7 +14346,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'409':
|
||||
description: ESELF — your own role or disable
|
||||
description: ESELF / ENOTOWNED / EOWNERFOLDER
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -14131,7 +14381,7 @@ paths:
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
minLength: 8
|
||||
minLength: 1
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
@@ -14282,6 +14532,12 @@ paths:
|
||||
owner:
|
||||
type: string
|
||||
nullable: true
|
||||
reader_display:
|
||||
type: string
|
||||
nullable: true
|
||||
owner_display:
|
||||
type: string
|
||||
nullable: true
|
||||
'403':
|
||||
description: EADMIN — a developer
|
||||
content:
|
||||
@@ -14368,6 +14624,132 @@ paths:
|
||||
nullable: true
|
||||
full:
|
||||
type: boolean
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: addPoolAccount
|
||||
summary: 'Admin: add a Claude (saved login, pasted credentials or setup-token) or Codex (API key / auth.json text) account to the pool, with their own password again. The secret is never answered back'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- tool
|
||||
- currentPassword
|
||||
properties:
|
||||
tool:
|
||||
type: string
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
name:
|
||||
type: string
|
||||
description: Defaults to the profile's name
|
||||
profile:
|
||||
type: string
|
||||
description: 'Claude: a saved switch-user profile, moved into the pool'
|
||||
credentials:
|
||||
type: string
|
||||
description: 'Claude: the text of a .credentials.json'
|
||||
token:
|
||||
type: string
|
||||
description: 'Claude: a setup-token; Codex: an API key or auth.json text'
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
'201':
|
||||
description: '`{account: {name, addedAt, …}}` — no token'
|
||||
'400':
|
||||
description: EBADTOOL, EBADNAME, EBADTOKEN
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'403':
|
||||
description: EREAUTH — wrong password; EADMIN — not an admin; ELOCALMODE
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'409':
|
||||
description: EEXISTS — the name or account is taken; EACTIVE — the host's CLI uses that profile
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — too many wrong passwords
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'502':
|
||||
description: EUPSTREAM — Anthropic could not be reached
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/accounts/profiles:
|
||||
get:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: listPoolProfiles
|
||||
summary: Saved switch-user profiles an admin may move into the Claude pool (no token)
|
||||
responses:
|
||||
'200':
|
||||
description: '`{profiles: [{name, label, email, subscriptionType, active}]}`'
|
||||
/api/accounts/{name}:
|
||||
delete:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: removePoolAccount
|
||||
summary: 'Admin: remove an account from the pool, with their own password again'
|
||||
parameters:
|
||||
- name: name
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- tool
|
||||
- currentPassword
|
||||
properties:
|
||||
tool:
|
||||
type: string
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: '`{ok: true}`'
|
||||
'403':
|
||||
description: EREAUTH — wrong password; EADMIN — not an admin; ELOCALMODE
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: ENOACCOUNT
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — too many wrong passwords
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/auth/me:
|
||||
get:
|
||||
tags:
|
||||
|
||||
Reference in New Issue
Block a user