gsd-pi 2.44.0-dev.848dd4c β 2.44.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 +12 -30
- package/dist/resources/extensions/gsd/auto-start.js +0 -10
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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_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 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- 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 +4 -4
- 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 +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- 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 +14 -14
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-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/app/_not-found/{page-f2a7482d42a5614b.js β page-2f24283c162b6ab3.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js β layout-9ecfd95f343793f0.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.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 +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +26 -24
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +48 -29
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +34 -30
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/src/resources/extensions/gsd/auto-start.ts +0 -14
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +16 -14
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
- package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +59 -38
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
- package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
- package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
- package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
- package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
- package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
- package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
- package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
- package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
- package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 β mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 β mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createTestContext } from './test-helpers.ts';
|
|
1
2
|
import * as path from 'node:path';
|
|
2
3
|
import * as os from 'node:os';
|
|
3
4
|
import * as fs from 'node:fs';
|
|
@@ -37,8 +38,8 @@ import {
|
|
|
37
38
|
} from '../files.ts';
|
|
38
39
|
import { clearPathCache, _clearGsdRootCache } from '../paths.ts';
|
|
39
40
|
import { invalidateStateCache } from '../state.ts';
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
42
43
|
|
|
43
44
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
44
45
|
// Helpers
|
|
@@ -173,27 +174,29 @@ function makeTaskSummaryContent(taskId: string): string {
|
|
|
173
174
|
// DB Accessor Tests
|
|
174
175
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
175
176
|
|
|
176
|
-
|
|
177
|
+
console.log('\nββ markdown-renderer: DB accessor basics ββ');
|
|
178
|
+
|
|
179
|
+
{
|
|
177
180
|
openDatabase(':memory:');
|
|
178
181
|
|
|
179
182
|
// getAllMilestones β empty
|
|
180
183
|
const empty = getAllMilestones();
|
|
181
|
-
|
|
184
|
+
assertEq(empty.length, 0, 'getAllMilestones returns empty when no milestones');
|
|
182
185
|
|
|
183
186
|
// Insert and retrieve
|
|
184
187
|
insertMilestone({ id: 'M001', title: 'Test MS', status: 'active' });
|
|
185
188
|
insertMilestone({ id: 'M002', title: 'Second MS', status: 'active' });
|
|
186
189
|
|
|
187
190
|
const all = getAllMilestones();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
191
|
+
assertEq(all.length, 2, 'getAllMilestones returns 2 milestones');
|
|
192
|
+
assertEq(all[0].id, 'M001', 'first milestone is M001');
|
|
193
|
+
assertEq(all[1].id, 'M002', 'second milestone is M002');
|
|
194
|
+
assertEq(all[0].title, 'Test MS', 'milestone title correct');
|
|
195
|
+
assertEq(all[0].status, 'active', 'milestone status correct');
|
|
193
196
|
|
|
194
197
|
// getMilestoneSlices β empty
|
|
195
198
|
const noSlices = getMilestoneSlices('M001');
|
|
196
|
-
|
|
199
|
+
assertEq(noSlices.length, 0, 'getMilestoneSlices returns empty when no slices');
|
|
197
200
|
|
|
198
201
|
// Insert slices and retrieve
|
|
199
202
|
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Slice 1', status: 'complete' });
|
|
@@ -201,24 +204,26 @@ test('ββ markdown-renderer: DB accessor basics ββ', () => {
|
|
|
201
204
|
insertSlice({ id: 'S01', milestoneId: 'M002', title: 'M2 Slice', status: 'pending' });
|
|
202
205
|
|
|
203
206
|
const m1Slices = getMilestoneSlices('M001');
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
assertEq(m1Slices.length, 2, 'M001 has 2 slices');
|
|
208
|
+
assertEq(m1Slices[0].id, 'S01', 'first slice is S01');
|
|
209
|
+
assertEq(m1Slices[0].status, 'complete', 'S01 status is complete');
|
|
210
|
+
assertEq(m1Slices[1].id, 'S02', 'second slice is S02');
|
|
211
|
+
assertEq(m1Slices[1].status, 'pending', 'S02 status is pending');
|
|
209
212
|
|
|
210
213
|
const m2Slices = getMilestoneSlices('M002');
|
|
211
|
-
|
|
214
|
+
assertEq(m2Slices.length, 1, 'M002 has 1 slice');
|
|
212
215
|
|
|
213
216
|
closeDatabase();
|
|
214
|
-
}
|
|
217
|
+
}
|
|
215
218
|
|
|
216
|
-
|
|
219
|
+
console.log('\nββ markdown-renderer: getArtifact accessor ββ');
|
|
220
|
+
|
|
221
|
+
{
|
|
217
222
|
openDatabase(':memory:');
|
|
218
223
|
|
|
219
224
|
// Not found
|
|
220
225
|
const missing = getArtifact('nonexistent/path');
|
|
221
|
-
|
|
226
|
+
assertEq(missing, null, 'getArtifact returns null for missing path');
|
|
222
227
|
|
|
223
228
|
// Insert and retrieve
|
|
224
229
|
insertArtifact({
|
|
@@ -231,19 +236,21 @@ test('ββ markdown-renderer: getArtifact accessor ββ', () => {
|
|
|
231
236
|
});
|
|
232
237
|
|
|
233
238
|
const found = getArtifact('milestones/M001/M001-ROADMAP.md');
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
239
|
+
assertTrue(found !== null, 'getArtifact returns non-null for existing path');
|
|
240
|
+
assertEq(found!.artifact_type, 'ROADMAP', 'artifact type correct');
|
|
241
|
+
assertEq(found!.milestone_id, 'M001', 'milestone_id correct');
|
|
242
|
+
assertEq(found!.full_content, '# Roadmap content', 'content correct');
|
|
238
243
|
|
|
239
244
|
closeDatabase();
|
|
240
|
-
}
|
|
245
|
+
}
|
|
241
246
|
|
|
242
247
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
243
248
|
// Roadmap Checkbox Round-Trip
|
|
244
249
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
245
250
|
|
|
246
|
-
|
|
251
|
+
console.log('\nββ markdown-renderer: renderRoadmapCheckboxes round-trip ββ');
|
|
252
|
+
|
|
253
|
+
{
|
|
247
254
|
const tmpDir = makeTmpDir();
|
|
248
255
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
249
256
|
openDatabase(dbPath);
|
|
@@ -268,34 +275,36 @@ test('ββ markdown-renderer: renderRoadmapCheckboxes round-trip ββ', asyn
|
|
|
268
275
|
|
|
269
276
|
// Render β should set S01 [x] and leave S02 [ ]
|
|
270
277
|
const ok = await renderRoadmapCheckboxes(tmpDir, 'M001');
|
|
271
|
-
|
|
278
|
+
assertTrue(ok, 'renderRoadmapCheckboxes returns true');
|
|
272
279
|
|
|
273
280
|
// Read rendered file and parse
|
|
274
281
|
const rendered = fs.readFileSync(roadmapPath, 'utf-8');
|
|
275
282
|
clearAllCaches();
|
|
276
283
|
const parsed = parseRoadmap(rendered);
|
|
277
284
|
|
|
278
|
-
|
|
285
|
+
assertEq(parsed.slices.length, 2, 'roadmap has 2 slices after render');
|
|
279
286
|
|
|
280
287
|
const s01 = parsed.slices.find(s => s.id === 'S01');
|
|
281
288
|
const s02 = parsed.slices.find(s => s.id === 'S02');
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
289
|
+
assertTrue(!!s01, 'S01 found in parsed roadmap');
|
|
290
|
+
assertTrue(!!s02, 'S02 found in parsed roadmap');
|
|
291
|
+
assertTrue(s01!.done, 'S01 is checked (done) after render');
|
|
292
|
+
assertTrue(!s02!.done, 'S02 is unchecked (pending) after render');
|
|
286
293
|
|
|
287
294
|
// Verify artifact stored in DB
|
|
288
295
|
const artifact = getArtifact('milestones/M001/M001-ROADMAP.md');
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
296
|
+
assertTrue(artifact !== null, 'roadmap artifact stored in DB after render');
|
|
297
|
+
assertTrue(artifact!.full_content.includes('[x] **S01:'), 'DB artifact has S01 checked');
|
|
298
|
+
assertTrue(artifact!.full_content.includes('[ ] **S02:'), 'DB artifact has S02 unchecked');
|
|
292
299
|
} finally {
|
|
293
300
|
closeDatabase();
|
|
294
301
|
cleanupDir(tmpDir);
|
|
295
302
|
}
|
|
296
|
-
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
console.log('\nββ markdown-renderer: renderRoadmapCheckboxes bidirectional ββ');
|
|
297
306
|
|
|
298
|
-
|
|
307
|
+
{
|
|
299
308
|
const tmpDir = makeTmpDir();
|
|
300
309
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
301
310
|
openDatabase(dbPath);
|
|
@@ -319,7 +328,7 @@ test('ββ markdown-renderer: renderRoadmapCheckboxes bidirectional ββ', a
|
|
|
319
328
|
clearAllCaches();
|
|
320
329
|
|
|
321
330
|
const ok = await renderRoadmapCheckboxes(tmpDir, 'M001');
|
|
322
|
-
|
|
331
|
+
assertTrue(ok, 'bidirectional render returns true');
|
|
323
332
|
|
|
324
333
|
const rendered = fs.readFileSync(roadmapPath, 'utf-8');
|
|
325
334
|
clearAllCaches();
|
|
@@ -327,19 +336,21 @@ test('ββ markdown-renderer: renderRoadmapCheckboxes bidirectional ββ', a
|
|
|
327
336
|
|
|
328
337
|
const s01 = parsed.slices.find(s => s.id === 'S01');
|
|
329
338
|
const s02 = parsed.slices.find(s => s.id === 'S02');
|
|
330
|
-
|
|
331
|
-
|
|
339
|
+
assertTrue(!s01!.done, 'S01 unchecked (DB says pending, was checked on disk)');
|
|
340
|
+
assertTrue(s02!.done, 'S02 checked (DB says complete, was unchecked on disk)');
|
|
332
341
|
} finally {
|
|
333
342
|
closeDatabase();
|
|
334
343
|
cleanupDir(tmpDir);
|
|
335
344
|
}
|
|
336
|
-
}
|
|
345
|
+
}
|
|
337
346
|
|
|
338
347
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
339
348
|
// Plan Checkbox Round-Trip
|
|
340
349
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
341
350
|
|
|
342
|
-
|
|
351
|
+
console.log('\nββ markdown-renderer: renderPlanCheckboxes round-trip ββ');
|
|
352
|
+
|
|
353
|
+
{
|
|
343
354
|
const tmpDir = makeTmpDir();
|
|
344
355
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
345
356
|
openDatabase(dbPath);
|
|
@@ -365,27 +376,29 @@ test('ββ markdown-renderer: renderPlanCheckboxes round-trip ββ', async (
|
|
|
365
376
|
clearAllCaches();
|
|
366
377
|
|
|
367
378
|
const ok = await renderPlanCheckboxes(tmpDir, 'M001', 'S01');
|
|
368
|
-
|
|
379
|
+
assertTrue(ok, 'renderPlanCheckboxes returns true');
|
|
369
380
|
|
|
370
381
|
const rendered = fs.readFileSync(planPath, 'utf-8');
|
|
371
382
|
clearAllCaches();
|
|
372
383
|
const parsed = parsePlan(rendered);
|
|
373
384
|
|
|
374
|
-
|
|
385
|
+
assertEq(parsed.tasks.length, 3, 'plan has 3 tasks after render');
|
|
375
386
|
|
|
376
387
|
const t01 = parsed.tasks.find(t => t.id === 'T01');
|
|
377
388
|
const t02 = parsed.tasks.find(t => t.id === 'T02');
|
|
378
389
|
const t03 = parsed.tasks.find(t => t.id === 'T03');
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
390
|
+
assertTrue(t01!.done, 'T01 checked (done in DB)');
|
|
391
|
+
assertTrue(t02!.done, 'T02 checked (done in DB)');
|
|
392
|
+
assertTrue(!t03!.done, 'T03 unchecked (pending in DB)');
|
|
382
393
|
} finally {
|
|
383
394
|
closeDatabase();
|
|
384
395
|
cleanupDir(tmpDir);
|
|
385
396
|
}
|
|
386
|
-
}
|
|
397
|
+
}
|
|
387
398
|
|
|
388
|
-
|
|
399
|
+
console.log('\nββ markdown-renderer: renderPlanCheckboxes bidirectional ββ');
|
|
400
|
+
|
|
401
|
+
{
|
|
389
402
|
const tmpDir = makeTmpDir();
|
|
390
403
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
391
404
|
openDatabase(dbPath);
|
|
@@ -409,7 +422,7 @@ test('ββ markdown-renderer: renderPlanCheckboxes bidirectional ββ', asyn
|
|
|
409
422
|
clearAllCaches();
|
|
410
423
|
|
|
411
424
|
const ok = await renderPlanCheckboxes(tmpDir, 'M001', 'S01');
|
|
412
|
-
|
|
425
|
+
assertTrue(ok, 'bidirectional plan render returns true');
|
|
413
426
|
|
|
414
427
|
const rendered = fs.readFileSync(planPath, 'utf-8');
|
|
415
428
|
clearAllCaches();
|
|
@@ -417,15 +430,17 @@ test('ββ markdown-renderer: renderPlanCheckboxes bidirectional ββ', asyn
|
|
|
417
430
|
|
|
418
431
|
const t01 = parsed.tasks.find(t => t.id === 'T01');
|
|
419
432
|
const t02 = parsed.tasks.find(t => t.id === 'T02');
|
|
420
|
-
|
|
421
|
-
|
|
433
|
+
assertTrue(!t01!.done, 'T01 unchecked (DB says pending, was checked)');
|
|
434
|
+
assertTrue(t02!.done, 'T02 checked (DB says done, was unchecked)');
|
|
422
435
|
} finally {
|
|
423
436
|
closeDatabase();
|
|
424
437
|
cleanupDir(tmpDir);
|
|
425
438
|
}
|
|
426
|
-
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
console.log('\nββ markdown-renderer: renderPlanFromDb creates parse-compatible slice plan + task plan files ββ');
|
|
427
442
|
|
|
428
|
-
|
|
443
|
+
{
|
|
429
444
|
const tmpDir = makeTmpDir();
|
|
430
445
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
431
446
|
openDatabase(dbPath);
|
|
@@ -483,48 +498,50 @@ test('ββ markdown-renderer: renderPlanFromDb creates parse-compatible slice
|
|
|
483
498
|
});
|
|
484
499
|
|
|
485
500
|
const rendered = await renderPlanFromDb(tmpDir, 'M001', 'S02');
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
501
|
+
assertTrue(fs.existsSync(rendered.planPath), 'slice plan written to disk');
|
|
502
|
+
assertEq(rendered.taskPlanPaths.length, 2, 'task plan paths returned for each task');
|
|
503
|
+
assertTrue(rendered.taskPlanPaths.every((p) => fs.existsSync(p)), 'all task plan files written to disk');
|
|
489
504
|
|
|
490
505
|
const planContent = fs.readFileSync(rendered.planPath, 'utf-8');
|
|
491
506
|
clearAllCaches();
|
|
492
507
|
const parsedPlan = parsePlan(planContent);
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
508
|
+
assertEq(parsedPlan.id, 'S02', 'rendered slice plan parses with correct slice id');
|
|
509
|
+
assertEq(parsedPlan.goal, 'Render slice plans from DB state.', 'rendered slice plan preserves goal');
|
|
510
|
+
assertEq(parsedPlan.demo, 'Rendered plans exist on disk.', 'rendered slice plan preserves demo');
|
|
511
|
+
assertEq(parsedPlan.mustHaves.length, 2, 'rendered slice plan exposes must-haves');
|
|
512
|
+
assertEq(parsedPlan.tasks.length, 2, 'rendered slice plan exposes all tasks');
|
|
513
|
+
assertEq(parsedPlan.tasks[0].id, 'T01', 'first task parses correctly');
|
|
514
|
+
assertTrue(parsedPlan.tasks[0].description.includes('DB-backed slice plan renderer'), 'task description preserved in slice plan');
|
|
515
|
+
assertEq(parsedPlan.tasks[0].files?.[0], 'src/resources/extensions/gsd/markdown-renderer.ts', 'files list preserved in slice plan');
|
|
516
|
+
assertEq(parsedPlan.tasks[0].verify, 'node --test markdown-renderer.test.ts', 'verify line preserved in slice plan');
|
|
502
517
|
|
|
503
518
|
const planArtifact = getArtifact('milestones/M001/slices/S02/S02-PLAN.md');
|
|
504
|
-
|
|
505
|
-
|
|
519
|
+
assertTrue(planArtifact !== null, 'slice plan artifact stored in DB');
|
|
520
|
+
assertTrue(planArtifact!.full_content.includes('## Tasks'), 'stored plan artifact contains task section');
|
|
506
521
|
|
|
507
522
|
const taskPlanPath = path.join(tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S02', 'tasks', 'T01-PLAN.md');
|
|
508
523
|
const taskPlanContent = fs.readFileSync(taskPlanPath, 'utf-8');
|
|
509
524
|
const taskPlanFile = parseTaskPlanFile(taskPlanContent);
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
525
|
+
assertEq(taskPlanFile.frontmatter.estimated_steps, 1, 'task plan frontmatter exposes estimated_steps');
|
|
526
|
+
assertEq(taskPlanFile.frontmatter.estimated_files, 1, 'task plan frontmatter exposes estimated_files');
|
|
527
|
+
assertEq(taskPlanFile.frontmatter.skills_used.length, 0, 'task plan frontmatter uses conservative empty skills list');
|
|
528
|
+
assertMatch(taskPlanContent, /^# T01: Render slice plan/m, 'task plan renders task heading');
|
|
529
|
+
assertMatch(taskPlanContent, /^## Inputs$/m, 'task plan renders Inputs section');
|
|
530
|
+
assertMatch(taskPlanContent, /^## Expected Output$/m, 'task plan renders Expected Output section');
|
|
531
|
+
assertMatch(taskPlanContent, /^## Verification$/m, 'task plan renders Verification section');
|
|
517
532
|
|
|
518
533
|
const taskArtifact = getArtifact('milestones/M001/slices/S02/tasks/T01-PLAN.md');
|
|
519
|
-
|
|
520
|
-
|
|
534
|
+
assertTrue(taskArtifact !== null, 'task plan artifact stored in DB');
|
|
535
|
+
assertTrue(taskArtifact!.full_content.includes('skills_used: []'), 'stored task plan artifact preserves conservative skills_used');
|
|
521
536
|
} finally {
|
|
522
537
|
closeDatabase();
|
|
523
538
|
cleanupDir(tmpDir);
|
|
524
539
|
}
|
|
525
|
-
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
console.log('\nββ markdown-renderer: renderTaskPlanFromDb throws for missing task ββ');
|
|
526
543
|
|
|
527
|
-
|
|
544
|
+
{
|
|
528
545
|
const tmpDir = makeTmpDir();
|
|
529
546
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
530
547
|
openDatabase(dbPath);
|
|
@@ -540,21 +557,23 @@ test('ββ markdown-renderer: renderTaskPlanFromDb throws for missing task β
|
|
|
540
557
|
await renderTaskPlanFromDb(tmpDir, 'M001', 'S02', 'T99');
|
|
541
558
|
} catch (error) {
|
|
542
559
|
threw = true;
|
|
543
|
-
|
|
560
|
+
assertMatch(String((error as Error).message), /task M001\/S02\/T99 not found/, 'renderTaskPlanFromDb should fail clearly when task row is missing');
|
|
544
561
|
}
|
|
545
|
-
|
|
562
|
+
assertTrue(threw, 'renderTaskPlanFromDb throws when the task row is missing');
|
|
546
563
|
} finally {
|
|
547
564
|
closeDatabase();
|
|
548
565
|
cleanupDir(tmpDir);
|
|
549
566
|
}
|
|
550
|
-
}
|
|
567
|
+
}
|
|
551
568
|
|
|
552
569
|
|
|
553
570
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
554
571
|
// Task Summary Rendering
|
|
555
572
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
556
573
|
|
|
557
|
-
|
|
574
|
+
console.log('\nββ markdown-renderer: renderTaskSummary round-trip ββ');
|
|
575
|
+
|
|
576
|
+
{
|
|
558
577
|
const tmpDir = makeTmpDir();
|
|
559
578
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
560
579
|
openDatabase(dbPath);
|
|
@@ -577,31 +596,33 @@ test('ββ markdown-renderer: renderTaskSummary round-trip ββ', async () =
|
|
|
577
596
|
});
|
|
578
597
|
|
|
579
598
|
const ok = await renderTaskSummary(tmpDir, 'M001', 'S01', 'T01');
|
|
580
|
-
|
|
599
|
+
assertTrue(ok, 'renderTaskSummary returns true');
|
|
581
600
|
|
|
582
601
|
// Verify file exists on disk
|
|
583
602
|
const summaryPath = path.join(
|
|
584
603
|
tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks', 'T01-SUMMARY.md',
|
|
585
604
|
);
|
|
586
|
-
|
|
605
|
+
assertTrue(fs.existsSync(summaryPath), 'T01-SUMMARY.md written to disk');
|
|
587
606
|
|
|
588
607
|
// Parse and verify
|
|
589
608
|
const rendered = fs.readFileSync(summaryPath, 'utf-8');
|
|
590
609
|
clearAllCaches();
|
|
591
610
|
const parsed = parseSummary(rendered);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
611
|
+
assertEq(parsed.frontmatter.id, 'T01', 'parsed summary has correct id');
|
|
612
|
+
assertEq(parsed.frontmatter.parent, 'S01', 'parsed summary has correct parent');
|
|
613
|
+
assertEq(parsed.frontmatter.milestone, 'M001', 'parsed summary has correct milestone');
|
|
614
|
+
assertEq(parsed.frontmatter.duration, '45m', 'parsed summary has correct duration');
|
|
615
|
+
assertTrue(parsed.title.includes('T01'), 'parsed summary title contains task ID');
|
|
616
|
+
assertTrue(parsed.whatHappened.includes('Built the test feature'), 'whatHappened content preserved');
|
|
598
617
|
} finally {
|
|
599
618
|
closeDatabase();
|
|
600
619
|
cleanupDir(tmpDir);
|
|
601
620
|
}
|
|
602
|
-
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
console.log('\nββ markdown-renderer: renderTaskSummary skips empty ββ');
|
|
603
624
|
|
|
604
|
-
|
|
625
|
+
{
|
|
605
626
|
const tmpDir = makeTmpDir();
|
|
606
627
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
607
628
|
openDatabase(dbPath);
|
|
@@ -622,18 +643,20 @@ test('ββ markdown-renderer: renderTaskSummary skips empty ββ', async ()
|
|
|
622
643
|
});
|
|
623
644
|
|
|
624
645
|
const ok = await renderTaskSummary(tmpDir, 'M001', 'S01', 'T01');
|
|
625
|
-
|
|
646
|
+
assertTrue(!ok, 'renderTaskSummary returns false for empty summary');
|
|
626
647
|
} finally {
|
|
627
648
|
closeDatabase();
|
|
628
649
|
cleanupDir(tmpDir);
|
|
629
650
|
}
|
|
630
|
-
}
|
|
651
|
+
}
|
|
631
652
|
|
|
632
653
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
633
654
|
// Slice Summary Rendering
|
|
634
655
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
635
656
|
|
|
636
|
-
|
|
657
|
+
console.log('\nββ markdown-renderer: renderSliceSummary round-trip ββ');
|
|
658
|
+
|
|
659
|
+
{
|
|
637
660
|
const tmpDir = makeTmpDir();
|
|
638
661
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
639
662
|
openDatabase(dbPath);
|
|
@@ -657,36 +680,38 @@ test('ββ markdown-renderer: renderSliceSummary round-trip ββ', async ()
|
|
|
657
680
|
});
|
|
658
681
|
|
|
659
682
|
const ok = await renderSliceSummary(tmpDir, 'M001', 'S01');
|
|
660
|
-
|
|
683
|
+
assertTrue(ok, 'renderSliceSummary returns true');
|
|
661
684
|
|
|
662
685
|
// Verify SUMMARY file
|
|
663
686
|
const summaryPath = path.join(
|
|
664
687
|
tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'S01-SUMMARY.md',
|
|
665
688
|
);
|
|
666
|
-
|
|
689
|
+
assertTrue(fs.existsSync(summaryPath), 'S01-SUMMARY.md written to disk');
|
|
667
690
|
|
|
668
691
|
const summaryContent = fs.readFileSync(summaryPath, 'utf-8');
|
|
669
|
-
|
|
692
|
+
assertTrue(summaryContent.includes('Test Slice Summary'), 'summary content correct');
|
|
670
693
|
|
|
671
694
|
// Verify UAT file
|
|
672
695
|
const uatPath = path.join(
|
|
673
696
|
tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'S01-UAT.md',
|
|
674
697
|
);
|
|
675
|
-
|
|
698
|
+
assertTrue(fs.existsSync(uatPath), 'S01-UAT.md written to disk');
|
|
676
699
|
|
|
677
700
|
const uatContent = fs.readFileSync(uatPath, 'utf-8');
|
|
678
|
-
|
|
701
|
+
assertTrue(uatContent.includes('artifact-driven'), 'UAT content correct');
|
|
679
702
|
} finally {
|
|
680
703
|
closeDatabase();
|
|
681
704
|
cleanupDir(tmpDir);
|
|
682
705
|
}
|
|
683
|
-
}
|
|
706
|
+
}
|
|
684
707
|
|
|
685
708
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
686
709
|
// renderAllFromDb
|
|
687
710
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
688
711
|
|
|
689
|
-
|
|
712
|
+
console.log('\nββ markdown-renderer: renderAllFromDb produces all files ββ');
|
|
713
|
+
|
|
714
|
+
{
|
|
690
715
|
const tmpDir = makeTmpDir();
|
|
691
716
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
692
717
|
openDatabase(dbPath);
|
|
@@ -754,8 +779,8 @@ test('ββ markdown-renderer: renderAllFromDb produces all files ββ', asyn
|
|
|
754
779
|
|
|
755
780
|
const result = await renderAllFromDb(tmpDir);
|
|
756
781
|
|
|
757
|
-
|
|
758
|
-
|
|
782
|
+
assertTrue(result.rendered > 0, 'renderAllFromDb rendered some files');
|
|
783
|
+
assertEq(result.errors.length, 0, 'renderAllFromDb had no errors');
|
|
759
784
|
|
|
760
785
|
// Verify M001 roadmap has S01 checked
|
|
761
786
|
const m1Roadmap = fs.readFileSync(
|
|
@@ -764,7 +789,7 @@ test('ββ markdown-renderer: renderAllFromDb produces all files ββ', asyn
|
|
|
764
789
|
clearAllCaches();
|
|
765
790
|
const parsed1 = parseRoadmap(m1Roadmap);
|
|
766
791
|
const s01 = parsed1.slices.find(s => s.id === 'S01');
|
|
767
|
-
|
|
792
|
+
assertTrue(s01!.done, 'M001 S01 checked after renderAll');
|
|
768
793
|
|
|
769
794
|
// Verify M001/S01 plan has T01 checked
|
|
770
795
|
const m1s1Plan = fs.readFileSync(
|
|
@@ -772,24 +797,26 @@ test('ββ markdown-renderer: renderAllFromDb produces all files ββ', asyn
|
|
|
772
797
|
);
|
|
773
798
|
clearAllCaches();
|
|
774
799
|
const parsedPlan = parsePlan(m1s1Plan);
|
|
775
|
-
|
|
800
|
+
assertTrue(parsedPlan.tasks[0].done, 'M001/S01 T01 checked after renderAll');
|
|
776
801
|
|
|
777
802
|
// Verify task summary written
|
|
778
803
|
const taskSummaryPath = path.join(
|
|
779
804
|
tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks', 'T01-SUMMARY.md',
|
|
780
805
|
);
|
|
781
|
-
|
|
806
|
+
assertTrue(fs.existsSync(taskSummaryPath), 'T01 summary written by renderAll');
|
|
782
807
|
} finally {
|
|
783
808
|
closeDatabase();
|
|
784
809
|
cleanupDir(tmpDir);
|
|
785
810
|
}
|
|
786
|
-
}
|
|
811
|
+
}
|
|
787
812
|
|
|
788
813
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
789
814
|
// Graceful Degradation (Disk Fallback)
|
|
790
815
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
791
816
|
|
|
792
|
-
|
|
817
|
+
console.log('\nββ markdown-renderer: graceful fallback reads from disk when artifact not in DB ββ');
|
|
818
|
+
|
|
819
|
+
{
|
|
793
820
|
const tmpDir = makeTmpDir();
|
|
794
821
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
795
822
|
openDatabase(dbPath);
|
|
@@ -811,27 +838,29 @@ test('ββ markdown-renderer: graceful fallback reads from disk when artifact
|
|
|
811
838
|
|
|
812
839
|
// Verify no artifact in DB
|
|
813
840
|
const before = getArtifact('milestones/M001/M001-ROADMAP.md');
|
|
814
|
-
|
|
841
|
+
assertEq(before, null, 'artifact not in DB before render');
|
|
815
842
|
|
|
816
843
|
// Render β should read from disk, store in DB
|
|
817
844
|
const ok = await renderRoadmapCheckboxes(tmpDir, 'M001');
|
|
818
|
-
|
|
845
|
+
assertTrue(ok, 'render succeeds with disk fallback');
|
|
819
846
|
|
|
820
847
|
// Verify artifact now in DB (stored after reading from disk)
|
|
821
848
|
const after = getArtifact('milestones/M001/M001-ROADMAP.md');
|
|
822
|
-
|
|
823
|
-
|
|
849
|
+
assertTrue(after !== null, 'artifact stored in DB after disk fallback render');
|
|
850
|
+
assertTrue(after!.full_content.includes('[x] **S01:'), 'DB artifact reflects rendered state');
|
|
824
851
|
} finally {
|
|
825
852
|
closeDatabase();
|
|
826
853
|
cleanupDir(tmpDir);
|
|
827
854
|
}
|
|
828
|
-
}
|
|
855
|
+
}
|
|
829
856
|
|
|
830
857
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
831
858
|
// stderr warnings (graceful degradation diagnostics)
|
|
832
859
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
833
860
|
|
|
834
|
-
|
|
861
|
+
console.log('\nββ markdown-renderer: stderr warning on missing content ββ');
|
|
862
|
+
|
|
863
|
+
{
|
|
835
864
|
openDatabase(':memory:');
|
|
836
865
|
|
|
837
866
|
// No milestone/slices in DB, no files on disk β should return false and emit stderr
|
|
@@ -839,16 +868,18 @@ test('ββ markdown-renderer: stderr warning on missing content ββ', async
|
|
|
839
868
|
// No slices inserted β should warn about no slices
|
|
840
869
|
|
|
841
870
|
const ok = await renderRoadmapCheckboxes('/nonexistent/path', 'M001');
|
|
842
|
-
|
|
871
|
+
assertTrue(!ok, 'returns false when no slices in DB');
|
|
843
872
|
|
|
844
873
|
closeDatabase();
|
|
845
|
-
}
|
|
874
|
+
}
|
|
846
875
|
|
|
847
876
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
848
877
|
// Stale Detection β Plan Checkbox Mismatch
|
|
849
878
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
850
879
|
|
|
851
|
-
|
|
880
|
+
console.log('\nββ markdown-renderer: detectStaleRenders finds plan checkbox mismatch ββ');
|
|
881
|
+
|
|
882
|
+
{
|
|
852
883
|
const tmpDir = makeTmpDir();
|
|
853
884
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
854
885
|
openDatabase(dbPath);
|
|
@@ -879,25 +910,27 @@ test('ββ markdown-renderer: detectStaleRenders finds plan checkbox mismatch
|
|
|
879
910
|
// The stale detection should find T02 as stale.
|
|
880
911
|
const stale = detectStaleRenders(tmpDir);
|
|
881
912
|
|
|
882
|
-
|
|
913
|
+
assertTrue(stale.length > 0, 'detectStaleRenders should find stale entries');
|
|
883
914
|
const t02Stale = stale.find(s => s.reason.includes('T02'));
|
|
884
|
-
|
|
885
|
-
|
|
915
|
+
assertTrue(!!t02Stale, 'should detect T02 as stale (done in DB, unchecked in plan)');
|
|
916
|
+
assertTrue(t02Stale!.reason.includes('done in DB but unchecked'), 'reason should explain the mismatch');
|
|
886
917
|
|
|
887
918
|
// T01 should NOT be stale β it's checked and done
|
|
888
919
|
const t01Stale = stale.find(s => s.reason.includes('T01'));
|
|
889
|
-
|
|
920
|
+
assertEq(t01Stale, undefined, 'T01 should not be stale (done and checked)');
|
|
890
921
|
} finally {
|
|
891
922
|
closeDatabase();
|
|
892
923
|
cleanupDir(tmpDir);
|
|
893
924
|
}
|
|
894
|
-
}
|
|
925
|
+
}
|
|
895
926
|
|
|
896
927
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
897
928
|
// Stale Repair β Plan Checkbox
|
|
898
929
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
899
930
|
|
|
900
|
-
|
|
931
|
+
console.log('\nββ markdown-renderer: repairStaleRenders fixes plan and second detect returns empty ββ');
|
|
932
|
+
|
|
933
|
+
{
|
|
901
934
|
const tmpDir = makeTmpDir();
|
|
902
935
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
903
936
|
openDatabase(dbPath);
|
|
@@ -923,32 +956,34 @@ test('ββ markdown-renderer: repairStaleRenders fixes plan and second detect
|
|
|
923
956
|
|
|
924
957
|
// Verify stale before repair
|
|
925
958
|
const staleBefore = detectStaleRenders(tmpDir);
|
|
926
|
-
|
|
959
|
+
assertTrue(staleBefore.length > 0, 'should have stale entries before repair');
|
|
927
960
|
|
|
928
961
|
// Repair
|
|
929
962
|
const repaired = await repairStaleRenders(tmpDir);
|
|
930
|
-
|
|
963
|
+
assertTrue(repaired > 0, 'repairStaleRenders should repair at least 1 file');
|
|
931
964
|
|
|
932
965
|
// After repair, detect again β should be empty
|
|
933
966
|
clearAllCaches();
|
|
934
967
|
const staleAfter = detectStaleRenders(tmpDir);
|
|
935
|
-
|
|
968
|
+
assertEq(staleAfter.length, 0, 'detectStaleRenders should return empty after repair');
|
|
936
969
|
|
|
937
970
|
// Verify the plan file was actually updated
|
|
938
971
|
const repairedContent = fs.readFileSync(planPath, 'utf-8');
|
|
939
|
-
|
|
940
|
-
|
|
972
|
+
assertTrue(repairedContent.includes('[x] **T01:'), 'T01 should be checked after repair');
|
|
973
|
+
assertTrue(repairedContent.includes('[x] **T02:'), 'T02 should be checked after repair');
|
|
941
974
|
} finally {
|
|
942
975
|
closeDatabase();
|
|
943
976
|
cleanupDir(tmpDir);
|
|
944
977
|
}
|
|
945
|
-
}
|
|
978
|
+
}
|
|
946
979
|
|
|
947
980
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
948
981
|
// Stale Detection β Roadmap Checkbox Mismatch
|
|
949
982
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
950
983
|
|
|
951
|
-
|
|
984
|
+
console.log('\nββ markdown-renderer: detectStaleRenders finds roadmap checkbox mismatch ββ');
|
|
985
|
+
|
|
986
|
+
{
|
|
952
987
|
const tmpDir = makeTmpDir();
|
|
953
988
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
954
989
|
openDatabase(dbPath);
|
|
@@ -972,21 +1007,23 @@ test('ββ markdown-renderer: detectStaleRenders finds roadmap checkbox mismat
|
|
|
972
1007
|
|
|
973
1008
|
const stale = detectStaleRenders(tmpDir);
|
|
974
1009
|
const s01Stale = stale.find(s => s.reason.includes('S01'));
|
|
975
|
-
|
|
1010
|
+
assertTrue(!!s01Stale, 'should detect S01 as stale (complete in DB, unchecked in roadmap)');
|
|
976
1011
|
|
|
977
1012
|
const s02Stale = stale.find(s => s.reason.includes('S02'));
|
|
978
|
-
|
|
1013
|
+
assertEq(s02Stale, undefined, 'S02 should not be stale (pending and unchecked β matches)');
|
|
979
1014
|
} finally {
|
|
980
1015
|
closeDatabase();
|
|
981
1016
|
cleanupDir(tmpDir);
|
|
982
1017
|
}
|
|
983
|
-
}
|
|
1018
|
+
}
|
|
984
1019
|
|
|
985
1020
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
986
1021
|
// Stale Detection β Missing Task Summary
|
|
987
1022
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
988
1023
|
|
|
989
|
-
|
|
1024
|
+
console.log('\nββ markdown-renderer: detectStaleRenders finds missing task summary ββ');
|
|
1025
|
+
|
|
1026
|
+
{
|
|
990
1027
|
const tmpDir = makeTmpDir();
|
|
991
1028
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
992
1029
|
openDatabase(dbPath);
|
|
@@ -1021,19 +1058,21 @@ test('ββ markdown-renderer: detectStaleRenders finds missing task summary
|
|
|
1021
1058
|
|
|
1022
1059
|
const stale = detectStaleRenders(tmpDir);
|
|
1023
1060
|
const summaryStale = stale.find(s => s.reason.includes('SUMMARY.md missing'));
|
|
1024
|
-
|
|
1025
|
-
|
|
1061
|
+
assertTrue(!!summaryStale, 'should detect missing T01-SUMMARY.md');
|
|
1062
|
+
assertTrue(summaryStale!.reason.includes('T01'), 'reason should mention T01');
|
|
1026
1063
|
} finally {
|
|
1027
1064
|
closeDatabase();
|
|
1028
1065
|
cleanupDir(tmpDir);
|
|
1029
1066
|
}
|
|
1030
|
-
}
|
|
1067
|
+
}
|
|
1031
1068
|
|
|
1032
1069
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1033
1070
|
// Stale Repair β Missing Task Summary
|
|
1034
1071
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1035
1072
|
|
|
1036
|
-
|
|
1073
|
+
console.log('\nββ markdown-renderer: repairStaleRenders writes missing task summary ββ');
|
|
1074
|
+
|
|
1075
|
+
{
|
|
1037
1076
|
const tmpDir = makeTmpDir();
|
|
1038
1077
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
1039
1078
|
openDatabase(dbPath);
|
|
@@ -1065,30 +1104,32 @@ test('ββ markdown-renderer: repairStaleRenders writes missing task summary
|
|
|
1065
1104
|
|
|
1066
1105
|
// Repair
|
|
1067
1106
|
const repaired = await repairStaleRenders(tmpDir);
|
|
1068
|
-
|
|
1107
|
+
assertTrue(repaired > 0, 'should repair missing summary');
|
|
1069
1108
|
|
|
1070
1109
|
// Verify file written
|
|
1071
1110
|
const summaryPath = path.join(
|
|
1072
1111
|
tmpDir, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks', 'T01-SUMMARY.md',
|
|
1073
1112
|
);
|
|
1074
|
-
|
|
1113
|
+
assertTrue(fs.existsSync(summaryPath), 'T01-SUMMARY.md should exist after repair');
|
|
1075
1114
|
|
|
1076
1115
|
// Second detect should be empty
|
|
1077
1116
|
clearAllCaches();
|
|
1078
1117
|
const staleAfter = detectStaleRenders(tmpDir);
|
|
1079
1118
|
const summaryStale = staleAfter.find(s => s.reason.includes('SUMMARY.md missing') && s.reason.includes('T01'));
|
|
1080
|
-
|
|
1119
|
+
assertEq(summaryStale, undefined, 'missing summary should be fixed after repair');
|
|
1081
1120
|
} finally {
|
|
1082
1121
|
closeDatabase();
|
|
1083
1122
|
cleanupDir(tmpDir);
|
|
1084
1123
|
}
|
|
1085
|
-
}
|
|
1124
|
+
}
|
|
1086
1125
|
|
|
1087
1126
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1088
1127
|
// Stale Repair β Idempotency
|
|
1089
1128
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1090
1129
|
|
|
1091
|
-
|
|
1130
|
+
console.log('\nββ markdown-renderer: repairStaleRenders idempotency β fully synced returns 0 ββ');
|
|
1131
|
+
|
|
1132
|
+
{
|
|
1092
1133
|
const tmpDir = makeTmpDir();
|
|
1093
1134
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
1094
1135
|
openDatabase(dbPath);
|
|
@@ -1111,18 +1152,20 @@ test('ββ markdown-renderer: repairStaleRenders idempotency β fully synced
|
|
|
1111
1152
|
|
|
1112
1153
|
// No stale entries when everything is in sync (no summary to check since no fullSummaryMd)
|
|
1113
1154
|
const repaired = await repairStaleRenders(tmpDir);
|
|
1114
|
-
|
|
1155
|
+
assertEq(repaired, 0, 'repairStaleRenders should return 0 on fully synced project');
|
|
1115
1156
|
} finally {
|
|
1116
1157
|
closeDatabase();
|
|
1117
1158
|
cleanupDir(tmpDir);
|
|
1118
1159
|
}
|
|
1119
|
-
}
|
|
1160
|
+
}
|
|
1120
1161
|
|
|
1121
1162
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1122
1163
|
// Stale Detection β Missing Slice Summary + UAT
|
|
1123
1164
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1124
1165
|
|
|
1125
|
-
|
|
1166
|
+
console.log('\nββ markdown-renderer: detectStaleRenders finds missing slice summary and UAT ββ');
|
|
1167
|
+
|
|
1168
|
+
{
|
|
1126
1169
|
const tmpDir = makeTmpDir();
|
|
1127
1170
|
const dbPath = path.join(tmpDir, '.gsd', 'gsd.db');
|
|
1128
1171
|
openDatabase(dbPath);
|
|
@@ -1149,13 +1192,14 @@ test('ββ markdown-renderer: detectStaleRenders finds missing slice summary a
|
|
|
1149
1192
|
const summaryStale = stale.find(s => s.reason.includes('SUMMARY.md missing') && s.reason.includes('S01'));
|
|
1150
1193
|
const uatStale = stale.find(s => s.reason.includes('UAT.md missing') && s.reason.includes('S01'));
|
|
1151
1194
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1195
|
+
assertTrue(!!summaryStale, 'should detect missing S01-SUMMARY.md');
|
|
1196
|
+
assertTrue(!!uatStale, 'should detect missing S01-UAT.md');
|
|
1154
1197
|
} finally {
|
|
1155
1198
|
closeDatabase();
|
|
1156
1199
|
cleanupDir(tmpDir);
|
|
1157
1200
|
}
|
|
1158
|
-
}
|
|
1201
|
+
}
|
|
1159
1202
|
|
|
1160
1203
|
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
1161
1204
|
|
|
1205
|
+
report();
|