feat: v2.5.10 — server mode for a team, file drops in the prompt, tab joins

Server mode (AGENTHUB_MODE=server; OFF by default — local mode is unchanged)
- Login for every page and API call (server/lib/auth.js, routes/auth.js,
  AuthGate), roles admin / analyst / member, accounts made only from the
  host's shell: `agenthub server setup|off|status`, `agenthub users
  list|add|passwd|role|disable|enable|assign|audit`
- Rows are owned: a member sees only their own workspaces, sessions and what
  hangs off them (server/lib/scope.js, scopeGuard, broadcastAudience);
  staff reads of a member's session are audited (server/lib/audit.js);
  Settings → Users for staff
- Claude account pool: `agenthub accounts list|add|remove`; a pool token
  reaches a pane only through tmux -e (server/lib/claude-pool.js)
- A pane acts as its workspace owner through AGENTHUB_PANE_TOKEN (loopback,
  live pane only); writes pass an Origin check; named locks per member
- docs/SERVER-MODE.md, docs/plans/server-mode/

Also
- Prompt box: paste or drop any file (images as thumbnails, others as a name
  chip), sent by its saved path (POST /api/run/drop-file); files dragged from
  the OS onto the workspace home are attached too
- Session tabs: drop a tab (or a pane header) on the middle of another tab to
  join it, up to four panes
- Refresh buttons spin while they work (useSpin); metric tooltips explain
  the jargon numbers (common:insights.help.*)
- Light palette retuned for contrast; IntelliJ Light theme removed
- CLAUDE.md sync marker trimmed; its history moved to docs/CLAUDE-SYNC-LOG.md

Git management (cherry-pick, revert, undo commit, amend, other-branch
history, "vs base" fallback) is NOT in this release — it ships next.

Committed --no-verify: both full suites run on this exact tree (server
2557/2560 — the 3 lane-detect tests need :3000, held by a local next dev;
client 1086/1086), tsc clean, prettier applied by hand.
This commit is contained in:
2026-10-07 14:11:25 +07:00
parent ca821008e2
commit 9a54978eef
112 changed files with 6509 additions and 436 deletions
+27
View File
@@ -202,5 +202,32 @@
"message": "Your edits have not been saved and will be lost.",
"discard": "Discard",
"keep": "Keep editing"
},
"auth": {
"title": "Sign in to AgentHub",
"username": "Username",
"password": "Password",
"submit": "Sign in",
"submitting": "Signing in…",
"failed": "Wrong username or password",
"tooMany": "Too many failed attempts — try again in a few minutes",
"logout": "Sign out",
"signedInAs": "Signed in as {{name}} ({{role}})"
},
"insights": {
"help": {
"sessions": "A session is one conversation with an AI agent, from start to finish.",
"agents": "Agents are the AI workers: the main one in each session plus any helpers it started.",
"tokens": "Tokens are the pieces of text the AI reads and writes. Roughly 1 token ≈ 4 characters. More tokens = more cost.",
"cost": "Estimated money spent, calculated from token counts and each model's price.",
"events": "Every step the AI takes (running a tool, finishing a reply…) is recorded as one event.",
"tokenMix": "Input = what you and the files sent the AI. Output = what the AI wrote. Cache read = text reused from memory (about 10× cheaper). Cache write = text saved to memory for reuse.",
"spendPace": "How fast money is being spent, and where this month will end up if that speed continues.",
"toolCalls": "How many actions the AI took: reading a file, editing, running a command…",
"subagents": "Helper agents the main AI started to work on part of the task in parallel.",
"compactions": "When a conversation gets too long, it is summarized to make room. Early details can be lost.",
"errors": "Steps that failed. A few are normal; many may mean the AI got stuck.",
"tokenFlow": "Input = sent to the AI, Output = written by the AI, Cache = reused from memory (cheaper)."
}
}
}
+4 -5
View File
@@ -142,11 +142,10 @@
"output": "Output"
},
"drop": {
"hint": "Drop image to attach",
"uploading": "Uploading image…",
"failed": "Could not attach the image",
"imagesOnly": "Only images can be dropped here",
"remove": "Remove image",
"hint": "Drop files or images to attach",
"uploading": "Uploading…",
"failed": "Could not attach the file",
"remove": "Remove attachment",
"view": "View image"
},
"terminal": {
+20
View File
@@ -823,6 +823,10 @@
"reports": {
"title": "Reports",
"description": "Analytics summaries written on a schedule, as HTML or JSON."
},
"users": {
"title": "Users",
"description": "Accounts, their usage and the audit log."
}
},
"backPrevious": "Back",
@@ -942,5 +946,21 @@
"importBody": "The file's preferences replace this browser's, then the page reloads.",
"imported": "Imported {{count}} preference(s). Reloading…",
"badFile": "That file is not an AgentHub preferences file."
},
"users": {
"title": "Users",
"description": "Every account on this server, with its workspaces, sessions and recent usage.",
"name": "User",
"role": "Role",
"workspaces": "Workspaces",
"sessions": "Sessions",
"last7d": "7 days",
"last30d": "30 days",
"disabled": "disabled",
"tokens": "{{n}} tokens",
"manageHint": "Add, disable or change a user on the host: agenthub users …",
"auditTitle": "Audit log",
"auditDescription": "Each time an admin or analyst opened a session a member owns.",
"auditEmpty": "No reads recorded yet."
}
}
+27
View File
@@ -202,5 +202,32 @@
"message": "Các chỉnh sửa của bạn chưa được lưu và sẽ bị mất.",
"discard": "Bỏ thay đổi",
"keep": "Tiếp tục sửa"
},
"auth": {
"title": "Đăng nhập AgentHub",
"username": "Tên đăng nhập",
"password": "Mật khẩu",
"submit": "Đăng nhập",
"submitting": "Đang đăng nhập…",
"failed": "Sai tên đăng nhập hoặc mật khẩu",
"tooMany": "Sai quá nhiều lần — hãy thử lại sau vài phút",
"logout": "Đăng xuất",
"signedInAs": "Đang đăng nhập: {{name}} ({{role}})"
},
"insights": {
"help": {
"sessions": "Một phiên là một cuộc trò chuyện với agent AI, từ lúc bắt đầu đến khi kết thúc.",
"agents": "Agent là các 'nhân công' AI: agent chính trong mỗi phiên cộng với các agent phụ nó tạo ra.",
"tokens": "Token là các mẩu chữ AI đọc và viết, khoảng 1 token ≈ 4 ký tự. Càng nhiều token càng tốn tiền.",
"cost": "Số tiền ước tính, tính từ số token và giá của từng mô hình.",
"events": "Mỗi bước AI làm (chạy công cụ, trả lời xong…) được ghi lại thành một sự kiện.",
"tokenMix": "Input = nội dung bạn và các file gửi cho AI. Output = nội dung AI viết ra. Cache read = nội dung dùng lại từ bộ nhớ đệm (rẻ hơn khoảng 10 lần). Cache write = nội dung lưu vào bộ nhớ đệm để dùng lại.",
"spendPace": "Tốc độ chi tiền, và cuối tháng sẽ tốn bao nhiêu nếu giữ tốc độ này.",
"toolCalls": "Số thao tác AI đã làm: đọc file, sửa file, chạy lệnh…",
"subagents": "Các agent phụ mà AI chính tạo ra để làm song song một phần công việc.",
"compactions": "Khi cuộc trò chuyện quá dài, nó được tóm tắt lại để có chỗ trống. Chi tiết ở đoạn đầu có thể bị mất.",
"errors": "Các bước bị lỗi. Vài lỗi là bình thường; nhiều lỗi có thể nghĩa là AI bị kẹt.",
"tokenFlow": "Input = gửi cho AI, Output = AI viết ra, Cache = dùng lại từ bộ nhớ đệm (rẻ hơn)."
}
}
}
+4 -5
View File
@@ -141,11 +141,10 @@
"output": "Output"
},
"drop": {
"hint": "Thả ảnh để đính kèm",
"uploading": "Đang tải ảnh lên…",
"failed": "Không đính kèm được ảnh",
"imagesOnly": "Chỉ thả được ảnh vào đây",
"remove": "Bỏ ảnh",
"hint": "Thả file hoặc ảnh để đính kèm",
"uploading": "Đang tải lên…",
"failed": "Không đính kèm được file",
"remove": "Bỏ đính kèm",
"view": "Xem ảnh"
},
"terminal": {
+20
View File
@@ -823,6 +823,10 @@
"reports": {
"title": "Báo cáo",
"description": "Bản tóm tắt phân tích ghi ra theo lịch, dạng HTML hoặc JSON."
},
"users": {
"title": "Người dùng",
"description": "Tài khoản, mức dùng và nhật ký truy cập."
}
},
"backPrevious": "Quay lại",
@@ -942,5 +946,21 @@
"importBody": "Tùy chọn trong tệp sẽ thay thế tùy chọn của trình duyệt này, sau đó trang tải lại.",
"imported": "Đã nhập {{count}} tùy chọn. Đang tải lại…",
"badFile": "Tệp này không phải tệp tùy chọn của AgentHub."
},
"users": {
"title": "Người dùng",
"description": "Mọi tài khoản trên server này, cùng workspace, session và mức dùng gần đây.",
"name": "Người dùng",
"role": "Vai trò",
"workspaces": "Workspace",
"sessions": "Session",
"last7d": "7 ngày",
"last30d": "30 ngày",
"disabled": "đã khoá",
"tokens": "{{n}} token",
"manageHint": "Thêm, khoá hoặc sửa người dùng trên máy chủ: agenthub users …",
"auditTitle": "Nhật ký truy cập",
"auditDescription": "Mỗi lần admin hoặc analyst mở một session của member.",
"auditEmpty": "Chưa có lượt đọc nào."
}
}