gsd-pi 2.32.0 → 2.33.0-dev.bafba33

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.
Files changed (91) hide show
  1. package/README.md +27 -20
  2. package/dist/resource-loader.js +13 -3
  3. package/dist/resources/extensions/gsd/auto-dashboard.ts +3 -1
  4. package/dist/resources/extensions/gsd/auto-dispatch.ts +40 -12
  5. package/dist/resources/extensions/gsd/auto-idempotency.ts +3 -2
  6. package/dist/resources/extensions/gsd/auto-observability.ts +2 -4
  7. package/dist/resources/extensions/gsd/auto-post-unit.ts +5 -5
  8. package/dist/resources/extensions/gsd/auto-prompts.ts +46 -44
  9. package/dist/resources/extensions/gsd/auto-recovery.ts +8 -22
  10. package/dist/resources/extensions/gsd/auto-start.ts +8 -6
  11. package/dist/resources/extensions/gsd/auto-stuck-detection.ts +3 -2
  12. package/dist/resources/extensions/gsd/auto-timeout-recovery.ts +2 -1
  13. package/dist/resources/extensions/gsd/auto-timers.ts +3 -2
  14. package/dist/resources/extensions/gsd/auto-verification.ts +6 -6
  15. package/dist/resources/extensions/gsd/auto-worktree.ts +5 -4
  16. package/dist/resources/extensions/gsd/auto.ts +108 -182
  17. package/dist/resources/extensions/gsd/commands-inspect.ts +2 -1
  18. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +2 -1
  19. package/dist/resources/extensions/gsd/complexity-classifier.ts +5 -7
  20. package/dist/resources/extensions/gsd/crash-recovery.ts +15 -2
  21. package/dist/resources/extensions/gsd/dispatch-guard.ts +2 -1
  22. package/dist/resources/extensions/gsd/error-utils.ts +6 -0
  23. package/dist/resources/extensions/gsd/export.ts +2 -1
  24. package/dist/resources/extensions/gsd/git-service.ts +3 -2
  25. package/dist/resources/extensions/gsd/guided-flow.ts +3 -2
  26. package/dist/resources/extensions/gsd/index.ts +12 -5
  27. package/dist/resources/extensions/gsd/key-manager.ts +2 -1
  28. package/dist/resources/extensions/gsd/marketplace-discovery.ts +4 -3
  29. package/dist/resources/extensions/gsd/metrics.ts +3 -3
  30. package/dist/resources/extensions/gsd/migrate-external.ts +21 -4
  31. package/dist/resources/extensions/gsd/milestone-ids.ts +2 -1
  32. package/dist/resources/extensions/gsd/native-git-bridge.ts +2 -1
  33. package/dist/resources/extensions/gsd/parallel-merge.ts +2 -1
  34. package/dist/resources/extensions/gsd/parallel-orchestrator.ts +2 -1
  35. package/dist/resources/extensions/gsd/post-unit-hooks.ts +8 -9
  36. package/dist/resources/extensions/gsd/quick.ts +58 -3
  37. package/dist/resources/extensions/gsd/repo-identity.ts +22 -1
  38. package/dist/resources/extensions/gsd/session-lock.ts +12 -1
  39. package/dist/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +14 -11
  40. package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  41. package/dist/resources/extensions/gsd/tests/loop-regression.test.ts +839 -0
  42. package/dist/resources/extensions/gsd/undo.ts +5 -7
  43. package/dist/resources/extensions/gsd/unit-id.ts +14 -0
  44. package/dist/resources/extensions/gsd/unit-runtime.ts +2 -1
  45. package/dist/resources/extensions/gsd/worktree-command.ts +8 -7
  46. package/package.json +3 -2
  47. package/packages/pi-coding-agent/package.json +1 -1
  48. package/pkg/package.json +1 -1
  49. package/src/resources/extensions/gsd/auto-dashboard.ts +3 -1
  50. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -12
  51. package/src/resources/extensions/gsd/auto-idempotency.ts +3 -2
  52. package/src/resources/extensions/gsd/auto-observability.ts +2 -4
  53. package/src/resources/extensions/gsd/auto-post-unit.ts +5 -5
  54. package/src/resources/extensions/gsd/auto-prompts.ts +46 -44
  55. package/src/resources/extensions/gsd/auto-recovery.ts +8 -22
  56. package/src/resources/extensions/gsd/auto-start.ts +8 -6
  57. package/src/resources/extensions/gsd/auto-stuck-detection.ts +3 -2
  58. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -1
  59. package/src/resources/extensions/gsd/auto-timers.ts +3 -2
  60. package/src/resources/extensions/gsd/auto-verification.ts +6 -6
  61. package/src/resources/extensions/gsd/auto-worktree.ts +5 -4
  62. package/src/resources/extensions/gsd/auto.ts +108 -182
  63. package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
  64. package/src/resources/extensions/gsd/commands-workflow-templates.ts +2 -1
  65. package/src/resources/extensions/gsd/complexity-classifier.ts +5 -7
  66. package/src/resources/extensions/gsd/crash-recovery.ts +15 -2
  67. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
  68. package/src/resources/extensions/gsd/error-utils.ts +6 -0
  69. package/src/resources/extensions/gsd/export.ts +2 -1
  70. package/src/resources/extensions/gsd/git-service.ts +3 -2
  71. package/src/resources/extensions/gsd/guided-flow.ts +3 -2
  72. package/src/resources/extensions/gsd/index.ts +12 -5
  73. package/src/resources/extensions/gsd/key-manager.ts +2 -1
  74. package/src/resources/extensions/gsd/marketplace-discovery.ts +4 -3
  75. package/src/resources/extensions/gsd/metrics.ts +3 -3
  76. package/src/resources/extensions/gsd/migrate-external.ts +21 -4
  77. package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
  78. package/src/resources/extensions/gsd/native-git-bridge.ts +2 -1
  79. package/src/resources/extensions/gsd/parallel-merge.ts +2 -1
  80. package/src/resources/extensions/gsd/parallel-orchestrator.ts +2 -1
  81. package/src/resources/extensions/gsd/post-unit-hooks.ts +8 -9
  82. package/src/resources/extensions/gsd/quick.ts +58 -3
  83. package/src/resources/extensions/gsd/repo-identity.ts +22 -1
  84. package/src/resources/extensions/gsd/session-lock.ts +12 -1
  85. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +14 -11
  86. package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
  87. package/src/resources/extensions/gsd/tests/loop-regression.test.ts +839 -0
  88. package/src/resources/extensions/gsd/undo.ts +5 -7
  89. package/src/resources/extensions/gsd/unit-id.ts +14 -0
  90. package/src/resources/extensions/gsd/unit-runtime.ts +2 -1
  91. package/src/resources/extensions/gsd/worktree-command.ts +8 -7
