feat(workspace): no double resume, server-picked tabs, terminal a11y
- A resume of a session a live pane already holds is refused (409 ESESSIONLIVE with error.run_id) and the client opens that pane, pasting any typed message there; catalog tools refuse resumeSessionId (EUNSUPPORTED) instead of silently starting fresh. - POST /api/lanes/:id/start takes slot: "auto": the server picks the free tab under the lane lock (components/lanes/startSession.ts on the client, kept out of WorkspaceHome so the sidebar does not pull react-markdown into the main bundle). - Unsaved whole-file edits are guarded on every exit (Back, another file, tab switch, close, lane/session change, beforeunload). - Closing an AI tab asks first; hiding a pane has its own icon. Tabs and pane headers show the session name, a state dot, rename by double-click. - Terminal: Ctrl+M toggles Tab-moves-focus (no keyboard trap), Cmd+F / Ctrl+Shift+F find bar, clickable links (noopener), a write-only OSC 52 clipboard, a Reconnecting overlay, debounced resizes, optional screen reader mode. Alt+1-4 / Alt+\ / Alt+W focus, split and hide panes. - Changes panel: draggable splitter, wrapping git bar, history paging, disarming discard/undo/abort, inline diff comments pasted only into a visible pane; drag MIME guard on sidebar rows; IME-safe Enter; Show more in the sidebar and Recents; idle dots readable with sr-only text. - Adds @xterm/addon-clipboard, @xterm/addon-search, @xterm/addon-web-links.
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
"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.commentNoPane": "No terminal of this workspace is on screen — open its session (or narrow the Changes panel) first",
|
||||
"changes.layout.split": "Side-by-side",
|
||||
"changes.layout.unified": "Unified",
|
||||
"changes.loading": "Reading the working copy…",
|
||||
@@ -390,7 +390,7 @@
|
||||
"panes.split.bottom": "Split down",
|
||||
"panes.full": "4 panes is the most a workspace can show",
|
||||
"panes.newTerminal": "New terminal",
|
||||
"panes.close": "Close pane (its session keeps running as a tab)",
|
||||
"panes.close": "Hide pane (its session keeps running as a tab)",
|
||||
"panes.resize": "Resize panes",
|
||||
"tabs.home": "Workspace home",
|
||||
"sessionMenu.open": "Open",
|
||||
@@ -401,9 +401,47 @@
|
||||
"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": "Close pane",
|
||||
"panes.closeShort": "Hide pane",
|
||||
"changes.copyPath": "Copy relative path",
|
||||
"changes.viewCommit": "View commit",
|
||||
"changes.copySha": "Copy commit SHA",
|
||||
"changes.copySubject": "Copy commit message"
|
||||
"changes.copySubject": "Copy commit message",
|
||||
"replay.live": "This session is open in a tab — continue it there.",
|
||||
"replay.noResume": "{{tool}} cannot resume a session by id, so this conversation is read-only here.",
|
||||
"replay.newSession": "Start a new session",
|
||||
"tabs.state.awaiting": "Waiting for you",
|
||||
"tabs.state.error": "Error",
|
||||
"tabs.state.running": "Running",
|
||||
"tabs.renameHint": "Double-click to rename",
|
||||
"tabs.stopTitle": "Stop “{{name}}”?",
|
||||
"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",
|
||||
"changes.commentPasted": "Pasted into tab {{tab}} — press Enter there to send it",
|
||||
"changes.splitter": "Resize the changes panel",
|
||||
"tree.archiveLiveTitle": "Archive a live session?",
|
||||
"tree.archiveLiveBody": "Its tab keeps running; archiving only hides it from this list. Unarchive it from the archived fold.",
|
||||
"tree.state.awaiting": "waiting for you",
|
||||
"tree.state.error": "error",
|
||||
"tree.state.live": "live",
|
||||
"tree.state.idle": "ended",
|
||||
"tree.showMore_one": "Show {{count}} more",
|
||||
"tree.showMore_other": "Show {{count}} more",
|
||||
"home.contextPanel": "Workspace context",
|
||||
"row.state.needsYou": "needs you",
|
||||
"row.state.error": "error",
|
||||
"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",
|
||||
"gitBar.done.publish": "Published",
|
||||
"runtime.listening": "listening",
|
||||
"runtime.notListening": "not listening",
|
||||
"replay.pasted": "That session was already open in a tab — your message is pasted there; press Enter to send it.",
|
||||
"replay.notPasted": "That session is open in a tab, but your message could not be pasted there: {{text}}"
|
||||
}
|
||||
|
||||
@@ -148,5 +148,17 @@
|
||||
"imagesOnly": "Only images can be dropped here",
|
||||
"remove": "Remove image",
|
||||
"view": "View image"
|
||||
},
|
||||
"terminal": {
|
||||
"ended": "[session ended, exit code {{code}}]",
|
||||
"reconnecting": "Reconnecting… keystrokes are not reaching the session until the terminal is back.",
|
||||
"keyboardHint": "Terminal. Press Ctrl+M to toggle whether Tab moves focus out of the terminal; Ctrl+Shift+F (Cmd+F on macOS) finds text.",
|
||||
"tabMoves": "Tab moves focus — Ctrl+M to give Tab back to the terminal",
|
||||
"selectHint": "Shift+drag to select text in the browser; a plain drag selects in tmux and copies on release.",
|
||||
"dismissHint": "Dismiss",
|
||||
"find": "Find in terminal",
|
||||
"findPrev": "Previous match",
|
||||
"findNext": "Next match",
|
||||
"findClose": "Close find"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user