From 8680f387468fea23acf47c678630d428db53a02c Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 18 Apr 2026 10:12:53 -0500 Subject: [PATCH] Fix stale workspace command matching Co-Authored-By: Paperclip --- .../shared/src/workspace-commands.test.ts | 22 +++++++++++ packages/shared/src/workspace-commands.ts | 4 ++ .../WorkspaceRuntimeControls.test.tsx | 38 +++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/packages/shared/src/workspace-commands.test.ts b/packages/shared/src/workspace-commands.test.ts index 1fc74478cda..9a5c610b68d 100644 --- a/packages/shared/src/workspace-commands.test.ts +++ b/packages/shared/src/workspace-commands.test.ts @@ -53,4 +53,26 @@ describe("workspace command helpers", () => { expect(match).toEqual(expect.objectContaining({ id: "runtime-web" })); }); + + it("does not match a stale runtime service after the configured command changes", () => { + const workspaceRuntime = { + commands: [ + { id: "web", name: "web", kind: "service", command: "pnpm dev:once --tailscale-auth", cwd: "." }, + ], + }; + const command = findWorkspaceCommandDefinition(workspaceRuntime, "web"); + expect(command).not.toBeNull(); + + const match = matchWorkspaceRuntimeServiceToCommand(command!, [ + { + id: "runtime-web", + serviceName: "web", + command: "pnpm dev", + cwd: "/repo", + configIndex: null, + }, + ]); + + expect(match).toBeNull(); + }); }); diff --git a/packages/shared/src/workspace-commands.ts b/packages/shared/src/workspace-commands.ts index 0510d3fbc65..dd98ef3dc03 100644 --- a/packages/shared/src/workspace-commands.ts +++ b/packages/shared/src/workspace-commands.ts @@ -166,6 +166,10 @@ export function scoreWorkspaceRuntimeServiceMatch( command: Pick, runtimeService: Pick, ) { + if (command.command && runtimeService.command && runtimeService.command !== command.command) { + return -1; + } + if (command.serviceIndex !== null && runtimeService.configIndex !== null && runtimeService.configIndex !== undefined) { return runtimeService.configIndex === command.serviceIndex ? 100 : -1; } diff --git a/ui/src/components/WorkspaceRuntimeControls.test.tsx b/ui/src/components/WorkspaceRuntimeControls.test.tsx index 3cbf327bf59..272e4584e48 100644 --- a/ui/src/components/WorkspaceRuntimeControls.test.tsx +++ b/ui/src/components/WorkspaceRuntimeControls.test.tsx @@ -76,6 +76,44 @@ describe("buildWorkspaceRuntimeControlSections", () => { workspaceCommandId: "db-migrate", }); }); + + it("keeps stale runtime services from masking updated inherited commands", () => { + const sections = buildWorkspaceRuntimeControlSections({ + runtimeConfig: { + commands: [ + { id: "web", name: "web", kind: "service", command: "pnpm dev:once --tailscale-auth" }, + ], + }, + runtimeServices: [ + createRuntimeService({ + id: "service-web", + serviceName: "web", + status: "stopped", + command: "pnpm dev", + }), + ], + canStartServices: true, + canRunJobs: true, + }); + + expect(sections.services).toEqual([ + expect.objectContaining({ + title: "web", + statusLabel: "stopped", + command: "pnpm dev:once --tailscale-auth", + runtimeServiceId: null, + }), + ]); + expect(sections.otherServices).toEqual([ + expect.objectContaining({ + title: "web", + statusLabel: "stopped", + command: "pnpm dev", + runtimeServiceId: "service-web", + disabledReason: "This runtime service no longer matches a configured workspace command.", + }), + ]); + }); }); describe("buildWorkspaceRuntimeControlItems", () => {