@@ -63,6 +63,8 @@ import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath } from "./debug-
63
63
  import type { AutoSession } from "./auto/session.js";
64
64
  import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "node:fs";
65
65
  import { join } from "node:path";
66
+ import { getErrorMessage } from "./error-utils.js";
67
+ import { parseUnitId } from "./unit-id.js";
66
68
 
67
69
  export interface BootstrapDeps {
68
70
  shouldUseWorktreeIsolation: () => boolean;
@@ -138,7 +140,7 @@ export async function bootstrapAutoSession(
138
140
  if (crashLock && crashLock.pid !== process.pid) {
139
141
  // We already hold the session lock, so no concurrent session is running.
140
142
  // The crash lock is from a dead process — recover context from it.
141
- const recoveredMid = crashLock.unitId.split("/")[0];
143
+ const recoveredMid = parseUnitId(crashLock.unitId).milestone;
142
144
  const milestoneAlreadyComplete = recoveredMid
143
145
  ? !!resolveMilestoneFile(base, recoveredMid, "SUMMARY")
144
146
  : false;
@@ -201,11 +203,11 @@ export async function bootstrapAutoSession(
201
203
  if (!midMatch) continue;
202
204
  const mid = midMatch[1];
203
205
  if (resolveMilestoneFile(base, mid, "SUMMARY")) {
204
- try { unlinkSync(join(runtimeUnitsDir, file)); } catch (e) { debugLog("stale-unit-cleanup-failed", { file, error: e instanceof Error ? e.message : String(e) }); }
206
+ try { unlinkSync(join(runtimeUnitsDir, file)); } catch (e) { debugLog("stale-unit-cleanup-failed", { file, error: getErrorMessage(e) }); }
205
207
  }
206
208
  }
207
209
  }
208
- } catch (e) { debugLog("stale-unit-dir-cleanup-failed", { error: e instanceof Error ? e.message : String(e) }); }
210
+ } catch (e) { debugLog("stale-unit-dir-cleanup-failed", { error: getErrorMessage(e) }); }
209
211
 
210
212
  let state = await deriveState(base);
211
213
 
