@opengsd/gsd-pi 1.7.0 → 1.8.1-dev.897b3c90
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 +8 -6
- package/dist/cli.js +5 -1
- package/dist/headless-events.d.ts +2 -1
- package/dist/headless-events.js +11 -3
- package/dist/headless-milestone-readiness.d.ts +29 -0
- package/dist/headless-milestone-readiness.js +161 -0
- package/dist/headless.js +25 -2
- package/dist/print-mode-exit.d.ts +12 -0
- package/dist/print-mode-exit.js +14 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +16 -47
- package/dist/resources/extensions/browser-tools/capture.js +2 -77
- package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +35 -1
- package/dist/resources/extensions/gsd/auto.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +78 -4
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +84 -26
- package/dist/resources/extensions/gsd/command-feedback.js +16 -12
- package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
- package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
- package/dist/resources/extensions/gsd/db/engine.js +51 -16
- package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
- package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
- package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
- package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -4
- package/dist/resources/extensions/gsd/doctor-history.js +65 -0
- package/dist/resources/extensions/gsd/doctor-state-checks.js +509 -0
- package/dist/resources/extensions/gsd/doctor-workspace-checks.js +91 -0
- package/dist/resources/extensions/gsd/doctor.js +14 -653
- package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
- package/dist/resources/extensions/gsd/gsd-db.js +187 -45
- package/dist/resources/extensions/gsd/guided-flow.js +29 -10
- package/dist/resources/extensions/gsd/markdown-renderer.js +16 -2
- package/dist/resources/extensions/gsd/md-importer.js +109 -16
- package/dist/resources/extensions/gsd/migrate/command.js +19 -162
- package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
- package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
- package/dist/resources/extensions/gsd/migrate/planning-writer.js +20 -19
- package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +4 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
- package/dist/resources/extensions/gsd/paths.js +4 -1
- package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
- package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +54 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +48 -5
- package/dist/resources/extensions/gsd/stop-notice.js +15 -1
- package/dist/resources/extensions/gsd/sync-lock.js +13 -7
- package/dist/resources/extensions/gsd/tools/complete-task.js +82 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
- package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
- package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
- package/dist/resources/extensions/gsd/unit-registry.js +4 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
- package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
- package/dist/resources/extensions/mac-tools/index.js +31 -9
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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 +4 -4
- 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.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 +5 -5
- 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 +5 -5
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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/2842.js +4 -4
- 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/.next/static/css/3b1ceb7abfb9a230.css +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/package.json +0 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +31 -3
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +12 -10
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/cloud-config.d.ts +1 -1
- package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
- package/packages/daemon/dist/cloud-config.js +30 -8
- package/packages/daemon/dist/cloud-config.js.map +1 -1
- package/packages/daemon/dist/cloud-config.test.js +69 -1
- package/packages/daemon/dist/cloud-config.test.js.map +1 -1
- package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
- package/packages/daemon/dist/local-tool-executor.js +2 -0
- package/packages/daemon/dist/local-tool-executor.js.map +1 -1
- package/packages/daemon/package.json +6 -6
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +18 -4
- package/packages/gsd-cloud/bin/gsd-cloud.js +6 -5
- package/packages/gsd-cloud/dist/cli.d.ts +5 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cli.js +160 -0
- package/packages/gsd-cloud/dist/cli.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.js +231 -0
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.js +37 -0
- package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
- package/packages/gsd-cloud/dist/config.d.ts +17 -0
- package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/config.js +146 -0
- package/packages/gsd-cloud/dist/config.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.js +128 -0
- package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
- package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.js +11 -0
- package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.js +29 -0
- package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
- package/packages/gsd-cloud/dist/index.d.ts +7 -0
- package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/index.js +8 -0
- package/packages/gsd-cloud/dist/index.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
- package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
- package/packages/gsd-cloud/dist/logger.d.ts +25 -0
- package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/logger.js +72 -0
- package/packages/gsd-cloud/dist/logger.js.map +1 -0
- package/packages/gsd-cloud/dist/types.d.ts +51 -0
- package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/types.js +9 -0
- package/packages/gsd-cloud/dist/types.js.map +1 -0
- package/packages/gsd-cloud/package.json +7 -5
- package/packages/mcp-server/README.md +8 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +64 -2
- 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/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +60 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +54 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +19 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/package.json +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/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +16 -47
- package/src/resources/extensions/browser-tools/capture.ts +2 -86
- package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
- package/src/resources/extensions/gsd/auto.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
- package/src/resources/extensions/gsd/command-feedback.ts +19 -12
- package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
- package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
- package/src/resources/extensions/gsd/db/engine.ts +53 -17
- package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
- package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
- package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
- package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
- package/src/resources/extensions/gsd/doctor-history.ts +81 -0
- package/src/resources/extensions/gsd/doctor-state-checks.ts +527 -0
- package/src/resources/extensions/gsd/doctor-workspace-checks.ts +97 -0
- package/src/resources/extensions/gsd/doctor.ts +14 -673
- package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
- package/src/resources/extensions/gsd/gsd-db.ts +255 -52
- package/src/resources/extensions/gsd/guided-flow.ts +39 -10
- package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
- package/src/resources/extensions/gsd/md-importer.ts +116 -13
- package/src/resources/extensions/gsd/migrate/command.ts +21 -227
- package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
- package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
- package/src/resources/extensions/gsd/migrate/planning-writer.ts +21 -23
- package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +3 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
- package/src/resources/extensions/gsd/paths.ts +4 -1
- package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
- package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +67 -20
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +47 -5
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
- package/src/resources/extensions/gsd/stop-notice.ts +18 -1
- package/src/resources/extensions/gsd/sync-lock.ts +14 -6
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
- package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/doctor-history-public-api.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
- package/src/resources/extensions/gsd/tests/planning-writer.test.ts +47 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +18 -3
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +177 -25
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
- package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
- package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
- package/src/resources/extensions/gsd/types.ts +11 -0
- package/src/resources/extensions/gsd/unit-registry.ts +4 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
- package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
- package/src/resources/extensions/mac-tools/index.ts +52 -9
- package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
- 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/css/18c2fdf261bfc1b7.css +0 -1
- /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
|
@@ -9,6 +9,7 @@ import { mkdirSync } from "node:fs";
|
|
|
9
9
|
import { join, relative } from "node:path";
|
|
10
10
|
import { getAllMilestones, getMilestoneSlices, getSliceTasks } from "../gsd-db.js";
|
|
11
11
|
import { saveFile } from "../files.js";
|
|
12
|
+
import { isClosedStatus } from "../status-guards.js";
|
|
12
13
|
import { applyPlanningProjectionWrites, } from "../compat/planning-compat.js";
|
|
13
14
|
function planningRoot(basePath) {
|
|
14
15
|
return join(basePath, ".planning");
|
|
@@ -86,7 +87,11 @@ function formatPlanningPlan(phaseNum, planNum, title, tasks) {
|
|
|
86
87
|
lines.push("<tasks>");
|
|
87
88
|
for (const t of tasks) {
|
|
88
89
|
const est = t.estimate ? ` _(${t.estimate})_` : "";
|
|
89
|
-
|
|
90
|
+
// Render the checkbox from the task's DB status so a DB→.planning
|
|
91
|
+
// projection preserves completion. Hardcoding `[ ]` here silently reset
|
|
92
|
+
// every completed historical task to unchecked on each reconcile (#1276).
|
|
93
|
+
const box = t.done ? "[x]" : "[ ]";
|
|
94
|
+
lines.push(`- ${box} **${t.id}**: ${t.title}${est}`);
|
|
90
95
|
}
|
|
91
96
|
lines.push("</tasks>");
|
|
92
97
|
lines.push("");
|
|
@@ -131,21 +136,21 @@ export async function writePlanningDirectory(basePath, layout) {
|
|
|
131
136
|
const phaseDir = join(root, "phases", phaseDirName);
|
|
132
137
|
mkdirSync(phaseDir, { recursive: true });
|
|
133
138
|
const tasks = getSliceTasks(milestone.id, slice.id);
|
|
134
|
-
const isDone = tasks.length > 0 && tasks.every((t) => t.status
|
|
139
|
+
const isDone = tasks.length > 0 && tasks.every((t) => isClosedStatus(t.status));
|
|
135
140
|
roadmapEntries.push({
|
|
136
141
|
number: phaseNum,
|
|
137
142
|
title: slice.title || slice.id,
|
|
138
143
|
done: isDone,
|
|
139
144
|
});
|
|
140
145
|
if (tasks.length === 0) {
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
// Sketch / undecomposed slice — zero tasks. Do NOT emit an ingestible
|
|
147
|
+
// *-PLAN.md here: the reverse transform maps one GSDTask per plan file
|
|
148
|
+
// (transformer.ts mapSlice), so a placeholder would materialize a
|
|
149
|
+
// phantom "Plan NN" task and flip the slice from "needs planning" to
|
|
150
|
+
// "has a planned task", causing auto-mode to skip planning (issue #1285).
|
|
151
|
+
// The phase dir is already created (mkdirSync above) and the slice is
|
|
152
|
+
// listed in ROADMAP.md, so it round-trips with tasks = [] — the correct
|
|
153
|
+
// sketch-slice shape.
|
|
149
154
|
}
|
|
150
155
|
else {
|
|
151
156
|
for (let ti = 0; ti < tasks.length; ti++) {
|
|
@@ -157,6 +162,7 @@ export async function writePlanningDirectory(basePath, layout) {
|
|
|
157
162
|
id: task.id,
|
|
158
163
|
title: task.title || task.id,
|
|
159
164
|
estimate: task.estimate || undefined,
|
|
165
|
+
done: isClosedStatus(task.status),
|
|
160
166
|
},
|
|
161
167
|
]));
|
|
162
168
|
paths.push(planPath);
|
|
@@ -168,19 +174,14 @@ export async function writePlanningDirectory(basePath, layout) {
|
|
|
168
174
|
}
|
|
169
175
|
}
|
|
170
176
|
}
|
|
171
|
-
// If no slices produced any phases,
|
|
172
|
-
//
|
|
177
|
+
// If no slices produced any phases, emit a single empty phase dir + ROADMAP
|
|
178
|
+
// entry so the layout stays discoverable. Do NOT write a placeholder
|
|
179
|
+
// *-PLAN.md — an ingestible plan file would round-trip into a phantom task
|
|
180
|
+
// (see the tasks.length === 0 branch above, issue #1285).
|
|
173
181
|
if (roadmapEntries.length === 0) {
|
|
174
182
|
const phaseDirName = `${pad(1)}-milestone`;
|
|
175
183
|
const phaseDir = join(root, "phases", phaseDirName);
|
|
176
184
|
mkdirSync(phaseDir, { recursive: true });
|
|
177
|
-
const planPath = join(phaseDir, `${pad(1)}-01-PLAN.md`);
|
|
178
|
-
await saveFile(planPath, formatPlanningPlan(1, 1, milestones[0].title || milestones[0].id, []));
|
|
179
|
-
paths.push(planPath);
|
|
180
|
-
projectionWrites.push({
|
|
181
|
-
relPath: toPlanningRel(planPath),
|
|
182
|
-
entities: [milestones[0].id],
|
|
183
|
-
});
|
|
184
185
|
roadmapEntries.push({ number: 1, title: milestones[0].title || milestones[0].id, done: false });
|
|
185
186
|
}
|
|
186
187
|
// Root files
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// gsd-pi - /gsd migrate presentation helpers.
|
|
2
|
+
// File Purpose: Pure formatting for migration previews and post-write review prompts.
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { gsdRoot } from "../paths.js";
|
|
7
|
+
function formatRequirements(preview) {
|
|
8
|
+
if (preview.requirements.total === 0)
|
|
9
|
+
return null;
|
|
10
|
+
return `Requirements: ${preview.requirements.total} (${preview.requirements.validated} validated, ${preview.requirements.active} active, ${preview.requirements.deferred} deferred, ${preview.requirements.outOfScope} out of scope)`;
|
|
11
|
+
}
|
|
12
|
+
function formatLegacyInputs(preview) {
|
|
13
|
+
if (!preview.migrationInputs)
|
|
14
|
+
return null;
|
|
15
|
+
return `Legacy inputs: ${preview.migrationInputs.milestonePhaseDirs} milestone phase dir(s), ${preview.migrationInputs.decisions} decision file(s), ${preview.migrationInputs.seeds} seed file(s)`;
|
|
16
|
+
}
|
|
17
|
+
export function buildMigrationPreviewSummary(preview, targetRoot) {
|
|
18
|
+
const lines = [
|
|
19
|
+
`Decisions: ${preview.decisions.total}`,
|
|
20
|
+
`Milestones: ${preview.milestoneCount}`,
|
|
21
|
+
`Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
|
|
22
|
+
`Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
|
|
23
|
+
];
|
|
24
|
+
const requirements = formatRequirements(preview);
|
|
25
|
+
if (requirements)
|
|
26
|
+
lines.push(requirements);
|
|
27
|
+
const legacyInputs = formatLegacyInputs(preview);
|
|
28
|
+
if (legacyInputs)
|
|
29
|
+
lines.push(legacyInputs);
|
|
30
|
+
const targetGsdPath = gsdRoot(targetRoot);
|
|
31
|
+
if (existsSync(targetGsdPath)) {
|
|
32
|
+
lines.push("");
|
|
33
|
+
lines.push(`⚠ A .gsd directory already exists at ${targetGsdPath}.`);
|
|
34
|
+
lines.push("It will be backed up, deleted, and rewritten fresh before DB import.");
|
|
35
|
+
}
|
|
36
|
+
return lines;
|
|
37
|
+
}
|
|
38
|
+
export function formatMigrationPreviewStats(preview) {
|
|
39
|
+
const lines = [
|
|
40
|
+
`- Decisions: ${preview.decisions.total}`,
|
|
41
|
+
`- Milestones: ${preview.milestoneCount}`,
|
|
42
|
+
`- Slices: ${preview.totalSlices} (${preview.doneSlices} done — ${preview.sliceCompletionPct}%)`,
|
|
43
|
+
`- Tasks: ${preview.totalTasks} (${preview.doneTasks} done — ${preview.taskCompletionPct}%)`,
|
|
44
|
+
];
|
|
45
|
+
const requirements = formatRequirements(preview);
|
|
46
|
+
if (requirements)
|
|
47
|
+
lines.push(`- ${requirements}`);
|
|
48
|
+
const legacyInputs = formatLegacyInputs(preview);
|
|
49
|
+
if (legacyInputs)
|
|
50
|
+
lines.push(`- ${legacyInputs}`);
|
|
51
|
+
return lines.join("\n");
|
|
52
|
+
}
|
|
53
|
+
function defaultReviewTemplatePath() {
|
|
54
|
+
const promptsDir = join(dirname(fileURLToPath(import.meta.url)), "..", "prompts");
|
|
55
|
+
return join(promptsDir, "review-migration.md");
|
|
56
|
+
}
|
|
57
|
+
export function buildReviewPrompt(input) {
|
|
58
|
+
const templatePath = input.templatePath ?? defaultReviewTemplatePath();
|
|
59
|
+
let content = readFileSync(templatePath, "utf-8");
|
|
60
|
+
content = content.replaceAll("{{sourcePath}}", input.sourcePath);
|
|
61
|
+
content = content.replaceAll("{{gsdPath}}", input.gsdPath);
|
|
62
|
+
content = content.replaceAll("{{previewStats}}", formatMigrationPreviewStats(input.preview));
|
|
63
|
+
return content.trim();
|
|
64
|
+
}
|
|
@@ -117,6 +117,10 @@ export function scanMarkdownHierarchy(basePath) {
|
|
|
117
117
|
scan.counts.slices += roadmap.slices.length;
|
|
118
118
|
for (const slice of roadmap.slices) {
|
|
119
119
|
scan.slices.add(`${milestoneId}/${slice.id}`);
|
|
120
|
+
// Sketch slices carry only a stub PLAN until refined; match migrateHierarchyToDb
|
|
121
|
+
// and do not count placeholder tasks from the <tasks> block (#1286).
|
|
122
|
+
if (slice.isSketch)
|
|
123
|
+
continue;
|
|
120
124
|
const planPath = resolveSliceFile(basePath, milestoneId, slice.id, "PLAN");
|
|
121
125
|
if (!planPath || !existsSync(planPath))
|
|
122
126
|
continue;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { deriveState } from "./state.js";
|
|
8
8
|
import { findMilestoneIds } from "./guided-flow.js";
|
|
9
|
-
import { isDbAvailable, getMilestoneSlices,
|
|
9
|
+
import { isDbAvailable, getMilestoneSlices, getTasksBySliceIds } from "./gsd-db.js";
|
|
10
10
|
import { openExistingWorkflowDatabase } from "./db-workspace.js";
|
|
11
11
|
// ─── File Collection ─────────────────────────────────────────────────────────
|
|
12
12
|
/**
|
|
@@ -16,10 +16,11 @@ import { openExistingWorkflowDatabase } from "./db-workspace.js";
|
|
|
16
16
|
async function collectTouchedFiles(basePath, milestoneId) {
|
|
17
17
|
const files = new Set();
|
|
18
18
|
if (isDbAvailable()) {
|
|
19
|
-
// DB path: query slices and their tasks for file lists
|
|
19
|
+
// DB path: query slices and their tasks for file lists (one batched task
|
|
20
|
+
// query instead of one per slice; file order is irrelevant here — Set dedup)
|
|
20
21
|
const slices = getMilestoneSlices(milestoneId);
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const tasksBySlice = getTasksBySliceIds(slices.map((slice) => ({ milestoneId, sliceId: slice.id })));
|
|
23
|
+
for (const tasks of tasksBySlice.values()) {
|
|
23
24
|
for (const task of tasks) {
|
|
24
25
|
if (Array.isArray(task.files)) {
|
|
25
26
|
for (const f of task.files) {
|
|
@@ -75,15 +75,18 @@ function discoverWorkers(basePath) {
|
|
|
75
75
|
}
|
|
76
76
|
return [...mids].sort();
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
// Slice progress + recent completions share one DB connection per worker per
|
|
79
|
+
// tick. Opening the isolated worker DB twice per refresh (once for each) was
|
|
80
|
+
// pure churn on the 5s interval.
|
|
81
|
+
function queryWorkerProgress(basePath, mid, workRoot = worktreePathFor(basePath, mid)) {
|
|
79
82
|
const dbPath = resolveGsdPathContract(workRoot, basePath).projectDb;
|
|
80
83
|
if (!existsSync(dbPath))
|
|
81
|
-
return [];
|
|
84
|
+
return { slices: [], completions: [] };
|
|
82
85
|
const db = openWorkflowDatabaseIsolated(dbPath);
|
|
83
86
|
if (!db)
|
|
84
|
-
return [];
|
|
87
|
+
return { slices: [], completions: [] };
|
|
85
88
|
try {
|
|
86
|
-
const
|
|
89
|
+
const sliceRows = db.prepare(`SELECT
|
|
87
90
|
s.id AS id,
|
|
88
91
|
s.status AS status,
|
|
89
92
|
COUNT(t.id) AS total,
|
|
@@ -93,15 +96,29 @@ function querySliceProgress(basePath, mid, workRoot = worktreePathFor(basePath,
|
|
|
93
96
|
WHERE s.milestone_id=:mid
|
|
94
97
|
GROUP BY s.id
|
|
95
98
|
ORDER BY s.id`).all({ ":mid": mid });
|
|
96
|
-
|
|
99
|
+
const slices = sliceRows.map((row) => ({
|
|
97
100
|
id: String(row["id"] ?? ""),
|
|
98
101
|
status: String(row["status"] ?? ""),
|
|
99
102
|
total: Number(row["total"] ?? 0),
|
|
100
103
|
done: Number(row["done"] ?? 0),
|
|
101
104
|
}));
|
|
105
|
+
const completionRows = db.prepare(`SELECT id, slice_id, one_liner
|
|
106
|
+
FROM tasks
|
|
107
|
+
WHERE milestone_id=:mid
|
|
108
|
+
AND status='complete'
|
|
109
|
+
AND completed_at IS NOT NULL
|
|
110
|
+
ORDER BY completed_at DESC
|
|
111
|
+
LIMIT 5`).all({ ":mid": mid });
|
|
112
|
+
const completions = completionRows.map((row) => {
|
|
113
|
+
const taskId = String(row["id"] ?? "");
|
|
114
|
+
const sliceId = String(row["slice_id"] ?? "");
|
|
115
|
+
const oneLiner = String(row["one_liner"] ?? "");
|
|
116
|
+
return `✓ ${mid}/${sliceId}/${taskId}${oneLiner ? ": " + oneLiner : ""}`;
|
|
117
|
+
});
|
|
118
|
+
return { slices, completions };
|
|
102
119
|
}
|
|
103
120
|
catch {
|
|
104
|
-
return [];
|
|
121
|
+
return { slices: [], completions: [] };
|
|
105
122
|
}
|
|
106
123
|
finally {
|
|
107
124
|
try {
|
|
@@ -200,39 +217,6 @@ function extractCostFromNdjson(basePath, mid) {
|
|
|
200
217
|
return ndjsonCostCache.get(stdoutPath)?.total ?? 0;
|
|
201
218
|
}
|
|
202
219
|
}
|
|
203
|
-
function queryRecentCompletions(basePath, mid) {
|
|
204
|
-
const workRoot = worktreePathFor(basePath, mid);
|
|
205
|
-
const dbPath = resolveGsdPathContract(workRoot, basePath).projectDb;
|
|
206
|
-
if (!existsSync(dbPath))
|
|
207
|
-
return [];
|
|
208
|
-
const db = openWorkflowDatabaseIsolated(dbPath);
|
|
209
|
-
if (!db)
|
|
210
|
-
return [];
|
|
211
|
-
try {
|
|
212
|
-
const rows = db.prepare(`SELECT id, slice_id, one_liner
|
|
213
|
-
FROM tasks
|
|
214
|
-
WHERE milestone_id=:mid
|
|
215
|
-
AND status='complete'
|
|
216
|
-
AND completed_at IS NOT NULL
|
|
217
|
-
ORDER BY completed_at DESC
|
|
218
|
-
LIMIT 5`).all({ ":mid": mid });
|
|
219
|
-
return rows.map((row) => {
|
|
220
|
-
const taskId = String(row["id"] ?? "");
|
|
221
|
-
const sliceId = String(row["slice_id"] ?? "");
|
|
222
|
-
const oneLiner = String(row["one_liner"] ?? "");
|
|
223
|
-
return `✓ ${mid}/${sliceId}/${taskId}${oneLiner ? ": " + oneLiner : ""}`;
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
return [];
|
|
228
|
-
}
|
|
229
|
-
finally {
|
|
230
|
-
try {
|
|
231
|
-
db.close();
|
|
232
|
-
}
|
|
233
|
-
catch { /* ignore */ }
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
220
|
function collectWorkerData(basePath) {
|
|
237
221
|
const mids = discoverWorkers(basePath);
|
|
238
222
|
const parallelDir = join(basePath, ".gsd", "parallel");
|
|
@@ -243,7 +227,7 @@ function collectWorkerData(basePath) {
|
|
|
243
227
|
const workRoot = worktreePathFor(basePath, mid);
|
|
244
228
|
const status = readJsonSafe(join(parallelDir, `${mid}.status.json`));
|
|
245
229
|
const lock = readJsonSafe(join(workRoot, ".gsd", "auto.lock"));
|
|
246
|
-
const slices =
|
|
230
|
+
const { slices, completions } = queryWorkerProgress(basePath, mid, workRoot);
|
|
247
231
|
const pid = lock?.pid || status?.pid || 0;
|
|
248
232
|
const alive = pid ? isPidAlive(pid) : false;
|
|
249
233
|
// Heartbeat: prefer status.json if PID matches, else use file mtime
|
|
@@ -303,6 +287,7 @@ function collectWorkerData(basePath) {
|
|
|
303
287
|
totalSlices: slices.length,
|
|
304
288
|
doneSlices,
|
|
305
289
|
slices,
|
|
290
|
+
completions,
|
|
306
291
|
errors,
|
|
307
292
|
});
|
|
308
293
|
}
|
|
@@ -355,10 +340,10 @@ export class ParallelMonitorOverlay {
|
|
|
355
340
|
if (this.disposed)
|
|
356
341
|
return;
|
|
357
342
|
this.workers = collectWorkerData(this.basePath);
|
|
358
|
-
// Collect completion events
|
|
343
|
+
// Collect completion events (already read during collectWorkerData's single
|
|
344
|
+
// DB open per worker — no second connection here).
|
|
359
345
|
for (const wk of this.workers) {
|
|
360
|
-
const
|
|
361
|
-
for (const evt of completions) {
|
|
346
|
+
for (const evt of wk.completions) {
|
|
362
347
|
if (!this.events.includes(evt))
|
|
363
348
|
this.events.push(evt);
|
|
364
349
|
}
|
|
@@ -585,19 +585,22 @@ function legacyMilestonesHasSubdirs(basePath) {
|
|
|
585
585
|
* See the matching TODO in markdown-renderer.ts detectStaleRenders, which
|
|
586
586
|
* disabled stale-render detection for the same reason.
|
|
587
587
|
*/
|
|
588
|
+
const LEGACY_MILESTONE_RUNTIME_DIRS = new Set(["anchors"]);
|
|
588
589
|
export function dirIsContentBearingLegacyMilestone(dir) {
|
|
589
590
|
try {
|
|
590
591
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
591
592
|
// 1. Any non-META regular file → real legacy content.
|
|
592
593
|
if (entries.some(e => e.isFile() && !e.name.endsWith("-META.json")))
|
|
593
594
|
return true;
|
|
594
|
-
// 2. A non-empty subdirectory → real legacy content (e.g. slices/ with slice dirs).
|
|
595
|
+
// 2. A non-empty non-runtime subdirectory → real legacy content (e.g. slices/ with slice dirs).
|
|
595
596
|
// An *empty* subdir is treated as scaffolding (e.g. git-service.ts may create
|
|
596
597
|
// an empty slices/ alongside the integration META file) and must NOT flip the
|
|
597
598
|
// layout — that is the Bugbot finding this guard addresses.
|
|
598
599
|
return entries.some(e => {
|
|
599
600
|
if (!e.isDirectory())
|
|
600
601
|
return false;
|
|
602
|
+
if (LEGACY_MILESTONE_RUNTIME_DIRS.has(e.name))
|
|
603
|
+
return false;
|
|
601
604
|
try {
|
|
602
605
|
return readdirSync(join(dir, e.name)).length > 0;
|
|
603
606
|
}
|
|
@@ -7,11 +7,14 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { gsdRoot } from "./paths.js";
|
|
9
9
|
function anchorsDir(basePath, milestoneId) {
|
|
10
|
-
return join(gsdRoot(basePath), "
|
|
10
|
+
return join(gsdRoot(basePath), "runtime", "anchors", milestoneId);
|
|
11
11
|
}
|
|
12
12
|
function anchorPath(basePath, milestoneId, phase) {
|
|
13
13
|
return join(anchorsDir(basePath, milestoneId), `${phase}.json`);
|
|
14
14
|
}
|
|
15
|
+
function legacyAnchorPath(basePath, milestoneId, phase) {
|
|
16
|
+
return join(gsdRoot(basePath), "milestones", milestoneId, "anchors", `${phase}.json`);
|
|
17
|
+
}
|
|
15
18
|
export function writePhaseAnchor(basePath, milestoneId, anchor) {
|
|
16
19
|
const dir = anchorsDir(basePath, milestoneId);
|
|
17
20
|
if (!existsSync(dir)) {
|
|
@@ -20,7 +23,9 @@ export function writePhaseAnchor(basePath, milestoneId, anchor) {
|
|
|
20
23
|
writeFileSync(anchorPath(basePath, milestoneId, anchor.phase), JSON.stringify(anchor, null, 2), "utf-8");
|
|
21
24
|
}
|
|
22
25
|
export function readPhaseAnchor(basePath, milestoneId, phase) {
|
|
23
|
-
const path = anchorPath(basePath, milestoneId, phase)
|
|
26
|
+
const path = existsSync(anchorPath(basePath, milestoneId, phase))
|
|
27
|
+
? anchorPath(basePath, milestoneId, phase)
|
|
28
|
+
: legacyAnchorPath(basePath, milestoneId, phase);
|
|
24
29
|
if (!existsSync(path))
|
|
25
30
|
return null;
|
|
26
31
|
try {
|
|
@@ -242,11 +242,11 @@ export function checkImportResolution(taskRow, _priorTasks, basePath) {
|
|
|
242
242
|
}
|
|
243
243
|
const imports = extractRelativeImports(source);
|
|
244
244
|
for (const { importPath, lineNum } of imports) {
|
|
245
|
-
// Framework-generated
|
|
246
|
-
// checks
|
|
247
|
-
// block task completion on these imports.
|
|
245
|
+
// Framework/codegen-generated modules may not exist on disk during
|
|
246
|
+
// post-exec checks. Don't block task completion on these imports.
|
|
248
247
|
if (/^\.{1,2}\/\+types\//.test(importPath) ||
|
|
249
|
-
/^(?:\.{1,2}\/)+(?:[^/]+\/)*\$types(?:$|\/)/.test(importPath)
|
|
248
|
+
/^(?:\.{1,2}\/)+(?:[^/]+\/)*\$types(?:$|\/)/.test(importPath) ||
|
|
249
|
+
/^(?:\.{1,2}\/)+(?:[^/]+\/)*_generated(?:$|\/)/.test(importPath)) {
|
|
250
250
|
continue;
|
|
251
251
|
}
|
|
252
252
|
const resolution = resolveImportPath(importPath, file, basePath);
|
|
@@ -66,12 +66,12 @@ Then:
|
|
|
66
66
|
**Web apps:** when inlined Web App UAT guidance is present, follow it for Playwright scaffolding and browser-capable verification commands.
|
|
67
67
|
4. For non-trivial slices, plan observability / proof level / integration closure, threat surface, and requirement impact. Omit entirely for simple slices.
|
|
68
68
|
5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`). `expectedOutput` is path-only: list only files the task creates or overwrites, and use `[]` for pure verification tasks. Never list GSD planning artifacts — anything under `.gsd/`, `.planning/`, or `.audits/`, or artifact names like `M001-CONTEXT.md` / `S01-PLAN.md` — in `inputs`, `files`, or `expectedOutput`: their content is preloaded as context, and they are written by workflow tools, not by tasks.
|
|
69
|
-
6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}`
|
|
69
|
+
6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` with embedded task planning automatically. Do NOT rely on direct `PLAN.md` writes.
|
|
70
70
|
7. **Self-audit the plan.** If every task were completed exactly as written, the slice goal/demo should be true. Every must-have maps to a task. Inputs and Expected Output are backtick-wrapped file paths.
|
|
71
71
|
8. If refinement produced structural decisions that diverge from the sketch, call `gsd_decision_save` for each; the tool persists the decision and regenerates `.gsd/DECISIONS.md`.
|
|
72
72
|
9. {{commitInstruction}}
|
|
73
73
|
|
|
74
|
-
The slice
|
|
74
|
+
The slice plan path already exists. Do NOT mkdir.
|
|
75
75
|
|
|
76
76
|
**Autonomous execution:** Do not call `ask_user_questions` or `secure_env_collect`. Document assumptions in the plan.
|
|
77
77
|
|
|
@@ -173,7 +173,7 @@ export function recordToolCall(toolCallId, toolName, input) {
|
|
|
173
173
|
toolCallId,
|
|
174
174
|
// gsd_exec / gsd_uat_exec carry the script body in `script` (or `code`);
|
|
175
175
|
// bash-style tools use `command`/`cmd`; gsd_exec_search uses `query`.
|
|
176
|
-
command:
|
|
176
|
+
command: formatExecutionEvidenceCommand(toolName, input),
|
|
177
177
|
exitCode: -1,
|
|
178
178
|
outputSnippet: "",
|
|
179
179
|
timestamp: Date.now(),
|
|
@@ -196,6 +196,31 @@ export function recordToolCall(toolCallId, toolName, input) {
|
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
|
+
function pickString(input, ...keys) {
|
|
200
|
+
for (const key of keys) {
|
|
201
|
+
const value = input[key];
|
|
202
|
+
if (typeof value === "string" && value.trim().length > 0)
|
|
203
|
+
return value.trim();
|
|
204
|
+
}
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
207
|
+
function canonicalExecutionToolLabel(toolName) {
|
|
208
|
+
const normalized = toolName.trim().toLowerCase();
|
|
209
|
+
const mcpMatch = normalized.match(/^mcp__.+__(gsd_(?:uat_)?exec(?:_search)?)$/);
|
|
210
|
+
return mcpMatch?.[1] ?? normalized;
|
|
211
|
+
}
|
|
212
|
+
function formatExecutionEvidenceCommand(toolName, input) {
|
|
213
|
+
const body = pickString(input, "command", "script", "cmd", "code", "query");
|
|
214
|
+
const tool = canonicalExecutionToolLabel(toolName);
|
|
215
|
+
const purpose = pickString(input, "purpose");
|
|
216
|
+
const runtime = pickString(input, "runtime").toLowerCase();
|
|
217
|
+
const label = purpose && (tool === "gsd_exec" || tool === "gsd_uat_exec")
|
|
218
|
+
? `${tool}${runtime ? ` ${runtime}` : ""}: ${purpose}`
|
|
219
|
+
: "";
|
|
220
|
+
if (label && body)
|
|
221
|
+
return `${label}\n${body}`;
|
|
222
|
+
return body || label;
|
|
223
|
+
}
|
|
199
224
|
/**
|
|
200
225
|
* Record a tool execution result. Matches the entry by toolCallId (assigned
|
|
201
226
|
* at dispatch time) and fills in exit code + output. Prior versions matched
|
|
@@ -118,16 +118,25 @@ function latestClaimBatch(claimedEvidence) {
|
|
|
118
118
|
*/
|
|
119
119
|
function findMatches(claimedCommand, bashCalls) {
|
|
120
120
|
const normalized = claimedCommand.trim();
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const exact = bashCalls.filter((b) => b.command.trim() === normalized);
|
|
122
|
+
// When an exact run exists, also consider wrapper-equivalent reruns (e.g.
|
|
123
|
+
// `cd ... && <command>`) so a newer pass is not shadowed by a stale exact
|
|
124
|
+
// failure. Do not merge arbitrary containing scripts: their exit code may
|
|
125
|
+
// belong to later work, not to the claimed verification command.
|
|
126
|
+
const scriptWrapped = bashCalls.filter((b) => {
|
|
127
|
+
const command = b.command.trim();
|
|
128
|
+
if (command.length === 0 || command === normalized)
|
|
129
|
+
return false;
|
|
130
|
+
return isWrapperEquivalentCommand(command, normalized);
|
|
131
|
+
});
|
|
123
132
|
if (exact.length > 0)
|
|
124
|
-
return exact;
|
|
133
|
+
return [...exact, ...scriptWrapped];
|
|
125
134
|
// Substring match: claimed is contained in actual or actual in claimed.
|
|
126
135
|
// A claimed verification command typically appears verbatim inside a
|
|
127
136
|
// larger gsd_exec script body (cd prefix, multi-line scripts), so
|
|
128
137
|
// script-containing-claim is the common direction. Blank-command entries
|
|
129
138
|
// must be excluded — `"x".includes("")` is true, so they'd match anything.
|
|
130
|
-
const substring = bashCalls.filter(b => b.command.trim().length > 0 &&
|
|
139
|
+
const substring = bashCalls.filter((b) => b.command.trim().length > 0 &&
|
|
131
140
|
(b.command.includes(normalized) || normalized.includes(b.command)));
|
|
132
141
|
if (substring.length > 0)
|
|
133
142
|
return substring;
|
|
@@ -150,5 +159,21 @@ function findMatches(claimedCommand, bashCalls) {
|
|
|
150
159
|
.map((match) => match.call);
|
|
151
160
|
}
|
|
152
161
|
function latestMatch(matches) {
|
|
153
|
-
return matches.reduce((latest, match) => (match.timestamp
|
|
162
|
+
return matches.reduce((latest, match) => (match.timestamp >= latest.timestamp ? match : latest));
|
|
163
|
+
}
|
|
164
|
+
/** True when `actual` is the same command with only shell wrapper noise. */
|
|
165
|
+
function isWrapperEquivalentCommand(actual, claimed) {
|
|
166
|
+
const claimIndex = actual.lastIndexOf(claimed);
|
|
167
|
+
if (claimIndex < 0)
|
|
168
|
+
return false;
|
|
169
|
+
const prefix = actual.slice(0, claimIndex).trim();
|
|
170
|
+
if (prefix.length > 0 && !/^cd\s+.+\s+&&$/.test(prefix))
|
|
171
|
+
return false;
|
|
172
|
+
const suffix = actual.slice(claimIndex + claimed.length).trim();
|
|
173
|
+
return suffix.length === 0 || isBenignWrapperSuffix(suffix);
|
|
174
|
+
}
|
|
175
|
+
function isBenignWrapperSuffix(suffix) {
|
|
176
|
+
if (/^;\s*echo\s+["']?[A-Z_]*EXIT=\$\?["']?$/.test(suffix))
|
|
177
|
+
return true;
|
|
178
|
+
return /^(?:(?:\d?>>?|&>)\s*\S+|\d?>&\d)(?:\s+(?:(?:\d?>>?|&>)\s*\S+|\d?>&\d))*$/.test(suffix);
|
|
154
179
|
}
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
//
|
|
4
4
|
// gsd-pi's DB is canonical, but .gsd/*.md is the inter-tool contract. When
|
|
5
5
|
// gsd-core edits a projection file, this handler detects the sha drift vs the
|
|
6
|
-
// recorded baseline in .gsd/.compat.json and re-imports
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// recorded baseline in .gsd/.compat.json and re-imports from markdown with
|
|
7
|
+
// status authority scoped to the affected milestone ids. The next
|
|
8
|
+
// renderAllFromDb pass re-projects; the write-time invalidation hook then
|
|
9
|
+
// refreshes the marker entry, closing the loop.
|
|
9
10
|
import { existsSync, readFileSync } from "node:fs";
|
|
10
11
|
import { join } from "node:path";
|
|
11
12
|
import { computeProjectionSha, readCompatMarker, writeCompatMarker, } from "../../compat/compat-marker.js";
|
|
@@ -43,23 +44,36 @@ function detectExternalMarkdownEdit(_state, ctx) {
|
|
|
43
44
|
return records;
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
|
-
* Idempotent repair: re-import hierarchy
|
|
47
|
-
* markdown
|
|
48
|
-
*
|
|
49
|
-
*
|
|
47
|
+
* Idempotent repair: re-import the hierarchy from markdown while allowing
|
|
48
|
+
* markdown status authority only for milestones named by the drifted file's
|
|
49
|
+
* marker entities, then update the marker entry so the next detect pass sees
|
|
50
|
+
* the file as expected. migrateHierarchyToDb is itself idempotent (upsert), so
|
|
51
|
+
* re-running this repair after a successful one is a no-op.
|
|
50
52
|
*/
|
|
51
53
|
async function repairExternalMarkdownEdit(record, ctx) {
|
|
52
54
|
try {
|
|
53
55
|
// Dynamic imports break a module-init cycle: this handler ← registry ←
|
|
54
56
|
// state.ts ← guided-flow.ts ← md-importer.ts ← (this handler's old static
|
|
55
57
|
// import). Deferring to repair time keeps module load cycle-free.
|
|
56
|
-
const { migrateHierarchyToDb } = await import("../../md-importer.js");
|
|
58
|
+
const { migrateHierarchyToDb, milestoneIdsFromEntities } = await import("../../md-importer.js");
|
|
57
59
|
const { invalidateStateCache } = await import("../../state.js");
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
|
|
60
|
+
// #027: migrateHierarchyToDb walks the whole tree (a cheap upsert), so
|
|
61
|
+
// without scoping every projection rides along with markdown *status*
|
|
62
|
+
// authority. That lets an unrelated file that is stale from gsd-pi's own
|
|
63
|
+
// miss silently revert a reopened slice/milestone. Scope status authority to
|
|
64
|
+
// exactly the milestone(s) this drifted file projects.
|
|
65
|
+
//
|
|
66
|
+
// Step 1: the marker's `entities` are DB ids (`M001`, `M001/S01`,
|
|
67
|
+
// `M001/S01/T01`), so the milestone id is always the first `/`-segment —
|
|
68
|
+
// layout-independent (legacy `milestones/<MID>/…` and flat `phases/NN-slug/…`
|
|
69
|
+
// both resolve the same way), no projectionPath parsing needed. An empty set
|
|
70
|
+
// (no resolvable entities) preserves DB status everywhere: fail toward
|
|
71
|
+
// protecting the DB, not toward markdown authority.
|
|
72
|
+
const statusAuthoritativeMilestones = milestoneIdsFromEntities(record.entities);
|
|
73
|
+
if (statusAuthoritativeMilestones.size === 0) {
|
|
74
|
+
logWarning("reconcile", `external-markdown-edit: no milestone scope resolved for ${record.projectionPath}; preserving DB status for all milestones`);
|
|
75
|
+
}
|
|
76
|
+
migrateHierarchyToDb(ctx.basePath, { statusAuthoritativeMilestones });
|
|
63
77
|
invalidateStateCache();
|
|
64
78
|
}
|
|
65
79
|
catch (err) {
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// Parallel to external-markdown-edit.ts. Detects sha drift between the compat
|
|
4
4
|
// marker's planning.projections/passthrough and current .planning/ files.
|
|
5
5
|
//
|
|
6
|
-
// Modeled files (projections): re-imported via parsePlanningDirectory → DB
|
|
6
|
+
// Modeled files (projections): re-imported via parsePlanningDirectory → DB,
|
|
7
|
+
// with markdown status authority scoped to their marker entity milestone ids.
|
|
7
8
|
// Passthrough files (un-modeled docs): sha refreshed, content untouched.
|
|
8
9
|
import { existsSync, readFileSync } from "node:fs";
|
|
9
10
|
import { join } from "node:path";
|
|
@@ -115,12 +116,21 @@ async function repairExternalPlanningEdit(record, ctx) {
|
|
|
115
116
|
const { parsePlanningDirectory } = await import("../../migrate/parser.js");
|
|
116
117
|
const { transformToGSD } = await import("../../migrate/transformer.js");
|
|
117
118
|
const { writeGSDDirectory } = await import("../../migrate/writer.js");
|
|
118
|
-
const { migrateHierarchyToDb } = await import("../../md-importer.js");
|
|
119
|
+
const { migrateHierarchyToDb, milestoneIdsFromEntities } = await import("../../md-importer.js");
|
|
119
120
|
const { invalidateStateCache } = await import("../../state.js");
|
|
120
121
|
const parsed = await parsePlanningDirectory(join(ctx.basePath, ".planning"));
|
|
121
122
|
const gsdProject = transformToGSD(parsed);
|
|
122
123
|
await writeGSDDirectory(gsdProject, ctx.basePath);
|
|
123
|
-
|
|
124
|
+
// #027: scope status authority to the milestone(s) this drifted .planning/
|
|
125
|
+
// file projects (first `/`-segment of its DB entity ids), so a stale
|
|
126
|
+
// checkbox in an unrelated projection can't revert a reopened slice/milestone
|
|
127
|
+
// in the DB. Unseeded files carry no entities → empty set → preserve DB
|
|
128
|
+
// status everywhere (fail toward the DB, log the breadcrumb).
|
|
129
|
+
const statusAuthoritativeMilestones = milestoneIdsFromEntities(record.entities);
|
|
130
|
+
if (statusAuthoritativeMilestones.size === 0) {
|
|
131
|
+
logWarning("reconcile", `external-planning-edit: no milestone scope resolved for ${record.projectionPath}; preserving DB status for all milestones`);
|
|
132
|
+
}
|
|
133
|
+
migrateHierarchyToDb(ctx.basePath, { statusAuthoritativeMilestones });
|
|
124
134
|
invalidateStateCache();
|
|
125
135
|
}
|
|
126
136
|
catch (err) {
|