gsd-pi 2.44.0 → 2.45.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 +30 -12
- package/dist/resources/extensions/gsd/activity-log.js +7 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +37 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +31 -2
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/repo-identity.js +45 -7
- package/dist/resources/extensions/gsd/rethink.js +115 -0
- package/dist/resources/extensions/gsd/state.js +41 -3
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +32 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- 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.js +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 +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 +2 -2
- 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 +2 -2
- 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/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_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_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 +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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +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 +7 -7
- 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/4024.11ca5c01938e5948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/{page-7e9530a7122506c5.js → page-12dd5ece0df4badc.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
- package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
- package/package.json +1 -1
- package/packages/native/dist/stream-process/index.js +2 -2
- package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
- package/packages/native/src/stream-process/index.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- 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 +24 -26
- 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 +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- 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 +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +46 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +39 -2
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/repo-identity.ts +46 -7
- package/src/resources/extensions/gsd/rethink.ts +154 -0
- package/src/resources/extensions/gsd/state.ts +41 -1
- 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 +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- 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 +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +43 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
- package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_ssgManifest.js +0 -0
|
@@ -39,61 +39,55 @@ function activeData(overrides: Partial<HealthWidgetData> = {}): HealthWidgetData
|
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
test("detectHealthWidgetProjectState: no .gsd returns none", () => {
|
|
42
|
+
test("detectHealthWidgetProjectState: no .gsd returns none", (t) => {
|
|
43
43
|
const dir = makeTempDir("none");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
cleanup(dir);
|
|
48
|
-
}
|
|
44
|
+
t.after(() => { cleanup(dir); });
|
|
45
|
+
|
|
46
|
+
assert.equal(detectHealthWidgetProjectState(dir), "none");
|
|
49
47
|
});
|
|
50
48
|
|
|
51
|
-
test("detectHealthWidgetProjectState: bootstrapped .gsd without milestones returns initialized", () => {
|
|
49
|
+
test("detectHealthWidgetProjectState: bootstrapped .gsd without milestones returns initialized", (t) => {
|
|
52
50
|
const dir = makeTempDir("initialized");
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
cleanup(dir);
|
|
58
|
-
}
|
|
51
|
+
t.after(() => { cleanup(dir); });
|
|
52
|
+
|
|
53
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
54
|
+
assert.equal(detectHealthWidgetProjectState(dir), "initialized");
|
|
59
55
|
});
|
|
60
56
|
|
|
61
|
-
test("detectHealthWidgetProjectState: milestone without metrics returns active", () => {
|
|
57
|
+
test("detectHealthWidgetProjectState: milestone without metrics returns active", (t) => {
|
|
62
58
|
const dir = makeTempDir("active");
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
cleanup(dir);
|
|
68
|
-
}
|
|
59
|
+
t.after(() => { cleanup(dir); });
|
|
60
|
+
|
|
61
|
+
mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
|
|
62
|
+
assert.equal(detectHealthWidgetProjectState(dir), "active");
|
|
69
63
|
});
|
|
70
64
|
|
|
71
|
-
test("buildHealthLines: none state shows onboarding copy", () => {
|
|
65
|
+
test("buildHealthLines: none state shows onboarding copy", (t) => {
|
|
72
66
|
assert.deepEqual(buildHealthLines(activeData({ projectState: "none" })), [
|
|
73
67
|
" GSD No project loaded — run /gsd to start",
|
|
74
68
|
]);
|
|
75
69
|
});
|
|
76
70
|
|
|
77
|
-
test("buildHealthLines: initialized state shows continue setup copy", () => {
|
|
71
|
+
test("buildHealthLines: initialized state shows continue setup copy", (t) => {
|
|
78
72
|
assert.deepEqual(buildHealthLines(activeData({ projectState: "initialized" })), [
|
|
79
73
|
" GSD Project initialized — run /gsd to continue setup",
|
|
80
74
|
]);
|
|
81
75
|
});
|
|
82
76
|
|
|
83
|
-
test("buildHealthLines: active state with ledger-driven spend shows spent summary", () => {
|
|
77
|
+
test("buildHealthLines: active state with ledger-driven spend shows spent summary", (t) => {
|
|
84
78
|
const lines = buildHealthLines(activeData({ budgetSpent: 0.42 }));
|
|
85
79
|
assert.equal(lines.length, 1);
|
|
86
80
|
assert.match(lines[0]!, /● System OK/);
|
|
87
81
|
assert.match(lines[0]!, /Spent: 42\.0¢/);
|
|
88
82
|
});
|
|
89
83
|
|
|
90
|
-
test("buildHealthLines: active state with budget ceiling shows percent summary", () => {
|
|
84
|
+
test("buildHealthLines: active state with budget ceiling shows percent summary", (t) => {
|
|
91
85
|
const lines = buildHealthLines(activeData({ budgetSpent: 2.5, budgetCeiling: 10 }));
|
|
92
86
|
assert.equal(lines.length, 1);
|
|
93
87
|
assert.match(lines[0]!, /Budget: \$2\.50\/\$10\.00 \(25%\)/);
|
|
94
88
|
});
|
|
95
89
|
|
|
96
|
-
test("buildHealthLines: active state with issues reports issue summary", () => {
|
|
90
|
+
test("buildHealthLines: active state with issues reports issue summary", (t) => {
|
|
97
91
|
const lines = buildHealthLines(activeData({
|
|
98
92
|
providerIssue: "✗ OpenAI key missing",
|
|
99
93
|
environmentErrorCount: 1,
|
|
@@ -104,17 +98,15 @@ test("buildHealthLines: active state with issues reports issue summary", () => {
|
|
|
104
98
|
assert.match(lines[0]!, /Env: 1 error/);
|
|
105
99
|
});
|
|
106
100
|
|
|
107
|
-
test("detectHealthWidgetProjectState: metrics file alone does not imply project", () => {
|
|
101
|
+
test("detectHealthWidgetProjectState: metrics file alone does not imply project", (t) => {
|
|
108
102
|
const dir = makeTempDir("metrics-only");
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
cleanup(dir);
|
|
119
|
-
}
|
|
103
|
+
t.after(() => { cleanup(dir); });
|
|
104
|
+
|
|
105
|
+
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
106
|
+
writeFileSync(
|
|
107
|
+
join(dir, ".gsd", "metrics.json"),
|
|
108
|
+
JSON.stringify({ version: 1, projectStartedAt: Date.now(), units: [] }),
|
|
109
|
+
"utf-8",
|
|
110
|
+
);
|
|
111
|
+
assert.equal(detectHealthWidgetProjectState(dir), "initialized");
|
|
120
112
|
});
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
verifyExpectedArtifact,
|
|
9
9
|
buildLoopRemediationSteps,
|
|
10
10
|
} from "../auto.ts";
|
|
11
|
-
import {
|
|
11
|
+
import { describe, test, beforeEach, afterEach } from 'node:test';
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
12
13
|
|
|
13
|
-
const { assertEq, assertTrue, report } = createTestContext();
|
|
14
14
|
function createFixtureBase(): string {
|
|
15
15
|
const base = mkdtempSync(join(tmpdir(), "gsd-idle-recovery-test-"));
|
|
16
16
|
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
|
|
@@ -23,99 +23,91 @@ function cleanup(base: string): void {
|
|
|
23
23
|
|
|
24
24
|
// ═══ resolveExpectedArtifactPath ═════════════════════════════════════════════
|
|
25
25
|
|
|
26
|
-
{
|
|
27
|
-
console.log("\n=== resolveExpectedArtifactPath: research-milestone ===");
|
|
26
|
+
test('resolveExpectedArtifactPath: research-milestone', () => {
|
|
28
27
|
const base = createFixtureBase();
|
|
29
28
|
try {
|
|
30
29
|
const result = resolveExpectedArtifactPath("research-milestone", "M001", base);
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
assert.ok(result !== null, "should resolve a path");
|
|
31
|
+
assert.ok(result!.endsWith("M001-RESEARCH.md"), `path should end with M001-RESEARCH.md, got ${result}`);
|
|
33
32
|
} finally {
|
|
34
33
|
cleanup(base);
|
|
35
34
|
}
|
|
36
|
-
}
|
|
35
|
+
});
|
|
37
36
|
|
|
38
|
-
{
|
|
39
|
-
console.log("\n=== resolveExpectedArtifactPath: plan-milestone ===");
|
|
37
|
+
test('resolveExpectedArtifactPath: plan-milestone', () => {
|
|
40
38
|
const base = createFixtureBase();
|
|
41
39
|
try {
|
|
42
40
|
const result = resolveExpectedArtifactPath("plan-milestone", "M001", base);
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
assert.ok(result !== null, "should resolve a path");
|
|
42
|
+
assert.ok(result!.endsWith("M001-ROADMAP.md"), `path should end with M001-ROADMAP.md, got ${result}`);
|
|
45
43
|
} finally {
|
|
46
44
|
cleanup(base);
|
|
47
45
|
}
|
|
48
|
-
}
|
|
46
|
+
});
|
|
49
47
|
|
|
50
|
-
{
|
|
51
|
-
console.log("\n=== resolveExpectedArtifactPath: research-slice ===");
|
|
48
|
+
test('resolveExpectedArtifactPath: research-slice', () => {
|
|
52
49
|
const base = createFixtureBase();
|
|
53
50
|
try {
|
|
54
51
|
const result = resolveExpectedArtifactPath("research-slice", "M001/S01", base);
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
assert.ok(result !== null, "should resolve a path");
|
|
53
|
+
assert.ok(result!.endsWith("S01-RESEARCH.md"), `path should end with S01-RESEARCH.md, got ${result}`);
|
|
57
54
|
} finally {
|
|
58
55
|
cleanup(base);
|
|
59
56
|
}
|
|
60
|
-
}
|
|
57
|
+
});
|
|
61
58
|
|
|
62
|
-
{
|
|
63
|
-
console.log("\n=== resolveExpectedArtifactPath: plan-slice ===");
|
|
59
|
+
test('resolveExpectedArtifactPath: plan-slice', () => {
|
|
64
60
|
const base = createFixtureBase();
|
|
65
61
|
try {
|
|
66
62
|
const result = resolveExpectedArtifactPath("plan-slice", "M001/S01", base);
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
assert.ok(result !== null, "should resolve a path");
|
|
64
|
+
assert.ok(result!.endsWith("S01-PLAN.md"), `path should end with S01-PLAN.md, got ${result}`);
|
|
69
65
|
} finally {
|
|
70
66
|
cleanup(base);
|
|
71
67
|
}
|
|
72
|
-
}
|
|
68
|
+
});
|
|
73
69
|
|
|
74
|
-
{
|
|
75
|
-
console.log("\n=== resolveExpectedArtifactPath: complete-milestone ===");
|
|
70
|
+
test('resolveExpectedArtifactPath: complete-milestone', () => {
|
|
76
71
|
const base = createFixtureBase();
|
|
77
72
|
try {
|
|
78
73
|
const result = resolveExpectedArtifactPath("complete-milestone", "M001", base);
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
assert.ok(result !== null, "should resolve a path");
|
|
75
|
+
assert.ok(result!.endsWith("M001-SUMMARY.md"), `path should end with M001-SUMMARY.md, got ${result}`);
|
|
81
76
|
} finally {
|
|
82
77
|
cleanup(base);
|
|
83
78
|
}
|
|
84
|
-
}
|
|
79
|
+
});
|
|
85
80
|
|
|
86
|
-
{
|
|
87
|
-
console.log("\n=== resolveExpectedArtifactPath: unknown unit type → null ===");
|
|
81
|
+
test('resolveExpectedArtifactPath: unknown unit type → null', () => {
|
|
88
82
|
const base = createFixtureBase();
|
|
89
83
|
try {
|
|
90
84
|
const result = resolveExpectedArtifactPath("unknown-type", "M001/S01", base);
|
|
91
|
-
|
|
85
|
+
assert.deepStrictEqual(result, null, "unknown type returns null");
|
|
92
86
|
} finally {
|
|
93
87
|
cleanup(base);
|
|
94
88
|
}
|
|
95
|
-
}
|
|
89
|
+
});
|
|
96
90
|
|
|
97
91
|
// ═══ writeBlockerPlaceholder ═════════════════════════════════════════════════
|
|
98
92
|
|
|
99
|
-
{
|
|
100
|
-
console.log("\n=== writeBlockerPlaceholder: writes file for research-slice ===");
|
|
93
|
+
test('writeBlockerPlaceholder: writes file for research-slice', () => {
|
|
101
94
|
const base = createFixtureBase();
|
|
102
95
|
try {
|
|
103
96
|
const result = writeBlockerPlaceholder("research-slice", "M001/S01", base, "idle recovery exhausted 2 attempts");
|
|
104
|
-
|
|
97
|
+
assert.ok(result !== null, "should return relative path");
|
|
105
98
|
const absPath = resolveExpectedArtifactPath("research-slice", "M001/S01", base)!;
|
|
106
|
-
|
|
99
|
+
assert.ok(existsSync(absPath), "file should exist on disk");
|
|
107
100
|
const content = readFileSync(absPath, "utf-8");
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
assert.ok(content.includes("BLOCKER"), "should contain BLOCKER heading");
|
|
102
|
+
assert.ok(content.includes("idle recovery exhausted 2 attempts"), "should contain the reason");
|
|
103
|
+
assert.ok(content.includes("research-slice"), "should mention the unit type");
|
|
104
|
+
assert.ok(content.includes("M001/S01"), "should mention the unit ID");
|
|
112
105
|
} finally {
|
|
113
106
|
cleanup(base);
|
|
114
107
|
}
|
|
115
|
-
}
|
|
108
|
+
});
|
|
116
109
|
|
|
117
|
-
{
|
|
118
|
-
console.log("\n=== writeBlockerPlaceholder: creates directory if missing ===");
|
|
110
|
+
test('writeBlockerPlaceholder: creates directory if missing', () => {
|
|
119
111
|
const base = mkdtempSync(join(tmpdir(), "gsd-idle-recovery-test-"));
|
|
120
112
|
try {
|
|
121
113
|
// Only create milestone dir, not slice dir
|
|
@@ -123,38 +115,36 @@ function cleanup(base: string): void {
|
|
|
123
115
|
// resolveSlicePath needs the slice dir to exist to resolve, so this should return null
|
|
124
116
|
const result = writeBlockerPlaceholder("research-slice", "M001/S01", base, "test reason");
|
|
125
117
|
// Since the slice dir doesn't exist, resolveExpectedArtifactPath returns null
|
|
126
|
-
|
|
118
|
+
assert.deepStrictEqual(result, null, "returns null when directory structure doesn't exist");
|
|
127
119
|
} finally {
|
|
128
120
|
cleanup(base);
|
|
129
121
|
}
|
|
130
|
-
}
|
|
122
|
+
});
|
|
131
123
|
|
|
132
|
-
{
|
|
133
|
-
console.log("\n=== writeBlockerPlaceholder: writes file for research-milestone ===");
|
|
124
|
+
test('writeBlockerPlaceholder: writes file for research-milestone', () => {
|
|
134
125
|
const base = createFixtureBase();
|
|
135
126
|
try {
|
|
136
127
|
const result = writeBlockerPlaceholder("research-milestone", "M001", base, "hard timeout");
|
|
137
|
-
|
|
128
|
+
assert.ok(result !== null, "should return relative path");
|
|
138
129
|
const absPath = resolveExpectedArtifactPath("research-milestone", "M001", base)!;
|
|
139
|
-
|
|
130
|
+
assert.ok(existsSync(absPath), "file should exist on disk");
|
|
140
131
|
const content = readFileSync(absPath, "utf-8");
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
assert.ok(content.includes("BLOCKER"), "should contain BLOCKER heading");
|
|
133
|
+
assert.ok(content.includes("hard timeout"), "should contain the reason");
|
|
143
134
|
} finally {
|
|
144
135
|
cleanup(base);
|
|
145
136
|
}
|
|
146
|
-
}
|
|
137
|
+
});
|
|
147
138
|
|
|
148
|
-
{
|
|
149
|
-
console.log("\n=== writeBlockerPlaceholder: unknown type → null ===");
|
|
139
|
+
test('writeBlockerPlaceholder: unknown type → null', () => {
|
|
150
140
|
const base = createFixtureBase();
|
|
151
141
|
try {
|
|
152
142
|
const result = writeBlockerPlaceholder("unknown-type", "M001/S01", base, "test");
|
|
153
|
-
|
|
143
|
+
assert.deepStrictEqual(result, null, "unknown type returns null");
|
|
154
144
|
} finally {
|
|
155
145
|
cleanup(base);
|
|
156
146
|
}
|
|
157
|
-
}
|
|
147
|
+
});
|
|
158
148
|
|
|
159
149
|
// ═══ verifyExpectedArtifact: complete-slice roadmap check ════════════════════
|
|
160
150
|
// Regression for #indefinite-hang: complete-slice must verify roadmap [x] or
|
|
@@ -177,8 +167,7 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
|
|
|
177
167
|
> After this: something works
|
|
178
168
|
`;
|
|
179
169
|
|
|
180
|
-
{
|
|
181
|
-
console.log("\n=== verifyExpectedArtifact: complete-slice — all artifacts present + roadmap marked [x] returns true ===");
|
|
170
|
+
test('verifyExpectedArtifact: complete-slice — all artifacts present + roadmap marked [x] returns true', () => {
|
|
182
171
|
const base = createFixtureBase();
|
|
183
172
|
try {
|
|
184
173
|
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
@@ -186,14 +175,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
|
|
|
186
175
|
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
|
187
176
|
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
|
|
188
177
|
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
|
189
|
-
|
|
178
|
+
assert.ok(result === true, "SUMMARY + UAT + roadmap [x] should verify as true");
|
|
190
179
|
} finally {
|
|
191
180
|
cleanup(base);
|
|
192
181
|
}
|
|
193
|
-
}
|
|
182
|
+
});
|
|
194
183
|
|
|
195
|
-
{
|
|
196
|
-
console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY + UAT present but roadmap NOT marked [x] returns false ===");
|
|
184
|
+
test('verifyExpectedArtifact: complete-slice — SUMMARY + UAT present but roadmap NOT marked [x] returns false', () => {
|
|
197
185
|
const base = createFixtureBase();
|
|
198
186
|
try {
|
|
199
187
|
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
@@ -201,14 +189,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
|
|
|
201
189
|
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
|
202
190
|
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_INCOMPLETE, "utf-8");
|
|
203
191
|
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
|
204
|
-
|
|
192
|
+
assert.ok(result === false, "roadmap not marked [x] should return false (crash recovery scenario)");
|
|
205
193
|
} finally {
|
|
206
194
|
cleanup(base);
|
|
207
195
|
}
|
|
208
|
-
}
|
|
196
|
+
});
|
|
209
197
|
|
|
210
|
-
{
|
|
211
|
-
console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY present but UAT missing returns false ===");
|
|
198
|
+
test('verifyExpectedArtifact: complete-slice — SUMMARY present but UAT missing returns false', () => {
|
|
212
199
|
const base = createFixtureBase();
|
|
213
200
|
try {
|
|
214
201
|
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
@@ -216,14 +203,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
|
|
|
216
203
|
// no UAT file
|
|
217
204
|
writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
|
|
218
205
|
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
|
219
|
-
|
|
206
|
+
assert.ok(result === false, "missing UAT should return false");
|
|
220
207
|
} finally {
|
|
221
208
|
cleanup(base);
|
|
222
209
|
}
|
|
223
|
-
}
|
|
210
|
+
});
|
|
224
211
|
|
|
225
|
-
{
|
|
226
|
-
console.log("\n=== verifyExpectedArtifact: complete-slice — no roadmap file present is lenient (returns true) ===");
|
|
212
|
+
test('verifyExpectedArtifact: complete-slice — no roadmap file present is lenient (returns true)', () => {
|
|
227
213
|
const base = createFixtureBase();
|
|
228
214
|
try {
|
|
229
215
|
const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
@@ -231,87 +217,80 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
|
|
|
231
217
|
writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
|
|
232
218
|
// no roadmap file
|
|
233
219
|
const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
|
|
234
|
-
|
|
220
|
+
assert.ok(result === true, "missing roadmap file should be lenient and return true");
|
|
235
221
|
} finally {
|
|
236
222
|
cleanup(base);
|
|
237
223
|
}
|
|
238
|
-
}
|
|
224
|
+
});
|
|
239
225
|
|
|
240
226
|
// ═══ buildLoopRemediationSteps ═══════════════════════════════════════════════
|
|
241
227
|
|
|
242
|
-
{
|
|
243
|
-
console.log("\n=== buildLoopRemediationSteps: execute-task returns concrete steps ===");
|
|
228
|
+
test('buildLoopRemediationSteps: execute-task returns concrete steps', () => {
|
|
244
229
|
const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
|
|
245
230
|
try {
|
|
246
231
|
mkdirSync(join(base, ".gsd", "milestones", "M002", "slices", "S03", "tasks"), { recursive: true });
|
|
247
232
|
const result = buildLoopRemediationSteps("execute-task", "M002/S03/T01", base);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
233
|
+
assert.ok(result !== null, "should return remediation steps");
|
|
234
|
+
assert.ok(result!.includes("gsd undo-task"), "steps include undo-task command");
|
|
235
|
+
assert.ok(result!.includes("T01"), "steps mention the task ID");
|
|
236
|
+
assert.ok(result!.includes("gsd undo-task"), "steps include gsd undo-task command");
|
|
252
237
|
} finally {
|
|
253
238
|
rmSync(base, { recursive: true, force: true });
|
|
254
239
|
}
|
|
255
|
-
}
|
|
240
|
+
});
|
|
256
241
|
|
|
257
|
-
{
|
|
258
|
-
console.log("\n=== buildLoopRemediationSteps: plan-slice returns concrete steps ===");
|
|
242
|
+
test('buildLoopRemediationSteps: plan-slice returns concrete steps', () => {
|
|
259
243
|
const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
|
|
260
244
|
try {
|
|
261
245
|
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
|
|
262
246
|
const result = buildLoopRemediationSteps("plan-slice", "M001/S01", base);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
247
|
+
assert.ok(result !== null, "should return remediation steps for plan-slice");
|
|
248
|
+
assert.ok(result!.includes("S01-PLAN.md"), "steps mention the slice plan file");
|
|
249
|
+
assert.ok(result!.includes("gsd recover"), "steps include gsd recover command");
|
|
266
250
|
} finally {
|
|
267
251
|
rmSync(base, { recursive: true, force: true });
|
|
268
252
|
}
|
|
269
|
-
}
|
|
253
|
+
});
|
|
270
254
|
|
|
271
|
-
{
|
|
272
|
-
console.log("\n=== buildLoopRemediationSteps: research-slice returns concrete steps ===");
|
|
255
|
+
test('buildLoopRemediationSteps: research-slice returns concrete steps', () => {
|
|
273
256
|
const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
|
|
274
257
|
try {
|
|
275
258
|
mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
|
|
276
259
|
const result = buildLoopRemediationSteps("research-slice", "M001/S01", base);
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
260
|
+
assert.ok(result !== null, "should return remediation steps for research-slice");
|
|
261
|
+
assert.ok(result!.includes("S01-RESEARCH.md"), "steps mention the slice research file");
|
|
262
|
+
assert.ok(result!.includes("gsd recover"), "steps include gsd recover command");
|
|
280
263
|
} finally {
|
|
281
264
|
rmSync(base, { recursive: true, force: true });
|
|
282
265
|
}
|
|
283
|
-
}
|
|
266
|
+
});
|
|
284
267
|
|
|
285
|
-
{
|
|
286
|
-
console.log("\n=== buildLoopRemediationSteps: unknown type returns null ===");
|
|
268
|
+
test('buildLoopRemediationSteps: unknown type returns null', () => {
|
|
287
269
|
const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
|
|
288
270
|
try {
|
|
289
271
|
const result = buildLoopRemediationSteps("unknown-type", "M001/S01", base);
|
|
290
|
-
|
|
272
|
+
assert.deepStrictEqual(result, null, "unknown type returns null");
|
|
291
273
|
} finally {
|
|
292
274
|
rmSync(base, { recursive: true, force: true });
|
|
293
275
|
}
|
|
294
|
-
}
|
|
276
|
+
});
|
|
295
277
|
|
|
296
278
|
// ═══ verifyExpectedArtifact: hook unit types ═════════════════════════════════
|
|
297
279
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
{
|
|
280
|
+
test('verifyExpectedArtifact: hook types always return true', () => {
|
|
301
281
|
const base = createFixtureBase();
|
|
302
282
|
try {
|
|
303
283
|
// Hook units don't have standard artifacts — they should always pass
|
|
304
284
|
const result1 = verifyExpectedArtifact("hook/code-review", "M001/S01/T01", base);
|
|
305
|
-
|
|
285
|
+
assert.ok(result1, "hook/code-review should always return true");
|
|
306
286
|
|
|
307
287
|
const result2 = verifyExpectedArtifact("hook/simplify", "M001/S01/T02", base);
|
|
308
|
-
|
|
288
|
+
assert.ok(result2, "hook/simplify should always return true");
|
|
309
289
|
|
|
310
290
|
const result3 = verifyExpectedArtifact("hook/custom-hook", "M001/S01", base);
|
|
311
|
-
|
|
291
|
+
assert.ok(result3, "hook/custom-hook at slice level should return true");
|
|
312
292
|
} finally {
|
|
313
293
|
rmSync(base, { recursive: true, force: true });
|
|
314
294
|
}
|
|
315
|
-
}
|
|
295
|
+
});
|
|
316
296
|
|
|
317
|
-
report();
|
|
@@ -7,10 +7,13 @@ import { isInfrastructureError, INFRA_ERROR_CODES } from "../auto/infra-errors.j
|
|
|
7
7
|
// ── INFRA_ERROR_CODES constant ───────────────────────────────────────────────
|
|
8
8
|
|
|
9
9
|
test("INFRA_ERROR_CODES contains the expected codes", () => {
|
|
10
|
-
for (const code of [
|
|
10
|
+
for (const code of [
|
|
11
|
+
"ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE",
|
|
12
|
+
"ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
|
|
13
|
+
]) {
|
|
11
14
|
assert.ok(INFRA_ERROR_CODES.has(code), `missing ${code}`);
|
|
12
15
|
}
|
|
13
|
-
assert.equal(INFRA_ERROR_CODES.size,
|
|
16
|
+
assert.equal(INFRA_ERROR_CODES.size, 9, "unexpected extra codes");
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
// ── isInfrastructureError: code property detection ───────────────────────────
|
|
@@ -45,6 +48,21 @@ test("detects ENFILE via code property", () => {
|
|
|
45
48
|
assert.equal(isInfrastructureError(err), "ENFILE");
|
|
46
49
|
});
|
|
47
50
|
|
|
51
|
+
test("detects ECONNREFUSED via code property", () => {
|
|
52
|
+
const err = Object.assign(new Error("connect ECONNREFUSED 127.0.0.1:3000"), { code: "ECONNREFUSED" });
|
|
53
|
+
assert.equal(isInfrastructureError(err), "ECONNREFUSED");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("detects ENOTFOUND via code property", () => {
|
|
57
|
+
const err = Object.assign(new Error("getaddrinfo ENOTFOUND api.example.com"), { code: "ENOTFOUND" });
|
|
58
|
+
assert.equal(isInfrastructureError(err), "ENOTFOUND");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("detects ENETUNREACH via code property", () => {
|
|
62
|
+
const err = Object.assign(new Error("connect ENETUNREACH 2607:f8b0:4004::"), { code: "ENETUNREACH" });
|
|
63
|
+
assert.equal(isInfrastructureError(err), "ENETUNREACH");
|
|
64
|
+
});
|
|
65
|
+
|
|
48
66
|
// ── isInfrastructureError: message fallback ──────────────────────────────────
|
|
49
67
|
|
|
50
68
|
test("falls back to message scanning when no code property", () => {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* inherited-repo-home-dir.test.ts — Regression test for #2393.
|
|
3
|
+
*
|
|
4
|
+
* When the user's home directory IS a git repo (common with dotfile
|
|
5
|
+
* managers like yadm), isInheritedRepo() must not treat ~/.gsd (the
|
|
6
|
+
* global GSD state directory) as a project .gsd belonging to the home
|
|
7
|
+
* repo. Without the fix, isInheritedRepo() returns false for project
|
|
8
|
+
* subdirectories because it sees ~/.gsd and concludes the parent repo
|
|
9
|
+
* has already been initialised with GSD — causing the wrong project
|
|
10
|
+
* state to be loaded.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, test, beforeEach, afterEach } from "node:test";
|
|
14
|
+
import assert from "node:assert/strict";
|
|
15
|
+
import {
|
|
16
|
+
mkdtempSync,
|
|
17
|
+
mkdirSync,
|
|
18
|
+
rmSync,
|
|
19
|
+
writeFileSync,
|
|
20
|
+
realpathSync,
|
|
21
|
+
symlinkSync,
|
|
22
|
+
} from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import { tmpdir } from "node:os";
|
|
25
|
+
import { execFileSync } from "node:child_process";
|
|
26
|
+
|
|
27
|
+
import { isInheritedRepo } from "../repo-identity.ts";
|
|
28
|
+
|
|
29
|
+
function run(cmd: string, args: string[], cwd: string): string {
|
|
30
|
+
return execFileSync(cmd, args, {
|
|
31
|
+
cwd,
|
|
32
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
33
|
+
encoding: "utf-8",
|
|
34
|
+
}).trim();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe("isInheritedRepo when git root is HOME (#2393)", () => {
|
|
38
|
+
let fakeHome: string;
|
|
39
|
+
let stateDir: string;
|
|
40
|
+
let origGsdHome: string | undefined;
|
|
41
|
+
let origGsdStateDir: string | undefined;
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
// Create a fake HOME that is itself a git repo (dotfile manager scenario).
|
|
45
|
+
fakeHome = realpathSync(mkdtempSync(join(tmpdir(), "gsd-home-repo-")));
|
|
46
|
+
run("git", ["init", "-b", "main"], fakeHome);
|
|
47
|
+
run("git", ["config", "user.name", "Test"], fakeHome);
|
|
48
|
+
run("git", ["config", "user.email", "test@example.com"], fakeHome);
|
|
49
|
+
writeFileSync(join(fakeHome, ".bashrc"), "# dotfiles\n", "utf-8");
|
|
50
|
+
run("git", ["add", ".bashrc"], fakeHome);
|
|
51
|
+
run("git", ["commit", "-m", "init dotfiles"], fakeHome);
|
|
52
|
+
|
|
53
|
+
// Create a plain ~/.gsd directory at fakeHome — this simulates the
|
|
54
|
+
// global GSD home directory, NOT a project .gsd.
|
|
55
|
+
mkdirSync(join(fakeHome, ".gsd", "projects"), { recursive: true });
|
|
56
|
+
|
|
57
|
+
// Save and override env. Point GSD_HOME at fakeHome/.gsd so the
|
|
58
|
+
// function recognizes it as the global state directory.
|
|
59
|
+
origGsdHome = process.env.GSD_HOME;
|
|
60
|
+
origGsdStateDir = process.env.GSD_STATE_DIR;
|
|
61
|
+
process.env.GSD_HOME = join(fakeHome, ".gsd");
|
|
62
|
+
stateDir = mkdtempSync(join(tmpdir(), "gsd-state-"));
|
|
63
|
+
process.env.GSD_STATE_DIR = stateDir;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
afterEach(() => {
|
|
67
|
+
if (origGsdHome !== undefined) process.env.GSD_HOME = origGsdHome;
|
|
68
|
+
else delete process.env.GSD_HOME;
|
|
69
|
+
if (origGsdStateDir !== undefined) process.env.GSD_STATE_DIR = origGsdStateDir;
|
|
70
|
+
else delete process.env.GSD_STATE_DIR;
|
|
71
|
+
|
|
72
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
73
|
+
rmSync(stateDir, { recursive: true, force: true });
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("subdirectory of home-as-git-root is detected as inherited even when ~/.gsd exists", () => {
|
|
77
|
+
// Create a project directory inside fake HOME
|
|
78
|
+
const projectDir = join(fakeHome, "projects", "my-app");
|
|
79
|
+
mkdirSync(projectDir, { recursive: true });
|
|
80
|
+
|
|
81
|
+
// The bug: isInheritedRepo sees ~/.gsd and returns false, thinking
|
|
82
|
+
// the home repo is a legitimate GSD project. It should return true
|
|
83
|
+
// because ~/.gsd is the global state dir, not a project .gsd.
|
|
84
|
+
assert.strictEqual(
|
|
85
|
+
isInheritedRepo(projectDir),
|
|
86
|
+
true,
|
|
87
|
+
"project inside home-as-git-root must be detected as inherited repo, " +
|
|
88
|
+
"even when ~/.gsd (global state dir) exists",
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("subdirectory with a real project .gsd symlink at git root is NOT inherited", () => {
|
|
93
|
+
// Simulate a legitimately initialised GSD project at the home repo root:
|
|
94
|
+
// .gsd is a symlink to an external state directory.
|
|
95
|
+
const externalState = join(stateDir, "projects", "home-project");
|
|
96
|
+
mkdirSync(externalState, { recursive: true });
|
|
97
|
+
const gsdDir = join(fakeHome, ".gsd");
|
|
98
|
+
|
|
99
|
+
// Remove the plain directory and replace with a symlink (real project .gsd)
|
|
100
|
+
rmSync(gsdDir, { recursive: true, force: true });
|
|
101
|
+
symlinkSync(externalState, gsdDir);
|
|
102
|
+
|
|
103
|
+
const projectDir = join(fakeHome, "projects", "my-app");
|
|
104
|
+
mkdirSync(projectDir, { recursive: true });
|
|
105
|
+
|
|
106
|
+
// When .gsd at root IS a project symlink, subdirectories are legitimate children
|
|
107
|
+
assert.strictEqual(
|
|
108
|
+
isInheritedRepo(projectDir),
|
|
109
|
+
false,
|
|
110
|
+
"subdirectory of a legitimately-initialised GSD project should NOT be inherited",
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("home-as-git-root itself is never inherited", () => {
|
|
115
|
+
assert.strictEqual(
|
|
116
|
+
isInheritedRepo(fakeHome),
|
|
117
|
+
false,
|
|
118
|
+
"the git root itself is never inherited",
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
});
|