diff --git a/console/web/src/components/chat/coder/OpenInEditorButton.tsx b/console/web/src/components/chat/coder/OpenInEditorButton.tsx index 90deef580..a6917a616 100644 --- a/console/web/src/components/chat/coder/OpenInEditorButton.tsx +++ b/console/web/src/components/chat/coder/OpenInEditorButton.tsx @@ -11,13 +11,14 @@ import { copyTextToClipboard } from '@/lib/clipboard' import { EDITORS, type EditorId, editorById } from '@/lib/editor-links' /** - * "open in editor" affordance for coder file-change rows: one button that - * always opens a menu of editors (cursor / vs code / zed) — each entry - * launches that editor via its URL scheme — plus "copy path", the fallback - * when the browser isn't on the machine that has the files. No editor is - * privileged; the menu is shown every time so the choice stays explicit. - * Renders nothing for non-absolute paths (result resolution failed — - * `coder` results are jail-resolved absolute on success). + * "open in editor" affordance for coder file-change rows: the console's + * own shell explorer first (`#/ext/shell/open/[:line]` — + * the shell worker serves both the `coder::*` surface that produced this + * row and that page, so the route always resolves), then external + * editors (cursor / vs code / zed) via their URL schemes, plus "copy + * path" — the fallback when the browser isn't on the machine that has + * the files. Renders nothing for non-absolute paths (result resolution + * failed — `coder` results are jail-resolved absolute on success). */ export function OpenInEditorButton({ path, @@ -29,6 +30,14 @@ export function OpenInEditorButton({ const [copied, setCopied] = useState(false) if (!path.startsWith('/')) return null + const openInShell = () => { + const anchor = + typeof line === 'number' && Number.isInteger(line) && line > 0 + ? `:${line}` + : '' + window.location.hash = `#/ext/shell/open/${encodeURIComponent(path)}${anchor}` + } + const openWith = (id: EditorId) => { window.location.href = editorById(id).buildUrl(path, line) } @@ -47,13 +56,17 @@ export function OpenInEditorButton({ + + open in shell + + {EDITORS.map((e) => ( openWith(e.id)}> open in {e.label}