@@ -343,7 +345,7 @@ export async function bootstrapAutoSession(
343
345
  registerSigtermHandler(s.originalBasePath);
344
346
  } catch (err) {
345
347
  ctx.ui.notify(
346
- `Auto-worktree setup failed: ${err instanceof Error ? err.message : String(err)}. Continuing in project root.`,
348
+ `Auto-worktree setup failed: ${getErrorMessage(err)}. Continuing in project root.`,
347
349
  "warning",
348
350
  );
349
351
  }
@@ -435,7 +437,7 @@ export async function bootstrapAutoSession(
435
437
  }
436
438
  } catch (err) {
437
439
  ctx.ui.notify(
438
- `Secrets check error: ${err instanceof Error ? err.message : String(err)}. Continuing without secrets.`,
440
+ `Secrets check error: ${getErrorMessage(err)}. Continuing without secrets.`,
439
441
  "warning",
440
442
  );
441
443
  }
@@ -453,7 +455,7 @@ export async function bootstrapAutoSession(
453
455
  ctx.ui.notify("Removed stale .git/index.lock from prior crash.", "info");
454
456
  }
455
457
  }
456
- } catch (e) { debugLog("git-lock-cleanup-failed", { error: e instanceof Error ? e.message : String(e) }); }
458
+ } catch (e) { debugLog("git-lock-cleanup-failed", { error: getErrorMessage(e) }); }
457
459
 
458
460
  // Pre-flight: validate milestone queue
