gsd-pi 2.39.0-dev.6ef0cb1 → 2.39.0-dev.d6a1625

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,6 +64,16 @@ export default function AsyncJobs(pi) {
64
64
  },
65
65
  });
66
66
  });
67
+ pi.on("session_before_switch", async () => {
68
+ if (manager) {
69
+ // Cancel all running background jobs — their results are no longer
70
+ // relevant to the new session and would produce wasteful follow-up
71
+ // notifications that trigger empty LLM turns (#1642).
72
+ for (const job of manager.getRunningJobs()) {
73
+ manager.cancel(job.id);
74
+ }
75
+ }
76
+ });
67
77
  pi.on("session_shutdown", async () => {
68
78
  if (manager) {
69
79
  manager.shutdown();
@@ -205,6 +205,20 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
205
205
  unitId,
206
206
  status: result.status,
207
207
  });
208
+ // Discard trailing follow-up messages (e.g. async_job_result notifications)
209
+ // from the completed unit. Without this, queued follow-ups trigger wasteful
210
+ // LLM turns before the next session can start (#1642).
211
+ // clearQueue() lives on AgentSession but isn't part of the typed
212
+ // ExtensionCommandContext interface — call it via runtime check.
213
+ try {
214
+ const cmdCtxAny = s.cmdCtx;
215
+ if (typeof cmdCtxAny?.clearQueue === "function") {
216
+ cmdCtxAny.clearQueue();
217
+ }
218
+ }
219
+ catch {
220
+ // Non-fatal — clearQueue may not be available in all contexts
221
+ }
208
222
  return result;
209
223
  }
210
224
  // ─── generateMilestoneReport ──────────────────────────────────────────────────
@@ -630,8 +630,8 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
630
630
  if (hasResult)
631
631
  return null;
632
632
  }
633
- // Classify UAT type; unknown type treat as human-experience (human review)
634
- const uatType = extractUatType(uatContent) ?? "human-experience";
633
+ // Classify UAT type; default to artifact-driven (LLM-executed UATs are always artifact-driven)
634
+ const uatType = extractUatType(uatContent) ?? "artifact-driven";
635
635
  return { sliceId: sid, uatType };
636
636
  }
637
637
  // ─── Prompt Builders ──────────────────────────────────────────────────────
@@ -1210,7 +1210,7 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
1210
1210
  inlined.push(projectInline);
1211
1211
  const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1212
1212
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
1213
- const uatType = extractUatType(uatContent) ?? "human-experience";
1213
+ const uatType = extractUatType(uatContent) ?? "artifact-driven";
1214
1214
  return loadPrompt("run-uat", {
1215
1215
  workingDirectory: base,
1216
1216
  milestoneId: mid,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsd-pi",
3
- "version": "2.39.0-dev.6ef0cb1",
3
+ "version": "2.39.0-dev.d6a1625",
4
4
  "description": "GSD — Get Shit Done coding agent",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -78,6 +78,17 @@ export default function AsyncJobs(pi: ExtensionAPI) {
78
78
  });
79
79
  });
80
80
 
81
+ pi.on("session_before_switch", async () => {
82
+ if (manager) {
83
+ // Cancel all running background jobs — their results are no longer
84
+ // relevant to the new session and would produce wasteful follow-up
85
+ // notifications that trigger empty LLM turns (#1642).
86
+ for (const job of manager.getRunningJobs()) {
87
+ manager.cancel(job.id);
88
+ }
89
+ }
90
+ });
91
+
81
92
  pi.on("session_shutdown", async () => {
82
93
  if (manager) {
83
94
  manager.shutdown();
@@ -287,6 +287,20 @@ export async function runUnit(
287
287
  status: result.status,
288
288
  });
289
289
 
290
+ // Discard trailing follow-up messages (e.g. async_job_result notifications)
291
+ // from the completed unit. Without this, queued follow-ups trigger wasteful
292
+ // LLM turns before the next session can start (#1642).
293
+ // clearQueue() lives on AgentSession but isn't part of the typed
294
+ // ExtensionCommandContext interface — call it via runtime check.
295
+ try {
296
+ const cmdCtxAny = s.cmdCtx as Record<string, unknown> | null;
297
+ if (typeof cmdCtxAny?.clearQueue === "function") {
298
+ (cmdCtxAny.clearQueue as () => unknown)();
299
+ }
300
+ } catch {
301
+ // Non-fatal — clearQueue may not be available in all contexts
302
+ }
303
+
290
304
  return result;
291
305
  }
292
306
 
@@ -759,8 +759,8 @@ export async function checkNeedsRunUat(
759
759
  if (hasResult) return null;
760
760
  }
761
761
 
762
- // Classify UAT type; unknown type treat as human-experience (human review)
763
- const uatType = extractUatType(uatContent) ?? "human-experience";
762
+ // Classify UAT type; default to artifact-driven (LLM-executed UATs are always artifact-driven)
763
+ const uatType = extractUatType(uatContent) ?? "artifact-driven";
764
764
 
765
765
  return { sliceId: sid, uatType };
766
766
  }
@@ -1403,7 +1403,7 @@ export async function buildRunUatPrompt(
1403
1403
  const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1404
1404
 
1405
1405
  const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
1406
- const uatType = extractUatType(uatContent) ?? "human-experience";
1406
+ const uatType = extractUatType(uatContent) ?? "artifact-driven";
1407
1407
 
1408
1408
  return loadPrompt("run-uat", {
1409
1409
  workingDirectory: base,