gsd-pi 2.44.0-dev.848dd4c → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -30
- package/dist/resources/extensions/gsd/auto-start.js +0 -10
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- 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.js +2 -2
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +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.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.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.js +2 -2
- 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.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.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.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.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.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/export-data/route.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.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.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.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.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.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.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.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.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.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.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.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.js +5 -5
- 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.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.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.js +2 -2
- 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.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.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.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.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.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.js +2 -2
- 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.js +2 -2
- 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.js +2 -2
- 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.js +4 -4
- 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.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.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.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.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 +4 -4
- 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 +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +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/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +26 -24
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +48 -29
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +34 -30
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +0 -14
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +16 -14
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
- package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +59 -38
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
- package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
- package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
- package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
- package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
- package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
- package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
- package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
- package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
- package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
|
@@ -25,9 +25,9 @@ import {
|
|
|
25
25
|
isSessionLockHeld,
|
|
26
26
|
} from '../session-lock.ts';
|
|
27
27
|
import { gsdRoot } from '../paths.ts';
|
|
28
|
-
import {
|
|
29
|
-
import assert from 'node:assert/strict';
|
|
28
|
+
import { createTestContext } from './test-helpers.ts';
|
|
30
29
|
|
|
30
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
31
31
|
const require = createRequire(import.meta.url);
|
|
32
32
|
|
|
33
33
|
function hasProperLockfile(): boolean {
|
|
@@ -41,7 +41,7 @@ function hasProperLockfile(): boolean {
|
|
|
41
41
|
|
|
42
42
|
const properLockfileAvailable = hasProperLockfile();
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
async function main(): Promise<void> {
|
|
45
45
|
|
|
46
46
|
// ─── 1. Basic acquire/release lifecycle ───────────────────────────────
|
|
47
47
|
console.log('\n=== 1. acquire → validate → release lifecycle ===');
|
|
@@ -51,22 +51,22 @@ describe('session-lock-regression', async () => {
|
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
53
|
const result = acquireSessionLock(base);
|
|
54
|
-
|
|
54
|
+
assertTrue(result.acquired, 'lock acquired successfully');
|
|
55
55
|
|
|
56
56
|
const valid = validateSessionLock(base);
|
|
57
|
-
|
|
57
|
+
assertTrue(valid, 'lock validates after acquisition');
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
assertTrue(isSessionLockHeld(base), 'isSessionLockHeld returns true');
|
|
60
60
|
|
|
61
61
|
releaseSessionLock(base);
|
|
62
62
|
|
|
63
63
|
// After release, the lock file should be cleaned up
|
|
64
64
|
const lockFile = join(gsdRoot(base), 'auto.lock');
|
|
65
|
-
|
|
65
|
+
assertTrue(!existsSync(lockFile), 'lock file removed after release');
|
|
66
66
|
|
|
67
67
|
// The .gsd.lock/ directory should be cleaned up
|
|
68
68
|
const lockDir = gsdRoot(base) + '.lock';
|
|
69
|
-
|
|
69
|
+
assertTrue(!existsSync(lockDir), '.gsd.lock/ directory removed after release (#1245)');
|
|
70
70
|
} finally {
|
|
71
71
|
rmSync(base, { recursive: true, force: true });
|
|
72
72
|
}
|
|
@@ -88,7 +88,7 @@ describe('session-lock-regression', async () => {
|
|
|
88
88
|
} catch {
|
|
89
89
|
threw = true;
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
assertTrue(!threw, 'double release does not throw');
|
|
92
92
|
} finally {
|
|
93
93
|
rmSync(base, { recursive: true, force: true });
|
|
94
94
|
}
|
|
@@ -106,13 +106,13 @@ describe('session-lock-regression', async () => {
|
|
|
106
106
|
updateSessionLock(base, 'execute-task', 'M001/S01/T01', 5, '/tmp/session.json');
|
|
107
107
|
|
|
108
108
|
const data = readSessionLockData(base);
|
|
109
|
-
|
|
109
|
+
assertTrue(data !== null, 'lock data readable after update');
|
|
110
110
|
if (data) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
assertEq(data.pid, process.pid, 'lock data has correct PID');
|
|
112
|
+
assertEq(data.unitType, 'execute-task', 'lock data has correct unit type');
|
|
113
|
+
assertEq(data.unitId, 'M001/S01/T01', 'lock data has correct unit ID');
|
|
114
|
+
assertEq(data.completedUnits, 5, 'lock data has correct completed count');
|
|
115
|
+
assertEq(data.sessionFile, '/tmp/session.json', 'lock data has session file');
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
releaseSessionLock(base);
|
|
@@ -142,7 +142,7 @@ describe('session-lock-regression', async () => {
|
|
|
142
142
|
|
|
143
143
|
// Should be able to acquire despite the stale lock
|
|
144
144
|
const result = acquireSessionLock(base);
|
|
145
|
-
|
|
145
|
+
assertTrue(result.acquired, '#1245: stale lock from dead PID → re-acquirable');
|
|
146
146
|
|
|
147
147
|
releaseSessionLock(base);
|
|
148
148
|
} finally {
|
|
@@ -158,7 +158,7 @@ describe('session-lock-regression', async () => {
|
|
|
158
158
|
|
|
159
159
|
try {
|
|
160
160
|
const data = readSessionLockData(base);
|
|
161
|
-
|
|
161
|
+
assertEq(data, null, 'no lock file → null');
|
|
162
162
|
} finally {
|
|
163
163
|
rmSync(base, { recursive: true, force: true });
|
|
164
164
|
}
|
|
@@ -176,7 +176,7 @@ describe('session-lock-regression', async () => {
|
|
|
176
176
|
// Multiple validations should all return true (regression for #1257)
|
|
177
177
|
for (let i = 0; i < 5; i++) {
|
|
178
178
|
const valid = validateSessionLock(base);
|
|
179
|
-
|
|
179
|
+
assertTrue(valid, `#1257: validation ${i + 1} returns true for own lock`);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
releaseSessionLock(base);
|
|
@@ -196,7 +196,7 @@ describe('session-lock-regression', async () => {
|
|
|
196
196
|
writeFileSync(lockFile, 'NOT VALID JSON {{{');
|
|
197
197
|
|
|
198
198
|
const data = readSessionLockData(base);
|
|
199
|
-
|
|
199
|
+
assertEq(data, null, 'corrupt JSON → null');
|
|
200
200
|
} finally {
|
|
201
201
|
rmSync(base, { recursive: true, force: true });
|
|
202
202
|
}
|
|
@@ -210,9 +210,9 @@ describe('session-lock-regression', async () => {
|
|
|
210
210
|
|
|
211
211
|
try {
|
|
212
212
|
const status = getSessionLockStatus(base);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
assertEq(status.valid, false, 'missing lock metadata is invalid');
|
|
214
|
+
assertEq(status.failureReason, 'missing-metadata', 'missing metadata reason is surfaced');
|
|
215
|
+
assertEq(status.expectedPid, process.pid, 'expected PID is included');
|
|
216
216
|
} finally {
|
|
217
217
|
rmSync(base, { recursive: true, force: true });
|
|
218
218
|
}
|
|
@@ -237,10 +237,10 @@ describe('session-lock-regression', async () => {
|
|
|
237
237
|
}, null, 2));
|
|
238
238
|
|
|
239
239
|
const status = getSessionLockStatus(base);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
assertEq(status.valid, false, 'foreign PID lock is invalid');
|
|
241
|
+
assertEq(status.failureReason, 'pid-mismatch', 'PID mismatch reason is surfaced');
|
|
242
|
+
assertEq(status.existingPid, foreignPid, 'existing PID is included');
|
|
243
|
+
assertEq(status.expectedPid, process.pid, 'expected PID is included');
|
|
244
244
|
} finally {
|
|
245
245
|
rmSync(base, { recursive: true, force: true });
|
|
246
246
|
}
|
|
@@ -254,11 +254,11 @@ describe('session-lock-regression', async () => {
|
|
|
254
254
|
|
|
255
255
|
try {
|
|
256
256
|
const r1 = acquireSessionLock(base);
|
|
257
|
-
|
|
257
|
+
assertTrue(r1.acquired, 'first acquisition');
|
|
258
258
|
releaseSessionLock(base);
|
|
259
259
|
|
|
260
260
|
const r2 = acquireSessionLock(base);
|
|
261
|
-
|
|
261
|
+
assertTrue(r2.acquired, 're-acquisition after release');
|
|
262
262
|
releaseSessionLock(base);
|
|
263
263
|
} finally {
|
|
264
264
|
rmSync(base, { recursive: true, force: true });
|
|
@@ -273,13 +273,13 @@ describe('session-lock-regression', async () => {
|
|
|
273
273
|
|
|
274
274
|
try {
|
|
275
275
|
const r1 = acquireSessionLock(base);
|
|
276
|
-
|
|
276
|
+
assertTrue(r1.acquired, 'first acquisition succeeds');
|
|
277
277
|
|
|
278
278
|
const r2 = acquireSessionLock(base);
|
|
279
|
-
|
|
279
|
+
assertTrue(r2.acquired, 're-entrant acquisition succeeds');
|
|
280
280
|
|
|
281
281
|
const valid = validateSessionLock(base);
|
|
282
|
-
|
|
282
|
+
assertTrue(valid, 're-entrant acquisition does not corrupt validation state');
|
|
283
283
|
|
|
284
284
|
releaseSessionLock(base);
|
|
285
285
|
} finally {
|
|
@@ -295,24 +295,31 @@ describe('session-lock-regression', async () => {
|
|
|
295
295
|
|
|
296
296
|
try {
|
|
297
297
|
const r1 = acquireSessionLock(base);
|
|
298
|
-
|
|
298
|
+
assertTrue(r1.acquired, 'first acquisition succeeds');
|
|
299
299
|
|
|
300
300
|
const lockDir = gsdRoot(base) + '.lock';
|
|
301
301
|
if (properLockfileAvailable) {
|
|
302
|
-
|
|
302
|
+
assertTrue(existsSync(lockDir), '.gsd.lock/ exists after first acquisition');
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
const r2 = acquireSessionLock(base);
|
|
306
|
-
|
|
306
|
+
assertTrue(r2.acquired, 'second acquisition succeeds');
|
|
307
307
|
if (properLockfileAvailable) {
|
|
308
|
-
|
|
308
|
+
assertTrue(existsSync(lockDir), '.gsd.lock/ exists after re-entrant acquisition');
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
assertTrue(validateSessionLock(base), 'lock remains valid after re-entrant acquisition');
|
|
311
311
|
|
|
312
312
|
releaseSessionLock(base);
|
|
313
|
-
|
|
313
|
+
assertTrue(!existsSync(lockDir), '.gsd.lock/ is removed after release');
|
|
314
314
|
} finally {
|
|
315
315
|
rmSync(base, { recursive: true, force: true });
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
|
+
|
|
319
|
+
report();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
main().catch((error) => {
|
|
323
|
+
console.error(error);
|
|
324
|
+
process.exit(1);
|
|
318
325
|
});
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
getAllMilestones,
|
|
15
15
|
_getAdapter,
|
|
16
16
|
} from '../gsd-db.ts';
|
|
17
|
-
import {
|
|
18
|
-
import assert from 'node:assert/strict';
|
|
17
|
+
import { createTestContext } from './test-helpers.ts';
|
|
19
18
|
|
|
19
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
20
20
|
|
|
21
21
|
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
22
22
|
|
|
@@ -30,14 +30,14 @@ function cleanup(dir: string): void {
|
|
|
30
30
|
|
|
31
31
|
// ─── Tests ────────────────────────────────────────────────────────────────
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
async function main() {
|
|
34
34
|
// ─── Test (a): resolveProjectRootDbPath returns project root DB for worktree path ───
|
|
35
35
|
console.log('\n=== shared-wal: resolve worktree path to project root DB ===');
|
|
36
36
|
{
|
|
37
37
|
const projectRoot = '/home/user/myproject';
|
|
38
38
|
const worktreePath = join(projectRoot, '.gsd', 'worktrees', 'M001');
|
|
39
39
|
const result = resolveProjectRootDbPath(worktreePath);
|
|
40
|
-
|
|
40
|
+
assertEq(result, join(projectRoot, '.gsd', 'gsd.db'),
|
|
41
41
|
'worktree path resolves to project root DB');
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -46,7 +46,7 @@ describe('shared-wal', async () => {
|
|
|
46
46
|
{
|
|
47
47
|
const projectRoot = '/home/user/myproject';
|
|
48
48
|
const result = resolveProjectRootDbPath(projectRoot);
|
|
49
|
-
|
|
49
|
+
assertEq(result, join(projectRoot, '.gsd', 'gsd.db'),
|
|
50
50
|
'project root path stays at project root DB');
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ describe('shared-wal', async () => {
|
|
|
56
56
|
const projectRoot = '/home/user/myproject';
|
|
57
57
|
const nestedPath = join(projectRoot, '.gsd', 'worktrees', 'M002', 'src', 'lib');
|
|
58
58
|
const result = resolveProjectRootDbPath(nestedPath);
|
|
59
|
-
|
|
59
|
+
assertEq(result, join(projectRoot, '.gsd', 'gsd.db'),
|
|
60
60
|
'nested worktree subdir resolves to project root DB');
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ describe('shared-wal', async () => {
|
|
|
64
64
|
console.log('\n=== shared-wal: resolve forward-slash path ===');
|
|
65
65
|
{
|
|
66
66
|
const result = resolveProjectRootDbPath('/proj/.gsd/worktrees/M001');
|
|
67
|
-
|
|
67
|
+
assertEq(result, join('/proj', '.gsd', 'gsd.db'),
|
|
68
68
|
'forward-slash worktree path resolves correctly');
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -99,9 +99,9 @@ describe('shared-wal', async () => {
|
|
|
99
99
|
|
|
100
100
|
// Verify all 3 milestones are visible
|
|
101
101
|
const all = getAllMilestones();
|
|
102
|
-
|
|
102
|
+
assertEq(all.length, 3, 'concurrent: all 3 milestones visible');
|
|
103
103
|
const ids = all.map(m => m.id).sort();
|
|
104
|
-
|
|
104
|
+
assertEq(ids, ['M001', 'M002', 'M003'], 'concurrent: correct IDs');
|
|
105
105
|
|
|
106
106
|
closeDatabase();
|
|
107
107
|
} finally {
|
|
@@ -132,7 +132,7 @@ describe('shared-wal', async () => {
|
|
|
132
132
|
// Connection 2: write M002, verify sees M001
|
|
133
133
|
openDatabase(dbPath);
|
|
134
134
|
const afterConn2Before = getAllMilestones();
|
|
135
|
-
|
|
135
|
+
assertTrue(afterConn2Before.some(m => m.id === 'M001'),
|
|
136
136
|
'rawconc: conn2 sees M001 from conn1');
|
|
137
137
|
insertMilestone({ id: 'M002', title: 'Writer 2', status: 'active' });
|
|
138
138
|
closeDatabase();
|
|
@@ -140,16 +140,16 @@ describe('shared-wal', async () => {
|
|
|
140
140
|
// Connection 3: write M003, verify sees M001 + M002
|
|
141
141
|
openDatabase(dbPath);
|
|
142
142
|
const afterConn3Before = getAllMilestones();
|
|
143
|
-
|
|
143
|
+
assertTrue(afterConn3Before.some(m => m.id === 'M001'),
|
|
144
144
|
'rawconc: conn3 sees M001');
|
|
145
|
-
|
|
145
|
+
assertTrue(afterConn3Before.some(m => m.id === 'M002'),
|
|
146
146
|
'rawconc: conn3 sees M002');
|
|
147
147
|
insertMilestone({ id: 'M003', title: 'Writer 3', status: 'active' });
|
|
148
148
|
|
|
149
149
|
// Final read: all 3 visible
|
|
150
150
|
const finalAll = getAllMilestones();
|
|
151
|
-
|
|
152
|
-
|
|
151
|
+
assertEq(finalAll.length, 3, 'rawconc: all 3 milestones visible');
|
|
152
|
+
assertEq(
|
|
153
153
|
finalAll.map(m => m.id).sort(),
|
|
154
154
|
['M001', 'M002', 'M003'],
|
|
155
155
|
'rawconc: all IDs present',
|
|
@@ -177,7 +177,7 @@ describe('shared-wal', async () => {
|
|
|
177
177
|
|
|
178
178
|
// Verify it committed
|
|
179
179
|
const all = getAllMilestones();
|
|
180
|
-
|
|
180
|
+
assertEq(all.length, 1, 'busy: M001 committed via transaction');
|
|
181
181
|
|
|
182
182
|
// Verify transaction rolls back on error
|
|
183
183
|
let errorCaught = false;
|
|
@@ -188,17 +188,17 @@ describe('shared-wal', async () => {
|
|
|
188
188
|
});
|
|
189
189
|
} catch (err) {
|
|
190
190
|
errorCaught = true;
|
|
191
|
-
|
|
191
|
+
assertTrue(
|
|
192
192
|
(err as Error).message.includes('Simulated failure'),
|
|
193
193
|
'busy: error propagated from transaction',
|
|
194
194
|
);
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
assertTrue(errorCaught, 'busy: transaction threw on error');
|
|
197
197
|
|
|
198
198
|
// M002 should NOT be visible (rolled back)
|
|
199
199
|
const afterRollback = getAllMilestones();
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
assertEq(afterRollback.length, 1, 'busy: M002 rolled back — still only 1 milestone');
|
|
201
|
+
assertEq(afterRollback[0]!.id, 'M001', 'busy: only M001 survives');
|
|
202
202
|
|
|
203
203
|
closeDatabase();
|
|
204
204
|
} finally {
|
|
@@ -206,4 +206,11 @@ describe('shared-wal', async () => {
|
|
|
206
206
|
cleanup(tmp);
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
|
+
|
|
210
|
+
report();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
main().catch((error) => {
|
|
214
|
+
console.error(error);
|
|
215
|
+
process.exit(1);
|
|
209
216
|
});
|
|
@@ -19,9 +19,9 @@ import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
|
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import { tmpdir } from "node:os";
|
|
21
21
|
import { recoverTimedOutUnit, type RecoveryContext } from "../auto-timeout-recovery.ts";
|
|
22
|
-
import {
|
|
23
|
-
import assert from 'node:assert/strict';
|
|
22
|
+
import { createTestContext } from './test-helpers.ts';
|
|
24
23
|
|
|
24
|
+
const { assertTrue, report } = createTestContext();
|
|
25
25
|
|
|
26
26
|
// Minimal mock for ExtensionContext — only the fields recoverTimedOutUnit touches.
|
|
27
27
|
function makeMockCtx() {
|
|
@@ -55,12 +55,12 @@ function makeMockPi() {
|
|
|
55
55
|
await recoverTimedOutUnit(ctx, pi, "execute-task", "M001/S01/T01", "idle", emptyRctx);
|
|
56
56
|
} catch (err: any) {
|
|
57
57
|
crashed = true;
|
|
58
|
-
|
|
58
|
+
assertTrue(
|
|
59
59
|
err.message.includes("path") || err.message.includes("string") || err.code === "ERR_INVALID_ARG_TYPE",
|
|
60
60
|
`should crash with path/type error, got: ${err.message}`,
|
|
61
61
|
);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
assertTrue(crashed, "should crash when basePath is undefined (reproduces #1855)");
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// ═══ #1855: valid RecoveryContext does not crash ═════════════════════════════
|
|
@@ -90,11 +90,13 @@ function makeMockPi() {
|
|
|
90
90
|
crashed = true;
|
|
91
91
|
console.error(` Unexpected crash: ${err.message}`);
|
|
92
92
|
}
|
|
93
|
-
|
|
93
|
+
assertTrue(!crashed, "should not crash with valid basePath");
|
|
94
94
|
// With no runtime record on disk and recoveryAttempts=0, the function
|
|
95
95
|
// should attempt steering recovery (sendMessage) and return "recovered".
|
|
96
|
-
|
|
96
|
+
assertTrue(result === "recovered", `should return 'recovered', got '${result}'`);
|
|
97
97
|
} finally {
|
|
98
98
|
rmSync(base, { recursive: true, force: true });
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
|
+
|
|
102
|
+
report();
|
|
@@ -23,15 +23,15 @@ import { tmpdir } from "node:os";
|
|
|
23
23
|
import { execSync } from "node:child_process";
|
|
24
24
|
|
|
25
25
|
import { ensureGsdSymlink, externalGsdRoot } from "../repo-identity.ts";
|
|
26
|
-
import {
|
|
27
|
-
import assert from 'node:assert/strict';
|
|
26
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
28
27
|
|
|
28
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
29
29
|
|
|
30
30
|
function run(command: string, cwd: string): string {
|
|
31
31
|
return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
async function main(): Promise<void> {
|
|
35
35
|
const base = realpathSync(mkdtempSync(join(tmpdir(), "gsd-symlink-variants-")));
|
|
36
36
|
const stateDir = realpathSync(mkdtempSync(join(tmpdir(), "gsd-state-variants-")));
|
|
37
37
|
|
|
@@ -58,14 +58,14 @@ describe('symlink-numbered-variants', async () => {
|
|
|
58
58
|
mkdirSync(join(base, ".gsd 4"), { recursive: true });
|
|
59
59
|
|
|
60
60
|
const result = ensureGsdSymlink(base);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
assertEq(result, externalPath, "ensureGsdSymlink returns external path");
|
|
62
|
+
assertTrue(existsSync(join(base, ".gsd")), ".gsd exists after ensureGsdSymlink");
|
|
63
|
+
assertTrue(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
|
|
64
64
|
|
|
65
65
|
// The numbered variants must have been removed
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" directory was cleaned up');
|
|
67
|
+
assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" directory was cleaned up');
|
|
68
|
+
assertTrue(!existsSync(join(base, ".gsd 4")), '".gsd 4" directory was cleaned up');
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// ── Test: numbered variant symlinks are cleaned up ─────────────────
|
|
@@ -82,12 +82,12 @@ describe('symlink-numbered-variants', async () => {
|
|
|
82
82
|
symlinkSync(staleTarget, join(base, ".gsd 3"), "junction");
|
|
83
83
|
|
|
84
84
|
const result = ensureGsdSymlink(base);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
assertEq(result, externalPath, "ensureGsdSymlink returns external path when variants exist");
|
|
86
|
+
assertTrue(existsSync(join(base, ".gsd")), ".gsd exists");
|
|
87
|
+
assertTrue(lstatSync(join(base, ".gsd")).isSymbolicLink(), ".gsd is a symlink");
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" symlink variant was cleaned up');
|
|
90
|
+
assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" symlink variant was cleaned up');
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// ── Test: real .gsd directory blocks symlink, but variants still cleaned ──
|
|
@@ -104,12 +104,12 @@ describe('symlink-numbered-variants', async () => {
|
|
|
104
104
|
|
|
105
105
|
const result = ensureGsdSymlink(base);
|
|
106
106
|
// When .gsd is a real directory, ensureGsdSymlink preserves it
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
assertEq(result, join(base, ".gsd"), "real .gsd directory preserved");
|
|
108
|
+
assertTrue(lstatSync(join(base, ".gsd")).isDirectory(), ".gsd remains a directory");
|
|
109
109
|
|
|
110
110
|
// But the numbered variants should still be cleaned up
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" cleaned even when .gsd is a directory');
|
|
112
|
+
assertTrue(!existsSync(join(base, ".gsd 3")), '".gsd 3" cleaned even when .gsd is a directory');
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// ── Test: only numeric-suffixed variants are removed ───────────────
|
|
@@ -127,10 +127,10 @@ describe('symlink-numbered-variants', async () => {
|
|
|
127
127
|
|
|
128
128
|
ensureGsdSymlink(base);
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
assertTrue(existsSync(join(base, ".gsd-backup")), ".gsd-backup is NOT removed");
|
|
131
|
+
assertTrue(existsSync(join(base, ".gsd_old")), ".gsd_old is NOT removed");
|
|
132
|
+
assertTrue(!existsSync(join(base, ".gsd 2")), '".gsd 2" removed');
|
|
133
|
+
assertTrue(!existsSync(join(base, ".gsd 10")), '".gsd 10" removed');
|
|
134
134
|
|
|
135
135
|
// Cleanup non-variant dirs
|
|
136
136
|
rmSync(join(base, ".gsd-backup"), { recursive: true, force: true });
|
|
@@ -141,5 +141,11 @@ describe('symlink-numbered-variants', async () => {
|
|
|
141
141
|
delete process.env.GSD_STATE_DIR;
|
|
142
142
|
try { rmSync(base, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
143
143
|
try { rmSync(stateDir, { recursive: true, force: true }); } catch { /* ignore */ }
|
|
144
|
+
report();
|
|
144
145
|
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main().catch((error) => {
|
|
149
|
+
console.error(error);
|
|
150
|
+
process.exit(1);
|
|
145
151
|
});
|