gsd-pi 2.82.0-dev.725028083 → 2.82.0-dev.9d5798940
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 +3 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +3 -1
- package/dist/resources/extensions/claude-code-cli/partial-builder.js +2 -1
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
- package/dist/resources/extensions/gsd/auto-dispatch.js +13 -6
- package/dist/resources/extensions/gsd/auto-post-unit.js +232 -126
- package/dist/resources/extensions/gsd/auto-prompts.js +2 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +31 -1
- package/dist/resources/extensions/gsd/auto-start.js +7 -3
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto-worktree.js +96 -0
- package/dist/resources/extensions/gsd/auto.js +128 -52
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -1
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +16 -7
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -2
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +37 -0
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +2 -2
- package/dist/resources/extensions/gsd/export-html.js +27 -425
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/milestone-actions.js +11 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +8 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +6 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +32 -10
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +49 -9
- package/dist/resources/extensions/shared/html-shell.js +388 -0
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +124 -0
- package/dist/resources/extensions/visual-brief/prompts.js +140 -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 +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -7
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -7
- 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 +4 -5
- 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 +2 -5
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -7
- 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 +4 -7
- 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 +4 -5
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -5
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/chunks/4266.js +2 -0
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/dist/web/standalone/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/layout-8c10ec293ae0f1d5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-9a4db269f9ed63ad.js} +1 -1
- package/dist/web/standalone/.next/static/css/746ee28c929d1880.css +1 -0
- package/package.json +3 -3
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/mcp-server/README.md +13 -4
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +22 -0
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- 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 +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/src/resources/GSD-WORKFLOW.md +3 -1
- package/src/resources/extensions/claude-code-cli/partial-builder.ts +2 -1
- package/src/resources/extensions/claude-code-cli/tests/partial-builder.test.ts +19 -2
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
- package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
- package/src/resources/extensions/gsd/auto-dispatch.ts +14 -6
- package/src/resources/extensions/gsd/auto-post-unit.ts +265 -138
- package/src/resources/extensions/gsd/auto-prompts.ts +2 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -0
- package/src/resources/extensions/gsd/auto-start.ts +7 -3
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto-worktree.ts +104 -0
- package/src/resources/extensions/gsd/auto.ts +136 -51
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +16 -6
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +19 -3
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +40 -0
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +3 -3
- package/src/resources/extensions/gsd/export-html.ts +27 -427
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/milestone-actions.ts +10 -4
- package/src/resources/extensions/gsd/native-git-bridge.ts +8 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +8 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +15 -1
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +69 -1
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +57 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/export-html-enhancements.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +55 -1
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-unit-git-failure.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +46 -2
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/stuck-state-via-db.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +86 -7
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +64 -12
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +47 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +47 -11
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +54 -9
- package/src/resources/extensions/shared/html-shell.ts +412 -0
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +136 -0
- package/src/resources/extensions/visual-brief/prompts.ts +183 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +212 -0
- package/dist/web/standalone/.next/server/chunks/5822.js +0 -2
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- package/dist/web/standalone/.next/static/css/de70bee13400563f.css +0 -1
- package/dist/web/standalone/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/dist/web/standalone/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → BdZQhe8yKl6bdKLiXVEzh}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{KDRTXR-22LPCsa80X9dey → BdZQhe8yKl6bdKLiXVEzh}/_ssgManifest.js +0 -0
|
@@ -26,6 +26,7 @@ const PLANNING_DISPATCH_REVIEW: ToolsPolicy = {
|
|
|
26
26
|
};
|
|
27
27
|
const READ_ONLY: ToolsPolicy = { mode: 'read-only' };
|
|
28
28
|
const ALL: ToolsPolicy = { mode: 'all' };
|
|
29
|
+
const VERIFICATION: ToolsPolicy = { mode: 'verification' };
|
|
29
30
|
const DOCS: ToolsPolicy = {
|
|
30
31
|
mode: 'docs',
|
|
31
32
|
allowedPathGlobs: ['docs/**', 'README.md', 'README.*.md', 'CHANGELOG.md', '*.md'],
|
|
@@ -172,6 +173,22 @@ test('planning-dispatch: extracts subagent classes from single, parallel, and ch
|
|
|
172
173
|
extractSubagentAgentClasses({ chain: [{ agent: 'reviewer' }, { agent: 'security' }] }),
|
|
173
174
|
['reviewer', 'security'],
|
|
174
175
|
);
|
|
176
|
+
assert.deepEqual(
|
|
177
|
+
extractSubagentAgentClasses({
|
|
178
|
+
chain: [
|
|
179
|
+
{ agent: 'scout' },
|
|
180
|
+
{ parallel: [{ agent: 'reviewer' }, { agent: ' security ' }] },
|
|
181
|
+
],
|
|
182
|
+
}),
|
|
183
|
+
['scout', 'reviewer', 'security'],
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test('planning-dispatch: extracts subagent classes without recursing through cycles', () => {
|
|
188
|
+
const input: { agent: string; parallel?: unknown[] } = { agent: 'scout' };
|
|
189
|
+
input.parallel = [input, { agent: 'reviewer' }];
|
|
190
|
+
|
|
191
|
+
assert.deepEqual(extractSubagentAgentClasses(input), ['scout', 'reviewer']);
|
|
175
192
|
});
|
|
176
193
|
|
|
177
194
|
test('planning-dispatch: blocks subagent dispatch when agentClasses is undefined (stale caller shim)', () => {
|
|
@@ -315,6 +332,36 @@ test('all-mode: execute-task can dispatch subagents', () => {
|
|
|
315
332
|
assert.strictEqual(r.block, false);
|
|
316
333
|
});
|
|
317
334
|
|
|
335
|
+
// ─── verification mode: bash allowed, writes still scoped ─────────────────
|
|
336
|
+
|
|
337
|
+
test('verification-mode: run-uat can run build commands', () => {
|
|
338
|
+
const r = shouldBlockPlanningUnit('bash', 'npm run build 2>&1', BASE, 'run-uat', VERIFICATION);
|
|
339
|
+
assert.strictEqual(r.block, false);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test('verification-mode: run-uat blocks destructive bash (rm -rf)', () => {
|
|
343
|
+
const r = shouldBlockPlanningUnit('bash', 'rm -rf dist', BASE, 'run-uat', VERIFICATION);
|
|
344
|
+
assert.strictEqual(r.block, true);
|
|
345
|
+
assert.match(r.reason!, /bash is restricted to build\/test verification commands/);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
test('verification-mode: run-uat allows read-only investigative bash (git status)', () => {
|
|
349
|
+
const r = shouldBlockPlanningUnit('bash', 'git status', BASE, 'run-uat', VERIFICATION);
|
|
350
|
+
assert.strictEqual(r.block, false);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test('verification-mode: run-uat still blocks user source edits', () => {
|
|
354
|
+
const r = shouldBlockPlanningUnit('edit', join(BASE, 'src', 'main.ts'), BASE, 'run-uat', VERIFICATION);
|
|
355
|
+
assert.strictEqual(r.block, true);
|
|
356
|
+
assert.match(r.reason!, /tools-policy "verification"/);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test('verification-mode: run-uat still blocks subagent dispatch', () => {
|
|
360
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION);
|
|
361
|
+
assert.strictEqual(r.block, true);
|
|
362
|
+
assert.match(r.reason!, /subagent dispatch is not permitted/);
|
|
363
|
+
});
|
|
364
|
+
|
|
318
365
|
// ─── read-only mode ───────────────────────────────────────────────────────
|
|
319
366
|
|
|
320
367
|
test('read-only: blocks any edit even to .gsd/', () => {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
upsertTaskPlanning,
|
|
11
11
|
insertGateRow,
|
|
12
12
|
updateSliceStatus,
|
|
13
|
+
setSliceSketchFlag,
|
|
13
14
|
} from "../gsd-db.js";
|
|
14
15
|
import type { GateId } from "../types.js";
|
|
15
16
|
import { invalidateStateCache } from "../state.js";
|
|
@@ -184,6 +185,7 @@ export async function handlePlanSlice(
|
|
|
184
185
|
if (isDeferredStatus(parentSlice.status)) {
|
|
185
186
|
updateSliceStatus(params.milestoneId, params.sliceId, "pending");
|
|
186
187
|
}
|
|
188
|
+
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
187
189
|
|
|
188
190
|
upsertSlicePlanning(params.milestoneId, params.sliceId, {
|
|
189
191
|
goal: params.goal,
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Adapts shared GSD workflow handlers for MCP executor calls.
|
|
3
|
+
|
|
1
4
|
import { ensureDbOpen } from "../bootstrap/dynamic-tools.js";
|
|
2
5
|
import { sanitizeCompleteMilestoneParams } from "../bootstrap/sanitize-complete-milestone.js";
|
|
3
6
|
import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, shouldBlockRootArtifactSaveInSnapshot } from "../bootstrap/write-gate.js";
|
|
@@ -25,6 +28,12 @@ import type { PlanSliceParams } from "./plan-slice.js";
|
|
|
25
28
|
import { handlePlanSlice } from "./plan-slice.js";
|
|
26
29
|
import type { ReplanSliceParams } from "./replan-slice.js";
|
|
27
30
|
import { handleReplanSlice } from "./replan-slice.js";
|
|
31
|
+
import type { ReopenMilestoneParams } from "./reopen-milestone.js";
|
|
32
|
+
import { handleReopenMilestone } from "./reopen-milestone.js";
|
|
33
|
+
import type { ReopenSliceParams } from "./reopen-slice.js";
|
|
34
|
+
import { handleReopenSlice } from "./reopen-slice.js";
|
|
35
|
+
import type { ReopenTaskParams } from "./reopen-task.js";
|
|
36
|
+
import { handleReopenTask } from "./reopen-task.js";
|
|
28
37
|
import type { ReassessRoadmapParams } from "./reassess-roadmap.js";
|
|
29
38
|
import { handleReassessRoadmap } from "./reassess-roadmap.js";
|
|
30
39
|
import type { ValidateMilestoneParams } from "./validate-milestone.js";
|
|
@@ -311,6 +320,9 @@ export type SliceCompleteExecutorParams = CompleteSliceParams;
|
|
|
311
320
|
export type PlanMilestoneExecutorParams = PlanMilestoneParams;
|
|
312
321
|
export type PlanSliceExecutorParams = PlanSliceParams;
|
|
313
322
|
export type ReplanSliceExecutorParams = ReplanSliceParams;
|
|
323
|
+
export type ReopenTaskExecutorParams = ReopenTaskParams;
|
|
324
|
+
export type ReopenSliceExecutorParams = ReopenSliceParams;
|
|
325
|
+
export type ReopenMilestoneExecutorParams = ReopenMilestoneParams;
|
|
314
326
|
export type ValidateMilestoneExecutorParams = ValidateMilestoneParams;
|
|
315
327
|
export type ReassessRoadmapExecutorParams = ReassessRoadmapParams;
|
|
316
328
|
|
|
@@ -371,6 +383,129 @@ export async function executeTaskComplete(
|
|
|
371
383
|
}
|
|
372
384
|
}
|
|
373
385
|
|
|
386
|
+
export async function executeTaskReopen(
|
|
387
|
+
params: ReopenTaskExecutorParams,
|
|
388
|
+
basePath: string = process.cwd(),
|
|
389
|
+
): Promise<ToolExecutionResult> {
|
|
390
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
391
|
+
if (!dbAvailable) {
|
|
392
|
+
return {
|
|
393
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen task." }],
|
|
394
|
+
details: { operation: "reopen_task", error: "db_unavailable" },
|
|
395
|
+
isError: true,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
const result = await handleReopenTask(params, basePath);
|
|
400
|
+
if ("error" in result) {
|
|
401
|
+
return {
|
|
402
|
+
content: [{ type: "text", text: `Error reopening task: ${result.error}` }],
|
|
403
|
+
details: { operation: "reopen_task", error: result.error },
|
|
404
|
+
isError: true,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
return {
|
|
408
|
+
content: [{ type: "text", text: `Reopened task ${result.taskId} (${result.sliceId}/${result.milestoneId})` }],
|
|
409
|
+
details: {
|
|
410
|
+
operation: "reopen_task",
|
|
411
|
+
taskId: result.taskId,
|
|
412
|
+
sliceId: result.sliceId,
|
|
413
|
+
milestoneId: result.milestoneId,
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
} catch (err) {
|
|
417
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
418
|
+
logError("tool", `reopen_task tool failed: ${msg}`, { tool: "gsd_task_reopen", error: String(err) });
|
|
419
|
+
return {
|
|
420
|
+
content: [{ type: "text", text: `Error reopening task: ${msg}` }],
|
|
421
|
+
details: { operation: "reopen_task", error: msg },
|
|
422
|
+
isError: true,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
export async function executeSliceReopen(
|
|
428
|
+
params: ReopenSliceExecutorParams,
|
|
429
|
+
basePath: string = process.cwd(),
|
|
430
|
+
): Promise<ToolExecutionResult> {
|
|
431
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
432
|
+
if (!dbAvailable) {
|
|
433
|
+
return {
|
|
434
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen slice." }],
|
|
435
|
+
details: { operation: "reopen_slice", error: "db_unavailable" },
|
|
436
|
+
isError: true,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
try {
|
|
440
|
+
const result = await handleReopenSlice(params, basePath);
|
|
441
|
+
if ("error" in result) {
|
|
442
|
+
return {
|
|
443
|
+
content: [{ type: "text", text: `Error reopening slice: ${result.error}` }],
|
|
444
|
+
details: { operation: "reopen_slice", error: result.error },
|
|
445
|
+
isError: true,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
content: [{ type: "text", text: `Reopened slice ${result.sliceId} (${result.milestoneId})` }],
|
|
450
|
+
details: {
|
|
451
|
+
operation: "reopen_slice",
|
|
452
|
+
sliceId: result.sliceId,
|
|
453
|
+
milestoneId: result.milestoneId,
|
|
454
|
+
tasksReset: result.tasksReset,
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
} catch (err) {
|
|
458
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
459
|
+
logError("tool", `reopen_slice tool failed: ${msg}`, { tool: "gsd_slice_reopen", error: String(err) });
|
|
460
|
+
return {
|
|
461
|
+
content: [{ type: "text", text: `Error reopening slice: ${msg}` }],
|
|
462
|
+
details: { operation: "reopen_slice", error: msg },
|
|
463
|
+
isError: true,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export async function executeMilestoneReopen(
|
|
469
|
+
params: ReopenMilestoneExecutorParams,
|
|
470
|
+
basePath: string = process.cwd(),
|
|
471
|
+
): Promise<ToolExecutionResult> {
|
|
472
|
+
const dbAvailable = await ensureDbOpen(basePath);
|
|
473
|
+
if (!dbAvailable) {
|
|
474
|
+
return {
|
|
475
|
+
content: [{ type: "text", text: "Error: GSD database is not available. Cannot reopen milestone." }],
|
|
476
|
+
details: { operation: "reopen_milestone", error: "db_unavailable" },
|
|
477
|
+
isError: true,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const result = await handleReopenMilestone(params, basePath);
|
|
482
|
+
if ("error" in result) {
|
|
483
|
+
return {
|
|
484
|
+
content: [{ type: "text", text: `Error reopening milestone: ${result.error}` }],
|
|
485
|
+
details: { operation: "reopen_milestone", error: result.error },
|
|
486
|
+
isError: true,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
content: [{ type: "text", text: `Reopened milestone ${result.milestoneId}` }],
|
|
491
|
+
details: {
|
|
492
|
+
operation: "reopen_milestone",
|
|
493
|
+
milestoneId: result.milestoneId,
|
|
494
|
+
slicesReset: result.slicesReset,
|
|
495
|
+
tasksReset: result.tasksReset,
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
} catch (err) {
|
|
499
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
500
|
+
logError("tool", `reopen_milestone tool failed: ${msg}`, { tool: "gsd_milestone_reopen", error: String(err) });
|
|
501
|
+
return {
|
|
502
|
+
content: [{ type: "text", text: `Error reopening milestone: ${msg}` }],
|
|
503
|
+
details: { operation: "reopen_milestone", error: msg },
|
|
504
|
+
isError: true,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
374
509
|
export async function executeSliceComplete(
|
|
375
510
|
params: SliceCompleteExecutorParams,
|
|
376
511
|
basePath: string = process.cwd(),
|
|
@@ -132,6 +132,9 @@ export type ContextModePolicy =
|
|
|
132
132
|
* the explicit `allowedPathGlobs` set; Bash safe-allowlist;
|
|
133
133
|
* no subagents. Reserved for rewrite-docs, which legitimately
|
|
134
134
|
* edits project markdown outside .gsd/.
|
|
135
|
+
* - "verification"
|
|
136
|
+
* — Read tools + Bash for verification commands, writes
|
|
137
|
+
* restricted to .gsd/**, no subagents.
|
|
135
138
|
*
|
|
136
139
|
* The allowlist for "docs" is declared per-manifest rather than hardcoded so
|
|
137
140
|
* projects with non-standard doc layouts can extend it without forking the
|
|
@@ -143,7 +146,8 @@ export type ToolsPolicy =
|
|
|
143
146
|
| { readonly mode: "read-only" }
|
|
144
147
|
| { readonly mode: "planning" }
|
|
145
148
|
| { readonly mode: "planning-dispatch"; readonly allowedSubagents: readonly string[] }
|
|
146
|
-
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
149
|
+
| { readonly mode: "docs"; readonly allowedPathGlobs: readonly string[] }
|
|
150
|
+
| { readonly mode: "verification" };
|
|
147
151
|
|
|
148
152
|
// ─── Computed-artifact registry (#4924 v2 contract) ───────────────────────
|
|
149
153
|
|
|
@@ -288,6 +292,7 @@ const COMMON_BUDGET_SMALL = 250_000; // ~65K tokens
|
|
|
288
292
|
|
|
289
293
|
const TOOLS_ALL: ToolsPolicy = { mode: "all" };
|
|
290
294
|
const TOOLS_PLANNING: ToolsPolicy = { mode: "planning" };
|
|
295
|
+
const TOOLS_VERIFICATION: ToolsPolicy = { mode: "verification" };
|
|
291
296
|
// Like TOOLS_PLANNING but permits dispatch to read-only recon/planning
|
|
292
297
|
// specialists. Runtime-enforced by write-gate.ts before the subagent tool runs.
|
|
293
298
|
const TOOLS_PLANNING_DISPATCH_RECON: ToolsPolicy = {
|
|
@@ -406,8 +411,8 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
406
411
|
contextMode: "verification",
|
|
407
412
|
// planning-dispatch: validation is a verification-fan-out unit. It reads
|
|
408
413
|
// the milestone surface and dispatches reviewer/security/tester subagents
|
|
409
|
-
// to report findings without touching user source.
|
|
410
|
-
//
|
|
414
|
+
// to report findings without touching user source. Write isolation to
|
|
415
|
+
// .gsd/ is preserved.
|
|
411
416
|
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
412
417
|
artifacts: {
|
|
413
418
|
inline: ["roadmap", "slice-summary", "slice-uat", "requirements", "decisions", "templates"],
|
|
@@ -423,11 +428,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
423
428
|
codebaseMap: false,
|
|
424
429
|
preferences: "active-only",
|
|
425
430
|
contextMode: "verification",
|
|
426
|
-
//
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
// preserved.
|
|
430
|
-
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
431
|
+
// Milestone closeout must run unrestricted shell verification commands
|
|
432
|
+
// against the final diff before recording completion.
|
|
433
|
+
tools: TOOLS_ALL,
|
|
431
434
|
artifacts: {
|
|
432
435
|
// #4780 landed slice-summary as excerpt for this unit; phase 2 of
|
|
433
436
|
// the architecture will read this manifest as the source of truth
|
|
@@ -447,7 +450,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
447
450
|
codebaseMap: true,
|
|
448
451
|
preferences: "active-only",
|
|
449
452
|
contextMode: "research",
|
|
450
|
-
|
|
453
|
+
// Multi-slice research dispatches use the research-slice unit contract to
|
|
454
|
+
// fan out scout subagents that write .gsd research artifacts.
|
|
455
|
+
tools: TOOLS_PLANNING_DISPATCH_RECON,
|
|
451
456
|
artifacts: {
|
|
452
457
|
inline: ["roadmap", "milestone-research", "dependency-summaries", "templates"],
|
|
453
458
|
excerpt: [],
|
|
@@ -587,7 +592,7 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
587
592
|
codebaseMap: false,
|
|
588
593
|
preferences: "active-only",
|
|
589
594
|
contextMode: "verification",
|
|
590
|
-
tools:
|
|
595
|
+
tools: TOOLS_VERIFICATION,
|
|
591
596
|
artifacts: {
|
|
592
597
|
// Phase 3 migration (#4782): manifest matches today's actual
|
|
593
598
|
// buildRunUatPrompt inlining. Prior phase-1 entry listed
|
|
@@ -606,7 +611,9 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
606
611
|
codebaseMap: false,
|
|
607
612
|
preferences: "active-only",
|
|
608
613
|
contextMode: "verification",
|
|
609
|
-
|
|
614
|
+
// Gate evaluation fans out tester-style subagents, which read the slice
|
|
615
|
+
// plan and report via the DB-backed gate-result tool.
|
|
616
|
+
tools: TOOLS_PLANNING_DISPATCH_REVIEW,
|
|
610
617
|
artifacts: {
|
|
611
618
|
inline: ["slice-plan", "prior-task-summaries"],
|
|
612
619
|
excerpt: [],
|
|
@@ -734,3 +741,32 @@ export const UNIT_MANIFESTS: Record<UnitType, UnitContextManifest> = {
|
|
|
734
741
|
export function resolveManifest(unitType: string): UnitContextManifest | null {
|
|
735
742
|
return (UNIT_MANIFESTS as Record<string, UnitContextManifest>)[unitType] ?? null;
|
|
736
743
|
}
|
|
744
|
+
|
|
745
|
+
export interface SubagentPermissionContract {
|
|
746
|
+
readonly allowed: boolean;
|
|
747
|
+
readonly allowedSubagents: readonly string[];
|
|
748
|
+
readonly toolsMode: ToolsPolicy["mode"] | "unknown";
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
export function compileSubagentPermissionContract(
|
|
752
|
+
policy: ToolsPolicy | null | undefined,
|
|
753
|
+
): SubagentPermissionContract {
|
|
754
|
+
if (!policy) {
|
|
755
|
+
return { allowed: false, allowedSubagents: [], toolsMode: "unknown" };
|
|
756
|
+
}
|
|
757
|
+
if (policy.mode === "all") {
|
|
758
|
+
return { allowed: true, allowedSubagents: ["*"], toolsMode: policy.mode };
|
|
759
|
+
}
|
|
760
|
+
if (policy.mode === "planning-dispatch") {
|
|
761
|
+
return {
|
|
762
|
+
allowed: true,
|
|
763
|
+
allowedSubagents: [...policy.allowedSubagents],
|
|
764
|
+
toolsMode: policy.mode,
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
return { allowed: false, allowedSubagents: [], toolsMode: policy.mode };
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
export function resolveSubagentPermissionContract(unitType: string): SubagentPermissionContract {
|
|
771
|
+
return compileSubagentPermissionContract(resolveManifest(unitType)?.tools);
|
|
772
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Host-owned verification verdict policy for auto-mode units.
|
|
3
|
+
|
|
4
|
+
import type { VerificationResult as VerificationGateResult } from "./types.js";
|
|
5
|
+
|
|
6
|
+
export type VerificationVerdictReason =
|
|
7
|
+
| "passed"
|
|
8
|
+
| "no-host-checks"
|
|
9
|
+
| "checks-failed";
|
|
10
|
+
|
|
11
|
+
export interface VerificationVerdict {
|
|
12
|
+
passed: boolean;
|
|
13
|
+
reason: VerificationVerdictReason;
|
|
14
|
+
retryable: boolean;
|
|
15
|
+
failureContext: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function decideVerificationVerdict(
|
|
19
|
+
unitType: string,
|
|
20
|
+
result: VerificationGateResult,
|
|
21
|
+
): VerificationVerdict {
|
|
22
|
+
if (unitType === "execute-task" && result.discoverySource === "none" && result.checks.length === 0) {
|
|
23
|
+
return {
|
|
24
|
+
passed: false,
|
|
25
|
+
reason: "no-host-checks",
|
|
26
|
+
retryable: false,
|
|
27
|
+
failureContext:
|
|
28
|
+
"No runnable host-owned verification command was discovered. Add project verification_commands or a runnable task-plan Verify command before completing this execute-task.",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!result.passed) {
|
|
33
|
+
return {
|
|
34
|
+
passed: false,
|
|
35
|
+
reason: "checks-failed",
|
|
36
|
+
retryable: true,
|
|
37
|
+
failureContext: "",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
passed: true,
|
|
43
|
+
reason: "passed",
|
|
44
|
+
retryable: false,
|
|
45
|
+
failureContext: "",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -76,6 +76,13 @@ import {
|
|
|
76
76
|
teardownAutoWorktree,
|
|
77
77
|
} from "./auto-worktree.js";
|
|
78
78
|
|
|
79
|
+
const recentWorktreeMergeFailures = new Map<string, number>();
|
|
80
|
+
const MERGE_FAILURE_DEDUPE_MS = 60_000;
|
|
81
|
+
|
|
82
|
+
export function resetRecentWorktreeMergeFailuresForTest(): void {
|
|
83
|
+
recentWorktreeMergeFailures.clear();
|
|
84
|
+
}
|
|
85
|
+
|
|
79
86
|
// ─── Types ───────────────────────────────────────────────────────────────
|
|
80
87
|
|
|
81
88
|
export interface NotifyCtx {
|
|
@@ -836,6 +843,32 @@ function rebuildGitService(
|
|
|
836
843
|
s.gitService = deps.gitServiceFactory(s.basePath);
|
|
837
844
|
}
|
|
838
845
|
|
|
846
|
+
function emitWorktreeMergeFailedOnce(
|
|
847
|
+
basePath: string,
|
|
848
|
+
milestoneId: string,
|
|
849
|
+
err: unknown,
|
|
850
|
+
): void {
|
|
851
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
852
|
+
const errorCategory = err instanceof Error ? err.name : "Error";
|
|
853
|
+
const now = Date.now();
|
|
854
|
+
const key = `${basePath}\0${milestoneId}\0${errorCategory}`;
|
|
855
|
+
const previous = recentWorktreeMergeFailures.get(key);
|
|
856
|
+
if (previous && now - previous < MERGE_FAILURE_DEDUPE_MS) return;
|
|
857
|
+
for (const [candidate, ts] of recentWorktreeMergeFailures) {
|
|
858
|
+
if (now - ts >= MERGE_FAILURE_DEDUPE_MS) {
|
|
859
|
+
recentWorktreeMergeFailures.delete(candidate);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
emitJournalEvent(basePath, {
|
|
863
|
+
ts: new Date().toISOString(),
|
|
864
|
+
flowId: randomUUID(),
|
|
865
|
+
seq: 0,
|
|
866
|
+
eventType: "worktree-merge-failed",
|
|
867
|
+
data: { milestoneId, error: msg },
|
|
868
|
+
});
|
|
869
|
+
recentWorktreeMergeFailures.set(key, now);
|
|
870
|
+
}
|
|
871
|
+
|
|
839
872
|
// ─── Session-less merge entry (ADR-016 phase 2 / A1) ─────────────────────
|
|
840
873
|
|
|
841
874
|
/**
|
|
@@ -985,13 +1018,7 @@ function _mergeWorktreeModeImpl(
|
|
|
985
1018
|
error: msg,
|
|
986
1019
|
fallback: "chdir-to-project-root",
|
|
987
1020
|
});
|
|
988
|
-
|
|
989
|
-
ts: new Date().toISOString(),
|
|
990
|
-
flowId: randomUUID(),
|
|
991
|
-
seq: 0,
|
|
992
|
-
eventType: "worktree-merge-failed",
|
|
993
|
-
data: { milestoneId, error: msg },
|
|
994
|
-
});
|
|
1021
|
+
emitWorktreeMergeFailedOnce(originalBasePath || worktreeBasePath, milestoneId, err);
|
|
995
1022
|
// Surface a clear, actionable error. Worktree and milestone branch
|
|
996
1023
|
// are intentionally preserved — nothing has been deleted. User can
|
|
997
1024
|
// retry /gsd dispatch complete-milestone or merge manually once the
|
|
@@ -1702,16 +1729,34 @@ export class WorktreeLifecycle {
|
|
|
1702
1729
|
}
|
|
1703
1730
|
|
|
1704
1731
|
/**
|
|
1705
|
-
* Restore `s.basePath` to `s.originalBasePath
|
|
1706
|
-
* No-op when `originalBasePath` is empty (fresh
|
|
1732
|
+
* Restore `s.basePath` to `s.originalBasePath`, chdir process cwd, and
|
|
1733
|
+
* rebuild `s.gitService`. No-op when `originalBasePath` is empty (fresh
|
|
1734
|
+
* sessions).
|
|
1707
1735
|
*
|
|
1708
1736
|
* Used by error/cleanup paths that need the session to behave as if the
|
|
1709
1737
|
* worktree was never entered. Does NOT teardown the worktree directory —
|
|
1710
1738
|
* callers that need teardown go through `exitMilestone({ merge: false })`.
|
|
1739
|
+
*
|
|
1740
|
+
* ADR-016 phase 3 (#5693): chdir lives inside the verb so callers do not
|
|
1741
|
+
* pair `restoreToProjectRoot()` with a redundant `process.chdir`. The
|
|
1742
|
+
* chdir runs BEFORE the throwable work (`rebuildGitService`, cache
|
|
1743
|
+
* invalidation) so that cleanup-path cwd is restored even if the
|
|
1744
|
+
* downstream rebuild throws. The chdir itself is best-effort; failure is
|
|
1745
|
+
* logged via debugLog and swallowed.
|
|
1711
1746
|
*/
|
|
1712
1747
|
restoreToProjectRoot(): void {
|
|
1713
1748
|
if (!this.s.originalBasePath) return;
|
|
1714
1749
|
this.s.basePath = this.s.originalBasePath;
|
|
1750
|
+
try {
|
|
1751
|
+
process.chdir(this.s.basePath);
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
debugLog("WorktreeLifecycle", {
|
|
1754
|
+
action: "restoreToProjectRoot",
|
|
1755
|
+
result: "chdir-failed",
|
|
1756
|
+
basePath: this.s.basePath,
|
|
1757
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1715
1760
|
rebuildGitService(this.s, this.deps);
|
|
1716
1761
|
invalidateAllCaches();
|
|
1717
1762
|
}
|