gsd-pi 2.78.1-dev.b6a389b66 → 2.78.1-dev.d8826a445
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/phases.js +7 -2
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +3 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
- package/dist/resources/extensions/gsd/auto-worktree.js +185 -40
- package/dist/resources/extensions/gsd/auto.js +62 -1
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -16
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +67 -55
- package/dist/resources/extensions/gsd/db-writer.js +96 -16
- package/dist/resources/extensions/gsd/delegation-policy.js +155 -0
- package/dist/resources/extensions/gsd/gsd-db.js +194 -0
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +117 -25
- package/dist/resources/extensions/gsd/metrics.js +287 -1
- package/dist/resources/extensions/gsd/paths.js +79 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
- package/dist/resources/extensions/gsd/templates/project.md +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/workspace.js +59 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +15 -2
- package/dist/resources/extensions/gsd/write-intercept.js +3 -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 +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/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.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/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/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/mcp-server/README.md +2 -11
- package/packages/mcp-server/dist/remote-questions.d.ts +27 -0
- package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
- package/packages/mcp-server/dist/remote-questions.js +28 -0
- package/packages/mcp-server/dist/remote-questions.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts +28 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +94 -4
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +226 -0
- package/packages/mcp-server/src/remote-questions.test.ts +103 -0
- package/packages/mcp-server/src/remote-questions.ts +35 -0
- package/packages/mcp-server/src/server.ts +129 -6
- package/packages/mcp-server/src/workflow-tools.ts +1 -1
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/phases.ts +8 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +10 -2
- package/src/resources/extensions/gsd/auto-post-unit.ts +8 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +225 -47
- package/src/resources/extensions/gsd/auto.ts +79 -1
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +17 -17
- package/src/resources/extensions/gsd/bootstrap/tests/write-gate-basepath.test.ts +103 -0
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -55
- package/src/resources/extensions/gsd/db-writer.ts +113 -17
- package/src/resources/extensions/gsd/delegation-policy.ts +197 -0
- package/src/resources/extensions/gsd/gsd-db.ts +184 -0
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +154 -25
- package/src/resources/extensions/gsd/metrics.ts +321 -1
- package/src/resources/extensions/gsd/paths.ts +67 -8
- package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -3
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +8 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +22 -7
- package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +6 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -1
- package/src/resources/extensions/gsd/templates/project.md +10 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +14 -14
- package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +331 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/db-writer-path-containment.test.ts +152 -0
- package/src/resources/extensions/gsd/tests/db-writer-root-artifact.test.ts +221 -0
- package/src/resources/extensions/gsd/tests/db-writer-scope.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/delegation-policy.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/dispatch-backgroundable-annotation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/draft-promotion.test.ts +3 -23
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +193 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +246 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +218 -0
- package/src/resources/extensions/gsd/tests/gsd-db-failed-open-restore.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/gsd-db-workspace-scope.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/gsd-root-canonical.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/gsd-root-home-guard.test.ts +68 -5
- package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +371 -0
- package/src/resources/extensions/gsd/tests/metrics-atomic-merge.test.ts +222 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-hardening.test.ts +400 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-not-acquired.test.ts +141 -0
- package/src/resources/extensions/gsd/tests/metrics-lock-retry-sleep.test.ts +287 -0
- package/src/resources/extensions/gsd/tests/metrics-prune-cache-invalidation.test.ts +149 -0
- package/src/resources/extensions/gsd/tests/metrics-scope.test.ts +378 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +329 -0
- package/src/resources/extensions/gsd/tests/path-cache-decoupled.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/path-normalization-unified.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/paths-cache.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +150 -7
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +28 -16
- package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +162 -0
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +239 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/workspace.test.ts +190 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +35 -35
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -52
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +1 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/workspace.ts +95 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +16 -2
- package/src/resources/extensions/gsd/write-intercept.ts +3 -3
- /package/dist/web/standalone/.next/static/{HahrZrc_Xn4wumj0O1Ydp → AT5qi39nKXkdmQIOIoh0f}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{HahrZrc_Xn4wumj0O1Ydp → AT5qi39nKXkdmQIOIoh0f}/_ssgManifest.js +0 -0
|
@@ -76,6 +76,7 @@ import {
|
|
|
76
76
|
nativeMergeAbort,
|
|
77
77
|
} from "./native-git-bridge.js";
|
|
78
78
|
import { gsdHome } from "./gsd-home.js";
|
|
79
|
+
import { type MilestoneScope, type GsdWorkspace, createWorkspace } from "./workspace.js";
|
|
79
80
|
|
|
80
81
|
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
81
82
|
const LEGACY_PROJECT_PREFERENCES_FILE = "preferences.md";
|
|
@@ -254,8 +255,16 @@ function forceOverwriteAssessmentsWithVerdict(
|
|
|
254
255
|
|
|
255
256
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
256
257
|
|
|
257
|
-
/**
|
|
258
|
-
let
|
|
258
|
+
/** Active workspace registry — replaces the legacy `originalBase` singleton. */
|
|
259
|
+
let activeWorkspace: GsdWorkspace | null = null;
|
|
260
|
+
|
|
261
|
+
function setActiveWorkspace(ws: GsdWorkspace | null): void {
|
|
262
|
+
activeWorkspace = ws;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getActiveWorkspace(): GsdWorkspace | null {
|
|
266
|
+
return activeWorkspace;
|
|
267
|
+
}
|
|
259
268
|
|
|
260
269
|
function clearProjectRootStateFiles(basePath: string, milestoneId: string): void {
|
|
261
270
|
const gsdDir = gsdRoot(basePath);
|
|
@@ -345,6 +354,41 @@ export const isSafeToAutoResolve = (filePath: string): boolean =>
|
|
|
345
354
|
* gsd.db in the worktree so it rebuilds from fresh disk state (#853).
|
|
346
355
|
* Non-fatal — sync failure should never block dispatch.
|
|
347
356
|
*/
|
|
357
|
+
/**
|
|
358
|
+
* Scope-typed variant of syncProjectRootToWorktree.
|
|
359
|
+
*
|
|
360
|
+
* Takes an explicit (rootScope, worktreeScope) pair where rootScope is the
|
|
361
|
+
* project root and worktreeScope is the auto-worktree. Direction is encoded
|
|
362
|
+
* in argument order. Asserts both scopes belong to the same workspace identity
|
|
363
|
+
* to prevent silent mismatch bugs.
|
|
364
|
+
*/
|
|
365
|
+
export function syncProjectRootToWorktreeByScope(
|
|
366
|
+
rootScope: MilestoneScope,
|
|
367
|
+
worktreeScope: MilestoneScope,
|
|
368
|
+
): void {
|
|
369
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
370
|
+
throw new Error(
|
|
371
|
+
`syncProjectRootToWorktreeByScope: scope identity mismatch — ` +
|
|
372
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
373
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`syncProjectRootToWorktreeByScope: milestoneId mismatch — ` +
|
|
379
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
383
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
384
|
+
const milestoneId = rootScope.milestoneId;
|
|
385
|
+
syncProjectRootToWorktree(projectRoot, worktreePath_, milestoneId);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* @deprecated Use syncProjectRootToWorktreeByScope instead.
|
|
390
|
+
* TODO(C-future): remove once all callers migrated.
|
|
391
|
+
*/
|
|
348
392
|
export function syncProjectRootToWorktree(
|
|
349
393
|
projectRoot: string,
|
|
350
394
|
worktreePath_: string,
|
|
@@ -430,12 +474,44 @@ export function syncProjectRootToWorktree(
|
|
|
430
474
|
}
|
|
431
475
|
}
|
|
432
476
|
|
|
477
|
+
/**
|
|
478
|
+
* Scope-typed variant of syncStateToProjectRoot.
|
|
479
|
+
*
|
|
480
|
+
* Takes an explicit (worktreeScope, rootScope) pair. Direction is encoded in
|
|
481
|
+
* argument order (worktree → root). Asserts both scopes belong to the same
|
|
482
|
+
* workspace identity to prevent silent mismatch bugs.
|
|
483
|
+
*/
|
|
484
|
+
export function syncStateToProjectRootByScope(
|
|
485
|
+
worktreeScope: MilestoneScope,
|
|
486
|
+
rootScope: MilestoneScope,
|
|
487
|
+
): void {
|
|
488
|
+
if (worktreeScope.workspace.identityKey !== rootScope.workspace.identityKey) {
|
|
489
|
+
throw new Error(
|
|
490
|
+
`syncStateToProjectRootByScope: scope identity mismatch — ` +
|
|
491
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}" ` +
|
|
492
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}"`,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
if (worktreeScope.milestoneId !== rootScope.milestoneId) {
|
|
496
|
+
throw new Error(
|
|
497
|
+
`syncStateToProjectRootByScope: milestoneId mismatch — ` +
|
|
498
|
+
`worktreeScope.milestoneId="${worktreeScope.milestoneId}" rootScope.milestoneId="${rootScope.milestoneId}"`,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
502
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
503
|
+
const milestoneId = worktreeScope.milestoneId;
|
|
504
|
+
syncStateToProjectRoot(worktreePath_, projectRoot, milestoneId);
|
|
505
|
+
}
|
|
506
|
+
|
|
433
507
|
/**
|
|
434
508
|
* Sync worktree diagnostics from worktree to project root.
|
|
435
509
|
* Only runs when inside an auto-worktree (worktreePath differs from projectRoot).
|
|
436
510
|
* DB/project-root state remains authoritative; markdown projections are not
|
|
437
511
|
* copied from the worktree back to the project root.
|
|
438
512
|
* Non-fatal — sync failure should never block dispatch.
|
|
513
|
+
* @deprecated Use syncStateToProjectRootByScope instead.
|
|
514
|
+
* TODO(C-future): remove once all callers migrated.
|
|
439
515
|
*/
|
|
440
516
|
export function syncStateToProjectRoot(
|
|
441
517
|
worktreePath_: string,
|
|
@@ -625,6 +701,30 @@ export function cleanStaleRuntimeUnits(
|
|
|
625
701
|
|
|
626
702
|
// ─── Worktree ↔ Main Repo Sync (#1311) ──────────────────────────────────────
|
|
627
703
|
|
|
704
|
+
/**
|
|
705
|
+
* Scope-typed variant of syncGsdStateToWorktree.
|
|
706
|
+
*
|
|
707
|
+
* Takes an explicit (rootScope, worktreeScope) pair. Note: milestoneId is not
|
|
708
|
+
* used by syncGsdStateToWorktree — this variant only requires workspace
|
|
709
|
+
* identity. Asserts both scopes belong to the same workspace identity to
|
|
710
|
+
* prevent silent mismatch bugs.
|
|
711
|
+
*/
|
|
712
|
+
export function syncGsdStateToWorktreeByScope(
|
|
713
|
+
rootScope: MilestoneScope,
|
|
714
|
+
worktreeScope: MilestoneScope,
|
|
715
|
+
): { synced: string[] } {
|
|
716
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
717
|
+
throw new Error(
|
|
718
|
+
`syncGsdStateToWorktreeByScope: scope identity mismatch — ` +
|
|
719
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
720
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
const mainBasePath = rootScope.workspace.projectRoot;
|
|
724
|
+
const worktreePath_ = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
725
|
+
return syncGsdStateToWorktree(mainBasePath, worktreePath_);
|
|
726
|
+
}
|
|
727
|
+
|
|
628
728
|
/**
|
|
629
729
|
* Sync .gsd/ state from the main repo into the worktree.
|
|
630
730
|
*
|
|
@@ -639,6 +739,8 @@ export function cleanStaleRuntimeUnits(
|
|
|
639
739
|
* Only adds missing content — never overwrites existing files in the worktree.
|
|
640
740
|
* Worktree files are compatibility projections; DB/project root remains
|
|
641
741
|
* authoritative for runtime state.
|
|
742
|
+
* @deprecated Use syncGsdStateToWorktreeByScope instead.
|
|
743
|
+
* TODO(C-future): remove once all callers migrated.
|
|
642
744
|
*/
|
|
643
745
|
export function syncGsdStateToWorktree(
|
|
644
746
|
mainBasePath: string,
|
|
@@ -1042,6 +1144,40 @@ export function enterBranchModeForMilestone(
|
|
|
1042
1144
|
* remains authoritative; this never downgrades checked boxes in a local
|
|
1043
1145
|
* worktree projection.
|
|
1044
1146
|
*/
|
|
1147
|
+
/**
|
|
1148
|
+
* Scope-typed variant of reconcilePlanCheckboxes.
|
|
1149
|
+
*
|
|
1150
|
+
* Takes an explicit (rootScope, worktreeScope) pair. milestoneId is taken
|
|
1151
|
+
* from rootScope. Asserts both scopes belong to the same workspace identity
|
|
1152
|
+
* to prevent silent mismatch bugs.
|
|
1153
|
+
*/
|
|
1154
|
+
export function reconcilePlanCheckboxesByScope(
|
|
1155
|
+
rootScope: MilestoneScope,
|
|
1156
|
+
worktreeScope: MilestoneScope,
|
|
1157
|
+
): void {
|
|
1158
|
+
if (rootScope.workspace.identityKey !== worktreeScope.workspace.identityKey) {
|
|
1159
|
+
throw new Error(
|
|
1160
|
+
`reconcilePlanCheckboxesByScope: scope identity mismatch — ` +
|
|
1161
|
+
`rootScope.identityKey="${rootScope.workspace.identityKey}" ` +
|
|
1162
|
+
`worktreeScope.identityKey="${worktreeScope.workspace.identityKey}"`,
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (rootScope.milestoneId !== worktreeScope.milestoneId) {
|
|
1166
|
+
throw new Error(
|
|
1167
|
+
`reconcilePlanCheckboxesByScope: milestoneId mismatch — ` +
|
|
1168
|
+
`rootScope.milestoneId="${rootScope.milestoneId}" worktreeScope.milestoneId="${worktreeScope.milestoneId}"`,
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
const projectRoot = rootScope.workspace.projectRoot;
|
|
1172
|
+
const wtPath = worktreeScope.workspace.worktreeRoot ?? worktreeScope.workspace.projectRoot;
|
|
1173
|
+
const milestoneId = rootScope.milestoneId;
|
|
1174
|
+
reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId);
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* @deprecated Use reconcilePlanCheckboxesByScope instead.
|
|
1179
|
+
* TODO(C-future): remove once all callers migrated.
|
|
1180
|
+
*/
|
|
1045
1181
|
function reconcilePlanCheckboxes(
|
|
1046
1182
|
projectRoot: string,
|
|
1047
1183
|
wtPath: string,
|
|
@@ -1218,10 +1354,10 @@ export function createAutoWorktree(
|
|
|
1218
1354
|
|
|
1219
1355
|
try {
|
|
1220
1356
|
process.chdir(info.path);
|
|
1221
|
-
|
|
1357
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1222
1358
|
} catch (err) {
|
|
1223
1359
|
// If chdir fails, the worktree was created but we couldn't enter it.
|
|
1224
|
-
// Don't
|
|
1360
|
+
// Don't set activeWorkspace -- caller can retry or clean up.
|
|
1225
1361
|
throw new GSDError(
|
|
1226
1362
|
GSD_IO_ERROR,
|
|
1227
1363
|
`Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -1302,48 +1438,87 @@ export function teardownAutoWorktree(
|
|
|
1302
1438
|
const { preserveBranch = false } = opts;
|
|
1303
1439
|
const previousCwd = process.cwd();
|
|
1304
1440
|
|
|
1441
|
+
// Wrap the entire teardown body in a single try/finally so activeWorkspace
|
|
1442
|
+
// is ALWAYS cleared — even if process.chdir throws (e.g. originalBasePath
|
|
1443
|
+
// was deleted before teardown ran). Previously the finally only covered
|
|
1444
|
+
// removeWorktree, leaving the registry stale on a chdir failure (H3 fix).
|
|
1305
1445
|
try {
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1446
|
+
try {
|
|
1447
|
+
process.chdir(originalBasePath);
|
|
1448
|
+
} catch (err) {
|
|
1449
|
+
throw new GSDError(
|
|
1450
|
+
GSD_IO_ERROR,
|
|
1451
|
+
`Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`,
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1314
1454
|
|
|
1315
|
-
|
|
1316
|
-
removeWorktree(originalBasePath, milestoneId, {
|
|
1317
|
-
branch,
|
|
1318
|
-
deleteBranch: !preserveBranch,
|
|
1319
|
-
});
|
|
1455
|
+
// Mirror cleanup steps from mergeMilestoneToMain abort path:
|
|
1320
1456
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
);
|
|
1333
|
-
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1334
|
-
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1335
|
-
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1457
|
+
// 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
|
|
1458
|
+
// Non-fatal — must not block teardown.
|
|
1459
|
+
try {
|
|
1460
|
+
clearProjectRootStateFiles(originalBasePath, milestoneId);
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
logWarning("worktree", `clearProjectRootStateFiles failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// 2. Reconcile worktree-local gsd.db into project root DB if both exist.
|
|
1466
|
+
// Non-fatal — handles legacy worktrees that have a local copy.
|
|
1467
|
+
if (isDbAvailable()) {
|
|
1336
1468
|
try {
|
|
1337
|
-
|
|
1469
|
+
const contract = resolveGsdPathContract(previousCwd, originalBasePath);
|
|
1470
|
+
const worktreeDbPath = join(contract.worktreeGsd ?? join(previousCwd, ".gsd"), "gsd.db");
|
|
1471
|
+
const mainDbPath = contract.projectDb;
|
|
1472
|
+
if (existsSync(worktreeDbPath) && !isSamePath(worktreeDbPath, mainDbPath)) {
|
|
1473
|
+
reconcileWorktreeDb(mainDbPath, worktreeDbPath);
|
|
1474
|
+
}
|
|
1338
1475
|
} catch (err) {
|
|
1339
|
-
|
|
1340
|
-
|
|
1476
|
+
/* non-fatal */
|
|
1477
|
+
logError("worktree", `DB reconciliation failed during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
1341
1478
|
}
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
nudgeGitBranchCache(previousCwd);
|
|
1482
|
+
|
|
1483
|
+
// 3. Remove the worktree. Errors propagate naturally — the outer finally
|
|
1484
|
+
// ensures activeWorkspace is cleared regardless.
|
|
1485
|
+
removeWorktree(originalBasePath, milestoneId, {
|
|
1486
|
+
branch,
|
|
1487
|
+
deleteBranch: !preserveBranch,
|
|
1488
|
+
});
|
|
1489
|
+
|
|
1490
|
+
// Verify cleanup succeeded — warn if the worktree directory is still on disk.
|
|
1491
|
+
// On Windows, bash-based cleanup can silently fail when paths contain
|
|
1492
|
+
// backslashes (#1436), leaving ~1 GB+ orphaned directories.
|
|
1493
|
+
const wtDir = worktreePath(originalBasePath, milestoneId);
|
|
1494
|
+
if (existsSync(wtDir)) {
|
|
1495
|
+
logWarning(
|
|
1496
|
+
"reconcile",
|
|
1497
|
+
`Worktree directory still exists after teardown: ${wtDir}. ` +
|
|
1498
|
+
`This is likely an orphaned directory consuming disk space. ` +
|
|
1499
|
+
`Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`,
|
|
1500
|
+
{ worktree: milestoneId },
|
|
1345
1501
|
);
|
|
1502
|
+
// Attempt a direct filesystem removal as a fallback — but ONLY if the
|
|
1503
|
+
// path is safely inside .gsd/worktrees/ to prevent #2365 data loss.
|
|
1504
|
+
if (isInsideWorktreesDir(originalBasePath, wtDir)) {
|
|
1505
|
+
try {
|
|
1506
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
1507
|
+
} catch (err) {
|
|
1508
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
1509
|
+
logWarning("worktree", `worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1510
|
+
}
|
|
1511
|
+
} else {
|
|
1512
|
+
console.error(
|
|
1513
|
+
`[GSD] REFUSING fallback rmSync — path is outside .gsd/worktrees/: ${wtDir}`,
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1346
1516
|
}
|
|
1517
|
+
} finally {
|
|
1518
|
+
// Clear module state unconditionally — regardless of which step above
|
|
1519
|
+
// failed. A stale activeWorkspace causes getActiveAutoWorktreeContext()
|
|
1520
|
+
// to return wrong data for subsequent operations.
|
|
1521
|
+
setActiveWorkspace(null);
|
|
1347
1522
|
}
|
|
1348
1523
|
}
|
|
1349
1524
|
|
|
@@ -1356,8 +1531,9 @@ export function isInAutoWorktree(basePath: string): boolean {
|
|
|
1356
1531
|
const targetPath = isGsdWorktreePath(basePath) ? basePath : process.cwd();
|
|
1357
1532
|
if (!isGsdWorktreePath(targetPath)) return false;
|
|
1358
1533
|
|
|
1359
|
-
const
|
|
1360
|
-
const
|
|
1534
|
+
const storedBase = getAutoWorktreeOriginalBase();
|
|
1535
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath, storedBase);
|
|
1536
|
+
const targetProjectRoot = resolveWorktreeProjectRoot(targetPath, storedBase);
|
|
1361
1537
|
if (
|
|
1362
1538
|
normalizeWorktreePathForCompare(projectRoot) !==
|
|
1363
1539
|
normalizeWorktreePathForCompare(targetProjectRoot)
|
|
@@ -1453,7 +1629,7 @@ export function enterAutoWorktree(
|
|
|
1453
1629
|
|
|
1454
1630
|
try {
|
|
1455
1631
|
process.chdir(p);
|
|
1456
|
-
|
|
1632
|
+
setActiveWorkspace(createWorkspace(basePath));
|
|
1457
1633
|
} catch (err) {
|
|
1458
1634
|
throw new GSDError(
|
|
1459
1635
|
GSD_IO_ERROR,
|
|
@@ -1470,11 +1646,11 @@ export function enterAutoWorktree(
|
|
|
1470
1646
|
* Returns null if not currently in an auto-worktree.
|
|
1471
1647
|
*/
|
|
1472
1648
|
export function getAutoWorktreeOriginalBase(): string | null {
|
|
1473
|
-
return
|
|
1649
|
+
return getActiveWorkspace()?.projectRoot ?? null;
|
|
1474
1650
|
}
|
|
1475
1651
|
|
|
1476
1652
|
export function _resetAutoWorktreeOriginalBaseForTests(): void {
|
|
1477
|
-
|
|
1653
|
+
setActiveWorkspace(null);
|
|
1478
1654
|
}
|
|
1479
1655
|
|
|
1480
1656
|
export function getActiveAutoWorktreeContext(): {
|
|
@@ -1482,7 +1658,9 @@ export function getActiveAutoWorktreeContext(): {
|
|
|
1482
1658
|
worktreeName: string;
|
|
1483
1659
|
branch: string;
|
|
1484
1660
|
} | null {
|
|
1485
|
-
|
|
1661
|
+
const ws = getActiveWorkspace();
|
|
1662
|
+
if (!ws) return null;
|
|
1663
|
+
const originalBase = ws.projectRoot;
|
|
1486
1664
|
const cwd = process.cwd();
|
|
1487
1665
|
if (!isGsdWorktreePath(cwd)) return null;
|
|
1488
1666
|
const cwdProjectRoot = resolveWorktreeProjectRoot(cwd, originalBase);
|
|
@@ -1563,11 +1741,11 @@ export function mergeMilestoneToMain(
|
|
|
1563
1741
|
// integration branch captures dirty files from OTHER milestones under a
|
|
1564
1742
|
// misleading commit message, contaminating the main branch (#2929).
|
|
1565
1743
|
//
|
|
1566
|
-
// When
|
|
1744
|
+
// When activeWorkspace is null (branch mode, no worktree), autoCommitDirtyState
|
|
1567
1745
|
// runs unconditionally — the caller is responsible for cwd placement.
|
|
1568
1746
|
{
|
|
1569
1747
|
let shouldAutoCommit = true;
|
|
1570
|
-
if (
|
|
1748
|
+
if (getActiveWorkspace() !== null) {
|
|
1571
1749
|
try {
|
|
1572
1750
|
const currentBranch = nativeGetCurrentBranch(worktreeCwd);
|
|
1573
1751
|
shouldAutoCommit = currentBranch === milestoneBranch;
|
|
@@ -2302,7 +2480,7 @@ export function mergeMilestoneToMain(
|
|
|
2302
2480
|
}
|
|
2303
2481
|
|
|
2304
2482
|
// 14. Clear module state
|
|
2305
|
-
|
|
2483
|
+
setActiveWorkspace(null);
|
|
2306
2484
|
nudgeGitBranchCache(previousCwd);
|
|
2307
2485
|
|
|
2308
2486
|
// 15. Anchor cwd at the project root on success-return. Step 12 removed
|
|
@@ -256,6 +256,7 @@ export type {
|
|
|
256
256
|
} from "./auto/session.js";
|
|
257
257
|
import { autoSession as s } from "./auto-runtime-state.js";
|
|
258
258
|
import { gsdHome } from "./gsd-home.js";
|
|
259
|
+
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
259
260
|
|
|
260
261
|
// ── ENCAPSULATION INVARIANT ─────────────────────────────────────────────────
|
|
261
262
|
// ALL mutable auto-mode state lives in the AutoSession class (auto/session.ts).
|
|
@@ -324,6 +325,32 @@ function restoreMilestoneLockEnv(): void {
|
|
|
324
325
|
s.milestoneLockEnvCaptured = false;
|
|
325
326
|
}
|
|
326
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Rebuild s.scope from the current s.basePath / s.originalBasePath / s.currentMilestoneId.
|
|
330
|
+
*
|
|
331
|
+
* Pass the worktree path as rawPath when entering a worktree so createWorkspace
|
|
332
|
+
* can detect the worktree layout and set mode="worktree". When no worktree is
|
|
333
|
+
* active, rawPath should equal the project root.
|
|
334
|
+
*
|
|
335
|
+
* Clears s.scope when milestoneId is absent — scope is only meaningful when a
|
|
336
|
+
* milestone is active.
|
|
337
|
+
*
|
|
338
|
+
* TODO(C8): remove basePath/originalBasePath once all readers use s.scope.
|
|
339
|
+
*/
|
|
340
|
+
function rebuildScope(rawPath: string, milestoneId: string | null): void {
|
|
341
|
+
if (!milestoneId) {
|
|
342
|
+
s.scope = null;
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
const workspace = createWorkspace(rawPath);
|
|
347
|
+
s.scope = scopeMilestone(workspace, milestoneId);
|
|
348
|
+
} catch {
|
|
349
|
+
// Non-fatal — scope is additive. Existing readers still use basePath.
|
|
350
|
+
s.scope = null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
327
354
|
function normalizeSessionFilePath(raw: unknown): string | null {
|
|
328
355
|
if (typeof raw !== "string") return null;
|
|
329
356
|
const trimmed = raw.trim();
|
|
@@ -509,6 +536,26 @@ export function _setAutoActiveForTest(active: boolean): void {
|
|
|
509
536
|
s.active = active;
|
|
510
537
|
}
|
|
511
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Test-only seam: emit the missing-worktree warning exactly as the resume path
|
|
541
|
+
* does. Allows unit tests to verify the warning is produced without
|
|
542
|
+
* bootstrapping the full auto-mode entry point. Do not use in production code.
|
|
543
|
+
*/
|
|
544
|
+
export function _warnIfWorktreeMissingForTest(
|
|
545
|
+
worktreePath: string | null | undefined,
|
|
546
|
+
milestoneId: string,
|
|
547
|
+
): boolean {
|
|
548
|
+
if (worktreePath && !existsSync(worktreePath)) {
|
|
549
|
+
logWarning(
|
|
550
|
+
"session",
|
|
551
|
+
`Worktree was expected at ${worktreePath} but is missing. Continuing in project-root mode. To restart with a fresh worktree, run /gsd-debug or recreate the milestone.`,
|
|
552
|
+
{ file: "auto.ts", milestoneId },
|
|
553
|
+
);
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
|
|
512
559
|
export function isAutoPaused(): boolean {
|
|
513
560
|
return s.paused;
|
|
514
561
|
}
|
|
@@ -1553,6 +1600,22 @@ export async function startAuto(
|
|
|
1553
1600
|
s.autoStartTime = meta.autoStartTime || Date.now();
|
|
1554
1601
|
s.sessionMilestoneLock = meta.milestoneLock ?? null;
|
|
1555
1602
|
s.paused = true;
|
|
1603
|
+
// Build scope from persisted state. Use worktreePath when present and
|
|
1604
|
+
// still on disk so mode is detected correctly; fall back to project root.
|
|
1605
|
+
{
|
|
1606
|
+
const persistedWorktreePath = meta.worktreePath ?? null;
|
|
1607
|
+
if (persistedWorktreePath && !existsSync(persistedWorktreePath)) {
|
|
1608
|
+
logWarning(
|
|
1609
|
+
"session",
|
|
1610
|
+
`Worktree was expected at ${persistedWorktreePath} but is missing. Continuing in project-root mode. To restart with a fresh worktree, run /gsd-debug or recreate the milestone.`,
|
|
1611
|
+
{ file: "auto.ts", milestoneId: meta.milestoneId ?? "" },
|
|
1612
|
+
);
|
|
1613
|
+
}
|
|
1614
|
+
const rawForScope = (persistedWorktreePath && existsSync(persistedWorktreePath))
|
|
1615
|
+
? persistedWorktreePath
|
|
1616
|
+
: (s.originalBasePath || base);
|
|
1617
|
+
rebuildScope(rawForScope, s.currentMilestoneId);
|
|
1618
|
+
}
|
|
1556
1619
|
try { unlinkSync(pausedPath); } catch (e) {
|
|
1557
1620
|
if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
1558
1621
|
logWarning("session", `pause file cleanup failed: ${e instanceof Error ? e.message : String(e)}`, { file: "auto.ts" });
|
|
@@ -1637,10 +1700,19 @@ export async function startAuto(
|
|
|
1637
1700
|
// session (e.g. isolation mode changed, detectWorktreeName differs across
|
|
1638
1701
|
// process restarts). We guard with existsSync so a stale or deleted
|
|
1639
1702
|
// worktree directory safely falls back to the project root.
|
|
1640
|
-
const resumeWorktreePath = freshStartAssessment.pausedSession?.worktreePath;
|
|
1703
|
+
const resumeWorktreePath = freshStartAssessment.pausedSession?.worktreePath ?? null;
|
|
1704
|
+
if (resumeWorktreePath && !existsSync(resumeWorktreePath)) {
|
|
1705
|
+
logWarning(
|
|
1706
|
+
"session",
|
|
1707
|
+
`Worktree was expected at ${resumeWorktreePath} but is missing. Continuing in project-root mode. To restart with a fresh worktree, run /gsd-debug or recreate the milestone.`,
|
|
1708
|
+
{ file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" },
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1641
1711
|
if (resumeWorktreePath && existsSync(resumeWorktreePath)) {
|
|
1642
1712
|
s.basePath = resumeWorktreePath;
|
|
1643
1713
|
}
|
|
1714
|
+
// Rebuild scope now that s.basePath reflects the actual worktree (or project root).
|
|
1715
|
+
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
1644
1716
|
// Ensure the workflow-logger audit log is pinned to the project root
|
|
1645
1717
|
// even when auto-mode is entered via a path that bypasses the
|
|
1646
1718
|
// bootstrap/dynamic-tools ensureDbOpen() → setLogBasePath() chain
|
|
@@ -1669,6 +1741,8 @@ export async function startAuto(
|
|
|
1669
1741
|
buildResolver().enterMilestone(s.currentMilestoneId, {
|
|
1670
1742
|
notify: ctx.ui.notify.bind(ctx.ui),
|
|
1671
1743
|
});
|
|
1744
|
+
// s.basePath may have been updated to a worktree path by enterMilestone.
|
|
1745
|
+
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
1672
1746
|
}
|
|
1673
1747
|
|
|
1674
1748
|
registerSigtermHandler(lockBase());
|
|
@@ -1783,6 +1857,10 @@ export async function startAuto(
|
|
|
1783
1857
|
);
|
|
1784
1858
|
if (!ready) return;
|
|
1785
1859
|
|
|
1860
|
+
// Build scope after bootstrap has populated s.basePath / s.originalBasePath /
|
|
1861
|
+
// s.currentMilestoneId (including worktree setup inside bootstrapAutoSession).
|
|
1862
|
+
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
1863
|
+
|
|
1786
1864
|
captureProjectRootEnv(s.originalBasePath || s.basePath);
|
|
1787
1865
|
try {
|
|
1788
1866
|
pi.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "sync" as const, preferences: loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences, state: await deriveState(s.basePath) });
|
|
@@ -76,7 +76,7 @@ export function registerHooks(
|
|
|
76
76
|
const { initHealthWidget } = await import("../health-widget.js");
|
|
77
77
|
initHealthWidget(ctx);
|
|
78
78
|
}
|
|
79
|
-
resetWriteGateState();
|
|
79
|
+
resetWriteGateState(process.cwd());
|
|
80
80
|
resetToolCallLoopGuard();
|
|
81
81
|
approvalQuestionAbortInFlight = false;
|
|
82
82
|
await resetAskUserQuestionsTurnCache();
|
|
@@ -126,10 +126,10 @@ export function registerHooks(
|
|
|
126
126
|
pi.on("session_switch", async (_event, ctx) => {
|
|
127
127
|
initNotificationStore(process.cwd());
|
|
128
128
|
installNotifyInterceptor(ctx);
|
|
129
|
-
resetWriteGateState();
|
|
129
|
+
resetWriteGateState(process.cwd());
|
|
130
130
|
resetToolCallLoopGuard();
|
|
131
131
|
await resetAskUserQuestionsTurnCache();
|
|
132
|
-
clearDiscussionFlowState();
|
|
132
|
+
clearDiscussionFlowState(process.cwd());
|
|
133
133
|
await syncServiceTierStatus(ctx);
|
|
134
134
|
await applyDisabledModelProviderPolicy(ctx);
|
|
135
135
|
// Skip MCP auto-prep when running inside an auto-worktree. The worktree
|
|
@@ -155,12 +155,13 @@ export function registerHooks(
|
|
|
155
155
|
const { getEcosystemReadyPromise } = await import("../ecosystem/loader.js");
|
|
156
156
|
await getEcosystemReadyPromise();
|
|
157
157
|
|
|
158
|
+
const beforeAgentBasePath = process.cwd();
|
|
158
159
|
const pendingApprovalGate = getPendingGate();
|
|
159
160
|
if (pendingApprovalGate && isExplicitApprovalResponse(event.prompt, pendingApprovalGate)) {
|
|
160
|
-
markApprovalGateVerified(pendingApprovalGate);
|
|
161
|
+
markApprovalGateVerified(pendingApprovalGate, beforeAgentBasePath);
|
|
161
162
|
const milestoneId = extractDepthVerificationMilestoneId(pendingApprovalGate);
|
|
162
|
-
if (milestoneId) markDepthVerified(milestoneId);
|
|
163
|
-
clearPendingGate();
|
|
163
|
+
if (milestoneId) markDepthVerified(milestoneId, beforeAgentBasePath);
|
|
164
|
+
clearPendingGate(beforeAgentBasePath);
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
// GSD's own context injection (existing behavior — unchanged).
|
|
@@ -346,7 +347,7 @@ export function registerHooks(
|
|
|
346
347
|
if (!shouldPauseForUserApprovalQuestion(unitType, [event.message])) return;
|
|
347
348
|
|
|
348
349
|
const gateId = approvalGateIdForUnit(unitType, unitId);
|
|
349
|
-
if (gateId) setPendingGate(gateId);
|
|
350
|
+
if (gateId) setPendingGate(gateId, process.cwd());
|
|
350
351
|
|
|
351
352
|
approvalQuestionAbortInFlight = true;
|
|
352
353
|
ctx.ui.notify(
|
|
@@ -393,7 +394,7 @@ export function registerHooks(
|
|
|
393
394
|
const questions: any[] = (event.input as any)?.questions ?? [];
|
|
394
395
|
const questionId = questions.find((question) => typeof question?.id === "string" && isGateQuestionId(question.id))?.id;
|
|
395
396
|
if (typeof questionId === "string") {
|
|
396
|
-
setPendingGate(questionId);
|
|
397
|
+
setPendingGate(questionId, discussionBasePath);
|
|
397
398
|
}
|
|
398
399
|
}
|
|
399
400
|
|
|
@@ -555,7 +556,8 @@ export function registerHooks(
|
|
|
555
556
|
}
|
|
556
557
|
const toolName = canonicalToolName(event.toolName);
|
|
557
558
|
if (toolName !== "ask_user_questions") return;
|
|
558
|
-
const
|
|
559
|
+
const basePath = process.cwd();
|
|
560
|
+
const milestoneId = await getDiscussionMilestoneIdFor(basePath);
|
|
559
561
|
const queueActive = isQueuePhaseActive();
|
|
560
562
|
|
|
561
563
|
const details = event.details as any;
|
|
@@ -588,10 +590,10 @@ export function registerHooks(
|
|
|
588
590
|
if (pendingQuestion) {
|
|
589
591
|
const answer = details.response?.answers?.[currentPendingGate];
|
|
590
592
|
if (isDepthConfirmationAnswer(answer?.selected, pendingQuestion.options)) {
|
|
591
|
-
markApprovalGateVerified(currentPendingGate);
|
|
593
|
+
markApprovalGateVerified(currentPendingGate, basePath);
|
|
592
594
|
const milestoneIdFromGate = extractDepthVerificationMilestoneId(currentPendingGate);
|
|
593
|
-
if (milestoneIdFromGate) markDepthVerified(milestoneIdFromGate);
|
|
594
|
-
clearPendingGate();
|
|
595
|
+
if (milestoneIdFromGate) markDepthVerified(milestoneIdFromGate, basePath);
|
|
596
|
+
clearPendingGate(basePath);
|
|
595
597
|
}
|
|
596
598
|
}
|
|
597
599
|
}
|
|
@@ -607,9 +609,9 @@ export function registerHooks(
|
|
|
607
609
|
const inferredMilestoneId = extractDepthVerificationMilestoneId(question.id) ?? milestoneId;
|
|
608
610
|
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
609
611
|
if (currentPendingGate && question.id !== currentPendingGate) break;
|
|
610
|
-
markApprovalGateVerified(question.id);
|
|
611
|
-
markDepthVerified(inferredMilestoneId);
|
|
612
|
-
clearPendingGate();
|
|
612
|
+
markApprovalGateVerified(question.id, basePath);
|
|
613
|
+
markDepthVerified(inferredMilestoneId, basePath);
|
|
614
|
+
clearPendingGate(basePath);
|
|
613
615
|
}
|
|
614
616
|
break;
|
|
615
617
|
}
|
|
@@ -617,8 +619,6 @@ export function registerHooks(
|
|
|
617
619
|
|
|
618
620
|
if (!milestoneId && !queueActive) return;
|
|
619
621
|
if (!milestoneId) return;
|
|
620
|
-
|
|
621
|
-
const basePath = process.cwd();
|
|
622
622
|
const milestoneDir = resolveMilestonePath(basePath, milestoneId);
|
|
623
623
|
if (!milestoneDir) return;
|
|
624
624
|
|