From 8a00605e51146c16b18393efb263fbd8667d99e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Facu=5FVi=C3=B1as?= Date: Wed, 11 Mar 2026 14:44:42 -0300 Subject: [PATCH] fix: sort prompt store by updatedAt instead of filename getLatestPromptSummary() sorted JSON filenames alphabetically to find the most recent prompt. Since filenames are UUIDs (random, not temporal), this returned arbitrary results. Now reads updatedAt from each record and picks the highest. Also fixes test isolation on Windows (USERPROFILE) and adds a regression test that fails with the old alphabetical sort. Co-Authored-By: Claude Opus 4.6 --- .../gsd/tests/remote-status.test.ts | 71 ++++++++++++++++--- .../extensions/remote-questions/status.ts | 14 +++- 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/resources/extensions/gsd/tests/remote-status.test.ts b/src/resources/extensions/gsd/tests/remote-status.test.ts index 4ca3ff0ce..507c9cf35 100644 --- a/src/resources/extensions/gsd/tests/remote-status.test.ts +++ b/src/resources/extensions/gsd/tests/remote-status.test.ts @@ -6,12 +6,25 @@ import { tmpdir } from "node:os"; import { createPromptRecord, writePromptRecord } from "../../remote-questions/store.ts"; import { getLatestPromptSummary } from "../../remote-questions/status.ts"; -test("getLatestPromptSummary returns latest stored prompt", async () => { - const home = process.env.HOME!; - const tempHome = join(tmpdir(), `gsd-remote-status-${Date.now()}`); - mkdirSync(join(tempHome, ".gsd", "runtime", "remote-questions"), { recursive: true }); - process.env.HOME = tempHome; +function withTempHome(fn: (tempHome: string) => void | Promise) { + return async () => { + const savedHome = process.env.HOME; + const savedUserProfile = process.env.USERPROFILE; + const tempHome = join(tmpdir(), `gsd-remote-status-${Date.now()}-${Math.random().toString(36).slice(2)}`); + mkdirSync(join(tempHome, ".gsd", "runtime", "remote-questions"), { recursive: true }); + process.env.HOME = tempHome; + process.env.USERPROFILE = tempHome; + try { + await fn(tempHome); + } finally { + process.env.HOME = savedHome; + process.env.USERPROFILE = savedUserProfile; + rmSync(tempHome, { recursive: true, force: true }); + } + }; +} +test("getLatestPromptSummary returns latest stored prompt", withTempHome(() => { const recordA = createPromptRecord({ id: "a-prompt", channel: "slack", @@ -38,7 +51,49 @@ test("getLatestPromptSummary returns latest stored prompt", async () => { const latest = getLatestPromptSummary(); assert.equal(latest?.id, "z-prompt"); assert.equal(latest?.status, "answered"); +})); - process.env.HOME = home; - rmSync(tempHome, { recursive: true, force: true }); -}); +test("getLatestPromptSummary sorts by updatedAt, not filename", withTempHome(() => { + // Record with alphabetically-LAST id but OLDEST timestamp + const old = createPromptRecord({ + id: "zzz-oldest", + channel: "slack", + createdAt: 1000, + timeoutAt: 9999, + pollIntervalMs: 5000, + questions: [], + }); + old.updatedAt = 1000; + writePromptRecord(old); + + // Record with alphabetically-FIRST id but NEWEST timestamp + const newest = createPromptRecord({ + id: "aaa-newest", + channel: "discord", + createdAt: 3000, + timeoutAt: 9999, + pollIntervalMs: 5000, + questions: [], + }); + newest.updatedAt = 3000; + newest.status = "answered"; + writePromptRecord(newest); + + // Record in between + const middle = createPromptRecord({ + id: "mmm-middle", + channel: "slack", + createdAt: 2000, + timeoutAt: 9999, + pollIntervalMs: 5000, + questions: [], + }); + middle.updatedAt = 2000; + writePromptRecord(middle); + + const latest = getLatestPromptSummary(); + // Should return "aaa-newest" (updatedAt=3000), NOT "zzz-oldest" (alphabetically last) + assert.equal(latest?.id, "aaa-newest", "should pick the most recently updated prompt, not the alphabetically last filename"); + assert.equal(latest?.status, "answered"); + assert.equal(latest?.updatedAt, 3000); +})); diff --git a/src/resources/extensions/remote-questions/status.ts b/src/resources/extensions/remote-questions/status.ts index e322aeaf8..dd4593488 100644 --- a/src/resources/extensions/remote-questions/status.ts +++ b/src/resources/extensions/remote-questions/status.ts @@ -16,8 +16,16 @@ export interface LatestPromptSummary { export function getLatestPromptSummary(): LatestPromptSummary | null { const runtimeDir = join(homedir(), ".gsd", "runtime", "remote-questions"); if (!existsSync(runtimeDir)) return null; - const files = readdirSync(runtimeDir).filter((f) => f.endsWith(".json")).sort().reverse(); + const files = readdirSync(runtimeDir).filter((f) => f.endsWith(".json")); if (files.length === 0) return null; - const record = readPromptRecord(files[0].replace(/\.json$/, "")); - return record ? { id: record.id, status: record.status, updatedAt: record.updatedAt } : null; + + let latest: LatestPromptSummary | null = null; + for (const file of files) { + const record = readPromptRecord(file.replace(/\.json$/, "")); + if (!record) continue; + if (!latest || record.updatedAt > latest.updatedAt) { + latest = { id: record.id, status: record.status, updatedAt: record.updatedAt }; + } + } + return latest; }