gsd-pi 2.33.1-dev.ee47f1b → 2.34.0-dev.bbb5216

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 (135) hide show
  1. package/dist/bundled-resource-path.d.ts +8 -0
  2. package/dist/bundled-resource-path.js +14 -0
  3. package/dist/headless-query.js +6 -6
  4. package/dist/resources/extensions/gsd/auto/session.js +27 -32
  5. package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
  6. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
  7. package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
  8. package/dist/resources/extensions/gsd/auto-loop.js +956 -0
  9. package/dist/resources/extensions/gsd/auto-observability.js +4 -2
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
  11. package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
  12. package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
  13. package/dist/resources/extensions/gsd/auto-start.js +330 -309
  14. package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
  15. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
  16. package/dist/resources/extensions/gsd/auto-timers.js +3 -4
  17. package/dist/resources/extensions/gsd/auto-verification.js +35 -73
  18. package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
  19. package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
  20. package/dist/resources/extensions/gsd/auto.js +283 -1013
  21. package/dist/resources/extensions/gsd/captures.js +10 -4
  22. package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
  23. package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  24. package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
  25. package/dist/resources/extensions/gsd/git-service.js +1 -1
  26. package/dist/resources/extensions/gsd/gsd-db.js +296 -151
  27. package/dist/resources/extensions/gsd/index.js +92 -228
  28. package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
  29. package/dist/resources/extensions/gsd/progress-score.js +61 -156
  30. package/dist/resources/extensions/gsd/quick.js +98 -122
  31. package/dist/resources/extensions/gsd/session-lock.js +13 -0
  32. package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
  33. package/dist/resources/extensions/gsd/undo.js +43 -48
  34. package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
  35. package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
  36. package/dist/resources/extensions/gsd/verification-gate.js +6 -35
  37. package/dist/resources/extensions/gsd/worktree-command.js +30 -24
  38. package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
  39. package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
  40. package/dist/resources/extensions/gsd/worktree.js +7 -44
  41. package/dist/tool-bootstrap.js +59 -11
  42. package/dist/worktree-cli.js +7 -7
  43. package/package.json +1 -1
  44. package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
  45. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  46. package/packages/pi-ai/dist/models.generated.js +735 -2588
  47. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  48. package/packages/pi-ai/src/models.generated.ts +1039 -2892
  49. package/packages/pi-coding-agent/package.json +1 -1
  50. package/pkg/package.json +1 -1
  51. package/src/resources/extensions/gsd/auto/session.ts +47 -30
  52. package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
  53. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
  54. package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
  55. package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
  56. package/src/resources/extensions/gsd/auto-observability.ts +4 -2
  57. package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
  58. package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
  59. package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
  60. package/src/resources/extensions/gsd/auto-start.ts +440 -354
  61. package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
  62. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
  63. package/src/resources/extensions/gsd/auto-timers.ts +3 -4
  64. package/src/resources/extensions/gsd/auto-verification.ts +76 -90
  65. package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
  66. package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
  67. package/src/resources/extensions/gsd/auto.ts +515 -1199
  68. package/src/resources/extensions/gsd/captures.ts +10 -4
  69. package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
  70. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
  71. package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
  72. package/src/resources/extensions/gsd/git-service.ts +8 -1
  73. package/src/resources/extensions/gsd/gitignore.ts +4 -2
  74. package/src/resources/extensions/gsd/gsd-db.ts +375 -180
  75. package/src/resources/extensions/gsd/index.ts +104 -263
  76. package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
  77. package/src/resources/extensions/gsd/progress-score.ts +65 -200
  78. package/src/resources/extensions/gsd/quick.ts +121 -125
  79. package/src/resources/extensions/gsd/session-lock.ts +11 -0
  80. package/src/resources/extensions/gsd/templates/preferences.md +1 -0
  81. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
  82. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
  83. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  84. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
  85. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
  86. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
  87. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
  88. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
  89. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
  90. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
  91. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
  92. package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
  93. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
  94. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
  95. package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
  96. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
  97. package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
  98. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
  99. package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
  100. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
  101. package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
  102. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
  103. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
  104. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
  105. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
  106. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
  107. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
  108. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
  109. package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
  110. package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
  111. package/src/resources/extensions/gsd/types.ts +90 -81
  112. package/src/resources/extensions/gsd/undo.ts +42 -46
  113. package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
  114. package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
  115. package/src/resources/extensions/gsd/verification-gate.ts +6 -39
  116. package/src/resources/extensions/gsd/worktree-command.ts +36 -24
  117. package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
  118. package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
  119. package/src/resources/extensions/gsd/worktree.ts +7 -44
  120. package/dist/resources/extensions/gsd/auto-constants.js +0 -5
  121. package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
  122. package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
  123. package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
  124. package/src/resources/extensions/gsd/auto-constants.ts +0 -6
  125. package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
  126. package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
  127. package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
  128. package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
  129. package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
  130. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
  131. package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
  132. package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
  133. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
  134. package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
  135. package/src/resources/extensions/gsd/tests/session-lock.test.ts +0 -434
