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:
2026-10-08 23:04:57 +07:00
parent a9c71cd905
commit b7f3735b29
147 changed files with 5644 additions and 2561 deletions
+105
View File
@@ -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",