@opengsd/gsd-pi 1.8.1 → 1.9.0-dev.5c1a3ff2
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 -8
- 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 +18 -49
- 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/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
- 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 +125 -18
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
- 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/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- 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 +26 -4
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
- package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +187 -45
- package/dist/resources/extensions/gsd/guided-flow.js +38 -13
- package/dist/resources/extensions/gsd/markdown-renderer.js +17 -13
- package/dist/resources/extensions/gsd/md-importer.js +107 -20
- 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 +12 -17
- package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
- package/dist/resources/extensions/gsd/model-router.js +11 -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 +55 -11
- package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
- package/dist/resources/extensions/gsd/preferences-types.js +5 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
- package/dist/resources/extensions/gsd/preferences.js +17 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- 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/safety/evidence-collector.js +26 -1
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- 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/stop-notice.js +15 -1
- package/dist/resources/extensions/gsd/sync-lock.js +13 -7
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
- 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/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/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-context-composer.js +28 -5
- 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/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- 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 +8 -8
- 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 +8 -8
- 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 +5 -1
- package/packages/daemon/dist/cloud-config.js.map +1 -1
- package/packages/daemon/dist/cloud-config.test.js +51 -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/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/package.json +7 -7
- 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 +3 -3
- package/packages/mcp-server/README.md +15 -2
- 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 +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/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/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +119 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +107 -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 +25 -1
- package/packages/pi-ai/dist/providers/anthropic.js.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-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.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-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
- 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/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 +18 -49
- 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/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
- 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 +142 -16
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
- 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/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- 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 +26 -4
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
- package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +255 -52
- package/src/resources/extensions/gsd/guided-flow.ts +48 -12
- package/src/resources/extensions/gsd/markdown-renderer.ts +25 -21
- package/src/resources/extensions/gsd/md-importer.ts +114 -16
- 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 +12 -20
- package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
- package/src/resources/extensions/gsd/model-router.ts +12 -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 +62 -11
- package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
- package/src/resources/extensions/gsd/preferences.ts +25 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- 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/safety/evidence-collector.ts +28 -1
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- 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/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/templates/PREFERENCES.md +5 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- 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 +362 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -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/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/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/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/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/milestone-leases.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- 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/parallel-skill-prompt-integration.test.ts +7 -5
- 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 +29 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- 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/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/skip-slice-cascades-tasks.test.ts +21 -0
- 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/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -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/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
- 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/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/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-context-composer.ts +34 -8
- 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/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- 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/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
|
@@ -97,6 +97,42 @@ test("projectRootToWorktree forwards root PROJECT.md into isolated worktrees", (
|
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
+
test("projectRootToWorktree projects flat-phase discuss artifacts before dispatch", () => {
|
|
101
|
+
const { dir, cleanup } = makeProjectRoot();
|
|
102
|
+
try {
|
|
103
|
+
const worktree = join(dir, ".gsd", "worktrees", "M001");
|
|
104
|
+
mkdirSync(join(worktree, ".gsd", "phases", "01-foundation"), { recursive: true });
|
|
105
|
+
|
|
106
|
+
const projectPhaseDir = join(dir, ".gsd", "phases", "01-foundation");
|
|
107
|
+
mkdirSync(projectPhaseDir, { recursive: true });
|
|
108
|
+
writeFileSync(join(projectPhaseDir, "01-CONTEXT.md"), "# M001 Context\n");
|
|
109
|
+
writeFileSync(join(projectPhaseDir, "01-DISCUSSION.md"), "# M001 Discussion\n");
|
|
110
|
+
|
|
111
|
+
const metaDir = join(dir, ".gsd", "milestones", "M001");
|
|
112
|
+
mkdirSync(metaDir, { recursive: true });
|
|
113
|
+
writeFileSync(join(metaDir, "M001-META.json"), '{"branch":"milestone/M001"}');
|
|
114
|
+
|
|
115
|
+
const workspace = createWorkspace(worktree);
|
|
116
|
+
const scope = scopeMilestone(workspace, "M001");
|
|
117
|
+
new WorktreeStateProjection().projectRootToWorktree(scope);
|
|
118
|
+
|
|
119
|
+
assert.ok(
|
|
120
|
+
existsSync(join(worktree, ".gsd", "milestones", "M001", "M001-META.json")),
|
|
121
|
+
"milestone metadata is projected into the worktree",
|
|
122
|
+
);
|
|
123
|
+
assert.ok(
|
|
124
|
+
existsSync(join(worktree, ".gsd", "phases", "01-foundation", "01-CONTEXT.md")),
|
|
125
|
+
"flat-phase CONTEXT.md is projected into the worktree",
|
|
126
|
+
);
|
|
127
|
+
assert.ok(
|
|
128
|
+
existsSync(join(worktree, ".gsd", "phases", "01-foundation", "01-DISCUSSION.md")),
|
|
129
|
+
"flat-phase DISCUSSION.md is projected into the worktree",
|
|
130
|
+
);
|
|
131
|
+
} finally {
|
|
132
|
+
cleanup();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
100
136
|
test("projectRootToWorktree projects prior-milestone slice/task SUMMARY.md, not just top-level files", () => {
|
|
101
137
|
// Regression: a worktree opened for the CURRENT milestone (M002) must also
|
|
102
138
|
// receive the full subtree of OTHER, already-completed milestones (M001) so
|
|
@@ -13,6 +13,7 @@ import { GSD_PHASE_SCOPE_DISPLAY_REASON, GSD_SECTION_CLOSE_GATE_DISPLAY_REASON }
|
|
|
13
13
|
import { ALLOWED_PLANNING_DISPATCH_AGENTS, shouldBlockPlanningUnit } from '../bootstrap/write-gate.ts';
|
|
14
14
|
import { extractSubagentAgentClasses } from '../bootstrap/subagent-input.ts';
|
|
15
15
|
import { isDeterministicPolicyError } from '../auto-tool-tracking.ts';
|
|
16
|
+
import { applyPlanningSubagentPreferences } from '../planning-subagent-policy.ts';
|
|
16
17
|
import type { ToolsPolicy } from '../unit-context-manifest.ts';
|
|
17
18
|
|
|
18
19
|
const BASE = join('/tmp', 'fake-project');
|
|
@@ -335,6 +336,39 @@ test('planning-dispatch: still allows writes inside .gsd/', () => {
|
|
|
335
336
|
assert.strictEqual(r.block, false);
|
|
336
337
|
});
|
|
337
338
|
|
|
339
|
+
test('planning_subagents: upgrades plan-milestone to controlled read-only dispatch', () => {
|
|
340
|
+
const policy = applyPlanningSubagentPreferences('plan-milestone', PLANNING, {
|
|
341
|
+
planning_subagents: {
|
|
342
|
+
'plan-milestone': { allowed: ['security'] },
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
const allowed = shouldBlockPlanningUnit('subagent', '', BASE, 'plan-milestone', policy, ['security']);
|
|
346
|
+
assert.strictEqual(allowed.block, false);
|
|
347
|
+
|
|
348
|
+
const blocked = shouldBlockPlanningUnit('subagent', '', BASE, 'plan-milestone', policy, ['reviewer']);
|
|
349
|
+
assert.strictEqual(blocked.block, true);
|
|
350
|
+
assert.match(blocked.reason!, /planning_subagents/);
|
|
351
|
+
assert.match(blocked.reason!, /permitted agents for this unit: security/);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test('planning_subagents: widens plan-slice manifest allowlist without allowing unsafe agents', () => {
|
|
355
|
+
const policy = applyPlanningSubagentPreferences('plan-slice', {
|
|
356
|
+
mode: 'planning-dispatch',
|
|
357
|
+
allowedSubagents: ['scout', 'planner'],
|
|
358
|
+
}, {
|
|
359
|
+
planning_subagents: {
|
|
360
|
+
'plan-slice': { allowed: ['security'] },
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const added = shouldBlockPlanningUnit('subagent', '', BASE, 'plan-slice', policy, ['security']);
|
|
365
|
+
assert.strictEqual(added.block, false);
|
|
366
|
+
|
|
367
|
+
const unsafe = shouldBlockPlanningUnit('subagent', '', BASE, 'plan-slice', policy, ['worker']);
|
|
368
|
+
assert.strictEqual(unsafe.block, true);
|
|
369
|
+
assert.match(unsafe.reason!, /read-only specialists/);
|
|
370
|
+
});
|
|
371
|
+
|
|
338
372
|
// ─── planning mode: pass-through tools ────────────────────────────────────
|
|
339
373
|
|
|
340
374
|
test('planning-unit: allows read tool', () => {
|
|
@@ -26,6 +26,7 @@ import { tmpdir } from "node:os";
|
|
|
26
26
|
|
|
27
27
|
import { registerHooks } from "../bootstrap/register-hooks.ts";
|
|
28
28
|
import {
|
|
29
|
+
_setWriteGateInterleaveHookForTest,
|
|
29
30
|
childWriteGateAdapter,
|
|
30
31
|
clearDiscussionFlowState,
|
|
31
32
|
getPendingGate,
|
|
@@ -36,6 +37,9 @@ import {
|
|
|
36
37
|
setPendingGate,
|
|
37
38
|
type WriteGateSnapshot,
|
|
38
39
|
} from "../bootstrap/write-gate.ts";
|
|
40
|
+
import { acquireSyncLock, releaseSyncLock } from "../sync-lock.ts";
|
|
41
|
+
|
|
42
|
+
const WRITE_GATE_LOCK_NAME = "write-gate.lock";
|
|
39
43
|
|
|
40
44
|
function makeTempDir(prefix: string): string {
|
|
41
45
|
const dir = join(
|
|
@@ -356,3 +360,51 @@ test("seam: mutateWriteGateState reset path drops stale pendingGateId on a corru
|
|
|
356
360
|
assert.equal(persisted.pendingGateId, null, "stale pending id must not be persisted after a corrupt-snapshot reconcile");
|
|
357
361
|
assert.deepEqual(persisted.verifiedDepthMilestones, ["M099"]);
|
|
358
362
|
});
|
|
363
|
+
|
|
364
|
+
// ── (f) cross-process lock closes the read-merge-write lost-update window ────
|
|
365
|
+
|
|
366
|
+
test("seam: read-merge-write holds the write-gate lock across the whole critical section", (t) => {
|
|
367
|
+
const dir = makeTempDir("lock-held");
|
|
368
|
+
t.after(() => {
|
|
369
|
+
_setWriteGateInterleaveHookForTest(null);
|
|
370
|
+
cleanup(dir);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Fire inside the host's critical section, standing in for the OTHER process
|
|
374
|
+
// attempting to enter its own read-merge-write. The lock must lock it out.
|
|
375
|
+
let peerAcquiredMidSection: boolean | null = null;
|
|
376
|
+
_setWriteGateInterleaveHookForTest((lockRoot) => {
|
|
377
|
+
const res = acquireSyncLock(lockRoot, 0, WRITE_GATE_LOCK_NAME);
|
|
378
|
+
peerAcquiredMidSection = res.acquired;
|
|
379
|
+
if (res.acquired) releaseSyncLock(lockRoot, WRITE_GATE_LOCK_NAME);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
markDepthVerified("M001", dir);
|
|
383
|
+
|
|
384
|
+
assert.equal(
|
|
385
|
+
peerAcquiredMidSection,
|
|
386
|
+
false,
|
|
387
|
+
"a concurrent process must be locked out of the read-merge-write section — this is what prevents the lost-update",
|
|
388
|
+
);
|
|
389
|
+
// The lock is released after the mutation, and the mutation still took effect.
|
|
390
|
+
assert.ok(loadWriteGateSnapshot(dir).verifiedDepthMilestones.includes("M001"));
|
|
391
|
+
assert.equal(acquireSyncLock(dir, 0, WRITE_GATE_LOCK_NAME).acquired, true, "lock released after mutation");
|
|
392
|
+
releaseSyncLock(dir, WRITE_GATE_LOCK_NAME);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
test("seam: gate mutation fails OPEN when a live peer holds the lock (never blocks/refuses)", (t) => {
|
|
396
|
+
const dir = makeTempDir("lock-fail-open");
|
|
397
|
+
t.after(() => cleanup(dir));
|
|
398
|
+
|
|
399
|
+
// A live peer holds the lock (its own PID → never stolen as stale).
|
|
400
|
+
assert.equal(acquireSyncLock(dir, 0, WRITE_GATE_LOCK_NAME).acquired, true);
|
|
401
|
+
try {
|
|
402
|
+
// Host arms a gate while contended: fail-open means it proceeds anyway.
|
|
403
|
+
const armed = setPendingGate(GATE, dir);
|
|
404
|
+
assert.equal(armed, true, "arm must succeed (fail-open) even though the lock is held");
|
|
405
|
+
assert.equal(getPendingGate(dir), GATE);
|
|
406
|
+
assert.equal(readDiskRaw(dir).pendingGateId, GATE, "fail-open still persists the mutation");
|
|
407
|
+
} finally {
|
|
408
|
+
releaseSyncLock(dir, WRITE_GATE_LOCK_NAME);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
@@ -29,10 +29,22 @@ import {
|
|
|
29
29
|
deleteVerificationEvidence,
|
|
30
30
|
saveGateResult,
|
|
31
31
|
getPendingGatesForTurn,
|
|
32
|
+
getUnresolvedBlockingReworkFindingsForTask,
|
|
33
|
+
getBlockingReworkFindingsForTask,
|
|
34
|
+
applyReworkResolutions,
|
|
35
|
+
type ReworkFindingStatus,
|
|
32
36
|
} from "../gsd-db.js";
|
|
33
37
|
import { getWorkflowDatabasePath, ensureWorkflowDbAtPath } from "../db-workspace.js";
|
|
34
38
|
import { getGatesForTurn } from "../gate-registry.js";
|
|
35
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
buildFlatTaskFileName,
|
|
41
|
+
buildTaskFileName,
|
|
42
|
+
gsdProjectionRoot,
|
|
43
|
+
clearPathCache,
|
|
44
|
+
legacyMilestonesDir,
|
|
45
|
+
resolveMilestonePath,
|
|
46
|
+
resolveSlicePath,
|
|
47
|
+
} from "../paths.js";
|
|
36
48
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
37
49
|
import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
|
|
38
50
|
import { saveFile, clearParseCache } from "../files.js";
|
|
@@ -85,13 +97,20 @@ function taskSummaryPath(
|
|
|
85
97
|
// a legacy layout and breaks all subsequent path resolution for the session.
|
|
86
98
|
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
87
99
|
const phaseDir = resolveMilestonePath(basePath, milestoneId);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
101
|
+
const isLegacy = phaseDir
|
|
102
|
+
? phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\")
|
|
103
|
+
: false;
|
|
104
|
+
if (isLegacy && phaseDir) {
|
|
105
|
+
// Legacy layout: the slice has its own slices/SID/ subdir → tasks/ subdir.
|
|
106
|
+
const legacySlicePath = slicePath && slicePath !== phaseDir
|
|
107
|
+
? slicePath
|
|
108
|
+
: join(phaseDir, "slices", sliceId);
|
|
109
|
+
return join(legacySlicePath, "tasks", buildTaskFileName(taskId, "SUMMARY"));
|
|
91
110
|
}
|
|
92
111
|
if (phaseDir) {
|
|
93
112
|
// Flat-phase: task summaries go in the phase dir (no tasks/ subdir)
|
|
94
|
-
return join(phaseDir,
|
|
113
|
+
return join(phaseDir, buildFlatTaskFileName(sliceId, taskId, "SUMMARY"));
|
|
95
114
|
}
|
|
96
115
|
// Fallback: legacy hardcoded path (milestone/slice dir not on disk yet)
|
|
97
116
|
return join(
|
|
@@ -185,6 +204,70 @@ export function normalizeListParam(value: unknown): string[] {
|
|
|
185
204
|
* Build a TaskRow-shaped object from CompleteTaskParams so the unified
|
|
186
205
|
* renderSummaryContent() can be used at completion time (#2720).
|
|
187
206
|
*/
|
|
207
|
+
|
|
208
|
+
function normalizeReworkResolution(params: CompleteTaskParams): Array<{
|
|
209
|
+
milestoneId: string;
|
|
210
|
+
sliceId: string;
|
|
211
|
+
taskId: string;
|
|
212
|
+
findingId: string;
|
|
213
|
+
status: "resolved" | "deferred-with-override";
|
|
214
|
+
evidence: string;
|
|
215
|
+
decisionRef?: string;
|
|
216
|
+
}> {
|
|
217
|
+
return (params.reworkResolution ?? []).map((resolution) => ({
|
|
218
|
+
milestoneId: params.milestoneId,
|
|
219
|
+
sliceId: params.sliceId,
|
|
220
|
+
taskId: params.taskId,
|
|
221
|
+
findingId: resolution.findingId,
|
|
222
|
+
status: resolution.status,
|
|
223
|
+
evidence: resolution.evidence,
|
|
224
|
+
decisionRef: resolution.decisionRef,
|
|
225
|
+
}));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function unresolvedReworkError(missingFindingIds: string[]): string {
|
|
229
|
+
const plural = missingFindingIds.length === 1 ? "finding" : "findings";
|
|
230
|
+
return `unresolved blocking rework ${plural}: ${missingFindingIds.join(", ")} — provide reworkResolution entries with status resolved and evidence, or status deferred-with-override with evidence and decisionRef, before completing the task`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function satisfiesBlockingReworkFinding(resolution: ReturnType<typeof normalizeReworkResolution>[number]): boolean {
|
|
234
|
+
if (resolution.evidence.trim().length === 0) return false;
|
|
235
|
+
if (resolution.status === "resolved") return true;
|
|
236
|
+
return (resolution.decisionRef ?? "").trim().length > 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Snapshot of a rework finding's status/evidence as it existed *before* this
|
|
241
|
+
* completion applied its reworkResolution. Captured inside the completion
|
|
242
|
+
* transaction so the compensating rollback paths can restore the exact prior
|
|
243
|
+
* state.
|
|
244
|
+
*/
|
|
245
|
+
type ReworkFindingSnapshot = {
|
|
246
|
+
milestoneId: string;
|
|
247
|
+
sliceId: string;
|
|
248
|
+
taskId: string;
|
|
249
|
+
findingId: string;
|
|
250
|
+
status: ReworkFindingStatus;
|
|
251
|
+
evidence: string;
|
|
252
|
+
decisionRef?: string;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Restore rework findings to their pre-completion state.
|
|
257
|
+
*
|
|
258
|
+
* The completion transaction flips blocking findings to resolved/
|
|
259
|
+
* deferred-with-override via applyReworkResolutions. When a later projection
|
|
260
|
+
* or escalation write fails and we compensate by reverting the task to
|
|
261
|
+
* `pending`, we must also revert those findings. Otherwise a retry sees no
|
|
262
|
+
* unresolved blocking findings (getUnresolvedBlockingReworkFindingsForTask
|
|
263
|
+
* only returns `pending` rows) and completes the task with the blocking gate
|
|
264
|
+
* silently skipped.
|
|
265
|
+
*/
|
|
266
|
+
function revertAppliedReworkResolutions(snapshot: ReworkFindingSnapshot[]): void {
|
|
267
|
+
if (snapshot.length === 0) return;
|
|
268
|
+
applyReworkResolutions(snapshot);
|
|
269
|
+
}
|
|
270
|
+
|
|
188
271
|
function paramsToTaskRow(params: CompleteTaskParams, completedAt: string): TaskRow {
|
|
189
272
|
return {
|
|
190
273
|
milestone_id: params.milestoneId,
|
|
@@ -271,6 +354,7 @@ export async function handleCompleteTask(
|
|
|
271
354
|
let guardError: string | null = null;
|
|
272
355
|
let summaryMd = "";
|
|
273
356
|
let repairTaskSummaryRow: TaskRow | null = null;
|
|
357
|
+
let appliedReworkSnapshot: ReworkFindingSnapshot[] = [];
|
|
274
358
|
const rollbackDbPath = getWorkflowDatabasePath();
|
|
275
359
|
|
|
276
360
|
// ── ADR-011 Phase 2: validate escalation payload BEFORE any side effects ─
|
|
@@ -282,6 +366,8 @@ export async function handleCompleteTask(
|
|
|
282
366
|
// no escalation recorded, and the loop would silently advance past it.
|
|
283
367
|
// The filesystem write happens later (after side effects) because that's
|
|
284
368
|
// the cheapest ordering and validation is where 99% of failures live.
|
|
369
|
+
const reworkResolutions = normalizeReworkResolution(params);
|
|
370
|
+
|
|
285
371
|
let validatedEscalationArtifact: ReturnType<typeof buildEscalationArtifact> | null = null;
|
|
286
372
|
let escalationWriteEnabled = false;
|
|
287
373
|
if (params.escalation) {
|
|
@@ -323,6 +409,20 @@ export async function handleCompleteTask(
|
|
|
323
409
|
}
|
|
324
410
|
|
|
325
411
|
const existingTask = getTask(params.milestoneId, params.sliceId, params.taskId);
|
|
412
|
+
const unresolvedRework = getUnresolvedBlockingReworkFindingsForTask(params.milestoneId, params.sliceId, params.taskId);
|
|
413
|
+
const resolvedFindingIds = new Set(
|
|
414
|
+
reworkResolutions
|
|
415
|
+
.filter(satisfiesBlockingReworkFinding)
|
|
416
|
+
.map((resolution) => resolution.findingId),
|
|
417
|
+
);
|
|
418
|
+
const missingFindingIds = unresolvedRework
|
|
419
|
+
.filter((finding) => !resolvedFindingIds.has(finding.finding_id))
|
|
420
|
+
.map((finding) => finding.finding_id);
|
|
421
|
+
if (missingFindingIds.length > 0) {
|
|
422
|
+
guardError = unresolvedReworkError(missingFindingIds);
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
326
426
|
if (existingTask && isClosedStatus(existingTask.status)) {
|
|
327
427
|
// Stale-turn path: a timed-out turn that was superseded by recovery
|
|
328
428
|
// can still reach this code when its LLM call eventually returns and
|
|
@@ -378,6 +478,38 @@ export async function handleCompleteTask(
|
|
|
378
478
|
fullSummaryMd: summaryMd,
|
|
379
479
|
});
|
|
380
480
|
|
|
481
|
+
// Only persist resolutions that actually satisfy the evidence
|
|
482
|
+
// requirement. The guard above admits a finding as long as ONE satisfying
|
|
483
|
+
// entry exists, but applyReworkResolutions writes by findingId and lets the
|
|
484
|
+
// last entry win. Persisting every entry would let a later non-satisfying
|
|
485
|
+
// duplicate (empty evidence, or deferred-with-override without decisionRef)
|
|
486
|
+
// overwrite a valid resolution and leave the finding non-pending without
|
|
487
|
+
// acceptable evidence. Filtering with the same predicate the guard uses
|
|
488
|
+
// keeps the applied set and the gate consistent.
|
|
489
|
+
const resolutionsToApply = reworkResolutions.filter(satisfiesBlockingReworkFinding);
|
|
490
|
+
if (resolutionsToApply.length > 0) {
|
|
491
|
+
// Snapshot the pre-resolution state of the findings we're about to
|
|
492
|
+
// change so a compensating rollback can restore them exactly (see
|
|
493
|
+
// revertAppliedReworkResolutions).
|
|
494
|
+
const resolvedFindingIdsForSnapshot = new Set(resolutionsToApply.map((r) => r.findingId));
|
|
495
|
+
appliedReworkSnapshot = getBlockingReworkFindingsForTask(
|
|
496
|
+
params.milestoneId,
|
|
497
|
+
params.sliceId,
|
|
498
|
+
params.taskId,
|
|
499
|
+
)
|
|
500
|
+
.filter((finding) => resolvedFindingIdsForSnapshot.has(finding.finding_id))
|
|
501
|
+
.map((finding) => ({
|
|
502
|
+
milestoneId: params.milestoneId,
|
|
503
|
+
sliceId: params.sliceId,
|
|
504
|
+
taskId: params.taskId,
|
|
505
|
+
findingId: finding.finding_id,
|
|
506
|
+
status: finding.status,
|
|
507
|
+
evidence: finding.evidence,
|
|
508
|
+
decisionRef: finding.decision_ref,
|
|
509
|
+
}));
|
|
510
|
+
applyReworkResolutions(resolutionsToApply);
|
|
511
|
+
}
|
|
512
|
+
|
|
381
513
|
for (const evidence of (params.verificationEvidence ?? [])) {
|
|
382
514
|
insertVerificationEvidence({
|
|
383
515
|
taskId: params.taskId,
|
|
@@ -459,6 +591,7 @@ export async function handleCompleteTask(
|
|
|
459
591
|
ensureWorkflowDbAtPath(rollbackDbPath);
|
|
460
592
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
461
593
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, "pending");
|
|
594
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
462
595
|
invalidateStateCache();
|
|
463
596
|
rollbackSucceeded = true;
|
|
464
597
|
} catch (rollbackErr) {
|
|
@@ -559,6 +692,7 @@ export async function handleCompleteTask(
|
|
|
559
692
|
try {
|
|
560
693
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
561
694
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
695
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
562
696
|
invalidateStateCache();
|
|
563
697
|
logWarning(
|
|
564
698
|
"tool",
|
|
@@ -580,6 +714,7 @@ export async function handleCompleteTask(
|
|
|
580
714
|
try {
|
|
581
715
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
582
716
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
717
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
583
718
|
invalidateStateCache();
|
|
584
719
|
logWarning(
|
|
585
720
|
"tool",
|
|
@@ -5,7 +5,7 @@ import { getGateIdsForTurn } from "../gate-registry.js";
|
|
|
5
5
|
import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning, insertGateRow, setSliceSketchFlag } from "../gsd-db.js";
|
|
6
6
|
import { invalidateStateCache } from "../state.js";
|
|
7
7
|
import { renderTaskPlanFromDb, renderPlanFromDb } from "../markdown-renderer.js";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveMilestonePath, resolveSlicePath } from "../paths.js";
|
|
9
9
|
import { flushWorkflowProjections } from "../projection-flush.js";
|
|
10
10
|
import { writeManifest } from "../workflow-manifest.js";
|
|
11
11
|
import { appendEvent } from "../workflow-events.js";
|
|
@@ -255,21 +255,19 @@ export async function handlePlanTask(
|
|
|
255
255
|
}
|
|
256
256
|
|
|
257
257
|
try {
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
// new/updated task appears in the plan file that gsd-core reads.
|
|
263
|
-
// Guard: resolveTasksDir is null in flat-phase (no tasks/ subdir exists).
|
|
258
|
+
const milestonePath = resolveMilestonePath(basePath, params.milestoneId);
|
|
259
|
+
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
260
|
+
const isLegacySliceLayout = Boolean(milestonePath && slicePath && slicePath !== milestonePath);
|
|
261
|
+
let renderedPath: string;
|
|
264
262
|
let slicePlanSynced = false;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
263
|
+
|
|
264
|
+
if (isLegacySliceLayout) {
|
|
265
|
+
const renderResult = await renderTaskPlanFromDb(basePath, params.milestoneId, params.sliceId, params.taskId);
|
|
266
|
+
renderedPath = renderResult.taskPlanPath;
|
|
267
|
+
} else {
|
|
268
|
+
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
269
|
+
renderedPath = renderResult.planPath;
|
|
270
|
+
slicePlanSynced = true;
|
|
273
271
|
}
|
|
274
272
|
|
|
275
273
|
if (slicePlanSynced) {
|
|
@@ -299,7 +297,7 @@ export async function handlePlanTask(
|
|
|
299
297
|
milestoneId: params.milestoneId,
|
|
300
298
|
sliceId: params.sliceId,
|
|
301
299
|
taskId: params.taskId,
|
|
302
|
-
taskPlanPath:
|
|
300
|
+
taskPlanPath: renderedPath,
|
|
303
301
|
};
|
|
304
302
|
} catch (err) {
|
|
305
303
|
return { error: `render failed: ${(err as Error).message}` };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, unlinkSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import {
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { gsdProjectionRoot, gsdRoot, resolveMilestoneFile, resolveMilestonePath, targetMilestoneFile } from "../paths.js";
|
|
4
4
|
import { clearParseCache } from "../files.js";
|
|
5
5
|
import { isClosedStatus } from "../status-guards.js";
|
|
6
6
|
import { isNonEmptyString } from "../validation.js";
|
|
@@ -53,6 +53,14 @@ export interface ReassessRoadmapResult {
|
|
|
53
53
|
roadmapPath: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function assessmentDbPathForRenderedFile(basePath: string, absPath: string): string {
|
|
57
|
+
const projectionRoot = gsdProjectionRoot(basePath);
|
|
58
|
+
const projectionRel = relative(projectionRoot, absPath);
|
|
59
|
+
const root = projectionRel && !projectionRel.startsWith("..") && !projectionRel.startsWith("/")
|
|
60
|
+
? projectionRoot
|
|
61
|
+
: gsdRoot(basePath);
|
|
62
|
+
return `.gsd/${relative(root, absPath).replace(/\\/g, "/")}`;
|
|
63
|
+
}
|
|
56
64
|
|
|
57
65
|
function validateParams(params: ReassessRoadmapParams): ReassessRoadmapParams {
|
|
58
66
|
if (!isNonEmptyString(params?.milestoneId)) throw new Error("milestoneId is required");
|
|
@@ -119,11 +127,6 @@ export async function handleReassessRoadmap(
|
|
|
119
127
|
return { error: `validation failed: ${(err as Error).message}` };
|
|
120
128
|
}
|
|
121
129
|
|
|
122
|
-
// ── Compute assessment artifact path ──────────────────────────────
|
|
123
|
-
// Assessment lives in the completed slice's directory.
|
|
124
|
-
// Use relSliceFile so the path is layout-aware (flat-phase or legacy).
|
|
125
|
-
const assessmentRelPath = relSliceFile(basePath, params.milestoneId, params.completedSliceId, "ASSESSMENT");
|
|
126
|
-
|
|
127
130
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
128
131
|
// Guards must be inside the transaction so the state they check cannot
|
|
129
132
|
// change between the read and the write (#2723).
|
|
@@ -207,16 +210,6 @@ export async function handleReassessRoadmap(
|
|
|
207
210
|
}
|
|
208
211
|
}
|
|
209
212
|
|
|
210
|
-
// Record assessment
|
|
211
|
-
insertAssessment({
|
|
212
|
-
path: assessmentRelPath,
|
|
213
|
-
milestoneId: params.milestoneId,
|
|
214
|
-
sliceId: params.completedSliceId,
|
|
215
|
-
status: params.verdict,
|
|
216
|
-
scope: "roadmap",
|
|
217
|
-
fullContent: params.assessment,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
213
|
// Apply slice modifications
|
|
221
214
|
for (const mod of params.sliceChanges.modified) {
|
|
222
215
|
updateSliceFields(params.milestoneId, mod.sliceId, {
|
|
@@ -282,6 +275,14 @@ export async function handleReassessRoadmap(
|
|
|
282
275
|
assessment: params.assessment,
|
|
283
276
|
completedSliceId: params.completedSliceId,
|
|
284
277
|
});
|
|
278
|
+
insertAssessment({
|
|
279
|
+
path: assessmentDbPathForRenderedFile(basePath, assessmentResult.assessmentPath),
|
|
280
|
+
milestoneId: params.milestoneId,
|
|
281
|
+
sliceId: params.completedSliceId,
|
|
282
|
+
status: params.verdict,
|
|
283
|
+
scope: "roadmap",
|
|
284
|
+
fullContent: params.assessment,
|
|
285
|
+
});
|
|
285
286
|
|
|
286
287
|
// ── Remove stale VALIDATION file from disk (#2957) ────────────
|
|
287
288
|
const hasStructuralChanges =
|
|
@@ -22,7 +22,15 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
22
22
|
import { debugLog } from "../debug-logger.js";
|
|
23
23
|
import { existsSync, unlinkSync } from "node:fs";
|
|
24
24
|
import { join } from "node:path";
|
|
25
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
buildFlatTaskFileName,
|
|
27
|
+
buildTaskFileName,
|
|
28
|
+
legacyMilestonesDir,
|
|
29
|
+
resolveMilestonePath,
|
|
30
|
+
resolveSlicePath,
|
|
31
|
+
resolveTasksDir,
|
|
32
|
+
clearPathCache,
|
|
33
|
+
} from "../paths.js";
|
|
26
34
|
|
|
27
35
|
export interface ReopenMilestoneParams {
|
|
28
36
|
milestoneId: string;
|
|
@@ -69,6 +77,10 @@ export async function handleReopenMilestone(
|
|
|
69
77
|
// auto-corrects entities back to "complete", making reopen a no-op (#3161).
|
|
70
78
|
try {
|
|
71
79
|
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
80
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
81
|
+
const isLegacy = !!milestoneDir && (
|
|
82
|
+
milestoneDir.startsWith(legacyBase + "/") || milestoneDir.startsWith(legacyBase + "\\")
|
|
83
|
+
);
|
|
72
84
|
if (milestoneDir) {
|
|
73
85
|
const milestoneSummary = join(milestoneDir, `${params.milestoneId}-SUMMARY.md`);
|
|
74
86
|
if (existsSync(milestoneSummary)) unlinkSync(milestoneSummary);
|
|
@@ -85,10 +97,17 @@ export async function handleReopenMilestone(
|
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
const tasksDir = resolveTasksDir(basePath, params.milestoneId, slice.id);
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
const tasks = getSliceTasks(params.milestoneId, slice.id);
|
|
101
|
+
for (const task of tasks) {
|
|
102
|
+
const taskSummaries = isLegacy
|
|
103
|
+
? (tasksDir ? [join(tasksDir, buildTaskFileName(task.id, "SUMMARY"))] : [])
|
|
104
|
+
: milestoneDir
|
|
105
|
+
? [
|
|
106
|
+
join(milestoneDir, buildFlatTaskFileName(slice.id, task.id, "SUMMARY")),
|
|
107
|
+
join(milestoneDir, buildTaskFileName(task.id, "SUMMARY")),
|
|
108
|
+
]
|
|
109
|
+
: [];
|
|
110
|
+
for (const taskSummary of taskSummaries) {
|
|
92
111
|
if (existsSync(taskSummary)) unlinkSync(taskSummary);
|
|
93
112
|
}
|
|
94
113
|
}
|
|
@@ -27,7 +27,15 @@ import { appendEvent } from "../workflow-events.js";
|
|
|
27
27
|
import { logWarning } from "../workflow-logger.js";
|
|
28
28
|
import { existsSync, unlinkSync } from "node:fs";
|
|
29
29
|
import { join } from "node:path";
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
buildFlatTaskFileName,
|
|
32
|
+
buildTaskFileName,
|
|
33
|
+
legacyMilestonesDir,
|
|
34
|
+
resolveMilestonePath,
|
|
35
|
+
resolveTasksDir,
|
|
36
|
+
resolveSlicePath,
|
|
37
|
+
clearPathCache,
|
|
38
|
+
} from "../paths.js";
|
|
31
39
|
|
|
32
40
|
export interface ReopenSliceParams {
|
|
33
41
|
milestoneId: string;
|
|
@@ -80,11 +88,23 @@ export async function handleReopenSlice(
|
|
|
80
88
|
// Without this, the DB-filesystem reconciler sees SUMMARY.md files and
|
|
81
89
|
// auto-corrects tasks back to "complete", making reopen a no-op (#3161).
|
|
82
90
|
try {
|
|
91
|
+
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
92
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
93
|
+
const isLegacy = !!milestoneDir && (
|
|
94
|
+
milestoneDir.startsWith(legacyBase + "/") || milestoneDir.startsWith(legacyBase + "\\")
|
|
95
|
+
);
|
|
83
96
|
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
const tasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
98
|
+
for (const task of tasks) {
|
|
99
|
+
const summaryPaths = isLegacy
|
|
100
|
+
? (tasksDir ? [join(tasksDir, buildTaskFileName(task.id, "SUMMARY"))] : [])
|
|
101
|
+
: milestoneDir
|
|
102
|
+
? [
|
|
103
|
+
join(milestoneDir, buildFlatTaskFileName(params.sliceId, task.id, "SUMMARY")),
|
|
104
|
+
join(milestoneDir, buildTaskFileName(task.id, "SUMMARY")),
|
|
105
|
+
]
|
|
106
|
+
: [];
|
|
107
|
+
for (const summaryPath of summaryPaths) {
|
|
88
108
|
if (existsSync(summaryPath)) unlinkSync(summaryPath);
|
|
89
109
|
}
|
|
90
110
|
}
|
|
@@ -25,8 +25,16 @@ import { appendEvent } from "../workflow-events.js";
|
|
|
25
25
|
import { logWarning } from "../workflow-logger.js";
|
|
26
26
|
import { writeReopenReason } from "../reopen-reason.js";
|
|
27
27
|
import { existsSync, unlinkSync } from "node:fs";
|
|
28
|
-
import { join
|
|
29
|
-
import {
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
import {
|
|
30
|
+
buildFlatTaskFileName,
|
|
31
|
+
buildTaskFileName,
|
|
32
|
+
legacyMilestonesDir,
|
|
33
|
+
resolveMilestonePath,
|
|
34
|
+
resolveTasksDir,
|
|
35
|
+
resolveSlicePath,
|
|
36
|
+
clearPathCache,
|
|
37
|
+
} from "../paths.js";
|
|
30
38
|
|
|
31
39
|
export interface ReopenTaskParams {
|
|
32
40
|
milestoneId: string;
|
|
@@ -113,13 +121,19 @@ export async function handleReopenTask(
|
|
|
113
121
|
// summary cleanup into tasks/ (#1208).
|
|
114
122
|
try {
|
|
115
123
|
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const milestonePath = resolveMilestonePath(basePath, params.milestoneId);
|
|
125
|
+
if (milestonePath) {
|
|
126
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
127
|
+
const isLegacy = milestonePath.startsWith(legacyBase + "/") || milestonePath.startsWith(legacyBase + "\\");
|
|
128
|
+
const summaryPaths = isLegacy
|
|
129
|
+
? [join(resolveTasksDir(basePath, params.milestoneId, params.sliceId) ?? slicePath ?? join(milestonePath, "slices", params.sliceId, "tasks"), buildTaskFileName(params.taskId, "SUMMARY"))]
|
|
130
|
+
: [
|
|
131
|
+
join(milestonePath, buildFlatTaskFileName(params.sliceId, params.taskId, "SUMMARY")),
|
|
132
|
+
join(milestonePath, buildTaskFileName(params.taskId, "SUMMARY")),
|
|
133
|
+
];
|
|
134
|
+
for (const summaryPath of summaryPaths) {
|
|
135
|
+
if (existsSync(summaryPath)) unlinkSync(summaryPath);
|
|
136
|
+
}
|
|
123
137
|
}
|
|
124
138
|
} catch (cleanupErr) {
|
|
125
139
|
logWarning("tool", `reopen-task artifact cleanup warning: ${(cleanupErr as Error).message}`);
|