feat(site): include chatId in editor deep links (#23214)

## Summary

- include the current agent chat ID in VS Code and Cursor deep links
opened from the agent detail page
- extend `getVSCodeHref` so `chatId` is added only when provided
- add focused tests for deep-link generation with and without `chatId`

## Testing

- `pnpm -C site run format -- src/modules/apps/apps.ts
src/modules/apps/apps.test.ts src/pages/AgentsPage/AgentDetail.tsx`
- `pnpm -C site run check -- src/modules/apps/apps.ts
src/modules/apps/apps.test.ts src/pages/AgentsPage/AgentDetail.tsx`
- `pnpm -C site exec vitest run src/modules/apps/apps.test.ts`
- `pnpm -C site run lint:types`

---
_Generated with [`mux`](https://github.com/coder/mux) • Model:
`openai:gpt-5.4` • Thinking: `high`_
This commit is contained in:
Thomas Kosiewski
2026-03-18 14:25:38 +01:00
committed by GitHub
parent 677f90b78a
commit 20ac96e68d
3 changed files with 50 additions and 2 deletions
+44 -1
View File
@@ -3,7 +3,50 @@ import {
MockWorkspaceAgent,
MockWorkspaceApp,
} from "testHelpers/entities";
import { getAppHref, SESSION_TOKEN_PLACEHOLDER } from "./apps";
import { getAppHref, getVSCodeHref, SESSION_TOKEN_PLACEHOLDER } from "./apps";
describe("getVSCodeHref", () => {
it("includes the chat ID when provided", () => {
const folder = "/workspace/test";
const href = getVSCodeHref("vscode", {
owner: MockWorkspace.owner_name,
workspace: MockWorkspace.name,
token: "user-session-token",
agent: MockWorkspaceAgent.name,
folder,
chatId: "chat-123",
});
const query = new URLSearchParams({
owner: MockWorkspace.owner_name,
workspace: MockWorkspace.name,
url: location.origin,
token: "user-session-token",
openRecent: "true",
agent: MockWorkspaceAgent.name,
folder,
chatId: "chat-123",
});
expect(href).toBe(`vscode://coder.coder-remote/open?${query}`);
});
it("omits the chat ID when none is provided", () => {
const href = getVSCodeHref("cursor", {
owner: MockWorkspace.owner_name,
workspace: MockWorkspace.name,
token: "user-session-token",
});
const query = new URLSearchParams({
owner: MockWorkspace.owner_name,
workspace: MockWorkspace.name,
url: location.origin,
token: "user-session-token",
openRecent: "true",
});
expect(href).toBe(`cursor://coder.coder-remote/open?${query}`);
});
});
describe("getAppHref", () => {
it("returns the URL without changes when external app has regular URL", () => {
+5 -1
View File
@@ -34,11 +34,12 @@ type GetVSCodeHrefParams = {
token: string;
agent?: string;
folder?: string;
chatId?: string;
};
export const getVSCodeHref = (
app: "vscode" | "vscode-insiders" | "cursor",
{ owner, workspace, token, agent, folder }: GetVSCodeHrefParams,
{ owner, workspace, token, agent, folder, chatId }: GetVSCodeHrefParams,
) => {
const query = new URLSearchParams({
owner,
@@ -53,6 +54,9 @@ export const getVSCodeHref = (
if (folder) {
query.set("folder", folder);
}
if (chatId) {
query.set("chatId", chatId);
}
return `${app}://coder.coder-remote/open?${query}`;
};
@@ -781,6 +781,7 @@ const AgentDetail: FC = () => {
token: key,
agent: workspaceAgent.name,
folder: workspaceAgent.expanded_directory,
chatId: agentId,
});
},
onError: () => {