From 27a18c6ed7c8c6516ad449f5903539d4e8db0644 Mon Sep 17 00:00:00 2001 From: Patrick Roza Date: Mon, 13 Jul 2026 08:40:16 +0200 Subject: [PATCH] feat(vscode): add T3 Code VS Code extension A dedicated VS Code chat client for synchronized T3 Code threads. - Sidebar webview + native @t3 Chat participant - Realtime synchronized threads with web/desktop/mobile - Editor context, slash commands, images, approvals, tools, tasks - Secure: worktree-scoped links, strict CSP, empty-window activation - Multi-root safe, tolerant of no open folder Connects to local T3 Desktop or remote T3 servers. --- apps/vscode/.vscodeignore | 6 + apps/vscode/README.md | 47 + apps/vscode/media/screenshot.jpg | Bin 0 -> 277454 bytes apps/vscode/media/t3-code.svg | 3 + apps/vscode/package.json | 203 +++ apps/vscode/src/chatViewProvider.ts | 732 +++++++++++ apps/vscode/src/desktopFavorites.ts | 196 +++ apps/vscode/src/editorContext.test.ts | 38 + apps/vscode/src/editorContext.ts | 55 + apps/vscode/src/extension.ts | 462 +++++++ apps/vscode/src/ids.ts | 14 + apps/vscode/src/pendingInteractions.test.ts | 79 ++ apps/vscode/src/pendingInteractions.ts | 113 ++ apps/vscode/src/providerIcon.ts | 58 + apps/vscode/src/serverResolution.test.ts | 24 + apps/vscode/src/serverResolution.ts | 28 + apps/vscode/src/t3Client.ts | 670 ++++++++++ apps/vscode/src/taskPresentation.test.ts | 54 + apps/vscode/src/taskPresentation.ts | 55 + apps/vscode/src/threadStatus.test.ts | 32 + apps/vscode/src/threadStatus.ts | 44 + apps/vscode/src/toolPresentation.test.ts | 116 ++ apps/vscode/src/toolPresentation.ts | 198 +++ apps/vscode/src/userInputPresentation.ts | 19 + apps/vscode/src/webview.ts | 1310 +++++++++++++++++++ apps/vscode/tsconfig.json | 8 + pnpm-lock.yaml | 56 + 27 files changed, 4620 insertions(+) create mode 100644 apps/vscode/.vscodeignore create mode 100644 apps/vscode/README.md create mode 100644 apps/vscode/media/screenshot.jpg create mode 100644 apps/vscode/media/t3-code.svg create mode 100644 apps/vscode/package.json create mode 100644 apps/vscode/src/chatViewProvider.ts create mode 100644 apps/vscode/src/desktopFavorites.ts create mode 100644 apps/vscode/src/editorContext.test.ts create mode 100644 apps/vscode/src/editorContext.ts create mode 100644 apps/vscode/src/extension.ts create mode 100644 apps/vscode/src/ids.ts create mode 100644 apps/vscode/src/pendingInteractions.test.ts create mode 100644 apps/vscode/src/pendingInteractions.ts create mode 100644 apps/vscode/src/providerIcon.ts create mode 100644 apps/vscode/src/serverResolution.test.ts create mode 100644 apps/vscode/src/serverResolution.ts create mode 100644 apps/vscode/src/t3Client.ts create mode 100644 apps/vscode/src/taskPresentation.test.ts create mode 100644 apps/vscode/src/taskPresentation.ts create mode 100644 apps/vscode/src/threadStatus.test.ts create mode 100644 apps/vscode/src/threadStatus.ts create mode 100644 apps/vscode/src/toolPresentation.test.ts create mode 100644 apps/vscode/src/toolPresentation.ts create mode 100644 apps/vscode/src/userInputPresentation.ts create mode 100644 apps/vscode/src/webview.ts create mode 100644 apps/vscode/tsconfig.json diff --git a/apps/vscode/.vscodeignore b/apps/vscode/.vscodeignore new file mode 100644 index 00000000000..77f1925a04a --- /dev/null +++ b/apps/vscode/.vscodeignore @@ -0,0 +1,6 @@ +.vscode/** +node_modules/** +src/** +tsconfig.json +vite.config.* +*.test.* diff --git a/apps/vscode/README.md b/apps/vscode/README.md new file mode 100644 index 00000000000..8386c738385 --- /dev/null +++ b/apps/vscode/README.md @@ -0,0 +1,47 @@ +# T3 Code for VS Code + +![T3 Code in VS Code](media/screenshot.jpg) + +This package exposes T3 Code as a dedicated VS Code secondary-sidebar chat tab, alongside the +Claude Code, Chat, and Codex tabs. It connects directly to the same T3 Code server used by the web, +desktop, and mobile clients, so projects, threads, messages, turn state, and assistant streaming +remain synchronized. It also provides an optional native `@t3` participant inside VS Code Chat. + +## Development + +1. Start T3 Code (`pnpm dev`), which listens at `http://127.0.0.1:3773` by default. +2. Build the extension with `pnpm --filter t3-code build`. +3. Open this repository in VS Code, choose **Run Extension** from the Run and Debug view, and point + the extension-development host at `apps/vscode` if prompted. +4. Select the **T3 Code** tab in the secondary sidebar. Use **T3 Code: Open Chat** from the Command + Palette if the secondary sidebar is hidden. + +The extension first uses the backend advertised by the T3 Desktop runtime beside its extension +host. This works independently in local, SSH, and other remote windows and avoids treating a +synced `127.0.0.1` setting as the same machine. For a fallback backend, set `t3Code.serverUrl`. +Remote servers can use **T3 Code: Set Server Bearer Token**; the token is stored in VS Code secret +storage and exchanged for a short-lived WebSocket ticket. + +## Dedicated chat workflow + +The T3 Code tab contains a worktree-scoped thread picker, synchronized transcript, context control, +and prompt composer. Select a thread to continue it on any T3 client, or use **+** to create one for +the open worktree. Enter sends; Shift+Enter inserts a newline. + +The same operations are also available through the optional native Chat participant: + +- `@t3 /threads` selects an existing thread whose worktree matches the open workspace folder. +- `@t3 /new` creates a synchronized thread (and a project when the folder is not registered yet). +- A normal `@t3` prompt continues the last selected thread, or the most recently updated matching + thread. If none exists, it creates one. +- `@t3 /history`, `/status`, and `/stop` inspect or control the selected server thread. + +Active editor context is included by default and can be toggled from the composer, with +`@t3 /context`, or **T3 Code: Toggle Automatic Editor Context**. This preference is kept in VS Code's +extension state and never written to workspace settings. A non-empty +selection includes the exact character range; an empty selection includes the cursor line and +column. Explicit Chat references such as `#file` and attached selections are always included. + +The **T3 Code: Ask About Selection** editor action opens Chat with `@t3` prefilled. Context is sent +as structured-looking provider context using workspace-relative paths and language-aware Markdown +fences. T3 Code clients present that envelope as a context reference rather than authored text. diff --git a/apps/vscode/media/screenshot.jpg b/apps/vscode/media/screenshot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5d7df918794f28a6fe76d26a93859c52530c67e1 GIT binary patch literal 277454 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 aIO2v#cpTyf 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

KVhI(+&cSm0g}t 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 V23?_Lg_D6~zke*OBmepFzW|_ZrQ84j literal 0 HcmV?d00001 diff --git a/apps/vscode/media/t3-code.svg b/apps/vscode/media/t3-code.svg new file mode 100644 index 00000000000..fd6dba4e5e5 --- /dev/null +++ b/apps/vscode/media/t3-code.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/vscode/package.json b/apps/vscode/package.json new file mode 100644 index 00000000000..d89b3d49803 --- /dev/null +++ b/apps/vscode/package.json @@ -0,0 +1,203 @@ +{ + "name": "t3-code", + "displayName": "T3 Code", + "version": "0.0.37", + "private": true, + "description": "A dedicated VS Code chat client for synchronized T3 Code threads.", + "categories": [ + "AI", + "Chat", + "Other" + ], + "publisher": "t3code", + "type": "module", + "main": "./dist/extension.cjs", + "scripts": { + "build": "esbuild src/extension.ts --bundle --platform=node --format=cjs --target=node20 --external:vscode --outfile=dist/extension.cjs && esbuild src/webview.ts --bundle --platform=browser --format=iife --target=es2022 --outfile=dist/webview.js", + "typecheck": "tsgo --noEmit", + "test": "vp test run" + }, + "dependencies": { + "@t3tools/client-runtime": "workspace:*", + "@t3tools/contracts": "workspace:*", + "@t3tools/shared": "workspace:*", + "dompurify": "^3.2.6", + "effect": "catalog:", + "marked": "^15.0.12" + }, + "devDependencies": { + "@types/vscode": "1.95.0", + "esbuild": "^0.28.0", + "vite-plus": "catalog:" + }, + "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "t3CodeViewContainer", + "title": "T3 Code", + "icon": "media/t3-code.svg", + "when": "t3Code.useActivityBar" + } + ], + "secondarySidebar": [ + { + "id": "t3CodeSecondaryViewContainer", + "title": "T3 Code", + "icon": "media/t3-code.svg", + "when": "!t3Code.useActivityBar" + } + ] + }, + "views": { + "t3CodeViewContainer": [ + { + "id": "t3Code.chatView", + "type": "webview", + "name": "T3 Code", + "when": "t3Code.useActivityBar" + } + ], + "t3CodeSecondaryViewContainer": [ + { + "id": "t3Code.chatViewSecondary", + "type": "webview", + "name": "T3 Code", + "when": "!t3Code.useActivityBar" + } + ] + }, + "chatParticipants": [ + { + "id": "t3-code.chat", + "name": "t3", + "fullName": "T3 Code", + "description": "Work with synchronized Codex, Claude, Cursor, Grok, and OpenCode threads.", + "isSticky": true, + "commands": [ + { + "name": "new", + "description": "Create a thread for this worktree" + }, + { + "name": "threads", + "description": "Choose a thread for this worktree" + }, + { + "name": "history", + "description": "Show the synchronized thread history" + }, + { + "name": "context", + "description": "Toggle automatic editor context" + }, + { + "name": "stop", + "description": "Interrupt the active turn" + }, + { + "name": "status", + "description": "Show connection and thread status" + } + ] + } + ], + "commands": [ + { + "command": "t3Code.newThread", + "title": "T3 Code: New Thread for Worktree", + "category": "T3 Code" + }, + { + "command": "t3Code.selectThread", + "title": "T3 Code: Select Worktree Thread", + "category": "T3 Code" + }, + { + "command": "t3Code.askSelection", + "title": "T3 Code: Ask About Selection", + "category": "T3 Code", + "icon": "$(comment-discussion)" + }, + { + "command": "t3Code.toggleEditorContext", + "title": "T3 Code: Toggle Automatic Editor Context", + "category": "T3 Code" + }, + { + "command": "t3Code.showDiagnostics", + "title": "T3 Code: Show Diagnostics", + "category": "T3 Code" + }, + { + "command": "t3Code.setBearerToken", + "title": "T3 Code: Set Server Bearer Token", + "category": "T3 Code" + }, + { + "command": "t3Code.clearBearerToken", + "title": "T3 Code: Clear Server Bearer Token", + "category": "T3 Code" + }, + { + "command": "t3Code.openChat", + "title": "T3 Code: Open Chat", + "category": "T3 Code" + } + ], + "menus": { + "editor/context": [ + { + "command": "t3Code.askSelection", + "group": "navigation@90", + "when": "editorHasSelection" + } + ] + }, + "configuration": { + "title": "T3 Code", + "properties": { + "t3Code.serverUrl": { + "type": "string", + "scope": "machine", + "default": "http://127.0.0.1:3773", + "description": "Fallback T3 Code server HTTP URL when no local T3 Desktop runtime is advertised. WebSocket and environment endpoints are derived from it." + }, + "t3Code.defaultRuntimeMode": { + "type": "string", + "enum": [ + "approval-required", + "auto-accept-edits", + "full-access" + ], + "default": "full-access", + "description": "Runtime mode for new T3 Code threads." + }, + "t3Code.desktopClientSettingsPath": { + "type": "string", + "default": "", + "description": "Optional path to T3 Desktop's client-settings.json for sharing provider and model favorites. The default auto-detects ~/.t3/userdata or ~/.t3/dev." + } + } + } + }, + "activationEvents": [ + "onChatParticipant:t3-code.chat", + "onCommand:t3Code.askSelection", + "onCommand:t3Code.clearBearerToken", + "onCommand:t3Code.newThread", + "onCommand:t3Code.openChat", + "onCommand:t3Code.selectThread", + "onCommand:t3Code.setBearerToken", + "onCommand:t3Code.showDiagnostics", + "onCommand:t3Code.toggleEditorContext", + "onView:t3Code.chatView", + "onView:t3Code.chatViewSecondary" + ], + "extensionKind": [ + "workspace" + ], + "engines": { + "vscode": "^1.95.0" + } +} diff --git a/apps/vscode/src/chatViewProvider.ts b/apps/vscode/src/chatViewProvider.ts new file mode 100644 index 00000000000..09f6ccd7f78 --- /dev/null +++ b/apps/vscode/src/chatViewProvider.ts @@ -0,0 +1,732 @@ +/* oxlint-disable unicorn/require-post-message-target-origin -- VS Code Webview.postMessage is not Window.postMessage. */ +import type { + ModelSelection, + OrchestrationThread, + OrchestrationThreadShell, + RuntimeMode, + ThreadId, + UploadChatAttachment, +} from "@t3tools/contracts"; +import { ApprovalRequestId, ProviderInstanceId } from "@t3tools/contracts"; +import * as vscode from "vscode"; + +import { composePrompt, type TextContext } from "./editorContext.ts"; +import { derivePendingInteractions } from "./pendingInteractions.ts"; +import type { T3Client } from "./t3Client.ts"; +import { resolveThreadDisplayStatus } from "./threadStatus.ts"; +import { presentTasks } from "./taskPresentation.ts"; +import { presentToolCalls } from "./toolPresentation.ts"; +import { presentResolvedUserInputs } from "./userInputPresentation.ts"; + +interface ChatViewActions { + readonly worktreePath: () => string; + readonly ensureConnected: () => Promise; + readonly restoreThread: () => Promise; + readonly createThread: (title?: string, modelSelection?: ModelSelection) => Promise; + readonly selectThread: (threadId: string) => Promise; + readonly toggleContext: () => Promise; + readonly contextEnabled: () => boolean; + readonly runtimeMode: () => RuntimeMode; + readonly editorContext: () => TextContext | null; + readonly favoriteProviderIds: () => ReadonlyArray; + readonly favoriteModelKeys: () => ReadonlyArray; + readonly toggleProviderFavorite: (instanceId: string) => Promise; + readonly toggleModelFavorite: (modelKey: string) => Promise; + readonly onFavoritesChanged: vscode.Event; +} + +type WebviewRequest = + | { readonly type: "ready" | "refresh" | "stop" | "toggleContext" } + | { + readonly type: "sendNewThread"; + readonly text: string; + readonly instanceId: string; + readonly model: string; + readonly options: ModelSelection["options"]; + readonly images: ReadonlyArray; + } + | { readonly type: "selectThread"; readonly threadId: string } + | { + readonly type: "selectModel"; + readonly instanceId: string; + readonly model: string; + readonly options: ModelSelection["options"]; + } + | { readonly type: "openLink"; readonly href: string } + | { readonly type: "openEditorContext"; readonly path: string; readonly detail: string } + | { readonly type: "copyText"; readonly text: string } + | { + readonly type: "approvalResponse"; + readonly requestId: string; + readonly decision: "accept" | "acceptForSession" | "decline"; + } + | { + readonly type: "userInputResponse"; + readonly requestId: string; + readonly answers: Readonly>>; + } + | { readonly type: "toggleProviderFavorite"; readonly instanceId: string } + | { readonly type: "toggleModelFavorite"; readonly modelKey: string } + | { + readonly type: "send"; + readonly text: string; + readonly images: ReadonlyArray; + }; + +function hasImageArray(value: object): boolean { + return ( + "images" in value && + Array.isArray(value.images) && + value.images.every( + (image) => + typeof image === "object" && + image !== null && + "type" in image && + image.type === "image" && + "name" in image && + typeof image.name === "string" && + "mimeType" in image && + typeof image.mimeType === "string" && + "sizeBytes" in image && + typeof image.sizeBytes === "number" && + "dataUrl" in image && + typeof image.dataUrl === "string", + ) + ); +} + +function nonce(): string { + return Array.from(globalThis.crypto.getRandomValues(new Uint8Array(16)), (byte) => + byte.toString(16).padStart(2, "0"), + ).join(""); +} + +function isRequest(value: unknown): value is WebviewRequest { + if (typeof value !== "object" || value === null || !("type" in value)) return false; + const type = (value as { readonly type?: unknown }).type; + if (type === "ready" || type === "refresh" || type === "stop" || type === "toggleContext") { + return true; + } + if (type === "sendNewThread") { + return ( + "text" in value && + typeof value.text === "string" && + "instanceId" in value && + typeof value.instanceId === "string" && + "model" in value && + typeof value.model === "string" && + "options" in value && + (value.options === undefined || Array.isArray(value.options)) && + hasImageArray(value) + ); + } + if (type === "selectThread") { + return "threadId" in value && typeof value.threadId === "string"; + } + if (type === "selectModel") { + return ( + "instanceId" in value && + typeof value.instanceId === "string" && + "model" in value && + typeof value.model === "string" && + "options" in value && + (value.options === undefined || Array.isArray(value.options)) + ); + } + if (type === "openLink") return "href" in value && typeof value.href === "string"; + if (type === "approvalResponse") { + return ( + "requestId" in value && + typeof value.requestId === "string" && + "decision" in value && + (value.decision === "accept" || + value.decision === "acceptForSession" || + value.decision === "decline") + ); + } + if (type === "userInputResponse") { + return ( + "requestId" in value && + typeof value.requestId === "string" && + "answers" in value && + typeof value.answers === "object" && + value.answers !== null && + Object.values(value.answers).every( + (answer) => + typeof answer === "string" || + (Array.isArray(answer) && answer.every((entry) => typeof entry === "string")), + ) + ); + } + if (type === "openEditorContext") { + return ( + "path" in value && + typeof value.path === "string" && + "detail" in value && + typeof value.detail === "string" + ); + } + if (type === "copyText") return "text" in value && typeof value.text === "string"; + if (type === "toggleProviderFavorite") { + return "instanceId" in value && typeof value.instanceId === "string"; + } + if (type === "toggleModelFavorite") { + return "modelKey" in value && typeof value.modelKey === "string"; + } + return ( + type === "send" && "text" in value && typeof value.text === "string" && hasImageArray(value) + ); +} + +export class T3ChatViewProvider implements vscode.WebviewViewProvider, vscode.Disposable { + static readonly primaryViewType = "t3Code.chatView"; + static readonly secondaryViewType = "t3Code.chatViewSecondary"; + + #view: vscode.WebviewView | null = null; + #busy = false; + #error: string | null = null; + readonly client: T3Client; + readonly actions: ChatViewActions; + readonly extensionUri: vscode.Uri; + readonly #disposables: vscode.Disposable[]; + readonly #attachmentUrls = new Map(); + readonly #attachmentLoads = new Set(); + + constructor(client: T3Client, actions: ChatViewActions, extensionUri: vscode.Uri) { + this.client = client; + this.actions = actions; + this.extensionUri = extensionUri; + this.#disposables = [ + client.onShellChanged(() => this.#publish()), + client.onThreadChanged(() => this.#publish()), + client.onConnectionChanged((connected) => { + if (!connected) this.#error = "Connection lost. Refresh to reconnect to T3 Code."; + this.#publish(); + }), + vscode.window.onDidChangeActiveTextEditor(() => this.#publish()), + vscode.window.onDidChangeTextEditorSelection(() => this.#publish()), + vscode.workspace.onDidChangeConfiguration((event) => { + if (event.affectsConfiguration("t3Code")) void this.#refresh(); + }), + actions.onFavoritesChanged(() => this.#publish()), + ]; + } + + resolveWebviewView(view: vscode.WebviewView): void { + this.#view = view; + view.webview.options = { + enableScripts: true, + localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, "dist")], + }; + view.webview.html = this.#html(view.webview); + this.#disposables.push( + view.webview.onDidReceiveMessage((message: unknown) => { + if (isRequest(message)) void this.#handle(message); + }), + view.onDidDispose(() => { + if (this.#view === view) this.#view = null; + }), + view.onDidChangeVisibility(() => { + if (view.visible && this.client.serverConfig === null) void this.#refresh(); + }), + ); + } + + dispose(): void { + for (const disposable of this.#disposables) disposable.dispose(); + this.#disposables.length = 0; + } + + async reveal(): Promise { + try { + await vscode.commands.executeCommand(`${T3ChatViewProvider.secondaryViewType}.focus`); + } catch { + await vscode.commands.executeCommand(`${T3ChatViewProvider.primaryViewType}.focus`); + } + await this.#view?.webview.postMessage({ type: "focusComposer" }); + } + + async #handle(message: WebviewRequest): Promise { + try { + switch (message.type) { + case "ready": + case "refresh": + await this.#refresh(); + return; + case "sendNewThread": + await this.#run(async () => { + const authored = message.text.trim(); + if (authored === "" && message.images.length === 0) return; + const modelSelection: ModelSelection = { + instanceId: ProviderInstanceId.make(message.instanceId), + model: message.model, + ...(message.options === undefined ? {} : { options: message.options }), + }; + const threadId = await this.actions.createThread( + authored.slice(0, 80) || "Image", + modelSelection, + ); + const editorContext = this.actions.contextEnabled() + ? this.actions.editorContext() + : null; + await this.client.sendPrompt({ + threadId, + prompt: composePrompt(authored, editorContext === null ? [] : [editorContext]), + runtimeMode: this.actions.runtimeMode(), + modelSelection, + attachments: message.images, + }); + // The shell/title update can arrive before the detail stream. Hydrate + // the authoritative first message before the webview leaves draft mode. + await this.client.selectThread(threadId); + await this.client.waitForActiveThread(); + await this.#view?.webview.postMessage({ type: "sentNewThread" }); + }); + return; + case "selectThread": + await this.#run(async () => { + await this.actions.selectThread(message.threadId); + await this.client.waitForActiveThread(); + }); + return; + case "selectModel": + await this.#run(() => + this.client.setModelSelection({ + instanceId: ProviderInstanceId.make(message.instanceId), + model: message.model, + ...(message.options === undefined ? {} : { options: message.options }), + }), + ); + return; + case "openLink": + await this.#openLink(message.href); + return; + case "openEditorContext": { + if (message.path.split("/").includes("..")) return; + const uri = vscode.Uri.joinPath( + vscode.Uri.file(this.actions.worktreePath()), + ...message.path.split("/"), + ); + const document = await vscode.workspace.openTextDocument(uri); + const editor = await vscode.window.showTextDocument(document); + const line = /(?:line|lines)\s+(\d+)/u.exec(message.detail)?.[1]; + if (line !== undefined) { + const position = new vscode.Position(Math.max(0, Number(line) - 1), 0); + editor.selection = new vscode.Selection(position, position); + editor.revealRange(new vscode.Range(position, position)); + } + return; + } + case "copyText": + await vscode.env.clipboard.writeText(message.text); + return; + case "approvalResponse": + await this.#run(() => + this.client.respondToApproval( + ApprovalRequestId.make(message.requestId), + message.decision, + ), + ); + return; + case "userInputResponse": + await this.#run(() => + this.client.respondToUserInput(ApprovalRequestId.make(message.requestId), { + ...message.answers, + }), + ); + return; + case "toggleProviderFavorite": + await this.actions.toggleProviderFavorite(message.instanceId); + this.#publish(); + return; + case "toggleModelFavorite": + await this.actions.toggleModelFavorite(message.modelKey); + this.#publish(); + return; + case "stop": + await this.#run(() => this.client.interrupt()); + return; + case "toggleContext": + await this.actions.toggleContext(); + this.#publish(); + return; + case "send": { + const authored = message.text.trim(); + if (authored === "" && message.images.length === 0) return; + await this.#run(async () => { + await this.actions.ensureConnected(); + // Resolve/restore thread for the *current* worktree (multi-root safe) before reusing activeThread. + await this.actions.restoreThread(); + const threadId = + this.client.activeThread?.id ?? + (await this.actions.createThread(authored.slice(0, 80))); + const context = this.actions.contextEnabled() ? this.actions.editorContext() : null; + await this.client.sendPrompt({ + threadId, + prompt: composePrompt(authored, context === null ? [] : [context]), + runtimeMode: this.actions.runtimeMode(), + attachments: message.images, + }); + await this.#view?.webview.postMessage({ type: "sent" }); + }); + return; + } + } + } catch (cause) { + this.#error = cause instanceof Error ? cause.message : String(cause); + this.#publish(); + } + } + + async #refresh(): Promise { + await this.#run(async () => { + await this.actions.ensureConnected(); + await this.actions.restoreThread(); + }); + } + + async #run(action: () => Promise): Promise { + if (this.#busy) return; + this.#busy = true; + this.#error = null; + this.#publish(); + try { + await action(); + } catch (cause) { + this.#error = cause instanceof Error ? cause.message : String(cause); + } finally { + this.#busy = false; + this.#publish(); + } + } + + #publish(): void { + const view = this.#view; + if (view === null) return; + let threads: ReadonlyArray = []; + try { + threads = this.client.threadsForWorktree(this.actions.worktreePath()); + } catch { + // The empty-workspace message below is more useful than surfacing this as a connection error. + } + const editorContext = this.actions.editorContext(); + this.#loadAttachmentUrls(this.client.activeThread); + void view.webview.postMessage({ + type: "state", + state: { + busy: this.#busy, + error: this.#error, + connected: this.client.serverConfig !== null, + environmentLabel: this.client.serverConfig?.environment.label ?? "T3 Code", + threads: threads.map((thread) => ({ + id: thread.id, + title: thread.title, + model: thread.modelSelection.model, + status: resolveThreadDisplayStatus(thread), + updatedAt: thread.updatedAt, + })), + activeThread: this.#serializeThread(this.client.activeThread), + models: + this.client.serverConfig?.providers + .filter((provider) => provider.enabled && provider.installed) + .flatMap((provider) => + provider.models.map((model) => ({ + instanceId: provider.instanceId, + model: model.slug, + driver: provider.driver, + providerLabel: provider.displayName ?? provider.driver, + modelLabel: model.name, + optionDescriptors: model.capabilities?.optionDescriptors ?? [], + })), + ) ?? [], + favoriteProviderIds: this.actions.favoriteProviderIds(), + favoriteModelKeys: this.actions.favoriteModelKeys(), + contextEnabled: this.actions.contextEnabled(), + editorContext: + editorContext === null + ? null + : { + path: editorContext.relativePath, + startLine: editorContext.startLine, + endLine: editorContext.endLine, + kind: editorContext.kind, + }, + }, + }); + } + + #serializeThread(thread: OrchestrationThread | null) { + if (thread === null) return null; + return { + id: thread.id, + title: thread.title, + model: thread.modelSelection.model, + instanceId: thread.modelSelection.instanceId, + runtimeMode: thread.runtimeMode, + status: resolveThreadDisplayStatus({ + latestTurn: thread.latestTurn, + session: thread.session, + }), + turnStartedAt: thread.latestTurn?.startedAt ?? thread.latestTurn?.requestedAt ?? null, + pendingInteractions: derivePendingInteractions(thread.activities), + tasks: presentTasks(thread.activities, thread.latestTurn?.turnId ?? null), + toolCalls: presentToolCalls(thread.activities, { + latestTurn: thread.latestTurn, + session: thread.session, + }), + resolvedUserInputs: presentResolvedUserInputs(thread.activities), + messages: thread.messages.map((message) => ({ + id: message.id, + role: message.role, + text: message.text, + streaming: message.streaming, + createdAt: message.createdAt, + attachments: (message.attachments ?? []).map((attachment) => ({ + ...attachment, + previewUrl: this.#attachmentUrls.get(attachment.id) ?? null, + })), + })), + }; + } + + #loadAttachmentUrls(thread: OrchestrationThread | null): void { + for (const message of thread?.messages ?? []) { + for (const attachment of message.attachments ?? []) { + if (this.#attachmentUrls.has(attachment.id) || this.#attachmentLoads.has(attachment.id)) { + continue; + } + this.#attachmentLoads.add(attachment.id); + void this.client + .createAttachmentUrl(attachment.id) + .then((url) => vscode.env.asExternalUri(vscode.Uri.parse(url))) + .then((uri) => this.#attachmentUrls.set(attachment.id, uri.toString(true))) + .catch(() => undefined) + .finally(() => { + this.#attachmentLoads.delete(attachment.id); + this.#publish(); + }); + } + } + } + + async #openLink(rawHref: string): Promise { + const href = rawHref.trim(); + if (href === "" || href.startsWith("#")) return; + if (/^https?:\/\//iu.test(href)) { + await vscode.env.openExternal(vscode.Uri.parse(href)); + return; + } + if (/^[a-z][a-z0-9+.-]*:/iu.test(href) && !href.startsWith("file:")) return; + const [pathPart = "", fragment = ""] = href.replace(/^file:\/\//iu, "").split("#", 2); + const worktree = this.actions.worktreePath(); + const uri = pathPart.startsWith("/") + ? vscode.Uri.file(pathPart) + : vscode.Uri.joinPath(vscode.Uri.file(worktree), pathPart); + // Defense-in-depth: only allow files inside the current worktree (consistent with editor context). + const normalizedWorktree = worktree.replace(/\\/gu, "/"); + const normalizedPath = uri.fsPath.replace(/\\/gu, "/"); + if ( + !normalizedPath.startsWith(normalizedWorktree + "/") && + normalizedPath !== normalizedWorktree + ) { + void vscode.window.showWarningMessage("Cannot open file outside the current worktree."); + return; + } + const document = await vscode.workspace.openTextDocument(uri); + const lineMatch = /^(?:L)?(\d+)/u.exec(fragment); + const line = Math.max(0, Number(lineMatch?.[1] ?? 1) - 1); + await vscode.window.showTextDocument(document, { + selection: new vscode.Range(line, 0, line, 0), + preview: true, + }); + } + + #html(webview: vscode.Webview): string { + const scriptNonce = nonce(); + const scriptUri = webview.asWebviewUri( + vscode.Uri.joinPath(this.extensionUri, "dist", "webview.js"), + ); + return ` + + + + + + + + +

+
+ + + +
+
Connecting to T3 Code…
+
+
+
+
+
+
+
+
+
+ + +`; + } +} diff --git a/apps/vscode/src/desktopFavorites.ts b/apps/vscode/src/desktopFavorites.ts new file mode 100644 index 00000000000..8d0d676d5c1 --- /dev/null +++ b/apps/vscode/src/desktopFavorites.ts @@ -0,0 +1,196 @@ +// @effect-diagnostics nodeBuiltinImport:off - VS Code extension host persistence uses Node's filesystem directly. +import * as NodeFS from "node:fs"; +import * as NodeOS from "node:os"; +import * as NodePath from "node:path"; +import * as vscode from "vscode"; + +interface FavoriteEntry { + readonly provider: string; + readonly model: string; +} + +interface DesktopServerRuntime { + readonly origin?: unknown; +} + +export async function readDesktopServerUrl(): Promise { + for (const candidate of [ + NodePath.join(NodeOS.homedir(), ".t3", "userdata", "server-runtime.json"), + NodePath.join(NodeOS.homedir(), ".t3", "dev", "server-runtime.json"), + ]) { + try { + const runtime = JSON.parse( + await NodeFS.promises.readFile(candidate, "utf8"), + ) as DesktopServerRuntime; + if (typeof runtime.origin === "string" && runtime.origin.trim() !== "") { + return new URL(runtime.origin).toString(); + } + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== "ENOENT") continue; + } + } + return null; +} + +export async function readDesktopBootstrapCredential(): Promise { + for (const candidate of [ + NodePath.join(NodeOS.homedir(), ".t3", "userdata", "local-bootstrap-credential"), + NodePath.join(NodeOS.homedir(), ".t3", "dev", "local-bootstrap-credential"), + ]) { + try { + const credential = (await NodeFS.promises.readFile(candidate, "utf8")).trim(); + if (credential !== "") return credential; + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== "ENOENT") continue; + } + } + return null; +} + +function isFavoriteEntry(value: unknown): value is FavoriteEntry { + return ( + typeof value === "object" && + value !== null && + "provider" in value && + typeof value.provider === "string" && + "model" in value && + typeof value.model === "string" + ); +} + +function parseDocument(text: string): Record { + const value: unknown = JSON.parse(text); + if (typeof value !== "object" || value === null || Array.isArray(value)) { + throw new Error("T3 desktop client settings are not a JSON object."); + } + return value as Record; +} + +export class DesktopFavoritesStore implements vscode.Disposable { + readonly #changed = new vscode.EventEmitter(); + #watcher: vscode.FileSystemWatcher | null = null; + #settingsPath = ""; + #favorites: ReadonlyArray = []; + #providerFavorites: ReadonlyArray = []; + + readonly onDidChange = this.#changed.event; + + get providerIds(): ReadonlyArray { + return this.#providerFavorites; + } + + get modelKeys(): ReadonlyArray { + return this.#favorites.map((favorite) => `${favorite.provider}:${favorite.model}`); + } + + async initialize(): Promise { + this.#settingsPath = await this.#resolveSettingsPath(); + await this.#reload(); + this.#watcher?.dispose(); + this.#watcher = vscode.workspace.createFileSystemWatcher( + new vscode.RelativePattern( + NodePath.dirname(this.#settingsPath), + NodePath.basename(this.#settingsPath), + ), + ); + this.#watcher.onDidChange(() => void this.#reload()); + this.#watcher.onDidCreate(() => void this.#reload()); + this.#watcher.onDidDelete(() => { + this.#favorites = []; + this.#providerFavorites = []; + this.#changed.fire(); + }); + } + + async toggleProvider(instanceId: string): Promise { + await this.#update((document) => { + const favorites = Array.isArray(document.providerFavorites) + ? document.providerFavorites.filter((value): value is string => typeof value === "string") + : []; + const index = favorites.indexOf(instanceId); + if (index >= 0) favorites.splice(index, 1); + else favorites.push(instanceId); + document.providerFavorites = favorites; + }); + } + + async toggleModel(modelKey: string): Promise { + const separator = modelKey.indexOf(":"); + if (separator <= 0 || separator === modelKey.length - 1) { + throw new Error("Invalid model favorite."); + } + await this.#toggle(modelKey.slice(0, separator), modelKey.slice(separator + 1)); + } + + dispose(): void { + this.#watcher?.dispose(); + this.#changed.dispose(); + } + + async #resolveSettingsPath(): Promise { + const configured = vscode.workspace + .getConfiguration("t3Code") + .get("desktopClientSettingsPath", "") + .trim(); + if (configured !== "") return configured.replace(/^~/u, NodeOS.homedir()); + const candidates = [ + NodePath.join(NodeOS.homedir(), ".t3", "userdata", "client-settings.json"), + NodePath.join(NodeOS.homedir(), ".t3", "dev", "client-settings.json"), + ]; + for (const candidate of candidates) { + try { + await NodeFS.promises.access(candidate); + return candidate; + } catch { + // Try the next desktop channel. + } + } + return candidates[0]!; + } + + async #reload(): Promise { + try { + const document = parseDocument(await NodeFS.promises.readFile(this.#settingsPath, "utf8")); + this.#favorites = Array.isArray(document.favorites) + ? document.favorites.filter(isFavoriteEntry) + : []; + this.#providerFavorites = Array.isArray(document.providerFavorites) + ? document.providerFavorites.filter((value): value is string => typeof value === "string") + : []; + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== "ENOENT") throw cause; + this.#favorites = []; + this.#providerFavorites = []; + } + this.#changed.fire(); + } + + async #toggle(provider: string, model: string): Promise { + await this.#update((document) => { + const favorites = Array.isArray(document.favorites) + ? document.favorites.filter(isFavoriteEntry) + : []; + const index = favorites.findIndex( + (favorite) => favorite.provider === provider && favorite.model === model, + ); + if (index >= 0) favorites.splice(index, 1); + else favorites.push({ provider, model }); + document.favorites = favorites; + }); + } + + async #update(mutate: (document: Record) => void): Promise { + let document: Record = {}; + try { + document = parseDocument(await NodeFS.promises.readFile(this.#settingsPath, "utf8")); + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== "ENOENT") throw cause; + } + mutate(document); + await NodeFS.promises.mkdir(NodePath.dirname(this.#settingsPath), { recursive: true }); + const temporaryPath = `${this.#settingsPath}.${process.pid}.tmp`; + await NodeFS.promises.writeFile(temporaryPath, `${JSON.stringify(document)}\n`, "utf8"); + await NodeFS.promises.rename(temporaryPath, this.#settingsPath); + await this.#reload(); + } +} diff --git a/apps/vscode/src/editorContext.test.ts b/apps/vscode/src/editorContext.test.ts new file mode 100644 index 00000000000..608590d4dda --- /dev/null +++ b/apps/vscode/src/editorContext.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { composePrompt, renderTextContext, splitEditorContext } from "./editorContext.ts"; + +describe("editor context", () => { + it("describes precise selections", () => { + expect( + renderTextContext({ + relativePath: "src/main.ts", + languageId: "typescript", + text: "const answer = 42;", + startLine: 8, + endLine: 8, + kind: "selection", + }), + ).toContain("src/main.ts (line 8)\n```typescript\nconst answer = 42;\n```"); + }); + + it("keeps context separate from the authored prompt", () => { + const rendered = composePrompt("Explain this", [ + { + relativePath: "readme.md", + languageId: "markdown", + text: "hello", + startLine: 1, + endLine: 1, + cursorColumn: 3, + kind: "cursor-line", + }, + ]); + expect(rendered).toMatch(/^Explain this\n\n/); + expect(rendered).toContain("line 1, column 3"); + expect(splitEditorContext(rendered)).toEqual({ + text: "Explain this", + references: [{ path: "readme.md", detail: "line 1, column 3" }], + }); + }); +}); diff --git a/apps/vscode/src/editorContext.ts b/apps/vscode/src/editorContext.ts new file mode 100644 index 00000000000..e7254520e4e --- /dev/null +++ b/apps/vscode/src/editorContext.ts @@ -0,0 +1,55 @@ +export interface TextContext { + readonly relativePath: string; + readonly languageId: string; + readonly text: string; + readonly startLine: number; + readonly endLine: number; + readonly cursorColumn?: number; + readonly kind: "selection" | "cursor-line" | "reference"; +} + +export interface ParsedEditorContext { + readonly text: string; + readonly references: ReadonlyArray<{ readonly path: string; readonly detail: string }>; +} + +const MAX_CONTEXT_CHARS = 48_000; + +function fenceFor(text: string): string { + let fence = "```"; + while (text.includes(fence)) fence += "`"; + return fence; +} + +export function renderTextContext(context: TextContext): string { + const clipped = + context.text.length > MAX_CONTEXT_CHARS + ? `${context.text.slice(0, MAX_CONTEXT_CHARS)}\n… (context truncated)` + : context.text; + const range = + context.startLine === context.endLine + ? `line ${context.startLine}` + : `lines ${context.startLine}-${context.endLine}`; + const cursor = context.cursorColumn === undefined ? "" : `, column ${context.cursorColumn}`; + const fence = fenceFor(clipped); + return `### ${context.relativePath} (${range}${cursor})\n${fence}${context.languageId}\n${clipped}\n${fence}`; +} + +export function composePrompt(prompt: string, contexts: ReadonlyArray): string { + if (contexts.length === 0) return prompt; + return `${prompt}\n\n\n${contexts.map(renderTextContext).join("\n\n")}\n`; +} + +export function splitEditorContext(prompt: string): ParsedEditorContext { + const references: Array<{ path: string; detail: string }> = []; + const text = prompt.replace( + /\n*\s*([\s\S]*?)\s*<\/editor_context>\s*/gu, + (_match, body: string) => { + for (const heading of body.matchAll(/^###\s+(.+?)\s+\(([^\n)]+)\)\s*$/gmu)) { + references.push({ path: heading[1]!, detail: heading[2]! }); + } + return ""; + }, + ); + return { text: text.trim(), references }; +} diff --git a/apps/vscode/src/extension.ts b/apps/vscode/src/extension.ts new file mode 100644 index 00000000000..ba741a0b20c --- /dev/null +++ b/apps/vscode/src/extension.ts @@ -0,0 +1,462 @@ +// @effect-diagnostics globalDate:off +import type { + ModelSelection, + OrchestrationMessage, + OrchestrationThread, + OrchestrationThreadShell, + RuntimeMode, + ThreadId, +} from "@t3tools/contracts"; +import * as vscode from "vscode"; + +import { composePrompt, type TextContext } from "./editorContext.ts"; +import { + DesktopFavoritesStore, + readDesktopBootstrapCredential, + readDesktopServerUrl, +} from "./desktopFavorites.ts"; +import { serverCandidates } from "./serverResolution.ts"; +import { T3ChatViewProvider } from "./chatViewProvider.ts"; +import { T3Client } from "./t3Client.ts"; + +const ACTIVE_THREAD_KEY_PREFIX = "t3Code.activeThread"; +const BEARER_TOKEN_SECRET = "t3Code.serverBearerToken"; + +function workspaceFolder(): vscode.WorkspaceFolder | undefined { + const activeUri = vscode.window.activeTextEditor?.document.uri; + return ( + (activeUri === undefined ? undefined : vscode.workspace.getWorkspaceFolder(activeUri)) ?? + vscode.workspace.workspaceFolders?.[0] + ); +} + +function worktreePath(): string { + const folder = workspaceFolder(); + if (folder === undefined) throw new Error("Open a workspace folder before using T3 Code."); + return folder.uri.fsPath; +} + +function activeThreadStorageKey(): string { + return `${ACTIVE_THREAD_KEY_PREFIX}:${workspaceFolder()?.uri.toString() ?? "none"}`; +} + +function relativePath(uri: vscode.Uri): string { + const folder = vscode.workspace.getWorkspaceFolder(uri); + return folder === undefined ? uri.fsPath : vscode.workspace.asRelativePath(uri, false); +} + +function languageFor(uri: vscode.Uri, fallback = "text"): string { + return ( + vscode.workspace.textDocuments.find((document) => document.uri.toString() === uri.toString()) + ?.languageId ?? fallback + ); +} + +function activeEditorContext(): TextContext | null { + const editor = vscode.window.activeTextEditor; + if (editor === undefined || editor.document.uri.scheme !== "file") return null; + const selection = editor.selection; + if (!selection.isEmpty) { + return { + relativePath: relativePath(editor.document.uri), + languageId: editor.document.languageId, + text: editor.document.getText(selection), + startLine: selection.start.line + 1, + endLine: selection.end.line + 1, + kind: "selection", + }; + } + const line = editor.document.lineAt(selection.active.line); + return { + relativePath: relativePath(editor.document.uri), + languageId: editor.document.languageId, + text: line.text, + startLine: line.lineNumber + 1, + endLine: line.lineNumber + 1, + cursorColumn: selection.active.character + 1, + kind: "cursor-line", + }; +} + +async function referenceContexts( + references: ReadonlyArray, +): Promise> { + const contexts: TextContext[] = []; + for (const reference of references.toReversed()) { + const value = reference.value; + if (value instanceof vscode.Location) { + const document = await vscode.workspace.openTextDocument(value.uri); + contexts.push({ + relativePath: relativePath(value.uri), + languageId: document.languageId, + text: document.getText(value.range), + startLine: value.range.start.line + 1, + endLine: value.range.end.line + 1, + kind: "reference", + }); + } else if (value instanceof vscode.Uri && value.scheme === "file") { + const document = await vscode.workspace.openTextDocument(value); + contexts.push({ + relativePath: relativePath(value), + languageId: languageFor(value, document.languageId), + text: document.getText(), + startLine: 1, + endLine: document.lineCount, + kind: "reference", + }); + } else if (typeof value === "string" && value.trim() !== "") { + contexts.push({ + relativePath: reference.modelDescription ?? reference.id, + languageId: "text", + text: value, + startLine: 1, + endLine: 1, + kind: "reference", + }); + } + } + return contexts; +} + +function configuration(): { + readonly serverUrl: string; + readonly runtimeMode: RuntimeMode; +} { + const config = vscode.workspace.getConfiguration("t3Code"); + return { + serverUrl: config.get("serverUrl", "http://127.0.0.1:3773"), + runtimeMode: config.get("defaultRuntimeMode", "full-access"), + }; +} + +function threadLabel( + thread: OrchestrationThreadShell, +): vscode.QuickPickItem & { threadId: ThreadId } { + const state = thread.latestTurn?.state ?? thread.session?.status ?? "idle"; + return { + label: thread.title, + description: state, + detail: `${thread.modelSelection.model} · ${new Date(thread.updatedAt).toLocaleString()}`, + threadId: thread.id, + }; +} + +function renderHistory(thread: OrchestrationThread): string { + if (thread.messages.length === 0) return "_No messages yet._"; + return thread.messages + .map( + (message) => + `**${message.role === "assistant" ? "T3 Code" : message.role}**\n\n${message.text}`, + ) + .join("\n\n---\n\n"); +} + +function newestAssistantMessage(thread: OrchestrationThread): OrchestrationMessage | null { + return thread.messages.findLast((message) => message.role === "assistant") ?? null; +} + +export function activate(context: vscode.ExtensionContext): void { + const output = vscode.window.createOutputChannel( + vscode.env.remoteName === undefined ? "T3 Code" : "T3 Code (Remote)", + ); + context.subscriptions.push(output); + const log = (message: string): void => { + output.appendLine(`${new Date().toISOString()} ${message}`); + }; + log( + `activate version=${String(context.extension.packageJSON.version)} remote=${vscode.env.remoteName ?? "local"} workspace=${workspaceFolder()?.uri.fsPath ?? "none"}`, + ); + const client = new T3Client(log); + const desktopFavorites = new DesktopFavoritesStore(); + context.subscriptions.push(desktopFavorites); + void desktopFavorites.initialize().catch((error: unknown) => { + void vscode.window.showWarningMessage( + `T3 Code could not load desktop favorites: ${error instanceof Error ? error.message : String(error)}`, + ); + }); + const [major = 1, minor = 0] = vscode.version.split(".").map(Number); + const supportsSecondarySidebar = major > 1 || (major === 1 && minor >= 106); + void vscode.commands.executeCommand( + "setContext", + "t3Code.useActivityBar", + !supportsSecondarySidebar, + ); + + const ensureConnected = async (): Promise => { + const config = configuration(); + const bearerToken = await context.secrets.get(BEARER_TOKEN_SECRET); + const bootstrapCredential = await readDesktopBootstrapCredential(); + const connect = async (serverUrl: string): Promise => { + if (bearerToken !== undefined && bearerToken !== "") { + try { + await client.connect(serverUrl, bearerToken); + return; + } catch (bearerCause) { + if (bootstrapCredential === null) throw bearerCause; + } + } + if (bootstrapCredential !== null) { + await client.connectWithBootstrap(serverUrl, bootstrapCredential); + } else { + await client.connect(serverUrl); + } + }; + const desktopServerUrl = await readDesktopServerUrl(); + const candidates = serverCandidates(desktopServerUrl, config.serverUrl); + let lastCause: unknown = new Error("No T3 Code server endpoint is available."); + for (const candidate of candidates) { + try { + log(`connection candidate source=${candidate.source} endpoint=${candidate.url}`); + await connect(candidate.url); + await client.waitForShell(); + return; + } catch (cause) { + lastCause = cause; + log( + `connection candidate failed source=${candidate.source} endpoint=${candidate.url} error=${cause instanceof Error ? cause.message : String(cause)}`, + ); + } + } + throw lastCause; + }; + + const rememberThread = async (threadId: ThreadId): Promise => { + await context.workspaceState.update(activeThreadStorageKey(), threadId); + }; + + const selectThread = async (): Promise => { + await ensureConnected(); + const threads = client.threadsForWorktree(worktreePath()); + if (threads.length === 0) { + void vscode.window.showInformationMessage("No T3 Code threads exist for this worktree yet."); + return undefined; + } + const picked = await vscode.window.showQuickPick(threads.map(threadLabel), { + title: "T3 Code threads for this worktree", + placeHolder: "Choose a synchronized thread", + }); + if (picked === undefined) return undefined; + await client.selectThread(picked.threadId); + await client.waitForActiveThread(); + await rememberThread(picked.threadId); + return picked.threadId; + }; + + const createThread = async ( + title = "New thread", + modelSelection?: ModelSelection, + ): Promise => { + await ensureConnected(); + const threadId = await client.createThreadForWorktree({ + worktreePath: worktreePath(), + title, + runtimeMode: configuration().runtimeMode, + ...(modelSelection === undefined ? {} : { modelSelection }), + }); + await rememberThread(threadId); + return threadId; + }; + + const restoreThread = async (): Promise => { + await ensureConnected(); + const stored = context.workspaceState.get(activeThreadStorageKey()); + const threads = client.threadsForWorktree(worktreePath()); + const thread = threads.find((candidate) => candidate.id === stored) ?? threads[0]; + if (thread === undefined) return undefined; + await client.selectThread(thread.id); + await client.waitForActiveThread(); + await rememberThread(thread.id); + return thread.id; + }; + + const editorContextStateKey = "t3Code.includeEditorContext"; + const contextEnabled = () => context.globalState.get(editorContextStateKey, true); + const toggleContext = async (): Promise => { + const next = !contextEnabled(); + await context.globalState.update(editorContextStateKey, next); + return next; + }; + + const selectThreadById = async (threadId: string): Promise => { + await ensureConnected(); + const thread = client.shell?.threads.find((candidate) => candidate.id === threadId); + if (thread === undefined) throw new Error("The selected T3 Code thread no longer exists."); + await client.selectThread(thread.id); + await client.waitForActiveThread(); + await rememberThread(thread.id); + }; + + const chatView = new T3ChatViewProvider( + client, + { + worktreePath, + ensureConnected, + restoreThread, + createThread, + selectThread: selectThreadById, + toggleContext, + contextEnabled, + runtimeMode: () => configuration().runtimeMode, + editorContext: activeEditorContext, + favoriteProviderIds: () => desktopFavorites.providerIds, + favoriteModelKeys: () => desktopFavorites.modelKeys, + toggleProviderFavorite: (instanceId) => desktopFavorites.toggleProvider(instanceId), + toggleModelFavorite: (modelKey) => desktopFavorites.toggleModel(modelKey), + onFavoritesChanged: desktopFavorites.onDidChange, + }, + context.extensionUri, + ); + + const handler: vscode.ChatRequestHandler = async (request, _chatContext, response, token) => { + try { + if (request.command === "context") { + const enabled = await toggleContext(); + response.markdown( + `Automatic active-editor context is now **${enabled ? "on" : "off"}**. Explicit \`#file\` and selection references are always included.`, + ); + return; + } + if (request.command === "threads") { + const selected = await selectThread(); + if (selected !== undefined) + response.markdown(`Selected synchronized thread \`${selected}\`.`); + return; + } + if (request.command === "new") { + const title = request.prompt.trim() || "New thread"; + const threadId = await createThread(title.slice(0, 80)); + response.markdown( + `Created synchronized thread **${title.slice(0, 80)}** (\`${threadId}\`).`, + ); + return; + } + const threadId = + (await restoreThread()) ?? + (await createThread(request.prompt.trim().slice(0, 80) || "New thread")); + if (request.command === "history") { + response.markdown(renderHistory(await client.waitForActiveThread())); + return; + } + if (request.command === "status") { + const thread = await client.waitForActiveThread(); + response.markdown( + `Connected to **${client.serverConfig?.environment.label ?? "T3 Code"}**.\n\nThread: **${thread.title}** \nModel: \`${thread.modelSelection.model}\` \nRuntime: \`${thread.runtimeMode}\` \nState: \`${thread.latestTurn?.state ?? thread.session?.status ?? "idle"}\``, + ); + return; + } + if (request.command === "stop") { + await client.interrupt(); + response.markdown("Interrupt requested."); + return; + } + + const explicit = await referenceContexts(request.references); + const automatic = contextEnabled() ? activeEditorContext() : null; + const contexts = automatic === null ? explicit : [automatic, ...explicit]; + const prompt = composePrompt(request.prompt, contexts); + for (const reference of request.references) { + if (reference.value instanceof vscode.Uri) response.reference(reference.value); + else if (reference.value instanceof vscode.Location) response.reference(reference.value); + } + + const initial = client.activeThread; + const initialAssistant = initial === null ? null : newestAssistantMessage(initial); + const initialTurnId = initial?.latestTurn?.turnId ?? null; + let emitted = ""; + let turnObserved = false; + let finished = false; + let disposeThreadChange = (): void => {}; + response.progress(`Sending to ${initial?.modelSelection.model ?? "T3 Code"}…`); + + const completion = new Promise((resolve, reject) => { + const disposable = client.onThreadChanged((thread) => { + if (thread === null || finished) return; + const turn = thread.latestTurn; + if (turn !== null && (turn.state === "running" || turn.turnId !== initialTurnId)) { + turnObserved = true; + } + const assistant = newestAssistantMessage(thread); + if (assistant !== null && assistant.id !== initialAssistant?.id) { + const next = assistant.text; + if (next.startsWith(emitted)) response.markdown(next.slice(emitted.length)); + else if (next !== emitted) response.markdown(`\n\n${next}`); + emitted = next; + } + if (turnObserved && turn !== null && turn.state !== "running") { + finished = true; + disposable.dispose(); + if (turn.state === "error") + reject(new Error(thread.session?.lastError ?? "The T3 Code turn failed.")); + else resolve(); + } + }); + token.onCancellationRequested(() => { + if (finished) return; + finished = true; + disposable.dispose(); + void client.interrupt().finally(resolve); + }); + disposeThreadChange = () => disposable.dispose(); + }); + try { + await client.sendPrompt({ threadId, prompt, runtimeMode: configuration().runtimeMode }); + await completion; + } finally { + disposeThreadChange(); + } + if (emitted === "") response.markdown("_Turn completed without an assistant message._"); + return { metadata: { threadId } }; + } catch (cause) { + const message = cause instanceof Error ? cause.message : String(cause); + response.markdown(`$(error) ${message}`); + return { errorDetails: { message } }; + } + }; + + const participant = vscode.chat.createChatParticipant("t3-code.chat", handler); + participant.iconPath = new vscode.ThemeIcon("comment-discussion"); + context.subscriptions.push( + vscode.commands.registerCommand("t3Code.showDiagnostics", () => output.show(true)), + chatView, + vscode.window.registerWebviewViewProvider(T3ChatViewProvider.primaryViewType, chatView, { + webviewOptions: { retainContextWhenHidden: true }, + }), + vscode.window.registerWebviewViewProvider(T3ChatViewProvider.secondaryViewType, chatView, { + webviewOptions: { retainContextWhenHidden: true }, + }), + participant, + vscode.commands.registerCommand("t3Code.newThread", async () => { + const title = await vscode.window.showInputBox({ + prompt: "Thread title", + value: "New thread", + }); + if (title !== undefined) await createThread(title.trim() || "New thread"); + }), + vscode.commands.registerCommand("t3Code.selectThread", selectThread), + vscode.commands.registerCommand("t3Code.toggleEditorContext", toggleContext), + vscode.commands.registerCommand("t3Code.askSelection", async () => { + await chatView.reveal(); + }), + vscode.commands.registerCommand("t3Code.openChat", () => chatView.reveal()), + vscode.commands.registerCommand("t3Code.setBearerToken", async () => { + const token = await vscode.window.showInputBox({ + prompt: "T3 Code server bearer token", + password: true, + ignoreFocusOut: true, + }); + if (token !== undefined && token.trim() !== "") { + await context.secrets.store(BEARER_TOKEN_SECRET, token.trim()); + void vscode.window.showInformationMessage( + "T3 Code bearer token stored in VS Code secret storage.", + ); + } + }), + vscode.commands.registerCommand("t3Code.clearBearerToken", async () => { + await context.secrets.delete(BEARER_TOKEN_SECRET); + void vscode.window.showInformationMessage("T3 Code bearer token cleared."); + }), + { dispose: () => void client.dispose() }, + ); +} + +export function deactivate(): void {} diff --git a/apps/vscode/src/ids.ts b/apps/vscode/src/ids.ts new file mode 100644 index 00000000000..e2e74dbb064 --- /dev/null +++ b/apps/vscode/src/ids.ts @@ -0,0 +1,14 @@ +import { CommandId, MessageId, ProjectId, ThreadId } from "@t3tools/contracts"; + +function randomUuid(): string { + const bytes = globalThis.crypto.getRandomValues(new Uint8Array(16)); + bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40; + bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80; + const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""); + return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`; +} + +export const newCommandId = (): CommandId => CommandId.make(randomUuid()); +export const newMessageId = (): MessageId => MessageId.make(randomUuid()); +export const newProjectId = (): ProjectId => ProjectId.make(randomUuid()); +export const newThreadId = (): ThreadId => ThreadId.make(randomUuid()); diff --git a/apps/vscode/src/pendingInteractions.test.ts b/apps/vscode/src/pendingInteractions.test.ts new file mode 100644 index 00000000000..f8326dcec33 --- /dev/null +++ b/apps/vscode/src/pendingInteractions.test.ts @@ -0,0 +1,79 @@ +import type { OrchestrationThreadActivity } from "@t3tools/contracts"; +import { describe, expect, it } from "vite-plus/test"; + +import { derivePendingInteractions } from "./pendingInteractions.ts"; + +const activity = (kind: string, payload: unknown, sequence: number): OrchestrationThreadActivity => + ({ + id: `activity-${sequence}`, + kind, + payload, + sequence, + tone: "approval", + summary: kind, + turnId: null, + createdAt: `2026-07-10T00:00:0${sequence}.000Z`, + }) as OrchestrationThreadActivity; + +describe("derivePendingInteractions", () => { + it("keeps unresolved approvals and removes resolved ones", () => { + expect( + derivePendingInteractions([ + activity("approval.requested", { requestId: "one", requestKind: "command" }, 1), + activity("approval.requested", { requestId: "two", requestType: "file_read_approval" }, 2), + activity("approval.resolved", { requestId: "one" }, 3), + ]), + ).toEqual([ + expect.objectContaining({ requestId: "two", requestKind: "file-read", kind: "approval" }), + ]); + }); + + it("preserves structured user-input questions", () => { + const [pending] = derivePendingInteractions([ + activity( + "user-input.requested", + { + requestId: "question", + questions: [ + { + id: "choice", + header: "Choice", + question: "Which one?", + options: [{ label: "First", description: "Use the first option." }], + multiSelect: false, + }, + ], + }, + 1, + ), + ]); + expect(pending).toMatchObject({ kind: "user-input", requestId: "question" }); + }); + + it("removes requests that the provider reports as stale", () => { + expect( + derivePendingInteractions([ + activity( + "user-input.requested", + { + requestId: "stale", + questions: [ + { + id: "choice", + header: "Choice", + question: "Which?", + options: [{ label: "One", description: "First." }], + }, + ], + }, + 1, + ), + activity( + "provider.user-input.respond.failed", + { requestId: "stale", detail: "Stale pending user-input request: stale" }, + 2, + ), + ]), + ).toEqual([]); + }); +}); diff --git a/apps/vscode/src/pendingInteractions.ts b/apps/vscode/src/pendingInteractions.ts new file mode 100644 index 00000000000..75c2fc4965e --- /dev/null +++ b/apps/vscode/src/pendingInteractions.ts @@ -0,0 +1,113 @@ +import type { OrchestrationThreadActivity, UserInputQuestion } from "@t3tools/contracts"; + +export interface PendingApproval { + readonly kind: "approval"; + readonly requestId: string; + readonly requestKind: "command" | "file-read" | "file-change"; + readonly detail: string | null; + readonly createdAt: string; +} + +export interface PendingUserInput { + readonly kind: "user-input"; + readonly requestId: string; + readonly questions: ReadonlyArray; + readonly createdAt: string; +} + +export type PendingInteraction = PendingApproval | PendingUserInput; + +function record(value: unknown): Record | null { + return typeof value === "object" && value !== null && !Array.isArray(value) + ? (value as Record) + : null; +} + +function requestKind(value: unknown): PendingApproval["requestKind"] | null { + if (value === "command" || value === "file-read" || value === "file-change") return value; + if ( + value === "command_execution_approval" || + value === "exec_command_approval" || + value === "dynamic_tool_call" + ) + return "command"; + if (value === "file_read_approval") return "file-read"; + if (value === "file_change_approval" || value === "apply_patch_approval") return "file-change"; + return null; +} + +function questions(value: unknown): ReadonlyArray | null { + if (!Array.isArray(value)) return null; + const parsed = value.filter((entry): entry is UserInputQuestion => { + const question = record(entry); + return ( + typeof question?.id === "string" && + typeof question.header === "string" && + typeof question.question === "string" && + Array.isArray(question.options) && + question.options.every((option) => { + const value = record(option); + return typeof value?.label === "string" && typeof value.description === "string"; + }) + ); + }); + return parsed.length === value.length && parsed.length > 0 ? parsed : null; +} + +function isStaleFailure(payload: Record): boolean { + const detail = typeof payload.detail === "string" ? payload.detail.toLowerCase() : ""; + return ( + detail.includes("stale pending approval request") || + detail.includes("stale pending user-input request") || + detail.includes("unknown pending approval request") || + detail.includes("unknown pending user-input request") + ); +} + +export function derivePendingInteractions( + activities: ReadonlyArray, +): ReadonlyArray { + const pending = new Map(); + for (const activity of [...activities].toSorted((left, right) => { + if (left.sequence !== undefined && right.sequence !== undefined) + return left.sequence - right.sequence; + return left.createdAt.localeCompare(right.createdAt); + })) { + const payload = record(activity.payload); + if (payload === null || typeof payload.requestId !== "string") continue; + const requestId = payload.requestId; + if (activity.kind === "approval.requested") { + const kind = requestKind(payload.requestKind ?? payload.requestType); + if (kind !== null) { + pending.set(requestId, { + kind: "approval", + requestId, + requestKind: kind, + detail: typeof payload.detail === "string" ? payload.detail : null, + createdAt: activity.createdAt, + }); + } + } else if (activity.kind === "user-input.requested") { + const parsed = questions(payload.questions); + if (parsed !== null) { + pending.set(requestId, { + kind: "user-input", + requestId, + questions: parsed, + createdAt: activity.createdAt, + }); + } + } else if (activity.kind === "approval.resolved" || activity.kind === "user-input.resolved") { + pending.delete(requestId); + } else if ( + (activity.kind === "provider.approval.respond.failed" || + activity.kind === "provider.user-input.respond.failed") && + isStaleFailure(payload) + ) { + pending.delete(requestId); + } + } + return [...pending.values()].toSorted((left, right) => + left.createdAt.localeCompare(right.createdAt), + ); +} diff --git a/apps/vscode/src/providerIcon.ts b/apps/vscode/src/providerIcon.ts new file mode 100644 index 00000000000..99f527dc1fe --- /dev/null +++ b/apps/vscode/src/providerIcon.ts @@ -0,0 +1,58 @@ +interface ProviderIconSpec { + readonly viewBox: string; + readonly color?: string; + readonly paths: ReadonlyArray; +} + +const ICONS: Readonly> = { + codex: { + viewBox: "0 0 256 260", + paths: [ + "M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z", + ], + }, + claudeAgent: { + viewBox: "0 0 24 24", + color: "#d97757", + paths: [ + "M12 1.5c.7 0 1.2.5 1.2 1.2v5l3.5-3.5a1.2 1.2 0 1 1 1.7 1.7l-3.5 3.5h5a1.2 1.2 0 1 1 0 2.4h-5l3.5 3.5a1.2 1.2 0 1 1-1.7 1.7l-3.5-3.5v5a1.2 1.2 0 1 1-2.4 0v-5L7.3 17a1.2 1.2 0 1 1-1.7-1.7l3.5-3.5h-5a1.2 1.2 0 1 1 0-2.4h5L5.6 5.9a1.2 1.2 0 1 1 1.7-1.7l3.5 3.5v-5c0-.7.5-1.2 1.2-1.2Z", + ], + }, + cursor: { + viewBox: "0 0 466.73 532.09", + paths: [ + "M457.43 125.94 244.42 2.96c-6.84-3.95-15.28-3.95-22.12 0L9.3 125.94C3.55 129.26 0 135.4 0 142.05v247.99c0 6.65 3.55 12.79 9.3 16.11l213.01 122.98c6.84 3.95 15.28 3.95 22.12 0l213.01-122.98c5.75-3.32 9.3-9.46 9.3-16.11V142.05c0-6.65-3.55-12.79-9.3-16.11ZM444.05 151.99 238.42 508.15c-1.39 2.4-5.06 1.42-5.06-1.36V273.58c0-4.66-2.49-8.97-6.53-11.31L24.87 145.67c-2.4-1.39-1.42-5.06 1.36-5.06h411.26c5.84 0 9.49 6.33 6.57 11.39Z", + ], + }, + grok: { + viewBox: "0 0 24 24", + paths: [ + "M9.269 15.284 17.248 9.361c.391-.291.95-.177 1.137.274.98 2.378.542 5.237-1.41 7.2-1.951 1.963-4.667 2.393-7.149 1.413l-2.711 1.262c3.889 2.673 8.612 2.012 11.563-.958 2.34-2.354 3.065-5.563 2.387-8.456-.983-4.245.242-5.944 2.757-9.668l-3.123 3.32L9.269 15.284Zm-1.647 1.44c-2.791-2.682-2.31-6.832.072-9.225 1.761-1.771 4.647-2.494 7.166-1.431l2.705-1.257c-.487-.354-1.112-.735-1.828-1.003-3.24-1.34-7.119-.673-9.753 1.973-2.533 2.548-3.33 6.465-1.962 9.808 1.384 3.383-2.2 5.816-4.022 7.983l7.622-6.848Z", + ], + }, + opencode: { + viewBox: "0 0 32 40", + paths: ["M24 32H8V16h16v16Z", "M24 8H8v24h16V8Zm8 32H0V0h32v40Z"], + }, +}; + +const SVG_NS = "http://www.w3.org/2000/svg"; + +export function renderProviderIcon(container: HTMLElement, driver: string, label: string): void { + container.replaceChildren(); + const spec = ICONS[driver]; + if (spec === undefined) { + container.textContent = label.slice(0, 2).toUpperCase(); + return; + } + const svg = document.createElementNS(SVG_NS, "svg"); + svg.setAttribute("viewBox", spec.viewBox); + svg.setAttribute("aria-hidden", "true"); + svg.setAttribute("fill", spec.color ?? "currentColor"); + for (const pathData of spec.paths) { + const path = document.createElementNS(SVG_NS, "path"); + path.setAttribute("d", pathData); + svg.append(path); + } + container.append(svg); +} diff --git a/apps/vscode/src/serverResolution.test.ts b/apps/vscode/src/serverResolution.test.ts new file mode 100644 index 00000000000..010aa425eaf --- /dev/null +++ b/apps/vscode/src/serverResolution.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { serverCandidates } from "./serverResolution.ts"; + +describe("serverCandidates", () => { + it("prefers the backend advertised by the local desktop runtime", () => { + expect(serverCandidates("http://127.0.0.1:3773", "http://127.0.0.1:8080")).toEqual([ + { source: "desktop", url: "http://127.0.0.1:3773/" }, + { source: "configured", url: "http://127.0.0.1:8080/" }, + ]); + }); + + it("deduplicates equivalent desktop and configured URLs", () => { + expect(serverCandidates("http://127.0.0.1:3773", "http://127.0.0.1:3773/")).toEqual([ + { source: "desktop", url: "http://127.0.0.1:3773/" }, + ]); + }); + + it("uses the configured URL when no desktop runtime is advertised", () => { + expect(serverCandidates(null, "http://remote.example:8080")).toEqual([ + { source: "configured", url: "http://remote.example:8080/" }, + ]); + }); +}); diff --git a/apps/vscode/src/serverResolution.ts b/apps/vscode/src/serverResolution.ts new file mode 100644 index 00000000000..8ada338919e --- /dev/null +++ b/apps/vscode/src/serverResolution.ts @@ -0,0 +1,28 @@ +export interface ServerCandidate { + readonly source: "desktop" | "configured"; + readonly url: string; +} + +function normalizeServerUrl(value: string | null): string | null { + if (value === null || value.trim() === "") return null; + return new URL(value).toString(); +} + +/** + * Prefer the backend advertised by the T3 process running beside this + * extension host. A configured localhost URL may be synced between machines + * or refer to a VS Code-forwarded port, so it is only a fallback. + */ +export function serverCandidates( + desktopServerUrl: string | null, + configuredServerUrl: string, +): ReadonlyArray { + const desktop = normalizeServerUrl(desktopServerUrl); + const configured = normalizeServerUrl(configuredServerUrl); + const candidates: Array = []; + if (desktop !== null) candidates.push({ source: "desktop", url: desktop }); + if (configured !== null && configured !== desktop) { + candidates.push({ source: "configured", url: configured }); + } + return candidates; +} diff --git a/apps/vscode/src/t3Client.ts b/apps/vscode/src/t3Client.ts new file mode 100644 index 00000000000..1b42d72b9d5 --- /dev/null +++ b/apps/vscode/src/t3Client.ts @@ -0,0 +1,670 @@ +// @effect-diagnostics globalDate:off globalFetch:off +import { + DEFAULT_MODEL, + DEFAULT_RUNTIME_MODE, + EnvironmentId, + ORCHESTRATION_WS_METHODS, + PRIMARY_LOCAL_ENVIRONMENT_ID, + ProviderInstanceId, + type ClientOrchestrationCommand, + type ModelSelection, + type OrchestrationProjectShell, + OrchestrationShellSnapshot, + OrchestrationThreadDetailSnapshot, + type OrchestrationThread, + type OrchestrationThreadShell, + type RuntimeMode, + type ApprovalRequestId, + type ProviderApprovalDecision, + type ProviderUserInputAnswers, + type ServerConfig, + type ThreadId, + type UploadChatAttachment, + WS_METHODS, +} from "@t3tools/contracts"; +import { + PrimaryConnectionTarget, + type PreparedConnection, +} from "@t3tools/client-runtime/connection"; +import { + remoteHttpClientLayer, + type RpcSession, + makeWsRpcProtocolClient, +} from "@t3tools/client-runtime/rpc"; +import { + bootstrapRemoteBearerSession, + resolveRemoteWebSocketConnectionUrl, +} from "@t3tools/client-runtime/authorization"; +import { fetchRemoteEnvironmentDescriptor } from "@t3tools/client-runtime/environment"; +import { applyShellStreamEvent } from "@t3tools/client-runtime/state/shell"; +import { applyThreadDetailEvent } from "@t3tools/client-runtime/state/threads"; +import * as Deferred from "effect/Deferred"; +import * as Effect from "effect/Effect"; +import * as Exit from "effect/Exit"; +import * as Fiber from "effect/Fiber"; +import * as Layer from "effect/Layer"; +import * as ManagedRuntime from "effect/ManagedRuntime"; +import * as Scope from "effect/Scope"; +import * as Schema from "effect/Schema"; +import * as Stream from "effect/Stream"; +import * as Schedule from "effect/Schedule"; +import * as Socket from "effect/unstable/socket/Socket"; +import * as RpcClient from "effect/unstable/rpc/RpcClient"; +import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization"; + +import { newCommandId, newMessageId, newProjectId, newThreadId } from "./ids.ts"; + +type ThreadListener = (thread: OrchestrationThread | null) => void; +type ShellListener = (shell: OrchestrationShellSnapshot) => void; +type ConnectionListener = (connected: boolean) => void; + +function wsBaseUrl(httpBaseUrl: string): string { + const url = new URL(httpBaseUrl); + url.protocol = url.protocol === "https:" ? "wss:" : "ws:"; + return url.toString(); +} + +function localSocketUrl(httpBaseUrl: string): string { + const url = new URL(wsBaseUrl(httpBaseUrl)); + url.pathname = "/ws"; + url.search = ""; + url.hash = ""; + return url.toString(); +} + +function normalizedPath(path: string): string { + return path.replaceAll("\\", "/").replace(/\/$/u, "").toLocaleLowerCase(); +} + +function messageFromCause(cause: unknown): string { + if (cause instanceof Error && cause.message.trim() !== "") return cause.message; + return String(cause); +} + +export class T3Client { + readonly #log: (message: string) => void; + readonly #runtime = ManagedRuntime.make( + Layer.merge( + Layer.succeed( + Socket.WebSocketConstructor, + (url: string, protocols?: string | string[]) => new globalThis.WebSocket(url, protocols), + ), + remoteHttpClientLayer((input, init) => globalThis.fetch(input, init)), + ), + ); + #scope: Scope.Closeable | null = null; + #session: RpcSession | null = null; + #shellFiber: Fiber.Fiber | null = null; + #threadFiber: Fiber.Fiber | null = null; + #closedFiber: Fiber.Fiber | null = null; + #shell: OrchestrationShellSnapshot | null = null; + #activeThread: OrchestrationThread | null = null; + #activeThreadSequence: number | null = null; + #activeThreadId: ThreadId | null = null; + #serverConfig: ServerConfig | null = null; + #httpBaseUrl: string | null = null; + #bearerToken: string | null = null; + #connectionKey = ""; + #listeners = new Set(); + #shellListeners = new Set(); + #connectionListeners = new Set(); + #shellWaiters = new Set<(snapshot: OrchestrationShellSnapshot) => void>(); + #threadWaiters = new Set<(thread: OrchestrationThread) => void>(); + + constructor(log: (message: string) => void = () => {}) { + this.#log = log; + } + + get shell(): OrchestrationShellSnapshot | null { + return this.#shell; + } + + get activeThread(): OrchestrationThread | null { + return this.#activeThread; + } + + get serverConfig(): ServerConfig | null { + return this.#serverConfig; + } + + onThreadChanged(listener: ThreadListener): { dispose(): void } { + this.#listeners.add(listener); + return { dispose: () => this.#listeners.delete(listener) }; + } + + onShellChanged(listener: ShellListener): { dispose(): void } { + this.#shellListeners.add(listener); + return { dispose: () => this.#shellListeners.delete(listener) }; + } + + onConnectionChanged(listener: ConnectionListener): { dispose(): void } { + this.#connectionListeners.add(listener); + return { dispose: () => this.#connectionListeners.delete(listener) }; + } + + async waitForShell(): Promise { + if (this.#shell !== null) return this.#shell; + return new Promise((resolve) => this.#shellWaiters.add(resolve)); + } + + async waitForActiveThread(): Promise { + if (this.#activeThread !== null) return this.#activeThread; + return new Promise((resolve) => this.#threadWaiters.add(resolve)); + } + + async connect(httpBaseUrl: string, bearerToken?: string): Promise { + const startedAt = Date.now(); + const normalizedBaseUrl = new URL(httpBaseUrl).toString(); + const key = `${normalizedBaseUrl}|${bearerToken ?? ""}`; + if (this.#session !== null && this.#connectionKey === key) return; + this.#log(`connect start endpoint=${normalizedBaseUrl}`); + await this.#closeConnection(); + + let environmentId = EnvironmentId.make(PRIMARY_LOCAL_ENVIRONMENT_ID); + let socketUrl = localSocketUrl(normalizedBaseUrl); + let label = "T3 Code"; + if (bearerToken !== undefined && bearerToken !== "") { + const descriptor = await this.#runtime.runPromise( + fetchRemoteEnvironmentDescriptor({ httpBaseUrl: normalizedBaseUrl }), + ); + socketUrl = await this.#runtime.runPromise( + resolveRemoteWebSocketConnectionUrl({ + wsBaseUrl: wsBaseUrl(normalizedBaseUrl), + httpBaseUrl: normalizedBaseUrl, + bearerToken, + }), + ); + label = descriptor.label; + environmentId = descriptor.environmentId; + } + const target = new PrimaryConnectionTarget({ + environmentId, + label, + httpBaseUrl: normalizedBaseUrl, + wsBaseUrl: wsBaseUrl(normalizedBaseUrl), + }); + const prepared: PreparedConnection = { + environmentId, + label, + httpBaseUrl: normalizedBaseUrl, + socketUrl, + httpAuthorization: + bearerToken === undefined || bearerToken === "" + ? null + : { _tag: "Bearer", token: bearerToken }, + target, + }; + const scope = await this.#runtime.runPromise(Scope.make()); + try { + const session = (await this.#runtime.runPromise( + this.#buildRpcSession(prepared).pipe(Scope.provide(scope)) as any, + )) as RpcSession; + this.#scope = scope; + this.#session = session; + this.#connectionKey = key; + this.#serverConfig = await this.#runtime.runPromise((session as any).initialConfig); + this.#log(`rpc ready in ${Date.now() - startedAt}ms endpoint=${normalizedBaseUrl}`); + this.#httpBaseUrl = normalizedBaseUrl; + this.#bearerToken = bearerToken ?? null; + await this.#loadShellSnapshot(normalizedBaseUrl, bearerToken); + this.#emitConnection(true); + this.#startShellSubscription(session as any); + if (this.#activeThreadId !== null) + this.#startThreadSubscription(session as any, this.#activeThreadId); + this.#closedFiber = this.#runtime.runFork( + Effect.exit((session as any).closed).pipe( + Effect.tap(() => + Effect.sync(() => { + if (this.#session === session) { + this.#session = null; + this.#serverConfig = null; + this.#connectionKey = ""; + this.#emitConnection(false); + } + }), + ), + Effect.asVoid, + ) as any, + ); + this.#log(`connect complete in ${Date.now() - startedAt}ms endpoint=${normalizedBaseUrl}`); + } catch (cause) { + await this.#runtime.runPromise(Scope.close(scope, Exit.void)); + throw new Error(`Could not connect to T3 Code: ${messageFromCause(cause)}`, { cause }); + } + } + + async connectWithBootstrap(httpBaseUrl: string, credential: string): Promise { + const baseUrl = new URL(httpBaseUrl); + if (this.#session !== null && this.#httpBaseUrl === baseUrl.toString()) return; + const startedAt = Date.now(); + this.#log(`bootstrap start endpoint=${baseUrl}`); + const session = await this.#runtime.runPromise( + bootstrapRemoteBearerSession({ + httpBaseUrl, + credential, + clientMetadata: { label: "T3 Code for VS Code", deviceType: "desktop" }, + }), + ); + this.#log(`bootstrap complete in ${Date.now() - startedAt}ms endpoint=${baseUrl}`); + await this.connect(httpBaseUrl, session.access_token); + } + + projectsForWorktree(worktreePath: string): ReadonlyArray { + const shell = this.#shell; + if (shell === null) return []; + const target = normalizedPath(worktreePath); + const projectIds = new Set( + shell.threads + .filter((thread) => { + const project = shell.projects.find((candidate) => candidate.id === thread.projectId); + return normalizedPath(thread.worktreePath ?? project?.workspaceRoot ?? "") === target; + }) + .map((thread) => thread.projectId), + ); + return shell.projects.filter( + (project) => normalizedPath(project.workspaceRoot) === target || projectIds.has(project.id), + ); + } + + threadsForWorktree(worktreePath: string): ReadonlyArray { + const shell = this.#shell; + if (shell === null) return []; + const target = normalizedPath(worktreePath); + return shell.threads + .filter((thread) => { + const project = shell.projects.find((candidate) => candidate.id === thread.projectId); + return normalizedPath(thread.worktreePath ?? project?.workspaceRoot ?? "") === target; + }) + .toSorted((left, right) => right.updatedAt.localeCompare(left.updatedAt)); + } + + async selectThread(threadId: ThreadId): Promise { + const session = this.#requireSession(); + this.#activeThreadId = threadId; + this.#activeThread = null; + this.#activeThreadSequence = null; + this.#emitThread(); + await this.#stopThreadSubscription(); + await this.#loadThreadSnapshot(threadId); + this.#startThreadSubscription(session, threadId); + } + + async createThreadForWorktree(input: { + readonly worktreePath: string; + readonly title: string; + readonly runtimeMode?: RuntimeMode; + readonly modelSelection?: ModelSelection; + }): Promise { + const session = this.#requireSession(); + const createdAt = new Date().toISOString(); + let project = this.projectsForWorktree(input.worktreePath)[0]; + if (project === undefined) { + const projectId = newProjectId(); + const modelSelection = input.modelSelection ?? this.#defaultModelSelection(); + await this.#dispatch({ + type: "project.create", + commandId: newCommandId(), + projectId, + title: input.worktreePath.split(/[\\/]/u).at(-1) ?? "Workspace", + workspaceRoot: input.worktreePath, + defaultModelSelection: modelSelection, + createdAt, + }); + project = { + id: projectId, + title: input.worktreePath.split(/[\\/]/u).at(-1) ?? "Workspace", + workspaceRoot: input.worktreePath, + defaultModelSelection: modelSelection, + scripts: [], + createdAt, + updatedAt: createdAt, + }; + } + const threadId = newThreadId(); + const modelSelection = + input.modelSelection ?? project.defaultModelSelection ?? this.#defaultModelSelection(); + const isProjectRoot = + normalizedPath(project.workspaceRoot) === normalizedPath(input.worktreePath); + await this.#dispatch({ + type: "thread.create", + commandId: newCommandId(), + threadId, + projectId: project.id, + title: input.title, + modelSelection, + runtimeMode: input.runtimeMode ?? DEFAULT_RUNTIME_MODE, + interactionMode: "default", + branch: null, + worktreePath: isProjectRoot ? null : input.worktreePath, + createdAt, + }); + this.#activeThreadId = threadId; + this.#activeThread = null; + this.#activeThreadSequence = null; + await this.#stopThreadSubscription(); + this.#startThreadSubscription(session, threadId); + return threadId; + } + + async sendPrompt(input: { + readonly threadId: ThreadId; + readonly prompt: string; + readonly runtimeMode?: RuntimeMode; + readonly modelSelection?: ModelSelection; + readonly attachments?: ReadonlyArray; + }): Promise { + const thread = this.#activeThread; + const modelSelection = + input.modelSelection ?? thread?.modelSelection ?? this.#defaultModelSelection(); + await this.#dispatch({ + type: "thread.turn.start", + commandId: newCommandId(), + threadId: input.threadId, + message: { + messageId: newMessageId(), + role: "user", + text: input.prompt, + attachments: input.attachments ?? [], + }, + modelSelection, + titleSeed: input.prompt.trim().slice(0, 80) || "New thread", + runtimeMode: input.runtimeMode ?? thread?.runtimeMode ?? DEFAULT_RUNTIME_MODE, + interactionMode: thread?.interactionMode ?? "default", + createdAt: new Date().toISOString(), + }); + } + + async setModelSelection(modelSelection: ModelSelection): Promise { + const thread = this.#activeThread; + if (thread === null) throw new Error("Select a T3 Code thread before changing models."); + await this.#dispatch({ + type: "thread.meta.update", + commandId: newCommandId(), + threadId: thread.id, + modelSelection, + }); + } + + async createAttachmentUrl(attachmentId: string): Promise { + const session = this.#requireSession(); + const httpBaseUrl = this.#httpBaseUrl; + if (httpBaseUrl === null) throw new Error("T3 Code is not connected."); + const result = await this.#runtime.runPromise( + session.client[WS_METHODS.assetsCreateUrl]({ + resource: { _tag: "attachment", attachmentId }, + }), + ); + return new URL(result.relativeUrl, httpBaseUrl).toString(); + } + + async interrupt(): Promise { + const thread = this.#activeThread; + if (thread === null) return; + await this.#dispatch({ + type: "thread.turn.interrupt", + commandId: newCommandId(), + threadId: thread.id, + ...(thread.latestTurn?.turnId === undefined ? {} : { turnId: thread.latestTurn.turnId }), + createdAt: new Date().toISOString(), + }); + } + + async respondToApproval( + requestId: ApprovalRequestId, + decision: ProviderApprovalDecision, + ): Promise { + const thread = this.#activeThread; + if (thread === null) throw new Error("Select a T3 Code thread before responding."); + await this.#dispatch({ + type: "thread.approval.respond", + commandId: newCommandId(), + threadId: thread.id, + requestId, + decision, + createdAt: new Date().toISOString(), + }); + } + + async respondToUserInput( + requestId: ApprovalRequestId, + answers: ProviderUserInputAnswers, + ): Promise { + const thread = this.#activeThread; + if (thread === null) throw new Error("Select a T3 Code thread before responding."); + await this.#dispatch({ + type: "thread.user-input.respond", + commandId: newCommandId(), + threadId: thread.id, + requestId, + answers, + createdAt: new Date().toISOString(), + }); + } + + async dispose(): Promise { + await this.#closeConnection(); + await this.#runtime.dispose(); + } + + #requireSession(): RpcSession { + if (this.#session === null) throw new Error("T3 Code is not connected."); + return this.#session; + } + + #defaultModelSelection(): ModelSelection { + const provider = this.#serverConfig?.providers.find( + (candidate) => candidate.enabled && candidate.installed && candidate.models.length > 0, + ); + return { + instanceId: provider?.instanceId ?? ProviderInstanceId.make("codex"), + model: + provider?.models.find((model) => !model.isCustom)?.slug ?? + provider?.models[0]?.slug ?? + DEFAULT_MODEL, + }; + } + + async #dispatch(command: ClientOrchestrationCommand): Promise { + const session = this.#requireSession(); + await this.#runtime.runPromise( + session.client[ORCHESTRATION_WS_METHODS.dispatchCommand](command), + ); + } + + #startShellSubscription(session: RpcSession): void { + const stream = session.client[ORCHESTRATION_WS_METHODS.subscribeShell]( + this.#shell === null ? {} : { afterSequence: this.#shell.snapshotSequence }, + ).pipe( + Stream.runForEach((item) => + Effect.sync(() => { + if (item.kind === "snapshot") this.#shell = item.snapshot; + else if (this.#shell !== null) this.#shell = applyShellStreamEvent(this.#shell, item); + if (this.#shell !== null) { + for (const resolve of this.#shellWaiters) resolve(this.#shell); + this.#shellWaiters.clear(); + for (const listener of this.#shellListeners) listener(this.#shell); + } + }), + ), + Effect.tapCause((cause) => Effect.sync(() => this.#log(`shell stream failed ${cause}`))), + ); + this.#shellFiber = this.#runtime.runFork(stream); + } + + #buildRpcSession(prepared: PreparedConnection): Effect.Effect { + // Simplified session construction for dumbed-down upstream vscode contribution. + // Matches the shape expected by the rest of T3Client. + return Effect.gen(function* () { + const connected = yield* Deferred.make() as any; + const disconnected = yield* Deferred.make() as any; + + const hooks = (RpcClient.ConnectionHooks as any).of({ + onConnect: Effect.asVoid(Deferred.succeed(connected, undefined)), + onDisconnect: Effect.flatMap((Deferred as any).isDone(connected), (was: boolean) => + (Deferred as any).fail(disconnected, new Error(was ? "disconnected" : "connect failed")), + ), + }); + + const socketLayer = (Socket as any).layerWebSocket(prepared.socketUrl, { + openTimeout: "15 seconds", + }); + const protocolLayer = Layer.effect( + (RpcClient as any).Protocol, + (RpcClient as any).makeProtocolSocket({ + retryTransientErrors: false, + retryPolicy: Schedule.recurs(0), + }), + ).pipe( + Layer.provide( + Layer.mergeAll( + socketLayer, + (RpcSerialization as any).layerJson, + Layer.succeed((RpcClient as any).ConnectionHooks, hooks), + ), + ), + ); + + const protocolContext = yield* Layer.build(protocolLayer) as any; + const client = yield* (makeWsRpcProtocolClient as any).pipe( + Effect.provide(protocolContext), + ) as any; + + const initialConfig = yield* (client as any) + [WS_METHODS.serverGetConfig]({}) + .pipe(Effect.cached) as any; + + const ready = Effect.raceFirst( + Effect.andThen(Deferred.await(connected), initialConfig as any).pipe(Effect.asVoid), + (Deferred as any).await(disconnected) as any, + ); + + return { + client, + initialConfig, + ready, + probe: Effect.asVoid((client as any)[WS_METHODS.serverGetConfig]({})), + closed: (Deferred as any).await(disconnected), + } as unknown as RpcSession; + }) as any; + } + + async #loadShellSnapshot(httpBaseUrl: string, bearerToken?: string): Promise { + const startedAt = Date.now(); + const url = new URL("/api/orchestration/shell", httpBaseUrl); + const headers = + bearerToken === undefined || bearerToken === "" + ? {} + : { authorization: `Bearer ${bearerToken}` }; + const response = await globalThis.fetch(url, { headers }); + if (!response.ok) { + throw new Error(`Could not load T3 Code threads (HTTP ${response.status}).`); + } + const decode = Schema.decodeUnknownSync(Schema.fromJsonString(OrchestrationShellSnapshot)); + this.#shell = decode(await response.text()); + this.#log( + `shell HTTP complete in ${Date.now() - startedAt}ms projects=${this.#shell.projects.length} threads=${this.#shell.threads.length} sequence=${this.#shell.snapshotSequence}`, + ); + for (const resolve of this.#shellWaiters) resolve(this.#shell); + this.#shellWaiters.clear(); + for (const listener of this.#shellListeners) listener(this.#shell); + } + + #startThreadSubscription(session: RpcSession, threadId: ThreadId): void { + const stream = session.client[ORCHESTRATION_WS_METHODS.subscribeThread]({ + threadId, + ...(this.#activeThreadSequence === null ? {} : { afterSequence: this.#activeThreadSequence }), + }).pipe( + Stream.runForEach((item) => + Effect.sync(() => { + if (item.kind === "snapshot") { + this.#activeThread = item.snapshot.thread; + this.#activeThreadSequence = item.snapshot.snapshotSequence; + } else if (this.#activeThread !== null) { + const result = applyThreadDetailEvent(this.#activeThread, item.event); + this.#activeThread = + result.kind === "updated" + ? result.thread + : result.kind === "deleted" + ? null + : this.#activeThread; + this.#activeThreadSequence = item.event.sequence; + } + if (this.#activeThread !== null) { + for (const resolve of this.#threadWaiters) resolve(this.#activeThread); + this.#threadWaiters.clear(); + } + this.#emitThread(); + }), + ), + Effect.tapCause((cause) => + Effect.sync(() => this.#log(`thread stream failed id=${threadId} ${cause}`)), + ), + ); + this.#threadFiber = this.#runtime.runFork(stream); + } + + async #loadThreadSnapshot(threadId: ThreadId): Promise { + const startedAt = Date.now(); + if (this.#httpBaseUrl === null) throw new Error("T3 Code is not connected."); + const url = new URL( + `/api/orchestration/threads/${encodeURIComponent(threadId)}`, + this.#httpBaseUrl, + ); + const headers = + this.#bearerToken === null ? {} : { authorization: `Bearer ${this.#bearerToken}` }; + const response = await globalThis.fetch(url, { headers }); + if (!response.ok) { + throw new Error(`Could not load the T3 Code thread (HTTP ${response.status}).`); + } + const decode = Schema.decodeUnknownSync( + Schema.fromJsonString(OrchestrationThreadDetailSnapshot), + ); + const snapshot = decode(await response.text()); + this.#activeThread = snapshot.thread; + this.#activeThreadSequence = snapshot.snapshotSequence; + this.#log( + `thread HTTP complete in ${Date.now() - startedAt}ms id=${threadId} messages=${snapshot.thread.messages.length} sequence=${snapshot.snapshotSequence}`, + ); + for (const resolve of this.#threadWaiters) resolve(this.#activeThread); + this.#threadWaiters.clear(); + this.#emitThread(); + } + + #emitThread(): void { + for (const listener of this.#listeners) listener(this.#activeThread); + } + + #emitConnection(connected: boolean): void { + for (const listener of this.#connectionListeners) listener(connected); + } + + async #stopThreadSubscription(): Promise { + if (this.#threadFiber === null) return; + await this.#runtime.runPromise(Fiber.interrupt(this.#threadFiber)); + this.#threadFiber = null; + } + + async #closeConnection(): Promise { + await this.#stopThreadSubscription(); + if (this.#closedFiber !== null) { + await this.#runtime.runPromise(Fiber.interrupt(this.#closedFiber)); + this.#closedFiber = null; + } + if (this.#shellFiber !== null) { + await this.#runtime.runPromise(Fiber.interrupt(this.#shellFiber)); + this.#shellFiber = null; + } + if (this.#scope !== null) { + await this.#runtime.runPromise(Scope.close(this.#scope, Exit.void)); + this.#scope = null; + } + this.#session = null; + this.#activeThread = null; + this.#activeThreadSequence = null; + this.#shell = null; + this.#serverConfig = null; + this.#httpBaseUrl = null; + this.#bearerToken = null; + this.#connectionKey = ""; + } +} diff --git a/apps/vscode/src/taskPresentation.test.ts b/apps/vscode/src/taskPresentation.test.ts new file mode 100644 index 00000000000..b1928700199 --- /dev/null +++ b/apps/vscode/src/taskPresentation.test.ts @@ -0,0 +1,54 @@ +import { TurnId, type OrchestrationThreadActivity } from "@t3tools/contracts"; +import { describe, expect, it } from "vite-plus/test"; + +import { presentTasks } from "./taskPresentation.ts"; + +function plan( + id: string, + turnId: string, + createdAt: string, + steps: ReadonlyArray>, +): OrchestrationThreadActivity { + return { + id, + kind: "turn.plan.updated", + tone: "info", + summary: "Plan updated", + payload: { plan: steps }, + turnId, + createdAt, + } as OrchestrationThreadActivity; +} + +describe("presentTasks", () => { + it("prefers the latest plan for the active turn", () => { + expect( + presentTasks( + [ + plan("old", "turn-1", "2026-07-11T00:00:00.000Z", [ + { step: "Old task", status: "pending" }, + ]), + plan("current", "turn-2", "2026-07-11T00:00:01.000Z", [ + { step: "Ship tasks", status: "inProgress" }, + { step: "Verify", status: "completed" }, + ]), + ], + TurnId.make("turn-2"), + ), + ).toMatchObject({ + tasks: [ + { step: "Ship tasks", status: "inProgress" }, + { step: "Verify", status: "completed" }, + ], + }); + }); + + it("falls back to the most recent plan across previous turns", () => { + expect( + presentTasks( + [plan("old", "turn-1", "2026-07-11T00:00:00.000Z", [{ step: "Persist" }])], + TurnId.make("turn-2"), + )?.tasks, + ).toEqual([{ step: "Persist", status: "pending" }]); + }); +}); diff --git a/apps/vscode/src/taskPresentation.ts b/apps/vscode/src/taskPresentation.ts new file mode 100644 index 00000000000..bc27dcc0ab4 --- /dev/null +++ b/apps/vscode/src/taskPresentation.ts @@ -0,0 +1,55 @@ +import type { OrchestrationThreadActivity, TurnId } from "@t3tools/contracts"; + +export interface PresentedTask { + readonly step: string; + readonly status: "pending" | "inProgress" | "completed"; +} + +export interface PresentedTasks { + readonly explanation: string | null; + readonly createdAt: string; + readonly tasks: ReadonlyArray; +} + +function planFromActivity(activity: OrchestrationThreadActivity): PresentedTasks | null { + if (activity.kind !== "turn.plan.updated") return null; + const payload = + typeof activity.payload === "object" && activity.payload !== null + ? (activity.payload as Record) + : null; + if (!Array.isArray(payload?.plan)) return null; + const tasks: PresentedTask[] = []; + for (const entry of payload.plan) { + if (typeof entry !== "object" || entry === null) continue; + const task = entry as Record; + if (typeof task.step !== "string" || task.step.trim() === "") continue; + tasks.push({ + step: task.step.trim(), + status: task.status === "completed" || task.status === "inProgress" ? task.status : "pending", + }); + } + if (tasks.length === 0) return null; + return { + explanation: typeof payload.explanation === "string" ? payload.explanation : null, + createdAt: activity.createdAt, + tasks, + }; +} + +export function presentTasks( + activities: ReadonlyArray, + latestTurnId: TurnId | null, +): PresentedTasks | null { + const plans = activities + .filter((activity) => activity.kind === "turn.plan.updated") + .toSorted( + (left, right) => + (left.sequence ?? 0) - (right.sequence ?? 0) || + left.createdAt.localeCompare(right.createdAt), + ); + const preferred = + (latestTurnId === null + ? undefined + : plans.findLast((activity) => activity.turnId === latestTurnId)) ?? plans.at(-1); + return preferred === undefined ? null : planFromActivity(preferred); +} diff --git a/apps/vscode/src/threadStatus.test.ts b/apps/vscode/src/threadStatus.test.ts new file mode 100644 index 00000000000..ec963249b2f --- /dev/null +++ b/apps/vscode/src/threadStatus.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vite-plus/test"; + +import { resolveThreadDisplayStatus } from "./threadStatus.ts"; + +describe("resolveThreadDisplayStatus", () => { + it("shows a live running thread as working", () => { + expect( + resolveThreadDisplayStatus({ + latestTurn: { state: "running" }, + session: { status: "running" }, + }), + ).toEqual({ kind: "working", label: "Working" }); + }); + + it("prioritizes an interrupted session over its stale running turn", () => { + expect( + resolveThreadDisplayStatus({ + latestTurn: { state: "running" }, + session: { status: "interrupted" }, + }), + ).toEqual({ kind: "needs-wake-up", label: "Needs wake up" }); + }); + + it("shows a settled turn as completed", () => { + expect( + resolveThreadDisplayStatus({ + latestTurn: { state: "completed" }, + session: { status: "ready" }, + }), + ).toEqual({ kind: "completed", label: "Completed" }); + }); +}); diff --git a/apps/vscode/src/threadStatus.ts b/apps/vscode/src/threadStatus.ts new file mode 100644 index 00000000000..842c781cf49 --- /dev/null +++ b/apps/vscode/src/threadStatus.ts @@ -0,0 +1,44 @@ +import type { OrchestrationLatestTurnState, OrchestrationSessionStatus } from "@t3tools/contracts"; + +export type ThreadDisplayStatusKind = + | "working" + | "completed" + | "needs-wake-up" + | "connecting" + | "needs-attention" + | "error" + | "ready"; + +export interface ThreadDisplayStatus { + readonly kind: ThreadDisplayStatusKind; + readonly label: string; +} + +export interface ThreadStatusSource { + readonly latestTurn: null | { readonly state: OrchestrationLatestTurnState }; + readonly session: null | { readonly status: OrchestrationSessionStatus }; + readonly hasPendingApprovals?: boolean; + readonly hasPendingUserInput?: boolean; +} + +export function resolveThreadDisplayStatus(source: ThreadStatusSource): ThreadDisplayStatus { + if (source.hasPendingApprovals || source.hasPendingUserInput) { + return { kind: "needs-attention", label: "Needs attention" }; + } + if (source.session?.status === "interrupted" || source.latestTurn?.state === "interrupted") { + return { kind: "needs-wake-up", label: "Needs wake up" }; + } + if (source.session?.status === "starting") { + return { kind: "connecting", label: "Connecting" }; + } + if (source.session?.status === "running" || source.latestTurn?.state === "running") { + return { kind: "working", label: "Working" }; + } + if (source.session?.status === "error" || source.latestTurn?.state === "error") { + return { kind: "error", label: "Error" }; + } + if (source.latestTurn?.state === "completed") { + return { kind: "completed", label: "Completed" }; + } + return { kind: "ready", label: "Ready" }; +} diff --git a/apps/vscode/src/toolPresentation.test.ts b/apps/vscode/src/toolPresentation.test.ts new file mode 100644 index 00000000000..64003ce93ea --- /dev/null +++ b/apps/vscode/src/toolPresentation.test.ts @@ -0,0 +1,116 @@ +import { type OrchestrationThreadActivity, TurnId } from "@t3tools/contracts"; +import { describe, expect, it } from "vite-plus/test"; + +import { presentToolCalls } from "./toolPresentation.ts"; + +function activity( + input: Omit, "id" | "kind"> & { + readonly id: string; + readonly kind: string; + }, +): OrchestrationThreadActivity { + return { + tone: "tool", + summary: "Tool call", + payload: {}, + turnId: null, + createdAt: "2026-07-10T00:00:00.000Z", + ...input, + } as OrchestrationThreadActivity; +} + +describe("presentToolCalls", () => { + it("collapses lifecycle updates and retains completed command details", () => { + expect( + presentToolCalls([ + activity({ + id: "start", + kind: "tool.updated", + payload: { itemType: "command_execution", data: { toolCallId: "call-1" } }, + }), + activity({ + id: "done", + kind: "tool.completed", + payload: { + itemType: "command_execution", + title: "Ran command", + data: { toolCallId: "call-1", item: { command: ["vp", "check"] } }, + }, + }), + ]), + ).toEqual([ + expect.objectContaining({ + id: "done", + title: "Ran command", + status: "completed", + preview: "vp check", + detail: "vp check", + }), + ]); + }); + + it("preserves MCP input and result JSON for expansion", () => { + const [tool] = presentToolCalls([ + activity({ + id: "mcp", + kind: "tool.completed", + summary: "t3-code · preview_status", + payload: { + itemType: "mcp_tool_call", + data: { item: { tool: "preview_status", arguments: {}, result: "attached" } }, + }, + }), + ]); + expect(tool?.detail).toContain('"tool": "preview_status"'); + expect(tool?.status).toBe("completed"); + }); + + it("omits non-tool activities", () => { + expect(presentToolCalls([activity({ id: "message", kind: "message.created" })])).toEqual([]); + }); + + it("collects and deduplicates nested changed file paths", () => { + const [tool] = presentToolCalls([ + activity({ + id: "files", + kind: "tool.completed", + summary: "File change", + payload: { + itemType: "file_change", + data: { + item: { + changes: [ + { path: "src/one.ts" }, + { filename: "src/two.ts" }, + { newPath: "src/one.ts" }, + ], + }, + }, + }, + }), + ]); + expect(tool?.changedFiles).toEqual(["src/one.ts", "src/two.ts"]); + expect(tool?.preview).toBe("2 changed files"); + }); + + it("settles orphan tool updates when their turn has completed", () => { + const orphan = activity({ + id: "orphan-progress", + kind: "tool.updated", + turnId: TurnId.make("old-turn"), + summary: "Tool updated", + }); + expect( + presentToolCalls([orphan], { + latestTurn: { turnId: "newer-turn", completedAt: null }, + session: { status: "running", activeTurnId: "newer-turn" }, + })[0]?.status, + ).toBe("completed"); + expect( + presentToolCalls([orphan], { + latestTurn: { turnId: "old-turn", completedAt: null }, + session: { status: "running", activeTurnId: "old-turn" }, + })[0]?.status, + ).toBe("running"); + }); +}); diff --git a/apps/vscode/src/toolPresentation.ts b/apps/vscode/src/toolPresentation.ts new file mode 100644 index 00000000000..e8ba1b6884e --- /dev/null +++ b/apps/vscode/src/toolPresentation.ts @@ -0,0 +1,198 @@ +import type { OrchestrationThreadActivity } from "@t3tools/contracts"; + +export interface PresentedToolCall { + readonly id: string; + readonly createdAt: string; + readonly title: string; + readonly itemType: string | null; + readonly status: "running" | "completed" | "failed" | "stopped"; + readonly preview: string | null; + readonly detail: string | null; + readonly changedFiles: ReadonlyArray; +} + +export interface ToolPresentationContext { + readonly latestTurn: null | { + readonly turnId: string; + readonly completedAt: string | null; + }; + readonly session: null | { + readonly status: string; + readonly activeTurnId: string | null; + }; +} + +function record(value: unknown): Record | null { + return typeof value === "object" && value !== null && !Array.isArray(value) + ? (value as Record) + : null; +} + +function text(value: unknown): string | null { + return typeof value === "string" && value.trim() !== "" ? value.trim() : null; +} + +function commandText(value: unknown): string | null { + if (typeof value === "string") return text(value); + if (!Array.isArray(value)) return null; + const parts = value.filter((part): part is string => typeof part === "string"); + return parts.length === value.length && parts.length > 0 ? parts.join(" ") : null; +} + +function toolCallId(payload: Record): string | null { + return text(record(payload.data)?.toolCallId) ?? text(payload.toolCallId); +} + +function toolCommand(payload: Record): string | null { + const data = record(payload.data); + const item = record(data?.item); + const input = record(item?.input); + const result = record(item?.result); + return ( + commandText(item?.command) ?? + commandText(input?.command) ?? + commandText(result?.command) ?? + commandText(data?.command) + ); +} + +function rawOutputDetail(payload: Record): string | null { + const rawOutput = record(record(payload.data)?.rawOutput); + if (rawOutput === null) return null; + const totalFiles = typeof rawOutput.totalFiles === "number" ? rawOutput.totalFiles : null; + if (totalFiles !== null) { + return `${totalFiles} file${totalFiles === 1 ? "" : "s"}${rawOutput.truncated === true ? "+" : ""}`; + } + return text(rawOutput.content) ?? text(rawOutput.stdout); +} + +function collectChangedFiles(value: unknown, target: string[], seen: Set, depth = 0): void { + if (depth > 4 || target.length >= 12) return; + if (Array.isArray(value)) { + for (const entry of value) collectChangedFiles(entry, target, seen, depth + 1); + return; + } + const data = record(value); + if (data === null) return; + for (const key of ["path", "filePath", "relativePath", "filename", "newPath", "oldPath"]) { + const path = text(data[key]); + if (path !== null && !seen.has(path)) { + seen.add(path); + target.push(path); + } + } + for (const key of [ + "item", + "result", + "input", + "data", + "changes", + "files", + "edits", + "patch", + "patches", + "operations", + ]) { + if (key in data) collectChangedFiles(data[key], target, seen, depth + 1); + } +} + +function changedFiles(payload: Record): ReadonlyArray { + const files: string[] = []; + collectChangedFiles(payload.data, files, new Set()); + return files; +} + +function expandedDetail(payload: Record, command: string | null): string | null { + const data = record(payload.data); + const item = record(data?.item); + const blocks = [command, text(payload.detail), rawOutputDetail(payload)]; + if (text(payload.itemType) === "mcp_tool_call" && item !== null) { + blocks.push(JSON.stringify(item, null, 2)); + } + const unique = [...new Set(blocks.filter((block): block is string => block !== null))]; + return unique.length > 0 ? unique.join("\n\n") : null; +} + +function lifecycleStatus( + activity: OrchestrationThreadActivity, + payload: Record, +): PresentedToolCall["status"] { + const status = text(payload.status)?.toLowerCase(); + if (status === "failed" || status === "declined") return "failed"; + if (status === "stopped") return "stopped"; + if (activity.kind === "tool.completed" || status === "completed") return "completed"; + return "running"; +} + +function present( + activity: OrchestrationThreadActivity, + context?: ToolPresentationContext, +): PresentedToolCall | null { + if (activity.kind !== "tool.updated" && activity.kind !== "tool.completed") return null; + const payload = record(activity.payload) ?? {}; + const command = toolCommand(payload); + const title = text(payload.title) ?? activity.summary.replace(/\s+complete(?:d)?$/iu, "").trim(); + const detail = expandedDetail(payload, command); + const files = changedFiles(payload); + const rawPreview = + command ?? + text(payload.detail) ?? + rawOutputDetail(payload) ?? + (files.length > 0 ? `${files.length} changed file${files.length === 1 ? "" : "s"}` : null); + const preview = rawPreview === title ? null : rawPreview; + const lifecycle = lifecycleStatus(activity, payload); + const turnIsSettled = + lifecycle === "running" && + activity.turnId !== null && + context?.latestTurn !== null && + context?.latestTurn !== undefined && + (activity.turnId !== context.latestTurn.turnId || + (context.latestTurn.completedAt !== null && + !( + context.session?.status === "running" && context.session.activeTurnId === activity.turnId + ))); + return { + id: activity.id, + createdAt: activity.createdAt, + title, + itemType: text(payload.itemType), + status: turnIsSettled ? "completed" : lifecycle, + preview, + detail, + changedFiles: files, + }; +} + +export function presentToolCalls( + activities: ReadonlyArray, + context?: ToolPresentationContext, +): ReadonlyArray { + const presented: Array = []; + for (const activity of [...activities].toSorted((left, right) => { + if (left.sequence !== undefined && right.sequence !== undefined) { + return left.sequence - right.sequence; + } + return left.createdAt.localeCompare(right.createdAt); + })) { + const tool = present(activity, context); + if (tool === null) continue; + const payload = record(activity.payload) ?? {}; + const id = toolCallId(payload); + const collapseKey = id === null ? `${tool.itemType ?? ""}\u001f${tool.title}` : `id:${id}`; + const previous = presented.at(-1); + if (previous?.collapseKey === collapseKey && previous.status === "running") { + presented[presented.length - 1] = { + ...previous, + ...tool, + preview: tool.preview ?? previous.preview, + detail: tool.detail ?? previous.detail, + changedFiles: [...new Set([...previous.changedFiles, ...tool.changedFiles])], + collapseKey, + }; + } else { + presented.push({ ...tool, collapseKey }); + } + } + return presented.map(({ collapseKey: _collapseKey, ...tool }) => tool); +} diff --git a/apps/vscode/src/userInputPresentation.ts b/apps/vscode/src/userInputPresentation.ts new file mode 100644 index 00000000000..17f03a984e8 --- /dev/null +++ b/apps/vscode/src/userInputPresentation.ts @@ -0,0 +1,19 @@ +import type { OrchestrationThreadActivity } from "@t3tools/contracts"; + +export interface PresentedResolvedUserInput { + readonly activityId: string; + readonly createdAt: string; + readonly answers: ReadonlyArray<{ + readonly header: string; + readonly question: string; + readonly answer: string; + }>; +} + +export function presentResolvedUserInputs( + _activities: ReadonlyArray, +): ReadonlyArray { + // Stub for dumbed-down upstream contribution; advanced user-input transcripts + // are a newer feature not required for the initial VS Code extension. + return []; +} diff --git a/apps/vscode/src/webview.ts b/apps/vscode/src/webview.ts new file mode 100644 index 00000000000..ee57683e7bf --- /dev/null +++ b/apps/vscode/src/webview.ts @@ -0,0 +1,1310 @@ +/* oxlint-disable no-unsanitized/property, unicorn/require-post-message-target-origin -- Markdown is sanitized; VS Code's postMessage API has no targetOrigin argument. */ +// @effect-diagnostics globalDate:off globalTimers:off +import DOMPurify from "dompurify"; +import { marked } from "marked"; + +import { splitEditorContext } from "./editorContext.ts"; +import { renderProviderIcon } from "./providerIcon.ts"; + +interface VsCodeApi { + readonly postMessage: (message: unknown) => void; +} + +declare function acquireVsCodeApi(): VsCodeApi; + +interface ViewThread { + readonly id: string; + readonly title: string; + readonly model: string; + readonly status: ThreadDisplayStatus; +} + +interface ThreadDisplayStatus { + readonly kind: + | "working" + | "completed" + | "needs-wake-up" + | "connecting" + | "needs-attention" + | "error" + | "ready"; + readonly label: string; +} + +interface ViewMessage { + readonly id: string; + readonly role: "user" | "assistant" | "system"; + readonly text: string; + readonly streaming: boolean; + readonly createdAt: string; + readonly attachments: ReadonlyArray<{ + readonly id: string; + readonly name: string; + readonly mimeType: string; + readonly previewUrl: string | null; + }>; +} + +interface ViewToolCall { + readonly id: string; + readonly createdAt: string; + readonly title: string; + readonly itemType: string | null; + readonly status: "running" | "completed" | "failed" | "stopped"; + readonly preview: string | null; + readonly detail: string | null; + readonly changedFiles: ReadonlyArray; +} + +interface ViewResolvedUserInput { + readonly activityId: string; + readonly createdAt: string; + readonly answers: ReadonlyArray<{ + readonly header: string; + readonly question: string; + readonly answer: string; + }>; +} + +interface ViewPendingApproval { + readonly kind: "approval"; + readonly requestId: string; + readonly requestKind: "command" | "file-read" | "file-change"; + readonly detail: string | null; +} + +interface ViewPendingUserInput { + readonly kind: "user-input"; + readonly requestId: string; + readonly questions: ReadonlyArray<{ + readonly id: string; + readonly header: string; + readonly question: string; + readonly multiSelect?: boolean; + readonly options: ReadonlyArray<{ readonly label: string; readonly description: string }>; + }>; +} + +interface ViewState { + readonly busy: boolean; + readonly error: string | null; + readonly environmentLabel: string; + readonly threads: ReadonlyArray; + readonly activeThread: null | { + readonly id: string; + readonly instanceId: string; + readonly model: string; + readonly options?: ReadonlyArray<{ readonly id: string; readonly value: string | boolean }>; + readonly status: ThreadDisplayStatus; + readonly turnStartedAt: string | null; + readonly messages: ReadonlyArray; + readonly toolCalls: ReadonlyArray; + readonly resolvedUserInputs: ReadonlyArray; + readonly pendingInteractions: ReadonlyArray; + readonly tasks: null | { + readonly explanation: string | null; + readonly createdAt: string; + readonly tasks: ReadonlyArray<{ + readonly step: string; + readonly status: "pending" | "inProgress" | "completed"; + }>; + }; + }; + readonly models: ReadonlyArray<{ + readonly instanceId: string; + readonly model: string; + readonly driver: string; + readonly providerLabel: string; + readonly modelLabel: string; + readonly optionDescriptors: ReadonlyArray< + | { + readonly id: string; + readonly label: string; + readonly type: "select"; + readonly currentValue?: string; + readonly options: ReadonlyArray<{ + readonly id: string; + readonly label: string; + readonly isDefault?: boolean; + }>; + } + | { + readonly id: string; + readonly label: string; + readonly type: "boolean"; + readonly currentValue?: boolean; + } + >; + }>; + readonly favoriteProviderIds: ReadonlyArray; + readonly favoriteModelKeys: ReadonlyArray; + readonly contextEnabled: boolean; + readonly editorContext: null | { + readonly path: string; + readonly startLine: number; + readonly endLine: number; + readonly kind: "selection" | "cursor-line" | "reference"; + }; +} + +const vscode = acquireVsCodeApi(); +const threads = requiredElement("threads"); +const messages = requiredElement("messages"); +const status = requiredElement("status"); +const prompt = requiredElement("prompt"); +const slashCommands = requiredElement("slash-commands"); +const send = requiredElement("send"); +const pendingAttachments = requiredElement("pending-attachments"); +const pendingInteractions = requiredElement("pending-interactions"); +const contextButton = requiredElement("context"); +const contextLabel = requiredElement("context-label"); +const provider = requiredElement("provider"); +const providerIcon = requiredElement("provider-icon"); +const favoriteProvider = requiredElement("favorite-provider"); +const model = requiredElement("model"); +const favoriteModel = requiredElement("favorite-model"); +const modelOptions = requiredElement("model-options"); +const tasksDetails = requiredElement("tasks-details"); +const tasksLabel = requiredElement("tasks-label"); +let currentState: ViewState | null = null; +let draftSelection: null | { + instanceId: string; + model: string; + options: Array<{ id: string; value: string | boolean }>; +} = null; +interface PendingImage { + readonly key: string; + readonly type: "image"; + readonly name: string; + readonly mimeType: string; + readonly sizeBytes: number; + readonly dataUrl: string; +} +let pendingImages: PendingImage[] = []; +let tasksExpanded = false; +let selectedSlashCommand = 0; +const pendingAnswers = new Map>(); +const submittedAnswers = new Map< + string, + Readonly>> +>(); +const submittedApprovals = new Map(); + +const COMMANDS = [ + { name: "/new", description: "Start a new synchronized thread" }, + { name: "/threads", description: "Choose a worktree thread" }, + { name: "/model", description: "Choose the active model" }, + { name: "/context", description: "Include or exclude editor context" }, + { name: "/stop", description: "Stop the active turn" }, +] as const; + +marked.setOptions({ + gfm: true, + breaks: false, +}); + +function requiredElement(id: string): A { + const element = document.getElementById(id); + if (element === null) throw new Error(`Missing webview element #${id}.`); + return element as A; +} + +function post(message: unknown): void { + vscode.postMessage(message); +} + +function emptyMessage(text: string): HTMLElement { + const element = document.createElement("div"); + element.className = "empty"; + element.textContent = text; + return element; +} + +function modelFavoriteKey(instanceId: string, modelSlug: string): string { + return `${instanceId}:${modelSlug}`; +} + +function favoritesFirst(items: ReadonlyArray, isFavorite: (item: A) => boolean): A[] { + return items + .map((item, index) => ({ item, index, favorite: isFavorite(item) })) + .toSorted( + (left, right) => Number(right.favorite) - Number(left.favorite) || left.index - right.index, + ) + .map(({ item }) => item); +} + +function formatElapsed(startedAt: string, nowMs: number): string | null { + const startMs = Date.parse(startedAt); + if (!Number.isFinite(startMs)) return null; + const totalSeconds = Math.max(0, Math.floor((nowMs - startMs) / 1_000)); + const hours = Math.floor(totalSeconds / 3_600); + const minutes = Math.floor((totalSeconds % 3_600) / 60); + const seconds = totalSeconds % 60; + if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`; + if (minutes > 0) return `${minutes}m ${seconds}s`; + return `${seconds}s`; +} + +function renderMarkdown(text: string): HTMLElement { + const content = document.createElement("div"); + content.className = "content markdown-body"; + const parsed = marked.parse(text, { async: false }); + content.innerHTML = DOMPurify.sanitize(parsed, { + USE_PROFILES: { html: true }, + ADD_ATTR: ["target", "rel"], + }); + + for (const anchor of content.querySelectorAll("a[href]")) { + anchor.rel = "noreferrer noopener"; + anchor.addEventListener("click", (event) => { + event.preventDefault(); + post({ type: "openLink", href: anchor.getAttribute("href") ?? "" }); + }); + } + + for (const code of content.querySelectorAll("code:not(pre code)")) { + const href = code.textContent?.trim() ?? ""; + if (!/^https?:\/\/\S+$/iu.test(href)) continue; + const anchor = document.createElement("a"); + anchor.href = href; + anchor.rel = "noreferrer noopener"; + anchor.className = "inline-code-link"; + anchor.addEventListener("click", (event) => { + event.preventDefault(); + post({ type: "openLink", href }); + }); + code.before(anchor); + anchor.append(code); + } + + for (const pre of content.querySelectorAll("pre")) { + const code = pre.querySelector("code"); + if (code === null) continue; + const wrapper = document.createElement("div"); + wrapper.className = "code-block"; + const header = document.createElement("div"); + header.className = "code-header"; + const language = [...code.classList] + .find((name) => name.startsWith("language-")) + ?.slice("language-".length); + const label = document.createElement("span"); + label.textContent = language ?? "code"; + const copy = document.createElement("button"); + copy.className = "copy-code"; + copy.textContent = "Copy"; + copy.title = "Copy code"; + copy.addEventListener("click", () => { + post({ type: "copyText", text: code.textContent ?? "" }); + copy.textContent = "Copied"; + globalThis.setTimeout(() => { + copy.textContent = "Copy"; + }, 1_200); + }); + header.append(label, copy); + pre.before(wrapper); + wrapper.append(header, pre); + } + + for (const table of content.querySelectorAll("table")) { + const wrapper = document.createElement("div"); + wrapper.className = "table-scroll"; + table.before(wrapper); + wrapper.append(table); + } + return content; +} + +function renderMessage(message: ViewMessage): HTMLElement { + const wrapper = document.createElement("article"); + wrapper.className = `message ${message.role}`; + wrapper.setAttribute("aria-label", `${message.role} message`); + const parsedContext = splitEditorContext(message.text); + const attachmentOnlyText = parsedContext.text.startsWith( + "[User attached one or more images without additional text.", + ); + const content = renderMarkdown( + attachmentOnlyText && message.attachments.length > 0 ? "" : parsedContext.text, + ); + if (message.streaming) content.classList.add("streaming"); + wrapper.append(content); + if (parsedContext.references.length > 0) { + const references = document.createElement("div"); + references.className = "context-references"; + for (const reference of parsedContext.references) { + const chip = document.createElement("button"); + chip.className = "context-reference"; + chip.textContent = `▱ ${reference.path} · ${reference.detail}`; + chip.title = `Open ${reference.path}`; + chip.addEventListener("click", () => + post({ type: "openEditorContext", path: reference.path, detail: reference.detail }), + ); + references.append(chip); + } + wrapper.append(references); + } + if (message.attachments.length > 0) { + const attachments = document.createElement("div"); + attachments.className = "attachments"; + for (const attachment of message.attachments) { + const link = document.createElement("a"); + link.className = "attachment"; + link.title = attachment.name; + if (attachment.previewUrl !== null) { + link.href = attachment.previewUrl; + link.addEventListener("click", (event) => { + event.preventDefault(); + post({ type: "openLink", href: attachment.previewUrl }); + }); + const image = document.createElement("img"); + image.src = attachment.previewUrl; + image.alt = attachment.name; + image.loading = "lazy"; + link.append(image); + } + const name = document.createElement("span"); + name.className = "attachment-name"; + name.textContent = + attachment.previewUrl === null ? `Loading ${attachment.name}…` : attachment.name; + link.append(name); + attachments.append(link); + } + wrapper.append(attachments); + } + return wrapper; +} + +function toolIcon(itemType: string | null): string { + if (itemType === "command_execution") return ">_"; + if (itemType === "file_change") return "±"; + if (itemType === "web_search") return "⌕"; + if (itemType === "image_view") return "◉"; + return "⌘"; +} + +function renderToolCall(tool: ViewToolCall): HTMLElement { + const wrapper = document.createElement("details"); + wrapper.className = `tool-call ${tool.status}`; + wrapper.open = false; + const summary = document.createElement("summary"); + const icon = document.createElement("span"); + icon.className = "tool-call-icon"; + icon.textContent = toolIcon(tool.itemType); + const title = document.createElement("span"); + title.className = "tool-call-title"; + title.textContent = tool.title; + const preview = document.createElement("span"); + preview.className = "tool-call-preview"; + preview.textContent = tool.preview === null ? "" : ` · ${tool.preview.replace(/\s+/gu, " ")}`; + const state = document.createElement("span"); + state.className = "tool-call-state"; + state.textContent = + tool.status === "completed" + ? "✓" + : tool.status === "running" + ? "●" + : tool.status === "stopped" + ? "■" + : "×"; + summary.append(icon, title, preview, state); + wrapper.append(summary); + if (tool.detail !== null) { + const detail = document.createElement("pre"); + detail.className = "tool-call-detail"; + detail.textContent = tool.detail; + wrapper.append(detail); + } + if (tool.changedFiles.length > 0) { + const files = document.createElement("div"); + files.className = "tool-changed-files"; + for (const path of tool.changedFiles) { + const button = document.createElement("button"); + button.className = "tool-changed-file"; + button.title = `Open ${path}`; + button.textContent = path; + button.addEventListener("click", () => + post({ type: "openEditorContext", path, detail: "changed file" }), + ); + files.append(button); + } + wrapper.append(files); + } + if (tool.detail === null && tool.changedFiles.length === 0) { + wrapper.classList.add("not-expandable"); + summary.addEventListener("click", (event) => event.preventDefault()); + } + return wrapper; +} + +function renderToolCallGroup(tools: ReadonlyArray): HTMLElement { + if (tools.length === 1) return renderToolCall(tools[0]!); + const group = document.createElement("details"); + group.className = "tool-call-group"; + // Tool output is intentionally opt-in. Live status updates rebuild the + // timeline, so never infer expansion from running state or viewport entry. + group.open = false; + const summary = document.createElement("summary"); + const running = tools.filter((tool) => tool.status === "running").length; + const failed = tools.filter((tool) => tool.status === "failed").length; + const state = running > 0 ? `${running} running` : failed > 0 ? `${failed} failed` : "Completed"; + summary.textContent = `${tools.length} tool calls · ${state}`; + const body = document.createElement("div"); + body.className = "tool-call-group-body"; + body.append(...tools.map(renderToolCall)); + group.append(summary, body); + return group; +} + +function renderResolvedUserInput(input: ViewResolvedUserInput): HTMLElement { + const wrapper = document.createElement("section"); + wrapper.className = "message user user-input-response"; + wrapper.setAttribute("aria-label", "Your answers"); + + for (const entry of input.answers) { + const answer = document.createElement("div"); + answer.className = "user-input-response-item"; + const question = document.createElement("div"); + question.className = "user-input-response-question"; + question.textContent = entry.question; + const value = document.createElement("div"); + value.className = "user-input-response-answer"; + value.textContent = entry.answer; + answer.append(question, value); + wrapper.append(answer); + } + return wrapper; +} + +function approvalLabel(kind: ViewPendingApproval["requestKind"]): string { + if (kind === "command") return "Command approval"; + if (kind === "file-read") return "File-read approval"; + return "File-change approval"; +} + +function renderApproval(interaction: ViewPendingApproval): HTMLElement { + const card = document.createElement("section"); + card.className = "interaction-card approval-card"; + const heading = document.createElement("div"); + heading.className = "interaction-heading"; + heading.textContent = approvalLabel(interaction.requestKind); + card.append(heading); + const submitted = submittedApprovals.get(interaction.requestId); + if (submitted !== undefined) { + heading.textContent = "Approval response submitted"; + const detail = document.createElement("div"); + detail.className = "interaction-detail"; + detail.textContent = submitted; + card.append(detail); + return card; + } + if (interaction.detail !== null) { + const detail = document.createElement("div"); + detail.className = "interaction-detail"; + detail.textContent = interaction.detail; + card.append(detail); + } + const actions = document.createElement("div"); + actions.className = "interaction-actions"; + for (const [label, decision, className] of [ + ["Deny", "decline", ""], + ["Allow for session", "acceptForSession", ""], + ["Allow", "accept", "allow"], + ] as const) { + const button = document.createElement("button"); + button.textContent = label; + button.className = className; + button.addEventListener("click", () => { + submittedApprovals.set(interaction.requestId, label); + if (currentState !== null) renderPendingInteractions(currentState); + post({ type: "approvalResponse", requestId: interaction.requestId, decision }); + }); + actions.append(button); + } + card.append(actions); + return card; +} + +function renderUserInput(interaction: ViewPendingUserInput): HTMLElement { + const card = document.createElement("section"); + card.className = "interaction-card user-input-card"; + const heading = document.createElement("div"); + heading.className = "interaction-heading"; + heading.textContent = "Input requested"; + card.append(heading); + const submitted = submittedAnswers.get(interaction.requestId); + if (submitted !== undefined) { + heading.textContent = "Input submitted"; + for (const question of interaction.questions) { + const answer = submitted[question.id]; + const row = document.createElement("div"); + row.className = "interaction-detail"; + row.textContent = `${question.header}: ${Array.isArray(answer) ? answer.join(", ") : String(answer ?? "")}`; + card.append(row); + } + return card; + } + const answers = pendingAnswers.get(interaction.requestId) ?? {}; + pendingAnswers.set(interaction.requestId, answers); + for (const question of interaction.questions) { + const group = document.createElement("fieldset"); + group.className = "interaction-question-group"; + const legend = document.createElement("legend"); + legend.textContent = question.header; + const questionText = document.createElement("div"); + questionText.className = "interaction-question"; + questionText.textContent = question.question; + group.append(legend, questionText); + for (const option of question.options) { + const label = document.createElement("label"); + label.className = "interaction-option"; + const input = document.createElement("input"); + input.type = question.multiSelect === true ? "checkbox" : "radio"; + input.name = `${interaction.requestId}:${question.id}`; + const current = answers[question.id]; + input.checked = Array.isArray(current) + ? current.includes(option.label) + : current === option.label; + input.addEventListener("change", () => { + if (question.multiSelect === true) { + const selected = Array.isArray(answers[question.id]) + ? [...(answers[question.id] as string[])] + : []; + answers[question.id] = input.checked + ? [...new Set([...selected, option.label])] + : selected.filter((value) => value !== option.label); + } else if (input.checked) { + answers[question.id] = option.label; + } + }); + const copy = document.createElement("span"); + copy.textContent = option.label; + const description = document.createElement("small"); + description.textContent = option.description; + copy.append(description); + label.append(input, copy); + group.append(label); + } + const custom = document.createElement("input"); + custom.className = "interaction-custom"; + custom.placeholder = "Other…"; + custom.value = + typeof answers[question.id] === "string" && + !question.options.some((option) => option.label === answers[question.id]) + ? (answers[question.id] as string) + : ""; + custom.addEventListener("input", () => { + if (custom.value.trim() !== "") answers[question.id] = custom.value.trim(); + else delete answers[question.id]; + }); + group.append(custom); + card.append(group); + } + const actions = document.createElement("div"); + actions.className = "interaction-actions"; + const submit = document.createElement("button"); + submit.className = "allow"; + submit.textContent = "Submit"; + submit.addEventListener("click", () => { + const complete = interaction.questions.every((question) => { + const answer = answers[question.id]; + return typeof answer === "string" ? answer.trim() !== "" : (answer?.length ?? 0) > 0; + }); + if (!complete) return; + submittedAnswers.set(interaction.requestId, { ...answers }); + if (currentState !== null) renderPendingInteractions(currentState); + post({ type: "userInputResponse", requestId: interaction.requestId, answers }); + }); + actions.append(submit); + card.append(actions); + return card; +} + +function renderPendingInteractions(state: ViewState): void { + const activeIds = new Set( + (state.activeThread?.pendingInteractions ?? []).map((interaction) => interaction.requestId), + ); + for (const requestId of submittedAnswers.keys()) { + if (!activeIds.has(requestId)) submittedAnswers.delete(requestId); + } + for (const requestId of submittedApprovals.keys()) { + if (!activeIds.has(requestId)) submittedApprovals.delete(requestId); + } + pendingInteractions.replaceChildren( + ...(state.activeThread?.pendingInteractions ?? []).map((interaction) => + interaction.kind === "approval" ? renderApproval(interaction) : renderUserInput(interaction), + ), + ); +} + +function renderTasks(state: ViewState): void { + const presented = state.activeThread?.tasks ?? null; + tasksDetails.replaceChildren(); + if (presented === null) { + tasksLabel.textContent = "Tasks"; + const empty = document.createElement("div"); + empty.className = "tasks-empty"; + empty.textContent = "No task list for this thread yet."; + tasksDetails.append(empty); + return; + } + const completed = presented.tasks.filter((task) => task.status === "completed").length; + tasksLabel.textContent = `Tasks ${completed}/${presented.tasks.length}`; + if (presented.explanation !== null) { + const explanation = document.createElement("div"); + explanation.className = "tasks-explanation"; + explanation.textContent = presented.explanation; + tasksDetails.append(explanation); + } + const list = document.createElement("ol"); + list.className = "tasks-list"; + for (const task of presented.tasks) { + const item = document.createElement("li"); + item.className = `task-item ${task.status}`; + const icon = document.createElement("span"); + icon.className = "task-icon"; + icon.textContent = task.status === "completed" ? "✓" : task.status === "inProgress" ? "◔" : "·"; + const text = document.createElement("span"); + text.textContent = task.step; + item.append(icon, text); + list.append(item); + } + tasksDetails.append(list); +} + +function render(next: ViewState): void { + currentState = next; + const wasNearBottom = messages.scrollHeight - messages.scrollTop - messages.clientHeight < 80; + threads.replaceChildren(); + if (draftSelection !== null) { + const draft = document.createElement("option"); + draft.textContent = "New thread"; + draft.value = "__draft__"; + draft.selected = true; + threads.append(draft); + for (const thread of next.threads) { + const option = document.createElement("option"); + option.value = thread.id; + option.textContent = `${thread.title} · ${thread.status.label}`; + threads.append(option); + } + } else if (next.threads.length === 0) { + const option = document.createElement("option"); + option.textContent = "No threads for this worktree"; + option.value = ""; + threads.append(option); + } else { + for (const thread of next.threads) { + const option = document.createElement("option"); + option.value = thread.id; + option.textContent = `${thread.title} · ${thread.status.label}`; + option.selected = thread.id === next.activeThread?.id; + threads.append(option); + } + } + threads.disabled = next.busy; + renderActiveStatus(next); + renderPendingInteractions(next); + renderTasks(next); + + messages.replaceChildren(); + if (draftSelection !== null) { + messages.append(emptyMessage("Choose a provider and model, then send your first message.")); + } else if ( + next.activeThread === null || + (next.activeThread.messages.length === 0 && + next.activeThread.toolCalls.length === 0 && + next.activeThread.resolvedUserInputs.length === 0) + ) { + messages.append( + emptyMessage( + next.activeThread === null + ? "Create or select a thread for this worktree." + : "Start a conversation in this synchronized thread.", + ), + ); + } else { + const timeline = [ + ...next.activeThread.messages.map((message) => ({ + kind: "message" as const, + createdAt: message.createdAt, + order: 0, + element: renderMessage(message), + })), + ...next.activeThread.toolCalls.map((tool) => ({ + kind: "tool" as const, + createdAt: tool.createdAt, + order: 1, + tool, + })), + ...next.activeThread.resolvedUserInputs.map((input) => ({ + kind: "input" as const, + createdAt: input.createdAt, + order: 2, + element: renderResolvedUserInput(input), + })), + ].toSorted( + (left, right) => left.createdAt.localeCompare(right.createdAt) || left.order - right.order, + ); + const elements: HTMLElement[] = []; + for (let index = 0; index < timeline.length; index += 1) { + const item = timeline[index]!; + if (item.kind !== "tool") { + elements.push(item.element); + continue; + } + const tools = [item.tool]; + while (timeline[index + 1]?.kind === "tool") { + index += 1; + tools.push((timeline[index] as Extract<(typeof timeline)[number], { kind: "tool" }>).tool); + } + elements.push(renderToolCallGroup(tools)); + } + messages.append(...elements); + if (wasNearBottom) messages.scrollTop = messages.scrollHeight; + } + + const editorContext = next.editorContext; + contextButton.classList.toggle("excluded", !next.contextEnabled); + contextButton.title = next.contextEnabled + ? "Exclude active editor context" + : "Include active editor context"; + contextButton.setAttribute("aria-pressed", String(next.contextEnabled)); + const contextDescription = + editorContext === null + ? "No active editor" + : editorContext.kind === "selection" + ? `${editorContext.endLine - editorContext.startLine + 1} lines selected` + : `${editorContext.path}:${editorContext.startLine}`; + contextLabel.textContent = next.contextEnabled + ? contextDescription + : `Excluded · ${contextDescription}`; + const selection = currentSelection(next); + provider.replaceChildren(); + model.replaceChildren(); + if (selection === null) { + const providerOption = document.createElement("option"); + providerOption.textContent = next.environmentLabel; + providerOption.value = ""; + provider.append(providerOption); + const modelOption = document.createElement("option"); + modelOption.textContent = "Select a thread"; + modelOption.value = ""; + model.append(modelOption); + } else { + const providers = new Map(); + for (const candidate of next.models) { + if (!providers.has(candidate.instanceId)) providers.set(candidate.instanceId, candidate); + } + const favoriteProviderIds = new Set(next.favoriteProviderIds); + for (const [instanceId, candidate] of favoritesFirst([...providers.entries()], ([instanceId]) => + favoriteProviderIds.has(instanceId), + )) { + const option = document.createElement("option"); + option.value = instanceId; + option.textContent = candidate.providerLabel; + option.selected = instanceId === selection.instanceId; + provider.append(option); + } + const favoriteModelKeys = new Set(next.favoriteModelKeys); + const selectedProviderModels = favoritesFirst( + next.models.filter((candidate) => candidate.instanceId === selection.instanceId), + (candidate) => favoriteModelKeys.has(modelFavoriteKey(candidate.instanceId, candidate.model)), + ); + for (const candidate of selectedProviderModels) { + const option = document.createElement("option"); + option.value = candidate.model; + option.textContent = candidate.modelLabel; + option.selected = candidate.model === selection.model; + model.append(option); + } + } + renderModelOptions(next); + renderProviderIdentity(next); + renderFavoriteControls(next); + provider.disabled = selection === null || draftSelection === null || next.busy; + model.disabled = selection === null || next.busy; + send.disabled = next.busy; + prompt.disabled = next.busy; + renderComposerAction(); +} + +function renderFavoriteControls(state: ViewState): void { + const selection = currentSelection(state); + favoriteProvider.disabled = selection === null; + favoriteModel.disabled = selection === null; + const providerActive = + selection !== null && state.favoriteProviderIds.includes(selection.instanceId); + const modelActive = + selection !== null && + state.favoriteModelKeys.includes(modelFavoriteKey(selection.instanceId, selection.model)); + for (const [button, active, noun] of [ + [favoriteProvider, providerActive, "provider"], + [favoriteModel, modelActive, "model"], + ] as const) { + button.textContent = active ? "★" : "☆"; + button.classList.toggle("active", active); + button.title = `${active ? "Remove" : "Add"} ${noun} ${active ? "from" : "to"} favorites`; + button.setAttribute("aria-label", button.title); + } +} + +function renderActiveStatus(state: ViewState): void { + const activeStatus = draftSelection === null ? state.activeThread?.status : undefined; + status.className = state.error === null ? (activeStatus?.kind ?? "") : "error"; + if (state.error !== null) { + status.textContent = state.error; + return; + } + if (state.busy) { + status.textContent = "Synchronizing…"; + return; + } + if (activeStatus === undefined) { + status.textContent = ""; + return; + } + if (activeStatus.kind === "working") { + const elapsed = state.activeThread?.turnStartedAt + ? formatElapsed(state.activeThread.turnStartedAt, Date.now()) + : null; + status.textContent = elapsed === null ? "Working…" : `Working for ${elapsed}`; + return; + } + status.textContent = activeStatus.kind === "connecting" ? "Connecting…" : activeStatus.label; +} + +function renderProviderIdentity(state: ViewState): void { + const candidate = selectedModelCandidate(state); + if (candidate === undefined) { + providerIcon.replaceChildren(); + return; + } + renderProviderIcon(providerIcon, candidate.driver, candidate.providerLabel); + providerIcon.title = candidate.providerLabel; +} + +function isRunning(): boolean { + return draftSelection === null && currentState?.activeThread?.status.kind === "working"; +} + +function hasComposerInput(): boolean { + return prompt.value.trim() !== "" || pendingImages.length > 0; +} + +function renderComposerAction(): void { + const stopping = isRunning() && !hasComposerInput(); + send.textContent = stopping ? "Stop" : "Send"; + send.title = stopping ? "Stop active turn" : "Send message"; + send.classList.toggle("stop-action", stopping); +} + +function uploadImages(): Array<{ + type: "image"; + name: string; + mimeType: string; + sizeBytes: number; + dataUrl: string; +}> { + return pendingImages.map(({ type, name, mimeType, sizeBytes, dataUrl }) => ({ + type, + name, + mimeType, + sizeBytes, + dataUrl, + })); +} + +function clearPendingImages(): void { + pendingImages = []; + renderPendingImages(); +} + +function renderPendingImages(): void { + pendingAttachments.replaceChildren(); + for (const image of pendingImages) { + const chip = document.createElement("div"); + chip.className = "pending-attachment"; + const thumbnail = document.createElement("img"); + thumbnail.src = image.dataUrl; + thumbnail.alt = image.name; + const label = document.createElement("span"); + label.textContent = image.name; + const remove = document.createElement("button"); + remove.textContent = "×"; + remove.title = `Remove ${image.name}`; + remove.addEventListener("click", () => { + pendingImages = pendingImages.filter((candidate) => candidate.key !== image.key); + renderPendingImages(); + }); + chip.append(thumbnail, label, remove); + pendingAttachments.append(chip); + } + renderComposerAction(); +} + +function fileDataUrl(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.addEventListener("load", () => + typeof reader.result === "string" + ? resolve(reader.result) + : reject(new Error("Invalid image")), + ); + reader.addEventListener("error", () => + reject(reader.error ?? new Error("Could not read image")), + ); + reader.readAsDataURL(file); + }); +} + +async function addClipboardImages(files: ReadonlyArray): Promise { + for (const [index, file] of files.entries()) { + if (!file.type.startsWith("image/")) continue; + pendingImages.push({ + key: `${file.name}:${file.size}:${globalThis.performance.now()}:${index}`, + type: "image", + name: file.name || `pasted-image-${pendingImages.length + 1}.png`, + mimeType: file.type || "image/png", + sizeBytes: file.size, + dataUrl: await fileDataUrl(file), + }); + } + renderPendingImages(); +} + +function currentSelection(state: ViewState) { + if (draftSelection !== null) return draftSelection; + const thread = state.activeThread; + if (thread === null) return null; + return { + instanceId: thread.instanceId, + model: thread.model, + options: [...(thread.options ?? [])], + }; +} + +function selectedModelCandidate(state: ViewState) { + const selection = currentSelection(state); + if (selection === null) return undefined; + return state.models.find( + (candidate) => + candidate.instanceId === selection.instanceId && candidate.model === selection.model, + ); +} + +function selectedOptions(state: ViewState): Array<{ id: string; value: string | boolean }> { + return [...(currentSelection(state)?.options ?? [])]; +} + +function sendModelSelection( + state: ViewState, + options: Array<{ id: string; value: string | boolean }>, +): void { + const selection = currentSelection(state); + if (selection === null) return; + if (draftSelection !== null) { + draftSelection = { ...draftSelection, options }; + renderModelOptions(state); + return; + } + post({ + type: "selectModel", + instanceId: selection.instanceId, + model: selection.model, + options, + }); +} + +function renderModelOptions(state: ViewState): void { + modelOptions.replaceChildren(); + const candidate = selectedModelCandidate(state); + if (candidate === undefined || candidate.optionDescriptors.length === 0) return; + const values = new Map(selectedOptions(state).map((option) => [option.id, option.value])); + for (const descriptor of candidate.optionDescriptors) { + const label = document.createElement("label"); + label.className = "model-option"; + const title = document.createElement("span"); + const optionIdentity = `${descriptor.id} ${descriptor.label}`.toLowerCase(); + const compactIcon = + optionIdentity.includes("service") || optionIdentity.includes("tier") ? "ϟ" : null; + const omitVisibleLabel = optionIdentity.includes("reason"); + title.textContent = compactIcon ?? (omitVisibleLabel ? "" : descriptor.label); + title.hidden = omitVisibleLabel; + title.className = compactIcon === null ? "" : "model-option-icon"; + title.title = descriptor.label; + label.append(title); + if (descriptor.type === "select") { + const select = document.createElement("select"); + select.setAttribute("aria-label", descriptor.label); + select.title = descriptor.label; + for (const choice of descriptor.options) { + const option = document.createElement("option"); + option.value = choice.id; + option.textContent = choice.label; + option.selected = + choice.id === + (values.get(descriptor.id) ?? + descriptor.currentValue ?? + descriptor.options.find((entry) => entry.isDefault)?.id); + select.append(option); + } + select.addEventListener("change", () => { + const options = selectedOptions(state).filter((option) => option.id !== descriptor.id); + options.push({ id: descriptor.id, value: select.value }); + sendModelSelection(state, options); + }); + label.append(select); + } else { + const checkbox = document.createElement("input"); + checkbox.type = "checkbox"; + checkbox.setAttribute("aria-label", descriptor.label); + checkbox.checked = Boolean(values.get(descriptor.id) ?? descriptor.currentValue ?? false); + checkbox.addEventListener("change", () => { + const options = selectedOptions(state).filter((option) => option.id !== descriptor.id); + options.push({ id: descriptor.id, value: checkbox.checked }); + sendModelSelection(state, options); + }); + label.prepend(checkbox); + } + modelOptions.append(label); + } +} + +function submit(): void { + const slash = prompt.value.trim(); + if (slash.startsWith("/") && executeSlashCommand(slash)) return; + if (!hasComposerInput()) return; + const images = uploadImages(); + if (draftSelection !== null) { + post({ + type: "sendNewThread", + text: prompt.value, + instanceId: draftSelection.instanceId, + model: draftSelection.model, + options: draftSelection.options, + images, + }); + return; + } + post({ type: "send", text: prompt.value, images }); +} + +function beginNewThread(): void { + if (currentState === null) return; + const active = currentSelection(currentState); + const fallback = currentState.models[0]; + if (active === null && fallback === undefined) return; + draftSelection = active ?? { + instanceId: fallback!.instanceId, + model: fallback!.model, + options: [], + }; + prompt.value = ""; + slashCommands.hidden = true; + render(currentState); + prompt.focus(); +} + +function executeSlashCommand(value: string): boolean { + const command = COMMANDS.find((candidate) => candidate.name === value.toLowerCase()); + if (command === undefined) return false; + prompt.value = ""; + slashCommands.hidden = true; + switch (command.name) { + case "/new": + beginNewThread(); + break; + case "/threads": + threads.focus(); + threads.click(); + break; + case "/model": + model.focus(); + model.click(); + break; + case "/context": + post({ type: "toggleContext" }); + break; + case "/stop": + post({ type: "stop" }); + break; + } + renderComposerAction(); + return true; +} + +function matchingSlashCommands(): ReadonlyArray<(typeof COMMANDS)[number]> { + const query = prompt.value.trim().toLowerCase(); + if (!query.startsWith("/") || query.includes(" ")) return []; + return COMMANDS.filter((command) => command.name.startsWith(query)); +} + +function renderSlashCommands(): void { + const matching = matchingSlashCommands(); + selectedSlashCommand = Math.min(selectedSlashCommand, Math.max(0, matching.length - 1)); + slashCommands.replaceChildren(); + slashCommands.hidden = matching.length === 0; + for (const [index, command] of matching.entries()) { + const button = document.createElement("button"); + button.className = `slash-command${index === selectedSlashCommand ? " selected" : ""}`; + button.type = "button"; + const name = document.createElement("span"); + name.className = "slash-command-name"; + name.textContent = command.name; + const description = document.createElement("span"); + description.className = "slash-command-description"; + description.textContent = command.description; + button.append(name, description); + button.addEventListener("mousedown", (event) => event.preventDefault()); + button.addEventListener("click", () => executeSlashCommand(command.name)); + slashCommands.append(button); + } +} + +function positionTasksDetails(): void { + const toggle = requiredElement("tasks-toggle"); + const viewportPadding = 8; + const width = Math.min(320, Math.max(0, globalThis.innerWidth - viewportPadding * 2)); + const toggleBounds = toggle.getBoundingClientRect(); + const left = Math.min( + Math.max(viewportPadding, toggleBounds.right - width), + Math.max(viewportPadding, globalThis.innerWidth - width - viewportPadding), + ); + tasksDetails.style.width = `${width}px`; + tasksDetails.style.left = `${left}px`; + tasksDetails.style.bottom = `${Math.max(viewportPadding, globalThis.innerHeight - toggleBounds.top + 7)}px`; +} + +window.addEventListener("message", (event: MessageEvent) => { + if (typeof event.data !== "object" || event.data === null || !("type" in event.data)) return; + if (event.data.type === "state" && "state" in event.data) render(event.data.state as ViewState); + if (event.data.type === "sent") { + prompt.value = ""; + clearPendingImages(); + prompt.focus(); + } + if (event.data.type === "sentNewThread") { + draftSelection = null; + prompt.value = ""; + clearPendingImages(); + prompt.focus(); + } + if (event.data.type === "focusComposer") prompt.focus(); +}); +threads.addEventListener("change", () => { + if (threads.value !== "" && threads.value !== "__draft__") { + draftSelection = null; + post({ type: "selectThread", threadId: threads.value }); + } +}); +provider.addEventListener("change", () => { + if (draftSelection === null || currentState === null || provider.value === "") return; + const firstModel = currentState.models.find( + (candidate) => candidate.instanceId === provider.value, + ); + if (firstModel === undefined) return; + draftSelection = { instanceId: firstModel.instanceId, model: firstModel.model, options: [] }; + render(currentState); +}); +model.addEventListener("change", () => { + if (model.value === "" || currentState === null) return; + const selection = currentSelection(currentState); + if (selection === null) return; + if (draftSelection !== null) { + draftSelection = { instanceId: selection.instanceId, model: model.value, options: [] }; + render(currentState); + return; + } + post({ type: "selectModel", instanceId: selection.instanceId, model: model.value, options: [] }); +}); +favoriteProvider.addEventListener("click", () => { + if (currentState === null) return; + const selection = currentSelection(currentState); + if (selection !== null) + post({ type: "toggleProviderFavorite", instanceId: selection.instanceId }); +}); +favoriteModel.addEventListener("click", () => { + if (currentState === null) return; + const selection = currentSelection(currentState); + if (selection !== null) { + post({ + type: "toggleModelFavorite", + modelKey: modelFavoriteKey(selection.instanceId, selection.model), + }); + } +}); +requiredElement("tasks-toggle").addEventListener("click", () => { + positionTasksDetails(); + tasksExpanded = !tasksExpanded; + requiredElement("tasks-control").classList.toggle("pinned", tasksExpanded); +}); +requiredElement("tasks-control").addEventListener("pointerenter", positionTasksDetails); +function closeComposerPopovers(): void { + tasksExpanded = false; + const control = requiredElement("tasks-control"); + control.classList.remove("pinned"); + if (control.contains(document.activeElement)) (document.activeElement as HTMLElement).blur(); +} +document.addEventListener("pointerdown", (event) => { + const target = event.target; + if (!(target instanceof Node)) return; + if (requiredElement("tasks-control").contains(target)) return; + closeComposerPopovers(); +}); +document.addEventListener("keydown", (event) => { + if (event.key === "Escape" && tasksExpanded) { + closeComposerPopovers(); + event.preventDefault(); + } +}); +globalThis.addEventListener("resize", () => { + positionTasksDetails(); +}); +requiredElement("new").addEventListener("click", beginNewThread); +requiredElement("refresh").addEventListener("click", () => post({ type: "refresh" })); +contextButton.addEventListener("click", () => post({ type: "toggleContext" })); +send.addEventListener("click", () => { + if (isRunning() && !hasComposerInput()) post({ type: "stop" }); + else submit(); +}); +prompt.addEventListener("input", () => { + selectedSlashCommand = 0; + renderSlashCommands(); + renderComposerAction(); +}); +prompt.addEventListener("paste", (event) => { + const images = [...(event.clipboardData?.files ?? [])].filter((file) => + file.type.startsWith("image/"), + ); + if (images.length === 0) return; + event.preventDefault(); + void addClipboardImages(images); +}); +prompt.addEventListener("keydown", (event) => { + const matching = matchingSlashCommands(); + if (matching.length > 0 && (event.key === "ArrowDown" || event.key === "ArrowUp")) { + event.preventDefault(); + selectedSlashCommand = + (selectedSlashCommand + (event.key === "ArrowDown" ? 1 : -1) + matching.length) % + matching.length; + renderSlashCommands(); + return; + } + if (event.key === "Escape" && !slashCommands.hidden) { + event.preventDefault(); + slashCommands.hidden = true; + return; + } + if (event.key === "Enter" && !event.shiftKey) { + event.preventDefault(); + if (matching.length > 0) { + executeSlashCommand(matching[selectedSlashCommand]!.name); + return; + } + submit(); + } +}); +post({ type: "ready" }); + +globalThis.setInterval(() => { + if (currentState?.activeThread?.status.kind === "working") renderActiveStatus(currentState); +}, 1_000); diff --git a/apps/vscode/tsconfig.json b/apps/vscode/tsconfig.json new file mode 100644 index 00000000000..b4e09f80a0f --- /dev/null +++ b/apps/vscode/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "types": ["vscode", "node"] + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee737f9e750..5d9a8fc35da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -495,6 +495,37 @@ importers: specifier: 'catalog:' version: 0.2.2(@types/node@24.12.4)(bufferutil@4.1.0)(esbuild@0.28.1)(jiti@2.7.0)(msw@2.12.11(@types/node@24.12.4)(typescript@6.0.3))(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0) + apps/vscode: + dependencies: + '@t3tools/client-runtime': + specifier: workspace:* + version: link:../../packages/client-runtime + '@t3tools/contracts': + specifier: workspace:* + version: link:../../packages/contracts + '@t3tools/shared': + specifier: workspace:* + version: link:../../packages/shared + dompurify: + specifier: ^3.2.6 + version: 3.4.12 + effect: + specifier: 4.0.0-beta.78 + version: 4.0.0-beta.78(patch_hash=c502bc684210b707dfceb87d8fe6ad6843395af6e19cfc02cd65854898bde2c5) + marked: + specifier: ^15.0.12 + version: 15.0.12 + devDependencies: + '@types/vscode': + specifier: 1.95.0 + version: 1.95.0 + esbuild: + specifier: ^0.28.0 + version: 0.28.1 + vite-plus: + specifier: 'catalog:' + version: 0.2.2(@types/node@24.12.4)(bufferutil@4.1.0)(esbuild@0.28.1)(jiti@2.7.0)(msw@2.12.11(@types/node@24.12.4)(typescript@6.0.3))(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(utf-8-validate@6.0.6)(yaml@2.9.0) + apps/web: dependencies: '@base-ui/react': @@ -4916,12 +4947,18 @@ packages: '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/vscode@1.95.0': + resolution: {integrity: sha512-0LBD8TEiNbet3NvWsmn59zLzOFu/txSlGxnv5yAFHCrhG9WvAnR3IvfHzMOs2aeWqgvNjq9pO99IUw8d3n+unw==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -6168,6 +6205,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.4.12: + resolution: {integrity: sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg==} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -7854,6 +7894,11 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} @@ -14958,10 +15003,15 @@ snapshots: '@types/statuses@2.0.6': {} + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} + '@types/vscode@1.95.0': {} + '@types/ws@8.18.1': dependencies: '@types/node': 24.12.4 @@ -16337,6 +16387,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.4.12: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 @@ -18322,6 +18376,8 @@ snapshots: markdown-table@3.0.4: {} + marked@15.0.12: {} + marky@1.3.0: {} matcher@3.0.0: