feat: account pool per tool with groups and a Cursor pool; update runs in the background
- The update dialog can be closed while an update applies: it keeps running, the page still reloads itself when the new server is up, and a failure re-opens the dialog with its error. - Account pool card: one tab per AI tool (Claude Code, Codex, Cursor CLI, Oh My Pi, and every other installed tool, which says it has no pool), accounts as cards with 5-hour and weekly quota shown as what is LEFT plus their reset times, and the saved profiles of Settings → AI tools → Profiles as cards with "Share to pool". - Cursor account pool (server/lib/cursor-pool.js): Cursor API keys handed to a cursor-agent pane only through tmux -e CURSOR_API_KEY; `agenthub accounts add <name> --tool cursor`. - Pool groups (server/lib/pool-groups.js, /api/accounts/groups): a group's members run only on its accounts of each tool, a user in no group on the accounts no group lists, a pin still wins. account_pins loses its tool CHECK (rebuilt, pins kept); three new tables. - Oh My Pi login sharing can be switched from its pool tab too.
This commit is contained in:
+229
-4
@@ -3,7 +3,7 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Agent Dashboard for Claude Code API
|
||||
version: 2.8.19
|
||||
version: 2.8.20
|
||||
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ĩ
|
||||
@@ -4632,6 +4632,36 @@ components:
|
||||
description: The pool account's name
|
||||
pinnedAt:
|
||||
type: string
|
||||
PoolGroup:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- users
|
||||
- accounts
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
createdAt:
|
||||
type: string
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
userId:
|
||||
type: integer
|
||||
username:
|
||||
type: string
|
||||
accounts:
|
||||
type: object
|
||||
description: Per tool (claude, codex, cursor), the pool account names it may use
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
UserPrefs:
|
||||
type: object
|
||||
required:
|
||||
@@ -15227,7 +15257,7 @@ paths:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: listPoolAccounts
|
||||
summary: The Claude and Codex account pools as the balancer sees them (never a key or token)
|
||||
summary: The Claude, Codex and Cursor account pools as the balancer sees them, and the pool groups (never a key or token)
|
||||
parameters:
|
||||
- name: force
|
||||
in: query
|
||||
@@ -15289,6 +15319,31 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/AccountPin'
|
||||
cursor:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/AccountPin'
|
||||
groups:
|
||||
type: array
|
||||
description: 'Pool groups (server/lib/pool-groups.js; empty in local mode): a member runs only on its group''s accounts, a user in no group on the accounts no group lists'
|
||||
items:
|
||||
$ref: '#/components/schemas/PoolGroup'
|
||||
cursor:
|
||||
type: array
|
||||
description: 'The Cursor account pool (server/lib/cursor-pool.js): API keys only, no quota or spend'
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
enum:
|
||||
- apikey
|
||||
addedAt:
|
||||
type: string
|
||||
livePanes:
|
||||
type: integer
|
||||
codex:
|
||||
type: array
|
||||
description: The Codex account pool (server/lib/codex-pool.js), same fields plus `kind`; no expiry
|
||||
@@ -15326,7 +15381,7 @@ paths:
|
||||
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'
|
||||
summary: 'Admin: add a Claude (saved login, pasted credentials or setup-token), Codex (saved profile, API key / auth.json text) or Cursor (API key) account to the pool, with their own password again. The secret is never answered back'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -15342,6 +15397,7 @@ paths:
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
- cursor
|
||||
name:
|
||||
type: string
|
||||
description: Defaults to the profile's name
|
||||
@@ -15353,7 +15409,7 @@ paths:
|
||||
description: 'Claude: the text of a .credentials.json'
|
||||
token:
|
||||
type: string
|
||||
description: 'Claude: a setup-token; Codex: an API key or auth.json text'
|
||||
description: 'Claude: a setup-token; Codex: an API key or auth.json text; Cursor: a Cursor API key'
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
@@ -15411,6 +15467,7 @@ paths:
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
- cursor
|
||||
userId:
|
||||
type: integer
|
||||
account:
|
||||
@@ -15482,6 +15539,7 @@ paths:
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
- cursor
|
||||
userIds:
|
||||
type: array
|
||||
items:
|
||||
@@ -15515,6 +15573,172 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/accounts/groups:
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: createPoolGroup
|
||||
summary: 'Admin: a new, empty pool group, with their own password again'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- currentPassword
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
'201':
|
||||
description: '`{group: {id, name}}`'
|
||||
'400':
|
||||
description: EBADNAME
|
||||
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 — a group has that name
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — too many wrong passwords
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/accounts/groups/{id}:
|
||||
patch:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: updatePoolGroup
|
||||
summary: 'Admin: rename a pool group, set exactly its members (one group per user — a member of another group moves here) and/or exactly its accounts of each tool named, with their own password again'
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- currentPassword
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
userIds:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
accounts:
|
||||
type: object
|
||||
description: '`{tool: [account names]}` for claude, codex, cursor'
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: '`{group}`'
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
group:
|
||||
$ref: '#/components/schemas/PoolGroup'
|
||||
'400':
|
||||
description: EBADNAME, EBADUSER, EBADTOOL
|
||||
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'
|
||||
'404':
|
||||
description: ENOGROUP, ENOUSER, ENOACCOUNT
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'409':
|
||||
description: EEXISTS — a group has that name
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — too many wrong passwords
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
delete:
|
||||
tags:
|
||||
- Auth
|
||||
operationId: deletePoolGroup
|
||||
summary: 'Admin: delete a pool group — its members go back to the shared pool, no account is removed — with their own password again'
|
||||
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: '`{ok: true}`'
|
||||
'403':
|
||||
description: EREAUTH — wrong password; EADMIN — not an admin; ELOCALMODE
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: ENOGROUP
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'429':
|
||||
description: ETOOMANY — too many wrong passwords
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
/api/accounts/{name}:
|
||||
delete:
|
||||
tags:
|
||||
@@ -15542,6 +15766,7 @@ paths:
|
||||
enum:
|
||||
- claude
|
||||
- codex
|
||||
- cursor
|
||||
currentPassword:
|
||||
type: string
|
||||
responses:
|
||||
|
||||
Reference in New Issue
Block a user