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
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* worktree-sync-tasks.test.ts
|
|
2
|
+
* worktree-sync-tasks.test.ts
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* DB-authoritative worktree contract: task and milestone markdown under a
|
|
5
|
+
* worktree .gsd directory are legacy projections. syncWorktreeStateBack must
|
|
6
|
+
* not copy them into the canonical project .gsd tree.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import test from "node:test";
|
|
@@ -11,7 +12,6 @@ import {
|
|
|
11
12
|
existsSync,
|
|
12
13
|
mkdirSync,
|
|
13
14
|
mkdtempSync,
|
|
14
|
-
readFileSync,
|
|
15
15
|
rmSync,
|
|
16
16
|
writeFileSync,
|
|
17
17
|
} from "node:fs";
|
|
@@ -20,19 +20,13 @@ import { tmpdir } from "node:os";
|
|
|
20
20
|
|
|
21
21
|
import { syncWorktreeStateBack } from "../auto-worktree.ts";
|
|
22
22
|
|
|
23
|
-
// ─── Helpers ─────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
23
|
function makeTempDir(prefix: string): string {
|
|
26
24
|
return mkdtempSync(join(tmpdir(), `gsd-sync-test-${prefix}-`));
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
function cleanup(...dirs: string[]): void {
|
|
30
28
|
for (const dir of dirs) {
|
|
31
|
-
|
|
32
|
-
rmSync(dir, { recursive: true, force: true });
|
|
33
|
-
} catch {
|
|
34
|
-
// ignore
|
|
35
|
-
}
|
|
29
|
+
rmSync(dir, { recursive: true, force: true });
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
32
|
|
|
@@ -42,168 +36,49 @@ function writeFile(dir: string, relativePath: string, content: string): void {
|
|
|
42
36
|
writeFileSync(fullPath, content, "utf-8");
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#1678)", () => {
|
|
39
|
+
test("syncWorktreeStateBack does not copy task markdown projections from worktree", () => {
|
|
48
40
|
const mainBase = makeTempDir("main");
|
|
49
41
|
const wtBase = makeTempDir("wt");
|
|
50
|
-
const currentMid = "M000"; // milestone being merged (skipped by sync)
|
|
51
|
-
const mid = "M001"; // other milestone that should be synced
|
|
52
42
|
|
|
53
43
|
try {
|
|
54
|
-
|
|
55
|
-
writeFile(wtBase,
|
|
56
|
-
writeFile(wtBase,
|
|
57
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`, "# Plan\n");
|
|
58
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`, "# Slice Summary\n");
|
|
59
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-UAT.md`, "# UAT\n");
|
|
60
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-PLAN.md`, "# Task 1 Plan\n");
|
|
61
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`, "# Task 1 Summary\n");
|
|
62
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-PLAN.md`, "# Task 2 Plan\n");
|
|
63
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-SUMMARY.md`, "# Task 2 Summary\n");
|
|
64
|
-
|
|
65
|
-
// Set up main with empty .gsd
|
|
44
|
+
writeFile(wtBase, ".gsd/milestones/M001/M001-ROADMAP.md", "# Roadmap\n");
|
|
45
|
+
writeFile(wtBase, ".gsd/milestones/M001/slices/S01/S01-PLAN.md", "# Plan\n");
|
|
46
|
+
writeFile(wtBase, ".gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md", "# Task Summary\n");
|
|
66
47
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
67
48
|
|
|
68
|
-
|
|
69
|
-
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
70
|
-
|
|
71
|
-
// Verify milestone-level files synced
|
|
72
|
-
assert.ok(
|
|
73
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/${mid}-ROADMAP.md`)),
|
|
74
|
-
"ROADMAP should be synced",
|
|
75
|
-
);
|
|
76
|
-
assert.ok(
|
|
77
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/${mid}-SUMMARY.md`)),
|
|
78
|
-
"SUMMARY should be synced",
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
// Verify slice-level files synced
|
|
82
|
-
assert.ok(
|
|
83
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`)),
|
|
84
|
-
"S01-PLAN should be synced",
|
|
85
|
-
);
|
|
86
|
-
assert.ok(
|
|
87
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`)),
|
|
88
|
-
"S01-SUMMARY should be synced",
|
|
89
|
-
);
|
|
49
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, "M000");
|
|
90
50
|
|
|
91
|
-
|
|
92
|
-
assert.
|
|
93
|
-
existsSync(join(mainBase,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
assert.ok(
|
|
97
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)),
|
|
98
|
-
"T01-SUMMARY should be synced (was dropped before fix)",
|
|
99
|
-
);
|
|
100
|
-
assert.ok(
|
|
101
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-PLAN.md`)),
|
|
102
|
-
"T02-PLAN should be synced (was dropped before fix)",
|
|
103
|
-
);
|
|
104
|
-
assert.ok(
|
|
105
|
-
existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T02-SUMMARY.md`)),
|
|
106
|
-
"T02-SUMMARY should be synced (was dropped before fix)",
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
// Verify task files appear in synced list
|
|
110
|
-
const taskSynced = result.synced.filter(p => p.includes("/tasks/"));
|
|
111
|
-
assert.ok(
|
|
112
|
-
taskSynced.length >= 4,
|
|
113
|
-
`Expected at least 4 task files in synced list, got ${taskSynced.length}: ${taskSynced.join(", ")}`,
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
// Verify content integrity
|
|
117
|
-
const t1Summary = readFileSync(
|
|
118
|
-
join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`),
|
|
119
|
-
"utf-8",
|
|
51
|
+
assert.equal(result.synced.some((p) => p.includes("milestones/")), false);
|
|
52
|
+
assert.equal(
|
|
53
|
+
existsSync(join(mainBase, ".gsd/milestones/M001/M001-ROADMAP.md")),
|
|
54
|
+
false,
|
|
55
|
+
"milestone markdown projection must not be copied",
|
|
120
56
|
);
|
|
121
|
-
assert.equal(t1Summary, "# Task 1 Summary\n");
|
|
122
|
-
} finally {
|
|
123
|
-
cleanup(mainBase, wtBase);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
128
|
-
const mainBase = makeTempDir("main");
|
|
129
|
-
const wtBase = makeTempDir("wt");
|
|
130
|
-
const currentMid = "M000"; // milestone being merged (skipped)
|
|
131
|
-
const mid = "M002"; // other milestone that should be synced
|
|
132
|
-
|
|
133
|
-
try {
|
|
134
|
-
// Set up two slices with tasks
|
|
135
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-SUMMARY.md`, "# S01\n");
|
|
136
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`, "# S01-T01\n");
|
|
137
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/S02-SUMMARY.md`, "# S02\n");
|
|
138
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T01-SUMMARY.md`, "# S02-T01\n");
|
|
139
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T02-SUMMARY.md`, "# S02-T02\n");
|
|
140
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S02/tasks/T03-SUMMARY.md`, "# S02-T03\n");
|
|
141
|
-
|
|
142
|
-
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
143
|
-
|
|
144
|
-
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
145
|
-
|
|
146
|
-
// All task summaries from both slices should be synced
|
|
147
|
-
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
|
|
148
|
-
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T01-SUMMARY.md`)));
|
|
149
|
-
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T02-SUMMARY.md`)));
|
|
150
|
-
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S02/tasks/T03-SUMMARY.md`)));
|
|
151
|
-
|
|
152
|
-
// Verify content integrity across slices
|
|
153
57
|
assert.equal(
|
|
154
|
-
|
|
155
|
-
|
|
58
|
+
existsSync(join(mainBase, ".gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md")),
|
|
59
|
+
false,
|
|
60
|
+
"task summary projection must not be copied",
|
|
156
61
|
);
|
|
157
62
|
} finally {
|
|
158
63
|
cleanup(mainBase, wtBase);
|
|
159
64
|
}
|
|
160
65
|
});
|
|
161
66
|
|
|
162
|
-
test("syncWorktreeStateBack
|
|
163
|
-
const mainBase = makeTempDir("main");
|
|
164
|
-
const wtBase = makeTempDir("wt");
|
|
165
|
-
const currentMid = "M000"; // milestone being merged (skipped)
|
|
166
|
-
const mid = "M003"; // other milestone that should be synced
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
// Slice with no tasks/ subdirectory (legitimate case: pre-planning)
|
|
170
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`, "# Research\n");
|
|
171
|
-
|
|
172
|
-
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
173
|
-
|
|
174
|
-
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
175
|
-
|
|
176
|
-
// Should sync the slice file without errors
|
|
177
|
-
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`)));
|
|
178
|
-
// Should not have any task entries
|
|
179
|
-
const taskSynced = result.synced.filter(p => p.includes("/tasks/"));
|
|
180
|
-
assert.equal(taskSynced.length, 0);
|
|
181
|
-
} finally {
|
|
182
|
-
cleanup(mainBase, wtBase);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
|
|
67
|
+
test("syncWorktreeStateBack still copies diagnostic root files", () => {
|
|
187
68
|
const mainBase = makeTempDir("main");
|
|
188
69
|
const wtBase = makeTempDir("wt");
|
|
189
|
-
const currentMid = "M000"; // milestone being merged (skipped)
|
|
190
|
-
const mid = "M004"; // other milestone that should be synced
|
|
191
70
|
|
|
192
71
|
try {
|
|
193
|
-
writeFile(wtBase,
|
|
194
|
-
writeFile(wtBase,
|
|
195
|
-
// Non-md file should be ignored
|
|
196
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/.DS_Store`, "junk");
|
|
197
|
-
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/tasks/notes.txt`, "notes");
|
|
198
|
-
|
|
72
|
+
writeFile(wtBase, ".gsd/completed-units.json", JSON.stringify({ units: ["M001/S01/T01"] }));
|
|
73
|
+
writeFile(wtBase, ".gsd/metrics.json", JSON.stringify({ version: 1, units: [] }));
|
|
199
74
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
200
75
|
|
|
201
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
76
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, "M001");
|
|
202
77
|
|
|
203
|
-
|
|
204
|
-
assert.ok(
|
|
205
|
-
assert.ok(
|
|
206
|
-
assert.ok(
|
|
78
|
+
assert.ok(result.synced.includes("completed-units.json"));
|
|
79
|
+
assert.ok(result.synced.includes("metrics.json"));
|
|
80
|
+
assert.ok(existsSync(join(mainBase, ".gsd/completed-units.json")));
|
|
81
|
+
assert.ok(existsSync(join(mainBase, ".gsd/metrics.json")));
|
|
207
82
|
} finally {
|
|
208
83
|
cleanup(mainBase, wtBase);
|
|
209
84
|
}
|
|
@@ -56,6 +56,7 @@ export interface CompleteMilestoneParams {
|
|
|
56
56
|
export interface CompleteMilestoneResult {
|
|
57
57
|
milestoneId: string;
|
|
58
58
|
summaryPath: string;
|
|
59
|
+
stale?: boolean;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams): string {
|
|
@@ -206,15 +207,15 @@ export async function handleCompleteMilestone(
|
|
|
206
207
|
// This handles re-dispatch scenarios (DB/disk state divergence) where a prior
|
|
207
208
|
// completion already wrote the file. Overwriting would silently destroy the
|
|
208
209
|
// richer content the agent produced during the original completion run.
|
|
210
|
+
let projectionStale = false;
|
|
209
211
|
if (!existsSync(summaryPath)) {
|
|
210
212
|
try {
|
|
211
213
|
await saveFile(summaryPath, summaryMd);
|
|
212
214
|
} catch (renderErr) {
|
|
213
|
-
|
|
214
|
-
logWarning("
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
215
|
+
projectionStale = true;
|
|
216
|
+
logWarning("projection", `complete_milestone projection write failed for ${params.milestoneId}; DB completion remains committed`, {
|
|
217
|
+
error: (renderErr as Error).message,
|
|
218
|
+
});
|
|
218
219
|
}
|
|
219
220
|
}
|
|
220
221
|
|
|
@@ -252,5 +253,6 @@ export async function handleCompleteMilestone(
|
|
|
252
253
|
return {
|
|
253
254
|
milestoneId: params.milestoneId,
|
|
254
255
|
summaryPath,
|
|
256
|
+
...(projectionStale ? { stale: true } : {}),
|
|
255
257
|
};
|
|
256
258
|
}
|
|
@@ -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
|
|
|
10
11
|
import { join } from "node:path";
|
|
@@ -277,7 +278,6 @@ export async function handleCompleteSlice(
|
|
|
277
278
|
|
|
278
279
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
279
280
|
const completedAt = new Date().toISOString();
|
|
280
|
-
const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
|
|
281
281
|
let guardError: string | null = null;
|
|
282
282
|
|
|
283
283
|
transaction(() => {
|
|
@@ -349,10 +349,6 @@ export async function handleCompleteSlice(
|
|
|
349
349
|
return { error: guardError };
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
-
// ── Filesystem operations (outside transaction) ─────────────────────────
|
|
353
|
-
// If disk render fails, roll back the DB status so deriveState() and
|
|
354
|
-
// verifyExpectedArtifact() stay consistent (both say "not done").
|
|
355
|
-
|
|
356
352
|
// Render summary markdown
|
|
357
353
|
const summaryMd = renderSliceSummaryMarkdown(params);
|
|
358
354
|
|
|
@@ -371,6 +367,8 @@ export async function handleCompleteSlice(
|
|
|
371
367
|
|
|
372
368
|
const uatMd = renderUatMarkdown(params);
|
|
373
369
|
const uatPath = summaryPath.replace(/-SUMMARY\.md$/, "-UAT.md");
|
|
370
|
+
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
371
|
+
let projectionStale = false;
|
|
374
372
|
|
|
375
373
|
try {
|
|
376
374
|
await saveFile(summaryPath, summaryMd);
|
|
@@ -382,16 +380,10 @@ export async function handleCompleteSlice(
|
|
|
382
380
|
logWarning("tool", `complete_slice — could not find roadmap for ${params.milestoneId}, skipping checkbox toggle`);
|
|
383
381
|
}
|
|
384
382
|
} catch (renderErr) {
|
|
385
|
-
|
|
386
|
-
logWarning("
|
|
387
|
-
updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
|
|
388
|
-
invalidateStateCache();
|
|
389
|
-
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
383
|
+
projectionStale = true;
|
|
384
|
+
logWarning("projection", `complete_slice projection write failed for ${params.milestoneId}/${params.sliceId}; DB completion remains committed`, { error: (renderErr as Error).message });
|
|
390
385
|
}
|
|
391
386
|
|
|
392
|
-
// Store rendered markdown in DB for D004 recovery
|
|
393
|
-
setSliceSummaryMd(params.milestoneId, params.sliceId, summaryMd, uatMd);
|
|
394
|
-
|
|
395
387
|
// ── Close gates owned by complete-slice (Q8) ───────────────────────────
|
|
396
388
|
// Each owned gate maps to a specific summary section via the registry.
|
|
397
389
|
// If the caller populated the corresponding field, record `pass`; if the
|
|
@@ -493,5 +485,6 @@ export async function handleCompleteSlice(
|
|
|
493
485
|
milestoneId: params.milestoneId,
|
|
494
486
|
summaryPath,
|
|
495
487
|
uatPath,
|
|
488
|
+
...(projectionStale ? { stale: true } : {}),
|
|
496
489
|
};
|
|
497
490
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
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
|
|
|
10
10
|
import { join } from "node:path";
|
|
@@ -22,13 +22,12 @@ import {
|
|
|
22
22
|
getSlice,
|
|
23
23
|
getTask,
|
|
24
24
|
updateTaskStatus,
|
|
25
|
-
setTaskSummaryMd,
|
|
26
25
|
deleteVerificationEvidence,
|
|
27
26
|
saveGateResult,
|
|
28
27
|
getPendingGatesForTurn,
|
|
29
28
|
} from "../gsd-db.js";
|
|
30
29
|
import { getGatesForTurn } from "../gate-registry.js";
|
|
31
|
-
import {
|
|
30
|
+
import { resolveTasksDir, clearPathCache } from "../paths.js";
|
|
32
31
|
import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
|
|
33
32
|
import { saveFile, clearParseCache } from "../files.js";
|
|
34
33
|
import { invalidateStateCache } from "../state.js";
|
|
@@ -168,6 +167,7 @@ export async function handleCompleteTask(
|
|
|
168
167
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
169
168
|
const completedAt = new Date().toISOString();
|
|
170
169
|
let guardError: string | null = null;
|
|
170
|
+
let summaryMd = "";
|
|
171
171
|
|
|
172
172
|
// ── ADR-011 Phase 2: validate escalation payload BEFORE any side effects ─
|
|
173
173
|
// Building the artifact runs the full shape validation (2-4 options, unique
|
|
@@ -237,6 +237,9 @@ export async function handleCompleteTask(
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
// All guards passed — perform writes
|
|
240
|
+
const taskRow = paramsToTaskRow(params, completedAt);
|
|
241
|
+
summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
|
|
242
|
+
|
|
240
243
|
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
241
244
|
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
242
245
|
insertTask({
|
|
@@ -254,6 +257,7 @@ export async function handleCompleteTask(
|
|
|
254
257
|
knownIssues: params.knownIssues ?? "None.",
|
|
255
258
|
keyFiles: params.keyFiles ?? [],
|
|
256
259
|
keyDecisions: params.keyDecisions ?? [],
|
|
260
|
+
fullSummaryMd: summaryMd,
|
|
257
261
|
});
|
|
258
262
|
|
|
259
263
|
for (const evidence of (params.verificationEvidence ?? [])) {
|
|
@@ -301,13 +305,7 @@ export async function handleCompleteTask(
|
|
|
301
305
|
return { error: guardError };
|
|
302
306
|
}
|
|
303
307
|
|
|
304
|
-
|
|
305
|
-
// If disk render fails, roll back the DB status so deriveState() and
|
|
306
|
-
// verifyExpectedArtifact() stay consistent (both say "not done").
|
|
307
|
-
|
|
308
|
-
// Render summary markdown via the single source of truth (#2720)
|
|
309
|
-
const taskRow = paramsToTaskRow(params, completedAt);
|
|
310
|
-
const summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
|
|
308
|
+
let projectionStale = false;
|
|
311
309
|
|
|
312
310
|
// Resolve and write summary to disk
|
|
313
311
|
let summaryPath: string;
|
|
@@ -325,30 +323,16 @@ export async function handleCompleteTask(
|
|
|
325
323
|
try {
|
|
326
324
|
await saveFile(summaryPath, summaryMd);
|
|
327
325
|
|
|
328
|
-
// Toggle plan
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
332
|
-
} else {
|
|
333
|
-
process.stderr.write(
|
|
334
|
-
`gsd-db: complete_task — could not find plan file for ${params.sliceId}/${params.milestoneId}, skipping checkbox toggle\n`,
|
|
335
|
-
);
|
|
336
|
-
}
|
|
326
|
+
// Toggle or regenerate the plan projection from DB. Missing projection
|
|
327
|
+
// files are rebuilt by the renderer instead of being skipped.
|
|
328
|
+
await renderPlanCheckboxes(basePath, params.milestoneId, params.sliceId);
|
|
337
329
|
} catch (renderErr) {
|
|
338
|
-
|
|
339
|
-
logWarning("
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
// Without this, retries accumulate duplicate evidence rows (#2724).
|
|
343
|
-
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
344
|
-
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
345
|
-
invalidateStateCache();
|
|
346
|
-
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
330
|
+
projectionStale = true;
|
|
331
|
+
logWarning("projection", `complete_task projection write failed for ${params.milestoneId}/${params.sliceId}/${params.taskId}; DB completion remains committed`, {
|
|
332
|
+
error: (renderErr as Error).message,
|
|
333
|
+
});
|
|
347
334
|
}
|
|
348
335
|
|
|
349
|
-
// Store rendered markdown in DB for D004 recovery
|
|
350
|
-
setTaskSummaryMd(params.milestoneId, params.sliceId, params.taskId, summaryMd);
|
|
351
|
-
|
|
352
336
|
// ── Close gates owned by execute-task (Q5/Q6/Q7) for this task ────────
|
|
353
337
|
// Each gate id maps to a specific params field via taskGateFieldForId.
|
|
354
338
|
// When the model populates the field, record `pass`; when it's empty,
|
|
@@ -471,5 +455,6 @@ export async function handleCompleteTask(
|
|
|
471
455
|
sliceId: params.sliceId,
|
|
472
456
|
milestoneId: params.milestoneId,
|
|
473
457
|
summaryPath,
|
|
458
|
+
...(projectionStale ? { stale: true } : {}),
|
|
474
459
|
};
|
|
475
460
|
}
|
|
@@ -14,7 +14,6 @@ import { join } from "node:path";
|
|
|
14
14
|
import {
|
|
15
15
|
transaction,
|
|
16
16
|
insertAssessment,
|
|
17
|
-
deleteAssessmentByScope,
|
|
18
17
|
getMilestoneSlices,
|
|
19
18
|
} from "../gsd-db.js";
|
|
20
19
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
@@ -45,6 +44,7 @@ export interface ValidateMilestoneResult {
|
|
|
45
44
|
milestoneId: string;
|
|
46
45
|
verdict: string;
|
|
47
46
|
validationPath: string;
|
|
47
|
+
stale?: boolean;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export interface ValidateMilestoneOptions {
|
|
@@ -150,13 +150,14 @@ export async function handleValidateMilestone(
|
|
|
150
150
|
});
|
|
151
151
|
|
|
152
152
|
// ── Filesystem render (outside transaction) ────────────────────────────
|
|
153
|
-
|
|
153
|
+
let projectionStale = false;
|
|
154
154
|
try {
|
|
155
155
|
await saveFile(validationPath, validationMd);
|
|
156
156
|
} catch (renderErr) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
projectionStale = true;
|
|
158
|
+
logWarning("projection", `validate_milestone projection write failed for ${params.milestoneId}; DB validation remains committed`, {
|
|
159
|
+
error: (renderErr as Error).message,
|
|
160
|
+
});
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
invalidateStateCache();
|
|
@@ -202,5 +203,6 @@ export async function handleValidateMilestone(
|
|
|
202
203
|
milestoneId: params.milestoneId,
|
|
203
204
|
verdict: params.verdict,
|
|
204
205
|
validationPath,
|
|
206
|
+
...(projectionStale ? { stale: true } : {}),
|
|
205
207
|
};
|
|
206
208
|
}
|
|
@@ -76,7 +76,9 @@ export function snapshotState(): StateManifest {
|
|
|
76
76
|
// Wrap all reads in a deferred transaction so the snapshot is consistent
|
|
77
77
|
// (all SELECTs see the same DB state even if a concurrent write lands between them).
|
|
78
78
|
return readTransaction(() => {
|
|
79
|
-
const rawMilestones = db.prepare(
|
|
79
|
+
const rawMilestones = db.prepare(
|
|
80
|
+
"SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id",
|
|
81
|
+
).all() as Record<string, unknown>[];
|
|
80
82
|
const milestones: MilestoneRow[] = rawMilestones.map((r) => ({
|
|
81
83
|
id: r["id"] as string,
|
|
82
84
|
title: r["title"] as string,
|
|
@@ -95,6 +97,7 @@ export function snapshotState(): StateManifest {
|
|
|
95
97
|
definition_of_done: JSON.parse((r["definition_of_done"] as string) || "[]"),
|
|
96
98
|
requirement_coverage: (r["requirement_coverage"] as string) ?? "",
|
|
97
99
|
boundary_map_markdown: (r["boundary_map_markdown"] as string) ?? "",
|
|
100
|
+
sequence: Number(r["sequence"] ?? 0),
|
|
98
101
|
}));
|
|
99
102
|
|
|
100
103
|
const rawSlices = db.prepare("SELECT * FROM slices ORDER BY milestone_id, sequence, id").all() as Record<string, unknown>[];
|
|
@@ -29,29 +29,13 @@ function getAuthModeSafe(
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function hasClaudeCodeProvider(ctx: WorkflowMcpAutoPrepContext): boolean {
|
|
33
|
-
return getAuthModeSafe(ctx, "claude-code") === "externalCli";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function isClaudeCodeProviderReady(ctx: WorkflowMcpAutoPrepContext): boolean {
|
|
37
|
-
const readyCheck = ctx.modelRegistry?.isProviderRequestReady;
|
|
38
|
-
if (typeof readyCheck !== "function") return false;
|
|
39
|
-
try {
|
|
40
|
-
return readyCheck("claude-code");
|
|
41
|
-
} catch {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
32
|
export function shouldAutoPrepareWorkflowMcp(ctx: WorkflowMcpAutoPrepContext): boolean {
|
|
47
33
|
const provider = ctx.model?.provider;
|
|
48
34
|
const baseUrl = ctx.model?.baseUrl;
|
|
49
35
|
const authMode = getAuthModeSafe(ctx, provider);
|
|
50
36
|
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
if (hasClaudeCodeProvider(ctx)) return true;
|
|
54
|
-
return isClaudeCodeProviderReady(ctx);
|
|
37
|
+
if (provider !== "claude-code") return false;
|
|
38
|
+
return usesWorkflowMcpTransport(authMode as any, baseUrl) || authMode === "externalCli";
|
|
55
39
|
}
|
|
56
40
|
|
|
57
41
|
export function prepareWorkflowMcpForProject(
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "./gsd-db.js";
|
|
21
21
|
import { isClosedStatus } from "./status-guards.js";
|
|
22
22
|
import { invalidateStateCache } from "./state.js";
|
|
23
|
-
import { clearPathCache } from "./paths.js";
|
|
23
|
+
import { clearPathCache, resolveGsdPathContract } from "./paths.js";
|
|
24
24
|
import { clearParseCache } from "./files.js";
|
|
25
25
|
import { writeManifest } from "./workflow-manifest.js";
|
|
26
26
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
@@ -492,7 +492,7 @@ function _reconcileWorktreeLogsInner(
|
|
|
492
492
|
atomicWriteSync(join(mainBasePath, ".gsd", "event-log.jsonl"), logContent);
|
|
493
493
|
|
|
494
494
|
// Step 8: Replay into DB (wrapped in a transaction by replayEvents)
|
|
495
|
-
openDatabase(
|
|
495
|
+
openDatabase(resolveGsdPathContract(mainBasePath).projectDb);
|
|
496
496
|
replayEvents(merged);
|
|
497
497
|
|
|
498
498
|
// Step 9: Write manifest
|
|
@@ -647,7 +647,7 @@ export function resolveConflict(
|
|
|
647
647
|
writeEventLog(targetBasePath, targetBaseEvents.concat(rewrittenTargetEvents));
|
|
648
648
|
|
|
649
649
|
// Replay resolved events through the DB (updates DB state)
|
|
650
|
-
openDatabase(
|
|
650
|
+
openDatabase(resolveGsdPathContract(basePath).projectDb);
|
|
651
651
|
replayEvents(eventsToReplay);
|
|
652
652
|
invalidateStateCache();
|
|
653
653
|
clearPathCache();
|
|
@@ -15,7 +15,7 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
15
15
|
import { autoCommitCurrentBranch, getMainBranch, resolveGitHeadPath, nudgeGitBranchCache } from "./worktree.js";
|
|
16
16
|
import { runWorktreePostCreateHook } from "./auto-worktree.js";
|
|
17
17
|
import { showConfirm } from "../shared/tui.js";
|
|
18
|
-
import { gsdRoot, milestonesDir } from "./paths.js";
|
|
18
|
+
import { gsdRoot, milestonesDir, resolveGsdPathContract } from "./paths.js";
|
|
19
19
|
import {
|
|
20
20
|
createWorktree,
|
|
21
21
|
listWorktrees,
|
|
@@ -651,8 +651,9 @@ async function handleMerge(
|
|
|
651
651
|
const commitMessage = `${commitType}: merge worktree ${name}\n\nGSD-Worktree: ${name}`;
|
|
652
652
|
|
|
653
653
|
// Reconcile worktree DB into main DB before squash merge
|
|
654
|
-
const
|
|
655
|
-
const
|
|
654
|
+
const contract = resolveGsdPathContract(worktreePath(basePath, name), basePath);
|
|
655
|
+
const wtDbPath = join(contract.worktreeGsd ?? join(contract.workRoot, ".gsd"), "gsd.db");
|
|
656
|
+
const mainDbPath = contract.projectDb;
|
|
656
657
|
if (existsSync(wtDbPath) && existsSync(mainDbPath)) {
|
|
657
658
|
try {
|
|
658
659
|
const { reconcileWorktreeDb } = await import("./gsd-db.js");
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
exports.id=8527,exports.ids=[8527],exports.modules={18527:(a,b,c)=>{"use strict";c.d(b,{isOnboardingComplete:()=>l,readOnboardingRecord:()=>k});var d=c(73024),e=c(76760);c(77598);var f=c(16698),g=c(48161);c(31421),process.env.GSD_ENABLE_NATIVE_GSD_PARSER,Symbol("native-unavailable"),new f.AsyncLocalStorage,c(89134),Object.values({Q3:{id:"Q3",scope:"slice",ownerTurn:"gate-evaluate",question:"How can this be exploited?",guidance:"Identify abuse scenarios: parameter tampering, replay attacks, privilege escalation.\nMap data exposure risks: PII, tokens, secrets accessible through this slice.\nDefine input trust boundaries: untrusted user input reaching DB, API, or filesystem.\nIf none apply, return verdict 'omitted' with rationale explaining why.",promptSection:"Abuse Surface"},Q4:{id:"Q4",scope:"slice",ownerTurn:"gate-evaluate",question:"Which existing requirements (R-IDs) does this slice touch, and which must be re-tested?",guidance:"List the R-IDs (e.g. R001, R003) touched by this slice; see the milestone requirements artifact at .gsd/milestones/<id>/REQUIREMENTS.md.\nIdentify what must be re-tested after shipping.\nFlag decisions that should be revisited given the new scope.\nIf no existing requirements are affected, return verdict 'omitted'.",promptSection:"Broken Promises"},Q5:{id:"Q5",scope:"task",ownerTurn:"execute-task",question:"What breaks when dependencies fail?",guidance:"Enumerate the task's external dependencies (APIs, filesystem, network, subprocesses).\nDescribe the failure path for each: timeout, malformed response, connection loss.\nVerify the implementation handles each failure or explicitly bubbles the error.\nReturn verdict 'omitted' only if the task has no external dependencies.",promptSection:"Failure Modes"},Q6:{id:"Q6",scope:"task",ownerTurn:"execute-task",question:"What is the 10x load breakpoint?",guidance:"Identify the resource that saturates first at 10x the expected load.\nDescribe the protection applied (pool sizing, rate limiting, pagination, caching).\nReturn verdict 'omitted' if the task has no runtime load dimension.",promptSection:"Load Profile"},Q7:{id:"Q7",scope:"task",ownerTurn:"execute-task",question:"What negative tests protect this task?",guidance:"List malformed inputs, error paths, and boundary conditions the tests cover.\nPoint to the specific test files or cases that assert each negative scenario.\nReturn verdict 'omitted' only if the task has no meaningful negative surface.",promptSection:"Negative Tests"},Q8:{id:"Q8",scope:"slice",ownerTurn:"complete-slice",question:"How will ops know this slice is healthy or broken?",guidance:"Describe the health signal (metric, log line, dashboard) that proves the slice works.\nDescribe the failure signal that triggers an alert or paging.\nDocument the recovery procedure and any monitoring gaps.\nReturn verdict 'omitted' only for slices with no runtime behavior at all.",promptSection:"Operational Readiness"},MV01:{id:"MV01",scope:"milestone",ownerTurn:"validate-milestone",question:"Is every success criterion in the milestone roadmap satisfied?",guidance:"Walk the success-criteria checklist from the milestone roadmap.\nFor each criterion, point to the slice / assessment / verification evidence that proves it.\nReturn verdict 'flag' if any criterion is unmet or unverifiable.",promptSection:"Success Criteria Checklist"},MV02:{id:"MV02",scope:"milestone",ownerTurn:"validate-milestone",question:"Does every slice have a SUMMARY.md and a passing assessment?",guidance:"Confirm every slice listed in the roadmap has a SUMMARY.md.\nConfirm each slice has an ASSESSMENT verdict of 'pass' (or justified 'omitted').\nFlag missing artifacts and slices with outstanding follow-ups or known limitations.",promptSection:"Slice Delivery Audit"},MV03:{id:"MV03",scope:"milestone",ownerTurn:"validate-milestone",question:"Do the slices integrate end-to-end?",guidance:"Trace at least one cross-slice flow proving the pieces compose.\nFlag gaps where two slices were built in isolation with no integration evidence.",promptSection:"Cross-Slice Integration"},MV04:{id:"MV04",scope:"milestone",ownerTurn:"validate-milestone",question:"Are all touched requirements covered and still coherent?",guidance:"For each requirement advanced, validated, surfaced, or invalidated across the milestone's slices, confirm the milestone-level evidence matches.\nFlag requirements that slices claim to advance but no artifact proves.",promptSection:"Requirement Coverage"}});let h=process.env.GSD_CODING_AGENT_DIR||(0,e.join)(process.env.GSD_HOME?(0,e.resolve)(process.env.GSD_HOME):(0,e.join)((0,g.homedir)(),".gsd"),"agent"),i=(0,e.join)(h,"onboarding.json"),j={version:1,flowVersion:1,completedAt:null,completedSteps:[],skippedSteps:[],lastResumePoint:null};function k(){if(!(0,d.existsSync)(i))return{...j};try{let a=JSON.parse((0,d.readFileSync)(i,"utf-8"));return{version:"number"==typeof a.version?a.version:1,flowVersion:"number"==typeof a.flowVersion?a.flowVersion:0,completedAt:"string"==typeof a.completedAt?a.completedAt:null,completedSteps:Array.isArray(a.completedSteps)?a.completedSteps.filter(a=>"string"==typeof a):[],skippedSteps:Array.isArray(a.skippedSteps)?a.skippedSteps.filter(a=>"string"==typeof a):[],lastResumePoint:"string"==typeof a.lastResumePoint?a.lastResumePoint:null}}catch{return{...j}}}function l(){let a=k();return null!==a.completedAt&&1===a.flowVersion}},65168:a=>{function b(a){var b=Error("Cannot find module '"+a+"'");throw b.code="MODULE_NOT_FOUND",b}b.keys=()=>[],b.resolve=b,b.id=65168,a.exports=b},89134:(a,b,c)=>{"use strict";c.d(b,{DZ:()=>e,rs:()=>d});let d="GSD_GIT_ERROR";class e extends Error{constructor(a,b,c){super(b,c),this.name="GSDError",this.code=a}}}};
|
|
File without changes
|
|
File without changes
|