gsd-pi 2.63.0 → 2.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -134
- package/dist/cli.js +48 -6
- package/dist/headless-query.js +11 -1
- package/dist/help-text.js +4 -1
- package/dist/onboarding.js +15 -8
- package/dist/resource-loader.js +18 -3
- package/dist/resources/extensions/cmux/index.js +21 -12
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +27 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +40 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -0
- package/dist/resources/extensions/gsd/auto/phases.js +157 -22
- package/dist/resources/extensions/gsd/auto/session.js +12 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +9 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +32 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +124 -10
- package/dist/resources/extensions/gsd/auto-prompts.js +25 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +15 -7
- package/dist/resources/extensions/gsd/auto-start.js +10 -21
- package/dist/resources/extensions/gsd/auto-timers.js +2 -1
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +17 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +13 -7
- package/dist/resources/extensions/gsd/auto.js +19 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +147 -75
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +13 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +85 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -1
- package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +54 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +30 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +9 -4
- package/dist/resources/extensions/gsd/constants.js +42 -0
- package/dist/resources/extensions/gsd/db-writer.js +72 -4
- package/dist/resources/extensions/gsd/forensics.js +20 -4
- package/dist/resources/extensions/gsd/gsd-db.js +64 -17
- package/dist/resources/extensions/gsd/guided-flow.js +19 -0
- package/dist/resources/extensions/gsd/metrics.js +27 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +5 -3
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences.js +7 -2
- package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/dist/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/dist/resources/extensions/gsd/prompts/system.md +4 -7
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/roadmap-mutations.js +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +9 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +73 -0
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +34 -0
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +109 -0
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +83 -0
- package/dist/resources/extensions/gsd/safety/file-change-validator.js +71 -0
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +91 -0
- package/dist/resources/extensions/gsd/safety/safety-harness.js +64 -0
- package/dist/resources/extensions/gsd/slice-parallel-conflict.js +67 -0
- package/dist/resources/extensions/gsd/slice-parallel-eligibility.js +51 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +378 -0
- package/dist/resources/extensions/gsd/state.js +74 -14
- package/dist/resources/extensions/gsd/status-guards.js +11 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +17 -12
- package/dist/resources/extensions/gsd/tools/complete-slice.js +40 -26
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -12
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +33 -25
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -8
- package/dist/resources/extensions/gsd/workflow-projections.js +21 -5
- package/dist/resources/extensions/gsd/worktree-manager.js +82 -29
- package/dist/resources/extensions/gsd/worktree-resolver.js +4 -3
- package/dist/resources/extensions/mcp-client/auth.js +101 -0
- package/dist/resources/extensions/mcp-client/index.js +10 -1
- package/dist/resources/extensions/ollama/index.js +28 -22
- package/dist/resources/extensions/ollama/model-capabilities.js +37 -34
- package/dist/resources/extensions/ollama/ndjson-stream.js +54 -0
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +380 -0
- package/dist/resources/extensions/ollama/ollama-client.js +23 -32
- package/dist/resources/extensions/ollama/ollama-discovery.js +2 -7
- package/dist/resources/extensions/ollama/ollama-tool.js +62 -0
- package/dist/resources/extensions/ollama/thinking-parser.js +104 -0
- package/dist/update-cmd.js +4 -2
- 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 +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.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 +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 +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 +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 +2 -2
- 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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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/onboarding/route.js +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 +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 +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 +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 +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 +2 -2
- 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 +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 +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/skill-health/route.js +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 +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 +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 +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 +2 -2
- 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 +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 +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/6897.js +12 -0
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/welcome-screen.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts +8 -0
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +50 -0
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +221 -5
- package/packages/pi-agent-core/src/agent-loop.ts +53 -0
- package/packages/pi-ai/dist/types.d.ts +16 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/types.ts +18 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +50 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +41 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +31 -4
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +28 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/extensions/provider-registration.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +12 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +3 -3
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +23 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +80 -56
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +53 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +66 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +39 -1
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +34 -4
- package/packages/pi-coding-agent/src/core/extensions/provider-registration.test.ts +81 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +14 -0
- package/packages/pi-coding-agent/src/core/model-resolver.ts +3 -3
- package/packages/pi-coding-agent/src/core/resource-loader.ts +89 -56
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cmux/index.ts +18 -12
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +27 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +46 -0
- package/src/resources/extensions/gsd/auto/loop.ts +5 -0
- package/src/resources/extensions/gsd/auto/phases.ts +194 -33
- package/src/resources/extensions/gsd/auto/session.ts +14 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +11 -3
- package/src/resources/extensions/gsd/auto-model-selection.ts +36 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +141 -12
- package/src/resources/extensions/gsd/auto-prompts.ts +21 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +9 -8
- package/src/resources/extensions/gsd/auto-start.ts +11 -20
- package/src/resources/extensions/gsd/auto-timers.ts +2 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +14 -6
- package/src/resources/extensions/gsd/auto.ts +22 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -88
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +15 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +98 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +36 -1
- package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +57 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +31 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +10 -4
- package/src/resources/extensions/gsd/constants.ts +44 -0
- package/src/resources/extensions/gsd/db-writer.ts +78 -4
- package/src/resources/extensions/gsd/forensics.ts +21 -5
- package/src/resources/extensions/gsd/gsd-db.ts +64 -17
- package/src/resources/extensions/gsd/guided-flow.ts +22 -0
- package/src/resources/extensions/gsd/metrics.ts +28 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -3
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -0
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +1 -0
- package/src/resources/extensions/gsd/prompts/forensics.md +2 -0
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +2 -0
- package/src/resources/extensions/gsd/prompts/system.md +4 -7
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/roadmap-mutations.ts +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +10 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +98 -0
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +49 -0
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +151 -0
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +120 -0
- package/src/resources/extensions/gsd/safety/file-change-validator.ts +108 -0
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +106 -0
- package/src/resources/extensions/gsd/safety/safety-harness.ts +105 -0
- package/src/resources/extensions/gsd/slice-parallel-conflict.ts +86 -0
- package/src/resources/extensions/gsd/slice-parallel-eligibility.ts +73 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +477 -0
- package/src/resources/extensions/gsd/state.ts +67 -12
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/artifact-corruption-2630.test.ts +288 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +34 -13
- package/src/resources/extensions/gsd/tests/cmux.test.ts +58 -0
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/complete-slice-string-coercion.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +109 -0
- package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +134 -0
- package/src/resources/extensions/gsd/tests/deferred-slice-dispatch.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +130 -0
- package/src/resources/extensions/gsd/tests/doctor-fix-flag.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/git-checkpoint.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/insert-slice-no-wipe.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +27 -7
- package/src/resources/extensions/gsd/tests/integration/idle-recovery.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/metrics.test.ts +116 -1
- package/src/resources/extensions/gsd/tests/milestone-status-tool.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/plan-milestone-title.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +82 -18
- package/src/resources/extensions/gsd/tests/preferences.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-conflict.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-eligibility.test.ts +95 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +349 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +35 -2
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +148 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +34 -20
- package/src/resources/extensions/gsd/tools/complete-slice.ts +41 -26
- package/src/resources/extensions/gsd/tools/complete-task.ts +12 -12
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +55 -30
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -8
- package/src/resources/extensions/gsd/types.ts +44 -22
- package/src/resources/extensions/gsd/workflow-logger.ts +2 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +23 -5
- package/src/resources/extensions/gsd/worktree-manager.ts +76 -28
- package/src/resources/extensions/gsd/worktree-resolver.ts +4 -3
- package/src/resources/extensions/mcp-client/auth.ts +149 -0
- package/src/resources/extensions/mcp-client/index.ts +16 -1
- package/src/resources/extensions/ollama/index.ts +26 -25
- package/src/resources/extensions/ollama/model-capabilities.ts +41 -34
- package/src/resources/extensions/ollama/ndjson-stream.ts +63 -0
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +20 -0
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +459 -0
- package/src/resources/extensions/ollama/ollama-client.ts +30 -30
- package/src/resources/extensions/ollama/ollama-discovery.ts +5 -8
- package/src/resources/extensions/ollama/ollama-tool.ts +69 -0
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-stream.test.ts +82 -0
- package/src/resources/extensions/ollama/tests/ollama-discovery.test.ts +0 -27
- package/src/resources/extensions/ollama/thinking-parser.ts +116 -0
- package/src/resources/extensions/ollama/types.ts +23 -0
- package/dist/web/standalone/.next/server/chunks/2229.js +0 -12
- /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → eebXKteM9EaWyseHKTjqp}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5FLUBNdqolRyyehCyChPd → eebXKteM9EaWyseHKTjqp}/_ssgManifest.js +0 -0
|
@@ -20,7 +20,7 @@ import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
|
20
20
|
import { isClosedStatus } from "../status-guards.js";
|
|
21
21
|
import { saveFile, clearParseCache } from "../files.js";
|
|
22
22
|
import { invalidateStateCache } from "../state.js";
|
|
23
|
-
import { renderAllProjections } from "../workflow-projections.js";
|
|
23
|
+
import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
|
|
24
24
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
25
|
import { appendEvent } from "../workflow-events.js";
|
|
26
26
|
import { logWarning } from "../workflow-logger.js";
|
|
@@ -30,15 +30,23 @@ export interface CompleteMilestoneParams {
|
|
|
30
30
|
title: string;
|
|
31
31
|
oneLiner: string;
|
|
32
32
|
narrative: string;
|
|
33
|
-
successCriteriaResults: string;
|
|
34
|
-
definitionOfDoneResults: string;
|
|
35
|
-
requirementOutcomes: string;
|
|
36
|
-
keyDecisions: string[];
|
|
37
|
-
keyFiles: string[];
|
|
38
|
-
lessonsLearned: string[];
|
|
39
|
-
followUps: string;
|
|
40
|
-
deviations: string;
|
|
41
33
|
verificationPassed: boolean;
|
|
34
|
+
/** @optional — defaults to "Not provided." when omitted by models with limited tool-calling */
|
|
35
|
+
successCriteriaResults?: string;
|
|
36
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
37
|
+
definitionOfDoneResults?: string;
|
|
38
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
39
|
+
requirementOutcomes?: string;
|
|
40
|
+
/** @optional — defaults to [] when omitted */
|
|
41
|
+
keyDecisions?: string[];
|
|
42
|
+
/** @optional — defaults to [] when omitted */
|
|
43
|
+
keyFiles?: string[];
|
|
44
|
+
/** @optional — defaults to [] when omitted */
|
|
45
|
+
lessonsLearned?: string[];
|
|
46
|
+
/** @optional — defaults to "None." when omitted */
|
|
47
|
+
followUps?: string;
|
|
48
|
+
/** @optional — defaults to "None." when omitted */
|
|
49
|
+
deviations?: string;
|
|
42
50
|
/** Optional caller-provided identity for audit trail */
|
|
43
51
|
actorName?: string;
|
|
44
52
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -52,22 +60,28 @@ export interface CompleteMilestoneResult {
|
|
|
52
60
|
|
|
53
61
|
function renderMilestoneSummaryMarkdown(params: CompleteMilestoneParams): string {
|
|
54
62
|
const now = new Date().toISOString();
|
|
63
|
+
const displayTitle = stripIdPrefix(params.title, params.milestoneId);
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
// Apply defaults for optional enrichment fields (#2771)
|
|
66
|
+
const keyDecisions = params.keyDecisions ?? [];
|
|
67
|
+
const keyFiles = params.keyFiles ?? [];
|
|
68
|
+
const lessonsLearned = params.lessonsLearned ?? [];
|
|
69
|
+
|
|
70
|
+
const keyDecisionsYaml = keyDecisions.length > 0
|
|
71
|
+
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
58
72
|
: " - (none)";
|
|
59
73
|
|
|
60
|
-
const keyFilesYaml =
|
|
61
|
-
?
|
|
74
|
+
const keyFilesYaml = keyFiles.length > 0
|
|
75
|
+
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
62
76
|
: " - (none)";
|
|
63
77
|
|
|
64
|
-
const lessonsYaml =
|
|
65
|
-
?
|
|
78
|
+
const lessonsYaml = lessonsLearned.length > 0
|
|
79
|
+
? lessonsLearned.map(l => ` - ${l}`).join("\n")
|
|
66
80
|
: " - (none)";
|
|
67
81
|
|
|
68
82
|
return `---
|
|
69
83
|
id: ${params.milestoneId}
|
|
70
|
-
title: "${
|
|
84
|
+
title: "${displayTitle}"
|
|
71
85
|
status: complete
|
|
72
86
|
completed_at: ${now}
|
|
73
87
|
key_decisions:
|
|
@@ -78,7 +92,7 @@ lessons_learned:
|
|
|
78
92
|
${lessonsYaml}
|
|
79
93
|
---
|
|
80
94
|
|
|
81
|
-
# ${params.milestoneId}: ${
|
|
95
|
+
# ${params.milestoneId}: ${displayTitle}
|
|
82
96
|
|
|
83
97
|
**${params.oneLiner}**
|
|
84
98
|
|
|
@@ -88,15 +102,15 @@ ${params.narrative}
|
|
|
88
102
|
|
|
89
103
|
## Success Criteria Results
|
|
90
104
|
|
|
91
|
-
${params.successCriteriaResults}
|
|
105
|
+
${params.successCriteriaResults ?? "Not provided."}
|
|
92
106
|
|
|
93
107
|
## Definition of Done Results
|
|
94
108
|
|
|
95
|
-
${params.definitionOfDoneResults}
|
|
109
|
+
${params.definitionOfDoneResults ?? "Not provided."}
|
|
96
110
|
|
|
97
111
|
## Requirement Outcomes
|
|
98
112
|
|
|
99
|
-
${params.requirementOutcomes}
|
|
113
|
+
${params.requirementOutcomes ?? "Not provided."}
|
|
100
114
|
|
|
101
115
|
## Deviations
|
|
102
116
|
|
|
@@ -46,58 +46,73 @@ export interface CompleteSliceResult {
|
|
|
46
46
|
function renderSliceSummaryMarkdown(params: CompleteSliceParams): string {
|
|
47
47
|
const now = new Date().toISOString();
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
// Apply defaults for optional enrichment arrays (#2771)
|
|
50
|
+
const provides = params.provides ?? [];
|
|
51
|
+
const requires = params.requires ?? [];
|
|
52
|
+
const affects = params.affects ?? [];
|
|
53
|
+
const keyFiles = params.keyFiles ?? [];
|
|
54
|
+
const keyDecisions = params.keyDecisions ?? [];
|
|
55
|
+
const patternsEstablished = params.patternsEstablished ?? [];
|
|
56
|
+
const observabilitySurfaces = params.observabilitySurfaces ?? [];
|
|
57
|
+
const drillDownPaths = params.drillDownPaths ?? [];
|
|
58
|
+
const requirementsAdvanced = params.requirementsAdvanced ?? [];
|
|
59
|
+
const requirementsValidated = params.requirementsValidated ?? [];
|
|
60
|
+
const requirementsSurfaced = params.requirementsSurfaced ?? [];
|
|
61
|
+
const requirementsInvalidated = params.requirementsInvalidated ?? [];
|
|
62
|
+
const filesModified = params.filesModified ?? [];
|
|
63
|
+
|
|
64
|
+
const providesYaml = provides.length > 0
|
|
65
|
+
? provides.map(p => ` - ${p}`).join("\n")
|
|
51
66
|
: " - (none)";
|
|
52
67
|
|
|
53
|
-
const requiresYaml =
|
|
54
|
-
?
|
|
68
|
+
const requiresYaml = requires.length > 0
|
|
69
|
+
? requires.map(r => ` - slice: ${r.slice}\n provides: ${r.provides}`).join("\n")
|
|
55
70
|
: " []";
|
|
56
71
|
|
|
57
|
-
const affectsYaml =
|
|
58
|
-
?
|
|
72
|
+
const affectsYaml = affects.length > 0
|
|
73
|
+
? affects.map(a => ` - ${a}`).join("\n")
|
|
59
74
|
: " []";
|
|
60
75
|
|
|
61
|
-
const keyFilesYaml =
|
|
62
|
-
?
|
|
76
|
+
const keyFilesYaml = keyFiles.length > 0
|
|
77
|
+
? keyFiles.map(f => ` - ${f}`).join("\n")
|
|
63
78
|
: " - (none)";
|
|
64
79
|
|
|
65
|
-
const keyDecisionsYaml =
|
|
66
|
-
?
|
|
80
|
+
const keyDecisionsYaml = keyDecisions.length > 0
|
|
81
|
+
? keyDecisions.map(d => ` - ${d}`).join("\n")
|
|
67
82
|
: " - (none)";
|
|
68
83
|
|
|
69
|
-
const patternsYaml =
|
|
70
|
-
?
|
|
84
|
+
const patternsYaml = patternsEstablished.length > 0
|
|
85
|
+
? patternsEstablished.map(p => ` - ${p}`).join("\n")
|
|
71
86
|
: " - (none)";
|
|
72
87
|
|
|
73
|
-
const observabilityYaml =
|
|
74
|
-
?
|
|
88
|
+
const observabilityYaml = observabilitySurfaces.length > 0
|
|
89
|
+
? observabilitySurfaces.map(o => ` - ${o}`).join("\n")
|
|
75
90
|
: " - none";
|
|
76
91
|
|
|
77
|
-
const drillDownYaml =
|
|
78
|
-
?
|
|
92
|
+
const drillDownYaml = drillDownPaths.length > 0
|
|
93
|
+
? drillDownPaths.map(d => ` - ${d}`).join("\n")
|
|
79
94
|
: " []";
|
|
80
95
|
|
|
81
96
|
// Requirements sections
|
|
82
|
-
const reqAdvanced =
|
|
83
|
-
?
|
|
97
|
+
const reqAdvanced = requirementsAdvanced.length > 0
|
|
98
|
+
? requirementsAdvanced.map(r => `- ${r.id} — ${r.how}`).join("\n")
|
|
84
99
|
: "None.";
|
|
85
100
|
|
|
86
|
-
const reqValidated =
|
|
87
|
-
?
|
|
101
|
+
const reqValidated = requirementsValidated.length > 0
|
|
102
|
+
? requirementsValidated.map(r => `- ${r.id} — ${r.proof}`).join("\n")
|
|
88
103
|
: "None.";
|
|
89
104
|
|
|
90
|
-
const reqSurfaced =
|
|
91
|
-
?
|
|
105
|
+
const reqSurfaced = requirementsSurfaced.length > 0
|
|
106
|
+
? requirementsSurfaced.map(r => `- ${r}`).join("\n")
|
|
92
107
|
: "None.";
|
|
93
108
|
|
|
94
|
-
const reqInvalidated =
|
|
95
|
-
?
|
|
109
|
+
const reqInvalidated = requirementsInvalidated.length > 0
|
|
110
|
+
? requirementsInvalidated.map(r => `- ${r.id} — ${r.what}`).join("\n")
|
|
96
111
|
: "None.";
|
|
97
112
|
|
|
98
113
|
// Files modified
|
|
99
|
-
const filesMod =
|
|
100
|
-
?
|
|
114
|
+
const filesMod = filesModified.length > 0
|
|
115
|
+
? filesModified.map(f => `- \`${f.path}\` — ${f.description}`).join("\n")
|
|
101
116
|
: "None.";
|
|
102
117
|
|
|
103
118
|
return `---
|
|
@@ -60,11 +60,11 @@ function paramsToTaskRow(params: CompleteTaskParams, completedAt: string): TaskR
|
|
|
60
60
|
verification_result: params.verification,
|
|
61
61
|
duration: "",
|
|
62
62
|
completed_at: completedAt,
|
|
63
|
-
blocker_discovered: params.blockerDiscovered,
|
|
64
|
-
deviations: params.deviations,
|
|
65
|
-
known_issues: params.knownIssues,
|
|
66
|
-
key_files: params.keyFiles,
|
|
67
|
-
key_decisions: params.keyDecisions,
|
|
63
|
+
blocker_discovered: params.blockerDiscovered ?? false,
|
|
64
|
+
deviations: params.deviations ?? "",
|
|
65
|
+
known_issues: params.knownIssues ?? "",
|
|
66
|
+
key_files: params.keyFiles ?? [],
|
|
67
|
+
key_decisions: params.keyDecisions ?? [],
|
|
68
68
|
full_summary_md: "",
|
|
69
69
|
description: "",
|
|
70
70
|
estimate: "",
|
|
@@ -152,14 +152,14 @@ export async function handleCompleteTask(
|
|
|
152
152
|
narrative: params.narrative,
|
|
153
153
|
verificationResult: params.verification,
|
|
154
154
|
duration: "",
|
|
155
|
-
blockerDiscovered: params.blockerDiscovered,
|
|
156
|
-
deviations: params.deviations,
|
|
157
|
-
knownIssues: params.knownIssues,
|
|
158
|
-
keyFiles: params.keyFiles,
|
|
159
|
-
keyDecisions: params.keyDecisions,
|
|
155
|
+
blockerDiscovered: params.blockerDiscovered ?? false,
|
|
156
|
+
deviations: params.deviations ?? "None.",
|
|
157
|
+
knownIssues: params.knownIssues ?? "None.",
|
|
158
|
+
keyFiles: params.keyFiles ?? [],
|
|
159
|
+
keyDecisions: params.keyDecisions ?? [],
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
-
for (const evidence of params.verificationEvidence) {
|
|
162
|
+
for (const evidence of (params.verificationEvidence ?? [])) {
|
|
163
163
|
insertVerificationEvidence({
|
|
164
164
|
taskId: params.taskId,
|
|
165
165
|
sliceId: params.sliceId,
|
|
@@ -182,7 +182,7 @@ export async function handleCompleteTask(
|
|
|
182
182
|
|
|
183
183
|
// Render summary markdown via the single source of truth (#2720)
|
|
184
184
|
const taskRow = paramsToTaskRow(params, completedAt);
|
|
185
|
-
const summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence);
|
|
185
|
+
const summaryMd = renderSummaryContent(taskRow, params.sliceId, params.milestoneId, params.verificationEvidence ?? []);
|
|
186
186
|
|
|
187
187
|
// Resolve and write summary to disk
|
|
188
188
|
let summaryPath: string;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
transaction,
|
|
6
6
|
getMilestone,
|
|
7
7
|
getMilestoneSlices,
|
|
8
|
+
getSlice,
|
|
8
9
|
insertMilestone,
|
|
9
10
|
insertSlice,
|
|
10
11
|
upsertMilestonePlanning,
|
|
@@ -33,24 +34,34 @@ export interface PlanMilestoneSliceInput {
|
|
|
33
34
|
export interface PlanMilestoneParams {
|
|
34
35
|
milestoneId: string;
|
|
35
36
|
title: string;
|
|
37
|
+
vision: string;
|
|
38
|
+
slices: PlanMilestoneSliceInput[];
|
|
36
39
|
status?: string;
|
|
37
40
|
dependsOn?: string[];
|
|
38
41
|
/** Optional caller-provided identity for audit trail */
|
|
39
42
|
actorName?: string;
|
|
40
43
|
/** Optional caller-provided reason this action was triggered */
|
|
41
44
|
triggerReason?: string;
|
|
42
|
-
|
|
43
|
-
successCriteria
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
/** @optional — defaults to [] when omitted by models with limited tool-calling */
|
|
46
|
+
successCriteria?: string[];
|
|
47
|
+
/** @optional — defaults to [] when omitted */
|
|
48
|
+
keyRisks?: Array<{ risk: string; whyItMatters: string }>;
|
|
49
|
+
/** @optional — defaults to [] when omitted */
|
|
50
|
+
proofStrategy?: Array<{ riskOrUnknown: string; retireIn: string; whatWillBeProven: string }>;
|
|
51
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
52
|
+
verificationContract?: string;
|
|
53
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
54
|
+
verificationIntegration?: string;
|
|
55
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
56
|
+
verificationOperational?: string;
|
|
57
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
58
|
+
verificationUat?: string;
|
|
59
|
+
/** @optional — defaults to [] when omitted */
|
|
60
|
+
definitionOfDone?: string[];
|
|
61
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
62
|
+
requirementCoverage?: string;
|
|
63
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
64
|
+
boundaryMapMarkdown?: string;
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
export interface PlanMilestoneResult {
|
|
@@ -149,20 +160,21 @@ function validateParams(params: PlanMilestoneParams): PlanMilestoneParams {
|
|
|
149
160
|
if (!isNonEmptyString(params?.milestoneId)) throw new Error("milestoneId is required");
|
|
150
161
|
if (!isNonEmptyString(params?.title)) throw new Error("title is required");
|
|
151
162
|
if (!isNonEmptyString(params?.vision)) throw new Error("vision is required");
|
|
152
|
-
if (!isNonEmptyString(params?.verificationContract)) throw new Error("verificationContract is required");
|
|
153
|
-
if (!isNonEmptyString(params?.verificationIntegration)) throw new Error("verificationIntegration is required");
|
|
154
|
-
if (!isNonEmptyString(params?.verificationOperational)) throw new Error("verificationOperational is required");
|
|
155
|
-
if (!isNonEmptyString(params?.verificationUat)) throw new Error("verificationUat is required");
|
|
156
|
-
if (!isNonEmptyString(params?.requirementCoverage)) throw new Error("requirementCoverage is required");
|
|
157
|
-
if (!isNonEmptyString(params?.boundaryMapMarkdown)) throw new Error("boundaryMapMarkdown is required");
|
|
158
163
|
|
|
159
164
|
return {
|
|
160
165
|
...params,
|
|
161
166
|
dependsOn: params.dependsOn ? validateStringArray(params.dependsOn, "dependsOn") : [],
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
// Apply defaults for optional enrichment fields (#2771)
|
|
168
|
+
successCriteria: params.successCriteria ? validateStringArray(params.successCriteria, "successCriteria") : [],
|
|
169
|
+
keyRisks: params.keyRisks ? validateRiskEntries(params.keyRisks) : [],
|
|
170
|
+
proofStrategy: params.proofStrategy ? validateProofStrategy(params.proofStrategy) : [],
|
|
171
|
+
verificationContract: params.verificationContract ?? "Not provided.",
|
|
172
|
+
verificationIntegration: params.verificationIntegration ?? "Not provided.",
|
|
173
|
+
verificationOperational: params.verificationOperational ?? "Not provided.",
|
|
174
|
+
verificationUat: params.verificationUat ?? "Not provided.",
|
|
175
|
+
definitionOfDone: params.definitionOfDone ? validateStringArray(params.definitionOfDone, "definitionOfDone") : [],
|
|
176
|
+
requirementCoverage: params.requirementCoverage ?? "Not provided.",
|
|
177
|
+
boundaryMapMarkdown: params.boundaryMapMarkdown ?? "Not provided.",
|
|
166
178
|
slices: validateSlices(params.slices),
|
|
167
179
|
};
|
|
168
180
|
}
|
|
@@ -191,15 +203,19 @@ export async function handlePlanMilestone(
|
|
|
191
203
|
return;
|
|
192
204
|
}
|
|
193
205
|
|
|
194
|
-
// Guard: refuse to re-plan a milestone that
|
|
195
|
-
//
|
|
196
|
-
//
|
|
197
|
-
//
|
|
206
|
+
// Guard: refuse to re-plan a milestone that would drop completed slices (#2960).
|
|
207
|
+
// Allow re-planning when all completed slices are still present in the
|
|
208
|
+
// incoming plan — their status is preserved below (#2558). Block only when
|
|
209
|
+
// the new plan omits a completed slice, which could shadow completed work.
|
|
198
210
|
const existingSlices = getMilestoneSlices(params.milestoneId);
|
|
199
211
|
const completedSlices = existingSlices.filter(s => isClosedStatus(s.status));
|
|
200
212
|
if (completedSlices.length > 0) {
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
const incomingSliceIds = new Set(params.slices.map(s => s.sliceId));
|
|
214
|
+
const droppedCompleted = completedSlices.filter(s => !incomingSliceIds.has(s.id));
|
|
215
|
+
if (droppedCompleted.length > 0) {
|
|
216
|
+
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.`;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
203
219
|
}
|
|
204
220
|
|
|
205
221
|
// Validate depends_on: all dependencies must exist and be complete
|
|
@@ -225,6 +241,8 @@ export async function handlePlanMilestone(
|
|
|
225
241
|
});
|
|
226
242
|
|
|
227
243
|
upsertMilestonePlanning(params.milestoneId, {
|
|
244
|
+
title: params.title,
|
|
245
|
+
status: params.status ?? "active",
|
|
228
246
|
vision: params.vision,
|
|
229
247
|
successCriteria: params.successCriteria,
|
|
230
248
|
keyRisks: params.keyRisks,
|
|
@@ -236,14 +254,21 @@ export async function handlePlanMilestone(
|
|
|
236
254
|
definitionOfDone: params.definitionOfDone,
|
|
237
255
|
requirementCoverage: params.requirementCoverage,
|
|
238
256
|
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
239
|
-
}
|
|
257
|
+
});
|
|
240
258
|
|
|
241
259
|
for (const slice of params.slices) {
|
|
260
|
+
// Preserve completed/done status on re-plan (#2558).
|
|
261
|
+
// Without this, a re-plan after milestone transition would reset
|
|
262
|
+
// already-completed slices back to "pending".
|
|
263
|
+
const existing = getSlice(params.milestoneId, slice.sliceId);
|
|
264
|
+
const status = existing && (existing.status === "complete" || existing.status === "done")
|
|
265
|
+
? existing.status
|
|
266
|
+
: "pending";
|
|
242
267
|
insertSlice({
|
|
243
268
|
id: slice.sliceId,
|
|
244
269
|
milestoneId: params.milestoneId,
|
|
245
270
|
title: slice.title,
|
|
246
|
-
status
|
|
271
|
+
status,
|
|
247
272
|
risk: slice.risk,
|
|
248
273
|
depends: slice.depends,
|
|
249
274
|
demo: slice.demo,
|
|
@@ -35,11 +35,15 @@ export interface PlanSliceParams {
|
|
|
35
35
|
milestoneId: string;
|
|
36
36
|
sliceId: string;
|
|
37
37
|
goal: string;
|
|
38
|
-
successCriteria: string;
|
|
39
|
-
proofLevel: string;
|
|
40
|
-
integrationClosure: string;
|
|
41
|
-
observabilityImpact: string;
|
|
42
38
|
tasks: PlanSliceTaskInput[];
|
|
39
|
+
/** @optional — defaults to "Not provided." when omitted by models with limited tool-calling */
|
|
40
|
+
successCriteria?: string;
|
|
41
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
42
|
+
proofLevel?: string;
|
|
43
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
44
|
+
integrationClosure?: string;
|
|
45
|
+
/** @optional — defaults to "Not provided." when omitted */
|
|
46
|
+
observabilityImpact?: string;
|
|
43
47
|
/** Optional caller-provided identity for audit trail */
|
|
44
48
|
actorName?: string;
|
|
45
49
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -112,13 +116,14 @@ function validateParams(params: PlanSliceParams): PlanSliceParams {
|
|
|
112
116
|
if (!isNonEmptyString(params?.milestoneId)) throw new Error("milestoneId is required");
|
|
113
117
|
if (!isNonEmptyString(params?.sliceId)) throw new Error("sliceId is required");
|
|
114
118
|
if (!isNonEmptyString(params?.goal)) throw new Error("goal is required");
|
|
115
|
-
if (!isNonEmptyString(params?.successCriteria)) throw new Error("successCriteria is required");
|
|
116
|
-
if (!isNonEmptyString(params?.proofLevel)) throw new Error("proofLevel is required");
|
|
117
|
-
if (!isNonEmptyString(params?.integrationClosure)) throw new Error("integrationClosure is required");
|
|
118
|
-
if (!isNonEmptyString(params?.observabilityImpact)) throw new Error("observabilityImpact is required");
|
|
119
119
|
|
|
120
120
|
return {
|
|
121
121
|
...params,
|
|
122
|
+
// Apply defaults for optional enrichment fields (#2771)
|
|
123
|
+
successCriteria: params.successCriteria ?? "Not provided.",
|
|
124
|
+
proofLevel: params.proofLevel ?? "Not provided.",
|
|
125
|
+
integrationClosure: params.integrationClosure ?? "Not provided.",
|
|
126
|
+
observabilityImpact: params.observabilityImpact ?? "Not provided.",
|
|
122
127
|
tasks: validateTasks(params.tasks),
|
|
123
128
|
};
|
|
124
129
|
}
|
|
@@ -515,12 +515,18 @@ export interface CompleteTaskParams {
|
|
|
515
515
|
oneLiner: string;
|
|
516
516
|
narrative: string;
|
|
517
517
|
verification: string;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
518
|
+
/** @optional — defaults to [] when omitted by models with limited tool-calling */
|
|
519
|
+
keyFiles?: string[];
|
|
520
|
+
/** @optional — defaults to [] when omitted by models with limited tool-calling */
|
|
521
|
+
keyDecisions?: string[];
|
|
522
|
+
/** @optional — defaults to "None." when omitted */
|
|
523
|
+
deviations?: string;
|
|
524
|
+
/** @optional — defaults to "None." when omitted */
|
|
525
|
+
knownIssues?: string;
|
|
526
|
+
/** @optional — defaults to false when omitted */
|
|
527
|
+
blockerDiscovered?: boolean;
|
|
528
|
+
/** @optional — defaults to [] when omitted by models with limited tool-calling */
|
|
529
|
+
verificationEvidence?: Array<{
|
|
524
530
|
command: string;
|
|
525
531
|
exitCode: number;
|
|
526
532
|
verdict: string;
|
|
@@ -541,23 +547,39 @@ export interface CompleteSliceParams {
|
|
|
541
547
|
oneLiner: string;
|
|
542
548
|
narrative: string;
|
|
543
549
|
verification: string;
|
|
544
|
-
keyFiles: string[];
|
|
545
|
-
keyDecisions: string[];
|
|
546
|
-
patternsEstablished: string[];
|
|
547
|
-
observabilitySurfaces: string[];
|
|
548
|
-
deviations: string;
|
|
549
|
-
knownLimitations: string;
|
|
550
|
-
followUps: string;
|
|
551
|
-
requirementsAdvanced: Array<{ id: string; how: string }>;
|
|
552
|
-
requirementsValidated: Array<{ id: string; proof: string }>;
|
|
553
|
-
requirementsSurfaced: string[];
|
|
554
|
-
requirementsInvalidated: Array<{ id: string; what: string }>;
|
|
555
|
-
filesModified: Array<{ path: string; description: string }>;
|
|
556
550
|
uatContent: string;
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
551
|
+
/** @optional — defaults to [] when omitted by models with limited tool-calling */
|
|
552
|
+
keyFiles?: string[];
|
|
553
|
+
/** @optional — defaults to [] when omitted */
|
|
554
|
+
keyDecisions?: string[];
|
|
555
|
+
/** @optional — defaults to [] when omitted */
|
|
556
|
+
patternsEstablished?: string[];
|
|
557
|
+
/** @optional — defaults to [] when omitted */
|
|
558
|
+
observabilitySurfaces?: string[];
|
|
559
|
+
/** @optional — defaults to "None." when omitted */
|
|
560
|
+
deviations?: string;
|
|
561
|
+
/** @optional — defaults to "None." when omitted */
|
|
562
|
+
knownLimitations?: string;
|
|
563
|
+
/** @optional — defaults to "None." when omitted */
|
|
564
|
+
followUps?: string;
|
|
565
|
+
/** @optional — defaults to [] when omitted */
|
|
566
|
+
requirementsAdvanced?: Array<{ id: string; how: string }>;
|
|
567
|
+
/** @optional — defaults to [] when omitted */
|
|
568
|
+
requirementsValidated?: Array<{ id: string; proof: string }>;
|
|
569
|
+
/** @optional — defaults to [] when omitted */
|
|
570
|
+
requirementsSurfaced?: string[];
|
|
571
|
+
/** @optional — defaults to [] when omitted */
|
|
572
|
+
requirementsInvalidated?: Array<{ id: string; what: string }>;
|
|
573
|
+
/** @optional — defaults to [] when omitted */
|
|
574
|
+
filesModified?: Array<{ path: string; description: string }>;
|
|
575
|
+
/** @optional — defaults to [] when omitted */
|
|
576
|
+
provides?: string[];
|
|
577
|
+
/** @optional — defaults to [] when omitted */
|
|
578
|
+
requires?: Array<{ slice: string; provides: string }>;
|
|
579
|
+
/** @optional — defaults to [] when omitted */
|
|
580
|
+
affects?: string[];
|
|
581
|
+
/** @optional — defaults to [] when omitted */
|
|
582
|
+
drillDownPaths?: string[];
|
|
561
583
|
/** Optional caller-provided identity for audit trail */
|
|
562
584
|
actorName?: string;
|
|
563
585
|
/** Optional caller-provided reason this action was triggered */
|
|
@@ -48,7 +48,8 @@ export type LogComponent =
|
|
|
48
48
|
| "bootstrap" // Extension bootstrap (system-context, agent-end)
|
|
49
49
|
| "guided" // Guided flow (discuss, plan wizards)
|
|
50
50
|
| "registry" // Rule registry hook state
|
|
51
|
-
| "renderer"
|
|
51
|
+
| "renderer" // Markdown renderer and projections
|
|
52
|
+
| "safety"; // LLM safety harness
|
|
52
53
|
|
|
53
54
|
export interface LogEntry {
|
|
54
55
|
ts: string;
|
|
@@ -19,6 +19,22 @@ import { logWarning } from "./workflow-logger.js";
|
|
|
19
19
|
import { deriveState } from "./state.js";
|
|
20
20
|
import type { GSDState } from "./types.js";
|
|
21
21
|
|
|
22
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Strip a leading ID prefix (e.g. "M001: " or "S04: ") from a title
|
|
26
|
+
* to prevent double-prefixing when the renderer adds its own prefix.
|
|
27
|
+
* Handles repeated prefixes (e.g. "M001: M001: M001: Title" → "Title").
|
|
28
|
+
*/
|
|
29
|
+
export function stripIdPrefix(title: string, id: string): string {
|
|
30
|
+
const prefix = `${id}: `;
|
|
31
|
+
let result = title;
|
|
32
|
+
while (result.startsWith(prefix)) {
|
|
33
|
+
result = result.slice(prefix.length);
|
|
34
|
+
}
|
|
35
|
+
return result.trim() || title;
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
// ─── PLAN.md Projection ──────────────────────────────────────────────────
|
|
23
39
|
|
|
24
40
|
/**
|
|
@@ -28,7 +44,8 @@ import type { GSDState } from "./types.js";
|
|
|
28
44
|
export function renderPlanContent(sliceRow: SliceRow, taskRows: TaskRow[]): string {
|
|
29
45
|
const lines: string[] = [];
|
|
30
46
|
|
|
31
|
-
|
|
47
|
+
const displayTitle = stripIdPrefix(sliceRow.title, sliceRow.id);
|
|
48
|
+
lines.push(`# ${sliceRow.id}: ${displayTitle}`);
|
|
32
49
|
lines.push("");
|
|
33
50
|
// #2945: never use full_summary_md/full_uat_md as display fallbacks —
|
|
34
51
|
// they contain multi-line rendered markdown that corrupts single-line fields.
|
|
@@ -97,7 +114,8 @@ export function renderPlanProjection(basePath: string, milestoneId: string, slic
|
|
|
97
114
|
export function renderRoadmapContent(milestoneRow: MilestoneRow, sliceRows: SliceRow[]): string {
|
|
98
115
|
const lines: string[] = [];
|
|
99
116
|
|
|
100
|
-
|
|
117
|
+
const displayTitle = stripIdPrefix(milestoneRow.title, milestoneRow.id);
|
|
118
|
+
lines.push(`# ${milestoneRow.id}: ${displayTitle}`);
|
|
101
119
|
lines.push("");
|
|
102
120
|
lines.push("## Vision");
|
|
103
121
|
lines.push(milestoneRow.vision || milestoneRow.title || "TBD");
|
|
@@ -265,14 +283,14 @@ export function renderStateContent(state: GSDState): string {
|
|
|
265
283
|
lines.push("# GSD State", "");
|
|
266
284
|
|
|
267
285
|
const activeSlice = state.activeSlice
|
|
268
|
-
? `${state.activeSlice.id}: ${state.activeSlice.title}`
|
|
286
|
+
? `${state.activeSlice.id}: ${stripIdPrefix(state.activeSlice.title, state.activeSlice.id)}`
|
|
269
287
|
: "None";
|
|
270
288
|
|
|
271
289
|
if (state.phase === 'complete' && state.lastCompletedMilestone) {
|
|
272
290
|
lines.push(`**Last Completed Milestone:** ${state.lastCompletedMilestone.id}: ${state.lastCompletedMilestone.title}`);
|
|
273
291
|
} else {
|
|
274
292
|
const activeMilestone = state.activeMilestone
|
|
275
|
-
? `${state.activeMilestone.id}: ${state.activeMilestone.title}`
|
|
293
|
+
? `${state.activeMilestone.id}: ${stripIdPrefix(state.activeMilestone.title, state.activeMilestone.id)}`
|
|
276
294
|
: "None";
|
|
277
295
|
lines.push(`**Active Milestone:** ${activeMilestone}`);
|
|
278
296
|
}
|
|
@@ -286,7 +304,7 @@ export function renderStateContent(state: GSDState): string {
|
|
|
286
304
|
|
|
287
305
|
for (const entry of state.registry) {
|
|
288
306
|
const glyph = entry.status === "complete" ? "\u2705" : entry.status === "active" ? "\uD83D\uDD04" : entry.status === "parked" ? "\u23F8\uFE0F" : "\u2B1C";
|
|
289
|
-
lines.push(`- ${glyph} **${entry.id}:** ${entry.title}`);
|
|
307
|
+
lines.push(`- ${glyph} **${entry.id}:** ${stripIdPrefix(entry.title, entry.id)}`);
|
|
290
308
|
}
|
|
291
309
|
|
|
292
310
|
lines.push("");
|