feat(workspace): AI tool per session, one place to start a session, ended sessions open like Claude Desktop

- A session picks its own AI tool: `tool` on POST /api/lanes/:id/start
  (a catalog id, known + enabled, else 400 EBADTOOL/EDISABLED); a resume
  keeps the tool its session ran on (`sessions.tool`). The workspace's
  `lanes.tool` is now only the default.
- The workspace home's prompt box is the one place a session starts. Its
  fields run in order: AI → AI Router (Native or a profile) → Model (the
  tool's own list, or the router's models) → Permission (Claude mode /
  Codex sandbox+approval / catalog bypass) → Effort.
- The pane's run form (RunSetup) is gone: New run, a single pane's exit and
  an empty split pane's New session all go to the home. RunSetup.tsx keeps
  PromptEditor, CwdAutocomplete and ModelPicker (new `choices` prop).
- The tool icon moved from the sidebar's workspace row to each session row
  (right edge, `session.tool`); the split-pane header shows the run's tool.
- An ended session opens in its workspace (`&session=`, SessionReplay.tsx):
  its conversation read-only plus a prompt box; only a SENT message resumes
  it (resumeSessionId + prompt, first free slot). The console is only
  hidden behind it.
- Analyst button beside Files/Changes in the right panel opens
  /sessions/:id for the opened session.
- Gemini CLI ships its own icon (client/public/ai-tools/gemini.svg, from
  zonalogo.com).
- RouterPicker always shows (Native disabled for tools without router
  support); useAiRouters() exported.
- Tests: server start-with-tool cases; SessionReplay, home field order/tool/
  router models, empty pane, Analyst; dropped the cwd-field suites
  (Run.defaultCwd, Workspace.laneCwd). Docs: CLAUDE.md rules, API.md,
  LANES.md, README, ARCHITECTURE, INSTALL.
This commit is contained in:
2026-10-02 15:29:38 +07:00
parent c507d37baf
commit 4802684d2f
34 changed files with 1137 additions and 2504 deletions
+6 -1
View File
@@ -317,6 +317,10 @@
"pane.close": "Stop this pane's session",
"panel.files": "Files",
"panel.changes": "Changes",
"panel.analyst": "Analyst",
"replay.placeholder": "Message to continue this session…",
"replay.hint": "Sending resumes the session in a free pane.",
"replay.send": "Send",
"sessions.resume": "Resume",
"resume.openPane": "Open pane",
"resume.hint": "Resume this session in a workspace pane — re-reads its whole transcript into context",
@@ -334,7 +338,7 @@
"tree.allTools": "All tools",
"tree.newSession": "New session",
"tree.noSessions": "No sessions yet",
"tree.transcriptHint": "No live pane — opens the transcript",
"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 second pane",
"tree.renameSession": "Rename session",
"tree.archiveSession": "Archive — hide from this workspace (deletes nothing)",
@@ -346,6 +350,7 @@
"tree.archived_other": "{{count}} archived sessions",
"tree.unarchive": "Unarchive",
"home.breadcrumb": "Workspaces",
"home.ai": "AI",
"home.repoRoot": "Repository root",
"home.mainBranch": "Main worktree's branch",
"home.worktreeCount_one": "{{count}} worktree",
+2
View File
@@ -1,6 +1,8 @@
{
"emptyPane": "No session in this pane. Start one from the workspace's prompt box.",
"actions": {
"newRun": "New run",
"newSession": "New session",
"send": "Send",
"sending": "Sending…",
"start": "Run",
+6 -1
View File
@@ -317,6 +317,10 @@
"pane.close": "Dừng phiên của ô này",
"panel.files": "Tệp",
"panel.changes": "Thay đổi",
"panel.analyst": "Analyst",
"replay.placeholder": "Nhắn để tiếp tục session này…",
"replay.hint": "Gửi tin sẽ resume session trong một pane trống.",
"replay.send": "Gửi",
"sessions.resume": "Tiếp tục",
"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",
@@ -334,7 +338,7 @@
"tree.allTools": "Mọi tool",
"tree.newSession": "Session mới",
"tree.noSessions": "Chưa có session",
"tree.transcriptHint": "Không còn pane — mở transcript",
"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ở ở pane thứ hai",
"tree.renameSession": "Đổi tên session",
"tree.archiveSession": "Lưu trữ — ẩn khỏi workspace này (không xoá gì)",
@@ -346,6 +350,7 @@
"tree.archived_other": "{{count}} session đã lưu trữ",
"tree.unarchive": "Bỏ lưu trữ",
"home.breadcrumb": "Không gian làm việc",
"home.ai": "AI",
"home.repoRoot": "Thư mục gốc của repo",
"home.mainBranch": "Branch của worktree chính",
"home.worktreeCount_one": "{{count}} worktree",
+2
View File
@@ -1,6 +1,8 @@
{
"emptyPane": "Pane này chưa có phiên nào. Hãy tạo phiên từ ô prompt của workspace.",
"actions": {
"newRun": "Lượt chạy mới",
"newSession": "Phiên mới",
"send": "Gửi",
"sending": "Đang gửi…",
"start": "Chạy",