@opengsd/gsd-pi 1.9.0-dev.97ef11e3 → 1.9.0-dev.e10b60d4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +4 -24
- package/dist/resources/extensions/gsd/auto/run-unit.js +1 -19
- package/dist/resources/extensions/gsd/auto-start.js +9 -29
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +3 -7
- package/dist/resources/extensions/gsd/auto.js +1 -12
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +2 -21
- package/dist/resources/extensions/gsd/flat-phase-migration.js +0 -12
- package/dist/resources/extensions/gsd/gsd-db.js +31 -75
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -20
- 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 +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.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/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +3 -9
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +15 -121
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.js +1 -7
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +3 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +7 -9
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/dist/cli-runner.d.ts +0 -3
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli-runner.js +33 -119
- package/packages/mcp-server/dist/cli-runner.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +0 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +0 -17
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +4 -48
- package/src/resources/extensions/gsd/auto/run-unit.ts +1 -20
- package/src/resources/extensions/gsd/auto-start.ts +8 -31
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +3 -10
- package/src/resources/extensions/gsd/auto.ts +1 -13
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +2 -27
- package/src/resources/extensions/gsd/flat-phase-migration.ts +0 -14
- package/src/resources/extensions/gsd/gsd-db.ts +33 -85
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -156
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +1 -21
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +1 -74
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +0 -83
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +0 -32
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +0 -13
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +0 -60
- package/src/resources/extensions/gsd/worktree-state-projection.ts +24 -21
- package/packages/gsd-cloud/dist/background-cli.test.d.ts +0 -2
- package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +0 -1
- package/packages/gsd-cloud/dist/background-cli.test.js +0 -248
- package/packages/gsd-cloud/dist/background-cli.test.js.map +0 -1
- package/packages/gsd-cloud/dist/runtime-process.d.ts +0 -27
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +0 -1
- package/packages/gsd-cloud/dist/runtime-process.js +0 -272
- package/packages/gsd-cloud/dist/runtime-process.js.map +0 -1
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts +0 -2
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +0 -1
- package/packages/gsd-cloud/dist/runtime-process.test.js +0 -97
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +0 -1
- /package/dist/web/standalone/.next/static/{DXD9fZPnqtjZSlT5xdC3v → V9MAVyYVPboQUB9KTTAMi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{DXD9fZPnqtjZSlT5xdC3v → V9MAVyYVPboQUB9KTTAMi}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-coding-agent",
|
|
3
|
-
"version": "1.9.0-dev.
|
|
3
|
+
"version": "1.9.0-dev.e10b60d4",
|
|
4
4
|
"description": "Coding agent CLI (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"copy-assets": "node scripts/copy-assets.cjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@opengsd/contracts": "^1.9.0-dev.
|
|
36
|
+
"@opengsd/contracts": "^1.9.0-dev.e10b60d4",
|
|
37
37
|
"@mariozechner/jiti": "^2.6.2",
|
|
38
38
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
39
39
|
"chalk": "5.6.2",
|
|
@@ -53,11 +53,11 @@
|
|
|
53
53
|
"typebox": "1.1.38",
|
|
54
54
|
"undici": "7.28.0",
|
|
55
55
|
"yaml": "2.9.0",
|
|
56
|
-
"@gsd/agent-core": "^1.9.0-dev.
|
|
57
|
-
"@gsd/native": "^1.9.0-dev.
|
|
58
|
-
"@gsd/pi-agent-core": "^1.9.0-dev.
|
|
59
|
-
"@gsd/pi-ai": "^1.9.0-dev.
|
|
60
|
-
"@gsd/pi-tui": "^1.9.0-dev.
|
|
56
|
+
"@gsd/agent-core": "^1.9.0-dev.e10b60d4",
|
|
57
|
+
"@gsd/native": "^1.9.0-dev.e10b60d4",
|
|
58
|
+
"@gsd/pi-agent-core": "^1.9.0-dev.e10b60d4",
|
|
59
|
+
"@gsd/pi-ai": "^1.9.0-dev.e10b60d4",
|
|
60
|
+
"@gsd/pi-tui": "^1.9.0-dev.e10b60d4",
|
|
61
61
|
"@sinclair/typebox": "^0.34.41"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gsd/pi-tui",
|
|
3
|
-
"version": "1.9.0-dev.
|
|
3
|
+
"version": "1.9.0-dev.e10b60d4",
|
|
4
4
|
"description": "Terminal UI library (vendored from earendil-works/pi)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"gsd": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"build": "node ../../scripts/clean-package-dist.cjs && tsc -p tsconfig.json --incremental false"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@gsd/native": "^1.9.0-dev.
|
|
24
|
+
"@gsd/native": "^1.9.0-dev.e10b60d4",
|
|
25
25
|
"get-east-asian-width": "1.6.0",
|
|
26
26
|
"marked": "15.0.12",
|
|
27
27
|
"@sinclair/typebox": "^0.34.41"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengsd/rpc-client",
|
|
3
|
-
"version": "1.9.0-dev.
|
|
3
|
+
"version": "1.9.0-dev.e10b60d4",
|
|
4
4
|
"description": "Standalone RPC client SDK for GSD — zero internal dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"gsd": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test": "node --test dist/rpc-client.test.js"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@opengsd/contracts": "^1.9.0-dev.
|
|
37
|
+
"@opengsd/contracts": "^1.9.0-dev.e10b60d4"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.0.0"
|
package/pkg/package.json
CHANGED
|
@@ -355,41 +355,7 @@ async function enforceMinRequestInterval(s: AutoSession, prefs: IterationContext
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
|
|
359
|
-
ctx: ExtensionContext,
|
|
360
|
-
s: AutoSession,
|
|
361
|
-
deps: LoopDeps,
|
|
362
|
-
iterData: IterationData,
|
|
363
|
-
): Promise<void> {
|
|
364
|
-
try {
|
|
365
|
-
const commitMsg = await deps.autoCommitUnit?.(
|
|
366
|
-
s.basePath,
|
|
367
|
-
iterData.unitType,
|
|
368
|
-
iterData.unitId,
|
|
369
|
-
ctx,
|
|
370
|
-
);
|
|
371
|
-
if (commitMsg) {
|
|
372
|
-
debugLog("autoLoop", {
|
|
373
|
-
phase: "crash-snapshot-commit",
|
|
374
|
-
unitType: iterData.unitType,
|
|
375
|
-
unitId: iterData.unitId,
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
} catch (snapshotErr) {
|
|
379
|
-
logWarning(
|
|
380
|
-
"dispatch",
|
|
381
|
-
`unit crash snapshot failed: ${snapshotErr instanceof Error ? snapshotErr.message : String(snapshotErr)}`,
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async function closeOutCrashedUnit(
|
|
387
|
-
ctx: ExtensionContext,
|
|
388
|
-
s: AutoSession,
|
|
389
|
-
deps: LoopDeps,
|
|
390
|
-
iterData: IterationData,
|
|
391
|
-
err: unknown,
|
|
392
|
-
): Promise<void> {
|
|
358
|
+
function closeOutCrashedUnit(s: AutoSession, iterData: IterationData, err: unknown): void {
|
|
393
359
|
const summary = formatDispatchExceptionSummary({ error: err });
|
|
394
360
|
try {
|
|
395
361
|
emitOpenUnitEndForUnit(
|
|
@@ -417,7 +383,6 @@ async function closeOutCrashedUnit(
|
|
|
417
383
|
} catch (closeoutErr) {
|
|
418
384
|
logWarning("dispatch", `unit crash closeout failed: ${closeoutErr instanceof Error ? closeoutErr.message : String(closeoutErr)}`);
|
|
419
385
|
}
|
|
420
|
-
await snapshotCrashedUnitWork(ctx, s, deps, iterData);
|
|
421
386
|
}
|
|
422
387
|
|
|
423
388
|
/**
|
|
@@ -561,20 +526,11 @@ export async function autoLoop(
|
|
|
561
526
|
active: s.active,
|
|
562
527
|
iteration,
|
|
563
528
|
maxIterations: MAX_LOOP_ITERATIONS,
|
|
564
|
-
hasCommandContext:
|
|
529
|
+
hasCommandContext: Boolean(s.cmdCtx),
|
|
565
530
|
sessionLockValid: true,
|
|
566
531
|
});
|
|
567
532
|
if (commandContextDecision.action === "stop" && commandContextDecision.reason === "missing-command-context") {
|
|
568
533
|
debugLog("autoLoop", { phase: "exit", reason: "no-cmdCtx" });
|
|
569
|
-
if (s.currentUnit) {
|
|
570
|
-
await deps.autoCommitUnit?.(
|
|
571
|
-
s.basePath,
|
|
572
|
-
s.currentUnit.type,
|
|
573
|
-
s.currentUnit.id,
|
|
574
|
-
ctx,
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
await deps.stopAuto(ctx, pi, commandContextDecision.message, { preserveWorktree: true });
|
|
578
534
|
finishTurn("stopped", "manual-attention", commandContextDecision.reason);
|
|
579
535
|
break;
|
|
580
536
|
}
|
|
@@ -774,7 +730,7 @@ export async function autoLoop(
|
|
|
774
730
|
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
775
731
|
throw err;
|
|
776
732
|
}
|
|
777
|
-
|
|
733
|
+
closeOutCrashedUnit(s, iterData, err);
|
|
778
734
|
throw err;
|
|
779
735
|
}
|
|
780
736
|
if (unitPhaseResult.action === "next") {
|
|
@@ -1329,7 +1285,7 @@ export async function autoLoop(
|
|
|
1329
1285
|
if (err instanceof ModelPolicyDispatchBlockedError) {
|
|
1330
1286
|
throw err;
|
|
1331
1287
|
}
|
|
1332
|
-
|
|
1288
|
+
closeOutCrashedUnit(s, iterData, err);
|
|
1333
1289
|
dispatchSettled = settleDispatchFailed(
|
|
1334
1290
|
dispatchId,
|
|
1335
1291
|
formatDispatchExceptionSummary({ error: err }),
|
|
@@ -91,25 +91,6 @@ export async function runUnit(
|
|
|
91
91
|
// ── Session creation with timeout ──
|
|
92
92
|
debugLog("runUnit", { phase: "session-create", unitType, unitId });
|
|
93
93
|
|
|
94
|
-
const cmdCtx = s.cmdCtx;
|
|
95
|
-
if (typeof cmdCtx?.newSession !== "function") {
|
|
96
|
-
const msg = "command context is missing newSession";
|
|
97
|
-
debugLog("runUnit", {
|
|
98
|
-
phase: "session-error",
|
|
99
|
-
unitType,
|
|
100
|
-
unitId,
|
|
101
|
-
error: msg,
|
|
102
|
-
});
|
|
103
|
-
return {
|
|
104
|
-
status: "cancelled",
|
|
105
|
-
errorContext: {
|
|
106
|
-
message: `Session creation failed: ${msg}`,
|
|
107
|
-
category: "session-failed",
|
|
108
|
-
isTransient: false,
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
94
|
let sessionResult: { cancelled: boolean };
|
|
114
95
|
let sessionTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
115
96
|
const mySessionSwitchGeneration = ++sessionSwitchGeneration;
|
|
@@ -119,7 +100,7 @@ export async function runUnit(
|
|
|
119
100
|
const sessionAbortController = new AbortController();
|
|
120
101
|
_setSessionSwitchInFlight(true);
|
|
121
102
|
try {
|
|
122
|
-
const sessionPromise = cmdCtx
|
|
103
|
+
const sessionPromise = s.cmdCtx!.newSession({
|
|
123
104
|
abortSignal: sessionAbortController.signal,
|
|
124
105
|
workspaceRoot: s.basePath,
|
|
125
106
|
}).finally(() => {
|
|
@@ -88,7 +88,6 @@ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.
|
|
|
88
88
|
import { extractVerdict } from "./verdict-parser.js";
|
|
89
89
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
90
90
|
import { parseProject } from "./schemas/parsers.js";
|
|
91
|
-
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
92
91
|
|
|
93
92
|
import {
|
|
94
93
|
debugLog,
|
|
@@ -153,33 +152,6 @@ export function hasGitIndexLockForTest(basePath: string): boolean {
|
|
|
153
152
|
return existsSync(join(basePath, ".git", "index.lock"));
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
function isEmptyDirectory(dirPath: string): boolean {
|
|
157
|
-
try {
|
|
158
|
-
return existsSync(dirPath) && readdirSync(dirPath).length === 0;
|
|
159
|
-
} catch {
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function reconcileFlatPhaseBootstrapLayout(basePath: string): boolean {
|
|
165
|
-
const gsdDir = join(basePath, ".gsd");
|
|
166
|
-
const phasesPath = join(gsdDir, LAYOUT_SEGMENTS.level1);
|
|
167
|
-
const milestonesPath = join(gsdDir, "milestones");
|
|
168
|
-
|
|
169
|
-
if (isEmptyDirectory(milestonesPath)) {
|
|
170
|
-
if (!existsSync(phasesPath)) mkdirSync(phasesPath, { recursive: true });
|
|
171
|
-
rmSync(milestonesPath, { recursive: true, force: true });
|
|
172
|
-
return true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (!existsSync(phasesPath) && !existsSync(milestonesPath)) {
|
|
176
|
-
mkdirSync(phasesPath, { recursive: true });
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
155
|
export function _shouldAbortBootstrapForUnavailableDbForTest(
|
|
184
156
|
gsdDbPath: string,
|
|
185
157
|
dbAvailable: boolean,
|
|
@@ -1180,14 +1152,19 @@ export async function bootstrapAutoSession(
|
|
|
1180
1152
|
ensureGitignore(base, { manageGitignore });
|
|
1181
1153
|
if (manageGitignore !== false) untrackRuntimeFiles(base);
|
|
1182
1154
|
|
|
1183
|
-
// Bootstrap
|
|
1184
|
-
|
|
1155
|
+
// Bootstrap milestones/ if it doesn't exist.
|
|
1156
|
+
// Check milestones/ directly — ensureGsdSymlink above already created .gsd/,
|
|
1157
|
+
// so checking .gsd/ existence would be dead code (#2942).
|
|
1158
|
+
const gsdDir = join(base, ".gsd");
|
|
1159
|
+
const milestonesPath = join(gsdDir, "milestones");
|
|
1160
|
+
if (!existsSync(milestonesPath)) {
|
|
1161
|
+
mkdirSync(milestonesPath, { recursive: true });
|
|
1185
1162
|
try {
|
|
1186
1163
|
nativeAddAll(base);
|
|
1187
1164
|
nativeCommit(base, "chore: init gsd");
|
|
1188
1165
|
} catch (err) {
|
|
1189
1166
|
/* nothing to commit */
|
|
1190
|
-
logWarning("engine", `
|
|
1167
|
+
logWarning("engine", `mkdir failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1191
1168
|
}
|
|
1192
1169
|
}
|
|
1193
1170
|
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
_isSamePath as isSamePath,
|
|
17
17
|
_shouldReconcileWorktreeDb,
|
|
18
18
|
} from "./auto-worktree-cleanup.js";
|
|
19
|
-
import {
|
|
19
|
+
import { resolveGsdPathContract } from "./paths.js";
|
|
20
20
|
import type { MilestoneScope } from "./workspace.js";
|
|
21
21
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
22
22
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -211,17 +211,10 @@ function syncMilestoneLayout(
|
|
|
211
211
|
if (!existsSync(mainMilestonesDir)) return;
|
|
212
212
|
|
|
213
213
|
try {
|
|
214
|
+
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
214
215
|
const mainMilestones = readdirSync(mainMilestonesDir, { withFileTypes: true })
|
|
215
216
|
.filter((entry) => entry.isDirectory())
|
|
216
|
-
.map((entry) => entry.name)
|
|
217
|
-
.filter((name) =>
|
|
218
|
-
layoutSegment !== "milestones" ||
|
|
219
|
-
dirIsContentBearingLegacyMilestone(join(mainMilestonesDir, name)),
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
if (mainMilestones.length === 0) return;
|
|
223
|
-
|
|
224
|
-
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
217
|
+
.map((entry) => entry.name);
|
|
225
218
|
|
|
226
219
|
for (const milestoneId of mainMilestones) {
|
|
227
220
|
syncMilestoneDirectory(
|
|
@@ -3163,19 +3163,7 @@ export async function dispatchHookUnit(
|
|
|
3163
3163
|
workspaceRoot: s.basePath,
|
|
3164
3164
|
});
|
|
3165
3165
|
|
|
3166
|
-
const
|
|
3167
|
-
if (typeof cmdCtx?.newSession !== "function") {
|
|
3168
|
-
const message = "Auto-mode has no command context for dispatch.";
|
|
3169
|
-
ctx.ui.notify(message, "error");
|
|
3170
|
-
const unitToCommit = previousCurrentUnit ?? s.currentUnit;
|
|
3171
|
-
if (unitToCommit) {
|
|
3172
|
-
await autoCommitUnit(s.basePath, unitToCommit.type, unitToCommit.id, ctx);
|
|
3173
|
-
}
|
|
3174
|
-
await stopAuto(ctx, pi, message, { preserveWorktree: true });
|
|
3175
|
-
return false;
|
|
3176
|
-
}
|
|
3177
|
-
|
|
3178
|
-
const result = await cmdCtx.newSession({ workspaceRoot: s.basePath });
|
|
3166
|
+
const result = await s.cmdCtx!.newSession({ workspaceRoot: s.basePath });
|
|
3179
3167
|
if (result.cancelled) {
|
|
3180
3168
|
await stopAuto(ctx, pi);
|
|
3181
3169
|
return false;
|
|
@@ -95,25 +95,6 @@ function reportCheckboxDbStatusDivergence(
|
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
function bareDuplicateMilestoneId(milestoneId: string): string | null {
|
|
99
|
-
const match = milestoneId.match(/^(M\d{3})-[a-z0-9]{6}$/i);
|
|
100
|
-
return match?.[1]?.toUpperCase() ?? null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function checkboxDbStatusMilestoneIds(basePath: string, milestoneIds: string[]): string[] {
|
|
104
|
-
if (!hasFlatPhaseLayout(basePath)) return milestoneIds;
|
|
105
|
-
|
|
106
|
-
// Flat-phase directories are keyed by phase number. A restored
|
|
107
|
-
// M003-xxxxxx row alongside M003 is a stale duplicate for the same
|
|
108
|
-
// phases/03-* projection, so checking both can compare DB status against two
|
|
109
|
-
// competing PLAN files and report a persistent false divergence.
|
|
110
|
-
const allIds = new Set(milestoneIds.map((id) => id.toUpperCase()));
|
|
111
|
-
return milestoneIds.filter((milestoneId) => {
|
|
112
|
-
const bareId = bareDuplicateMilestoneId(milestoneId);
|
|
113
|
-
return !bareId || !allIds.has(bareId);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
98
|
function checkProjectionCheckboxDbStatus(basePath: string, milestoneIds: string[], issues: DoctorIssue[]): void {
|
|
118
99
|
for (const milestoneId of milestoneIds) {
|
|
119
100
|
const roadmapPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
@@ -453,9 +434,7 @@ function staleMilestonesArtifactRowFixable(basePath: string, row: ArtifactRow, a
|
|
|
453
434
|
|
|
454
435
|
function stalePhasesArtifactRowFixable(basePath: string, row: ArtifactRow, artifactRows: ArtifactRow[]): boolean {
|
|
455
436
|
const issuePath = artifactPathRelativeToGsd(row.path);
|
|
456
|
-
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) &&
|
|
457
|
-
(hasPresentFlatPhaseReplacement(basePath, row, artifactRows) ||
|
|
458
|
-
hasPresentMilestonesReplacement(basePath, row, artifactRows));
|
|
437
|
+
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) && hasPresentMilestonesReplacement(basePath, row, artifactRows);
|
|
459
438
|
}
|
|
460
439
|
|
|
461
440
|
function staleArtifactRowFixable(basePath: string, row: ArtifactRow, artifactRows: ArtifactRow[]): boolean {
|
|
@@ -828,11 +807,7 @@ export async function checkEngineHealth(
|
|
|
828
807
|
// block doctor.
|
|
829
808
|
try {
|
|
830
809
|
if (isDbAvailable()) {
|
|
831
|
-
checkProjectionCheckboxDbStatus(
|
|
832
|
-
basePath,
|
|
833
|
-
checkboxDbStatusMilestoneIds(basePath, getAllMilestones().map((milestone) => milestone.id)),
|
|
834
|
-
issues,
|
|
835
|
-
);
|
|
810
|
+
checkProjectionCheckboxDbStatus(basePath, getAllMilestones().map((milestone) => milestone.id), issues);
|
|
836
811
|
}
|
|
837
812
|
} catch {
|
|
838
813
|
// Non-fatal: checkbox-vs-DB divergence check must never block doctor
|
|
@@ -155,19 +155,6 @@ function isInsideFlatProjectionBackup(backupDir: string, src: string): boolean {
|
|
|
155
155
|
return src === phaseBackupDir || src.startsWith(`${phaseBackupDir}/`) || src.startsWith(`${phaseBackupDir}\\`);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
function removeFlatProjectionBackup(backupDir: string): void {
|
|
159
|
-
const phaseBackupDir = join(backupDir, "__phases");
|
|
160
|
-
if (!existsSync(phaseBackupDir)) return;
|
|
161
|
-
try {
|
|
162
|
-
removePathWithRetries(phaseBackupDir);
|
|
163
|
-
} catch (err) {
|
|
164
|
-
logWarning(
|
|
165
|
-
"migration",
|
|
166
|
-
`flat-phase migration succeeded but could not remove temporary ${LAYOUT_SEGMENTS.level1}/ backup: ${(err as Error).message}`,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
158
|
function restoreFlatProjectionFromBackup(basePath: string, backupDir: string): void {
|
|
172
159
|
const phaseBackupDir = join(backupDir, "__phases");
|
|
173
160
|
if (!existsSync(phaseBackupDir)) return;
|
|
@@ -507,5 +494,4 @@ export async function migrateToFlatPhase(basePath: string): Promise<void> {
|
|
|
507
494
|
`flat-phase migration succeeded but could not remove ${LEGACY_MIGRATING_SEGMENT}: ${(err as Error).message}`,
|
|
508
495
|
);
|
|
509
496
|
}
|
|
510
|
-
removeFlatProjectionBackup(backupDir);
|
|
511
497
|
}
|
|
@@ -67,13 +67,6 @@ export type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
|
|
|
67
67
|
|
|
68
68
|
import { TERMINAL_STATUS_SQL } from "./db/sql-constants.js";
|
|
69
69
|
import { applyStatusTransition } from "./db/writers/status.js";
|
|
70
|
-
import {
|
|
71
|
-
LAYOUT_SEGMENTS,
|
|
72
|
-
derivePhaseSlug,
|
|
73
|
-
milestoneIdToPhaseNum,
|
|
74
|
-
milestoneIdUniqueSuffix,
|
|
75
|
-
phaseDirName,
|
|
76
|
-
} from "./layout-policy.js";
|
|
77
70
|
|
|
78
71
|
export function insertDecision(d: Omit<Decision, "seq">): void {
|
|
79
72
|
if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
@@ -213,47 +206,6 @@ export function insertArtifact(a: {
|
|
|
213
206
|
});
|
|
214
207
|
}
|
|
215
208
|
|
|
216
|
-
function canonicalPhaseDirNameForDb(milestoneId: string, title: string): string {
|
|
217
|
-
const phaseNum = milestoneIdToPhaseNum(milestoneId);
|
|
218
|
-
const slug = derivePhaseSlug(title || milestoneId);
|
|
219
|
-
const suffix = milestoneIdUniqueSuffix(milestoneId);
|
|
220
|
-
return phaseDirName(phaseNum, suffix ? `${suffix}-${slug}` : slug);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function reconcileMilestonePhaseArtifactPaths(milestoneId: string, title: string): void {
|
|
224
|
-
const db = getDbOrNull()!;
|
|
225
|
-
const phaseNumPrefix = String(milestoneIdToPhaseNum(milestoneId)).padStart(2, "0");
|
|
226
|
-
const canonicalDir = canonicalPhaseDirNameForDb(milestoneId, title);
|
|
227
|
-
const staleRows = db.prepare(
|
|
228
|
-
`SELECT path
|
|
229
|
-
FROM artifacts
|
|
230
|
-
WHERE milestone_id = :milestone_id
|
|
231
|
-
AND path LIKE :phase_prefix`,
|
|
232
|
-
).all({
|
|
233
|
-
":milestone_id": milestoneId,
|
|
234
|
-
":phase_prefix": `${LAYOUT_SEGMENTS.level1}/${phaseNumPrefix}-%/%`,
|
|
235
|
-
}) as Array<{ path: string }>;
|
|
236
|
-
|
|
237
|
-
const updatePath = db.prepare("UPDATE artifacts SET path = :new_path WHERE path = :old_path");
|
|
238
|
-
const deletePath = db.prepare("DELETE FROM artifacts WHERE path = :path");
|
|
239
|
-
const existingPath = db.prepare("SELECT 1 AS present FROM artifacts WHERE path = :path");
|
|
240
|
-
|
|
241
|
-
for (const row of staleRows) {
|
|
242
|
-
const parts = row.path.split("/");
|
|
243
|
-
if (parts.length < 3) continue;
|
|
244
|
-
if (parts[0] !== LAYOUT_SEGMENTS.level1) continue;
|
|
245
|
-
if (parts[1] === canonicalDir) continue;
|
|
246
|
-
if (!parts[1]?.startsWith(`${phaseNumPrefix}-`)) continue;
|
|
247
|
-
|
|
248
|
-
const newPath = [LAYOUT_SEGMENTS.level1, canonicalDir, ...parts.slice(2)].join("/");
|
|
249
|
-
if (existingPath.get({ ":path": newPath })) {
|
|
250
|
-
deletePath.run({ ":path": row.path });
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
253
|
-
updatePath.run({ ":new_path": newPath, ":old_path": row.path });
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
209
|
export interface MilestonePlanningRecord {
|
|
258
210
|
vision: string;
|
|
259
211
|
successCriteria: string[];
|
|
@@ -335,43 +287,39 @@ export function insertMilestone(m: {
|
|
|
335
287
|
|
|
336
288
|
export function upsertMilestonePlanning(milestoneId: string, planning: Partial<MilestonePlanningRecord> & { title?: string; status?: string; depends_on?: string[] }): void {
|
|
337
289
|
if (!getDbOrNull()!) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
":boundary_map_markdown": planning.boundaryMapMarkdown ?? null,
|
|
372
|
-
});
|
|
373
|
-
const finalTitle = planning.title?.trim();
|
|
374
|
-
if (finalTitle) reconcileMilestonePhaseArtifactPaths(milestoneId, finalTitle);
|
|
290
|
+
getDbOrNull()!.prepare(
|
|
291
|
+
`UPDATE milestones SET
|
|
292
|
+
title = COALESCE(NULLIF(:title, ''), title),
|
|
293
|
+
status = COALESCE(NULLIF(:status, ''), status),
|
|
294
|
+
depends_on = COALESCE(:depends_on, depends_on),
|
|
295
|
+
vision = COALESCE(:vision, vision),
|
|
296
|
+
success_criteria = COALESCE(:success_criteria, success_criteria),
|
|
297
|
+
key_risks = COALESCE(:key_risks, key_risks),
|
|
298
|
+
proof_strategy = COALESCE(:proof_strategy, proof_strategy),
|
|
299
|
+
verification_contract = COALESCE(:verification_contract, verification_contract),
|
|
300
|
+
verification_integration = COALESCE(:verification_integration, verification_integration),
|
|
301
|
+
verification_operational = COALESCE(:verification_operational, verification_operational),
|
|
302
|
+
verification_uat = COALESCE(:verification_uat, verification_uat),
|
|
303
|
+
definition_of_done = COALESCE(:definition_of_done, definition_of_done),
|
|
304
|
+
requirement_coverage = COALESCE(:requirement_coverage, requirement_coverage),
|
|
305
|
+
boundary_map_markdown = COALESCE(:boundary_map_markdown, boundary_map_markdown)
|
|
306
|
+
WHERE id = :id`,
|
|
307
|
+
).run({
|
|
308
|
+
":id": milestoneId,
|
|
309
|
+
":title": planning.title ?? "",
|
|
310
|
+
":status": planning.status ?? "",
|
|
311
|
+
":depends_on": planning.depends_on ? JSON.stringify(planning.depends_on) : null,
|
|
312
|
+
":vision": planning.vision ?? null,
|
|
313
|
+
":success_criteria": planning.successCriteria ? JSON.stringify(planning.successCriteria) : null,
|
|
314
|
+
":key_risks": planning.keyRisks ? JSON.stringify(planning.keyRisks) : null,
|
|
315
|
+
":proof_strategy": planning.proofStrategy ? JSON.stringify(planning.proofStrategy) : null,
|
|
316
|
+
":verification_contract": planning.verificationContract ?? null,
|
|
317
|
+
":verification_integration": planning.verificationIntegration ?? null,
|
|
318
|
+
":verification_operational": planning.verificationOperational ?? null,
|
|
319
|
+
":verification_uat": planning.verificationUat ?? null,
|
|
320
|
+
":definition_of_done": planning.definitionOfDone ? JSON.stringify(planning.definitionOfDone) : null,
|
|
321
|
+
":requirement_coverage": planning.requirementCoverage ?? null,
|
|
322
|
+
":boundary_map_markdown": planning.boundaryMapMarkdown ?? null,
|
|
375
323
|
});
|
|
376
324
|
}
|
|
377
325
|
|