@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.955e4da0
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/dist/cli-web-branch.d.ts +2 -0
- package/dist/cli-web-branch.js +9 -2
- package/dist/help-text.js +5 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +78 -23
- package/dist/resources/extensions/bg-shell/utilities.js +2 -2
- package/dist/resources/extensions/claude-code-cli/models.js +9 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +92 -230
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
- package/dist/resources/extensions/github-sync/templates.js +3 -3
- package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
- package/dist/resources/extensions/gsd/auto/loop.js +74 -56
- package/dist/resources/extensions/gsd/auto/orchestrator.js +142 -15
- package/dist/resources/extensions/gsd/auto/phases.js +34 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +12 -9
- package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
- package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
- package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -36
- package/dist/resources/extensions/gsd/auto-timers.js +16 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
- package/dist/resources/extensions/gsd/auto-verification.js +7 -7
- package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +34 -289
- package/dist/resources/extensions/gsd/auto.js +15 -14
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +20 -43
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +131 -140
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +89 -8
- package/dist/resources/extensions/gsd/captures.js +5 -13
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
- package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
- package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
- package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
- package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
- package/dist/resources/extensions/gsd/commands-ship.js +2 -2
- package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
- package/dist/resources/extensions/gsd/db/engine.js +755 -0
- package/dist/resources/extensions/gsd/db/queries.js +372 -0
- package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
- package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
- package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
- package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
- package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
- package/dist/resources/extensions/gsd/db-workspace.js +103 -0
- package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
- package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
- package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -2
- package/dist/resources/extensions/gsd/doctor.js +16 -9
- package/dist/resources/extensions/gsd/error-classifier.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +3 -0
- package/dist/resources/extensions/gsd/gsd-db.js +183 -2048
- package/dist/resources/extensions/gsd/guided-flow.js +68 -471
- package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
- package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
- package/dist/resources/extensions/gsd/md-importer.js +4 -3
- package/dist/resources/extensions/gsd/migrate/safety.js +19 -11
- package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
- package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
- package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
- package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
- package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
- package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
- package/dist/resources/extensions/gsd/model-router.js +3 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
- package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/paths.js +10 -24
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
- package/dist/resources/extensions/gsd/preferences.js +161 -29
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
- package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
- package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
- package/dist/resources/extensions/gsd/question-transport.js +86 -0
- package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
- package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
- package/dist/resources/extensions/gsd/state.js +13 -5
- package/dist/resources/extensions/gsd/status-guards.js +56 -8
- package/dist/resources/extensions/gsd/templates/plan.md +7 -0
- package/dist/resources/extensions/gsd/templates/project.md +1 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/dist/resources/extensions/gsd/templates/uat.md +5 -1
- package/dist/resources/extensions/gsd/tool-contract.js +52 -8
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
- package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
- package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
- package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
- package/dist/resources/extensions/gsd/uat-policy.js +16 -10
- package/dist/resources/extensions/gsd/uat-run.js +9 -14
- package/dist/resources/extensions/gsd/undo.js +8 -7
- package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
- package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
- package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
- package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
- package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
- package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
- package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
- package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
- package/dist/resources/extensions/gsd/worktree-root.js +17 -6
- package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
- package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
- package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
- package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
- package/dist/resources/extensions/shared/interview-ui.js +2 -2
- package/dist/resources/shared/claude-runtime-floor.js +182 -0
- package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/update-cmd.js +20 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
- package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
- package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
- package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
- package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/web-mode.d.ts +2 -0
- package/dist/web-mode.js +20 -8
- package/dist/worktree-status-banner.js +7 -3
- package/package.json +2 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
- package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +10 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +8 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +32 -22
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
- package/packages/pi-ai/dist/image-models.generated.js +6 -6
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +295 -98
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +309 -154
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/components/input.js +1 -1
- package/packages/pi-tui/dist/components/input.js.map +1 -1
- package/packages/pi-tui/dist/keys.d.ts.map +1 -1
- package/packages/pi-tui/dist/keys.js +39 -30
- package/packages/pi-tui/dist/keys.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +22 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- 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/extensions/ask-user-questions.ts +87 -24
- package/src/resources/extensions/bg-shell/utilities.ts +2 -2
- package/src/resources/extensions/claude-code-cli/models.ts +9 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +114 -281
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +268 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
- package/src/resources/extensions/github-sync/templates.ts +3 -3
- package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
- package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
- package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
- package/src/resources/extensions/gsd/auto/loop.ts +83 -61
- package/src/resources/extensions/gsd/auto/orchestrator.ts +164 -17
- package/src/resources/extensions/gsd/auto/phases.ts +45 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
- package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -8
- package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
- package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
- package/src/resources/extensions/gsd/auto-start.ts +25 -34
- package/src/resources/extensions/gsd/auto-timers.ts +16 -2
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
- package/src/resources/extensions/gsd/auto-verification.ts +7 -8
- package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +53 -306
- package/src/resources/extensions/gsd/auto.ts +27 -17
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +20 -43
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -153
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +132 -6
- package/src/resources/extensions/gsd/captures.ts +5 -14
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
- package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
- package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
- package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
- package/src/resources/extensions/gsd/commands-ship.ts +2 -2
- package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
- package/src/resources/extensions/gsd/db/engine.ts +809 -0
- package/src/resources/extensions/gsd/db/queries.ts +453 -0
- package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
- package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
- package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
- package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
- package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
- package/src/resources/extensions/gsd/db-workspace.ts +170 -0
- package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
- package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
- package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
- package/src/resources/extensions/gsd/doctor.ts +15 -5
- package/src/resources/extensions/gsd/error-classifier.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +3 -0
- package/src/resources/extensions/gsd/gsd-db.ts +185 -2373
- package/src/resources/extensions/gsd/guided-flow.ts +81 -561
- package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
- package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -3
- package/src/resources/extensions/gsd/migrate/safety.ts +17 -9
- package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
- package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
- package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
- package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
- package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
- package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
- package/src/resources/extensions/gsd/model-router.ts +3 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
- package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/paths.ts +9 -22
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +191 -28
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
- package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
- package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
- package/src/resources/extensions/gsd/question-transport.ts +138 -0
- package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
- package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
- package/src/resources/extensions/gsd/state.ts +15 -5
- package/src/resources/extensions/gsd/status-guards.ts +59 -8
- package/src/resources/extensions/gsd/templates/plan.md +7 -0
- package/src/resources/extensions/gsd/templates/project.md +1 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
- package/src/resources/extensions/gsd/templates/uat.md +5 -1
- package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
- package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +185 -1
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +121 -0
- package/src/resources/extensions/gsd/tool-contract.ts +86 -8
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
- package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
- package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
- package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
- package/src/resources/extensions/gsd/uat-policy.ts +19 -10
- package/src/resources/extensions/gsd/uat-run.ts +10 -14
- package/src/resources/extensions/gsd/undo.ts +9 -8
- package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
- package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
- package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
- package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
- package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
- package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
- package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +17 -17
- package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
- package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
- package/src/resources/extensions/gsd/worktree-root.ts +17 -6
- package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
- package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
- package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
- package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
- package/src/resources/extensions/shared/interview-ui.ts +15 -2
- package/src/resources/shared/claude-runtime-floor.ts +248 -0
- package/src/resources/skills/gsd-browser/SKILL.md +1 -1
- package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
- package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
- package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
- package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Plans milestone roadmap state through DB-backed workflow tools.
|
|
3
3
|
|
|
4
|
-
import { clearParseCache } from "../files.js";
|
|
5
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
6
4
|
import { isNonEmptyString, validateStringArray, validateTitle } from "../validation.js";
|
|
7
|
-
import {
|
|
8
|
-
transaction,
|
|
9
|
-
getMilestone,
|
|
10
|
-
getMilestoneSlices,
|
|
11
|
-
getSlice,
|
|
12
|
-
insertMilestone,
|
|
13
|
-
insertSlice,
|
|
14
|
-
upsertMilestonePlanning,
|
|
15
|
-
upsertSlicePlanning,
|
|
16
|
-
} from "../gsd-db.js";
|
|
17
|
-
import { invalidateStateCache } from "../state.js";
|
|
18
|
-
import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
19
|
-
import { renderAllProjections } from "../workflow-projections.js";
|
|
20
|
-
import { writeManifest } from "../workflow-manifest.js";
|
|
21
|
-
import { appendEvent } from "../workflow-events.js";
|
|
22
|
-
import { logWarning } from "../workflow-logger.js";
|
|
5
|
+
import { persistMilestonePlan } from "../milestone-planning-persistence.js";
|
|
23
6
|
|
|
24
7
|
export interface PlanMilestoneSliceInput {
|
|
25
8
|
sliceId: string;
|
|
@@ -115,11 +98,21 @@ function validateProofStrategy(value: unknown): Array<{ riskOrUnknown: string; r
|
|
|
115
98
|
});
|
|
116
99
|
}
|
|
117
100
|
|
|
101
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
102
|
+
|
|
118
103
|
function validateSlices(value: unknown): PlanMilestoneSliceInput[] {
|
|
119
104
|
if (!Array.isArray(value) || value.length === 0) {
|
|
120
105
|
throw new Error("slices must be a non-empty array");
|
|
121
106
|
}
|
|
122
107
|
|
|
108
|
+
// Pre-collect all slice IDs so depends cross-validation can reference the full set.
|
|
109
|
+
const allSliceIds = new Set<string>(
|
|
110
|
+
(value as unknown[])
|
|
111
|
+
.filter((e): e is Record<string, unknown> => !!e && typeof e === "object")
|
|
112
|
+
.map(e => e.sliceId)
|
|
113
|
+
.filter((id): id is string => isNonEmptyString(id)),
|
|
114
|
+
);
|
|
115
|
+
|
|
123
116
|
const seen = new Set<string>();
|
|
124
117
|
return value.map((entry, index) => {
|
|
125
118
|
if (!entry || typeof entry !== "object") {
|
|
@@ -154,8 +147,13 @@ function validateSlices(value: unknown): PlanMilestoneSliceInput[] {
|
|
|
154
147
|
const titleIssue = validateTitle(title);
|
|
155
148
|
if (titleIssue) throw new Error(`slices[${index}].title is invalid: ${titleIssue}`);
|
|
156
149
|
if (!isNonEmptyString(risk)) throw new Error(`slices[${index}].risk must be a non-empty string`);
|
|
157
|
-
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item))) {
|
|
158
|
-
throw new Error(`slices[${index}].depends must be an array of
|
|
150
|
+
if (!Array.isArray(depends) || depends.some((item) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item as string))) {
|
|
151
|
+
throw new Error(`slices[${index}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
152
|
+
}
|
|
153
|
+
for (const dep of depends as string[]) {
|
|
154
|
+
if (!allSliceIds.has(dep)) {
|
|
155
|
+
throw new Error(`slices[${index}].depends references unknown slice "${dep}" — check that it is defined in the same milestone`);
|
|
156
|
+
}
|
|
159
157
|
}
|
|
160
158
|
if (!isNonEmptyString(demo)) throw new Error(`slices[${index}].demo must be a non-empty string`);
|
|
161
159
|
if (!isNonEmptyString(goal)) throw new Error(`slices[${index}].goal must be a non-empty string`);
|
|
@@ -227,144 +225,5 @@ export async function handlePlanMilestone(
|
|
|
227
225
|
return { error: `validation failed: ${(err as Error).message}` };
|
|
228
226
|
}
|
|
229
227
|
|
|
230
|
-
|
|
231
|
-
// Guards must be inside the transaction so the state they check cannot
|
|
232
|
-
// change between the read and the write (#2723).
|
|
233
|
-
let guardError: string | null = null;
|
|
234
|
-
|
|
235
|
-
try {
|
|
236
|
-
transaction(() => {
|
|
237
|
-
const existingMilestone = getMilestone(params.milestoneId);
|
|
238
|
-
if (existingMilestone && isClosedStatus(existingMilestone.status)) {
|
|
239
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: it is already complete`;
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Guard: refuse to re-plan a milestone that would drop completed slices (#2960).
|
|
244
|
-
// Allow re-planning when all completed slices are still present in the
|
|
245
|
-
// incoming plan — their status is preserved below (#2558). Block only when
|
|
246
|
-
// the new plan omits a completed slice, which could shadow completed work.
|
|
247
|
-
const existingSlices = getMilestoneSlices(params.milestoneId);
|
|
248
|
-
const completedSlices = existingSlices.filter(s => isClosedStatus(s.status));
|
|
249
|
-
if (completedSlices.length > 0) {
|
|
250
|
-
const incomingSliceIds = new Set(params.slices.map(s => s.sliceId));
|
|
251
|
-
const droppedCompleted = completedSlices.filter(s => !incomingSliceIds.has(s.id));
|
|
252
|
-
if (droppedCompleted.length > 0) {
|
|
253
|
-
guardError = `cannot re-plan milestone ${params.milestoneId}: ${droppedCompleted.length} completed slice(s) would be dropped (${droppedCompleted.map(s => s.id).join(", ")}). Use gsd_reassess_roadmap to modify the roadmap.`;
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Validate depends_on: all dependencies must exist and be complete
|
|
259
|
-
if (params.dependsOn && params.dependsOn.length > 0) {
|
|
260
|
-
for (const depId of params.dependsOn) {
|
|
261
|
-
const dep = getMilestone(depId);
|
|
262
|
-
if (!dep) {
|
|
263
|
-
guardError = `depends_on references unknown milestone: ${depId}`;
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
if (!isClosedStatus(dep.status)) {
|
|
267
|
-
guardError = `depends_on milestone ${depId} is not yet complete (status: ${dep.status})`;
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
insertMilestone({
|
|
274
|
-
id: params.milestoneId,
|
|
275
|
-
title: params.title,
|
|
276
|
-
status: params.status ?? "active",
|
|
277
|
-
depends_on: params.dependsOn ?? [],
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
upsertMilestonePlanning(params.milestoneId, {
|
|
281
|
-
title: params.title,
|
|
282
|
-
status: params.status ?? "active",
|
|
283
|
-
depends_on: params.dependsOn ?? [],
|
|
284
|
-
vision: params.vision,
|
|
285
|
-
successCriteria: params.successCriteria,
|
|
286
|
-
keyRisks: params.keyRisks,
|
|
287
|
-
proofStrategy: params.proofStrategy,
|
|
288
|
-
verificationContract: params.verificationContract,
|
|
289
|
-
verificationIntegration: params.verificationIntegration,
|
|
290
|
-
verificationOperational: params.verificationOperational,
|
|
291
|
-
verificationUat: params.verificationUat,
|
|
292
|
-
definitionOfDone: params.definitionOfDone,
|
|
293
|
-
requirementCoverage: params.requirementCoverage,
|
|
294
|
-
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
for (let i = 0; i < params.slices.length; i++) {
|
|
298
|
-
const slice = params.slices[i]!;
|
|
299
|
-
// Preserve completed/done status on re-plan (#2558).
|
|
300
|
-
// Without this, a re-plan after milestone transition would reset
|
|
301
|
-
// already-completed slices back to "pending".
|
|
302
|
-
const existing = getSlice(params.milestoneId, slice.sliceId);
|
|
303
|
-
const status = existing && (existing.status === "complete" || existing.status === "done")
|
|
304
|
-
? existing.status
|
|
305
|
-
: "pending";
|
|
306
|
-
insertSlice({
|
|
307
|
-
id: slice.sliceId,
|
|
308
|
-
milestoneId: params.milestoneId,
|
|
309
|
-
title: slice.title,
|
|
310
|
-
status,
|
|
311
|
-
risk: slice.risk,
|
|
312
|
-
depends: slice.depends,
|
|
313
|
-
demo: slice.demo,
|
|
314
|
-
sequence: i + 1, // Preserve agent-ordered sequence (#3356)
|
|
315
|
-
// ADR-011: pass undefined through so ON CONFLICT preserves existing values
|
|
316
|
-
// when the caller omitted the fields on a re-plan.
|
|
317
|
-
isSketch: slice.isSketch,
|
|
318
|
-
sketchScope: slice.sketchScope,
|
|
319
|
-
});
|
|
320
|
-
upsertSlicePlanning(params.milestoneId, slice.sliceId, {
|
|
321
|
-
goal: slice.goal,
|
|
322
|
-
successCriteria: slice.successCriteria,
|
|
323
|
-
proofLevel: slice.proofLevel,
|
|
324
|
-
integrationClosure: slice.integrationClosure,
|
|
325
|
-
observabilityImpact: slice.observabilityImpact,
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
} catch (err) {
|
|
330
|
-
return { error: `db write failed: ${(err as Error).message}` };
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (guardError) {
|
|
334
|
-
return { error: guardError };
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
let roadmapPath: string;
|
|
338
|
-
try {
|
|
339
|
-
const renderResult = await renderRoadmapFromDb(basePath, params.milestoneId);
|
|
340
|
-
roadmapPath = renderResult.roadmapPath;
|
|
341
|
-
} catch (renderErr) {
|
|
342
|
-
logWarning("tool", `plan_milestone — render failed (DB rows preserved for debugging): ${(renderErr as Error).message}`);
|
|
343
|
-
invalidateStateCache();
|
|
344
|
-
return { error: `render failed: ${(renderErr as Error).message}` };
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
invalidateStateCache();
|
|
348
|
-
clearParseCache();
|
|
349
|
-
|
|
350
|
-
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
351
|
-
try {
|
|
352
|
-
await renderAllProjections(basePath, params.milestoneId);
|
|
353
|
-
writeManifest(basePath);
|
|
354
|
-
appendEvent(basePath, {
|
|
355
|
-
cmd: "plan-milestone",
|
|
356
|
-
params: { milestoneId: params.milestoneId },
|
|
357
|
-
ts: new Date().toISOString(),
|
|
358
|
-
actor: "agent",
|
|
359
|
-
actor_name: params.actorName,
|
|
360
|
-
trigger_reason: params.triggerReason,
|
|
361
|
-
});
|
|
362
|
-
} catch (hookErr) {
|
|
363
|
-
logWarning("tool", `plan-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
milestoneId: params.milestoneId,
|
|
368
|
-
roadmapPath,
|
|
369
|
-
};
|
|
228
|
+
return persistMilestonePlan(params, basePath);
|
|
370
229
|
}
|
|
@@ -75,12 +75,19 @@ function validateParams(params: ReassessRoadmapParams): ReassessRoadmapParams {
|
|
|
75
75
|
throw new Error("sliceChanges.removed must be an array");
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
|
|
79
|
+
|
|
78
80
|
// Validate each modified slice
|
|
79
81
|
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
80
82
|
const s = params.sliceChanges.modified[i];
|
|
81
83
|
if (!s || typeof s !== "object") throw new Error(`sliceChanges.modified[${i}] must be an object`);
|
|
82
84
|
if (!isNonEmptyString(s.sliceId)) throw new Error(`sliceChanges.modified[${i}].sliceId is required`);
|
|
83
85
|
if (!isNonEmptyString(s.title)) throw new Error(`sliceChanges.modified[${i}].title is required`);
|
|
86
|
+
if (s.depends !== undefined) {
|
|
87
|
+
if (!Array.isArray(s.depends) || s.depends.some((item: unknown) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item as string))) {
|
|
88
|
+
throw new Error(`sliceChanges.modified[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
// Validate each added slice
|
|
@@ -89,6 +96,11 @@ function validateParams(params: ReassessRoadmapParams): ReassessRoadmapParams {
|
|
|
89
96
|
if (!s || typeof s !== "object") throw new Error(`sliceChanges.added[${i}] must be an object`);
|
|
90
97
|
if (!isNonEmptyString(s.sliceId)) throw new Error(`sliceChanges.added[${i}].sliceId is required`);
|
|
91
98
|
if (!isNonEmptyString(s.title)) throw new Error(`sliceChanges.added[${i}].title is required`);
|
|
99
|
+
if (s.depends !== undefined) {
|
|
100
|
+
if (!Array.isArray(s.depends) || s.depends.some((item: unknown) => !isNonEmptyString(item) || !SLICE_ID_RE.test(item as string))) {
|
|
101
|
+
throw new Error(`sliceChanges.added[${i}].depends must be an array of valid slice IDs (e.g. "S01")`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
return params;
|
|
@@ -166,6 +178,37 @@ export async function handleReassessRoadmap(
|
|
|
166
178
|
}
|
|
167
179
|
}
|
|
168
180
|
|
|
181
|
+
// Cross-milestone depends validation — effective slice ID set after this reassessment
|
|
182
|
+
const removedIds = new Set<string>(params.sliceChanges.removed);
|
|
183
|
+
const effectiveSliceIds = new Set<string>(
|
|
184
|
+
existingSlices.map(s => s.id).filter(id => !removedIds.has(id)),
|
|
185
|
+
);
|
|
186
|
+
for (const added of params.sliceChanges.added) {
|
|
187
|
+
effectiveSliceIds.add(added.sliceId);
|
|
188
|
+
}
|
|
189
|
+
for (let i = 0; i < params.sliceChanges.modified.length; i++) {
|
|
190
|
+
const mod = params.sliceChanges.modified[i]!;
|
|
191
|
+
if (mod.depends !== undefined) {
|
|
192
|
+
for (const dep of mod.depends) {
|
|
193
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
194
|
+
guardError = `sliceChanges.modified[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
201
|
+
const added = params.sliceChanges.added[i]!;
|
|
202
|
+
if (added.depends !== undefined) {
|
|
203
|
+
for (const dep of added.depends) {
|
|
204
|
+
if (!effectiveSliceIds.has(dep)) {
|
|
205
|
+
guardError = `sliceChanges.added[${i}].depends references unknown slice "${dep}" — check that it is defined in this milestone`;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
169
212
|
// Record assessment
|
|
170
213
|
insertAssessment({
|
|
171
214
|
path: assessmentRelPath,
|
|
@@ -10,16 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
|
-
getMilestone,
|
|
14
13
|
getMilestoneSlices,
|
|
15
14
|
getSliceTasks,
|
|
16
|
-
|
|
17
|
-
updateSliceStatus,
|
|
18
|
-
updateTaskStatus,
|
|
19
|
-
transaction,
|
|
15
|
+
reopenMilestoneCascade,
|
|
20
16
|
} from "../gsd-db.js";
|
|
21
17
|
import { invalidateStateCache } from "../state.js";
|
|
22
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
23
18
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
24
19
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
20
|
import { appendEvent } from "../workflow-events.js";
|
|
@@ -53,40 +48,18 @@ export async function handleReopenMilestone(
|
|
|
53
48
|
return { error: "milestoneId is required and must be a non-empty string" };
|
|
54
49
|
}
|
|
55
50
|
|
|
56
|
-
// ──
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
guardError = `milestone not found: ${params.milestoneId}`;
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (!isClosedStatus(milestone.status)) {
|
|
68
|
-
guardError = `milestone ${params.milestoneId} is not closed (status: ${milestone.status}) — nothing to reopen`;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
reopenMilestoneStatus(params.milestoneId);
|
|
73
|
-
|
|
74
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
75
|
-
slicesResetCount = slices.length;
|
|
76
|
-
|
|
77
|
-
for (const slice of slices) {
|
|
78
|
-
updateSliceStatus(params.milestoneId, slice.id, "in_progress");
|
|
79
|
-
const tasks = getSliceTasks(params.milestoneId, slice.id);
|
|
80
|
-
tasksResetCount += tasks.length;
|
|
81
|
-
for (const task of tasks) {
|
|
82
|
-
updateTaskStatus(params.milestoneId, slice.id, task.id, "pending");
|
|
83
|
-
}
|
|
51
|
+
// ── Atomic reopen cascade (guards + writes in one transaction) ───────────
|
|
52
|
+
const outcome = reopenMilestoneCascade(params.milestoneId);
|
|
53
|
+
if (!outcome.ok) {
|
|
54
|
+
switch (outcome.reason) {
|
|
55
|
+
case "milestone-not-found":
|
|
56
|
+
return { error: `milestone not found: ${params.milestoneId}` };
|
|
57
|
+
case "milestone-not-closed":
|
|
58
|
+
return { error: `milestone ${params.milestoneId} is not closed (status: ${outcome.status}) — nothing to reopen` };
|
|
84
59
|
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
if (guardError) {
|
|
88
|
-
return { error: guardError };
|
|
89
60
|
}
|
|
61
|
+
const slicesResetCount = outcome.slicesReset;
|
|
62
|
+
const tasksResetCount = outcome.tasksReset;
|
|
90
63
|
|
|
91
64
|
// ── Invalidate caches ────────────────────────────────────────────────────
|
|
92
65
|
invalidateStateCache();
|
|
@@ -12,15 +12,10 @@
|
|
|
12
12
|
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
getMilestone,
|
|
16
|
-
getSlice,
|
|
17
15
|
getSliceTasks,
|
|
18
|
-
|
|
19
|
-
updateTaskStatus,
|
|
20
|
-
transaction,
|
|
16
|
+
reopenSliceCascade,
|
|
21
17
|
} from "../gsd-db.js";
|
|
22
18
|
import { invalidateStateCache } from "../state.js";
|
|
23
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
24
19
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
25
20
|
import { writeManifest } from "../workflow-manifest.js";
|
|
26
21
|
import { appendEvent } from "../workflow-events.js";
|
|
@@ -57,44 +52,21 @@ export async function handleReopenSlice(
|
|
|
57
52
|
return { error: "milestoneId is required and must be a non-empty string" };
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
// ──
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const slice = getSlice(params.milestoneId, params.sliceId);
|
|
76
|
-
if (!slice) {
|
|
77
|
-
guardError = `slice not found: ${params.milestoneId}/${params.sliceId}`;
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
if (!isClosedStatus(slice.status)) {
|
|
81
|
-
guardError = `slice ${params.sliceId} is not complete (status: ${slice.status}) — nothing to reopen`;
|
|
82
|
-
return;
|
|
55
|
+
// ── Atomic reopen cascade (guards + writes in one transaction) ───────────
|
|
56
|
+
const outcome = reopenSliceCascade(params.milestoneId, params.sliceId);
|
|
57
|
+
if (!outcome.ok) {
|
|
58
|
+
switch (outcome.reason) {
|
|
59
|
+
case "milestone-not-found":
|
|
60
|
+
return { error: `milestone not found: ${params.milestoneId}` };
|
|
61
|
+
case "milestone-closed":
|
|
62
|
+
return { error: `cannot reopen slice in a closed milestone: ${params.milestoneId} (status: ${outcome.status})` };
|
|
63
|
+
case "slice-not-found":
|
|
64
|
+
return { error: `slice not found: ${params.milestoneId}/${params.sliceId}` };
|
|
65
|
+
case "slice-not-complete":
|
|
66
|
+
return { error: `slice ${params.sliceId} is not complete (status: ${outcome.status}) — nothing to reopen` };
|
|
83
67
|
}
|
|
84
|
-
|
|
85
|
-
// Fetch tasks inside txn so the list is consistent with the slice status check
|
|
86
|
-
const tasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
87
|
-
tasksResetCount = tasks.length;
|
|
88
|
-
|
|
89
|
-
updateSliceStatus(params.milestoneId, params.sliceId, "in_progress");
|
|
90
|
-
for (const task of tasks) {
|
|
91
|
-
updateTaskStatus(params.milestoneId, params.sliceId, task.id, "pending");
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
if (guardError) {
|
|
96
|
-
return { error: guardError };
|
|
97
68
|
}
|
|
69
|
+
const tasksResetCount = outcome.tasksReset;
|
|
98
70
|
|
|
99
71
|
// ── Invalidate caches ────────────────────────────────────────────────────
|
|
100
72
|
invalidateStateCache();
|
|
@@ -11,14 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
|
-
getSlice,
|
|
15
|
-
getSliceTasks,
|
|
16
14
|
isDbAvailable,
|
|
17
|
-
|
|
18
|
-
updateSliceStatus,
|
|
19
|
-
updateTaskStatus,
|
|
15
|
+
skipSliceCascade,
|
|
20
16
|
} from "../gsd-db.js";
|
|
21
|
-
import { isClosedStatus } from "../status-guards.js";
|
|
22
17
|
|
|
23
18
|
/**
|
|
24
19
|
* Input parameters for {@link handleSkipSlice}.
|
|
@@ -90,44 +85,23 @@ export function handleSkipSlice(params: SkipSliceParams): SkipSliceResult {
|
|
|
90
85
|
throw new Error("handleSkipSlice: GSD database is not available");
|
|
91
86
|
}
|
|
92
87
|
|
|
93
|
-
// ──
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
wasAlreadySkipped = slice.status === "skipped";
|
|
113
|
-
if (!wasAlreadySkipped) {
|
|
114
|
-
updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
|
|
88
|
+
// ── Atomic skip cascade (guards + writes in one transaction) ────────────
|
|
89
|
+
const outcome = skipSliceCascade(params.milestoneId, params.sliceId);
|
|
90
|
+
if (!outcome.ok) {
|
|
91
|
+
switch (outcome.reason) {
|
|
92
|
+
case "slice-not-found":
|
|
93
|
+
return {
|
|
94
|
+
...base,
|
|
95
|
+
error: `Slice ${params.sliceId} not found in milestone ${params.milestoneId}`,
|
|
96
|
+
errorCode: "slice_not_found" as SkipSliceErrorCode,
|
|
97
|
+
};
|
|
98
|
+
case "slice-already-complete":
|
|
99
|
+
return {
|
|
100
|
+
...base,
|
|
101
|
+
error: `Slice ${params.sliceId} is already complete — cannot skip.`,
|
|
102
|
+
errorCode: "already_complete" as SkipSliceErrorCode,
|
|
103
|
+
};
|
|
115
104
|
}
|
|
116
|
-
|
|
117
|
-
// Cascade: mark every non-closed task as skipped so milestone completion
|
|
118
|
-
// doesn't trip the deep-task guard (#4375). Closed tasks (complete/done/
|
|
119
|
-
// skipped) are left untouched — we never downgrade.
|
|
120
|
-
const tasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
121
|
-
for (const task of tasks) {
|
|
122
|
-
if (!isClosedStatus(task.status)) {
|
|
123
|
-
updateTaskStatus(params.milestoneId, params.sliceId, task.id, "skipped");
|
|
124
|
-
tasksSkipped++;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
if (guardError) {
|
|
130
|
-
return { ...base, error: guardError, errorCode: guardCode ?? undefined };
|
|
131
105
|
}
|
|
132
|
-
return { ...base, tasksSkipped, wasAlreadySkipped };
|
|
106
|
+
return { ...base, tasksSkipped: outcome.tasksSkipped, wasAlreadySkipped: outcome.wasAlreadySkipped };
|
|
133
107
|
}
|
|
@@ -19,11 +19,11 @@ import {
|
|
|
19
19
|
insertAssessment,
|
|
20
20
|
getMilestoneSlices,
|
|
21
21
|
getMilestone,
|
|
22
|
-
getArtifact,
|
|
23
22
|
} from "../gsd-db.js";
|
|
24
|
-
import { gsdProjectionRoot, clearPathCache
|
|
23
|
+
import { gsdProjectionRoot, clearPathCache } from "../paths.js";
|
|
25
24
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
26
|
-
import {
|
|
25
|
+
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
26
|
+
import { saveFile, clearParseCache } from "../files.js";
|
|
27
27
|
import { invalidateStateCache } from "../state.js";
|
|
28
28
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
29
29
|
import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
|
|
@@ -31,7 +31,10 @@ import { logWarning } from "../workflow-logger.js";
|
|
|
31
31
|
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
32
32
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
33
33
|
import { resolveUokFlags } from "../uok/flags.js";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
applyBrowserEvidenceGate,
|
|
36
|
+
browserEvidenceGateRequiresAttention,
|
|
37
|
+
} from "../milestone-validation-evidence.js";
|
|
35
38
|
|
|
36
39
|
export interface ValidateMilestoneParams {
|
|
37
40
|
milestoneId: string;
|
|
@@ -78,86 +81,6 @@ function getRequiredVerificationClasses(milestoneId: string): string[] {
|
|
|
78
81
|
return required;
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
function hasRuntimeExecutableUatEvidenceText(text: string): boolean {
|
|
82
|
-
if (!/\buatType:\s*runtime-executable\b/i.test(text)) return false;
|
|
83
|
-
if (!/\bverdict:\s*PASS\b/i.test(text)) return false;
|
|
84
|
-
return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async function browserEvidenceGateRequiresAttention(
|
|
88
|
-
params: ValidateMilestoneParams,
|
|
89
|
-
basePath: string,
|
|
90
|
-
): Promise<boolean> {
|
|
91
|
-
if (params.verdict !== "pass") return false;
|
|
92
|
-
|
|
93
|
-
const milestone = getMilestone(params.milestoneId);
|
|
94
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
95
|
-
const requirementText = compactTextParts([
|
|
96
|
-
milestone?.vision,
|
|
97
|
-
milestone?.success_criteria,
|
|
98
|
-
milestone?.verification_uat,
|
|
99
|
-
params.successCriteriaChecklist,
|
|
100
|
-
params.verificationClasses,
|
|
101
|
-
...slices.flatMap((slice) => [
|
|
102
|
-
slice.demo,
|
|
103
|
-
slice.goal,
|
|
104
|
-
slice.success_criteria,
|
|
105
|
-
]),
|
|
106
|
-
]);
|
|
107
|
-
if (!hasBrowserRequiredText(requirementText)) return false;
|
|
108
|
-
|
|
109
|
-
// Collect per-slice evidence so the runtime bypass is checked independently
|
|
110
|
-
// for each slice. Concatenating all slices before checking would allow runtime
|
|
111
|
-
// evidence from one slice to cover another slice's browser requirements.
|
|
112
|
-
const sliceEvidencePairs: Array<{ sliceRequirementText: string; evidenceText: string }> = [];
|
|
113
|
-
for (const slice of slices) {
|
|
114
|
-
const chunks: string[] = [];
|
|
115
|
-
const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
|
|
116
|
-
const artifact = getArtifact(artifactPath);
|
|
117
|
-
if (artifact?.full_content) chunks.push(artifact.full_content);
|
|
118
|
-
const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
|
|
119
|
-
const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
|
|
120
|
-
if (assessmentContent) chunks.push(assessmentContent);
|
|
121
|
-
sliceEvidencePairs.push({
|
|
122
|
-
sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
|
|
123
|
-
evidenceText: chunks.join("\n\n"),
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
|
|
127
|
-
|
|
128
|
-
// Runtime bypass: each slice whose own requirement text has browser-observable
|
|
129
|
-
// criteria must have its own runtime-executable UAT evidence. When no individual
|
|
130
|
-
// slice has slice-level browser requirements (e.g., they come from milestone-level
|
|
131
|
-
// fields only), fall back to checking whether any slice has runtime evidence.
|
|
132
|
-
const browserRequiringSlices = sliceEvidencePairs.filter((s) =>
|
|
133
|
-
hasBrowserRequiredText(s.sliceRequirementText),
|
|
134
|
-
);
|
|
135
|
-
const runtimeBypasses =
|
|
136
|
-
browserRequiringSlices.length > 0
|
|
137
|
-
? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
|
|
138
|
-
: sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
|
|
139
|
-
if (runtimeBypasses) return false;
|
|
140
|
-
|
|
141
|
-
const validationEvidence = compactTextParts([
|
|
142
|
-
params.successCriteriaChecklist,
|
|
143
|
-
params.verificationClasses,
|
|
144
|
-
params.verdictRationale,
|
|
145
|
-
params.remediationPlan,
|
|
146
|
-
]);
|
|
147
|
-
return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function applyBrowserEvidenceGate(params: ValidateMilestoneParams): ValidateMilestoneParams {
|
|
151
|
-
const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
|
|
152
|
-
return {
|
|
153
|
-
...params,
|
|
154
|
-
verdict: "needs-attention",
|
|
155
|
-
verdictRationale: params.verdictRationale.trim()
|
|
156
|
-
? `${params.verdictRationale.trim()}\n\n${note}`
|
|
157
|
-
: note,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
84
|
function renderValidationMarkdown(params: ValidateMilestoneParams): string {
|
|
162
85
|
let md = `---
|
|
163
86
|
verdict: ${params.verdict}
|
|
@@ -279,6 +202,24 @@ export async function handleValidateMilestone(
|
|
|
279
202
|
let projectionStale = false;
|
|
280
203
|
try {
|
|
281
204
|
await saveFile(validationPath, validationMd);
|
|
205
|
+
const projectRoot = resolveWorktreeProjectRoot(basePath);
|
|
206
|
+
if (projectRoot !== artifactBasePath) {
|
|
207
|
+
const projectValidationPath = join(
|
|
208
|
+
gsdProjectionRoot(projectRoot),
|
|
209
|
+
"milestones",
|
|
210
|
+
effectiveParams.milestoneId,
|
|
211
|
+
`${effectiveParams.milestoneId}-VALIDATION.md`,
|
|
212
|
+
);
|
|
213
|
+
try {
|
|
214
|
+
await saveFile(projectValidationPath, validationMd);
|
|
215
|
+
} catch (mirrorErr) {
|
|
216
|
+
logWarning(
|
|
217
|
+
"projection",
|
|
218
|
+
`validate_milestone project-root VALIDATION mirror failed for ${effectiveParams.milestoneId}`,
|
|
219
|
+
{ error: (mirrorErr as Error).message },
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
282
223
|
} catch (renderErr) {
|
|
283
224
|
projectionStale = true;
|
|
284
225
|
logWarning("projection", `validate_milestone projection write failed for ${effectiveParams.milestoneId}; DB validation remains committed`, {
|