gsd-pi 2.54.0-dev.e1efc1a → 2.55.0-dev.9ec7cdf
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/cli.js +19 -19
- package/dist/headless-ui.d.ts +27 -1
- package/dist/headless-ui.js +203 -13
- package/dist/headless.js +60 -3
- package/dist/resources/extensions/bg-shell/bg-shell-lifecycle.js +2 -2
- package/dist/resources/extensions/bg-shell/utilities.js +34 -5
- package/dist/resources/extensions/gsd/auto/phases.js +19 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +17 -1
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
- package/dist/resources/extensions/gsd/auto-start.js +12 -5
- package/dist/resources/extensions/gsd/auto-worktree.js +39 -14
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +18 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +18 -5
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +20 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +2 -1
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +15 -1
- package/dist/resources/extensions/gsd/crash-recovery.js +2 -2
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +413 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -1
- package/dist/resources/extensions/gsd/session-lock.js +46 -12
- package/dist/resources/extensions/gsd/skill-health.js +2 -2
- package/dist/resources/extensions/gsd/visualizer-overlay.js +3 -3
- package/dist/resources/extensions/shared/format-utils.js +1 -1
- package/dist/resources/extensions/subagent/worker-registry.js +2 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +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_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/chunks/2229.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.2305d0afd2385711.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-b950e4e384cc62b3.js → page-0c485498795110d6.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{webpack-bca0e732db0dcec3.js → webpack-4332cbd5dd1be584.js} +1 -1
- package/package.json +6 -4
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +14 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +16 -2
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +45 -41
- package/src/resources/extensions/bg-shell/bg-shell-lifecycle.ts +2 -2
- package/src/resources/extensions/bg-shell/utilities.ts +39 -4
- package/src/resources/extensions/gsd/auto/phases.ts +25 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +21 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +15 -0
- package/src/resources/extensions/gsd/auto-start.ts +13 -5
- package/src/resources/extensions/gsd/auto-worktree.ts +46 -13
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +53 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +19 -6
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +24 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +2 -1
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +19 -1
- package/src/resources/extensions/gsd/crash-recovery.ts +2 -3
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +497 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -1
- package/src/resources/extensions/gsd/session-lock.ts +46 -12
- package/src/resources/extensions/gsd/skill-health.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/{all-milestones-complete-merge.test.ts → integration/all-milestones-complete-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{atomic-task-closeout.test.ts → integration/atomic-task-closeout.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{auto-preflight.test.ts → integration/auto-preflight.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{auto-recovery.test.ts → integration/auto-recovery.test.ts} +7 -7
- package/src/resources/extensions/gsd/tests/{auto-secrets-gate.test.ts → integration/auto-secrets-gate.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{auto-stash-merge.test.ts → integration/auto-stash-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{auto-worktree-milestone-merge.test.ts → integration/auto-worktree-milestone-merge.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{auto-worktree.test.ts → integration/auto-worktree.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{continue-here.test.ts → integration/continue-here.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{doctor-completion-deferral.test.ts → integration/doctor-completion-deferral.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-delimiter-fix.test.ts → integration/doctor-delimiter-fix.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-enhancements.test.ts → integration/doctor-enhancements.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{doctor-environment-worktree.test.ts → integration/doctor-environment-worktree.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-environment.test.ts → integration/doctor-environment.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-fixlevel.test.ts → integration/doctor-fixlevel.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{doctor-git.test.ts → integration/doctor-git.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-proactive.test.ts → integration/doctor-proactive.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-roadmap-summary-atomicity.test.ts → integration/doctor-roadmap-summary-atomicity.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor-runtime.test.ts → integration/doctor-runtime.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{doctor.test.ts → integration/doctor.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{e2e-workflow-pipeline-integration.test.ts → integration/e2e-workflow-pipeline-integration.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{feature-branch-lifecycle-integration.test.ts → integration/feature-branch-lifecycle-integration.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{git-locale.test.ts → integration/git-locale.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{git-self-heal.test.ts → integration/git-self-heal.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{git-service.test.ts → integration/git-service.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{gitignore-tracked-gsd.test.ts → integration/gitignore-tracked-gsd.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{idle-recovery.test.ts → integration/idle-recovery.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{inherited-repo-home-dir.test.ts → integration/inherited-repo-home-dir.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{integration-lifecycle.test.ts → integration/integration-lifecycle.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{integration-mixed-milestones.test.ts → integration/integration-mixed-milestones.test.ts} +6 -6
- package/src/resources/extensions/gsd/tests/{integration-proof.test.ts → integration/integration-proof.test.ts} +12 -12
- package/src/resources/extensions/gsd/tests/{migrate-command.test.ts → integration/migrate-command.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{milestone-transition-worktree.test.ts → integration/milestone-transition-worktree.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{parallel-merge.test.ts → integration/parallel-merge.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{parallel-workers-multi-milestone-e2e.test.ts → integration/parallel-workers-multi-milestone-e2e.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{paths.test.ts → integration/paths.test.ts} +1 -1
- package/src/resources/extensions/gsd/tests/{plugin-importer-live.test.ts → integration/plugin-importer-live.test.ts} +2 -2
- package/src/resources/extensions/gsd/tests/{queue-completed-milestone-perf.test.ts → integration/queue-completed-milestone-perf.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{queue-reorder-e2e.test.ts → integration/queue-reorder-e2e.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{quick-branch-lifecycle.test.ts → integration/quick-branch-lifecycle.test.ts} +5 -5
- package/src/resources/extensions/gsd/tests/{run-uat.test.ts → integration/run-uat.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/{token-savings.test.ts → integration/token-savings.test.ts} +3 -3
- package/src/resources/extensions/gsd/tests/{worktree-e2e.test.ts → integration/worktree-e2e.test.ts} +4 -4
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +226 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-queue-context.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +61 -19
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +49 -24
- package/src/resources/extensions/gsd/visualizer-overlay.ts +3 -3
- package/src/resources/extensions/shared/format-utils.ts +1 -1
- package/src/resources/extensions/subagent/worker-registry.ts +2 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +0 -9
- /package/dist/web/standalone/.next/static/{nISuDzAIpGYC-DVTvs4Po → k92jvAf8IfV4dZE3nnrAr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{nISuDzAIpGYC-DVTvs4Po → k92jvAf8IfV4dZE3nnrAr}/_ssgManifest.js +0 -0
|
@@ -21,7 +21,7 @@ import { join, dirname } from "node:path";
|
|
|
21
21
|
import { fileURLToPath } from "node:url";
|
|
22
22
|
import { gsdRoot } from "./paths.js";
|
|
23
23
|
import { createWorktree, worktreePath } from "./worktree-manager.js";
|
|
24
|
-
import { autoWorktreeBranch, runWorktreePostCreateHook } from "./auto-worktree.js";
|
|
24
|
+
import { autoWorktreeBranch, runWorktreePostCreateHook, syncGsdStateToWorktree } from "./auto-worktree.js";
|
|
25
25
|
import { nativeBranchExists } from "./native-git-bridge.js";
|
|
26
26
|
import { readIntegrationBranch } from "./git-service.js";
|
|
27
27
|
import { resolveParallelConfig } from "./preferences.js";
|
|
@@ -507,6 +507,11 @@ function createMilestoneWorktree(basePath: string, milestoneId: string): string
|
|
|
507
507
|
// Run post-create hook if configured
|
|
508
508
|
runWorktreePostCreateHook(basePath, info.path);
|
|
509
509
|
|
|
510
|
+
// Copy .gsd/ planning artifacts (milestones, CONTEXT, ROADMAP, etc.) from the
|
|
511
|
+
// project root into the worktree. Without this, workers for newly-planned
|
|
512
|
+
// milestones can't find their roadmap and exit immediately (#2184 Bug 4).
|
|
513
|
+
syncGsdStateToWorktree(basePath, info.path);
|
|
514
|
+
|
|
510
515
|
return info.path;
|
|
511
516
|
}
|
|
512
517
|
|
|
@@ -83,10 +83,31 @@ let _lockAcquiredAt: number = 0;
|
|
|
83
83
|
|
|
84
84
|
const LOCK_FILE = "auto.lock";
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Derive the effective lock file name for the current process.
|
|
88
|
+
* In parallel worker mode (GSD_PARALLEL_WORKER + GSD_MILESTONE_LOCK),
|
|
89
|
+
* each worker uses a per-milestone lock file (`auto-<milestoneId>.lock`)
|
|
90
|
+
* to avoid contending on the shared `.gsd/auto.lock` (#2184).
|
|
91
|
+
*/
|
|
92
|
+
export function effectiveLockFile(): string {
|
|
93
|
+
const mid = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : null;
|
|
94
|
+
return mid ? `auto-${mid}.lock` : LOCK_FILE;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Derive the OS-level lock target directory for the current process.
|
|
99
|
+
* In parallel worker mode, uses `.gsd/parallel/<milestoneId>/` instead of
|
|
100
|
+
* `.gsd/` so workers don't contend on the same proper-lockfile directory (#2184).
|
|
101
|
+
*/
|
|
102
|
+
export function effectiveLockTarget(gsdDir: string): string {
|
|
103
|
+
const mid = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_MILESTONE_LOCK : null;
|
|
104
|
+
return mid ? join(gsdDir, "parallel", mid) : gsdDir;
|
|
105
|
+
}
|
|
106
|
+
|
|
86
107
|
function lockPath(basePath: string): string {
|
|
87
108
|
// If we have a snapshotted path from acquisition, use it for consistency
|
|
88
109
|
if (_snapshotLockPath) return _snapshotLockPath;
|
|
89
|
-
return join(gsdRoot(basePath),
|
|
110
|
+
return join(gsdRoot(basePath), effectiveLockFile());
|
|
90
111
|
}
|
|
91
112
|
|
|
92
113
|
// ─── Stray Lock Cleanup ─────────────────────────────────────────────────────
|
|
@@ -265,14 +286,16 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
|
|
|
265
286
|
}
|
|
266
287
|
|
|
267
288
|
const gsdDir = gsdRoot(basePath);
|
|
289
|
+
const lockTarget = effectiveLockTarget(gsdDir);
|
|
268
290
|
|
|
269
291
|
try {
|
|
270
|
-
// Try to acquire an exclusive OS-level lock on the lock
|
|
271
|
-
// We lock
|
|
272
|
-
//
|
|
273
|
-
|
|
292
|
+
// Try to acquire an exclusive OS-level lock on the lock target.
|
|
293
|
+
// We lock a directory since proper-lockfile works best on directories,
|
|
294
|
+
// and the lock file itself may not exist yet.
|
|
295
|
+
// In parallel worker mode, lockTarget is .gsd/parallel/<MID>/ (#2184).
|
|
296
|
+
mkdirSync(lockTarget, { recursive: true });
|
|
274
297
|
|
|
275
|
-
const release = lockfile.lockSync(
|
|
298
|
+
const release = lockfile.lockSync(lockTarget, {
|
|
276
299
|
realpath: false,
|
|
277
300
|
stale: 1_800_000, // 30 minutes — safe for laptop sleep / long event loop stalls
|
|
278
301
|
update: 10_000, // Update lock mtime every 10s to prove liveness
|
|
@@ -283,7 +306,7 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
|
|
|
283
306
|
|
|
284
307
|
// Safety net: clean up lock dir on process exit if _releaseFunction
|
|
285
308
|
// wasn't called (e.g., normal exit after clean completion) (#1245).
|
|
286
|
-
ensureExitHandler(
|
|
309
|
+
ensureExitHandler(lockTarget);
|
|
287
310
|
|
|
288
311
|
// Write the informational lock data
|
|
289
312
|
atomicWriteSync(lp, JSON.stringify(lockData, null, 2));
|
|
@@ -298,12 +321,12 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
|
|
|
298
321
|
// If no lock file or no alive process, try to clean up and re-acquire (#1245)
|
|
299
322
|
if (!existingData || (existingPid && !isPidAlive(existingPid))) {
|
|
300
323
|
try {
|
|
301
|
-
const lockDir = join(
|
|
324
|
+
const lockDir = join(lockTarget + ".lock");
|
|
302
325
|
if (existsSync(lockDir)) rmSync(lockDir, { recursive: true, force: true });
|
|
303
326
|
if (existsSync(lp)) unlinkSync(lp);
|
|
304
327
|
|
|
305
328
|
// Retry acquisition after cleanup
|
|
306
|
-
const release = lockfile.lockSync(
|
|
329
|
+
const release = lockfile.lockSync(lockTarget, {
|
|
307
330
|
realpath: false,
|
|
308
331
|
stale: 1_800_000, // 30 minutes — match primary lock settings
|
|
309
332
|
update: 10_000,
|
|
@@ -312,7 +335,7 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
|
|
|
312
335
|
assignLockState(basePath, release, lp);
|
|
313
336
|
|
|
314
337
|
// Safety net — uses centralized handler to avoid double-registration
|
|
315
|
-
ensureExitHandler(
|
|
338
|
+
ensureExitHandler(lockTarget);
|
|
316
339
|
|
|
317
340
|
atomicWriteSync(lp, JSON.stringify(lockData, null, 2));
|
|
318
341
|
return { acquired: true };
|
|
@@ -483,13 +506,24 @@ export function releaseSessionLock(basePath: string): void {
|
|
|
483
506
|
// Non-fatal
|
|
484
507
|
}
|
|
485
508
|
|
|
486
|
-
// Remove the proper-lockfile directory
|
|
509
|
+
// Remove the proper-lockfile directory for the current lock target.
|
|
510
|
+
// In parallel worker mode, this is .gsd/parallel/<MID>.lock/ (#2184).
|
|
511
|
+
const gsdDir = gsdRoot(basePath);
|
|
512
|
+
const lockTarget = effectiveLockTarget(gsdDir);
|
|
487
513
|
try {
|
|
488
|
-
const lockDir = join(
|
|
514
|
+
const lockDir = join(lockTarget + ".lock");
|
|
489
515
|
if (existsSync(lockDir)) rmSync(lockDir, { recursive: true, force: true });
|
|
490
516
|
} catch {
|
|
491
517
|
// Non-fatal
|
|
492
518
|
}
|
|
519
|
+
// Also clean the per-milestone parallel directory itself if it exists
|
|
520
|
+
if (lockTarget !== gsdDir) {
|
|
521
|
+
try {
|
|
522
|
+
if (existsSync(lockTarget)) rmSync(lockTarget, { recursive: true, force: true });
|
|
523
|
+
} catch {
|
|
524
|
+
// Non-fatal
|
|
525
|
+
}
|
|
526
|
+
}
|
|
493
527
|
|
|
494
528
|
// Clean ALL registered lock paths (#1578) — lock files accumulate across
|
|
495
529
|
// main project .gsd/, worktree .gsd/, and projects registry paths.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* research identified as critical for skill quality.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
16
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
17
17
|
import { join } from "node:path";
|
|
18
18
|
import { homedir } from "node:os";
|
|
19
19
|
import type { UnitMetrics, MetricsLedger } from "./metrics.js";
|
|
@@ -210,7 +210,7 @@ export function formatSkillDetail(basePath: string, skillName: string): string {
|
|
|
210
210
|
// Check for SKILL.md existence
|
|
211
211
|
const skillPath = join(homedir(), ".agents", "skills", skillName, "SKILL.md");
|
|
212
212
|
if (existsSync(skillPath)) {
|
|
213
|
-
const stat =
|
|
213
|
+
const stat = statSync(skillPath);
|
|
214
214
|
lines.push("");
|
|
215
215
|
lines.push(`SKILL.md: ${skillPath}`);
|
|
216
216
|
lines.push(`Last modified: ${stat.mtime.toISOString().slice(0, 10)}`);
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
|
|
7
|
+
import { resolvePreferredModelConfig } from "../auto-model-selection.js";
|
|
8
|
+
|
|
9
|
+
function makeTempDir(prefix: string): string {
|
|
10
|
+
return mkdtempSync(join(tmpdir(), prefix));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
test("resolvePreferredModelConfig synthesizes heavy routing ceiling when models section is absent", () => {
|
|
14
|
+
const originalCwd = process.cwd();
|
|
15
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
16
|
+
const tempProject = makeTempDir("gsd-routing-project-");
|
|
17
|
+
const tempGsdHome = makeTempDir("gsd-routing-home-");
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
21
|
+
writeFileSync(
|
|
22
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
23
|
+
[
|
|
24
|
+
"---",
|
|
25
|
+
"dynamic_routing:",
|
|
26
|
+
" enabled: true",
|
|
27
|
+
" tier_models:",
|
|
28
|
+
" light: claude-haiku-4-5",
|
|
29
|
+
" standard: claude-sonnet-4-6",
|
|
30
|
+
" heavy: claude-opus-4-6",
|
|
31
|
+
"---",
|
|
32
|
+
].join("\n"),
|
|
33
|
+
"utf-8",
|
|
34
|
+
);
|
|
35
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
36
|
+
process.chdir(tempProject);
|
|
37
|
+
|
|
38
|
+
const config = resolvePreferredModelConfig("plan-slice", {
|
|
39
|
+
provider: "anthropic",
|
|
40
|
+
id: "claude-sonnet-4-6",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
assert.deepEqual(config, {
|
|
44
|
+
primary: "claude-opus-4-6",
|
|
45
|
+
fallbacks: [],
|
|
46
|
+
});
|
|
47
|
+
} finally {
|
|
48
|
+
process.chdir(originalCwd);
|
|
49
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
50
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
51
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
52
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("resolvePreferredModelConfig falls back to auto start model when heavy tier is absent", () => {
|
|
57
|
+
const originalCwd = process.cwd();
|
|
58
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
59
|
+
const tempProject = makeTempDir("gsd-routing-project-");
|
|
60
|
+
const tempGsdHome = makeTempDir("gsd-routing-home-");
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
64
|
+
writeFileSync(
|
|
65
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
66
|
+
[
|
|
67
|
+
"---",
|
|
68
|
+
"dynamic_routing:",
|
|
69
|
+
" enabled: true",
|
|
70
|
+
" tier_models:",
|
|
71
|
+
" light: claude-haiku-4-5",
|
|
72
|
+
" standard: claude-sonnet-4-6",
|
|
73
|
+
"---",
|
|
74
|
+
].join("\n"),
|
|
75
|
+
"utf-8",
|
|
76
|
+
);
|
|
77
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
78
|
+
process.chdir(tempProject);
|
|
79
|
+
|
|
80
|
+
const config = resolvePreferredModelConfig("execute-task", {
|
|
81
|
+
provider: "openai",
|
|
82
|
+
id: "gpt-5.4",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
assert.deepEqual(config, {
|
|
86
|
+
primary: "openai/gpt-5.4",
|
|
87
|
+
fallbacks: [],
|
|
88
|
+
});
|
|
89
|
+
} finally {
|
|
90
|
+
process.chdir(originalCwd);
|
|
91
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
92
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
93
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
94
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("resolvePreferredModelConfig keeps explicit phase models as the ceiling", () => {
|
|
99
|
+
const originalCwd = process.cwd();
|
|
100
|
+
const originalGsdHome = process.env.GSD_HOME;
|
|
101
|
+
const tempProject = makeTempDir("gsd-routing-project-");
|
|
102
|
+
const tempGsdHome = makeTempDir("gsd-routing-home-");
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
mkdirSync(join(tempProject, ".gsd"), { recursive: true });
|
|
106
|
+
writeFileSync(
|
|
107
|
+
join(tempProject, ".gsd", "PREFERENCES.md"),
|
|
108
|
+
[
|
|
109
|
+
"---",
|
|
110
|
+
"models:",
|
|
111
|
+
" planning: claude-sonnet-4-6",
|
|
112
|
+
"dynamic_routing:",
|
|
113
|
+
" enabled: true",
|
|
114
|
+
" tier_models:",
|
|
115
|
+
" heavy: claude-opus-4-6",
|
|
116
|
+
"---",
|
|
117
|
+
].join("\n"),
|
|
118
|
+
"utf-8",
|
|
119
|
+
);
|
|
120
|
+
process.env.GSD_HOME = tempGsdHome;
|
|
121
|
+
process.chdir(tempProject);
|
|
122
|
+
|
|
123
|
+
const config = resolvePreferredModelConfig("plan-slice", {
|
|
124
|
+
provider: "anthropic",
|
|
125
|
+
id: "claude-opus-4-6",
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
assert.deepEqual(config, {
|
|
129
|
+
primary: "claude-sonnet-4-6",
|
|
130
|
+
fallbacks: [],
|
|
131
|
+
});
|
|
132
|
+
} finally {
|
|
133
|
+
process.chdir(originalCwd);
|
|
134
|
+
if (originalGsdHome === undefined) delete process.env.GSD_HOME;
|
|
135
|
+
else process.env.GSD_HOME = originalGsdHome;
|
|
136
|
+
rmSync(tempProject, { recursive: true, force: true });
|
|
137
|
+
rmSync(tempGsdHome, { recursive: true, force: true });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
const sourcePath = join(import.meta.dirname, "..", "auto-start.ts");
|
|
7
|
+
const source = readFileSync(sourcePath, "utf-8");
|
|
8
|
+
|
|
9
|
+
test("bootstrapAutoSession snapshots ctx.model before guided-flow entry (#2829)", () => {
|
|
10
|
+
const snapshotIdx = source.indexOf("const startModelSnapshot = ctx.model");
|
|
11
|
+
assert.ok(snapshotIdx > -1, "auto-start.ts should snapshot ctx.model at bootstrap start");
|
|
12
|
+
|
|
13
|
+
const firstDiscussIdx = source.indexOf('await showSmartEntry(ctx, pi, base, { step: requestedStepMode });');
|
|
14
|
+
assert.ok(firstDiscussIdx > -1, "auto-start.ts should route through showSmartEntry during guided flow");
|
|
15
|
+
|
|
16
|
+
assert.ok(
|
|
17
|
+
snapshotIdx < firstDiscussIdx,
|
|
18
|
+
"auto-start.ts must capture the start model before guided-flow can mutate ctx.model",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("bootstrapAutoSession restores autoModeStartModel from the early snapshot (#2829)", () => {
|
|
23
|
+
const assignmentIdx = source.indexOf("s.autoModeStartModel = {");
|
|
24
|
+
assert.ok(assignmentIdx > -1, "auto-start.ts should assign autoModeStartModel");
|
|
25
|
+
|
|
26
|
+
const snapshotRefIdx = source.indexOf("provider: startModelSnapshot.provider", assignmentIdx);
|
|
27
|
+
assert.ok(snapshotRefIdx > -1, "autoModeStartModel should be restored from startModelSnapshot");
|
|
28
|
+
});
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
isInAutoWorktree,
|
|
32
32
|
getAutoWorktreeOriginalBase,
|
|
33
33
|
mergeMilestoneToMain,
|
|
34
|
-
} from "
|
|
34
|
+
} from "../../auto-worktree.ts";
|
|
35
35
|
|
|
36
36
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
37
37
|
|
|
@@ -78,9 +78,9 @@ function createMilestoneArtifacts(dir: string, mid: string): void {
|
|
|
78
78
|
// ─── Source-level: verify the merge code exists in the "all complete" path ────
|
|
79
79
|
|
|
80
80
|
test("auto-loop 'all milestones complete' path merges before stopping (#962)", () => {
|
|
81
|
-
const loopSrc = readFileSync(join(__dirname, "
|
|
81
|
+
const loopSrc = readFileSync(join(__dirname, "../..", "auto", "phases.ts"), "utf-8");
|
|
82
82
|
const resolverSrc = readFileSync(
|
|
83
|
-
join(__dirname, "
|
|
83
|
+
join(__dirname, "../..", "worktree-resolver.ts"),
|
|
84
84
|
"utf-8",
|
|
85
85
|
);
|
|
86
86
|
|
|
@@ -9,7 +9,7 @@ import { join } from "node:path";
|
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import test from "node:test";
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
|
-
import { runGSDDoctor } from "
|
|
12
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
13
13
|
|
|
14
14
|
function makeTmp(name: string): string {
|
|
15
15
|
const dir = join(tmpdir(), `atomic-closeout-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -4,7 +4,7 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
7
|
-
import { runGSDDoctor, selectDoctorScope, filterDoctorIssues } from "
|
|
7
|
+
import { runGSDDoctor, selectDoctorScope, filterDoctorIssues } from "../../doctor.js";
|
|
8
8
|
|
|
9
9
|
test("auto-preflight scopes to active milestone, ignoring historical", async (t) => {
|
|
10
10
|
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-auto-preflight-test-"));
|
|
@@ -11,19 +11,19 @@ import {
|
|
|
11
11
|
diagnoseExpectedArtifact,
|
|
12
12
|
buildLoopRemediationSteps,
|
|
13
13
|
hasImplementationArtifacts,
|
|
14
|
-
} from "
|
|
15
|
-
import { parseRoadmap, parsePlan } from "
|
|
16
|
-
import { parseTaskPlanFile, clearParseCache } from "
|
|
17
|
-
import { invalidateAllCaches } from "
|
|
18
|
-
import { deriveState, invalidateStateCache } from "
|
|
14
|
+
} from "../../auto-recovery.ts";
|
|
15
|
+
import { parseRoadmap, parsePlan } from "../../parsers-legacy.ts";
|
|
16
|
+
import { parseTaskPlanFile, clearParseCache } from "../../files.ts";
|
|
17
|
+
import { invalidateAllCaches } from "../../cache.ts";
|
|
18
|
+
import { deriveState, invalidateStateCache } from "../../state.ts";
|
|
19
19
|
import {
|
|
20
20
|
openDatabase,
|
|
21
21
|
closeDatabase,
|
|
22
22
|
insertMilestone,
|
|
23
23
|
insertSlice,
|
|
24
24
|
insertTask,
|
|
25
|
-
} from "
|
|
26
|
-
import { renderPlanFromDb } from "
|
|
25
|
+
} from "../../gsd-db.ts";
|
|
26
|
+
import { renderPlanFromDb } from "../../markdown-renderer.ts";
|
|
27
27
|
|
|
28
28
|
function makeTmpBase(): string {
|
|
29
29
|
const base = join(tmpdir(), `gsd-test-${randomUUID()}`);
|
|
@@ -16,8 +16,8 @@ import assert from 'node:assert/strict';
|
|
|
16
16
|
import { mkdirSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { tmpdir } from 'node:os';
|
|
19
|
-
import { getManifestStatus } from '
|
|
20
|
-
import { collectSecretsFromManifest } from '
|
|
19
|
+
import { getManifestStatus } from '../../files.ts';
|
|
20
|
+
import { collectSecretsFromManifest } from '../../../get-secrets-from-user.ts';
|
|
21
21
|
|
|
22
22
|
function makeTempDir(prefix: string): string {
|
|
23
23
|
const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -12,8 +12,8 @@ import { join } from "node:path";
|
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { execSync } from "node:child_process";
|
|
14
14
|
|
|
15
|
-
import { createAutoWorktree, mergeMilestoneToMain } from "
|
|
16
|
-
import { nativeMergeSquash } from "
|
|
15
|
+
import { createAutoWorktree, mergeMilestoneToMain } from "../../auto-worktree.ts";
|
|
16
|
+
import { nativeMergeSquash } from "../../native-git-bridge.ts";
|
|
17
17
|
|
|
18
18
|
function run(cmd: string, cwd: string): string {
|
|
19
19
|
return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
@@ -88,7 +88,7 @@ test("#2151 bug 1: auto-stash unblocks merge when unrelated files are dirty", ()
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
test("#2151 bug 2: nativeMergeSquash returns dirty filenames", async () => {
|
|
91
|
-
const { nativeMergeSquash } = await import("
|
|
91
|
+
const { nativeMergeSquash } = await import("../../native-git-bridge.ts");
|
|
92
92
|
const repo = createTempRepo();
|
|
93
93
|
try {
|
|
94
94
|
run("git checkout -b milestone/M210", repo);
|
|
@@ -21,9 +21,9 @@ import {
|
|
|
21
21
|
createAutoWorktree,
|
|
22
22
|
mergeMilestoneToMain,
|
|
23
23
|
getAutoWorktreeOriginalBase,
|
|
24
|
-
} from "
|
|
25
|
-
import { getSliceBranchName } from "
|
|
26
|
-
import { nativeMergeSquash } from "
|
|
24
|
+
} from "../../auto-worktree.ts";
|
|
25
|
+
import { getSliceBranchName } from "../../worktree.ts";
|
|
26
|
+
import { nativeMergeSquash } from "../../native-git-bridge.ts";
|
|
27
27
|
|
|
28
28
|
function run(cmd: string, cwd: string): string {
|
|
29
29
|
// Safe: all inputs are hardcoded test strings, not user input
|
|
@@ -329,7 +329,7 @@ describe("auto-worktree-milestone-merge", { timeout: 300_000 }, () => {
|
|
|
329
329
|
});
|
|
330
330
|
|
|
331
331
|
test("#1738 bug 1: nativeMergeSquash detects dirty working tree", async () => {
|
|
332
|
-
const { nativeMergeSquash } = await import("
|
|
332
|
+
const { nativeMergeSquash } = await import("../../native-git-bridge.ts");
|
|
333
333
|
const repo = freshRepo();
|
|
334
334
|
|
|
335
335
|
run("git checkout -b milestone/M070", repo);
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
enterAutoWorktree,
|
|
21
21
|
getAutoWorktreeOriginalBase,
|
|
22
22
|
getActiveAutoWorktreeContext,
|
|
23
|
-
} from "
|
|
23
|
+
} from "../../auto-worktree.ts";
|
|
24
24
|
|
|
25
25
|
// Note: execSync is used intentionally in tests for git operations with
|
|
26
26
|
// controlled, hardcoded inputs (no user input). This is safe and matches
|
|
@@ -150,7 +150,7 @@ describe("auto-worktree lifecycle", () => {
|
|
|
150
150
|
run("git commit -m \"add milestone\"", tempDir);
|
|
151
151
|
|
|
152
152
|
// Import createWorktree directly for manual worktree
|
|
153
|
-
const { createWorktree } = await import("
|
|
153
|
+
const { createWorktree } = await import("../../worktree-manager.ts");
|
|
154
154
|
|
|
155
155
|
// Create manual worktree (uses worktree/<name> branch)
|
|
156
156
|
const manualWt = createWorktree(tempDir, "feature-x");
|
|
@@ -164,7 +164,7 @@ describe("auto-worktree lifecycle", () => {
|
|
|
164
164
|
|
|
165
165
|
// Cleanup both
|
|
166
166
|
teardownAutoWorktree(tempDir, "M003");
|
|
167
|
-
const { removeWorktree } = await import("
|
|
167
|
+
const { removeWorktree } = await import("../../worktree-manager.ts");
|
|
168
168
|
removeWorktree(tempDir, "feature-x");
|
|
169
169
|
});
|
|
170
170
|
|
|
@@ -190,7 +190,7 @@ describe("auto-worktree lifecycle", () => {
|
|
|
190
190
|
run("git add .", tempDir);
|
|
191
191
|
run("git commit -m \"add milestone\"", tempDir);
|
|
192
192
|
|
|
193
|
-
const { GitServiceImpl } = await import("
|
|
193
|
+
const { GitServiceImpl } = await import("../../git-service.ts");
|
|
194
194
|
|
|
195
195
|
// Create worktree
|
|
196
196
|
const wtPath = createAutoWorktree(tempDir, "M005");
|
|
@@ -215,7 +215,7 @@ describe("auto-worktree lifecycle", () => {
|
|
|
215
215
|
run("git commit -m \"add milestone\"", tempDir);
|
|
216
216
|
|
|
217
217
|
// Simulate a crash leaving a stale directory with no .git file.
|
|
218
|
-
const { worktreePath } = await import("
|
|
218
|
+
const { worktreePath } = await import("../../worktree-manager.ts");
|
|
219
219
|
const staleDir = worktreePath(tempDir, "M010");
|
|
220
220
|
mkdirSync(staleDir, { recursive: true });
|
|
221
221
|
writeFileSync(join(staleDir, "orphan.txt"), "stale leftover\n");
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { describe, it } from "node:test";
|
|
13
13
|
import assert from "node:assert/strict";
|
|
14
14
|
|
|
15
|
-
import { computeBudgets } from "
|
|
15
|
+
import { computeBudgets } from "../../context-budget.js";
|
|
16
16
|
|
|
17
17
|
// ─── Pure threshold / pipeline tests ──────────────────────────────────────────
|
|
18
18
|
// These test the budget engine outputs that the continue-here monitor relies on.
|
|
@@ -164,7 +164,7 @@ describe("continue-here", () => {
|
|
|
164
164
|
describe("continueHereFired runtime record field", () => {
|
|
165
165
|
it("AutoUnitRuntimeRecord includes continueHereFired with default false", async (t) => {
|
|
166
166
|
// Import writeUnitRuntimeRecord to verify the field is present and defaults
|
|
167
|
-
const { writeUnitRuntimeRecord, readUnitRuntimeRecord, clearUnitRuntimeRecord } = await import("
|
|
167
|
+
const { writeUnitRuntimeRecord, readUnitRuntimeRecord, clearUnitRuntimeRecord } = await import("../../unit-runtime.js");
|
|
168
168
|
const fs = await import("node:fs");
|
|
169
169
|
const path = await import("node:path");
|
|
170
170
|
const os = await import("node:os");
|
|
@@ -202,7 +202,7 @@ describe("continue-here", () => {
|
|
|
202
202
|
|
|
203
203
|
describe("context-pressure monitor integration", () => {
|
|
204
204
|
it("should fire wrap-up when context >= threshold and mark continueHereFired", async (t) => {
|
|
205
|
-
const { writeUnitRuntimeRecord, readUnitRuntimeRecord, clearUnitRuntimeRecord } = await import("
|
|
205
|
+
const { writeUnitRuntimeRecord, readUnitRuntimeRecord, clearUnitRuntimeRecord } = await import("../../unit-runtime.js");
|
|
206
206
|
const fs = await import("node:fs");
|
|
207
207
|
const path = await import("node:path");
|
|
208
208
|
const os = await import("node:os");
|
|
@@ -10,7 +10,7 @@ import { join } from "node:path";
|
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import test from "node:test";
|
|
12
12
|
import assert from "node:assert/strict";
|
|
13
|
-
import { runGSDDoctor } from "
|
|
13
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
14
14
|
|
|
15
15
|
function makeTmp(name: string): string {
|
|
16
16
|
const dir = join(tmpdir(), `doctor-deferral-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -10,7 +10,7 @@ import assert from "node:assert/strict";
|
|
|
10
10
|
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
|
-
import { runGSDDoctor } from "
|
|
13
|
+
import { runGSDDoctor } from "../../doctor.js";
|
|
14
14
|
|
|
15
15
|
test("doctor fix=true sanitizes em-dash in milestone title", async (t) => {
|
|
16
16
|
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-delim-"));
|
|
@@ -4,8 +4,8 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
7
|
-
import { runGSDDoctor } from "
|
|
8
|
-
import { formatDoctorReportJson } from "
|
|
7
|
+
import { runGSDDoctor } from "../../doctor.js";
|
|
8
|
+
import { formatDoctorReportJson } from "../../doctor-format.js";
|
|
9
9
|
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
10
10
|
|
|
11
11
|
function makeBase(): { base: string; gsd: string; mDir: string } {
|
|
@@ -230,7 +230,7 @@ describe('doctor-enhancements', async () => {
|
|
|
230
230
|
const historyPath = join(gsd, "doctor-history.jsonl");
|
|
231
231
|
assert.ok(existsSync(historyPath), "doctor-history.jsonl is created after run");
|
|
232
232
|
|
|
233
|
-
const { readDoctorHistory } = await import("
|
|
233
|
+
const { readDoctorHistory } = await import("../../doctor.js");
|
|
234
234
|
const history = await readDoctorHistory(base);
|
|
235
235
|
assert.ok(history.length >= 1, "history has at least one entry");
|
|
236
236
|
assert.ok(typeof history[0]?.ts === "string", "history entry has ts field");
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
runEnvironmentChecks,
|
|
21
21
|
environmentResultsToDoctorIssues,
|
|
22
22
|
checkEnvironmentHealth,
|
|
23
|
-
} from "
|
|
23
|
+
} from "../../doctor-environment.ts";
|
|
24
24
|
/** Create a directory tree with files. */
|
|
25
25
|
function createDir(files: Record<string, string> = {}): string {
|
|
26
26
|
const dir = mkdtempSync(join(tmpdir(), "gsd-wt-env-"));
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
formatEnvironmentReport,
|
|
27
27
|
checkEnvironmentHealth,
|
|
28
28
|
type EnvironmentCheckResult,
|
|
29
|
-
} from "
|
|
29
|
+
} from "../../doctor-environment.ts";
|
|
30
30
|
function createProjectDir(files: Record<string, string> = {}): string {
|
|
31
31
|
const dir = mkdtempSync(join(tmpdir(), "gsd-env-test-"));
|
|
32
32
|
for (const [name, content] of Object.entries(files)) {
|
|
@@ -14,8 +14,8 @@ import { join } from "node:path";
|
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
15
|
import test from "node:test";
|
|
16
16
|
import assert from "node:assert/strict";
|
|
17
|
-
import { runGSDDoctor } from "
|
|
18
|
-
import { closeDatabase } from "
|
|
17
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
18
|
+
import { closeDatabase } from "../../gsd-db.ts";
|
|
19
19
|
|
|
20
20
|
function makeTmp(name: string): string {
|
|
21
21
|
const dir = join(tmpdir(), `doctor-fixlevel-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
package/src/resources/extensions/gsd/tests/{doctor-git.test.ts → integration/doctor-git.test.ts}
RENAMED
|
@@ -15,7 +15,7 @@ import { join } from "node:path";
|
|
|
15
15
|
import { tmpdir } from "node:os";
|
|
16
16
|
import { execSync } from "node:child_process";
|
|
17
17
|
|
|
18
|
-
import { runGSDDoctor } from "
|
|
18
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
19
19
|
function run(cmd: string, cwd: string): string {
|
|
20
20
|
return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
21
21
|
}
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
checkHealEscalation,
|
|
24
24
|
resetProactiveHealing,
|
|
25
25
|
formatHealthSummary,
|
|
26
|
-
} from "
|
|
26
|
+
} from "../../doctor-proactive.ts";
|
|
27
27
|
function run(cmd: string, cwd: string): string {
|
|
28
28
|
return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
29
29
|
}
|
|
@@ -12,7 +12,7 @@ import { join } from "node:path";
|
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import test from "node:test";
|
|
14
14
|
import assert from "node:assert/strict";
|
|
15
|
-
import { runGSDDoctor } from "
|
|
15
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
16
16
|
|
|
17
17
|
function makeTmp(name: string): string {
|
|
18
18
|
const dir = join(tmpdir(), `doctor-roadmap-summary-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -14,7 +14,7 @@ import { join } from "node:path";
|
|
|
14
14
|
import { tmpdir } from "node:os";
|
|
15
15
|
import { execSync } from "node:child_process";
|
|
16
16
|
|
|
17
|
-
import { runGSDDoctor } from "
|
|
17
|
+
import { runGSDDoctor } from "../../doctor.ts";
|
|
18
18
|
function run(cmd: string, cwd: string): string {
|
|
19
19
|
return execSync(cmd, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
20
20
|
}
|
|
@@ -4,7 +4,7 @@ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync, existsSync
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
|
|
7
|
-
import { formatDoctorReport, runGSDDoctor, summarizeDoctorIssues, filterDoctorIssues, selectDoctorScope, validateTitle } from "
|
|
7
|
+
import { formatDoctorReport, runGSDDoctor, summarizeDoctorIssues, filterDoctorIssues, selectDoctorScope, validateTitle } from "../../doctor.js";
|
|
8
8
|
const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-test-"));
|
|
9
9
|
const gsd = join(tmpBase, ".gsd");
|
|
10
10
|
const mDir = join(gsd, "milestones", "M001");
|