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 fs from 'node:fs';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
import * as os from 'node:os';
|
|
@@ -16,8 +17,8 @@ import {
|
|
|
16
17
|
parseRequirementsSections,
|
|
17
18
|
migrateFromMarkdown,
|
|
18
19
|
} from '../md-importer.ts';
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
21
22
|
|
|
22
23
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
24
|
// Fixtures
|
|
@@ -134,37 +135,43 @@ function cleanupDir(dir: string): void {
|
|
|
134
135
|
// md-importer: parseDecisionsTable
|
|
135
136
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
console.log('\n=== md-importer: parseDecisionsTable ===');
|
|
139
|
+
|
|
140
|
+
{
|
|
138
141
|
const decisions = parseDecisionsTable(DECISIONS_MD);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
142
|
+
assertEq(decisions.length, 4, 'should parse 4 decisions');
|
|
143
|
+
assertEq(decisions[0].id, 'D001', 'first decision should be D001');
|
|
144
|
+
assertEq(decisions[0].decision, 'SQLite library', 'D001 decision text');
|
|
145
|
+
assertEq(decisions[0].choice, 'better-sqlite3', 'D001 choice');
|
|
146
|
+
assertEq(decisions[0].scope, 'library', 'D001 scope');
|
|
147
|
+
assertEq(decisions[0].revisable, 'No', 'D001 revisable');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
console.log('=== md-importer: supersession detection ===');
|
|
151
|
+
|
|
152
|
+
{
|
|
148
153
|
const decisions = parseDecisionsTable(DECISIONS_MD);
|
|
149
154
|
|
|
150
155
|
// D010 amends D001 → D001.superseded_by = D010
|
|
151
156
|
const d001 = decisions.find(d => d.id === 'D001');
|
|
152
|
-
|
|
157
|
+
assertEq(d001?.superseded_by, 'D010', 'D001 should be superseded by D010');
|
|
153
158
|
|
|
154
159
|
// D020 amends D010 → D010.superseded_by = D020
|
|
155
160
|
const d010 = decisions.find(d => d.id === 'D010');
|
|
156
|
-
|
|
161
|
+
assertEq(d010?.superseded_by, 'D020', 'D010 should be superseded by D020');
|
|
157
162
|
|
|
158
163
|
// D002 is not amended
|
|
159
164
|
const d002 = decisions.find(d => d.id === 'D002');
|
|
160
|
-
|
|
165
|
+
assertEq(d002?.superseded_by, null, 'D002 should not be superseded');
|
|
161
166
|
|
|
162
167
|
// D020 is the latest in chain, not superseded
|
|
163
168
|
const d020 = decisions.find(d => d.id === 'D020');
|
|
164
|
-
|
|
165
|
-
}
|
|
169
|
+
assertEq(d020?.superseded_by, null, 'D020 should not be superseded');
|
|
170
|
+
}
|
|
166
171
|
|
|
167
|
-
|
|
172
|
+
console.log('=== md-importer: malformed/empty rows skipped ===');
|
|
173
|
+
|
|
174
|
+
{
|
|
168
175
|
const malformedInput = `# Decisions
|
|
169
176
|
|
|
170
177
|
| # | When | Scope | Decision | Choice | Rationale | Revisable? |
|
|
@@ -175,20 +182,24 @@ test('md-importer: malformed/empty rows skipped', () => {
|
|
|
175
182
|
| D003 | M001 | arch | Config | JSON | Simple | Yes |
|
|
176
183
|
`;
|
|
177
184
|
const decisions = parseDecisionsTable(malformedInput);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
185
|
+
assertEq(decisions.length, 2, 'should skip rows without D-prefix IDs');
|
|
186
|
+
assertEq(decisions[0].id, 'D001', 'first valid row');
|
|
187
|
+
assertEq(decisions[1].id, 'D003', 'second valid row (skipping malformed)');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log('=== md-importer: made_by backward compatibility (old 7-column format) ===');
|
|
182
191
|
|
|
183
|
-
|
|
192
|
+
{
|
|
184
193
|
const decisions = parseDecisionsTable(DECISIONS_MD);
|
|
185
194
|
// Old format has no Made By column — should default to 'agent'
|
|
186
195
|
for (const d of decisions) {
|
|
187
|
-
|
|
196
|
+
assertEq(d.made_by, 'agent', `${d.id} made_by defaults to agent for legacy format`);
|
|
188
197
|
}
|
|
189
|
-
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log('=== md-importer: made_by column parsing (new 8-column format) ===');
|
|
190
201
|
|
|
191
|
-
|
|
202
|
+
{
|
|
192
203
|
const newFormatMd = `# Decisions Register
|
|
193
204
|
|
|
194
205
|
| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |
|
|
@@ -199,58 +210,62 @@ test('md-importer: made_by column parsing (new 8-column format)', () => {
|
|
|
199
210
|
| D004 | M002 | impl | Cache strategy | LRU | Predictable | No | bogus |
|
|
200
211
|
`;
|
|
201
212
|
const decisions = parseDecisionsTable(newFormatMd);
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
213
|
+
assertEq(decisions.length, 4, 'should parse 4 decisions with new format');
|
|
214
|
+
assertEq(decisions[0].made_by, 'human', 'D001 made_by = human');
|
|
215
|
+
assertEq(decisions[1].made_by, 'agent', 'D002 made_by = agent');
|
|
216
|
+
assertEq(decisions[2].made_by, 'collaborative', 'D003 made_by = collaborative');
|
|
217
|
+
assertEq(decisions[3].made_by, 'agent', 'D004 invalid made_by defaults to agent');
|
|
218
|
+
}
|
|
208
219
|
|
|
209
220
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
210
221
|
// md-importer: parseRequirementsSections
|
|
211
222
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
212
223
|
|
|
213
|
-
|
|
224
|
+
console.log('=== md-importer: parseRequirementsSections ===');
|
|
225
|
+
|
|
226
|
+
{
|
|
214
227
|
const reqs = parseRequirementsSections(REQUIREMENTS_MD);
|
|
215
|
-
|
|
228
|
+
assertEq(reqs.length, 5, 'should parse 5 unique requirements');
|
|
216
229
|
|
|
217
230
|
const r001 = reqs.find(r => r.id === 'R001');
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
231
|
+
assertTrue(!!r001, 'R001 should exist');
|
|
232
|
+
assertEq(r001?.class, 'core-capability', 'R001 class');
|
|
233
|
+
assertEq(r001?.status, 'active', 'R001 status');
|
|
234
|
+
assertEq(r001?.description, 'A SQLite database with typed wrappers', 'R001 description');
|
|
235
|
+
assertEq(r001?.why, 'Foundation for storage', 'R001 why');
|
|
236
|
+
assertEq(r001?.source, 'user', 'R001 source');
|
|
237
|
+
assertEq(r001?.primary_owner, 'M001/S01', 'R001 primary_owner');
|
|
238
|
+
assertEq(r001?.supporting_slices, 'none', 'R001 supporting_slices');
|
|
239
|
+
assertEq(r001?.validation, 'unmapped', 'R001 validation');
|
|
240
|
+
assertEq(r001?.notes, 'WAL mode enabled', 'R001 notes');
|
|
241
|
+
assertTrue(r001?.full_content?.includes('### R001') ?? false, 'R001 full_content should have heading');
|
|
229
242
|
|
|
230
243
|
// Validated section — R017 (abbreviated format with "Validated by" / "Proof" bullets)
|
|
231
244
|
const r017 = reqs.find(r => r.id === 'R017');
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
245
|
+
assertTrue(!!r017, 'R017 should exist');
|
|
246
|
+
assertEq(r017?.status, 'validated', 'R017 status from validated section');
|
|
247
|
+
assertEq(r017?.validation, 'M001/S01', 'R017 validation (from "Validated by" bullet)');
|
|
248
|
+
assertEq(r017?.notes, '50 decisions queried in 0.62ms', 'R017 notes (from "Proof" bullet)');
|
|
236
249
|
|
|
237
250
|
// Deferred requirement
|
|
238
251
|
const r030 = reqs.find(r => r.id === 'R030');
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
252
|
+
assertEq(r030?.status, 'deferred', 'R030 status should be deferred');
|
|
253
|
+
assertEq(r030?.class, 'differentiator', 'R030 class');
|
|
254
|
+
assertEq(r030?.description, 'Rust crate for embeddings', 'R030 description');
|
|
242
255
|
|
|
243
256
|
// Out of scope
|
|
244
257
|
const r040 = reqs.find(r => r.id === 'R040');
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
258
|
+
assertEq(r040?.status, 'out-of-scope', 'R040 status should be out-of-scope');
|
|
259
|
+
assertEq(r040?.class, 'anti-feature', 'R040 class');
|
|
260
|
+
}
|
|
248
261
|
|
|
249
262
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
250
263
|
// md-importer: migrateFromMarkdown orchestrator
|
|
251
264
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
252
265
|
|
|
253
|
-
|
|
266
|
+
console.log('=== md-importer: migrateFromMarkdown orchestrator ===');
|
|
267
|
+
|
|
268
|
+
{
|
|
254
269
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-import-test-'));
|
|
255
270
|
createFixtureTree(tmpDir);
|
|
256
271
|
|
|
@@ -258,51 +273,53 @@ test('md-importer: migrateFromMarkdown orchestrator', () => {
|
|
|
258
273
|
openDatabase(':memory:');
|
|
259
274
|
const result = migrateFromMarkdown(tmpDir);
|
|
260
275
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
276
|
+
assertEq(result.decisions, 4, 'should import 4 decisions');
|
|
277
|
+
assertEq(result.requirements, 5, 'should import 5 requirements');
|
|
278
|
+
assertTrue(result.artifacts > 0, 'should import some artifacts');
|
|
264
279
|
|
|
265
280
|
// Verify decisions queryable
|
|
266
281
|
const d001 = getDecisionById('D001');
|
|
267
|
-
|
|
268
|
-
|
|
282
|
+
assertTrue(!!d001, 'D001 should be queryable');
|
|
283
|
+
assertEq(d001?.superseded_by, 'D010', 'D001 superseded_by should be D010');
|
|
269
284
|
|
|
270
285
|
// Verify requirements queryable
|
|
271
286
|
const r001 = getRequirementById('R001');
|
|
272
|
-
|
|
273
|
-
|
|
287
|
+
assertTrue(!!r001, 'R001 should be queryable');
|
|
288
|
+
assertEq(r001?.status, 'active', 'R001 status from DB');
|
|
274
289
|
|
|
275
290
|
// Verify active views
|
|
276
291
|
const activeD = getActiveDecisions();
|
|
277
|
-
|
|
292
|
+
assertEq(activeD.length, 2, 'should have 2 active decisions (D002, D020)');
|
|
278
293
|
|
|
279
294
|
// Verify artifacts table
|
|
280
295
|
const adapter = _getAdapter();
|
|
281
296
|
const artifacts = adapter?.prepare('SELECT count(*) as c FROM artifacts').get();
|
|
282
|
-
|
|
297
|
+
assertTrue((artifacts?.c as number) > 0, 'artifacts table should have rows');
|
|
283
298
|
|
|
284
299
|
// Verify hierarchy correctness
|
|
285
300
|
const roadmap = adapter?.prepare('SELECT * FROM artifacts WHERE artifact_type = :type').get({ ':type': 'ROADMAP' });
|
|
286
|
-
|
|
287
|
-
|
|
301
|
+
assertTrue(!!roadmap, 'ROADMAP artifact should exist');
|
|
302
|
+
assertEq(roadmap?.milestone_id, 'M001', 'ROADMAP should be in M001');
|
|
288
303
|
|
|
289
304
|
const taskPlan = adapter?.prepare('SELECT * FROM artifacts WHERE task_id = :taskId AND artifact_type = :type').get({
|
|
290
305
|
':taskId': 'T01',
|
|
291
306
|
':type': 'PLAN',
|
|
292
307
|
});
|
|
293
|
-
|
|
308
|
+
assertTrue(!!taskPlan, 'T01-PLAN artifact should exist');
|
|
294
309
|
|
|
295
310
|
closeDatabase();
|
|
296
311
|
} finally {
|
|
297
312
|
cleanupDir(tmpDir);
|
|
298
313
|
}
|
|
299
|
-
}
|
|
314
|
+
}
|
|
300
315
|
|
|
301
316
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
302
317
|
// md-importer: idempotent re-import
|
|
303
318
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
304
319
|
|
|
305
|
-
|
|
320
|
+
console.log('=== md-importer: idempotent re-import ===');
|
|
321
|
+
|
|
322
|
+
{
|
|
306
323
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-idemp-test-'));
|
|
307
324
|
createFixtureTree(tmpDir);
|
|
308
325
|
|
|
@@ -311,9 +328,9 @@ test('md-importer: idempotent re-import', () => {
|
|
|
311
328
|
const r1 = migrateFromMarkdown(tmpDir);
|
|
312
329
|
const r2 = migrateFromMarkdown(tmpDir);
|
|
313
330
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
331
|
+
assertEq(r1.decisions, r2.decisions, 'double import should produce same decision count');
|
|
332
|
+
assertEq(r1.requirements, r2.requirements, 'double import should produce same requirement count');
|
|
333
|
+
assertEq(r1.artifacts, r2.artifacts, 'double import should produce same artifact count');
|
|
317
334
|
|
|
318
335
|
// Verify no duplicates
|
|
319
336
|
const adapter = _getAdapter();
|
|
@@ -321,21 +338,23 @@ test('md-importer: idempotent re-import', () => {
|
|
|
321
338
|
const rc = adapter?.prepare('SELECT count(*) as c FROM requirements').get()?.c as number;
|
|
322
339
|
const ac = adapter?.prepare('SELECT count(*) as c FROM artifacts').get()?.c as number;
|
|
323
340
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
341
|
+
assertEq(dc, r1.decisions, 'DB decision count matches import count');
|
|
342
|
+
assertEq(rc, r1.requirements, 'DB requirement count matches import count');
|
|
343
|
+
assertEq(ac, r1.artifacts, 'DB artifact count matches import count');
|
|
327
344
|
|
|
328
345
|
closeDatabase();
|
|
329
346
|
} finally {
|
|
330
347
|
cleanupDir(tmpDir);
|
|
331
348
|
}
|
|
332
|
-
}
|
|
349
|
+
}
|
|
333
350
|
|
|
334
351
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
335
352
|
// md-importer: missing file graceful handling
|
|
336
353
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
337
354
|
|
|
338
|
-
|
|
355
|
+
console.log('=== md-importer: missing file handling ===');
|
|
356
|
+
|
|
357
|
+
{
|
|
339
358
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-empty-test-'));
|
|
340
359
|
// Create empty .gsd/ with no files
|
|
341
360
|
fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
|
|
@@ -344,39 +363,43 @@ test('md-importer: missing file handling', () => {
|
|
|
344
363
|
openDatabase(':memory:');
|
|
345
364
|
const result = migrateFromMarkdown(tmpDir);
|
|
346
365
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
366
|
+
assertEq(result.decisions, 0, 'missing DECISIONS.md → 0 decisions');
|
|
367
|
+
assertEq(result.requirements, 0, 'missing REQUIREMENTS.md → 0 requirements');
|
|
368
|
+
assertEq(result.artifacts, 0, 'empty tree → 0 artifacts');
|
|
350
369
|
|
|
351
370
|
closeDatabase();
|
|
352
371
|
} finally {
|
|
353
372
|
cleanupDir(tmpDir);
|
|
354
373
|
}
|
|
355
|
-
}
|
|
374
|
+
}
|
|
356
375
|
|
|
357
376
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
358
377
|
// md-importer: schema v1→v2 migration on existing DBs
|
|
359
378
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
360
379
|
|
|
361
|
-
|
|
380
|
+
console.log('=== md-importer: schema v1→v2 migration ===');
|
|
381
|
+
|
|
382
|
+
{
|
|
362
383
|
// This test verifies that opening a fresh DB auto-migrates to current schema version
|
|
363
384
|
openDatabase(':memory:');
|
|
364
385
|
const adapter = _getAdapter();
|
|
365
386
|
const version = adapter?.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
366
|
-
|
|
387
|
+
assertEq(version?.v, 10, 'new DB should be at schema version 10');
|
|
367
388
|
|
|
368
389
|
// Artifacts table should exist
|
|
369
390
|
const tableCheck = adapter?.prepare("SELECT count(*) as c FROM sqlite_master WHERE type='table' AND name='artifacts'").get();
|
|
370
|
-
|
|
391
|
+
assertEq(tableCheck?.c, 1, 'artifacts table should exist');
|
|
371
392
|
|
|
372
393
|
closeDatabase();
|
|
373
|
-
}
|
|
394
|
+
}
|
|
374
395
|
|
|
375
396
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
376
397
|
// md-importer: round-trip fidelity
|
|
377
398
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
378
399
|
|
|
379
|
-
|
|
400
|
+
console.log('=== md-importer: round-trip fidelity ===');
|
|
401
|
+
|
|
402
|
+
{
|
|
380
403
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-roundtrip-test-'));
|
|
381
404
|
createFixtureTree(tmpDir);
|
|
382
405
|
|
|
@@ -386,31 +409,32 @@ test('md-importer: round-trip fidelity', () => {
|
|
|
386
409
|
|
|
387
410
|
// Round-trip: verify imported field values match source
|
|
388
411
|
const d002 = getDecisionById('D002');
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
412
|
+
assertEq(d002?.when_context, 'M001', 'D002 when_context round-trip');
|
|
413
|
+
assertEq(d002?.scope, 'arch', 'D002 scope round-trip');
|
|
414
|
+
assertEq(d002?.decision, 'DB location', 'D002 decision round-trip');
|
|
415
|
+
assertEq(d002?.choice, '.gsd/gsd.db', 'D002 choice round-trip');
|
|
416
|
+
assertEq(d002?.rationale, 'Derived state', 'D002 rationale round-trip');
|
|
394
417
|
|
|
395
418
|
const r002 = getRequirementById('R002');
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
419
|
+
assertEq(r002?.class, 'failure-visibility', 'R002 class round-trip');
|
|
420
|
+
assertEq(r002?.description, 'Falls back to markdown if SQLite unavailable', 'R002 description round-trip');
|
|
421
|
+
assertEq(r002?.why, 'Must not break on exotic platforms', 'R002 why round-trip');
|
|
422
|
+
assertEq(r002?.primary_owner, 'M001/S01', 'R002 primary_owner round-trip');
|
|
423
|
+
assertEq(r002?.supporting_slices, 'M001/S03', 'R002 supporting_slices round-trip');
|
|
424
|
+
assertEq(r002?.notes, 'Transparent fallback', 'R002 notes round-trip');
|
|
425
|
+
assertEq(r002?.validation, 'unmapped', 'R002 validation round-trip');
|
|
403
426
|
|
|
404
427
|
// Verify artifact content is stored
|
|
405
428
|
const adapter = _getAdapter();
|
|
406
429
|
const project = adapter?.prepare("SELECT * FROM artifacts WHERE path = :path").get({ ':path': 'PROJECT.md' });
|
|
407
|
-
|
|
430
|
+
assertTrue((project?.full_content as string)?.includes('Test Project'), 'PROJECT.md content round-trip');
|
|
408
431
|
|
|
409
432
|
closeDatabase();
|
|
410
433
|
} finally {
|
|
411
434
|
cleanupDir(tmpDir);
|
|
412
435
|
}
|
|
413
|
-
}
|
|
436
|
+
}
|
|
414
437
|
|
|
415
438
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
416
439
|
|
|
440
|
+
report();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createTestContext } from './test-helpers.ts';
|
|
1
2
|
import { parseMemoryResponse, _resetExtractionState } from '../memory-extractor.ts';
|
|
2
3
|
import {
|
|
3
4
|
openDatabase,
|
|
@@ -9,14 +10,15 @@ import {
|
|
|
9
10
|
getActiveMemoriesRanked,
|
|
10
11
|
} from '../memory-store.ts';
|
|
11
12
|
import type { MemoryAction } from '../memory-store.ts';
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
14
15
|
|
|
15
16
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
16
17
|
// memory-extractor: parse valid JSON response
|
|
17
18
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
console.log('\n=== memory-extractor: parse valid JSON ===');
|
|
21
|
+
{
|
|
20
22
|
const response = JSON.stringify([
|
|
21
23
|
{ action: 'CREATE', category: 'gotcha', content: 'esbuild drops binaries', confidence: 0.85 },
|
|
22
24
|
{ action: 'REINFORCE', id: 'MEM001' },
|
|
@@ -25,52 +27,56 @@ test('memory-extractor: parse valid JSON', () => {
|
|
|
25
27
|
]);
|
|
26
28
|
|
|
27
29
|
const actions = parseMemoryResponse(response);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
30
|
+
assertEq(actions.length, 4, 'should parse 4 actions');
|
|
31
|
+
assertEq(actions[0].action, 'CREATE', 'first action should be CREATE');
|
|
32
|
+
assertEq((actions[0] as any).category, 'gotcha', 'CREATE category');
|
|
33
|
+
assertEq((actions[0] as any).confidence, 0.85, 'CREATE confidence');
|
|
34
|
+
assertEq(actions[1].action, 'REINFORCE', 'second action should be REINFORCE');
|
|
35
|
+
assertEq(actions[2].action, 'UPDATE', 'third action should be UPDATE');
|
|
36
|
+
assertEq(actions[3].action, 'SUPERSEDE', 'fourth action should be SUPERSEDE');
|
|
37
|
+
}
|
|
36
38
|
|
|
37
39
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
38
40
|
// memory-extractor: parse fenced JSON response
|
|
39
41
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
console.log('\n=== memory-extractor: parse fenced JSON ===');
|
|
44
|
+
{
|
|
42
45
|
const response = '```json\n[\n {"action": "CREATE", "category": "convention", "content": "test memory"}\n]\n```';
|
|
43
46
|
|
|
44
47
|
const actions = parseMemoryResponse(response);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
+
assertEq(actions.length, 1, 'should parse 1 action from fenced JSON');
|
|
49
|
+
assertEq(actions[0].action, 'CREATE', 'action should be CREATE');
|
|
50
|
+
}
|
|
48
51
|
|
|
49
52
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
53
|
// memory-extractor: parse empty array response
|
|
51
54
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
console.log('\n=== memory-extractor: parse empty array ===');
|
|
57
|
+
{
|
|
54
58
|
const actions = parseMemoryResponse('[]');
|
|
55
|
-
|
|
56
|
-
}
|
|
59
|
+
assertEq(actions.length, 0, 'empty array should parse to empty actions');
|
|
60
|
+
}
|
|
57
61
|
|
|
58
62
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
59
63
|
// memory-extractor: parse malformed response
|
|
60
64
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
console.log('\n=== memory-extractor: malformed responses ===');
|
|
67
|
+
{
|
|
68
|
+
assertEq(parseMemoryResponse('not json at all'), [], 'garbage text should return []');
|
|
69
|
+
assertEq(parseMemoryResponse('{"action": "CREATE"}'), [], 'non-array should return []');
|
|
70
|
+
assertEq(parseMemoryResponse(''), [], 'empty string should return []');
|
|
71
|
+
assertEq(parseMemoryResponse('```\nbroken\n```'), [], 'fenced non-JSON should return []');
|
|
72
|
+
}
|
|
68
73
|
|
|
69
74
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
70
75
|
// memory-extractor: validation of required fields
|
|
71
76
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
72
77
|
|
|
73
|
-
|
|
78
|
+
console.log('\n=== memory-extractor: field validation ===');
|
|
79
|
+
{
|
|
74
80
|
const response = JSON.stringify([
|
|
75
81
|
// Valid CREATE
|
|
76
82
|
{ action: 'CREATE', category: 'gotcha', content: 'valid' },
|
|
@@ -97,18 +103,19 @@ test('memory-extractor: field validation', () => {
|
|
|
97
103
|
]);
|
|
98
104
|
|
|
99
105
|
const actions = parseMemoryResponse(response);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
+
assertEq(actions.length, 4, 'should only accept 4 valid actions');
|
|
107
|
+
assertEq(actions[0].action, 'CREATE', 'first valid is CREATE');
|
|
108
|
+
assertEq(actions[1].action, 'REINFORCE', 'second valid is REINFORCE');
|
|
109
|
+
assertEq(actions[2].action, 'UPDATE', 'third valid is UPDATE');
|
|
110
|
+
assertEq(actions[3].action, 'SUPERSEDE', 'fourth valid is SUPERSEDE');
|
|
111
|
+
}
|
|
106
112
|
|
|
107
113
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
108
114
|
// Integration: applyMemoryActions with mixed actions
|
|
109
115
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
console.log('\n=== integration: mixed action lifecycle ===');
|
|
118
|
+
{
|
|
112
119
|
openDatabase(':memory:');
|
|
113
120
|
|
|
114
121
|
// Phase 1: Create initial memories
|
|
@@ -119,7 +126,7 @@ test('integration: mixed action lifecycle', () => {
|
|
|
119
126
|
], 'plan-slice', 'M001/S01');
|
|
120
127
|
|
|
121
128
|
let active = getActiveMemoriesRanked(30);
|
|
122
|
-
|
|
129
|
+
assertEq(active.length, 3, 'phase 1: 3 active memories');
|
|
123
130
|
|
|
124
131
|
// Phase 2: Reinforce one, update another, create new
|
|
125
132
|
applyMemoryActions([
|
|
@@ -129,13 +136,13 @@ test('integration: mixed action lifecycle', () => {
|
|
|
129
136
|
], 'execute-task', 'M001/S01/T01');
|
|
130
137
|
|
|
131
138
|
active = getActiveMemoriesRanked(30);
|
|
132
|
-
|
|
133
|
-
|
|
139
|
+
assertEq(active.length, 4, 'phase 2: 4 active memories');
|
|
140
|
+
assertEq(
|
|
134
141
|
active.find(m => m.id === 'MEM001')?.content,
|
|
135
142
|
'npm run build requires tsc --noEmit first',
|
|
136
143
|
'MEM001 content should be updated',
|
|
137
144
|
);
|
|
138
|
-
|
|
145
|
+
assertEq(active.find(m => m.id === 'MEM002')?.hit_count, 1, 'MEM002 should be reinforced');
|
|
139
146
|
|
|
140
147
|
// Phase 3: Supersede MEM001 with MEM005
|
|
141
148
|
applyMemoryActions([
|
|
@@ -144,28 +151,30 @@ test('integration: mixed action lifecycle', () => {
|
|
|
144
151
|
], 'execute-task', 'M001/S01/T02');
|
|
145
152
|
|
|
146
153
|
active = getActiveMemoriesRanked(30);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
assertEq(active.length, 4, 'phase 3: 4 active (1 superseded, 1 created)');
|
|
155
|
+
assertTrue(!active.find(m => m.id === 'MEM001'), 'MEM001 should be superseded');
|
|
156
|
+
assertTrue(!!active.find(m => m.id === 'MEM005'), 'MEM005 should be active');
|
|
150
157
|
|
|
151
158
|
// Verify ranking: MEM003 (0.85) > MEM005 (0.9) but MEM002 has 1 hit
|
|
152
159
|
// MEM002: 0.8 * (1 + 1*0.1) = 0.88
|
|
153
160
|
// MEM003: 0.85 * 1.0 = 0.85
|
|
154
161
|
// MEM005: 0.9 * 1.0 = 0.9
|
|
155
162
|
// MEM004: 0.75 * 1.0 = 0.75
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
assertEq(active[0].id, 'MEM005', 'MEM005 should rank first (0.9)');
|
|
164
|
+
assertEq(active[1].id, 'MEM002', 'MEM002 should rank second (0.88)');
|
|
158
165
|
|
|
159
166
|
closeDatabase();
|
|
160
|
-
}
|
|
167
|
+
}
|
|
161
168
|
|
|
162
169
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
163
170
|
// memory-extractor: _resetExtractionState
|
|
164
171
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
165
172
|
|
|
166
|
-
|
|
173
|
+
console.log('\n=== memory-extractor: reset extraction state ===');
|
|
174
|
+
{
|
|
167
175
|
// Just verify it doesn't throw
|
|
168
176
|
_resetExtractionState();
|
|
169
|
-
|
|
170
|
-
}
|
|
177
|
+
assertTrue(true, '_resetExtractionState should not throw');
|
|
178
|
+
}
|
|
171
179
|
|
|
180
|
+
report();
|