feat: workspace aliases, tab groups of split panes, native path picker (v2.1.0)

- /api/workspaces and `agenthub workspace(s)` / `--workspace` as aliases of
  /api/lanes and `agenthub lanes` / `--lane`; old names print one stderr note.
  REPL `help lanes|workspace|workspaces` resolves through the aliases.
- A workspace holds up to ten sessions (slots 0-9); every console tab is a
  group of 1-4 split panes (PaneGroups, agenthub.workspace.paneLayout);
  parseGroups keeps the stored active tab when an earlier one is dropped.
- Browse button beside path fields: POST /api/lanes/pick-path opens the OS
  picker on the server's desktop — loopback only and no forwarding header
  (EREMOTE), a display failure is ENODIALOG not a Cancel, the dialog is
  killed when the request closes, a folder field falls back to the in-app
  browser on any failure.
- Changes rail counts chip, image viewer (/git/raw), status bar session
  counts and per-day cost (`date=` on /api/pricing/cost).
- /agenthub-open and /agenthub-doctor run from the INSTALLED build
  (supersededBy), doctor offers fixes behind two confirmations; plugin-open
  treats a locked bootstrap as non-fatal.
- New-terminal shell waits for the first attach (issue #55).
- repo-onboarding / debug-live-issue skills removed.
- OpenAPI: pick-path, lane/date on /pricing/cost, tool on /run/history,
  /api/workspaces mount.
This commit is contained in:
2026-10-06 11:31:26 +07:00
parent c067abc68f
commit 6c605849d8
104 changed files with 3478 additions and 1396 deletions
+10 -10
View File
@@ -45,8 +45,10 @@
"addLaneWorktreesTitle": "Worktrees of this repo ({{count}})",
"browse.button": "Browse",
"browse.empty": "This folder is empty.",
"browse.fileTitle": "Browse for a file",
"browse.select": "Select this folder",
"browse.title": "Browse for a folder",
"browse.typePath": "No native picker is available here — type the path instead.",
"changes.back": "All files",
"changes.bin": "bin",
"changes.binary": "Binary file — not shown.",
@@ -241,6 +243,7 @@
"changes.nextHunk": "Next change",
"changes.hunkOf": "{{n}} of {{total}}",
"changes.noEditBinary": "Binary file — not editable here",
"changes.imageFailed": "Could not show this image (deleted, or larger than 20 MB).",
"changes.noEditTooBig": "Too large to edit here (over 1 MB)",
"changes.noEdit": "Not editable here",
"gitBar.loginTitle": "Git needs a login for {{host}}",
@@ -291,8 +294,6 @@
"changes.takeTheirsHint": "Take the incoming version of the whole file",
"row.actions": "Workspace actions",
"row.hint": "Double-click to rename · drag or Alt+↑/↓ to reorder · right-click for actions",
"menu.start": "Start",
"menu.stop": "Stop",
"menu.rename": "Rename",
"menu.newHere": "New workspace here…",
"menu.copyPath": "Copy path",
@@ -321,6 +322,7 @@
"tree.allTools": "All tools",
"tree.newSession": "New session",
"tree.noSessions": "No sessions yet",
"tree.closedTerminal": "Closed terminal — click opens a new one in this workspace's folder (Ctrl/Cmd+click: in a split)",
"tree.transcriptHint": "No live pane — opens its conversation; a message you send resumes it",
"tree.splitHint": "Live pane — Ctrl/Cmd+click opens it in a split beside the focused pane",
"tree.renameSession": "Rename session",
@@ -349,7 +351,7 @@
"home.localHint": "Work in the workspace folder itself",
"home.worktree": "New worktree",
"home.worktreeHint": "Run this session in its own git worktree — <repo>/.claude/worktrees/, a branch of its own, made and cleaned up by Claude Code",
"home.allBusy": "All four panes of this workspace are busy — stop one before starting another session.",
"home.allBusy": "All 10 sessions of this workspace are in use — stop one before starting another.",
"home.recents": "Recents",
"home.noRecents": "No sessions yet — start one above.",
"home.instructions": "Instructions",
@@ -380,7 +382,7 @@
"tabs.newTerminal": "New terminal",
"tabs.terminal": "Terminal",
"tabs.close": "Close tab (stops its session)",
"tabs.full": "All 4 tabs are in use — close one first",
"tabs.full": "All 10 sessions are in use — stop one first",
"tabs.agentSettings": "Agent settings…",
"tabs.splitHint": "Ctrl/Cmd+click: open in a split · drag onto a pane to place it",
"panes.drag": "Drag to move this pane — onto another pane's edge to split there, onto its middle to swap",
@@ -388,9 +390,9 @@
"panes.empty": "No session",
"panes.split.right": "Split right",
"panes.split.bottom": "Split down",
"panes.full": "4 panes is the most a workspace can show",
"panes.full": "A tab holds at most 4 panes",
"panes.newTerminal": "New terminal",
"panes.close": "Hide pane (its session keeps running as a tab)",
"panes.close": "Move to its own tab (the session keeps running)",
"panes.resize": "Resize panes",
"tabs.home": "Workspace home",
"sessionMenu.open": "Open",
@@ -401,7 +403,7 @@
"panes.show": "Show {{name}} here",
"panes.splitNew.right": "Split right with a new terminal",
"panes.splitNew.bottom": "Split down with a new terminal",
"panes.closeShort": "Hide pane",
"panes.closeShort": "Move to own tab",
"changes.copyPath": "Copy relative path",
"changes.viewCommit": "View commit",
"changes.copySha": "Copy commit SHA",
@@ -414,6 +416,7 @@
"tabs.state.running": "Running",
"tabs.renameHint": "Double-click to rename",
"tabs.stopTitle": "Stop “{{name}}”?",
"tabs.stopGroupTitle": "Stop the {{count}} sessions in this tab?",
"tabs.stopBody": "Closing the tab stops its session, even mid-turn. It can be resumed later from Recents.",
"tabs.stopConfirm": "Stop session",
"changes.loadMore": "Load more commits",
@@ -434,9 +437,6 @@
"row.state.running": "running",
"row.state.active": "active",
"row.state.idle": "idle",
"menu.stopTitle_one": "Stop the running session?",
"menu.stopTitle_other": "Stop {{count}} running sessions?",
"menu.stopBody": "Every tab of this workspace stops, even mid-turn. Its sessions can be resumed later from Recents.",
"gitBar.done.fetch": "Fetched",
"gitBar.done.pull": "Pulled",
"gitBar.done.push": "Pushed",
+2 -1
View File
@@ -66,7 +66,8 @@
"needYou": "{{count}} need you",
"today": "Today {{cost}}",
"workspace": "Workspace {{cost}}",
"session": "Session {{cost}}"
"session": "Session {{cost}}",
"tokens": "({{tokens}} Tokens)"
},
"version": "Version",
"openMenu": "Open menu",
+10 -10
View File
@@ -45,8 +45,10 @@
"addLaneWorktreesTitle": "Worktree của repo này ({{count}})",
"browse.button": "Duyệt",
"browse.empty": "Thư mục này trống.",
"browse.fileTitle": "Duyệt chọn tệp",
"browse.select": "Chọn thư mục này",
"browse.title": "Duyệt chọn thư mục",
"browse.typePath": "Không mở được hộp thoại chọn của hệ điều hành ở đây — hãy gõ đường dẫn.",
"changes.back": "Tất cả file",
"changes.bin": "bin",
"changes.binary": "File nhị phân — không hiển thị.",
@@ -241,6 +243,7 @@
"changes.nextHunk": "Thay đổi sau",
"changes.hunkOf": "{{n}} / {{total}}",
"changes.noEditBinary": "File nhị phân — không sửa được ở đây",
"changes.imageFailed": "Không hiển thị được ảnh này (đã bị xoá, hoặc lớn hơn 20 MB).",
"changes.noEditTooBig": "File quá lớn để sửa ở đây (trên 1 MB)",
"changes.noEdit": "Không sửa được ở đây",
"gitBar.loginTitle": "Git cần đăng nhập {{host}}",
@@ -291,8 +294,6 @@
"changes.takeTheirsHint": "Lấy bản kia cho cả file",
"row.actions": "Thao tác workspace",
"row.hint": "Nhấp đúp để đổi tên · kéo hoặc Alt+↑/↓ để sắp xếp · chuột phải để xem thao tác",
"menu.start": "Bắt đầu",
"menu.stop": "Dừng",
"menu.rename": "Đổi tên",
"menu.newHere": "Workspace mới tại đây…",
"menu.copyPath": "Sao chép đường dẫn",
@@ -321,6 +322,7 @@
"tree.allTools": "Mọi tool",
"tree.newSession": "Session mới",
"tree.noSessions": "Chưa có session",
"tree.closedTerminal": "Terminal đã đóng — bấm để mở terminal mới ở thư mục của workspace (Ctrl/Cmd+click: mở ở split)",
"tree.transcriptHint": "Không còn pane — mở hội thoại; gửi tin nhắn sẽ tiếp tục (resume) session",
"tree.splitHint": "Pane đang chạy — Ctrl/Cmd+click để mở ở split cạnh pane đang focus",
"tree.renameSession": "Đổi tên session",
@@ -349,7 +351,7 @@
"home.localHint": "Làm việc ngay trong thư mục của workspace",
"home.worktree": "Worktree mới",
"home.worktreeHint": "Chạy session này trong worktree git riêng — <repo>/.claude/worktrees/, branch riêng, do Claude Code tạo và dọn",
"home.allBusy": "Cả bốn pane của workspace này đang bận — hãy dừng một pane trước khi mở session mới.",
"home.allBusy": "Workspace này đã dùng hết 10 session — hãy dừng một session trước khi mở session mới.",
"home.recents": "Gần đây",
"home.noRecents": "Chưa có session nào — bắt đầu ở ô phía trên.",
"home.instructions": "Hướng dẫn",
@@ -380,7 +382,7 @@
"tabs.newTerminal": "Terminal mới",
"tabs.terminal": "Terminal",
"tabs.close": "Đóng tab (dừng phiên của nó)",
"tabs.full": "Đã dùng hết 4 tab — hãy đóng bớt một tab",
"tabs.full": "Đã dùng hết 10 session — hãy dừng bớt một session",
"tabs.agentSettings": "Cài đặt agent…",
"tabs.splitHint": "Ctrl/Cmd+click: mở ở split · kéo thả vào một pane để đặt vị trí",
"panes.drag": "Kéo để di chuyển pane — thả vào cạnh pane khác để tách ở đó, vào giữa để đổi chỗ",
@@ -388,9 +390,9 @@
"panes.empty": "Không có session",
"panes.split.right": "Tách sang phải",
"panes.split.bottom": "Tách xuống dưới",
"panes.full": "Một workspace hiện tối đa 4 pane",
"panes.full": "Một tab chứa tối đa 4 pane",
"panes.newTerminal": "Terminal mới",
"panes.close": "Ẩn pane (session vẫn chạy dưới dạng tab)",
"panes.close": "Tách ra tab riêng (session vẫn chạy)",
"panes.resize": "Đổi kích thước pane",
"tabs.home": "Trang chủ workspace",
"sessionMenu.open": "Mở",
@@ -401,7 +403,7 @@
"panes.show": "Hiện {{name}} ở đây",
"panes.splitNew.right": "Chia sang phải với terminal mới",
"panes.splitNew.bottom": "Chia xuống dưới với terminal mới",
"panes.closeShort": "Ẩn pane",
"panes.closeShort": "Tách ra tab riêng",
"changes.copyPath": "Sao chép đường dẫn tương đối",
"changes.viewCommit": "Xem commit",
"changes.copySha": "Sao chép SHA của commit",
@@ -414,6 +416,7 @@
"tabs.state.running": "Đang chạy",
"tabs.renameHint": "Nhấp đúp để đổi tên",
"tabs.stopTitle": "Dừng “{{name}}”?",
"tabs.stopGroupTitle": "Dừng {{count}} session trong tab này?",
"tabs.stopBody": "Đóng tab sẽ dừng phiên của nó, kể cả khi đang chạy dở. Bạn có thể tiếp tục (resume) sau từ mục Gần đây.",
"tabs.stopConfirm": "Dừng phiên",
"changes.loadMore": "Tải thêm commit",
@@ -434,9 +437,6 @@
"row.state.running": "đang chạy",
"row.state.active": "đang hoạt động",
"row.state.idle": "nghỉ",
"menu.stopTitle_one": "Dừng phiên đang chạy?",
"menu.stopTitle_other": "Dừng {{count}} phiên đang chạy?",
"menu.stopBody": "Mọi tab của workspace này sẽ dừng, kể cả khi đang chạy dở. Có thể tiếp tục các phiên sau từ mục Gần đây.",
"gitBar.done.fetch": "Đã fetch",
"gitBar.done.pull": "Đã pull",
"gitBar.done.push": "Đã push",
+2 -1
View File
@@ -66,7 +66,8 @@
"needYou": "{{count}} cần bạn",
"today": "Hôm nay {{cost}}",
"workspace": "Workspace {{cost}}",
"session": "Session {{cost}}"
"session": "Session {{cost}}",
"tokens": "({{tokens}} Tokens)"
},
"version": "Phiên bản",
"openMenu": "Mở menu",