@@ -11,6 +11,7 @@
11
11
  */
12
12
 
13
13
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'node:fs';
14
+ import { createRequire } from 'node:module';
14
15
  import { join } from 'node:path';
15
16
  import { tmpdir } from 'node:os';
16
17
 
@@ -26,6 +27,18 @@ import { gsdRoot } from '../paths.ts';
26
27
  import { createTestContext } from './test-helpers.ts';
27
28
 
28
29
  const { assertEq, assertTrue, report } = createTestContext();
30
+ const require = createRequire(import.meta.url);
31
+
32
+ function hasProperLockfile(): boolean {
33
+ try {
34
+ require("proper-lockfile");
35
+ return true;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ const properLockfileAvailable = hasProperLockfile();
29
42
 
30
43
  async function main(): Promise<void> {
31
44
 
@@ -207,6 +220,57 @@ async function main(): Promise<void> {
207
220
  }
208
221
  }
209
222
 
223
+ // ─── 9. Re-entrant acquisition without explicit release ───────────────
224
+ console.log('\n=== 9. re-entrant acquire without explicit release ===');
225
+ {
226
+ const base = mkdtempSync(join(tmpdir(), 'gsd-session-lock-'));
227
+ mkdirSync(join(base, '.gsd'), { recursive: true });
228
+
229
+ try {
230
+ const r1 = acquireSessionLock(base);
231
+ assertTrue(r1.acquired, 'first acquisition succeeds');
232
+
233
+ const r2 = acquireSessionLock(base);
234
+ assertTrue(r2.acquired, 're-entrant acquisition succeeds');
235
+
236
+ const valid = validateSessionLock(base);
237
+ assertTrue(valid, 're-entrant acquisition does not corrupt validation state');
238
+
239
+ releaseSessionLock(base);
240
+ } finally {
241
+ rmSync(base, { recursive: true, force: true });
242
+ }
243
+ }
244
+
245
+ // ─── 10. Re-entrant acquisition refreshes lock artifacts ──────────────
246
+ console.log('\n=== 10. re-entrant acquire refreshes lock artifacts ===');
247
+ {
248
+ const base = mkdtempSync(join(tmpdir(), 'gsd-session-lock-'));
249
+ mkdirSync(join(base, '.gsd'), { recursive: true });
250
+
251
+ try {
252
+ const r1 = acquireSessionLock(base);
253
+ assertTrue(r1.acquired, 'first acquisition succeeds');
254
+
255
+ const lockDir = gsdRoot(base) + '.lock';
256
+ if (properLockfileAvailable) {
257
+ assertTrue(existsSync(lockDir), '.gsd.lock/ exists after first acquisition');
258
+ }
259
+
260
+ const r2 = acquireSessionLock(base);
261
+ assertTrue(r2.acquired, 'second acquisition succeeds');
262
+ if (properLockfileAvailable) {
263
+ assertTrue(existsSync(lockDir), '.gsd.lock/ exists after re-entrant acquisition');
264
+ }
265
+ assertTrue(validateSessionLock(base), 'lock remains valid after re-entrant acquisition');
266
+
267
+ releaseSessionLock(base);
268
+ assertTrue(!existsSync(lockDir), '.gsd.lock/ is removed after release');
269
+ } finally {
270
+ rmSync(base, { recursive: true, force: true });
271
+ }
272
+ }
273
+
210
274
  report();
211
275
  }
212
276
 
@@ -0,0 +1,181 @@
1
+ /**
2
+ * sidecar-queue.test.ts — Source-level contract tests for the sidecar queue pattern (S03).
3
+ *
4
+ * Verifies the structural invariants of the sidecar queue: the SidecarItem type,
5
+ * AutoSession sidecarQueue field, enqueue patterns in postUnitPostVerification,
6
+ * and dequeue logic in autoLoop. These are source-reading tests — no runtime required.
7
+ */
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { readFileSync } from "node:fs";
12
+ import { join, dirname } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const SESSION_TS_PATH = join(__dirname, "..", "auto", "session.ts");
17
+ const POST_UNIT_TS_PATH = join(__dirname, "..", "auto-post-unit.ts");
18
+ const AUTO_LOOP_TS_PATH = join(__dirname, "..", "auto-loop.ts");
19
+
20
+ function getSessionTsSource(): string {
21
+ return readFileSync(SESSION_TS_PATH, "utf-8");
22
+ }
23
+
24
+ function getPostUnitTsSource(): string {
25
+ return readFileSync(POST_UNIT_TS_PATH, "utf-8");
26
+ }
27
+
28
+ function getAutoLoopTsSource(): string {
29
+ return readFileSync(AUTO_LOOP_TS_PATH, "utf-8");
30
+ }
31
+
32
+ /**
33
+ * Extract the body of postUnitPostVerification from auto-post-unit.ts source.
34
+ */
35
+ function getPostUnitPostVerificationBody(): string {
36
+ const source = getPostUnitTsSource();
37
+ const fnIdx = source.indexOf("export async function postUnitPostVerification");
38
+ assert.ok(fnIdx > -1, "postUnitPostVerification must exist in auto-post-unit.ts");
39
+ return source.slice(fnIdx);
40
+ }
41
+
42
+ // ─── SidecarItem type contract ───────────────────────────────────────────────
43
+
44
+ test("SidecarItem type is exported from session.ts", () => {
45
+ const source = getSessionTsSource();
46
+ assert.ok(
47
+ source.includes("export interface SidecarItem"),
48
+ "session.ts must export the SidecarItem interface",
49
+ );
50
+ });
51
+
52
+ test("SidecarItem has required kind field with hook/triage/quick-task union", () => {
53
+ const source = getSessionTsSource();
54
+ const ifaceIdx = source.indexOf("export interface SidecarItem");
55
+ const ifaceBlock = source.slice(ifaceIdx, ifaceIdx + 500);
56
+ assert.ok(
57
+ ifaceBlock.includes('"hook"') && ifaceBlock.includes('"triage"') && ifaceBlock.includes('"quick-task"'),
58
+ "SidecarItem.kind must be a union of 'hook' | 'triage' | 'quick-task'",
59
+ );
60
+ });
61
+
62
+ // ─── AutoSession sidecarQueue field ──────────────────────────────────────────
63
+
64
+ test("AutoSession declares sidecarQueue field", () => {
65
+ const source = getSessionTsSource();
66
+ assert.ok(
67
+ source.includes("sidecarQueue"),
68
+ "AutoSession must declare sidecarQueue property",
69
+ );
70
+ assert.ok(
71
+ source.includes("SidecarItem[]"),
72
+ "sidecarQueue must be typed as SidecarItem[]",
73
+ );
74
+ });
75
+
76
+ test("AutoSession resets sidecarQueue in reset()", () => {
77
+ const source = getSessionTsSource();
78
+ const resetIdx = source.indexOf("reset(): void");
79
+ assert.ok(resetIdx > -1, "AutoSession must have a reset() method");
80
+ const resetBlock = source.slice(resetIdx, resetIdx + 3000);
81
+ assert.ok(
82
+ resetBlock.includes("sidecarQueue"),
83
+ "reset() must clear sidecarQueue",
84
+ );
85
+ });
86
+
87
+ // ─── postUnitPostVerification: no inline dispatch ────────────────────────────
88
+
89
+ test("postUnitPostVerification does not call pi.sendMessage", () => {
90
+ const body = getPostUnitPostVerificationBody();
91
+ assert.ok(
92
+ !body.includes("pi.sendMessage"),
93
+ "postUnitPostVerification must not call pi.sendMessage — all dispatch goes through sidecar queue",
94
+ );
95
+ });
96
+
97
+ test("postUnitPostVerification does not call newSession", () => {
98
+ const body = getPostUnitPostVerificationBody();
99
+ assert.ok(
100
+ !body.includes("s.cmdCtx.newSession") && !body.includes("cmdCtx.newSession"),
101
+ "postUnitPostVerification must not call newSession — all dispatch goes through sidecar queue",
102
+ );
103
+ });
104
+
105
+ // ─── postUnitPostVerification: sidecar enqueue for hooks ─────────────────────
106
+
107
+ test("postUnitPostVerification pushes to sidecarQueue for hooks", () => {
108
+ const source = getPostUnitTsSource();
109
+ // Find the hook section (marked by the post-unit hooks comment)
110
+ const hookSectionStart = source.indexOf("// ── Post-unit hooks");
111
+ assert.ok(hookSectionStart > -1, "auto-post-unit.ts must have a post-unit hooks section");
112
+ const triageSectionStart = source.indexOf("// ── Triage check");
113
+ assert.ok(triageSectionStart > -1, "auto-post-unit.ts must have a triage check section");
114
+ const hookSection = source.slice(hookSectionStart, triageSectionStart);
115
+ assert.ok(
116
+ hookSection.includes("s.sidecarQueue.push("),
117
+ "hook section must push to s.sidecarQueue",
118
+ );
119
+ assert.ok(
120
+ hookSection.includes('kind: "hook"'),
121
+ "hook sidecar item must have kind: 'hook'",
122
+ );
123
+ });
124
+
125
+ // ─── postUnitPostVerification: sidecar enqueue for triage ────────────────────
126
+
127
+ test("postUnitPostVerification pushes to sidecarQueue for triage", () => {
128
+ const source = getPostUnitTsSource();
129
+ const triageSectionStart = source.indexOf("// ── Triage check");
130
+ const quickTaskSectionStart = source.indexOf("// ── Quick-task dispatch");
131
+ assert.ok(triageSectionStart > -1, "auto-post-unit.ts must have a triage check section");
132
+ assert.ok(quickTaskSectionStart > -1, "auto-post-unit.ts must have a quick-task dispatch section");
133
+ const triageSection = source.slice(triageSectionStart, quickTaskSectionStart);
134
+ assert.ok(
135
+ triageSection.includes("s.sidecarQueue.push("),
136
+ "triage section must push to s.sidecarQueue",
137
+ );
138
+ assert.ok(
139
+ triageSection.includes('kind: "triage"'),
140
+ "triage sidecar item must have kind: 'triage'",
141
+ );
142
+ });
143
+
144
+ // ─── postUnitPostVerification: sidecar enqueue for quick-tasks ───────────────
145
+
146
+ test("postUnitPostVerification pushes to sidecarQueue for quick-tasks", () => {
147
+ const source = getPostUnitTsSource();
148
+ const quickTaskSectionStart = source.indexOf("// ── Quick-task dispatch");
149
+ assert.ok(quickTaskSectionStart > -1, "auto-post-unit.ts must have a quick-task dispatch section");
150
+ const quickTaskSection = source.slice(quickTaskSectionStart);
151
+ assert.ok(
152
+ quickTaskSection.includes("s.sidecarQueue.push("),
153
+ "quick-task section must push to s.sidecarQueue",
154
+ );
155
+ assert.ok(
156
+ quickTaskSection.includes('kind: "quick-task"'),
157
+ "quick-task sidecar item must have kind: 'quick-task'",
158
+ );
159
+ });
160
+
161
+ // ─── autoLoop: sidecar dequeue ───────────────────────────────────────────────
162
+
163
+ test("autoLoop has sidecar-dequeue phase", () => {
164
+ const source = getAutoLoopTsSource();
165
+ assert.ok(
166
+ source.includes('"sidecar-dequeue"'),
167
+ "autoLoop must log phase: 'sidecar-dequeue' when draining the sidecar queue",
168
+ );
169
+ });
170
+
171
+ test("autoLoop does not have inline dispatch loop", () => {
172
+ const source = getAutoLoopTsSource();
173
+ assert.ok(
174
+ !source.includes('"await-inline-dispatch"'),
175
+ "autoLoop must not contain 'await-inline-dispatch' — replaced by sidecar queue",
176
+ );
177
+ assert.ok(
178
+ !source.includes("while (inlineResult"),
179
+ "autoLoop must not contain a while(inlineResult...) loop — replaced by sidecar queue drain",
180
+ );
181
+ });
@@ -28,9 +28,6 @@ function createTempRepo(): string {
28
28
  run("git config user.email test@test.com", dir);
29
29
  run("git config user.name Test", dir);
30
30
  writeFileSync(join(dir, "README.md"), "# test\n");
31
- // Mirror production: .gsd/worktrees/ is gitignored so autoCommitDirtyState
32
- // doesn't pick up the worktrees directory as dirty state (#1127 fix).
33
- writeFileSync(join(dir, ".gitignore"), ".gsd/worktrees/\n");
34
31
  run("git add .", dir);
35
32
  run("git commit -m init", dir);
36
33
  run("git branch -M main", dir);
@@ -36,16 +36,16 @@ const typesSrc = readFileSync(join(__dirname, "..", "types.ts"), "utf-8");
36
36
 
37
37
  test("types: TokenProfile type exported with budget/balanced/quality", () => {
38
38
  assert.ok(typesSrc.includes("export type TokenProfile"), "TokenProfile should be exported");
39
- assert.ok(typesSrc.includes("'budget'"), "should include budget");
40
- assert.ok(typesSrc.includes("'balanced'"), "should include balanced");
41
- assert.ok(typesSrc.includes("'quality'"), "should include quality");
39
+ assert.match(typesSrc, /["']budget["']/, "should include budget");
40
+ assert.match(typesSrc, /["']balanced["']/, "should include balanced");
41
+ assert.match(typesSrc, /["']quality["']/, "should include quality");
42
42
  });
43
43
 
44
44
  test("types: InlineLevel type exported with full/standard/minimal", () => {
45
45
  assert.ok(typesSrc.includes("export type InlineLevel"), "InlineLevel should be exported");
46
- assert.ok(typesSrc.includes("'full'"), "should include full");
47
- assert.ok(typesSrc.includes("'standard'"), "should include standard");
48
- assert.ok(typesSrc.includes("'minimal'"), "should include minimal");
46
+ assert.match(typesSrc, /["']full["']/, "should include full");
47
+ assert.match(typesSrc, /["']standard["']/, "should include standard");
48
+ assert.match(typesSrc, /["']minimal["']/, "should include minimal");
49
49
  });
50
50
 
51
51
  test("types: PhaseSkipPreferences interface exported", () => {
@@ -108,14 +108,14 @@ test("dispatch: triage check guards against quick-task triggering triage", () =>
108
108
  );
109
109
  });
110
110
 
111
- test("dispatch: triage dispatch uses return-value pattern", () => {
111
+ test("dispatch: triage dispatch keeps the loop in continue mode", () => {
112
112
  const triageBlock = postUnitSrc.slice(
113
113
  postUnitSrc.indexOf("// ── Triage check"),
114
114
  postUnitSrc.indexOf("// ── Quick-task dispatch"),
115
115
  );
116
116
  assert.ok(
117
- triageBlock.includes('return "dispatched"'),
118
- "triage dispatch should return 'dispatched' after sending message",
117
+ triageBlock.includes('return "continue"'),
118
+ "triage dispatch should return 'continue' after enqueuing sidecar work",
119
119
  );
120
120
  });
121
121
 
@@ -309,14 +309,14 @@ test("dispatch: quick-task dispatch marks capture as executed", () => {
309
309
  );
310
310
  });
311
311
 
312
- test("dispatch: quick-task dispatch uses return-value pattern", () => {
312
+ test("dispatch: quick-task dispatch keeps the loop in continue mode", () => {
313
313
  const quickTaskSection = postUnitSrc.slice(
314
314
  postUnitSrc.indexOf("// ── Quick-task dispatch"),
315
315
  postUnitSrc.indexOf("if (s.stepMode)"),
316
316
  );
317
317
  assert.ok(
318
- quickTaskSection.includes('return "dispatched"'),
319
- "quick-task dispatch should return 'dispatched' after sending message",
318
+ quickTaskSection.includes('return "continue"'),
319
+ "quick-task dispatch should return 'continue' after enqueuing sidecar work",
320
320
  );
321
321
  });
322
322
 
@@ -19,11 +19,17 @@ test("handleUndo without --force only warns and leaves completed units intact",
19
19
  const base = makeTempDir("gsd-undo-confirm");
20
20
  try {
21
21
  mkdirSync(join(base, ".gsd"), { recursive: true });
22
+ mkdirSync(join(base, ".gsd", "activity"), { recursive: true });
22
23
  writeFileSync(
23
24
  join(base, ".gsd", "completed-units.json"),
24
25
  JSON.stringify(["execute-task/M001/S01/T01"]),
25
26
  "utf-8",
26
27
  );
28
+ writeFileSync(
29
+ join(base, ".gsd", "activity", "001-execute-task-M001-S01-T01.jsonl"),
30
+ "",
31
+ "utf-8",
32
+ );
27
33
 
28
34
  const notifications: Array<{ message: string; level: string }> = [];
29
35
  const ctx = {
@@ -58,7 +58,6 @@ test("verification-evidence: writeVerificationJSON writes correct JSON shape", (
58
58
  stdout: "all good",
59
59
  stderr: "",
60
60
  durationMs: 2340,
61
- blocking: true,
62
61
  },
63
62
  ],
64
63
  });
@@ -106,9 +105,9 @@ test("verification-evidence: writeVerificationJSON maps exitCode to verdict corr
106
105
  const result = makeResult({
107
106
  passed: false,
108
107
  checks: [
109
- { command: "lint", exitCode: 0, stdout: "", stderr: "", durationMs: 100, blocking: true },
110
- { command: "test", exitCode: 1, stdout: "", stderr: "fail", durationMs: 200, blocking: true },
111
- { command: "audit", exitCode: 2, stdout: "", stderr: "err", durationMs: 300, blocking: true },
108
+ { command: "lint", exitCode: 0, stdout: "", stderr: "", durationMs: 100 },
109
+ { command: "test", exitCode: 1, stdout: "", stderr: "fail", durationMs: 200 },
110
+ { command: "audit", exitCode: 2, stdout: "", stderr: "err", durationMs: 300 },
112
111
  ],
113
112
  });
114
113
 
@@ -134,7 +133,6 @@ test("verification-evidence: writeVerificationJSON excludes stdout/stderr from o
134
133
  stdout: "hello\n",
135
134
  stderr: "some warning",
136
135
  durationMs: 50,
137
- blocking: true,
138
136
  },
139
137
  ],
140
138
  });
@@ -183,8 +181,8 @@ test("verification-evidence: writeVerificationJSON uses optional unitId when pro
183
181
  test("verification-evidence: formatEvidenceTable returns markdown table with correct columns", () => {
184
182
  const result = makeResult({
185
183
  checks: [
186
- { command: "npm run typecheck", exitCode: 0, stdout: "", stderr: "", durationMs: 2340, blocking: true },
187
- { command: "npm run lint", exitCode: 1, stdout: "", stderr: "err", durationMs: 1100, blocking: true },
184
+ { command: "npm run typecheck", exitCode: 0, stdout: "", stderr: "", durationMs: 2340 },
185
+ { command: "npm run lint", exitCode: 1, stdout: "", stderr: "err", durationMs: 1100 },
188
186
  ],
189
187
  });
190
188
 
@@ -216,9 +214,9 @@ test("verification-evidence: formatEvidenceTable returns no-checks message for e
216
214
  test("verification-evidence: formatEvidenceTable formats duration as seconds with 1 decimal", () => {
217
215
  const result = makeResult({
218
216
  checks: [
219
- { command: "fast", exitCode: 0, stdout: "", stderr: "", durationMs: 150, blocking: true },
220
- { command: "slow", exitCode: 0, stdout: "", stderr: "", durationMs: 2340, blocking: true },
221
- { command: "zero", exitCode: 0, stdout: "", stderr: "", durationMs: 0, blocking: true },
217
+ { command: "fast", exitCode: 0, stdout: "", stderr: "", durationMs: 150 },
218
+ { command: "slow", exitCode: 0, stdout: "", stderr: "", durationMs: 2340 },
219
+ { command: "zero", exitCode: 0, stdout: "", stderr: "", durationMs: 0 },
222
220
  ],
223
221
  });
224
222
 
@@ -232,8 +230,8 @@ test("verification-evidence: formatEvidenceTable uses ✅/❌ emoji for pass/fai
232
230
  const result = makeResult({
233
231
  passed: false,
234
232
  checks: [
235
- { command: "pass-cmd", exitCode: 0, stdout: "", stderr: "", durationMs: 100, blocking: true },
236
- { command: "fail-cmd", exitCode: 1, stdout: "", stderr: "", durationMs: 200, blocking: true },
233
+ { command: "pass-cmd", exitCode: 0, stdout: "", stderr: "", durationMs: 100 },
234
+ { command: "fail-cmd", exitCode: 1, stdout: "", stderr: "", durationMs: 200 },
237
235
  ],
238
236
  });
239
237
 
@@ -337,8 +335,8 @@ test("verification-evidence: integration — VerificationResult → JSON → tab
337
335
  const result = makeResult({
338
336
  passed: false,
339
337
  checks: [
340
- { command: "npm run typecheck", exitCode: 0, stdout: "ok", stderr: "", durationMs: 1500, blocking: true },
341
- { command: "npm run test:unit", exitCode: 1, stdout: "", stderr: "1 failed", durationMs: 3200, blocking: true },
338
+ { command: "npm run typecheck", exitCode: 0, stdout: "ok", stderr: "", durationMs: 1500 },
339
+ { command: "npm run test:unit", exitCode: 1, stdout: "", stderr: "1 failed", durationMs: 3200 },
342
340
  ],
343
341
  discoverySource: "package-json",
344
342
  });
@@ -392,7 +390,7 @@ test("verification-evidence: writeVerificationJSON with retryAttempt and maxRetr
392
390
  const result = makeResult({
393
391
  passed: false,
394
392
  checks: [
395
- { command: "npm run lint", exitCode: 1, stdout: "", stderr: "error", durationMs: 300, blocking: true },
393
+ { command: "npm run lint", exitCode: 1, stdout: "", stderr: "error", durationMs: 300 },
396
394
  ],
397
395
  });
398
396
 
@@ -417,7 +415,7 @@ test("verification-evidence: writeVerificationJSON without retry params omits re
417
415
  const result = makeResult({
418
416
  passed: true,
419
417
  checks: [
420
- { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100, blocking: true },
418
+ { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100 },
421
419
  ],
422
420
  });
423
421
 
@@ -443,7 +441,7 @@ test("verification-evidence: writeVerificationJSON includes runtimeErrors when p
443
441
  const result = makeResult({
444
442
  passed: false,
445
443
  checks: [
446
- { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100, blocking: true },
444
+ { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100 },
447
445
  ],
448
446
  runtimeErrors: [
449
447
  { source: "bg-shell", severity: "crash", message: "Server crashed", blocking: true },
@@ -475,7 +473,7 @@ test("verification-evidence: writeVerificationJSON omits runtimeErrors when abse
475
473
  const result = makeResult({
476
474
  passed: true,
477
475
  checks: [
478
- { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 50, blocking: true },
476
+ { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 50 },
479
477
  ],
480
478
  });
481
479
 
@@ -514,7 +512,7 @@ test("verification-evidence: formatEvidenceTable appends runtime errors section"
514
512
  const result = makeResult({
515
513
  passed: false,
516
514
  checks: [
517
- { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100, blocking: true },
515
+ { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100 },
518
516
  ],
519
517
  runtimeErrors: [
520
518
  { source: "bg-shell", severity: "crash", message: "Server crashed with SIGKILL", blocking: true },
@@ -539,7 +537,7 @@ test("verification-evidence: formatEvidenceTable omits runtime errors section wh
539
537
  const result = makeResult({
540
538
  passed: true,
541
539
  checks: [
542
- { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 200, blocking: true },
540
+ { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 200 },
543
541
  ],
544
542
  });
545
543
 
@@ -554,7 +552,7 @@ test("verification-evidence: formatEvidenceTable truncates runtime error message
554
552
  const result = makeResult({
555
553
  passed: false,
556
554
  checks: [
557
- { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100, blocking: true },
555
+ { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100 },
558
556
  ],
559
557
  runtimeErrors: [
560
558
  { source: "bg-shell", severity: "error", message: longMessage, blocking: false },
@@ -600,7 +598,7 @@ test("verification-evidence: writeVerificationJSON includes auditWarnings when p
600
598
  const result = makeResult({
601
599
  passed: true,
602
600
  checks: [
603
- { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100, blocking: true },
601
+ { command: "npm run test", exitCode: 0, stdout: "ok", stderr: "", durationMs: 100 },
604
602
  ],
605
603
  auditWarnings: SAMPLE_AUDIT_WARNINGS,
606
604
  });
@@ -629,7 +627,7 @@ test("verification-evidence: writeVerificationJSON omits auditWarnings when abse
629
627
  const result = makeResult({
630
628
  passed: true,
631
629
  checks: [
632
- { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 50, blocking: true },
630
+ { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 50 },
633
631
  ],
634
632
  });
635
633
 
@@ -668,7 +666,7 @@ test("verification-evidence: formatEvidenceTable appends audit warnings section"
668
666
  const result = makeResult({
669
667
  passed: true,
670
668
  checks: [
671
- { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100, blocking: true },
669
+ { command: "npm run test", exitCode: 0, stdout: "", stderr: "", durationMs: 100 },
672
670
  ],
673
671
  auditWarnings: SAMPLE_AUDIT_WARNINGS,
674
672
  });
@@ -691,7 +689,7 @@ test("verification-evidence: formatEvidenceTable omits audit warnings section wh
691
689
  const result = makeResult({
692
690
  passed: true,
693
691
  checks: [
694
- { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 200, blocking: true },
692
+ { command: "npm run lint", exitCode: 0, stdout: "", stderr: "", durationMs: 200 },
695
693
  ],
696
694
  });
697
695
 
@@ -707,7 +705,7 @@ test("verification-evidence: integration — VerificationResult with auditWarnin
707
705
  const result = makeResult({
708
706
  passed: true,
709
707
  checks: [
710
- { command: "npm run typecheck", exitCode: 0, stdout: "ok", stderr: "", durationMs: 1500, blocking: true },
708
+ { command: "npm run typecheck", exitCode: 0, stdout: "ok", stderr: "", durationMs: 1500 },
711
709
  ],
712
710
  auditWarnings: [
713
711
  {