From 258c14c6c3eac58a1f3b96bd985328a35ad3959d Mon Sep 17 00:00:00 2001 From: "exe.dev user" Date: Tue, 20 Oct 2026 20:51:30 +0000 Subject: [PATCH] fix: preserve configured exe.dev VM tags --- packages/api/src/postgres/integration-service.ts | 2 +- packages/api/test/loading-parallel.test.ts | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/api/src/postgres/integration-service.ts b/packages/api/src/postgres/integration-service.ts index 76052953..79a3fa09 100644 --- a/packages/api/src/postgres/integration-service.ts +++ b/packages/api/src/postgres/integration-service.ts @@ -93,7 +93,7 @@ export class IntegrationService { const connectionsPromise = this.connections.all(["linear", "clickup", "exe:", "amp:", "cloudflare-tail:"]); const [connections, tails] = await Promise.all([connectionsPromise, this.tails(connectionsPromise)]); const linear = connections.get("linear"), clickup = connections.get("clickup"); - const exeConnections = [...connections].filter(([kind]) => kind.startsWith("exe:")).map(([kind, value]) => { const agentKind = value?.agentKind; return { connectionId: kind.slice(4), credentialStatus: "connected" as const, accountTags: tags(value?.availableTags ?? value?.tags), ...(agentKind ? { agentKind } : {}), models: (agentKind && (value?.modelsByAgent?.[agentKind] ?? value?.models)) ?? [], efforts: agentKind ? effortOptions[agentKind as keyof typeof effortOptions] ?? [] : [] }; }); + const exeConnections = [...connections].filter(([kind]) => kind.startsWith("exe:")).map(([kind, value]) => { const agentKind = value?.agentKind; return { connectionId: kind.slice(4), credentialStatus: "connected" as const, accountTags: [...new Set([...tags(value?.availableTags), ...tags(value?.tags)])].sort((a, b) => a.localeCompare(b)), ...(agentKind ? { agentKind } : {}), models: (agentKind && (value?.modelsByAgent?.[agentKind] ?? value?.models)) ?? [], efforts: agentKind ? effortOptions[agentKind as keyof typeof effortOptions] ?? [] : [] }; }); const ampConnections = [...connections].filter(([kind]) => kind.startsWith("amp:")).map(([kind, value]) => ({ connectionId: kind.slice(4), project: text(value?.project) ?? "Unnamed Amp project", ...(text(value?.apiBaseUrl) ? { apiBaseUrl: text(value.apiBaseUrl) } : {}) })); return { linear: linear ? { organizationName: text(linear.organizationName) ?? null, viewerEmail: text(linear.viewerEmail) ?? null } : null, clickup: clickup ? { teamName: text(clickup.teamName) ?? null } : null, exe: exeConnections[0] ?? null, exeConnections, ampConnections, cloudflareTail: { count: tails.length, installations: tails } }; } diff --git a/packages/api/test/loading-parallel.test.ts b/packages/api/test/loading-parallel.test.ts index 554f7cc4..840e5426 100644 --- a/packages/api/test/loading-parallel.test.ts +++ b/packages/api/test/loading-parallel.test.ts @@ -32,6 +32,15 @@ describe("independent loading", () => { connections.resolve(new Map()); counts.resolve({ rows: [] }); expect(await result).toMatchObject({ exeConnections: [], ampConnections: [], cloudflareTail: { count: 0, installations: [] } }); }); + + it("keeps configured exe.dev tags visible when inventory refresh omits them", async () => { + vi.spyOn(ConnectionRepository.prototype, "all").mockResolvedValue(new Map([ + ["exe:vm", { availableTags: ["current"], tags: ["anarack", "current"], agentKind: "codex" }], + ])); + vi.spyOn(IntegrationService.prototype, "tails").mockResolvedValue([]); + const result = await new IntegrationService({ pool: { query: vi.fn(async () => ({ rows: [] })) } } as any, "tenant", "key").status(); + expect(result.exeConnections[0].accountTags).toEqual(["anarack", "current"]); + }); it("propagates a failed integration read without leaving an unhandled sibling promise", async () => { vi.spyOn(ConnectionRepository.prototype, "all").mockRejectedValue(new Error("Connection read failed")); const query = vi.fn(async () => ({ rows: [] }));