gsd-pi 2.80.0-dev.0aaa4fc17 → 2.80.0-dev.1486c1899
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/README.md +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/phases.js +22 -15
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto.js +52 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +21 -2
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +27 -20
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +21 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/guided-flow.js +19 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +11 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +13 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +8 -0
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +3 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +7 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/phases.ts +28 -20
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +18 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +17 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto.ts +60 -3
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +27 -19
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/guided-flow.ts +32 -4
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +234 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +11 -0
- /package/dist/web/standalone/.next/static/{YRK7-Es93MwpIn3VL35K0 → O-2rnxSJki_W-2fkK3zIj}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{YRK7-Es93MwpIn3VL35K0 → O-2rnxSJki_W-2fkK3zIj}/_ssgManifest.js +0 -0
|
@@ -21,12 +21,18 @@ import type {
|
|
|
21
21
|
ComputedArtifactRegistry,
|
|
22
22
|
UnitContextManifest,
|
|
23
23
|
} from "../unit-context-manifest.ts";
|
|
24
|
-
import { UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
-
import {
|
|
24
|
+
import { KNOWN_UNIT_TYPES, UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
+
import {
|
|
26
|
+
buildExecuteTaskPrompt,
|
|
27
|
+
buildGateEvaluatePrompt,
|
|
28
|
+
buildReassessRoadmapPrompt,
|
|
29
|
+
buildWorkflowPreferencesPrompt,
|
|
30
|
+
} from "../auto-prompts.ts";
|
|
26
31
|
import { invalidateAllCaches } from "../cache.ts";
|
|
27
32
|
import {
|
|
28
33
|
openDatabase,
|
|
29
34
|
closeDatabase,
|
|
35
|
+
insertGateRow,
|
|
30
36
|
insertMilestone,
|
|
31
37
|
upsertMilestonePlanning,
|
|
32
38
|
insertSlice,
|
|
@@ -121,7 +127,7 @@ test("Context Mode composer: standalone output starts with heading and includes
|
|
|
121
127
|
assert.ok(out.startsWith("## Context Mode"));
|
|
122
128
|
assert.match(out, /execution lane/i);
|
|
123
129
|
assert.match(out, /`gsd_exec`/);
|
|
124
|
-
assert.match(out, /
|
|
130
|
+
assert.match(out, /builds, tests, and diagnostics/);
|
|
125
131
|
assert.match(out, /`gsd_exec_search`/);
|
|
126
132
|
assert.match(out, /before reruns/);
|
|
127
133
|
assert.match(out, /`gsd_resume`/);
|
|
@@ -136,7 +142,45 @@ test("Context Mode composer: nested output is compact single sentence", () => {
|
|
|
136
142
|
assert.match(out, /`gsd_exec`/);
|
|
137
143
|
assert.match(out, /`gsd_exec_search`/);
|
|
138
144
|
assert.match(out, /`gsd_resume`/);
|
|
139
|
-
assert.ok(out.length <
|
|
145
|
+
assert.ok(out.length < 240, `nested guidance should stay compact, got ${out.length} chars`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const laneLabelByMode: Record<string, string> = {
|
|
149
|
+
interview: "interview",
|
|
150
|
+
research: "research",
|
|
151
|
+
planning: "planning",
|
|
152
|
+
execution: "execution",
|
|
153
|
+
verification: "verification",
|
|
154
|
+
orchestration: "orchestration",
|
|
155
|
+
docs: "documentation",
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
test("Context Mode composer: every known eligible unit renders its configured lane and required tools", () => {
|
|
159
|
+
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
160
|
+
const manifest = UNIT_MANIFESTS[unitType];
|
|
161
|
+
assert.ok(manifest, `missing manifest for ${unitType}`);
|
|
162
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode: "standalone" });
|
|
163
|
+
if (manifest.contextMode === "none") {
|
|
164
|
+
assert.strictEqual(out, "", `${unitType} should not render Context Mode`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
168
|
+
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
169
|
+
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
170
|
+
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
171
|
+
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("Context Mode composer: workflow-preferences and research-decision render no Context Mode block", () => {
|
|
176
|
+
assert.strictEqual(
|
|
177
|
+
composeContextModeInstructions("workflow-preferences", { enabled: true, renderMode: "standalone" }),
|
|
178
|
+
"",
|
|
179
|
+
);
|
|
180
|
+
assert.strictEqual(
|
|
181
|
+
composeContextModeInstructions("research-decision", { enabled: true, renderMode: "standalone" }),
|
|
182
|
+
"",
|
|
183
|
+
);
|
|
140
184
|
});
|
|
141
185
|
|
|
142
186
|
// ─── Integration: migrated buildReassessRoadmapPrompt ─────────────────────
|
|
@@ -220,6 +264,94 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
|
|
|
220
264
|
assert.ok(!prompt.includes("Slice Context (from discussion)"));
|
|
221
265
|
});
|
|
222
266
|
|
|
267
|
+
test("Context Mode resume injection: eligible prompts include one bounded snapshot block above inlined context", async (t) => {
|
|
268
|
+
const base = makeFixtureBase();
|
|
269
|
+
t.after(() => cleanup(base));
|
|
270
|
+
invalidateAllCaches();
|
|
271
|
+
|
|
272
|
+
seed(base, "M001");
|
|
273
|
+
writeArtifacts(base);
|
|
274
|
+
writeFileSync(
|
|
275
|
+
join(base, ".gsd", "last-snapshot.md"),
|
|
276
|
+
"# GSD context snapshot\n\nResume evidence.\n",
|
|
277
|
+
"utf-8",
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
281
|
+
|
|
282
|
+
assert.equal(prompt.match(/## Context Snapshot/g)?.length, 1);
|
|
283
|
+
assert.match(prompt, /Source: `\.gsd\/last-snapshot\.md`/);
|
|
284
|
+
assert.match(prompt, /Resume evidence/);
|
|
285
|
+
assert.ok(prompt.indexOf("## Context Mode") < prompt.indexOf("## Context Snapshot"));
|
|
286
|
+
assert.ok(prompt.indexOf("## Context Snapshot") < prompt.indexOf("## Inlined Context"));
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("Context Mode resume injection: missing snapshot does not add an empty block", async (t) => {
|
|
290
|
+
const base = makeFixtureBase();
|
|
291
|
+
t.after(() => cleanup(base));
|
|
292
|
+
invalidateAllCaches();
|
|
293
|
+
|
|
294
|
+
seed(base, "M001");
|
|
295
|
+
writeArtifacts(base);
|
|
296
|
+
|
|
297
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
298
|
+
|
|
299
|
+
assert.match(prompt, /## Context Mode/);
|
|
300
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("Context Mode resume injection: disabled mode suppresses guidance and snapshot reads", async (t) => {
|
|
304
|
+
const base = makeFixtureBase();
|
|
305
|
+
t.after(() => cleanup(base));
|
|
306
|
+
invalidateAllCaches();
|
|
307
|
+
|
|
308
|
+
seed(base, "M001");
|
|
309
|
+
writeArtifacts(base);
|
|
310
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
311
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
312
|
+
|
|
313
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
314
|
+
|
|
315
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
316
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
317
|
+
assert.doesNotMatch(prompt, /Do not inject/);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("Context Mode resume injection: none-mode units do not inject snapshots", async () => {
|
|
321
|
+
const base = makeFixtureBase();
|
|
322
|
+
try {
|
|
323
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nNo lane.\n", "utf-8");
|
|
324
|
+
const prompt = await buildWorkflowPreferencesPrompt(base);
|
|
325
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
326
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
327
|
+
assert.doesNotMatch(prompt, /No lane/);
|
|
328
|
+
} finally {
|
|
329
|
+
cleanup(base);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("Context Mode prompt suppression: disabled inlined, phase-anchor, and nested prompts omit Context Mode", async (t) => {
|
|
334
|
+
const base = makeFixtureBase();
|
|
335
|
+
t.after(() => cleanup(base));
|
|
336
|
+
invalidateAllCaches();
|
|
337
|
+
|
|
338
|
+
seed(base, "M001");
|
|
339
|
+
writeArtifacts(base);
|
|
340
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
341
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
342
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
343
|
+
|
|
344
|
+
const inlinedPrompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
345
|
+
assert.doesNotMatch(inlinedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
346
|
+
|
|
347
|
+
const phaseAnchorPrompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
348
|
+
assert.doesNotMatch(phaseAnchorPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
349
|
+
|
|
350
|
+
const nestedPrompt = await buildGateEvaluatePrompt("M001", "Test", "S01", "First", base);
|
|
351
|
+
assert.match(nestedPrompt, /Use this as the prompt for a `subagent` call/);
|
|
352
|
+
assert.doesNotMatch(nestedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
353
|
+
});
|
|
354
|
+
|
|
223
355
|
// ─── v2 surface (#4924) ───────────────────────────────────────────────────
|
|
224
356
|
|
|
225
357
|
const fakeBase: BaseResolverContext = {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
markFailed,
|
|
22
22
|
markStuck,
|
|
23
23
|
markCanceled,
|
|
24
|
+
markLatestActiveForWorkerCanceled,
|
|
24
25
|
getRecentForUnit,
|
|
25
26
|
getLatestForUnit,
|
|
26
27
|
} from "../db/unit-dispatches.ts";
|
|
@@ -196,6 +197,35 @@ test("markStuck and markCanceled set their respective statuses", (t) => {
|
|
|
196
197
|
assert.equal(getLatestForUnit("M001/S01/T01")!.status, "canceled");
|
|
197
198
|
});
|
|
198
199
|
|
|
200
|
+
test("markLatestActiveForWorkerCanceled cancels only the latest active dispatch for a worker", (t) => {
|
|
201
|
+
const base = makeBase();
|
|
202
|
+
t.after(() => cleanup(base));
|
|
203
|
+
const { workerId, leaseToken } = setup(base);
|
|
204
|
+
|
|
205
|
+
const first = recordDispatchClaim({
|
|
206
|
+
traceId: "tc-1", workerId, milestoneLeaseToken: leaseToken,
|
|
207
|
+
milestoneId: "M001", unitType: "plan-slice", unitId: "M001/S01",
|
|
208
|
+
});
|
|
209
|
+
assert.equal(first.ok, true);
|
|
210
|
+
if (!first.ok) return;
|
|
211
|
+
markCompleted(first.dispatchId);
|
|
212
|
+
|
|
213
|
+
const second = recordDispatchClaim({
|
|
214
|
+
traceId: "tc-2", workerId, milestoneLeaseToken: leaseToken,
|
|
215
|
+
milestoneId: "M001", unitType: "run-task", unitId: "M001/S01/T01",
|
|
216
|
+
});
|
|
217
|
+
assert.equal(second.ok, true);
|
|
218
|
+
if (!second.ok) return;
|
|
219
|
+
markRunning(second.dispatchId);
|
|
220
|
+
|
|
221
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), true);
|
|
222
|
+
assert.equal(getLatestForUnit("M001/S01")!.status, "completed");
|
|
223
|
+
const latest = getLatestForUnit("M001/S01/T01")!;
|
|
224
|
+
assert.equal(latest.status, "canceled");
|
|
225
|
+
assert.equal(latest.exit_reason, "signal-exit");
|
|
226
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), false);
|
|
227
|
+
});
|
|
228
|
+
|
|
199
229
|
test("terminal transitions do not overwrite an already terminal dispatch", (t) => {
|
|
200
230
|
const base = makeBase();
|
|
201
231
|
t.after(() => cleanup(base));
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
readUnitRuntimeRecord,
|
|
10
10
|
writeUnitRuntimeRecord,
|
|
11
11
|
} from "../unit-runtime.ts";
|
|
12
|
+
import { closeDatabase, insertMilestone, insertSlice, insertTask, openDatabase } from "../gsd-db.ts";
|
|
12
13
|
import { clearPathCache } from '../paths.ts';
|
|
13
14
|
import { test } from 'node:test';
|
|
14
15
|
import assert from 'node:assert/strict';
|
|
@@ -72,6 +73,35 @@ console.log("\n=== runtime record cleanup ===");
|
|
|
72
73
|
assert.deepStrictEqual(loaded, null, "record removed");
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
console.log("\n=== execute-task durability trusts closed DB task status ===");
|
|
77
|
+
{
|
|
78
|
+
const dbBase = mkdtempSync(join(tmpdir(), "gsd-unit-runtime-db-test-"));
|
|
79
|
+
mkdirSync(join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "tasks"), { recursive: true });
|
|
80
|
+
try {
|
|
81
|
+
openDatabase(join(dbBase, ".gsd", "gsd.db"));
|
|
82
|
+
insertMilestone({ id: "M300", title: "DB Milestone", status: "active" });
|
|
83
|
+
insertSlice({ id: "S01", milestoneId: "M300", title: "DB Slice", status: "in_progress" });
|
|
84
|
+
insertTask({ id: "T01", milestoneId: "M300", sliceId: "S01", title: "DB Task", status: "complete" });
|
|
85
|
+
writeFileSync(
|
|
86
|
+
join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "S01-PLAN.md"),
|
|
87
|
+
"# S01\n\n## Tasks\n\n- [ ] **T01: DB Task** `est:10m`\n",
|
|
88
|
+
"utf-8",
|
|
89
|
+
);
|
|
90
|
+
writeFileSync(join(dbBase, ".gsd", "STATE.md"), "## Next Action\nExecute T01 for S01: DB task\n", "utf-8");
|
|
91
|
+
|
|
92
|
+
const status = await inspectExecuteTaskDurability(dbBase, "M300/S01/T01");
|
|
93
|
+
assert.ok(status !== null, "db-complete: status exists");
|
|
94
|
+
assert.equal(status!.dbComplete, true, "db-complete: closed DB status is captured");
|
|
95
|
+
assert.equal(status!.summaryExists, false, "db-complete: summary can still be missing");
|
|
96
|
+
assert.equal(status!.taskChecked, false, "db-complete: checkbox can still be unchecked");
|
|
97
|
+
assert.equal(status!.nextActionAdvanced, false, "db-complete: next action can still point at task");
|
|
98
|
+
assert.equal(formatExecuteTaskRecoveryStatus(status!), "DB task status is closed");
|
|
99
|
+
} finally {
|
|
100
|
+
closeDatabase();
|
|
101
|
+
rmSync(dbBase, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
75
105
|
console.log("\n=== hook unit type sanitization (slash in unitType) ===");
|
|
76
106
|
{
|
|
77
107
|
// Hook units have unitType like "hook/code-review" with a slash
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Shared Context Mode tool result helpers.
|
|
3
|
+
|
|
4
|
+
export interface ToolExecutionResult {
|
|
5
|
+
content: Array<{ type: "text"; text: string }>;
|
|
6
|
+
details: Record<string, unknown>;
|
|
7
|
+
isError?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type ContextModeToolName = "gsd_exec" | "gsd_exec_search" | "gsd_resume";
|
|
11
|
+
|
|
12
|
+
export function contextModeDisabledResult(operation: ContextModeToolName): ToolExecutionResult {
|
|
13
|
+
return {
|
|
14
|
+
content: [
|
|
15
|
+
{
|
|
16
|
+
type: "text",
|
|
17
|
+
text:
|
|
18
|
+
`${operation} is disabled by \`context_mode.enabled: false\` in preferences. ` +
|
|
19
|
+
"Remove that override or set it to true to re-enable Context Mode tools.",
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
details: { operation, error: "context_mode_disabled" },
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// re-discover past runs without re-executing. Read-only; no DB writes.
|
|
5
5
|
|
|
6
6
|
import { searchExecHistory, type ExecSearchOptions } from "../exec-history.js";
|
|
7
|
+
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
8
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
7
9
|
|
|
8
10
|
export interface ExecSearchToolParams {
|
|
9
11
|
query?: string;
|
|
@@ -12,16 +14,14 @@ export interface ExecSearchToolParams {
|
|
|
12
14
|
limit?: number;
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
export interface ToolExecutionResult {
|
|
16
|
-
content: Array<{ type: "text"; text: string }>;
|
|
17
|
-
details: Record<string, unknown>;
|
|
18
|
-
isError?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
17
|
export function executeExecSearch(
|
|
22
18
|
params: ExecSearchToolParams,
|
|
23
|
-
opts: { baseDir: string },
|
|
19
|
+
opts: { baseDir: string; preferences?: { context_mode?: ContextModeConfig } | null },
|
|
24
20
|
): ToolExecutionResult {
|
|
21
|
+
if (!isContextModeEnabled(opts.preferences)) {
|
|
22
|
+
return contextModeDisabledResult("gsd_exec_search");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
25
|
const searchOpts: ExecSearchOptions = {
|
|
26
26
|
query: typeof params.query === "string" ? params.query : undefined,
|
|
27
27
|
runtime: params.runtime,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type ExecSandboxResult,
|
|
13
13
|
} from "../exec-sandbox.js";
|
|
14
14
|
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
15
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
15
16
|
|
|
16
17
|
export interface ExecToolParams {
|
|
17
18
|
runtime: ExecSandboxRequest["runtime"];
|
|
@@ -20,17 +21,12 @@ export interface ExecToolParams {
|
|
|
20
21
|
timeout_ms?: number;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
export interface ToolExecutionResult {
|
|
24
|
-
content: Array<{ type: "text"; text: string }>;
|
|
25
|
-
details: Record<string, unknown>;
|
|
26
|
-
isError?: boolean;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
export interface ExecToolDeps {
|
|
30
25
|
baseDir: string;
|
|
31
26
|
preferences: { context_mode?: ContextModeConfig } | null;
|
|
32
27
|
/** Optional override for testing. */
|
|
33
28
|
run?: (req: ExecSandboxRequest, opts: ExecSandboxOptions) => Promise<ExecSandboxResult>;
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
34
30
|
now?: () => Date;
|
|
35
31
|
generateId?: () => string;
|
|
36
32
|
}
|
|
@@ -77,21 +73,6 @@ function isEnabled(prefs: ExecToolDeps["preferences"]): boolean {
|
|
|
77
73
|
return isContextModeEnabled(prefs);
|
|
78
74
|
}
|
|
79
75
|
|
|
80
|
-
function disabledResult(): ToolExecutionResult {
|
|
81
|
-
return {
|
|
82
|
-
content: [
|
|
83
|
-
{
|
|
84
|
-
type: "text",
|
|
85
|
-
text:
|
|
86
|
-
"gsd_exec is disabled by `context_mode.enabled: false` in preferences. Remove that " +
|
|
87
|
-
"override (or set it to true) to re-enable sandboxed tool-output execution.",
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
details: { operation: "gsd_exec", error: "context_mode_disabled" },
|
|
91
|
-
isError: true,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
76
|
function paramError(message: string): ToolExecutionResult {
|
|
96
77
|
return {
|
|
97
78
|
content: [{ type: "text", text: `Error: ${message}` }],
|
|
@@ -104,7 +85,7 @@ export async function executeGsdExec(
|
|
|
104
85
|
params: ExecToolParams,
|
|
105
86
|
deps: ExecToolDeps,
|
|
106
87
|
): Promise<ToolExecutionResult> {
|
|
107
|
-
if (!isEnabled(deps.preferences)) return
|
|
88
|
+
if (!isEnabled(deps.preferences)) return contextModeDisabledResult("gsd_exec");
|
|
108
89
|
|
|
109
90
|
const runtime = params.runtime;
|
|
110
91
|
if (runtime !== "bash" && runtime !== "node" && runtime !== "python") {
|
|
@@ -121,7 +102,7 @@ export async function executeGsdExec(
|
|
|
121
102
|
const opts = buildExecOptions(
|
|
122
103
|
deps.baseDir,
|
|
123
104
|
deps.preferences?.context_mode,
|
|
124
|
-
{ now: deps.now, generateId: deps.generateId },
|
|
105
|
+
{ env: deps.env, now: deps.now, generateId: deps.generateId },
|
|
125
106
|
);
|
|
126
107
|
const run = deps.run ?? runExecSandbox;
|
|
127
108
|
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
// re-deriving project memory state.
|
|
4
4
|
|
|
5
5
|
import { readCompactionSnapshot } from "../compaction-snapshot.js";
|
|
6
|
+
import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
|
|
7
|
+
import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
|
|
6
8
|
|
|
7
9
|
export interface ResumeToolParams {
|
|
8
10
|
/** Ignored — reserved for future variant (e.g. dated snapshots). */
|
|
9
11
|
_variant?: string;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
export interface ToolExecutionResult {
|
|
13
|
-
content: Array<{ type: "text"; text: string }>;
|
|
14
|
-
details: Record<string, unknown>;
|
|
15
|
-
isError?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
export function executeResume(
|
|
19
15
|
_params: ResumeToolParams,
|
|
20
|
-
opts: { baseDir: string },
|
|
16
|
+
opts: { baseDir: string; preferences?: { context_mode?: ContextModeConfig } | null },
|
|
21
17
|
): ToolExecutionResult {
|
|
18
|
+
if (!isContextModeEnabled(opts.preferences)) {
|
|
19
|
+
return contextModeDisabledResult("gsd_resume");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
22
|
const snapshot = readCompactionSnapshot(opts.baseDir);
|
|
23
23
|
if (snapshot == null) {
|
|
24
24
|
return {
|
|
@@ -112,8 +112,22 @@ const CONTEXT_MODE_LANE_LABELS: Record<Exclude<ContextModePolicy, "none">, strin
|
|
|
112
112
|
docs: "documentation",
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
const
|
|
116
|
-
|
|
115
|
+
const CONTEXT_MODE_GUIDANCE_BY_LANE: Record<Exclude<ContextModePolicy, "none">, string> = {
|
|
116
|
+
interview:
|
|
117
|
+
"Use `gsd_resume` to restore prior discussion, `gsd_exec` for noisy discovery, and `gsd_exec_search` before repeating scans.",
|
|
118
|
+
research:
|
|
119
|
+
"Use `gsd_exec` for noisy research scans, `gsd_exec_search` before reruns, and `gsd_resume` to restore prior findings.",
|
|
120
|
+
planning:
|
|
121
|
+
"Use `gsd_resume` for planning continuity, `gsd_exec` for noisy checks, and `gsd_exec_search` before rerunning diagnostics.",
|
|
122
|
+
execution:
|
|
123
|
+
"Use `gsd_exec` for builds, tests, and diagnostics, `gsd_exec_search` before reruns, and `gsd_resume` after compaction or resume.",
|
|
124
|
+
verification:
|
|
125
|
+
"Use `gsd_exec` for verification commands, `gsd_exec_search` to reuse prior evidence, and `gsd_resume` after compaction or resume.",
|
|
126
|
+
orchestration:
|
|
127
|
+
"Use `gsd_resume` before resuming orchestration, `gsd_exec_search` to reuse prior runs, and `gsd_exec` for noisy coordination checks.",
|
|
128
|
+
docs:
|
|
129
|
+
"Use `gsd_resume` for prior context, `gsd_exec_search` for saved evidence, and `gsd_exec` for noisy doc validation commands.",
|
|
130
|
+
};
|
|
117
131
|
|
|
118
132
|
/**
|
|
119
133
|
* Render the Context Mode instruction lane for a unit type. Unknown unit
|
|
@@ -129,15 +143,16 @@ export function composeContextModeInstructions(
|
|
|
129
143
|
if (!manifest || manifest.contextMode === "none") return "";
|
|
130
144
|
|
|
131
145
|
const lane = CONTEXT_MODE_LANE_LABELS[manifest.contextMode];
|
|
146
|
+
const guidance = CONTEXT_MODE_GUIDANCE_BY_LANE[manifest.contextMode];
|
|
132
147
|
if (opts.renderMode === "nested") {
|
|
133
|
-
return `Context Mode (${lane} lane): ${
|
|
148
|
+
return `Context Mode (${lane} lane): ${guidance}`;
|
|
134
149
|
}
|
|
135
150
|
|
|
136
151
|
return [
|
|
137
152
|
"## Context Mode",
|
|
138
153
|
"",
|
|
139
154
|
`Lane: **${lane} lane**.`,
|
|
140
|
-
|
|
155
|
+
guidance,
|
|
141
156
|
].join("\n");
|
|
142
157
|
}
|
|
143
158
|
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "./paths.js";
|
|
11
11
|
import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
|
|
12
12
|
import { parseUnitId } from "./unit-id.js";
|
|
13
|
+
import { getTask, isDbAvailable, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
|
|
14
|
+
import { isClosedStatus } from "./status-guards.js";
|
|
13
15
|
|
|
14
16
|
// Per-record advisory lock — prevents read-modify-write races between
|
|
15
17
|
// concurrent writers updating disjoint fields of the same runtime record.
|
|
@@ -92,6 +94,7 @@ export interface ExecuteTaskRecoveryStatus {
|
|
|
92
94
|
summaryExists: boolean;
|
|
93
95
|
taskChecked: boolean;
|
|
94
96
|
nextActionAdvanced: boolean;
|
|
97
|
+
dbComplete: boolean;
|
|
95
98
|
mustHaveCount: number;
|
|
96
99
|
mustHavesMentionedInSummary: number;
|
|
97
100
|
}
|
|
@@ -213,6 +216,12 @@ export async function inspectExecuteTaskDurability(
|
|
|
213
216
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
214
217
|
const taskChecked = !!planContent && new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m").test(planContent);
|
|
215
218
|
const nextActionAdvanced = !new RegExp(`Execute ${tid}\\b`).test(stateContent);
|
|
219
|
+
let dbComplete = false;
|
|
220
|
+
if (isDbAvailable()) {
|
|
221
|
+
refreshOpenDatabaseFromDisk();
|
|
222
|
+
const task = getTask(mid, sid, tid);
|
|
223
|
+
dbComplete = !!task && isClosedStatus(task.status);
|
|
224
|
+
}
|
|
216
225
|
|
|
217
226
|
// Must-have coverage: load task plan and count mentions in summary
|
|
218
227
|
let mustHaveCount = 0;
|
|
@@ -239,12 +248,14 @@ export async function inspectExecuteTaskDurability(
|
|
|
239
248
|
summaryExists,
|
|
240
249
|
taskChecked,
|
|
241
250
|
nextActionAdvanced,
|
|
251
|
+
dbComplete,
|
|
242
252
|
mustHaveCount,
|
|
243
253
|
mustHavesMentionedInSummary,
|
|
244
254
|
};
|
|
245
255
|
}
|
|
246
256
|
|
|
247
257
|
export function formatExecuteTaskRecoveryStatus(status: ExecuteTaskRecoveryStatus): string {
|
|
258
|
+
if (status.dbComplete) return "DB task status is closed";
|
|
248
259
|
const missing = [] as string[];
|
|
249
260
|
if (!status.summaryExists) missing.push(`summary missing (${status.summaryPath})`);
|
|
250
261
|
if (!status.taskChecked) missing.push(`task checkbox unchecked in ${status.planPath}`);
|
|
File without changes
|
|
File without changes
|