Skip to content

Commit 036d998

Browse files
committed
Track context doc generation metadata and pending status
1 parent 717c2d9 commit 036d998

7 files changed

Lines changed: 379 additions & 47 deletions

File tree

apps/desktop/src/main/services/context/contextDocBuilder.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,9 +531,16 @@ export function readContextStatus(deps: {
531531
warnings: latestWarnings,
532532
generation: {
533533
state: "idle",
534+
requestedAt: null,
534535
startedAt: null,
535536
finishedAt: null,
536537
error: null,
538+
source: null,
539+
event: null,
540+
reason: null,
541+
provider: null,
542+
modelId: null,
543+
reasoningEffort: null,
537544
},
538545
};
539546
}

apps/desktop/src/main/services/context/contextDocService.test.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ import {
4646
runContextDocGeneration,
4747
} from "./contextDocBuilder";
4848

49+
function createDeferred<T>() {
50+
let resolve!: (value: T | PromiseLike<T>) => void;
51+
let reject!: (reason?: unknown) => void;
52+
const promise = new Promise<T>((res, rej) => {
53+
resolve = res;
54+
reject = rej;
55+
});
56+
return { promise, resolve, reject };
57+
}
58+
4959
function createLogger() {
5060
return {
5161
debug: () => {},
@@ -221,4 +231,99 @@ describe("contextDocService", () => {
221231
expect(service.getDocPath("prd_ade")).toBe(path.join(projectRoot, "prd_ade.md"));
222232
expect(resolveContextDocPath).toHaveBeenCalledWith(projectRoot, "prd_ade");
223233
});
234+
235+
it("persists active auto-refresh status as pending/running with trigger metadata", async () => {
236+
const { service } = await createFixture();
237+
const deferred = createDeferred<Awaited<ReturnType<typeof runContextDocGeneration>>>();
238+
vi.mocked(runContextDocGeneration).mockReturnValueOnce(deferred.promise as ReturnType<typeof runContextDocGeneration>);
239+
240+
await service.savePrefs({
241+
provider: "unified",
242+
modelId: "gpt-5",
243+
reasoningEffort: "medium",
244+
events: { onPrLand: true },
245+
});
246+
247+
const refreshPromise = service.maybeAutoRefreshDocs({
248+
event: "pr_land",
249+
reason: "prs_land:123",
250+
});
251+
252+
const duringRun = service.getStatus().generation;
253+
expect(["pending", "running"]).toContain(duringRun.state);
254+
expect(duringRun.source).toBe("auto");
255+
expect(duringRun.event).toBe("pr_land");
256+
expect(duringRun.reason).toBe("prs_land:123");
257+
expect(duringRun.provider).toBe("unified");
258+
expect(duringRun.modelId).toBe("gpt-5");
259+
expect(duringRun.reasoningEffort).toBe("medium");
260+
261+
deferred.resolve({
262+
provider: "unified",
263+
generatedAt: "2026-03-05T12:01:00.000Z",
264+
prdPath: "/tmp/PRD.ade.md",
265+
architecturePath: "/tmp/ARCHITECTURE.ade.md",
266+
usedFallbackPath: false,
267+
warnings: [],
268+
outputPreview: "generated",
269+
});
270+
271+
await expect(refreshPromise).resolves.toMatchObject({
272+
provider: "unified",
273+
generatedAt: "2026-03-05T12:01:00.000Z",
274+
});
275+
276+
expect(service.getStatus().generation).toMatchObject({
277+
state: "succeeded",
278+
source: "auto",
279+
event: "pr_land",
280+
reason: "prs_land:123",
281+
provider: "unified",
282+
modelId: "gpt-5",
283+
reasoningEffort: "medium",
284+
finishedAt: "2026-03-05T12:01:00.000Z",
285+
});
286+
});
287+
288+
it("records manual generation metadata on completion", async () => {
289+
const { service } = await createFixture();
290+
291+
await service.generateDocs({
292+
provider: "codex",
293+
modelId: "gpt-5-codex",
294+
reasoningEffort: "high",
295+
events: { onPrCreate: true },
296+
});
297+
298+
expect(service.getStatus().generation).toMatchObject({
299+
state: "succeeded",
300+
source: "manual",
301+
event: null,
302+
reason: "manual_generate",
303+
provider: "codex",
304+
modelId: "gpt-5-codex",
305+
reasoningEffort: "high",
306+
finishedAt: "2026-03-05T12:00:00.000Z",
307+
});
308+
});
309+
310+
it("maps legacy idle generation records with a finish time to succeeded", async () => {
311+
const { db, service } = await createFixture();
312+
313+
db.setJson("context:docs:generationStatus.v1", {
314+
state: "idle",
315+
finishedAt: "2026-03-05T09:30:00.000Z",
316+
source: "auto",
317+
event: "pr_create",
318+
reason: "legacy_run",
319+
});
320+
321+
expect(service.getStatus().generation).toMatchObject({
322+
state: "succeeded",
323+
source: "auto",
324+
event: "pr_create",
325+
reason: "legacy_run",
326+
finishedAt: "2026-03-05T09:30:00.000Z",
327+
});
328+
});
224329
});

0 commit comments

Comments
 (0)