gsd-pi 2.78.1-dev.b0759e59b → 2.78.1-dev.e9d88a536
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 +8 -5
- package/dist/headless-recover.d.ts +23 -0
- package/dist/headless-recover.js +93 -0
- package/dist/headless.js +9 -0
- package/dist/help-text.js +1 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +8 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +4 -56
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -27
- package/dist/resources/extensions/gsd/auto-start.js +1 -8
- package/dist/resources/extensions/gsd/auto-worktree.js +59 -176
- package/dist/resources/extensions/gsd/auto.js +24 -6
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +9 -77
- package/dist/resources/extensions/gsd/commands-codebase.js +2 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +5 -5
- package/dist/resources/extensions/gsd/commands-logs.js +2 -2
- package/dist/resources/extensions/gsd/commands-scan.js +2 -2
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +5 -5
- package/dist/resources/extensions/gsd/db-writer.js +16 -85
- package/dist/resources/extensions/gsd/dispatch-guard.js +6 -10
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -2
- package/dist/resources/extensions/gsd/gsd-db.js +74 -8
- package/dist/resources/extensions/gsd/guided-flow.js +31 -8
- package/dist/resources/extensions/gsd/markdown-renderer.js +14 -51
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -13
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +5 -2
- package/dist/resources/extensions/gsd/paths.js +35 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/dist/resources/extensions/gsd/queue-order.js +6 -1
- package/dist/resources/extensions/gsd/rethink.js +2 -2
- package/dist/resources/extensions/gsd/state.js +91 -372
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +6 -5
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -12
- package/dist/resources/extensions/gsd/tools/complete-task.js +19 -31
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -5
- package/dist/resources/extensions/gsd/workflow-manifest.js +2 -1
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -21
- package/dist/resources/extensions/gsd/workflow-reconcile.js +3 -3
- package/dist/resources/extensions/gsd/worktree-command.js +4 -3
- 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 +12 -12
- 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/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +12 -12
- package/dist/web/standalone/.next/server/chunks/6336.js +1 -0
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- 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 +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +6 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +56 -2
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/parse-workflow-args.test.ts +80 -0
- package/packages/mcp-server/src/workflow-tools.ts +61 -2
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +13 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +4 -60
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -26
- package/src/resources/extensions/gsd/auto-start.ts +1 -8
- package/src/resources/extensions/gsd/auto-worktree.ts +61 -204
- package/src/resources/extensions/gsd/auto.ts +23 -6
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +9 -84
- package/src/resources/extensions/gsd/commands-codebase.ts +2 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +5 -5
- package/src/resources/extensions/gsd/commands-logs.ts +2 -2
- package/src/resources/extensions/gsd/commands-scan.ts +2 -2
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +5 -5
- package/src/resources/extensions/gsd/db-writer.ts +16 -83
- package/src/resources/extensions/gsd/dispatch-guard.ts +6 -11
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -2
- package/src/resources/extensions/gsd/gsd-db.ts +85 -8
- package/src/resources/extensions/gsd/guided-flow.ts +35 -8
- package/src/resources/extensions/gsd/markdown-renderer.ts +13 -64
- package/src/resources/extensions/gsd/parallel-merge.ts +14 -13
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +5 -2
- package/src/resources/extensions/gsd/paths.ts +55 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -0
- package/src/resources/extensions/gsd/queue-order.ts +6 -1
- package/src/resources/extensions/gsd/rethink.ts +2 -2
- package/src/resources/extensions/gsd/state.ts +91 -389
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +21 -34
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +12 -27
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +18 -5
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +10 -38
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +136 -56
- package/src/resources/extensions/gsd/tests/derive-state-draft.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +119 -61
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +6 -20
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +14 -15
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +11 -16
- package/src/resources/extensions/gsd/tests/escalation.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +15 -36
- package/src/resources/extensions/gsd/tests/handler-worktree-write-isolation.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +15 -15
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +15 -5
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +14 -8
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +25 -16
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +184 -0
- package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/resolve-ts.mjs +4 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/slice-disk-reconcile.test.ts +10 -56
- package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +15 -16
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +23 -27
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +13 -14
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +10 -33
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +12 -7
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +65 -71
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +26 -151
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -5
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -14
- package/src/resources/extensions/gsd/tools/complete-task.ts +19 -34
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +7 -5
- package/src/resources/extensions/gsd/workflow-manifest.ts +4 -1
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -18
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/worktree-command.ts +4 -3
- package/dist/web/standalone/.next/server/chunks/8527.js +0 -1
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rk1EN3FQTE6Z1yalkW_GE → oZGTPvJBQX_IDKKnuV8Bt}/_ssgManifest.js +0 -0
|
@@ -145,16 +145,16 @@ export async function handleCompleteMilestone(params, basePath) {
|
|
|
145
145
|
// This handles re-dispatch scenarios (DB/disk state divergence) where a prior
|
|
146
146
|
// completion already wrote the file. Overwriting would silently destroy the
|
|
147
147
|
// richer content the agent produced during the original completion run.
|
|
148
|
+
let projectionStale = false;
|
|
148
149
|
if (!existsSync(summaryPath)) {
|
|
149
150
|
try {
|
|
150
151
|
await saveFile(summaryPath, summaryMd);
|
|
151
152
|
}
|
|
152
153
|
catch (renderErr) {
|
|
153
|
-
|
|
154
|
-
logWarning("
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return { error: `disk render failed: ${renderErr.message}` };
|
|
154
|
+
projectionStale = true;
|
|
155
|
+
logWarning("projection", `complete_milestone projection write failed for ${params.milestoneId}; DB completion remains committed`, {
|
|
156
|
+
error: renderErr.message,
|
|
157
|
+
});
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
// Invalidate all caches
|
|
@@ -192,5 +192,6 @@ export async function handleCompleteMilestone(params, basePath) {
|
|
|
192
192
|
return {
|
|
193
193
|
milestoneId: params.milestoneId,
|
|
194
194
|
summaryPath,
|
|
195
|
+
...(projectionStale ? { stale: true } : {}),
|
|
195
196
|
};
|
|
196
197
|
}
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Validates inputs, checks all tasks are complete, writes slice row to DB in
|
|
5
5
|
* a transaction, then (outside the transaction) renders SUMMARY.md + UAT.md
|
|
6
6
|
* to disk, toggles the roadmap checkbox, stores rendered markdown in DB for
|
|
7
|
-
* D004 recovery, and invalidates caches.
|
|
7
|
+
* D004 recovery, and invalidates caches. Projection write failures are stale
|
|
8
|
+
* projection diagnostics and do not roll back committed DB state.
|
|
8
9
|
*/
|
|
9
10
|
import { join } from "node:path";
|
|
10
11
|
import { mkdirSync } from "node:fs";
|
|
@@ -216,7 +217,6 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
216
217
|
}
|
|
217
218
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
218
219
|
const completedAt = new Date().toISOString();
|
|
219
|
-
const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
|
|
220
220
|
let guardError = null;
|
|
221
221
|
transaction(() => {
|
|
222
222
|
// State machine preconditions (inside txn for atomicity).
|
|
@@ -272,9 +272,6 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
272
272
|
if (guardError) {
|
|
273
273
|
return { error: guardError };
|
|
274
274
|
}
|
|
275
|
-
// ── Filesystem operations (outside transaction) ─────────────────────────
|
|
276
|
-
// If disk render fails, roll back the DB status so deriveState() and
|
|
277
|
-
// verifyExpectedArtifact() stay consistent (both say "not done").
|
|
278
275
|
// Render summary markdown
|
|
279
276
|
const summaryMd = renderSliceSummaryMarkdown(params);
|
|
280
277
|
// Resolve and write summary to disk
|
|
@@ -292,6 +289,8 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
292
289
|
}
|
|
293
290
|
const uatMd = renderUatMarkdown(params);
|
|
294
291
|
const uatPath = summaryPath.replace(/-SUMMARY\.md$/, "-UAT.md");
|
|
292
|
+
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
293
|
+
let projectionStale = false;
|
|
295
294
|
try {
|
|
296
295
|
await saveFile(summaryPath, summaryMd);
|
|
297
296
|
await saveFile(uatPath, uatMd);
|
|
@@ -302,14 +301,9 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
302
301
|
}
|
|
303
302
|
}
|
|
304
303
|
catch (renderErr) {
|
|
305
|
-
|
|
306
|
-
logWarning("
|
|
307
|
-
updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
|
|
308
|
-
invalidateStateCache();
|
|
309
|
-
return { error: `disk render failed: ${renderErr.message}` };
|
|
304
|
+
projectionStale = true;
|
|
305
|
+
logWarning("projection", `complete_slice projection write failed for ${params.milestoneId}/${params.sliceId}; DB completion remains committed`, { error: renderErr.message });
|
|
310
306
|
}
|
|
311
|
-
// Store rendered markdown in DB for D004 recovery
|
|
312
|
-
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
313
307
|
// ── Close gates owned by complete-slice (Q8) ───────────────────────────
|
|
314
308
|
// Each owned gate maps to a specific summary section via the registry.
|
|
315
309
|
// If the caller populated the corresponding field, record `pass`; if the
|
|
@@ -400,5 +394,6 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
400
394
|
milestoneId: params.milestoneId,
|
|
401
395
|
summaryPath,
|
|
402
396
|
uatPath,
|
|
397
|
+
...(projectionStale ? { stale: true } : {}),
|
|
403
398
|
};
|
|
404
399
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* complete-task handler — the core operation behind gsd_complete_task.
|
|
3
3
|
*
|
|
4
|
-
* Validates inputs, writes task row to DB in a
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Validates inputs, writes task row and rendered SUMMARY.md to DB in a
|
|
5
|
+
* transaction, then renders projections to disk and invalidates caches.
|
|
6
|
+
* Projection write failures are reported as stale projections and do not roll
|
|
7
|
+
* back committed DB state.
|
|
8
8
|
*/
|
|
9
9
|
import { join } from "node:path";
|
|
10
10
|
import { mkdirSync } from "node:fs";
|
|
11
11
|
import { isClosedStatus } from "../status-guards.js";
|
|
12
|
-
import { transaction, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, getMilestone, getSlice, getTask, updateTaskStatus,
|
|
12
|
+
import { transaction, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, getMilestone, getSlice, getTask, updateTaskStatus, deleteVerificationEvidence, saveGateResult, getPendingGatesForTurn, } from "../gsd-db.js";
|
|
13
13
|
import { getGatesForTurn } from "../gate-registry.js";
|
|
14
|
-
import {
|
|
14
|
+
import { resolveTasksDir, clearPathCache } from "../paths.js";
|
|
15
15
|
import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
|
|
16
16
|
import { saveFile, clearParseCache } from "../files.js";
|
|
17
17
|
import { invalidateStateCache } from "../state.js";
|
|
@@ -119,6 +119,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
119
119
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
120
120
|
const completedAt = new Date().toISOString();
|
|
121
121
|
let guardError = null;
|
|
122
|
+
let summaryMd = "";
|
|
122
123
|
// ── ADR-011 Phase 2: validate escalation payload BEFORE any side effects ─
|
|
123
124
|
// Building the artifact runs the full shape validation (2-4 options, unique
|
|
124
125
|
// ids, recommendation references a real id). If the payload is malformed
|
|
@@ -184,6 +185,8 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
184
185
|
return;
|
|
185
186
|
}
|
|
186
187
|
// All guards passed — perform writes
|
|
188
|
+
const taskRow = paramsToTaskRow(params, completedAt);
|
|
189
|
+
summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
|
|
187
190
|
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
188
191
|
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
189
192
|
insertTask({
|
|
@@ -201,6 +204,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
201
204
|
knownIssues: params.knownIssues ?? "None.",
|
|
202
205
|
keyFiles: params.keyFiles ?? [],
|
|
203
206
|
keyDecisions: params.keyDecisions ?? [],
|
|
207
|
+
fullSummaryMd: summaryMd,
|
|
204
208
|
});
|
|
205
209
|
for (const evidence of (params.verificationEvidence ?? [])) {
|
|
206
210
|
insertVerificationEvidence({
|
|
@@ -235,12 +239,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
235
239
|
if (guardError) {
|
|
236
240
|
return { error: guardError };
|
|
237
241
|
}
|
|
238
|
-
|
|
239
|
-
// If disk render fails, roll back the DB status so deriveState() and
|
|
240
|
-
// verifyExpectedArtifact() stay consistent (both say "not done").
|
|
241
|
-
// Render summary markdown via the single source of truth (#2720)
|
|
242
|
-
const taskRow = paramsToTaskRow(params, completedAt);
|
|
243
|
-
const summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
|
|
242
|
+
let projectionStale = false;
|
|
244
243
|
// Resolve and write summary to disk
|
|
245
244
|
let summaryPath;
|
|
246
245
|
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
@@ -256,28 +255,16 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
256
255
|
}
|
|
257
256
|
try {
|
|
258
257
|
await saveFile(summaryPath, summaryMd);
|
|
259
|
-
// Toggle plan
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
process.stderr.write(`gsd-db: complete_task — could not find plan file for ${params.sliceId}/${params.milestoneId}, skipping checkbox toggle\n`);
|
|
266
|
-
}
|
|
258
|
+
// Toggle or regenerate the plan projection from DB. Missing projection
|
|
259
|
+
// files are rebuilt by the renderer instead of being skipped.
|
|
260
|
+
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
267
261
|
}
|
|
268
262
|
catch (renderErr) {
|
|
269
|
-
|
|
270
|
-
logWarning("
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// Without this, retries accumulate duplicate evidence rows (#2724).
|
|
274
|
-
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
275
|
-
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
276
|
-
invalidateStateCache();
|
|
277
|
-
return { error: `disk render failed: ${renderErr.message}` };
|
|
263
|
+
projectionStale = true;
|
|
264
|
+
logWarning("projection", `complete_task projection write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}; DB completion remains committed`, {
|
|
265
|
+
error: renderErr.message,
|
|
266
|
+
});
|
|
278
267
|
}
|
|
279
|
-
// Store rendered markdown in DB for D004 recovery
|
|
280
|
-
setTaskSummaryMd(params.milestoneId, params.sliceId, params.taskId, summaryMd);
|
|
281
268
|
// ── Close gates owned by execute-task (Q5/Q6/Q7) for this task ────────
|
|
282
269
|
// Each gate id maps to a specific params field via taskGateFieldForId.
|
|
283
270
|
// When the model populates the field, record `pass`; when it's empty,
|
|
@@ -387,5 +374,6 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
387
374
|
sliceId: params.sliceId,
|
|
388
375
|
milestoneId: params.milestoneId,
|
|
389
376
|
summaryPath,
|
|
377
|
+
...(projectionStale ? { stale: true } : {}),
|
|
390
378
|
};
|
|
391
379
|
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* despite passing validation.
|
|
10
10
|
*/
|
|
11
11
|
import { join } from "node:path";
|
|
12
|
-
import { transaction, insertAssessment,
|
|
12
|
+
import { transaction, insertAssessment, getMilestoneSlices, } from "../gsd-db.js";
|
|
13
13
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
14
14
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
15
15
|
import { saveFile, clearParseCache } from "../files.js";
|
|
@@ -99,14 +99,15 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
99
99
|
insertMilestoneValidationGates(params.milestoneId, gateSliceId, params.verdict, validatedAt);
|
|
100
100
|
});
|
|
101
101
|
// ── Filesystem render (outside transaction) ────────────────────────────
|
|
102
|
-
|
|
102
|
+
let projectionStale = false;
|
|
103
103
|
try {
|
|
104
104
|
await saveFile(validationPath, validationMd);
|
|
105
105
|
}
|
|
106
106
|
catch (renderErr) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
projectionStale = true;
|
|
108
|
+
logWarning("projection", `validate_milestone projection write failed for ${params.milestoneId}; DB validation remains committed`, {
|
|
109
|
+
error: renderErr.message,
|
|
110
|
+
});
|
|
110
111
|
}
|
|
111
112
|
invalidateStateCache();
|
|
112
113
|
clearPathCache();
|
|
@@ -147,5 +148,6 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
147
148
|
milestoneId: params.milestoneId,
|
|
148
149
|
verdict: params.verdict,
|
|
149
150
|
validationPath,
|
|
151
|
+
...(projectionStale ? { stale: true } : {}),
|
|
150
152
|
};
|
|
151
153
|
}
|
|
@@ -42,7 +42,7 @@ export function snapshotState() {
|
|
|
42
42
|
// Wrap all reads in a deferred transaction so the snapshot is consistent
|
|
43
43
|
// (all SELECTs see the same DB state even if a concurrent write lands between them).
|
|
44
44
|
return readTransaction(() => {
|
|
45
|
-
const rawMilestones = db.prepare("SELECT * FROM milestones ORDER BY id").all();
|
|
45
|
+
const rawMilestones = db.prepare("SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id").all();
|
|
46
46
|
const milestones = rawMilestones.map((r) => ({
|
|
47
47
|
id: r["id"],
|
|
48
48
|
title: r["title"],
|
|
@@ -61,6 +61,7 @@ export function snapshotState() {
|
|
|
61
61
|
definition_of_done: JSON.parse(r["definition_of_done"] || "[]"),
|
|
62
62
|
requirement_coverage: r["requirement_coverage"] ?? "",
|
|
63
63
|
boundary_map_markdown: r["boundary_map_markdown"] ?? "",
|
|
64
|
+
sequence: Number(r["sequence"] ?? 0),
|
|
64
65
|
}));
|
|
65
66
|
const rawSlices = db.prepare("SELECT * FROM slices ORDER BY milestone_id, sequence, id").all();
|
|
66
67
|
const slices = rawSlices.map((r) => ({
|
|
@@ -13,31 +13,13 @@ function getAuthModeSafe(ctx, provider) {
|
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
function hasClaudeCodeProvider(ctx) {
|
|
17
|
-
return getAuthModeSafe(ctx, "claude-code") === "externalCli";
|
|
18
|
-
}
|
|
19
|
-
function isClaudeCodeProviderReady(ctx) {
|
|
20
|
-
const readyCheck = ctx.modelRegistry?.isProviderRequestReady;
|
|
21
|
-
if (typeof readyCheck !== "function")
|
|
22
|
-
return false;
|
|
23
|
-
try {
|
|
24
|
-
return readyCheck("claude-code");
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
16
|
export function shouldAutoPrepareWorkflowMcp(ctx) {
|
|
31
17
|
const provider = ctx.model?.provider;
|
|
32
18
|
const baseUrl = ctx.model?.baseUrl;
|
|
33
19
|
const authMode = getAuthModeSafe(ctx, provider);
|
|
34
|
-
if (
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
return true;
|
|
38
|
-
if (hasClaudeCodeProvider(ctx))
|
|
39
|
-
return true;
|
|
40
|
-
return isClaudeCodeProviderReady(ctx);
|
|
20
|
+
if (provider !== "claude-code")
|
|
21
|
+
return false;
|
|
22
|
+
return usesWorkflowMcpTransport(authMode, baseUrl) || authMode === "externalCli";
|
|
41
23
|
}
|
|
42
24
|
export function prepareWorkflowMcpForProject(ctx, projectRoot) {
|
|
43
25
|
if (!shouldAutoPrepareWorkflowMcp(ctx))
|
|
@@ -5,7 +5,7 @@ import { readEvents, findForkPoint, getSessionId } from "./workflow-events.js";
|
|
|
5
5
|
import { transaction, updateTaskStatus, updateSliceStatus, updateMilestoneStatus, getSliceTasks, insertMilestone, getMilestoneSlices, insertVerificationEvidence, upsertDecision, openDatabase, setTaskBlockerDiscovered, insertOrIgnoreSlice, insertOrIgnoreTask, } from "./gsd-db.js";
|
|
6
6
|
import { isClosedStatus } from "./status-guards.js";
|
|
7
7
|
import { invalidateStateCache } from "./state.js";
|
|
8
|
-
import { clearPathCache } from "./paths.js";
|
|
8
|
+
import { clearPathCache, resolveGsdPathContract } from "./paths.js";
|
|
9
9
|
import { clearParseCache } from "./files.js";
|
|
10
10
|
import { writeManifest } from "./workflow-manifest.js";
|
|
11
11
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -407,7 +407,7 @@ function _reconcileWorktreeLogsInner(mainBasePath, worktreeBasePath) {
|
|
|
407
407
|
mkdirSync(join(mainBasePath, ".gsd"), { recursive: true });
|
|
408
408
|
atomicWriteSync(join(mainBasePath, ".gsd", "event-log.jsonl"), logContent);
|
|
409
409
|
// Step 8: Replay into DB (wrapped in a transaction by replayEvents)
|
|
410
|
-
openDatabase(
|
|
410
|
+
openDatabase(resolveGsdPathContract(mainBasePath).projectDb);
|
|
411
411
|
replayEvents(merged);
|
|
412
412
|
// Step 9: Write manifest
|
|
413
413
|
try {
|
|
@@ -540,7 +540,7 @@ pick) {
|
|
|
540
540
|
const targetBaseEvents = pick === "main" ? wtBaseEvents : mainBaseEvents;
|
|
541
541
|
writeEventLog(targetBasePath, targetBaseEvents.concat(rewrittenTargetEvents));
|
|
542
542
|
// Replay resolved events through the DB (updates DB state)
|
|
543
|
-
openDatabase(
|
|
543
|
+
openDatabase(resolveGsdPathContract(basePath).projectDb);
|
|
544
544
|
replayEvents(eventsToReplay);
|
|
545
545
|
invalidateStateCache();
|
|
546
546
|
clearPathCache();
|
|
@@ -13,7 +13,7 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
13
13
|
import { autoCommitCurrentBranch, getMainBranch, nudgeGitBranchCache } from "./worktree.js";
|
|
14
14
|
import { runWorktreePostCreateHook } from "./auto-worktree.js";
|
|
15
15
|
import { showConfirm } from "../shared/tui.js";
|
|
16
|
-
import { gsdRoot, milestonesDir } from "./paths.js";
|
|
16
|
+
import { gsdRoot, milestonesDir, resolveGsdPathContract } from "./paths.js";
|
|
17
17
|
import { createWorktree, listWorktrees, removeWorktree, mergeWorktreeToMain, diffWorktreeAll, diffWorktreeNumstat, getWorktreeGSDDiff, getWorktreeCodeDiff, getWorktreeLog, worktreeBranchName, worktreePath, } from "./worktree-manager.js";
|
|
18
18
|
import { inferCommitType } from "./git-service.js";
|
|
19
19
|
import { existsSync, realpathSync, readdirSync, rmSync, unlinkSync } from "node:fs";
|
|
@@ -530,8 +530,9 @@ async function handleMerge(basePath, name, ctx, pi, targetBranch) {
|
|
|
530
530
|
const commitType = inferCommitType(name);
|
|
531
531
|
const commitMessage = `${commitType}: merge worktree ${name}\n\nGSD-Worktree: ${name}`;
|
|
532
532
|
// Reconcile worktree DB into main DB before squash merge
|
|
533
|
-
const
|
|
534
|
-
const
|
|
533
|
+
const contract = resolveGsdPathContract(worktreePath(basePath, name), basePath);
|
|
534
|
+
const wtDbPath = join(contract.worktreeGsd ?? join(contract.workRoot, ".gsd"), "gsd.db");
|
|
535
|
+
const mainDbPath = contract.projectDb;
|
|
535
536
|
if (existsSync(wtDbPath) && existsSync(mainDbPath)) {
|
|
536
537
|
try {
|
|
537
538
|
const { reconcileWorktreeDb } = await import("./gsd-db.js");
|