459
461
  try {
@@ -39,6 +39,7 @@ import {
39
39
  import type { AutoSession } from "./auto/session.js";
40
40
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
41
41
  import { join } from "node:path";
42
+ import { parseUnitId } from "./unit-id.js";
42
43
 
43
44
  export interface StuckContext {
44
45
  s: AutoSession;
@@ -99,7 +100,7 @@ export async function checkStuckAndRecover(sctx: StuckContext): Promise<StuckRes
99
100
 
100
101
  // Final reconciliation pass for execute-task
101
102
  if (unitType === "execute-task") {
102
- const [mid, sid, tid] = unitId.split("/");
103
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
103
104
  if (mid && sid && tid) {
104
105
  const status = await inspectExecuteTaskDurability(basePath, unitId);
105
106
  if (status) {
@@ -168,7 +169,7 @@ export async function checkStuckAndRecover(sctx: StuckContext): Promise<StuckRes
168
169
  // Adaptive self-repair: each retry attempts a different remediation step.
169
170
  if (unitType === "execute-task") {
170
171
  const status = await inspectExecuteTaskDurability(basePath, unitId);
171
- const [mid, sid, tid] = unitId.split("/");
172
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
172
173
  if (status && mid && sid && tid) {
173
174
  if (status.summaryExists && !status.taskChecked) {
174
175
  const repaired = skipExecuteTask(basePath, mid, sid, tid, status, "self-repair", 0);
@@ -18,6 +18,7 @@ import {
18
18
  writeBlockerPlaceholder,
19
19
  } from "./auto-recovery.js";
20
20
  import { existsSync } from "node:fs";
21
+ import { parseUnitId } from "./unit-id.js";
21
22
 
22
23
  export interface RecoveryContext {
23
24
  basePath: string;
@@ -128,7 +129,7 @@ export async function recoverTimedOutUnit(
128
129
 
129
130
  // Retries exhausted — write missing durable artifacts and advance.
130
131
  const diagnostic = formatExecuteTaskRecoveryStatus(status);
131
- const [mid, sid, tid] = unitId.split("/");
132
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
132
133
  const skipped = mid && sid && tid
133
134
  ? skipExecuteTask(basePath, mid, sid, tid, status, reason, maxRecoveryAttempts)
134
135
  : false;
@@ -20,6 +20,7 @@ import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
20
20
  import { saveActivityLog } from "./activity-log.js";
21
21
  import { recoverTimedOutUnit, type RecoveryContext } from "./auto-timeout-recovery.js";
22
22
  import type { AutoSession } from "./auto/session.js";
23
+ import { getErrorMessage } from "./error-utils.js";
23
24
 
24
25
  export interface SupervisionContext {
25
26
  s: AutoSession;
@@ -127,7 +128,7 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
127
128
  );
128
129
  await pauseAuto(ctx, pi);
129
130
  } catch (err) {
130
- const message = err instanceof Error ? err.message : String(err);
131
+ const message = getErrorMessage(err);
131
132
  console.error(`[idle-watchdog] Unhandled error: ${message}`);
132
133
  try {
133
134
  ctx.ui.notify(`Idle watchdog error: ${message}`, "warning");
@@ -159,7 +160,7 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
159
160
  );
160
161
  await pauseAuto(ctx, pi);
161
162
  } catch (err) {
162
- const message = err instanceof Error ? err.message : String(err);
163
+ const message = getErrorMessage(err);
163
164
  console.error(`[hard-timeout] Unhandled error: ${message}`);
164
165
  try {
165
166
  ctx.ui.notify(`Hard timeout error: ${message}`, "warning");
@@ -24,6 +24,8 @@ import { writeVerificationJSON } from "./verification-evidence.js";
24
24
  import { removePersistedKey } from "./auto-recovery.js";
25
25
  import type { AutoSession, PendingVerificationRetry } from "./auto/session.js";
26
26
  import { join } from "node:path";
27
+ import { getErrorMessage } from "./error-utils.js";
28
+ import { parseUnitId } from "./unit-id.js";
27
29
 
28
30
  export interface VerificationContext {
29
31
  s: AutoSession;
@@ -57,10 +59,9 @@ export async function runPostUnitVerification(
57
59
  const prefs = effectivePrefs?.preferences;
58
60
 
59
61
  // Read task plan verify field
60
- const parts = s.currentUnit.id.split("/");
62
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
61
63
  let taskPlanVerify: string | undefined;
62
- if (parts.length >= 3) {
63
- const [mid, sid, tid] = parts;
64
+ if (mid && sid && tid) {
64
65
  const planFile = resolveSliceFile(s.basePath, mid, sid, "PLAN");
65
66
  if (planFile) {
66
67
  const planContent = await loadFile(planFile);
@@ -152,9 +153,8 @@ export async function runPostUnitVerification(
152
153
 
153
154
  // Write verification evidence JSON
154
155
  const attempt = s.verificationRetryCount.get(s.currentUnit.id) ?? 0;
155
- if (parts.length >= 3) {
156
+ if (mid && sid && tid) {
156
157
  try {
157
- const [mid, sid, tid] = parts;
158
158
  const sDir = resolveSlicePath(s.basePath, mid, sid);
159
159
  if (sDir) {
160
160
  const tasksDir = join(sDir, "tasks");
@@ -204,7 +204,7 @@ export async function runPostUnitVerification(
204
204
  try {
205
205
  await dispatchNextUnit(ctx, pi);
206
206
  } catch (retryDispatchErr) {
207
- const msg = retryDispatchErr instanceof Error ? retryDispatchErr.message : String(retryDispatchErr);
207
+ const msg = getErrorMessage(retryDispatchErr);
208
208
  ctx.ui.notify(`Verification retry dispatch error: ${msg}`, "error");
209
209
  startDispatchGapWatchdog(ctx, pi);
210
210
  }
@@ -38,6 +38,7 @@ import {
38
38
  nativeBranchDelete,
39
39
  nativeBranchExists,
40
40
  } from "./native-git-bridge.js";
41
+ import { getErrorMessage } from "./error-utils.js";
41
42
 
42
43
  // ─── Module State ──────────────────────────────────────────────────────────
43
44
 
@@ -81,7 +82,7 @@ export function runWorktreePostCreateHook(sourceDir: string, worktreeDir: string
81
82
  });
82
83
  return null;
83
84
  } catch (err) {
84
- const msg = err instanceof Error ? err.message : String(err);
85
+ const msg = getErrorMessage(err);
85
86
  return `Worktree post-create hook failed: ${msg}`;
86
87
  }
87
88
  }
@@ -141,7 +142,7 @@ export function createAutoWorktree(basePath: string, milestoneId: string): strin
141
142
  // Don't store originalBase -- caller can retry or clean up.
142
143
  throw new GSDError(
143
144
  GSD_IO_ERROR,
144
- `Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`,
145
+ `Auto-worktree created at ${info.path} but chdir failed: ${getErrorMessage(err)}`,
145
146
  );
146
147
  }
147
148
 
@@ -168,7 +169,7 @@ export function teardownAutoWorktree(
168
169
  } catch (err) {
169
170
  throw new GSDError(
170
171
  GSD_IO_ERROR,
171
- `Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`,
172
+ `Failed to chdir back to ${originalBasePath} during teardown: ${getErrorMessage(err)}`,
172
173
  );
173
174
  }
174
175
 
@@ -274,7 +275,7 @@ export function enterAutoWorktree(basePath: string, milestoneId: string): string
274
275
  } catch (err) {
275
276
  throw new GSDError(
276
277
  GSD_IO_ERROR,
277
- `Failed to enter auto-worktree at ${p}: ${err instanceof Error ? err.message : String(err)}`,
278
+ `Failed to enter auto-worktree at ${p}: ${getErrorMessage(err)}`,
278
279
  );
279
280
  }
280
281