gsd-pi 2.43.0 → 2.44.0-dev.62b5d6c
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.js +13 -1
- package/dist/help-text.js +24 -0
- package/dist/resources/extensions/bg-shell/overlay.js +3 -0
- package/dist/resources/extensions/github-sync/sync.js +2 -1
- package/dist/resources/extensions/gsd/auto/loop.js +0 -2
- package/dist/resources/extensions/gsd/auto/phases.js +7 -12
- package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
- package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
- package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
- package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
- package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
- package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
- package/dist/resources/extensions/gsd/auto-verification.js +5 -10
- package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
- package/dist/resources/extensions/gsd/auto.js +1 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
- package/dist/resources/extensions/gsd/db-writer.js +95 -4
- package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
- package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
- package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
- package/dist/resources/extensions/gsd/doctor-types.js +0 -15
- package/dist/resources/extensions/gsd/doctor.js +46 -282
- package/dist/resources/extensions/gsd/file-watcher.js +5 -1
- package/dist/resources/extensions/gsd/files.js +14 -198
- package/dist/resources/extensions/gsd/git-service.js +4 -0
- package/dist/resources/extensions/gsd/gitignore.js +4 -0
- package/dist/resources/extensions/gsd/gsd-db.js +819 -197
- package/dist/resources/extensions/gsd/guided-flow.js +18 -8
- package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
- package/dist/resources/extensions/gsd/md-importer.js +182 -4
- package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
- package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
- package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
- package/dist/resources/extensions/gsd/preferences.js +1 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
- package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
- package/dist/resources/extensions/gsd/skill-health.js +3 -1
- package/dist/resources/extensions/gsd/state.js +484 -30
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
- package/dist/resources/extensions/gsd/undo.js +197 -3
- package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
- package/dist/resources/extensions/gsd/workspace-index.js +63 -39
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -16
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +4 -4
- package/dist/web/standalone/.next/routes-manifest.json +6 -0
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +5 -5
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -16
- package/dist/web/standalone/.next/server/chunks/229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
- 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/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- 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/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
- package/dist/web/standalone/.next/static/fOnWQBjWXMKUs4bqTg530/_buildManifest.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +4 -4
- package/packages/pi-ai/dist/models.custom.d.ts +173 -0
- package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.custom.js +170 -0
- package/packages/pi-ai/dist/models.custom.js.map +1 -0
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +16 -1
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.d.ts +2 -0
- package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/models.test.js +67 -0
- package/packages/pi-ai/dist/models.test.js.map +1 -0
- package/packages/pi-ai/src/models.custom.ts +172 -0
- package/packages/pi-ai/src/models.test.ts +85 -0
- package/packages/pi-ai/src/models.ts +17 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -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 +80 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -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/fallback-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
- package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
- package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -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 +40 -3
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
- package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
- package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
- package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +3 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +11 -199
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +21 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
- package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
- package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
- package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
- package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
- package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
- package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
- package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
- package/packages/pi-coding-agent/src/index.ts +7 -0
- package/packages/pi-coding-agent/src/main.ts +11 -232
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
- package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +8 -15
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/overlay.ts +4 -0
- package/src/resources/extensions/github-sync/sync.ts +2 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
- package/src/resources/extensions/gsd/auto/loop.ts +0 -2
- package/src/resources/extensions/gsd/auto/phases.ts +7 -20
- package/src/resources/extensions/gsd/auto/types.ts +0 -1
- package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
- package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
- package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
- package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
- package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
- package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
- package/src/resources/extensions/gsd/auto-verification.ts +4 -9
- package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
- package/src/resources/extensions/gsd/auto.ts +0 -9
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
- package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
- package/src/resources/extensions/gsd/db-writer.ts +105 -4
- package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
- package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
- package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
- package/src/resources/extensions/gsd/doctor-types.ts +0 -23
- package/src/resources/extensions/gsd/doctor.ts +45 -295
- package/src/resources/extensions/gsd/file-watcher.ts +4 -1
- package/src/resources/extensions/gsd/files.ts +16 -220
- package/src/resources/extensions/gsd/git-service.ts +4 -0
- package/src/resources/extensions/gsd/gitignore.ts +4 -0
- package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
- package/src/resources/extensions/gsd/guided-flow.ts +20 -8
- package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
- package/src/resources/extensions/gsd/md-importer.ts +211 -2
- package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
- package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
- package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
- package/src/resources/extensions/gsd/preferences-types.ts +3 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
- package/src/resources/extensions/gsd/preferences.ts +1 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
- package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
- package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
- package/src/resources/extensions/gsd/skill-health.ts +2 -1
- package/src/resources/extensions/gsd/state.ts +547 -29
- package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +150 -5
- package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +15 -20
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +410 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +439 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +527 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +593 -2
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +104 -57
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +22 -80
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -130
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +38 -76
- package/src/resources/extensions/gsd/tests/doctor.test.ts +9 -19
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +290 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +240 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +462 -0
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +4 -172
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1205 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +439 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/parsers.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
- package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
- package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +216 -0
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -3
- package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
- package/src/resources/extensions/gsd/types.ts +50 -0
- package/src/resources/extensions/gsd/undo.ts +247 -3
- package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
- package/src/resources/extensions/gsd/workspace-index.ts +64 -46
- package/dist/resources/extensions/gsd/auto-observability.js +0 -56
- package/dist/resources/extensions/gsd/observability-validator.js +0 -422
- package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
- package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
- package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
- package/src/resources/extensions/gsd/auto-observability.ts +0 -74
- package/src/resources/extensions/gsd/observability-validator.ts +0 -456
- package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
- package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
- package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
- /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → fOnWQBjWXMKUs4bqTg530}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,1098 @@
|
|
|
1
|
+
// GSD Markdown Renderer — DB → Markdown file generation
|
|
2
|
+
//
|
|
3
|
+
// Transforms DB state into correct markdown files on disk.
|
|
4
|
+
// Each render function reads from DB (with disk fallback),
|
|
5
|
+
// patches content to match DB status, writes atomically to disk,
|
|
6
|
+
// stores updated content in the artifacts table, and invalidates caches.
|
|
7
|
+
//
|
|
8
|
+
// Critical invariant: rendered markdown must round-trip through
|
|
9
|
+
// parseRoadmap(), parsePlan(), parseSummary() in files.ts.
|
|
10
|
+
|
|
11
|
+
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
12
|
+
import { join, relative } from "node:path";
|
|
13
|
+
import { createRequire } from "node:module";
|
|
14
|
+
import {
|
|
15
|
+
getAllMilestones,
|
|
16
|
+
getMilestone,
|
|
17
|
+
getMilestoneSlices,
|
|
18
|
+
getSliceTasks,
|
|
19
|
+
getTask,
|
|
20
|
+
getSlice,
|
|
21
|
+
getArtifact,
|
|
22
|
+
insertArtifact,
|
|
23
|
+
} from "./gsd-db.js";
|
|
24
|
+
import type { MilestoneRow, SliceRow, TaskRow, ArtifactRow } from "./gsd-db.js";
|
|
25
|
+
import {
|
|
26
|
+
resolveMilestoneFile,
|
|
27
|
+
resolveSliceFile,
|
|
28
|
+
resolveSlicePath,
|
|
29
|
+
resolveTasksDir,
|
|
30
|
+
gsdRoot,
|
|
31
|
+
buildTaskFileName,
|
|
32
|
+
buildSliceFileName,
|
|
33
|
+
} from "./paths.js";
|
|
34
|
+
import { saveFile, clearParseCache } from "./files.js";
|
|
35
|
+
import { invalidateStateCache } from "./state.js";
|
|
36
|
+
import { clearPathCache } from "./paths.js";
|
|
37
|
+
|
|
38
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Convert an absolute file path to a .gsd-relative artifact path.
|
|
42
|
+
* E.g. "/project/.gsd/milestones/M001/M001-ROADMAP.md" → "milestones/M001/M001-ROADMAP.md"
|
|
43
|
+
*/
|
|
44
|
+
function toArtifactPath(absPath: string, basePath: string): string {
|
|
45
|
+
const root = gsdRoot(basePath);
|
|
46
|
+
const rel = relative(root, absPath);
|
|
47
|
+
// Normalize to forward slashes for consistent DB keys
|
|
48
|
+
return rel.replace(/\\/g, "/");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Invalidate all caches after a disk write.
|
|
53
|
+
*/
|
|
54
|
+
function invalidateCaches(): void {
|
|
55
|
+
invalidateStateCache();
|
|
56
|
+
clearPathCache();
|
|
57
|
+
clearParseCache();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Load artifact content from DB first, falling back to reading from disk.
|
|
62
|
+
* On disk fallback, stores the content in the artifacts table for future use.
|
|
63
|
+
* Returns null if content is unavailable from both sources.
|
|
64
|
+
*/
|
|
65
|
+
function loadArtifactContent(
|
|
66
|
+
artifactPath: string,
|
|
67
|
+
absPath: string | null,
|
|
68
|
+
opts: {
|
|
69
|
+
artifact_type: string;
|
|
70
|
+
milestone_id: string;
|
|
71
|
+
slice_id?: string;
|
|
72
|
+
task_id?: string;
|
|
73
|
+
},
|
|
74
|
+
): string | null {
|
|
75
|
+
// Try DB first
|
|
76
|
+
const artifact = getArtifact(artifactPath);
|
|
77
|
+
if (artifact && artifact.full_content) {
|
|
78
|
+
return artifact.full_content;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Fall back to disk
|
|
82
|
+
if (!absPath) {
|
|
83
|
+
process.stderr.write(
|
|
84
|
+
`markdown-renderer: artifact not found in DB or on disk: ${artifactPath}\n`,
|
|
85
|
+
);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let content: string;
|
|
90
|
+
try {
|
|
91
|
+
content = readFileSync(absPath, "utf-8");
|
|
92
|
+
} catch {
|
|
93
|
+
process.stderr.write(
|
|
94
|
+
`markdown-renderer: cannot read file from disk: ${absPath}\n`,
|
|
95
|
+
);
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Store in DB for future use (graceful degradation path)
|
|
100
|
+
try {
|
|
101
|
+
insertArtifact({
|
|
102
|
+
path: artifactPath,
|
|
103
|
+
artifact_type: opts.artifact_type,
|
|
104
|
+
milestone_id: opts.milestone_id,
|
|
105
|
+
slice_id: opts.slice_id ?? null,
|
|
106
|
+
task_id: opts.task_id ?? null,
|
|
107
|
+
full_content: content,
|
|
108
|
+
});
|
|
109
|
+
} catch {
|
|
110
|
+
// Non-fatal: we have the content, DB storage is best-effort
|
|
111
|
+
process.stderr.write(
|
|
112
|
+
`markdown-renderer: warning — failed to store disk fallback in DB: ${artifactPath}\n`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return content;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Write rendered content to disk and update the artifacts table.
|
|
121
|
+
*/
|
|
122
|
+
async function writeAndStore(
|
|
123
|
+
absPath: string,
|
|
124
|
+
artifactPath: string,
|
|
125
|
+
content: string,
|
|
126
|
+
opts: {
|
|
127
|
+
artifact_type: string;
|
|
128
|
+
milestone_id: string;
|
|
129
|
+
slice_id?: string;
|
|
130
|
+
task_id?: string;
|
|
131
|
+
},
|
|
132
|
+
): Promise<void> {
|
|
133
|
+
await saveFile(absPath, content);
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
insertArtifact({
|
|
137
|
+
path: artifactPath,
|
|
138
|
+
artifact_type: opts.artifact_type,
|
|
139
|
+
milestone_id: opts.milestone_id,
|
|
140
|
+
slice_id: opts.slice_id ?? null,
|
|
141
|
+
task_id: opts.task_id ?? null,
|
|
142
|
+
full_content: content,
|
|
143
|
+
});
|
|
144
|
+
} catch {
|
|
145
|
+
// Non-fatal: file is on disk, DB is best-effort
|
|
146
|
+
process.stderr.write(
|
|
147
|
+
`markdown-renderer: warning — failed to update artifact in DB: ${artifactPath}\n`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
invalidateCaches();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function renderRoadmapMarkdown(milestone: MilestoneRow, slices: SliceRow[]): string {
|
|
155
|
+
const lines: string[] = [];
|
|
156
|
+
|
|
157
|
+
lines.push(`# ${milestone.id}: ${milestone.title || milestone.id}`);
|
|
158
|
+
lines.push("");
|
|
159
|
+
lines.push(`**Vision:** ${milestone.vision}`);
|
|
160
|
+
lines.push("");
|
|
161
|
+
|
|
162
|
+
if (milestone.success_criteria.length > 0) {
|
|
163
|
+
lines.push("## Success Criteria");
|
|
164
|
+
lines.push("");
|
|
165
|
+
for (const criterion of milestone.success_criteria) {
|
|
166
|
+
lines.push(`- ${criterion}`);
|
|
167
|
+
}
|
|
168
|
+
lines.push("");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
lines.push("## Slices");
|
|
172
|
+
lines.push("");
|
|
173
|
+
for (const slice of slices) {
|
|
174
|
+
const done = slice.status === "complete" ? "x" : " ";
|
|
175
|
+
const depends = `[${(slice.depends ?? []).join(",")}]`;
|
|
176
|
+
lines.push(`- [${done}] **${slice.id}: ${slice.title}** \`risk:${slice.risk}\` \`depends:${depends}\``);
|
|
177
|
+
lines.push(` > After this: ${slice.demo}`);
|
|
178
|
+
lines.push("");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (milestone.boundary_map_markdown.trim()) {
|
|
182
|
+
lines.push("## Boundary Map");
|
|
183
|
+
lines.push("");
|
|
184
|
+
lines.push(milestone.boundary_map_markdown.trim());
|
|
185
|
+
lines.push("");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function renderTaskPlanMarkdown(task: TaskRow): string {
|
|
192
|
+
const estimatedSteps = Math.max(1, task.description.trim().split(/\n+/).filter(Boolean).length || 1);
|
|
193
|
+
const estimatedFiles = task.files.length > 0
|
|
194
|
+
? task.files.length
|
|
195
|
+
: task.expected_output.length > 0
|
|
196
|
+
? task.expected_output.length
|
|
197
|
+
: task.inputs.length > 0
|
|
198
|
+
? task.inputs.length
|
|
199
|
+
: 1;
|
|
200
|
+
|
|
201
|
+
const lines: string[] = [];
|
|
202
|
+
lines.push("---");
|
|
203
|
+
lines.push(`estimated_steps: ${estimatedSteps}`);
|
|
204
|
+
lines.push(`estimated_files: ${estimatedFiles}`);
|
|
205
|
+
lines.push("skills_used: []");
|
|
206
|
+
lines.push("---");
|
|
207
|
+
lines.push("");
|
|
208
|
+
lines.push(`# ${task.id}: ${task.title || task.id}`);
|
|
209
|
+
lines.push("");
|
|
210
|
+
|
|
211
|
+
if (task.description.trim()) {
|
|
212
|
+
lines.push(task.description.trim());
|
|
213
|
+
lines.push("");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
lines.push("## Inputs");
|
|
217
|
+
lines.push("");
|
|
218
|
+
if (task.inputs.length > 0) {
|
|
219
|
+
for (const input of task.inputs) {
|
|
220
|
+
lines.push(`- \`${input}\``);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
lines.push("- None specified.");
|
|
224
|
+
}
|
|
225
|
+
lines.push("");
|
|
226
|
+
|
|
227
|
+
lines.push("## Expected Output");
|
|
228
|
+
lines.push("");
|
|
229
|
+
if (task.expected_output.length > 0) {
|
|
230
|
+
for (const output of task.expected_output) {
|
|
231
|
+
lines.push(`- \`${output}\``);
|
|
232
|
+
}
|
|
233
|
+
} else if (task.files.length > 0) {
|
|
234
|
+
for (const file of task.files) {
|
|
235
|
+
lines.push(`- \`${file}\``);
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
lines.push("- Update the implementation and proof artifacts needed for this task.");
|
|
239
|
+
}
|
|
240
|
+
lines.push("");
|
|
241
|
+
|
|
242
|
+
lines.push("## Verification");
|
|
243
|
+
lines.push("");
|
|
244
|
+
lines.push(task.verify.trim() || "- Verify the task outcome with the slice-level checks.");
|
|
245
|
+
lines.push("");
|
|
246
|
+
|
|
247
|
+
if (task.observability_impact.trim()) {
|
|
248
|
+
lines.push("## Observability Impact");
|
|
249
|
+
lines.push("");
|
|
250
|
+
lines.push(task.observability_impact.trim());
|
|
251
|
+
lines.push("");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function renderSlicePlanMarkdown(slice: SliceRow, tasks: TaskRow[]): string {
|
|
258
|
+
const lines: string[] = [];
|
|
259
|
+
|
|
260
|
+
lines.push(`# ${slice.id}: ${slice.title || slice.id}`);
|
|
261
|
+
lines.push("");
|
|
262
|
+
lines.push(`**Goal:** ${slice.goal}`);
|
|
263
|
+
lines.push(`**Demo:** ${slice.demo}`);
|
|
264
|
+
lines.push("");
|
|
265
|
+
|
|
266
|
+
lines.push("## Must-Haves");
|
|
267
|
+
lines.push("");
|
|
268
|
+
if (slice.success_criteria.trim()) {
|
|
269
|
+
for (const line of slice.success_criteria.split(/\n+/).map((entry) => entry.trim()).filter(Boolean)) {
|
|
270
|
+
lines.push(line.startsWith("-") ? line : `- ${line}`);
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
lines.push("- Complete the planned slice outcomes.");
|
|
274
|
+
}
|
|
275
|
+
lines.push("");
|
|
276
|
+
|
|
277
|
+
if (slice.proof_level.trim()) {
|
|
278
|
+
lines.push("## Proof Level");
|
|
279
|
+
lines.push("");
|
|
280
|
+
lines.push(`- This slice proves: ${slice.proof_level.trim()}`);
|
|
281
|
+
lines.push("");
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (slice.integration_closure.trim()) {
|
|
285
|
+
lines.push("## Integration Closure");
|
|
286
|
+
lines.push("");
|
|
287
|
+
lines.push(slice.integration_closure.trim());
|
|
288
|
+
lines.push("");
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
lines.push("## Verification");
|
|
292
|
+
lines.push("");
|
|
293
|
+
if (slice.observability_impact.trim()) {
|
|
294
|
+
const verificationLines = slice.observability_impact
|
|
295
|
+
.split(/\n+/)
|
|
296
|
+
.map((entry) => entry.trim())
|
|
297
|
+
.filter(Boolean);
|
|
298
|
+
for (const line of verificationLines) {
|
|
299
|
+
lines.push(line.startsWith("-") ? line : `- ${line}`);
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
lines.push("- Run the task and slice verification checks for this slice.");
|
|
303
|
+
}
|
|
304
|
+
lines.push("");
|
|
305
|
+
|
|
306
|
+
lines.push("## Tasks");
|
|
307
|
+
lines.push("");
|
|
308
|
+
for (const task of tasks) {
|
|
309
|
+
const done = task.status === "done" || task.status === "complete" ? "x" : " ";
|
|
310
|
+
const estimate = task.estimate.trim() ? ` \`est:${task.estimate.trim()}\`` : "";
|
|
311
|
+
lines.push(`- [${done}] **${task.id}: ${task.title || task.id}**${estimate}`);
|
|
312
|
+
if (task.description.trim()) {
|
|
313
|
+
lines.push(` ${task.description.trim()}`);
|
|
314
|
+
}
|
|
315
|
+
if (task.files.length > 0) {
|
|
316
|
+
lines.push(` - Files: ${task.files.map((file) => `\`${file}\``).join(", ")}`);
|
|
317
|
+
}
|
|
318
|
+
if (task.verify.trim()) {
|
|
319
|
+
lines.push(` - Verify: ${task.verify.trim()}`);
|
|
320
|
+
}
|
|
321
|
+
lines.push("");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const filesLikelyTouched = Array.from(new Set(tasks.flatMap((task) => task.files)));
|
|
325
|
+
if (filesLikelyTouched.length > 0) {
|
|
326
|
+
lines.push("## Files Likely Touched");
|
|
327
|
+
lines.push("");
|
|
328
|
+
for (const file of filesLikelyTouched) {
|
|
329
|
+
lines.push(`- ${file}`);
|
|
330
|
+
}
|
|
331
|
+
lines.push("");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function renderPlanFromDb(
|
|
338
|
+
basePath: string,
|
|
339
|
+
milestoneId: string,
|
|
340
|
+
sliceId: string,
|
|
341
|
+
): Promise<{ planPath: string; taskPlanPaths: string[]; content: string }> {
|
|
342
|
+
const slice = getSlice(milestoneId, sliceId);
|
|
343
|
+
if (!slice) {
|
|
344
|
+
throw new Error(`slice ${milestoneId}/${sliceId} not found`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
348
|
+
if (tasks.length === 0) {
|
|
349
|
+
throw new Error(`no tasks found for ${milestoneId}/${sliceId}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
|
|
353
|
+
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId);
|
|
354
|
+
const absPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN")
|
|
355
|
+
?? join(slicePath, `${sliceId}-PLAN.md`);
|
|
356
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
357
|
+
const content = renderSlicePlanMarkdown(slice, tasks);
|
|
358
|
+
|
|
359
|
+
await writeAndStore(absPath, artifactPath, content, {
|
|
360
|
+
artifact_type: "PLAN",
|
|
361
|
+
milestone_id: milestoneId,
|
|
362
|
+
slice_id: sliceId,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
const taskPlanPaths: string[] = [];
|
|
366
|
+
for (const task of tasks) {
|
|
367
|
+
const rendered = await renderTaskPlanFromDb(basePath, milestoneId, sliceId, task.id);
|
|
368
|
+
taskPlanPaths.push(rendered.taskPlanPath);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return { planPath: absPath, taskPlanPaths, content };
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export async function renderTaskPlanFromDb(
|
|
375
|
+
basePath: string,
|
|
376
|
+
milestoneId: string,
|
|
377
|
+
sliceId: string,
|
|
378
|
+
taskId: string,
|
|
379
|
+
): Promise<{ taskPlanPath: string; content: string }> {
|
|
380
|
+
const task = getTask(milestoneId, sliceId, taskId);
|
|
381
|
+
if (!task) {
|
|
382
|
+
throw new Error(`task ${milestoneId}/${sliceId}/${taskId} not found`);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId)
|
|
386
|
+
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId, "tasks");
|
|
387
|
+
mkdirSync(tasksDir, { recursive: true });
|
|
388
|
+
const absPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
389
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
390
|
+
const content = renderTaskPlanMarkdown(task);
|
|
391
|
+
|
|
392
|
+
await writeAndStore(absPath, artifactPath, content, {
|
|
393
|
+
artifact_type: "PLAN",
|
|
394
|
+
milestone_id: milestoneId,
|
|
395
|
+
slice_id: sliceId,
|
|
396
|
+
task_id: taskId,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return { taskPlanPath: absPath, content };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export async function renderRoadmapFromDb(
|
|
403
|
+
basePath: string,
|
|
404
|
+
milestoneId: string,
|
|
405
|
+
): Promise<{ roadmapPath: string; content: string }> {
|
|
406
|
+
const milestone = getMilestone(milestoneId);
|
|
407
|
+
if (!milestone) {
|
|
408
|
+
throw new Error(`milestone ${milestoneId} not found`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
412
|
+
const absPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP") ??
|
|
413
|
+
join(gsdRoot(basePath), "milestones", milestoneId, `${milestoneId}-ROADMAP.md`);
|
|
414
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
415
|
+
const content = renderRoadmapMarkdown(milestone, slices);
|
|
416
|
+
|
|
417
|
+
await writeAndStore(absPath, artifactPath, content, {
|
|
418
|
+
artifact_type: "ROADMAP",
|
|
419
|
+
milestone_id: milestoneId,
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
return { roadmapPath: absPath, content };
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ─── Roadmap Checkbox Rendering ───────────────────────────────────────────
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Render roadmap checkbox states from DB.
|
|
429
|
+
*
|
|
430
|
+
* For each slice in the milestone, sets [x] if status === 'complete',
|
|
431
|
+
* [ ] otherwise. Handles bidirectional updates (can uncheck previously
|
|
432
|
+
* checked slices if DB says pending).
|
|
433
|
+
*
|
|
434
|
+
* @returns true if the roadmap was written, false on skip/error
|
|
435
|
+
*/
|
|
436
|
+
export async function renderRoadmapCheckboxes(
|
|
437
|
+
basePath: string,
|
|
438
|
+
milestoneId: string,
|
|
439
|
+
): Promise<boolean> {
|
|
440
|
+
const slices = getMilestoneSlices(milestoneId);
|
|
441
|
+
if (slices.length === 0) {
|
|
442
|
+
process.stderr.write(
|
|
443
|
+
`markdown-renderer: no slices found for milestone ${milestoneId}\n`,
|
|
444
|
+
);
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const absPath = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
449
|
+
const artifactPath = absPath ? toArtifactPath(absPath, basePath) : null;
|
|
450
|
+
|
|
451
|
+
// Load content from DB (with disk fallback)
|
|
452
|
+
let content: string | null = null;
|
|
453
|
+
if (artifactPath) {
|
|
454
|
+
content = loadArtifactContent(artifactPath, absPath, {
|
|
455
|
+
artifact_type: "ROADMAP",
|
|
456
|
+
milestone_id: milestoneId,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (!content) {
|
|
461
|
+
process.stderr.write(
|
|
462
|
+
`markdown-renderer: no roadmap content available for ${milestoneId}\n`,
|
|
463
|
+
);
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Apply checkbox patches for each slice
|
|
468
|
+
let updated = content;
|
|
469
|
+
for (const slice of slices) {
|
|
470
|
+
const isDone = slice.status === "complete";
|
|
471
|
+
const sid = slice.id;
|
|
472
|
+
|
|
473
|
+
if (isDone) {
|
|
474
|
+
// Set [x]: replace "- [ ] **S01:" with "- [x] **S01:"
|
|
475
|
+
updated = updated.replace(
|
|
476
|
+
new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${sid}:`, "m"),
|
|
477
|
+
`$1[x] **${sid}:`,
|
|
478
|
+
);
|
|
479
|
+
} else {
|
|
480
|
+
// Set [ ]: replace "- [x] **S01:" with "- [ ] **S01:"
|
|
481
|
+
updated = updated.replace(
|
|
482
|
+
new RegExp(`^(\\s*-\\s+)\\[x\\]\\s+\\*\\*${sid}:`, "mi"),
|
|
483
|
+
`$1[ ] **${sid}:`,
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (!absPath) return false;
|
|
489
|
+
|
|
490
|
+
await writeAndStore(absPath, artifactPath!, updated, {
|
|
491
|
+
artifact_type: "ROADMAP",
|
|
492
|
+
milestone_id: milestoneId,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
return true;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// ─── Plan Checkbox Rendering ──────────────────────────────────────────────
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Render plan checkbox states from DB.
|
|
502
|
+
*
|
|
503
|
+
* For each task in the slice, sets [x] if status === 'done',
|
|
504
|
+
* [ ] otherwise. Bidirectional.
|
|
505
|
+
*
|
|
506
|
+
* @returns true if the plan was written, false on skip/error
|
|
507
|
+
*/
|
|
508
|
+
export async function renderPlanCheckboxes(
|
|
509
|
+
basePath: string,
|
|
510
|
+
milestoneId: string,
|
|
511
|
+
sliceId: string,
|
|
512
|
+
): Promise<boolean> {
|
|
513
|
+
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
514
|
+
if (tasks.length === 0) {
|
|
515
|
+
process.stderr.write(
|
|
516
|
+
`markdown-renderer: no tasks found for ${milestoneId}/${sliceId}\n`,
|
|
517
|
+
);
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const absPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
522
|
+
const artifactPath = absPath ? toArtifactPath(absPath, basePath) : null;
|
|
523
|
+
|
|
524
|
+
let content: string | null = null;
|
|
525
|
+
if (artifactPath) {
|
|
526
|
+
content = loadArtifactContent(artifactPath, absPath, {
|
|
527
|
+
artifact_type: "PLAN",
|
|
528
|
+
milestone_id: milestoneId,
|
|
529
|
+
slice_id: sliceId,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (!content) {
|
|
534
|
+
process.stderr.write(
|
|
535
|
+
`markdown-renderer: no plan content available for ${milestoneId}/${sliceId}\n`,
|
|
536
|
+
);
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Apply checkbox patches for each task
|
|
541
|
+
let updated = content;
|
|
542
|
+
for (const task of tasks) {
|
|
543
|
+
const isDone = task.status === "done" || task.status === "complete";
|
|
544
|
+
const tid = task.id;
|
|
545
|
+
|
|
546
|
+
if (isDone) {
|
|
547
|
+
// Set [x]
|
|
548
|
+
updated = updated.replace(
|
|
549
|
+
new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${tid}:`, "m"),
|
|
550
|
+
`$1[x] **${tid}:`,
|
|
551
|
+
);
|
|
552
|
+
} else {
|
|
553
|
+
// Set [ ]
|
|
554
|
+
updated = updated.replace(
|
|
555
|
+
new RegExp(`^(\\s*-\\s+)\\[x\\]\\s+\\*\\*${tid}:`, "mi"),
|
|
556
|
+
`$1[ ] **${tid}:`,
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (!absPath) return false;
|
|
562
|
+
|
|
563
|
+
await writeAndStore(absPath, artifactPath!, updated, {
|
|
564
|
+
artifact_type: "PLAN",
|
|
565
|
+
milestone_id: milestoneId,
|
|
566
|
+
slice_id: sliceId,
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// ─── Task Summary Rendering ───────────────────────────────────────────────
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Render a task summary from DB to disk.
|
|
576
|
+
* Reads full_summary_md from the tasks table and writes it to the appropriate file.
|
|
577
|
+
*
|
|
578
|
+
* @returns true if the summary was written, false on skip/error
|
|
579
|
+
*/
|
|
580
|
+
export async function renderTaskSummary(
|
|
581
|
+
basePath: string,
|
|
582
|
+
milestoneId: string,
|
|
583
|
+
sliceId: string,
|
|
584
|
+
taskId: string,
|
|
585
|
+
): Promise<boolean> {
|
|
586
|
+
const task = getTask(milestoneId, sliceId, taskId);
|
|
587
|
+
if (!task || !task.full_summary_md) {
|
|
588
|
+
return false; // No summary to render — skip silently
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Resolve the tasks directory, creating path if needed
|
|
592
|
+
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
593
|
+
if (!slicePath) {
|
|
594
|
+
process.stderr.write(
|
|
595
|
+
`markdown-renderer: cannot resolve slice path for ${milestoneId}/${sliceId}\n`,
|
|
596
|
+
);
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const tasksDir = join(slicePath, "tasks");
|
|
601
|
+
const fileName = buildTaskFileName(taskId, "SUMMARY");
|
|
602
|
+
const absPath = join(tasksDir, fileName);
|
|
603
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
604
|
+
|
|
605
|
+
await writeAndStore(absPath, artifactPath, task.full_summary_md, {
|
|
606
|
+
artifact_type: "SUMMARY",
|
|
607
|
+
milestone_id: milestoneId,
|
|
608
|
+
slice_id: sliceId,
|
|
609
|
+
task_id: taskId,
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// ─── Slice Summary Rendering ──────────────────────────────────────────────
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Render slice summary and UAT files from DB to disk.
|
|
619
|
+
* Reads full_summary_md and full_uat_md from the slices table.
|
|
620
|
+
*
|
|
621
|
+
* @returns true if at least one file was written, false on skip/error
|
|
622
|
+
*/
|
|
623
|
+
export async function renderSliceSummary(
|
|
624
|
+
basePath: string,
|
|
625
|
+
milestoneId: string,
|
|
626
|
+
sliceId: string,
|
|
627
|
+
): Promise<boolean> {
|
|
628
|
+
const slice = getSlice(milestoneId, sliceId);
|
|
629
|
+
if (!slice) {
|
|
630
|
+
return false; // No slice data — skip silently
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
634
|
+
if (!slicePath) {
|
|
635
|
+
process.stderr.write(
|
|
636
|
+
`markdown-renderer: cannot resolve slice path for ${milestoneId}/${sliceId}\n`,
|
|
637
|
+
);
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
let wrote = false;
|
|
642
|
+
|
|
643
|
+
// Write SUMMARY
|
|
644
|
+
if (slice.full_summary_md) {
|
|
645
|
+
const summaryName = buildSliceFileName(sliceId, "SUMMARY");
|
|
646
|
+
const summaryAbs = join(slicePath, summaryName);
|
|
647
|
+
const summaryArtifact = toArtifactPath(summaryAbs, basePath);
|
|
648
|
+
|
|
649
|
+
await writeAndStore(summaryAbs, summaryArtifact, slice.full_summary_md, {
|
|
650
|
+
artifact_type: "SUMMARY",
|
|
651
|
+
milestone_id: milestoneId,
|
|
652
|
+
slice_id: sliceId,
|
|
653
|
+
});
|
|
654
|
+
wrote = true;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Write UAT
|
|
658
|
+
if (slice.full_uat_md) {
|
|
659
|
+
const uatName = buildSliceFileName(sliceId, "UAT");
|
|
660
|
+
const uatAbs = join(slicePath, uatName);
|
|
661
|
+
const uatArtifact = toArtifactPath(uatAbs, basePath);
|
|
662
|
+
|
|
663
|
+
await writeAndStore(uatAbs, uatArtifact, slice.full_uat_md, {
|
|
664
|
+
artifact_type: "UAT",
|
|
665
|
+
milestone_id: milestoneId,
|
|
666
|
+
slice_id: sliceId,
|
|
667
|
+
});
|
|
668
|
+
wrote = true;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
return wrote;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ─── Render All From DB ───────────────────────────────────────────────────
|
|
675
|
+
|
|
676
|
+
export interface RenderAllResult {
|
|
677
|
+
rendered: number;
|
|
678
|
+
skipped: number;
|
|
679
|
+
errors: string[];
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Iterate all milestones, slices, and tasks in the DB and render each artifact to disk.
|
|
684
|
+
* Returns structured result for inspection.
|
|
685
|
+
*/
|
|
686
|
+
export async function renderAllFromDb(basePath: string): Promise<RenderAllResult> {
|
|
687
|
+
const result: RenderAllResult = { rendered: 0, skipped: 0, errors: [] };
|
|
688
|
+
const milestones = getAllMilestones();
|
|
689
|
+
|
|
690
|
+
for (const milestone of milestones) {
|
|
691
|
+
// Render roadmap checkboxes
|
|
692
|
+
try {
|
|
693
|
+
const ok = await renderRoadmapCheckboxes(basePath, milestone.id);
|
|
694
|
+
if (ok) result.rendered++;
|
|
695
|
+
else result.skipped++;
|
|
696
|
+
} catch (err) {
|
|
697
|
+
result.errors.push(`roadmap ${milestone.id}: ${(err as Error).message}`);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Iterate slices
|
|
701
|
+
const slices = getMilestoneSlices(milestone.id);
|
|
702
|
+
for (const slice of slices) {
|
|
703
|
+
// Render plan checkboxes
|
|
704
|
+
try {
|
|
705
|
+
const ok = await renderPlanCheckboxes(basePath, milestone.id, slice.id);
|
|
706
|
+
if (ok) result.rendered++;
|
|
707
|
+
else result.skipped++;
|
|
708
|
+
} catch (err) {
|
|
709
|
+
result.errors.push(
|
|
710
|
+
`plan ${milestone.id}/${slice.id}: ${(err as Error).message}`,
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Render slice summary
|
|
715
|
+
try {
|
|
716
|
+
const ok = await renderSliceSummary(basePath, milestone.id, slice.id);
|
|
717
|
+
if (ok) result.rendered++;
|
|
718
|
+
else result.skipped++;
|
|
719
|
+
} catch (err) {
|
|
720
|
+
result.errors.push(
|
|
721
|
+
`slice summary ${milestone.id}/${slice.id}: ${(err as Error).message}`,
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Iterate tasks
|
|
726
|
+
const tasks = getSliceTasks(milestone.id, slice.id);
|
|
727
|
+
for (const task of tasks) {
|
|
728
|
+
try {
|
|
729
|
+
const ok = await renderTaskSummary(
|
|
730
|
+
basePath,
|
|
731
|
+
milestone.id,
|
|
732
|
+
slice.id,
|
|
733
|
+
task.id,
|
|
734
|
+
);
|
|
735
|
+
if (ok) result.rendered++;
|
|
736
|
+
else result.skipped++;
|
|
737
|
+
} catch (err) {
|
|
738
|
+
result.errors.push(
|
|
739
|
+
`task summary ${milestone.id}/${slice.id}/${task.id}: ${(err as Error).message}`,
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return result;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// ─── Stale Detection ──────────────────────────────────────────────────────
|
|
750
|
+
|
|
751
|
+
export interface StaleEntry {
|
|
752
|
+
path: string;
|
|
753
|
+
reason: string;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Detect stale renders by comparing DB state against file content.
|
|
758
|
+
*
|
|
759
|
+
* Checks:
|
|
760
|
+
* 1. Roadmap checkbox states vs DB slice statuses
|
|
761
|
+
* 2. Plan checkbox states vs DB task statuses
|
|
762
|
+
* 3. Missing SUMMARY.md files for complete tasks with full_summary_md
|
|
763
|
+
* 4. Missing SUMMARY.md/UAT.md files for complete slices with content
|
|
764
|
+
*
|
|
765
|
+
* Returns a list of stale entries with file path and reason.
|
|
766
|
+
* Logs to stderr when stale files are detected.
|
|
767
|
+
*/
|
|
768
|
+
export function detectStaleRenders(basePath: string): StaleEntry[] {
|
|
769
|
+
// Lazy-load parsers — intentional disk-vs-DB comparison requires parsers
|
|
770
|
+
const _require = createRequire(import.meta.url);
|
|
771
|
+
let parseRoadmap: Function, parsePlan: Function;
|
|
772
|
+
try {
|
|
773
|
+
const m = _require("./parsers-legacy.ts");
|
|
774
|
+
parseRoadmap = m.parseRoadmap; parsePlan = m.parsePlan;
|
|
775
|
+
} catch {
|
|
776
|
+
const m = _require("./parsers-legacy.js");
|
|
777
|
+
parseRoadmap = m.parseRoadmap; parsePlan = m.parsePlan;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const stale: StaleEntry[] = [];
|
|
781
|
+
const milestones = getAllMilestones();
|
|
782
|
+
|
|
783
|
+
for (const milestone of milestones) {
|
|
784
|
+
const slices = getMilestoneSlices(milestone.id);
|
|
785
|
+
|
|
786
|
+
// ── Check roadmap checkbox state ──────────────────────────────────
|
|
787
|
+
const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
|
|
788
|
+
if (roadmapPath && existsSync(roadmapPath)) {
|
|
789
|
+
try {
|
|
790
|
+
const content = readFileSync(roadmapPath, "utf-8");
|
|
791
|
+
const parsed = parseRoadmap(content);
|
|
792
|
+
|
|
793
|
+
for (const slice of slices) {
|
|
794
|
+
const isCompleteInDb = slice.status === "complete";
|
|
795
|
+
const roadmapSlice = parsed.slices.find((s: { id: string }) => s.id === slice.id);
|
|
796
|
+
if (!roadmapSlice) continue;
|
|
797
|
+
|
|
798
|
+
if (isCompleteInDb && !roadmapSlice.done) {
|
|
799
|
+
stale.push({
|
|
800
|
+
path: roadmapPath,
|
|
801
|
+
reason: `${slice.id} is complete in DB but unchecked in roadmap`,
|
|
802
|
+
});
|
|
803
|
+
} else if (!isCompleteInDb && roadmapSlice.done) {
|
|
804
|
+
stale.push({
|
|
805
|
+
path: roadmapPath,
|
|
806
|
+
reason: `${slice.id} is not complete in DB but checked in roadmap`,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
} catch {
|
|
811
|
+
// Can't parse roadmap — skip silently
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// ── Check plan checkbox state and summaries for each slice ────────
|
|
816
|
+
for (const slice of slices) {
|
|
817
|
+
const tasks = getSliceTasks(milestone.id, slice.id);
|
|
818
|
+
|
|
819
|
+
// Check plan checkboxes
|
|
820
|
+
const planPath = resolveSliceFile(basePath, milestone.id, slice.id, "PLAN");
|
|
821
|
+
if (planPath && existsSync(planPath)) {
|
|
822
|
+
try {
|
|
823
|
+
const content = readFileSync(planPath, "utf-8");
|
|
824
|
+
const parsed = parsePlan(content);
|
|
825
|
+
|
|
826
|
+
for (const task of tasks) {
|
|
827
|
+
const isDoneInDb = task.status === "done" || task.status === "complete";
|
|
828
|
+
const planTask = parsed.tasks.find((t: { id: string }) => t.id === task.id);
|
|
829
|
+
if (!planTask) continue;
|
|
830
|
+
|
|
831
|
+
if (isDoneInDb && !planTask.done) {
|
|
832
|
+
stale.push({
|
|
833
|
+
path: planPath,
|
|
834
|
+
reason: `${task.id} is done in DB but unchecked in plan`,
|
|
835
|
+
});
|
|
836
|
+
} else if (!isDoneInDb && planTask.done) {
|
|
837
|
+
stale.push({
|
|
838
|
+
path: planPath,
|
|
839
|
+
reason: `${task.id} is not done in DB but checked in plan`,
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
} catch {
|
|
844
|
+
// Can't parse plan — skip silently
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// Check missing task summary files
|
|
849
|
+
for (const task of tasks) {
|
|
850
|
+
if ((task.status === "done" || task.status === "complete") && task.full_summary_md) {
|
|
851
|
+
const slicePath = resolveSlicePath(basePath, milestone.id, slice.id);
|
|
852
|
+
if (slicePath) {
|
|
853
|
+
const tasksDir = join(slicePath, "tasks");
|
|
854
|
+
const fileName = buildTaskFileName(task.id, "SUMMARY");
|
|
855
|
+
const summaryAbsPath = join(tasksDir, fileName);
|
|
856
|
+
|
|
857
|
+
if (!existsSync(summaryAbsPath)) {
|
|
858
|
+
stale.push({
|
|
859
|
+
path: summaryAbsPath,
|
|
860
|
+
reason: `${task.id} is complete with summary in DB but SUMMARY.md missing on disk`,
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Check missing slice summary/UAT files
|
|
868
|
+
const sliceRow = getSlice(milestone.id, slice.id);
|
|
869
|
+
if (sliceRow && sliceRow.status === "complete") {
|
|
870
|
+
const slicePath = resolveSlicePath(basePath, milestone.id, slice.id);
|
|
871
|
+
if (slicePath) {
|
|
872
|
+
if (sliceRow.full_summary_md) {
|
|
873
|
+
const summaryName = buildSliceFileName(slice.id, "SUMMARY");
|
|
874
|
+
const summaryAbsPath = join(slicePath, summaryName);
|
|
875
|
+
if (!existsSync(summaryAbsPath)) {
|
|
876
|
+
stale.push({
|
|
877
|
+
path: summaryAbsPath,
|
|
878
|
+
reason: `${slice.id} is complete with summary in DB but SUMMARY.md missing on disk`,
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (sliceRow.full_uat_md) {
|
|
884
|
+
const uatName = buildSliceFileName(slice.id, "UAT");
|
|
885
|
+
const uatAbsPath = join(slicePath, uatName);
|
|
886
|
+
if (!existsSync(uatAbsPath)) {
|
|
887
|
+
stale.push({
|
|
888
|
+
path: uatAbsPath,
|
|
889
|
+
reason: `${slice.id} is complete with UAT in DB but UAT.md missing on disk`,
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (stale.length > 0) {
|
|
899
|
+
process.stderr.write(
|
|
900
|
+
`markdown-renderer: detected ${stale.length} stale render(s):\n`,
|
|
901
|
+
);
|
|
902
|
+
for (const entry of stale) {
|
|
903
|
+
process.stderr.write(` - ${entry.path}: ${entry.reason}\n`);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return stale;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// ─── Stale Repair ─────────────────────────────────────────────────────────
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Repair all stale renders detected by `detectStaleRenders()`.
|
|
914
|
+
*
|
|
915
|
+
* For each stale entry, calls the appropriate render function:
|
|
916
|
+
* - Roadmap checkbox mismatches → renderRoadmapCheckboxes()
|
|
917
|
+
* - Plan checkbox mismatches → renderPlanCheckboxes()
|
|
918
|
+
* - Missing task summaries → renderTaskSummary()
|
|
919
|
+
* - Missing slice summaries/UATs → renderSliceSummary()
|
|
920
|
+
*
|
|
921
|
+
* Idempotent: calling twice with no DB changes produces zero repairs on the second call.
|
|
922
|
+
*
|
|
923
|
+
* @returns the number of files repaired
|
|
924
|
+
*/
|
|
925
|
+
export async function repairStaleRenders(basePath: string): Promise<number> {
|
|
926
|
+
const staleEntries = detectStaleRenders(basePath);
|
|
927
|
+
if (staleEntries.length === 0) return 0;
|
|
928
|
+
|
|
929
|
+
// Deduplicate: a single roadmap/plan file might appear multiple times
|
|
930
|
+
// (once per mismatched checkbox). We only need to re-render it once.
|
|
931
|
+
const repairedPaths = new Set<string>();
|
|
932
|
+
let repairCount = 0;
|
|
933
|
+
|
|
934
|
+
for (const entry of staleEntries) {
|
|
935
|
+
if (repairedPaths.has(entry.path)) continue;
|
|
936
|
+
// Normalize path separators for cross-platform regex matching
|
|
937
|
+
const normPath = entry.path.replace(/\\/g, "/");
|
|
938
|
+
|
|
939
|
+
try {
|
|
940
|
+
// Determine repair action from the reason
|
|
941
|
+
if (entry.reason.includes("in roadmap")) {
|
|
942
|
+
// Roadmap checkbox mismatch — extract milestone ID from path
|
|
943
|
+
const milestoneMatch = normPath.match(/milestones\/([^/]+)\//);
|
|
944
|
+
if (milestoneMatch) {
|
|
945
|
+
const ok = await renderRoadmapCheckboxes(basePath, milestoneMatch[1]);
|
|
946
|
+
if (ok) {
|
|
947
|
+
repairedPaths.add(entry.path);
|
|
948
|
+
repairCount++;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
} else if (entry.reason.includes("in plan")) {
|
|
952
|
+
// Plan checkbox mismatch — extract milestone + slice IDs from path
|
|
953
|
+
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
954
|
+
if (pathMatch) {
|
|
955
|
+
const ok = await renderPlanCheckboxes(basePath, pathMatch[1], pathMatch[2]);
|
|
956
|
+
if (ok) {
|
|
957
|
+
repairedPaths.add(entry.path);
|
|
958
|
+
repairCount++;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
} else if (entry.reason.includes("SUMMARY.md missing") && entry.reason.match(/^T\d+/)) {
|
|
962
|
+
// Missing task summary — extract IDs from path
|
|
963
|
+
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\/tasks\//);
|
|
964
|
+
const taskMatch = entry.reason.match(/^(T\d+)/);
|
|
965
|
+
if (pathMatch && taskMatch) {
|
|
966
|
+
const ok = await renderTaskSummary(basePath, pathMatch[1], pathMatch[2], taskMatch[1]);
|
|
967
|
+
if (ok) {
|
|
968
|
+
repairedPaths.add(entry.path);
|
|
969
|
+
repairCount++;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
} else if (entry.reason.includes("SUMMARY.md missing") && entry.reason.match(/^S\d+/)) {
|
|
973
|
+
// Missing slice summary — extract IDs from path
|
|
974
|
+
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
975
|
+
if (pathMatch) {
|
|
976
|
+
const ok = await renderSliceSummary(basePath, pathMatch[1], pathMatch[2]);
|
|
977
|
+
if (ok) {
|
|
978
|
+
repairedPaths.add(entry.path);
|
|
979
|
+
repairCount++;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
} else if (entry.reason.includes("UAT.md missing")) {
|
|
983
|
+
// Missing slice UAT — renderSliceSummary handles both SUMMARY + UAT
|
|
984
|
+
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
985
|
+
if (pathMatch) {
|
|
986
|
+
const ok = await renderSliceSummary(basePath, pathMatch[1], pathMatch[2]);
|
|
987
|
+
if (ok) {
|
|
988
|
+
repairedPaths.add(entry.path);
|
|
989
|
+
repairCount++;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
} catch (err) {
|
|
994
|
+
process.stderr.write(
|
|
995
|
+
`markdown-renderer: repair failed for ${entry.path}: ${(err as Error).message}\n`,
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
if (repairCount > 0) {
|
|
1001
|
+
process.stderr.write(
|
|
1002
|
+
`markdown-renderer: repaired ${repairCount} stale render(s)\n`,
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
return repairCount;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
// ─── Replan & Assessment Renderers ────────────────────────────────────────
|
|
1010
|
+
|
|
1011
|
+
export interface ReplanData {
|
|
1012
|
+
blockerTaskId: string;
|
|
1013
|
+
blockerDescription: string;
|
|
1014
|
+
whatChanged: string;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
export interface AssessmentData {
|
|
1018
|
+
verdict: string;
|
|
1019
|
+
assessment: string;
|
|
1020
|
+
completedSliceId?: string;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
export async function renderReplanFromDb(
|
|
1024
|
+
basePath: string,
|
|
1025
|
+
milestoneId: string,
|
|
1026
|
+
sliceId: string,
|
|
1027
|
+
replanData: ReplanData,
|
|
1028
|
+
): Promise<{ replanPath: string; content: string }> {
|
|
1029
|
+
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
|
|
1030
|
+
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId);
|
|
1031
|
+
const absPath = join(slicePath, `${sliceId}-REPLAN.md`);
|
|
1032
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
1033
|
+
|
|
1034
|
+
const lines: string[] = [];
|
|
1035
|
+
lines.push(`# ${sliceId} Replan`);
|
|
1036
|
+
lines.push("");
|
|
1037
|
+
lines.push(`**Milestone:** ${milestoneId}`);
|
|
1038
|
+
lines.push(`**Slice:** ${sliceId}`);
|
|
1039
|
+
lines.push(`**Blocker Task:** ${replanData.blockerTaskId}`);
|
|
1040
|
+
lines.push(`**Created:** ${new Date().toISOString()}`);
|
|
1041
|
+
lines.push("");
|
|
1042
|
+
lines.push("## Blocker Description");
|
|
1043
|
+
lines.push("");
|
|
1044
|
+
lines.push(replanData.blockerDescription);
|
|
1045
|
+
lines.push("");
|
|
1046
|
+
lines.push("## What Changed");
|
|
1047
|
+
lines.push("");
|
|
1048
|
+
lines.push(replanData.whatChanged);
|
|
1049
|
+
lines.push("");
|
|
1050
|
+
|
|
1051
|
+
const content = `${lines.join("\n").trimEnd()}\n`;
|
|
1052
|
+
|
|
1053
|
+
await writeAndStore(absPath, artifactPath, content, {
|
|
1054
|
+
artifact_type: "REPLAN",
|
|
1055
|
+
milestone_id: milestoneId,
|
|
1056
|
+
slice_id: sliceId,
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
return { replanPath: absPath, content };
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
export async function renderAssessmentFromDb(
|
|
1063
|
+
basePath: string,
|
|
1064
|
+
milestoneId: string,
|
|
1065
|
+
sliceId: string,
|
|
1066
|
+
assessmentData: AssessmentData,
|
|
1067
|
+
): Promise<{ assessmentPath: string; content: string }> {
|
|
1068
|
+
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
|
|
1069
|
+
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId);
|
|
1070
|
+
const absPath = join(slicePath, `${sliceId}-ASSESSMENT.md`);
|
|
1071
|
+
const artifactPath = toArtifactPath(absPath, basePath);
|
|
1072
|
+
|
|
1073
|
+
const lines: string[] = [];
|
|
1074
|
+
lines.push(`# ${sliceId} Assessment`);
|
|
1075
|
+
lines.push("");
|
|
1076
|
+
lines.push(`**Milestone:** ${milestoneId}`);
|
|
1077
|
+
lines.push(`**Slice:** ${sliceId}`);
|
|
1078
|
+
if (assessmentData.completedSliceId) {
|
|
1079
|
+
lines.push(`**Completed Slice:** ${assessmentData.completedSliceId}`);
|
|
1080
|
+
}
|
|
1081
|
+
lines.push(`**Verdict:** ${assessmentData.verdict}`);
|
|
1082
|
+
lines.push(`**Created:** ${new Date().toISOString()}`);
|
|
1083
|
+
lines.push("");
|
|
1084
|
+
lines.push("## Assessment");
|
|
1085
|
+
lines.push("");
|
|
1086
|
+
lines.push(assessmentData.assessment);
|
|
1087
|
+
lines.push("");
|
|
1088
|
+
|
|
1089
|
+
const content = `${lines.join("\n").trimEnd()}\n`;
|
|
1090
|
+
|
|
1091
|
+
await writeAndStore(absPath, artifactPath, content, {
|
|
1092
|
+
artifact_type: "ASSESSMENT",
|
|
1093
|
+
milestone_id: milestoneId,
|
|
1094
|
+
slice_id: sliceId,
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
return { assessmentPath: absPath, content };
|
|
1098
|
+
}
|