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
+12 -8
View File
@@ -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"),
},
},
},