@opengsd/gsd-pi 1.9.0 → 1.10.0-dev.a5e42e99
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 +10 -9
- package/dist/headless.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto/loop.js +24 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
- package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
- package/dist/resources/extensions/gsd/auto-start.js +30 -10
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -26
- package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
- package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
- package/dist/resources/extensions/gsd/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- package/dist/resources/extensions/gsd/db/engine.js +5 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +33 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +40 -12
- package/dist/resources/extensions/gsd/error-classifier.js +12 -2
- package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
- package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +75 -31
- package/dist/resources/extensions/gsd/guided-flow.js +11 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
- package/dist/resources/extensions/gsd/md-importer.js +5 -6
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -1
- package/dist/resources/extensions/gsd/model-router.js +16 -0
- package/dist/resources/extensions/gsd/paths.js +66 -15
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +33 -0
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +6 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +86 -4
- package/dist/resources/extensions/gsd/preferences.js +24 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
- package/dist/resources/extensions/gsd/stop-notice.js +9 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
- package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
- package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- package/dist/resources/extensions/shared/interview-ui.js +43 -6
- package/dist/resources/extensions/subagent/index.js +1 -1
- package/dist/startup-model-validation.d.ts +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/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/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.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/mcp-connections/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/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 +2 -2
- 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 +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.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 +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.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 +9 -9
- package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
- package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +3 -3
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- 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/server.js +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +8 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -1
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/rpc.test.js +1 -1
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +1 -0
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/cli/args.js +2 -2
- package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +21 -5
- package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/background-cli.test.js +325 -0
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +146 -16
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.js +7 -1
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +7 -4
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +115 -31
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts +32 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.js +640 -0
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js +543 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/README.md +7 -2
- package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli-runner.js +119 -33
- package/packages/mcp-server/dist/cli-runner.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +2 -2
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +187 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +145 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js +18 -6
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +6 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +9 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -4
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +54 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +1 -0
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto/loop.ts +48 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
- package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
- package/src/resources/extensions/gsd/auto-start.ts +32 -9
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +20 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +10 -31
- package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
- package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
- package/src/resources/extensions/gsd/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- package/src/resources/extensions/gsd/db/engine.ts +5 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +33 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +45 -11
- package/src/resources/extensions/gsd/error-classifier.ts +13 -2
- package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
- package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +85 -33
- package/src/resources/extensions/gsd/guided-flow.ts +11 -4
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
- package/src/resources/extensions/gsd/md-importer.ts +5 -5
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -1
- package/src/resources/extensions/gsd/model-router.ts +17 -0
- package/src/resources/extensions/gsd/paths.ts +73 -15
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +45 -0
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +26 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +108 -3
- package/src/resources/extensions/gsd/preferences.ts +38 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
- package/src/resources/extensions/gsd/stop-notice.ts +11 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
- package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +74 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
- package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
- package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
- package/src/resources/extensions/shared/interview-ui.ts +47 -8
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
- package/src/resources/extensions/subagent/index.ts +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_ssgManifest.js +0 -0
|
@@ -18,6 +18,7 @@ import test from "node:test";
|
|
|
18
18
|
import assert from "node:assert/strict";
|
|
19
19
|
|
|
20
20
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
21
|
+
import { autoSession } from "../auto-runtime-state.ts";
|
|
21
22
|
import { classifyCommand } from "../safety/destructive-guard.ts";
|
|
22
23
|
import {
|
|
23
24
|
DESTRUCTIVE_CONFIRM_GATE_MARKER,
|
|
@@ -232,6 +233,38 @@ test("integration: real hooks block a force push, then allow it once after confi
|
|
|
232
233
|
assert.equal(thirdAttempt?.block, true, "second run of the same command re-blocks (one-shot)");
|
|
233
234
|
});
|
|
234
235
|
|
|
236
|
+
test("integration: auto-mode destructive block does not pause before confirmation can be asked", async (t) => {
|
|
237
|
+
const dir = "/tmp/gsd-destructive-confirm-int-auto-defer";
|
|
238
|
+
const notifications: string[] = [];
|
|
239
|
+
const ctx = {
|
|
240
|
+
cwd: dir,
|
|
241
|
+
isIdle: () => true,
|
|
242
|
+
sessionManager: { getSessionFile: () => null },
|
|
243
|
+
ui: { notify: (message: string) => notifications.push(message) },
|
|
244
|
+
} as any;
|
|
245
|
+
resetDestructiveConfirmation(dir);
|
|
246
|
+
autoSession.reset();
|
|
247
|
+
autoSession.active = true;
|
|
248
|
+
autoSession.basePath = dir;
|
|
249
|
+
t.after(() => {
|
|
250
|
+
resetDestructiveConfirmation(dir);
|
|
251
|
+
autoSession.reset();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const { handlers, pi } = makeHookHarness();
|
|
255
|
+
registerHooks(pi, []);
|
|
256
|
+
|
|
257
|
+
const block = await runBashGuard(handlers, FORCE_PUSH, ctx);
|
|
258
|
+
|
|
259
|
+
assert.equal(block?.block, true, "real guard blocks the first destructive attempt");
|
|
260
|
+
assert.equal(autoSession.active, true, "auto-mode must remain active so ask_user_questions can run");
|
|
261
|
+
assert.deepEqual(
|
|
262
|
+
notifications.filter((message) => message.includes("Destructive-command confirmation")),
|
|
263
|
+
[],
|
|
264
|
+
"destructive confirmation pause must not fire from the bash tool_call hook",
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
|
|
235
268
|
test("integration: declining the confirm gate leaves the command blocked", async (t) => {
|
|
236
269
|
const dir = "/tmp/gsd-destructive-confirm-int-decline";
|
|
237
270
|
const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
|
|
@@ -29,6 +29,7 @@ test("destructive guard still detects direct and wrapper-prefixed recursive dele
|
|
|
29
29
|
"find . -exec rm -rf {} \\;",
|
|
30
30
|
"cat doomed.txt | xargs rm -rf /tmp/x",
|
|
31
31
|
'rm -rf "/tmp/my build"',
|
|
32
|
+
"rm --recursive build",
|
|
32
33
|
];
|
|
33
34
|
|
|
34
35
|
for (const command of destructiveCommands) {
|
|
@@ -39,6 +40,19 @@ test("destructive guard still detects direct and wrapper-prefixed recursive dele
|
|
|
39
40
|
}
|
|
40
41
|
});
|
|
41
42
|
|
|
43
|
+
test("destructive guard does not classify force-only rm as recursive delete", () => {
|
|
44
|
+
const nonRecursiveCommands = [
|
|
45
|
+
"rm -f single-file.md",
|
|
46
|
+
"rm -fv single-file.md",
|
|
47
|
+
"rm single-file.md -f",
|
|
48
|
+
"rm --force single-file.md",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
for (const command of nonRecursiveCommands) {
|
|
52
|
+
assert.deepEqual(classifyCommand(command), { destructive: false, labels: [] }, command);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
42
56
|
test("destructive guard treats quoted interpreter payloads as literals", () => {
|
|
43
57
|
assert.deepEqual(classifyCommand('bash -c "rm -rf /"'), { destructive: false, labels: [] });
|
|
44
58
|
});
|
|
@@ -167,6 +167,77 @@ test("checkEngineHealth keeps PLAN checkbox divergence after stale projection fl
|
|
|
167
167
|
assert.match(readFileSync(plan.planPath, "utf-8"), /- \[ \] \*\*T01\*\*:/);
|
|
168
168
|
});
|
|
169
169
|
|
|
170
|
+
test("checkEngineHealth ignores stale suffixed flat-phase duplicate when bare milestone exists", async (t) => {
|
|
171
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-checkbox-flat-duplicate-"));
|
|
172
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
173
|
+
|
|
174
|
+
const gsdDir = join(base, ".gsd");
|
|
175
|
+
mkdirSync(gsdDir, { recursive: true });
|
|
176
|
+
|
|
177
|
+
openDatabase(join(gsdDir, "gsd.db"));
|
|
178
|
+
insertMilestone({ id: "M003", title: "M003-vaz73w: New milestone M003-vaz73w", status: "active" });
|
|
179
|
+
insertSlice({ id: "S01", milestoneId: "M003", title: "Slice", status: "pending", risk: "low", depends: [], sequence: 1 });
|
|
180
|
+
for (const taskId of ["T01", "T02", "T03"]) {
|
|
181
|
+
insertTask({ id: taskId, milestoneId: "M003", sliceId: "S01", title: taskId, status: "complete", sequence: Number(taskId.slice(1)) });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
insertMilestone({ id: "M003-vaz73w", title: "New milestone M003-vaz73w", status: "active" });
|
|
185
|
+
insertSlice({ id: "S01", milestoneId: "M003-vaz73w", title: "Slice", status: "pending", risk: "low", depends: [], sequence: 1 });
|
|
186
|
+
for (const taskId of ["T01", "T02", "T03"]) {
|
|
187
|
+
insertTask({ id: taskId, milestoneId: "M003-vaz73w", sliceId: "S01", title: taskId, status: "complete", sequence: Number(taskId.slice(1)) });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const canonicalPlan = await renderPlanFromDb(base, "M003", "S01");
|
|
191
|
+
const staleDir = join(gsdDir, "phases", "03-vaz73w-new-milestone-m003-vaz73w");
|
|
192
|
+
mkdirSync(staleDir, { recursive: true });
|
|
193
|
+
writeFileSync(
|
|
194
|
+
join(staleDir, "03-01-PLAN.md"),
|
|
195
|
+
canonicalPlan.content.replace("- [x] **T03**:", "- [ ] **T03**:"),
|
|
196
|
+
"utf-8",
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const issues: any[] = [];
|
|
200
|
+
await checkEngineHealth(base, issues, []);
|
|
201
|
+
|
|
202
|
+
assert.deepEqual(
|
|
203
|
+
issues.filter((issue) => issue.code === "checkbox_db_status_divergence").map((issue) => issue.unitId),
|
|
204
|
+
[],
|
|
205
|
+
"stale suffixed duplicate phase projection must not compete with the bare milestone projection",
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("checkEngineHealth reads task checkboxes from the canonical milestone worktree", async (t) => {
|
|
210
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-checkbox-worktree-"));
|
|
211
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
212
|
+
|
|
213
|
+
const gsdDir = join(base, ".gsd");
|
|
214
|
+
mkdirSync(gsdDir, { recursive: true });
|
|
215
|
+
|
|
216
|
+
openDatabase(join(gsdDir, "gsd.db"));
|
|
217
|
+
insertMilestone({ id: "M003", title: "Milestone", status: "active" });
|
|
218
|
+
insertSlice({ id: "S01", milestoneId: "M003", title: "Slice", status: "pending", risk: "low", depends: [], sequence: 1 });
|
|
219
|
+
insertTask({ id: "T03", milestoneId: "M003", sliceId: "S01", title: "Task", status: "complete", sequence: 1 });
|
|
220
|
+
|
|
221
|
+
const plan = await renderPlanFromDb(base, "M003", "S01");
|
|
222
|
+
const checkedPlan = readFileSync(plan.planPath, "utf-8");
|
|
223
|
+
writeFileSync(plan.planPath, checkedPlan.replace("- [x] **T03**:", "- [ ] **T03**:"), "utf-8");
|
|
224
|
+
|
|
225
|
+
const worktree = join(base, ".gsd-worktrees", "M003");
|
|
226
|
+
const worktreePlan = join(worktree, ".gsd", "phases", "03-milestone", "03-01-PLAN.md");
|
|
227
|
+
mkdirSync(join(worktree, ".gsd", "phases", "03-milestone"), { recursive: true });
|
|
228
|
+
writeFileSync(join(worktree, ".git"), `gitdir: ${join(base, ".git", "worktrees", "M003")}\n`);
|
|
229
|
+
writeFileSync(worktreePlan, checkedPlan, "utf-8");
|
|
230
|
+
|
|
231
|
+
const issues: any[] = [];
|
|
232
|
+
await checkEngineHealth(base, issues, []);
|
|
233
|
+
|
|
234
|
+
assert.deepEqual(
|
|
235
|
+
issues.filter((issue) => issue.code === "checkbox_db_status_divergence").map((issue) => issue.unitId),
|
|
236
|
+
[],
|
|
237
|
+
"the stale project-root PLAN must not compete with the live milestone worktree projection",
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
170
241
|
test("checkEngineHealth reads task checkboxes from the <tasks> block, not a stray line above it", async (t) => {
|
|
171
242
|
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-task-section-"));
|
|
172
243
|
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
@@ -336,6 +407,38 @@ test("checkEngineHealth reports artifact rows whose files are missing on disk",
|
|
|
336
407
|
assert.equal(missing.fixable, false);
|
|
337
408
|
});
|
|
338
409
|
|
|
410
|
+
test("checkEngineHealth resolves artifact rows through the canonical milestone worktree", async (t) => {
|
|
411
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-artifact-worktree-"));
|
|
412
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
413
|
+
|
|
414
|
+
const gsdDir = join(base, ".gsd");
|
|
415
|
+
const artifactPath = "phases/03-milestone/03-01-PLAN.md";
|
|
416
|
+
const worktree = join(base, ".gsd-worktrees", "M003");
|
|
417
|
+
mkdirSync(gsdDir, { recursive: true });
|
|
418
|
+
mkdirSync(join(worktree, ".gsd", "phases", "03-milestone"), { recursive: true });
|
|
419
|
+
writeFileSync(join(worktree, ".git"), `gitdir: ${join(base, ".git", "worktrees", "M003")}\n`);
|
|
420
|
+
writeFileSync(join(worktree, ".gsd", artifactPath), "# Plan\n", "utf-8");
|
|
421
|
+
|
|
422
|
+
openDatabase(join(gsdDir, "gsd.db"));
|
|
423
|
+
insertArtifact({
|
|
424
|
+
path: artifactPath,
|
|
425
|
+
artifact_type: "PLAN",
|
|
426
|
+
milestone_id: "M003",
|
|
427
|
+
slice_id: "S01",
|
|
428
|
+
task_id: null,
|
|
429
|
+
full_content: "# Plan\n",
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
const issues: any[] = [];
|
|
433
|
+
await checkEngineHealth(base, issues, []);
|
|
434
|
+
|
|
435
|
+
assert.equal(
|
|
436
|
+
issues.some((issue) => issue.code === "artifact_file_missing" && issue.file === artifactPath),
|
|
437
|
+
false,
|
|
438
|
+
"worktree-local artifact rows must not be reported missing from the project root",
|
|
439
|
+
);
|
|
440
|
+
});
|
|
441
|
+
|
|
339
442
|
test("checkEngineHealth resolves escaped .gsd artifact rows against the project .gsd directory", async (t) => {
|
|
340
443
|
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-escaped-artifact-"));
|
|
341
444
|
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
@@ -428,6 +531,50 @@ test("checkEngineHealth repair prunes stale phases artifact rows with present mi
|
|
|
428
531
|
assert.deepEqual(rows.map((row) => row.path), []);
|
|
429
532
|
});
|
|
430
533
|
|
|
534
|
+
test("checkEngineHealth repair prunes stale phases artifact rows with renamed flat-phase files", async (t) => {
|
|
535
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-prune-renamed-flat-phase-artifact-"));
|
|
536
|
+
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
537
|
+
|
|
538
|
+
const gsdDir = join(base, ".gsd");
|
|
539
|
+
const stalePath = "phases/01-new-milestone-m001/01-01-PLAN.md";
|
|
540
|
+
const replacementPath = "phases/01-lokably-brand-foundation-and-welcome-pag/01-01-PLAN.md";
|
|
541
|
+
mkdirSync(join(gsdDir, "phases", "01-lokably-brand-foundation-and-welcome-pag"), { recursive: true });
|
|
542
|
+
writeFileSync(join(gsdDir, replacementPath), "# Plan\n", "utf-8");
|
|
543
|
+
|
|
544
|
+
openDatabase(join(gsdDir, "gsd.db"));
|
|
545
|
+
insertArtifact({
|
|
546
|
+
path: stalePath,
|
|
547
|
+
artifact_type: "PLAN",
|
|
548
|
+
milestone_id: "M001",
|
|
549
|
+
slice_id: "S01",
|
|
550
|
+
task_id: null,
|
|
551
|
+
full_content: "# stale plan\n",
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
const beforeIssues: any[] = [];
|
|
555
|
+
await checkEngineHealth(base, beforeIssues, []);
|
|
556
|
+
|
|
557
|
+
const beforeIssue = beforeIssues.find((issue) => issue.code === "artifact_file_missing" && issue.file === stalePath);
|
|
558
|
+
assert.ok(beforeIssue, "stale renamed phases row should be reported when repair is off");
|
|
559
|
+
assert.equal(beforeIssue.fixable, true, "renamed phases rows with a flat replacement should be fixable");
|
|
560
|
+
|
|
561
|
+
const repairIssues: any[] = [];
|
|
562
|
+
const fixes: string[] = [];
|
|
563
|
+
await checkEngineHealth(base, repairIssues, fixes, { repair: true });
|
|
564
|
+
|
|
565
|
+
assert.equal(
|
|
566
|
+
repairIssues.some((issue) => issue.code === "artifact_file_missing" && issue.file === stalePath),
|
|
567
|
+
false,
|
|
568
|
+
"repair should not report stale rows it pruned",
|
|
569
|
+
);
|
|
570
|
+
assert.ok(fixes.includes(`pruned stale flat-phase artifact row ${stalePath}`));
|
|
571
|
+
|
|
572
|
+
const rows = _getAdapter()!
|
|
573
|
+
.prepare("SELECT path FROM artifacts ORDER BY path")
|
|
574
|
+
.all() as Array<{ path: string }>;
|
|
575
|
+
assert.deepEqual(rows.map((row) => row.path), []);
|
|
576
|
+
});
|
|
577
|
+
|
|
431
578
|
test("checkEngineHealth repair keeps phases rows whose own file is still present", async (t) => {
|
|
432
579
|
const base = mkdtempSync(join(tmpdir(), "gsd-doctor-keep-present-phase-artifact-"));
|
|
433
580
|
t.after(() => rmSync(base, { recursive: true, force: true }));
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { test } from 'node:test';
|
|
5
5
|
import assert from 'node:assert/strict';
|
|
6
|
-
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
6
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
|
|
@@ -152,6 +152,38 @@ test('runExecSandbox: node runtime executes JS', async () => {
|
|
|
152
152
|
}
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
+
test('runExecSandbox: node runtime forwards NODE_PATH for GSD-installed dependencies', async () => {
|
|
156
|
+
const base = freshBase();
|
|
157
|
+
try {
|
|
158
|
+
const dependencyRoot = join(base, 'parent-node_modules');
|
|
159
|
+
const packageDir = join(dependencyRoot, 'fake-gsd-dep');
|
|
160
|
+
const worktree = join(base, 'project', '.gsd', 'worktrees', 'M003');
|
|
161
|
+
mkdirSync(packageDir, { recursive: true });
|
|
162
|
+
mkdirSync(worktree, { recursive: true });
|
|
163
|
+
writeFileSync(
|
|
164
|
+
join(packageDir, 'package.json'),
|
|
165
|
+
JSON.stringify({ name: 'fake-gsd-dep', version: '1.0.0', main: 'index.js' }),
|
|
166
|
+
);
|
|
167
|
+
writeFileSync(join(packageDir, 'index.js'), "module.exports = 'resolved-via-node-path';\n");
|
|
168
|
+
|
|
169
|
+
const result = await runExecSandbox(
|
|
170
|
+
{ runtime: 'node', script: "console.log(require('fake-gsd-dep'))" },
|
|
171
|
+
baseOpts(worktree, {
|
|
172
|
+
env: {
|
|
173
|
+
PATH: '/usr/bin:/bin',
|
|
174
|
+
HOME: '/tmp',
|
|
175
|
+
NODE_PATH: dependencyRoot,
|
|
176
|
+
},
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
assert.equal(result.exit_code, 0, readFileSync(result.stderr_path, 'utf-8'));
|
|
181
|
+
assert.ok(result.digest.includes('resolved-via-node-path'));
|
|
182
|
+
} finally {
|
|
183
|
+
cleanup(base);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
155
187
|
test('runExecSandbox: rewrites NUL redirects for bash on Windows', async () => {
|
|
156
188
|
const originalPlatform = process.platform;
|
|
157
189
|
Object.defineProperty(process, 'platform', { value: 'win32' });
|
|
@@ -8,7 +8,8 @@ import { tmpdir } from "node:os";
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
|
|
10
10
|
import { externalMarkdownEditHandler } from "../state-reconciliation/drift/external-markdown-edit.ts";
|
|
11
|
-
import { writeCompatMarker, computeProjectionSha } from "../compat/compat-marker.ts";
|
|
11
|
+
import { readCompatMarker, writeCompatMarker, computeProjectionSha } from "../compat/compat-marker.ts";
|
|
12
|
+
import { closeDatabase, insertArtifact, openDatabase } from "../gsd-db.ts";
|
|
12
13
|
import type { DriftContext } from "../state-reconciliation/types.ts";
|
|
13
14
|
import type { GSDState } from "../types.ts";
|
|
14
15
|
|
|
@@ -28,6 +29,11 @@ function ctx(base: string): DriftContext {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
afterEach(() => {
|
|
32
|
+
try {
|
|
33
|
+
closeDatabase();
|
|
34
|
+
} catch {
|
|
35
|
+
/* noop */
|
|
36
|
+
}
|
|
31
37
|
for (const dir of tmpDirs) {
|
|
32
38
|
try { rmSync(dir, { recursive: true, force: true }); } catch { /* */ }
|
|
33
39
|
}
|
|
@@ -71,6 +77,37 @@ test("detect returns drift when file content differs from marker", async () => {
|
|
|
71
77
|
assert.deepEqual(drift[0].entities, ["m1"]);
|
|
72
78
|
});
|
|
73
79
|
|
|
80
|
+
test("detect refreshes stale marker when current file already matches DB artifact", async () => {
|
|
81
|
+
const base = makeTmpBase();
|
|
82
|
+
const rel = "milestones/M001/M001-ROADMAP.md";
|
|
83
|
+
const dbRel = "phases/01-alpha/01-ROADMAP.md";
|
|
84
|
+
const content = "# M001: Alpha\n\n## Slices\n\n- [ ] **S01: Work** `risk:low` `depends:[]`\n";
|
|
85
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
86
|
+
writeFileSync(join(base, ".gsd", rel), content, "utf-8");
|
|
87
|
+
openDatabase(join(base, ".gsd", "gsd.db"));
|
|
88
|
+
insertArtifact({
|
|
89
|
+
path: dbRel,
|
|
90
|
+
artifact_type: "ROADMAP",
|
|
91
|
+
milestone_id: "M001",
|
|
92
|
+
slice_id: null,
|
|
93
|
+
task_id: null,
|
|
94
|
+
full_content: content,
|
|
95
|
+
});
|
|
96
|
+
writeCompatMarker(base, {
|
|
97
|
+
schema: 2,
|
|
98
|
+
lastWriter: "gsd-pi",
|
|
99
|
+
lastProjectedAt: "2026-06-21T00:00:00.000Z",
|
|
100
|
+
projections: { [rel]: { sha: "stale000000000000", entities: ["M001"] } },
|
|
101
|
+
planning: { active: false, layout: null, projections: {}, passthrough: {} },
|
|
102
|
+
piVersion: "1.9.0",
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const drift = await externalMarkdownEditHandler.detect(stubState, ctx(base));
|
|
106
|
+
assert.equal(drift.length, 0);
|
|
107
|
+
const marker = readCompatMarker(base);
|
|
108
|
+
assert.equal(marker.projections[rel]?.sha, computeProjectionSha(content));
|
|
109
|
+
});
|
|
110
|
+
|
|
74
111
|
test("detect treats missing marker as drift on every tracked projection file", async () => {
|
|
75
112
|
const base = makeTmpBase();
|
|
76
113
|
const rel = "m1/roadmap.md";
|
|
@@ -122,7 +122,7 @@ test("migrateToFlatPhase creates a backup", async () => {
|
|
|
122
122
|
assert.ok(backups.length >= 1, "at least one migrate-* backup dir should exist");
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
-
test("migrateToFlatPhase
|
|
125
|
+
test("migrateToFlatPhase removes disposable phases snapshot after successful migration", async () => {
|
|
126
126
|
const base = makeTmp();
|
|
127
127
|
const reviewPath = join(base, ".gsd", "phases", "01-foundation", "PLAN-REVIEW.md");
|
|
128
128
|
mkdirSync(join(base, ".gsd", "phases", "01-foundation"), { recursive: true });
|
|
@@ -133,11 +133,10 @@ test("migrateToFlatPhase backs up existing phases projection before clearing it"
|
|
|
133
133
|
const backupRoot = join(base, ".gsd-backups");
|
|
134
134
|
const backups = readdirSync(backupRoot).filter(d => d.startsWith("migrate-"));
|
|
135
135
|
assert.equal(backups.length, 1, "one migrate backup should exist");
|
|
136
|
-
const backedUpReview = join(backupRoot, backups[0]!, "__phases", "01-foundation", "PLAN-REVIEW.md");
|
|
137
136
|
assert.equal(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
"
|
|
137
|
+
existsSync(join(backupRoot, backups[0]!, "__phases")),
|
|
138
|
+
false,
|
|
139
|
+
"temporary phases/ recovery snapshot should be removed after success",
|
|
141
140
|
);
|
|
142
141
|
});
|
|
143
142
|
|
|
@@ -202,7 +201,7 @@ test("failed migration rolls back without leaking a .gsd-backups/migrate-* dir",
|
|
|
202
201
|
assert.equal(leaked.length, 0, "rollback must delete the migrate-* backup it created");
|
|
203
202
|
});
|
|
204
203
|
|
|
205
|
-
test("resumed migration
|
|
204
|
+
test("resumed migration removes disposable phases snapshot after success", async () => {
|
|
206
205
|
const base = makeTmp();
|
|
207
206
|
const milestonesPath = join(base, ".gsd", "milestones");
|
|
208
207
|
const migratingPath = join(base, ".gsd", "milestones.migrating");
|
|
@@ -218,9 +217,9 @@ test("resumed migration stores phases backup in retained migrate snapshot", asyn
|
|
|
218
217
|
const backups = readdirSync(backupRoot).filter((d) => d.startsWith("migrate-"));
|
|
219
218
|
assert.equal(backups.length, 1, "resumed migration should create one retained migrate backup");
|
|
220
219
|
assert.equal(
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
"
|
|
220
|
+
existsSync(join(backupRoot, backups[0]!, "__phases")),
|
|
221
|
+
false,
|
|
222
|
+
"temporary phases/ recovery snapshot should be removed after resumed success",
|
|
224
223
|
);
|
|
225
224
|
assert.equal(
|
|
226
225
|
existsSync(join(migratingPath, "__phases")),
|
|
@@ -9,7 +9,7 @@ import { join } from "node:path";
|
|
|
9
9
|
import assert from "node:assert/strict";
|
|
10
10
|
import test from "node:test";
|
|
11
11
|
|
|
12
|
-
import { normalizeRealPath, relMilestoneFile, relSliceFile, resolveMilestoneFile, targetMilestoneFile } from "../paths.ts";
|
|
12
|
+
import { normalizeRealPath, relMilestoneFile, relSliceFile, resolveMilestoneFile, resolveSliceFile, targetMilestoneFile } from "../paths.ts";
|
|
13
13
|
|
|
14
14
|
function makeFlatPhaseFixture(): { basePath: string; cleanup: () => void } {
|
|
15
15
|
const basePath = mkdtempSync(join(tmpdir(), "flat-phase-validation-"));
|
|
@@ -99,6 +99,25 @@ test("flat-phase: resolveMilestoneFile finds the on-disk file", (t) => {
|
|
|
99
99
|
assert.equal(existsSync(abs!), true);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
+
test("flat-phase: file resolvers ignore directories with artifact-like names", (t) => {
|
|
103
|
+
const basePath = mkdtempSync(join(tmpdir(), "flat-phase-dir-artifacts-"));
|
|
104
|
+
t.after(() => rmSync(basePath, { recursive: true, force: true }));
|
|
105
|
+
const phaseDir = join(basePath, ".gsd", "phases", "03-match-capture-manual-entry");
|
|
106
|
+
mkdirSync(join(phaseDir, "03-VALIDATION.md"), { recursive: true });
|
|
107
|
+
mkdirSync(join(phaseDir, "03-01-SUMMARY.md"), { recursive: true });
|
|
108
|
+
|
|
109
|
+
assert.equal(
|
|
110
|
+
resolveMilestoneFile(basePath, "M003", "VALIDATION"),
|
|
111
|
+
null,
|
|
112
|
+
"milestone resolver must not return a directory as a validation file",
|
|
113
|
+
);
|
|
114
|
+
assert.equal(
|
|
115
|
+
resolveSliceFile(basePath, "M003", "S01", "SUMMARY"),
|
|
116
|
+
null,
|
|
117
|
+
"slice resolver must not return a directory as a summary file",
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
|
|
102
121
|
test("flat-phase: the legacy hardcoded path does NOT resolve (regression for #876)", (t) => {
|
|
103
122
|
const { basePath, cleanup } = makeFlatPhaseFixture();
|
|
104
123
|
t.after(cleanup);
|
|
@@ -46,6 +46,9 @@ import {
|
|
|
46
46
|
tryCreateMemoriesFts,
|
|
47
47
|
_isLikelyWslDrvFsPathForTest,
|
|
48
48
|
_shouldAttemptVacuumRecoveryForTest,
|
|
49
|
+
insertArtifact,
|
|
50
|
+
getArtifact,
|
|
51
|
+
upsertMilestonePlanning,
|
|
49
52
|
} from '../gsd-db.ts';
|
|
50
53
|
import { MigrationBackupError } from '../db-migration-backup.ts';
|
|
51
54
|
import { _resetLogs, peekLogs, setStderrLoggingEnabled } from '../workflow-logger.ts';
|
|
@@ -357,6 +360,35 @@ describe('gsd-db', () => {
|
|
|
357
360
|
closeDatabase();
|
|
358
361
|
});
|
|
359
362
|
|
|
363
|
+
test("gsd-db: upsertMilestonePlanning rewrites placeholder phase artifact paths to final title slug", () => {
|
|
364
|
+
openDatabase(":memory:");
|
|
365
|
+
|
|
366
|
+
const stalePath = "phases/01-new-milestone-m001/01-ROADMAP.md";
|
|
367
|
+
const finalPath = "phases/01-lokably-brand-foundation-and-welcome-pag/01-ROADMAP.md";
|
|
368
|
+
insertMilestone({ id: "M001", title: "New milestone M001", status: "active" });
|
|
369
|
+
insertArtifact({
|
|
370
|
+
path: stalePath,
|
|
371
|
+
artifact_type: "ROADMAP",
|
|
372
|
+
milestone_id: "M001",
|
|
373
|
+
slice_id: null,
|
|
374
|
+
task_id: null,
|
|
375
|
+
full_content: "# Placeholder roadmap\n",
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
upsertMilestonePlanning("M001", {
|
|
379
|
+
title: "Lokably brand foundation and welcome page rebuild",
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
assert.equal(getArtifact(stalePath), null, "placeholder-derived artifact row should be removed");
|
|
383
|
+
assert.equal(
|
|
384
|
+
getArtifact(finalPath)?.full_content,
|
|
385
|
+
"# Placeholder roadmap\n",
|
|
386
|
+
"artifact row should move to the final title-derived phase path",
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
closeDatabase();
|
|
390
|
+
});
|
|
391
|
+
|
|
360
392
|
test('gsd-db: active_requirements view excludes superseded', () => {
|
|
361
393
|
openDatabase(':memory:');
|
|
362
394
|
|
package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts
CHANGED
|
@@ -87,6 +87,28 @@ test("guided milestone prompt builder preloads milestone planning context", asyn
|
|
|
87
87
|
}
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
test("guided milestone prompt builder prepends configured response language", async () => {
|
|
91
|
+
const base = mkdtempSync(join(tmpdir(), "gsd-guided-milestone-language-"));
|
|
92
|
+
const gsdHome = mkdtempSync(join(tmpdir(), "gsd-guided-milestone-language-home-"));
|
|
93
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
94
|
+
process.env.GSD_HOME = gsdHome;
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
writeFileSync(join(gsdHome, "PREFERENCES.md"), "---\nversion: 1\nlanguage: 中文\n---\n", "utf-8");
|
|
98
|
+
|
|
99
|
+
const prompt = await buildDiscussMilestonePrompt("M001", "Language Preference", base, "true", {
|
|
100
|
+
includeContextMode: false,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
assert.match(prompt, /^## Response Language\n\nAlways respond in 中文/);
|
|
104
|
+
} finally {
|
|
105
|
+
if (previousGsdHome === undefined) delete process.env.GSD_HOME;
|
|
106
|
+
else process.env.GSD_HOME = previousGsdHome;
|
|
107
|
+
rmSync(base, { recursive: true, force: true });
|
|
108
|
+
rmSync(gsdHome, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
90
112
|
test("guided milestone prompt builder caps prior draft seed before interpolation", async () => {
|
|
91
113
|
const base = mkdtempSync(join(tmpdir(), "gsd-guided-milestone-draft-cap-"));
|
|
92
114
|
const previousGsdHome = process.env.GSD_HOME;
|
|
@@ -1428,6 +1428,19 @@ process.exit(result.status ?? 0);
|
|
|
1428
1428
|
rmSync(repo, { recursive: true, force: true });
|
|
1429
1429
|
});
|
|
1430
1430
|
|
|
1431
|
+
test('Integration branch: write does not create legacy milestones scaffold', () => {
|
|
1432
|
+
const repo = initBranchTestRepo();
|
|
1433
|
+
mkdirSync(join(repo, ".gsd", "phases"), { recursive: true });
|
|
1434
|
+
|
|
1435
|
+
writeIntegrationBranch(repo, "M001", "f-123-new-thing");
|
|
1436
|
+
|
|
1437
|
+
assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-new-thing");
|
|
1438
|
+
assert.ok(existsSync(join(repo, ".gsd", "M001-META.json")), "metadata is written at the flat .gsd root");
|
|
1439
|
+
assert.ok(!existsSync(join(repo, ".gsd", "milestones")), "legacy milestones/ root is not created");
|
|
1440
|
+
|
|
1441
|
+
rmSync(repo, { recursive: true, force: true });
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1431
1444
|
// ─── writeIntegrationBranch: updates when branch changes (#300) ──────
|
|
1432
1445
|
|
|
1433
1446
|
test('Integration branch: updates on branch change', () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, mkdirSync, rmSync, realpathSync, symlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, realpathSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { spawnSync } from "node:child_process";
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
resolveGsdPathContract,
|
|
13
13
|
resolveSliceFile,
|
|
14
14
|
resolveTaskFile,
|
|
15
|
+
resolveTaskFiles,
|
|
16
|
+
taskIdFromTaskFileName,
|
|
15
17
|
_clearGsdRootCache,
|
|
16
18
|
} from "../../paths.ts";
|
|
17
19
|
/** Create a tmp dir and resolve symlinks + 8.3 short names (macOS /var→/private/var, Windows RUNNER~1→runneradmin). */
|
|
@@ -171,21 +173,37 @@ describe('paths', () => {
|
|
|
171
173
|
test('Case 9: flat-phase task SUMMARY resolves at phase root despite a stray slices/SID/ dir', () => {
|
|
172
174
|
const root = tmp();
|
|
173
175
|
try {
|
|
174
|
-
// Hybrid flat-phase milestone: phase dir holds flat
|
|
176
|
+
// Hybrid flat-phase milestone: phase dir holds flat task summaries, but a
|
|
175
177
|
// stray slices/S01/ folder also exists on disk. resolveSlicePath then points
|
|
176
178
|
// under slices/, so layout (phases/ vs milestones/) — not slicePath===phaseDir
|
|
177
179
|
// — must decide the flat-phase task summary location.
|
|
178
180
|
const phaseDir = join(root, ".gsd", "phases", "01-foo");
|
|
179
181
|
mkdirSync(join(phaseDir, "slices", "S01"), { recursive: true });
|
|
180
|
-
const flatSummary = join(phaseDir, "T01-SUMMARY.md");
|
|
182
|
+
const flatSummary = join(phaseDir, "S01-T01-SUMMARY.md");
|
|
183
|
+
const legacyFlatSummary = join(phaseDir, "T01-SUMMARY.md");
|
|
181
184
|
writeFileSync(flatSummary, "# task summary\n");
|
|
185
|
+
writeFileSync(legacyFlatSummary, "# legacy task summary\n");
|
|
182
186
|
|
|
183
187
|
_clearGsdRootCache();
|
|
184
188
|
|
|
189
|
+
assert.deepStrictEqual(resolveTaskFiles(phaseDir, "SUMMARY").sort(), [
|
|
190
|
+
"S01-T01-SUMMARY.md",
|
|
191
|
+
"T01-SUMMARY.md",
|
|
192
|
+
]);
|
|
193
|
+
assert.equal(taskIdFromTaskFileName("S01-T01-SUMMARY.md", "SUMMARY"), "T01");
|
|
194
|
+
assert.equal(taskIdFromTaskFileName("T01-SUMMARY.md", "SUMMARY"), "T01");
|
|
195
|
+
|
|
185
196
|
assert.deepStrictEqual(
|
|
186
197
|
resolveTaskFile(root, "M001", "S01", "T01", "SUMMARY"),
|
|
187
198
|
flatSummary,
|
|
188
|
-
"flat-phase
|
|
199
|
+
"flat-phase S01-T01-SUMMARY.md at phase root is preferred even when slices/S01/ exists",
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
unlinkSync(flatSummary);
|
|
203
|
+
assert.deepStrictEqual(
|
|
204
|
+
resolveTaskFile(root, "M001", "S01", "T01", "SUMMARY"),
|
|
205
|
+
legacyFlatSummary,
|
|
206
|
+
"legacy flat T01-SUMMARY.md is still found as a fallback",
|
|
189
207
|
);
|
|
190
208
|
} finally { cleanup(root); }
|
|
191
209
|
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// gsd-pi — Integration-branch META lives OUTSIDE milestones/<MID>/ (ADR-045).
|
|
2
|
+
// Verifies the relocation from milestones/<MID>/<MID>-META.json to the flat
|
|
3
|
+
// .gsd/<MID>-META.json so it can never poison isLegacyMilestonesLayout.
|
|
4
|
+
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { afterEach, beforeEach, test } from "node:test";
|
|
7
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
|
|
11
|
+
import { readIntegrationBranch, writeIntegrationBranch } from "../git-service.js";
|
|
12
|
+
import { gsdRoot, isLegacyMilestonesLayout } from "../paths.js";
|
|
13
|
+
|
|
14
|
+
let repo: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
repo = mkdtempSync(join(tmpdir(), "gsd-meta-loc-"));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
rmSync(repo, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("write goes to the new flat .gsd/<MID>-META.json, not milestones/<MID>/", () => {
|
|
25
|
+
writeIntegrationBranch(repo, "M001", "main");
|
|
26
|
+
|
|
27
|
+
assert.ok(
|
|
28
|
+
existsSync(join(gsdRoot(repo), "M001-META.json")),
|
|
29
|
+
"META written to flat .gsd/<MID>-META.json",
|
|
30
|
+
);
|
|
31
|
+
assert.ok(
|
|
32
|
+
!existsSync(join(gsdRoot(repo), "milestones", "M001", "M001-META.json")),
|
|
33
|
+
"no META in legacy milestones/<MID>/ location",
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("round-trip: read returns what write recorded", () => {
|
|
38
|
+
writeIntegrationBranch(repo, "M001", "main");
|
|
39
|
+
assert.equal(readIntegrationBranch(repo, "M001"), "main");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("read falls back to the legacy milestones/<MID>/ location", () => {
|
|
43
|
+
const legacyDir = join(gsdRoot(repo), "milestones", "M001");
|
|
44
|
+
mkdirSync(legacyDir, { recursive: true });
|
|
45
|
+
writeFileSync(
|
|
46
|
+
join(legacyDir, "M001-META.json"),
|
|
47
|
+
JSON.stringify({ integrationBranch: "develop" }) + "\n",
|
|
48
|
+
"utf-8",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
assert.equal(readIntegrationBranch(repo, "M001"), "develop");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("writing META does not create milestones/<MID>/ or flip layout detection", () => {
|
|
55
|
+
assert.equal(isLegacyMilestonesLayout(repo), false, "clean tree is not legacy layout");
|
|
56
|
+
writeIntegrationBranch(repo, "M001", "main");
|
|
57
|
+
assert.equal(
|
|
58
|
+
isLegacyMilestonesLayout(repo),
|
|
59
|
+
false,
|
|
60
|
+
"writing integration-branch META must not poison layout detection",
|
|
61
|
+
);
|
|
62
|
+
});
|