feat: workspaces own their sessions; desktop parity; sidebar and settings cleanup

Workspace sessions (docs/plans/desktop-parity, phases 1-5 and 7):
- sessions.lane_id: a workspace lists only the sessions its panes held,
  stamped by bindRunSession (first writer wins, nested `claude -p`
  excluded); GET /api/sessions?lane=&archived=
- session row state dot, double-click rename, archive (sessions.archived_at,
  hides only); the activity bar's duplicate Sessions tab removed
- Fork beside Resume (--fork-session, Claude only), Ctrl/Cmd+click a live
  session opens it in a second pane, a diff line's comment is pasted into
  the workspace's last-focused pane (lib/panePaste.ts)

dashboard_runs stability:
- a pane's previous run is archived as <pane>@<started_at> instead of being
  overwritten by INSERT OR REPLACE
- a run is flagged abandoned only once its tmux session is gone, at boot and
  on the run-heal beat (panes outlive a server restart)

UI:
- sidebar: no footer, language or theme block; small collapse button in the
  brand corner; version + update check in the connection details modal, a
  status-bar dot while a release is out; language in Settings -> General
- one Switch component for every switch, the themed Checkbox for every
  checkbox (no native checkboxes)

Also: AI Tools catalog trimmed to 10 built-ins (custom-file prompt modes
tested through fixtures), and the workspace plans under docs/plans/ (the
multi-user server plan lives in the AgentHub-Server repo).
This commit is contained in:
2026-10-02 12:05:00 +07:00
parent 5b269698f6
commit a6bd33bcff
121 changed files with 2699 additions and 1552 deletions
+16 -4
View File
@@ -88,6 +88,11 @@
"changes.expandFile": "Expand {{path}}",
"changes.fileGone": "That file no longer has changes in this range.",
"changes.fileTruncated": "Diff cut short — open the file in an editor for the rest.",
"changes.commentLine": "Comment on line {{n}} — pasted into this workspace's pane",
"changes.commentOn": "Comment on {{at}} — pasted into the pane you used last; nothing is sent until you press Enter there",
"changes.commentSend": "Paste into pane",
"changes.commentCancel": "Cancel",
"changes.commentNoPane": "No pane of this workspace is open — open its session first",
"changes.layout.split": "Side-by-side",
"changes.layout.unified": "Unified",
"changes.loading": "Reading the working copy…",
@@ -325,16 +330,17 @@
"pane.close": "Stop this pane's session",
"panel.files": "Files",
"panel.changes": "Changes",
"panel.sessions": "Sessions",
"sessions.empty": "No sessions in this workspace yet",
"sessions.resume": "Resume",
"sessions.open": "Open",
"resume.openPane": "Open pane",
"resume.hint": "Resume this session in a workspace pane — re-reads its whole transcript into context",
"resume.title": "Resume this session?",
"resume.body": "Resuming re-reads the session's whole transcript into the model's context, so its next turns pay for all of it again. It opens in the first free pane of {{workspace}}. To only read it, stay on this page.",
"resume.confirm": "Resume session",
"sessions.search": "Filter sessions…",
"resume.fork": "Fork",
"resume.forkHint": "Continue from here as a NEW session — the original stays as it is",
"resume.forkTitle": "Fork this session?",
"resume.forkBody": "A fork re-reads the session's whole transcript into a NEW session (its own id), so its turns pay for all of it again; the original is left untouched. It opens in the first free pane of {{workspace}}.",
"resume.forkConfirm": "Fork session",
"tree.title": "Workspaces",
"tree.search": "Search workspaces and sessions",
"tree.toolFilter": "Filter by tool",
@@ -342,6 +348,12 @@
"tree.newSession": "New session",
"tree.noSessions": "No sessions yet",
"tree.transcriptHint": "No live pane — opens the transcript",
"tree.splitHint": "Live pane — Ctrl/Cmd+click opens it in a second pane",
"tree.renameSession": "Rename session",
"tree.archiveSession": "Archive — hide from this workspace (deletes nothing)",
"tree.archived_one": "{{count}} archived session",
"tree.archived_other": "{{count}} archived sessions",
"tree.unarchive": "Unarchive",
"home.breadcrumb": "Workspaces",
"home.repoRoot": "Repository root",
"home.mainBranch": "Main worktree's branch",
+2 -10
View File
@@ -11,7 +11,6 @@
"checkingForUpdates": "Checking for updates...",
"close": "Close",
"collapse": "Collapse sidebar",
"collapseShort": "Collapse",
"connection": "Connection",
"connectionDetails": "Connection details",
"connectionUptime": "Connected",
@@ -49,14 +48,6 @@
"settings": "Settings",
"skipToContent": "Skip to content",
"statsPersisted": "Stats persist across reloads",
"switchLanguage": "Switch to {{language}}",
"switchTheme": "Switch to {{theme}}",
"theme": "Theme",
"themeNames": {
"dark": "Dark",
"light": "Light",
"system": "System"
},
"throughput60s": "Throughput · last 60s",
"topEventTypes": "Top event types",
"unitEvents": "events",
@@ -74,5 +65,6 @@
"running": "{{count}} running",
"needYou": "{{count}} need you",
"today": "Today {{cost}}"
}
},
"version": "Version"
}
+9
View File
@@ -710,5 +710,14 @@
"claudeDesc": "Worktrees under <repo>/.claude/worktrees/, made by Claude Code's own agents.",
"agenthub": "AgentHub-managed worktrees",
"agenthubDesc": "Worktrees AgentHub created under its workspaces root."
},
"language": {
"title": "Language",
"description": "The language of the whole dashboard, remembered in this browser.",
"label": "Interface language",
"names": {
"en": "English",
"vi": "Tiếng Việt"
}
}
}
+16 -4
View File
@@ -88,6 +88,11 @@
"changes.expandFile": "Mở {{path}}",
"changes.fileGone": "File này không còn thay đổi nào trong phạm vi đang xem.",
"changes.fileTruncated": "Diff bị cắt bớt — mở file trong editor để xem phần còn lại.",
"changes.commentLine": "Comment dòng {{n}} — dán vào pane của workspace này",
"changes.commentOn": "Comment {{at}} — dán vào pane bạn dùng gần nhất; chưa gửi gì cho tới khi bạn nhấn Enter ở đó",
"changes.commentSend": "Dán vào pane",
"changes.commentCancel": "Huỷ",
"changes.commentNoPane": "Workspace này chưa mở pane nào — hãy mở session trước",
"changes.layout.split": "Hai cột",
"changes.layout.unified": "Một cột",
"changes.loading": "Đang đọc working copy…",
@@ -325,16 +330,17 @@
"pane.close": "Dừng phiên của ô này",
"panel.files": "Tệp",
"panel.changes": "Thay đổi",
"panel.sessions": "Phiên",
"sessions.empty": "Chưa có phiên nào trong workspace này",
"sessions.resume": "Tiếp tục",
"sessions.open": "Mở",
"resume.openPane": "Mở pane",
"resume.hint": "Tiếp tục session này trong một pane của workspace — nạp lại toàn bộ transcript vào context",
"resume.title": "Tiếp tục session này?",
"resume.body": "Tiếp tục sẽ nạp lại toàn bộ transcript của session vào context của model, nên các lượt sau phải trả lại chi phí cho tất cả phần đó. Session mở ở pane trống đầu tiên của {{workspace}}. Nếu chỉ cần đọc, hãy ở lại trang này.",
"resume.confirm": "Tiếp tục session",
"sessions.search": "Lọc phiên…",
"resume.fork": "Fork",
"resume.forkHint": "Tiếp tục từ đây thành một session MỚI — session gốc giữ nguyên",
"resume.forkTitle": "Fork session này?",
"resume.forkBody": "Fork nạp lại toàn bộ transcript vào một session MỚI (id riêng), nên các lượt sau phải trả lại chi phí cho tất cả phần đó; session gốc không bị đụng tới. Session mở ở pane trống đầu tiên của {{workspace}}.",
"resume.forkConfirm": "Fork session",
"tree.title": "Không gian làm việc",
"tree.search": "Tìm workspace và session",
"tree.toolFilter": "Lọc theo tool",
@@ -342,6 +348,12 @@
"tree.newSession": "Session mới",
"tree.noSessions": "Chưa có session",
"tree.transcriptHint": "Không còn pane — mở transcript",
"tree.splitHint": "Pane đang chạy — Ctrl/Cmd+click để mở ở pane thứ hai",
"tree.renameSession": "Đổi tên session",
"tree.archiveSession": "Lưu trữ — ẩn khỏi workspace này (không xoá gì)",
"tree.archived_one": "{{count}} session đã lưu trữ",
"tree.archived_other": "{{count}} session đã lưu trữ",
"tree.unarchive": "Bỏ lưu trữ",
"home.breadcrumb": "Không gian làm việc",
"home.repoRoot": "Thư mục gốc của repo",
"home.mainBranch": "Branch của worktree chính",
+2 -10
View File
@@ -11,7 +11,6 @@
"checkingForUpdates": "Đang kiểm tra cập nhật...",
"close": "Đóng",
"collapse": "Thu gọn thanh bên",
"collapseShort": "Thu gọn",
"connection": "Kết nối",
"connectionDetails": "Chi tiết kết nối",
"connectionUptime": "Đã kết nối",
@@ -49,14 +48,6 @@
"settings": "Cài đặt",
"skipToContent": "Bỏ qua đến nội dung",
"statsPersisted": "Số liệu được lưu sau khi tải lại",
"switchLanguage": "Chuyển sang {{language}}",
"switchTheme": "Chuyển sang {{theme}}",
"theme": "Giao diện",
"themeNames": {
"dark": "Tối",
"light": "Sáng",
"system": "Theo hệ thống"
},
"throughput60s": "Lưu lượng · 60s qua",
"topEventTypes": "Loại sự kiện phổ biến",
"unitEvents": "sự kiện",
@@ -74,5 +65,6 @@
"running": "{{count}} đang chạy",
"needYou": "{{count}} cần bạn",
"today": "Hôm nay {{cost}}"
}
},
"version": "Phiên bản"
}
+9
View File
@@ -710,5 +710,14 @@
"claudeDesc": "Worktree dưới <repo>/.claude/worktrees/, do agent của Claude Code tạo.",
"agenthub": "Worktree do AgentHub quản lý",
"agenthubDesc": "Worktree AgentHub tạo dưới thư mục gốc workspace của nó."
},
"language": {
"title": "Ngôn ngữ",
"description": "Ngôn ngữ của toàn bộ dashboard, được ghi nhớ trong trình duyệt này.",
"label": "Ngôn ngữ giao diện",
"names": {
"en": "English",
"vi": "Tiếng Việt"
}
}
}