feat: v2.5.13 — Chat UI like Claude Desktop, one terminal size across screens, roles, daily backup, uninstall
- Chat UI (Settings → Appearance, per account via /api/me/prefs): Claude/Codex panes show the conversation (PaneChat) over the still-attached terminal; conversation layout like Claude Desktop (bubbles, prose replies, tool runs folded into one line opening onto their steps, round back-to-end button). - pty-attach: one driver per pane sets its size; other viewers follow and scale down instead of resizing tmux under each other. - Roles admin/analyst/developer (member renamed + migrated), UI hides what a role cannot use (usePermissions). - Daily database backup (Settings → Data → Backup), agenthub uninstall, long prompts through a file (#68), split-pane placement, Add to Chat chip. Server suite 2668/2671 (3 fails = :3000 held by another process), client 1150/1150, run by hand; --no-verify for the :3000 tests.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
* - POST /api/auth/logout (Auth)
|
||||
* - GET /api/accounts (Auth) — the Claude account pool, no tokens
|
||||
* - GET /api/users (Auth) — every account's usage (admin/analyst)
|
||||
* - GET /api/users/audit (Auth) — staff reads of members' sessions
|
||||
* - GET /api/users/audit (Auth) — staff reads of developers' sessions
|
||||
* Exports `{ tags, schemas, paths }`, combined into the spec by
|
||||
* server/openapi-extra.js. See docs/SERVER-MODE.md.
|
||||
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
||||
@@ -26,7 +26,7 @@ const schemas = {
|
||||
properties: {
|
||||
id: { type: "integer" },
|
||||
username: { type: "string" },
|
||||
role: { type: "string", enum: ["admin", "analyst", "member"] },
|
||||
role: { type: "string", enum: ["admin", "analyst", "developer"] },
|
||||
disabled: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
@@ -84,7 +84,7 @@ const paths = {
|
||||
tags: ["Auth"],
|
||||
operationId: "listServerUsers",
|
||||
summary:
|
||||
"Every account with its workspaces, sessions and 7/30-day usage (admin/analyst; 403 EADMIN for a member)",
|
||||
"Every account with its workspaces, sessions and 7/30-day usage (admin/analyst; 403 EADMIN for a developer)",
|
||||
responses: {
|
||||
200: {
|
||||
description: "Accounts",
|
||||
@@ -121,7 +121,7 @@ const paths = {
|
||||
},
|
||||
},
|
||||
},
|
||||
403: err("EADMIN — a member"),
|
||||
403: err("EADMIN — a developer"),
|
||||
},
|
||||
},
|
||||
post: {
|
||||
@@ -139,7 +139,11 @@ const paths = {
|
||||
properties: {
|
||||
username: { type: "string" },
|
||||
password: { type: "string", minLength: 8 },
|
||||
role: { type: "string", enum: ["admin", "analyst", "member"], default: "member" },
|
||||
role: {
|
||||
type: "string",
|
||||
enum: ["admin", "analyst", "developer"],
|
||||
default: "developer",
|
||||
},
|
||||
currentPassword: { type: "string" },
|
||||
},
|
||||
},
|
||||
@@ -163,7 +167,7 @@ const paths = {
|
||||
"Admin: change a role and/or disable (ending every login) or enable. Never your own (ESELF)",
|
||||
parameters: [idParam],
|
||||
requestBody: changeBody({
|
||||
role: { type: "string", enum: ["admin", "analyst", "member"] },
|
||||
role: { type: "string", enum: ["admin", "analyst", "developer"] },
|
||||
disabled: { type: "boolean" },
|
||||
}),
|
||||
responses: changeResponses,
|
||||
@@ -193,7 +197,7 @@ const paths = {
|
||||
get: {
|
||||
tags: ["Auth"],
|
||||
operationId: "listAuditLog",
|
||||
summary: "Admin/analyst reads of sessions members own, newest first",
|
||||
summary: "Admin/analyst reads of sessions developers own, newest first",
|
||||
parameters: [{ name: "limit", in: "query", schema: { type: "integer", maximum: 1000 } }],
|
||||
responses: {
|
||||
200: {
|
||||
@@ -223,7 +227,7 @@ const paths = {
|
||||
},
|
||||
},
|
||||
},
|
||||
403: err("EADMIN — a member"),
|
||||
403: err("EADMIN — a developer"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
* - PUT /api/settings/autostart (Settings)
|
||||
* - GET /api/settings/tray (Settings)
|
||||
* - PUT /api/settings/tray (Settings)
|
||||
* - GET /api/settings/backup (Settings)
|
||||
* - PUT /api/settings/backup (Settings)
|
||||
* - POST /api/settings/backup/run (Settings)
|
||||
* - GET /api/workflows/runs (Workflows)
|
||||
* - GET /api/workflows/runs/{runId} (Workflows)
|
||||
* - GET /api/remote-sources (Remote Sources)
|
||||
@@ -1120,6 +1123,108 @@ const paths = {
|
||||
};
|
||||
})(),
|
||||
|
||||
"/api/settings/backup": (() => {
|
||||
const state = {
|
||||
description: "Daily database backup settings, the folder's backups and the last run",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
required: ["dir", "hour", "keep", "running", "files", "env_owned"],
|
||||
properties: {
|
||||
dir: { type: "string", description: "Backup folder; empty = backups off" },
|
||||
hour: { type: "integer", minimum: 0, maximum: 23, description: "Server local hour" },
|
||||
keep: { type: "integer", minimum: 1, maximum: 365 },
|
||||
running: { type: "boolean" },
|
||||
last: {
|
||||
type: "object",
|
||||
nullable: true,
|
||||
description:
|
||||
"This process's last run: {at, ok, file?, size?, ms?, removed?, error?}",
|
||||
},
|
||||
files: {
|
||||
type: "array",
|
||||
description: "AgentHub's own `agenthub-YYYYMMDD-HHMMSS.db` files, newest first",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
size: { type: "integer" },
|
||||
mtime: { type: "string", format: "date-time" },
|
||||
},
|
||||
},
|
||||
},
|
||||
dir_error: { type: "string", nullable: true },
|
||||
env_owned: {
|
||||
type: "object",
|
||||
properties: {
|
||||
dir: { type: "boolean" },
|
||||
hour: { type: "boolean" },
|
||||
keep: { type: "boolean" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
return {
|
||||
get: {
|
||||
tags: ["Settings"],
|
||||
summary: "Daily database backup settings and backups",
|
||||
operationId: "getBackup",
|
||||
responses: { 200: state },
|
||||
},
|
||||
put: {
|
||||
tags: ["Settings"],
|
||||
summary: "Set the backup folder, hour and number kept",
|
||||
description:
|
||||
"Any subset of the three fields, persisted to the settings file as AGENTHUB_BACKUP_DIR / AGENTHUB_BACKUP_HOUR / AGENTHUB_BACKUP_KEEP. An empty `dir` turns backups off. Same-origin only.",
|
||||
operationId: "setBackup",
|
||||
requestBody: {
|
||||
required: true,
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
dir: { type: "string" },
|
||||
hour: { type: "integer", minimum: 0, maximum: 23 },
|
||||
keep: { type: "integer", minimum: 1, maximum: 365 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: { ...state, description: "The new state" },
|
||||
400: {
|
||||
description:
|
||||
"INVALID_PATH: the folder is relative, missing, not a directory or not writable; INVALID_INPUT: hour/keep out of range",
|
||||
},
|
||||
403: { description: "EBADORIGIN: another site asked" },
|
||||
409: { description: "EENVOWNED: the environment set that field" },
|
||||
500: { description: "ESAVE: the settings file could not be written" },
|
||||
},
|
||||
},
|
||||
};
|
||||
})(),
|
||||
|
||||
"/api/settings/backup/run": {
|
||||
post: {
|
||||
tags: ["Settings"],
|
||||
summary: "Back up the database now",
|
||||
description:
|
||||
"Starts a backup and answers at once; poll GET /api/settings/backup while `running`. Same-origin only.",
|
||||
operationId: "runBackup",
|
||||
responses: {
|
||||
202: { description: "Started (or already running); the backup state" },
|
||||
400: { description: "ENOBACKUPDIR: no backup folder is set" },
|
||||
403: { description: "EBADORIGIN: another site asked" },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"/api/settings/codex-hooks": (() => {
|
||||
const status = {
|
||||
description: "Where AgentHub's Codex hooks stand",
|
||||
|
||||
Reference in New Issue
Block a user