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.
- package/dist/bundled-resource-path.d.ts +8 -0
- package/dist/bundled-resource-path.js +14 -0
- package/dist/headless-query.js +6 -6
- package/dist/resources/extensions/gsd/auto/session.js +27 -32
- package/dist/resources/extensions/gsd/auto-dashboard.js +29 -109
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +6 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +52 -81
- package/dist/resources/extensions/gsd/auto-loop.js +956 -0
- package/dist/resources/extensions/gsd/auto-observability.js +4 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +75 -185
- package/dist/resources/extensions/gsd/auto-prompts.js +133 -101
- package/dist/resources/extensions/gsd/auto-recovery.js +59 -97
- package/dist/resources/extensions/gsd/auto-start.js +330 -309
- package/dist/resources/extensions/gsd/auto-supervisor.js +5 -11
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +7 -7
- package/dist/resources/extensions/gsd/auto-timers.js +3 -4
- package/dist/resources/extensions/gsd/auto-verification.js +35 -73
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +167 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +291 -126
- package/dist/resources/extensions/gsd/auto.js +283 -1013
- package/dist/resources/extensions/gsd/captures.js +10 -4
- package/dist/resources/extensions/gsd/dispatch-guard.js +7 -8
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/dist/resources/extensions/gsd/doctor-checks.js +3 -4
- package/dist/resources/extensions/gsd/git-service.js +1 -1
- package/dist/resources/extensions/gsd/gsd-db.js +296 -151
- package/dist/resources/extensions/gsd/index.js +92 -228
- package/dist/resources/extensions/gsd/post-unit-hooks.js +13 -13
- package/dist/resources/extensions/gsd/progress-score.js +61 -156
- package/dist/resources/extensions/gsd/quick.js +98 -122
- package/dist/resources/extensions/gsd/session-lock.js +13 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +1 -0
- package/dist/resources/extensions/gsd/undo.js +43 -48
- package/dist/resources/extensions/gsd/unit-runtime.js +16 -15
- package/dist/resources/extensions/gsd/verification-evidence.js +0 -1
- package/dist/resources/extensions/gsd/verification-gate.js +6 -35
- package/dist/resources/extensions/gsd/worktree-command.js +30 -24
- package/dist/resources/extensions/gsd/worktree-manager.js +2 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +344 -0
- package/dist/resources/extensions/gsd/worktree.js +7 -44
- package/dist/tool-bootstrap.js +59 -11
- package/dist/worktree-cli.js +7 -7
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +3630 -5483
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +735 -2588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/src/models.generated.ts +1039 -2892
- package/packages/pi-coding-agent/package.json +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/session.ts +47 -30
- package/src/resources/extensions/gsd/auto-dashboard.ts +28 -131
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +6 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +135 -91
- package/src/resources/extensions/gsd/auto-loop.ts +1665 -0
- package/src/resources/extensions/gsd/auto-observability.ts +4 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +85 -228
- package/src/resources/extensions/gsd/auto-prompts.ts +138 -109
- package/src/resources/extensions/gsd/auto-recovery.ts +124 -118
- package/src/resources/extensions/gsd/auto-start.ts +440 -354
- package/src/resources/extensions/gsd/auto-supervisor.ts +5 -12
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +8 -8
- package/src/resources/extensions/gsd/auto-timers.ts +3 -4
- package/src/resources/extensions/gsd/auto-verification.ts +76 -90
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +204 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +389 -141
- package/src/resources/extensions/gsd/auto.ts +515 -1199
- package/src/resources/extensions/gsd/captures.ts +10 -4
- package/src/resources/extensions/gsd/dispatch-guard.ts +13 -9
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -18
- package/src/resources/extensions/gsd/doctor-checks.ts +3 -4
- package/src/resources/extensions/gsd/git-service.ts +8 -1
- package/src/resources/extensions/gsd/gitignore.ts +4 -2
- package/src/resources/extensions/gsd/gsd-db.ts +375 -180
- package/src/resources/extensions/gsd/index.ts +104 -263
- package/src/resources/extensions/gsd/post-unit-hooks.ts +13 -13
- package/src/resources/extensions/gsd/progress-score.ts +65 -200
- package/src/resources/extensions/gsd/quick.ts +121 -125
- package/src/resources/extensions/gsd/session-lock.ts +11 -0
- package/src/resources/extensions/gsd/templates/preferences.md +1 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +32 -59
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +75 -27
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1458 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +8 -162
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -108
- package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +0 -55
- package/src/resources/extensions/gsd/tests/headless-query.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +8 -11
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/undo.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +24 -26
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +7 -201
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +442 -0
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +705 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +57 -106
- package/src/resources/extensions/gsd/tests/worktree.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +43 -132
- package/src/resources/extensions/gsd/types.ts +90 -81
- package/src/resources/extensions/gsd/undo.ts +42 -46
- package/src/resources/extensions/gsd/unit-runtime.ts +14 -18
- package/src/resources/extensions/gsd/verification-evidence.ts +1 -3
- package/src/resources/extensions/gsd/verification-gate.ts +6 -39
- package/src/resources/extensions/gsd/worktree-command.ts +36 -24
- package/src/resources/extensions/gsd/worktree-manager.ts +2 -3
- package/src/resources/extensions/gsd/worktree-resolver.ts +485 -0
- package/src/resources/extensions/gsd/worktree.ts +7 -44
- package/dist/resources/extensions/gsd/auto-constants.js +0 -5
- package/dist/resources/extensions/gsd/auto-idempotency.js +0 -106
- package/dist/resources/extensions/gsd/auto-stuck-detection.js +0 -165
- package/dist/resources/extensions/gsd/mechanical-completion.js +0 -351
- package/src/resources/extensions/gsd/auto-constants.ts +0 -6
- package/src/resources/extensions/gsd/auto-idempotency.ts +0 -151
- package/src/resources/extensions/gsd/auto-stuck-detection.ts +0 -221
- package/src/resources/extensions/gsd/mechanical-completion.ts +0 -430
- package/src/resources/extensions/gsd/tests/auto-dispatch-loop.test.ts +0 -691
- package/src/resources/extensions/gsd/tests/auto-reentrancy-guard.test.ts +0 -127
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +0 -123
- package/src/resources/extensions/gsd/tests/dispatch-stall-guard.test.ts +0 -126
- package/src/resources/extensions/gsd/tests/loop-regression.test.ts +0 -874
- package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +0 -356
- package/src/resources/extensions/gsd/tests/progress-score.test.ts +0 -206
- 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.
|
|
40
|
-
assert.
|
|
41
|
-
assert.
|
|
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.
|
|
47
|
-
assert.
|
|
48
|
-
assert.
|
|
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
|
|
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 "
|
|
118
|
-
"triage dispatch should return '
|
|
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
|
|
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 "
|
|
319
|
-
"quick-task dispatch should return '
|
|
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
|
|
110
|
-
{ command: "test", exitCode: 1, stdout: "", stderr: "fail", durationMs: 200
|
|
111
|
-
{ command: "audit", exitCode: 2, stdout: "", stderr: "err", durationMs: 300
|
|
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
|
|
187
|
-
{ command: "npm run lint", exitCode: 1, stdout: "", stderr: "err", durationMs: 1100
|
|
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
|
|
220
|
-
{ command: "slow", exitCode: 0, stdout: "", stderr: "", durationMs: 2340
|
|
221
|
-
{ command: "zero", exitCode: 0, stdout: "", stderr: "", durationMs: 0
|
|
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
|
|
236
|
-
{ command: "fail-cmd", exitCode: 1, stdout: "", stderr: "", durationMs: 200
|
|
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
|
|
341
|
-
{ command: "npm run test:unit", exitCode: 1, stdout: "", stderr: "1 failed", durationMs: 3200
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
708
|
+
{ command: "npm run typecheck", exitCode: 0, stdout: "ok", stderr: "", durationMs: 1500 },
|
|
711
709
|
],
|
|
712
710
|
auditWarnings: [
|
|
713
711
|
{
|