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,14 +1,15 @@
|
|
|
1
1
|
// GSD Extension - Override Tests
|
|
2
2
|
// Tests for parseOverrides, appendOverride, loadActiveOverrides, formatOverridesSection, resolveAllOverrides
|
|
3
3
|
|
|
4
|
-
import { describe, test, afterEach } from 'node:test';
|
|
5
|
-
import assert from 'node:assert/strict';
|
|
6
4
|
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "node:fs";
|
|
7
5
|
import { join } from "node:path";
|
|
8
6
|
import { tmpdir } from "node:os";
|
|
7
|
+
import { createTestContext } from './test-helpers.ts';
|
|
9
8
|
import { parseOverrides, appendOverride, loadActiveOverrides, formatOverridesSection, resolveAllOverrides } from '../files.ts';
|
|
10
9
|
import type { Override } from '../files.ts';
|
|
11
10
|
|
|
11
|
+
const { assertEq, assertTrue, assertMatch, assertNoMatch, report } = createTestContext();
|
|
12
|
+
|
|
12
13
|
const tempDirs: string[] = [];
|
|
13
14
|
|
|
14
15
|
function makeTempDir(prefix: string): string {
|
|
@@ -25,100 +26,106 @@ function cleanup(): void {
|
|
|
25
26
|
tempDirs.length = 0;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
29
|
+
console.log('\n=== parseOverrides: empty content ===');
|
|
30
|
+
{ const result = parseOverrides(""); assertEq(result.length, 0, "empty content returns no overrides"); }
|
|
31
|
+
|
|
32
|
+
console.log('\n=== parseOverrides: single active override ===');
|
|
33
|
+
{
|
|
34
|
+
const content = `# GSD Overrides\n\nUser-issued overrides that supersede plan document content.\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** active\n**Applied-at:** M001/S02/T03\n\n---\n`;
|
|
35
|
+
const result = parseOverrides(content);
|
|
36
|
+
assertEq(result.length, 1, "parses one override");
|
|
37
|
+
assertEq(result[0].timestamp, "2026-03-14T10:00:00.000Z", "correct timestamp");
|
|
38
|
+
assertEq(result[0].change, "Use Postgres instead of SQLite", "correct change");
|
|
39
|
+
assertEq(result[0].scope, "active", "correct scope");
|
|
40
|
+
assertEq(result[0].appliedAt, "M001/S02/T03", "correct appliedAt");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log('\n=== parseOverrides: multiple overrides, mixed scopes ===');
|
|
44
|
+
{
|
|
45
|
+
const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Use Postgres instead of SQLite\n**Scope:** resolved\n**Applied-at:** M001/S02/T03\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Use JWT instead of session cookies\n**Scope:** active\n**Applied-at:** M001/S03/T01\n\n---\n`;
|
|
46
|
+
const result = parseOverrides(content);
|
|
47
|
+
assertEq(result.length, 2, "parses two overrides");
|
|
48
|
+
assertEq(result[0].scope, "resolved", "first is resolved");
|
|
49
|
+
assertEq(result[1].scope, "active", "second is active");
|
|
50
|
+
assertEq(result[1].change, "Use JWT instead of session cookies", "second change text");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('\n=== appendOverride: creates new file ===');
|
|
54
|
+
{
|
|
55
|
+
const tmp = makeTempDir("append-new");
|
|
56
|
+
await appendOverride(tmp, "Use Postgres", "M001/S01/T01");
|
|
57
|
+
const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
|
|
58
|
+
assertTrue(content.includes("# GSD Overrides"), "has header");
|
|
59
|
+
assertTrue(content.includes("**Change:** Use Postgres"), "has change");
|
|
60
|
+
assertTrue(content.includes("**Scope:** active"), "has active scope");
|
|
61
|
+
assertTrue(content.includes("**Applied-at:** M001/S01/T01"), "has appliedAt");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('\n=== appendOverride: appends to existing file ===');
|
|
65
|
+
{
|
|
66
|
+
const tmp = makeTempDir("append-existing");
|
|
67
|
+
await appendOverride(tmp, "First override", "M001/S01/T01");
|
|
68
|
+
await appendOverride(tmp, "Second override", "M001/S02/T02");
|
|
69
|
+
const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
|
|
70
|
+
assertTrue(content.includes("**Change:** First override"), "has first override");
|
|
71
|
+
assertTrue(content.includes("**Change:** Second override"), "has second override");
|
|
72
|
+
const parsed = parseOverrides(content);
|
|
73
|
+
assertEq(parsed.length, 2, "two overrides in file");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log('\n=== loadActiveOverrides: no file ===');
|
|
77
|
+
{
|
|
78
|
+
const tmp = makeTempDir("load-no-file");
|
|
79
|
+
const result = await loadActiveOverrides(tmp);
|
|
80
|
+
assertEq(result.length, 0, "returns empty when no file");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log('\n=== loadActiveOverrides: filters to active only ===');
|
|
84
|
+
{
|
|
85
|
+
const tmp = makeTempDir("load-filter");
|
|
86
|
+
const content = `# GSD Overrides\n\n---\n\n## Override: 2026-03-14T10:00:00.000Z\n\n**Change:** Resolved change\n**Scope:** resolved\n**Applied-at:** M001/S01/T01\n\n---\n\n## Override: 2026-03-14T11:00:00.000Z\n\n**Change:** Active change\n**Scope:** active\n**Applied-at:** M001/S02/T01\n\n---\n`;
|
|
87
|
+
writeFileSync(join(tmp, ".gsd", "OVERRIDES.md"), content, "utf-8");
|
|
88
|
+
const result = await loadActiveOverrides(tmp);
|
|
89
|
+
assertEq(result.length, 1, "only one active override");
|
|
90
|
+
assertEq(result[0].change, "Active change", "correct active change");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log('\n=== formatOverridesSection: empty array ===');
|
|
94
|
+
{ const result = formatOverridesSection([]); assertEq(result, "", "empty overrides returns empty string"); }
|
|
95
|
+
|
|
96
|
+
console.log('\n=== formatOverridesSection: formats section ===');
|
|
97
|
+
{
|
|
98
|
+
const overrides: Override[] = [
|
|
99
|
+
{ timestamp: "2026-03-14T10:00:00.000Z", change: "Use Postgres", scope: "active", appliedAt: "M001/S01/T01" },
|
|
100
|
+
];
|
|
101
|
+
const result = formatOverridesSection(overrides);
|
|
102
|
+
assertTrue(result.includes("## Active Overrides (supersede plan content)"), "has header");
|
|
103
|
+
assertTrue(result.includes("**Use Postgres**"), "has change text");
|
|
104
|
+
assertTrue(result.includes("supersede any conflicting content"), "has instruction");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log('\n=== resolveAllOverrides: marks all as resolved ===');
|
|
108
|
+
{
|
|
109
|
+
const tmp = makeTempDir("resolve-all");
|
|
110
|
+
await appendOverride(tmp, "First", "M001/S01/T01");
|
|
111
|
+
await appendOverride(tmp, "Second", "M001/S02/T01");
|
|
112
|
+
let active = await loadActiveOverrides(tmp);
|
|
113
|
+
assertEq(active.length, 2, "two active before resolve");
|
|
114
|
+
await resolveAllOverrides(tmp);
|
|
115
|
+
active = await loadActiveOverrides(tmp);
|
|
116
|
+
assertEq(active.length, 0, "no active after resolve");
|
|
117
|
+
const content = readFileSync(join(tmp, ".gsd", "OVERRIDES.md"), "utf-8");
|
|
118
|
+
const allOverrides = parseOverrides(content);
|
|
119
|
+
assertEq(allOverrides.length, 2, "still two overrides total");
|
|
120
|
+
assertTrue(allOverrides.every(o => o.scope === "resolved"), "all resolved");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.log('\n=== resolveAllOverrides: no file — no error ===');
|
|
124
|
+
{
|
|
125
|
+
const tmp = makeTempDir("resolve-no-file");
|
|
126
|
+
await resolveAllOverrides(tmp);
|
|
127
|
+
assertTrue(true, "resolveAllOverrides with no file does not throw");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
cleanup();
|
|
131
|
+
report();
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* restored after a coordinator crash, with PID liveness filtering.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { describe, test } from 'node:test';
|
|
9
|
-
import assert from 'node:assert/strict';
|
|
10
8
|
import {
|
|
11
9
|
mkdtempSync,
|
|
12
10
|
mkdirSync,
|
|
@@ -26,6 +24,10 @@ import {
|
|
|
26
24
|
type PersistedState,
|
|
27
25
|
} from "../parallel-orchestrator.ts";
|
|
28
26
|
import { writeSessionStatus, readAllSessionStatuses, removeSessionStatus } from "../session-status-io.ts";
|
|
27
|
+
import { createTestContext } from './test-helpers.ts';
|
|
28
|
+
|
|
29
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
30
|
+
|
|
29
31
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
30
32
|
|
|
31
33
|
function makeTempDir(): string {
|
|
@@ -55,9 +57,8 @@ function makePersistedState(overrides: Partial<PersistedState> = {}): PersistedS
|
|
|
55
57
|
|
|
56
58
|
// ─── Tests ────────────────────────────────────────────────────────────────────
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
test('Test 1: persistState writes valid JSON', () => {
|
|
60
|
+
// Test 1: persistState writes valid JSON
|
|
61
|
+
{
|
|
61
62
|
const basePath = makeTempDir();
|
|
62
63
|
try {
|
|
63
64
|
// We can't call persistState directly without internal state set up,
|
|
@@ -81,27 +82,29 @@ test('Test 1: persistState writes valid JSON', () => {
|
|
|
81
82
|
|
|
82
83
|
const raw = readFileSync(stateFilePath(basePath), "utf-8");
|
|
83
84
|
const parsed = JSON.parse(raw) as PersistedState;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
assertEq(parsed.active, true, "persistState: active field preserved");
|
|
86
|
+
assertEq(parsed.workers.length, 1, "persistState: worker count preserved");
|
|
87
|
+
assertEq(parsed.workers[0].milestoneId, "M001", "persistState: milestoneId preserved");
|
|
88
|
+
assertEq(parsed.workers[0].cost, 0.15, "persistState: cost preserved");
|
|
89
|
+
assertEq(parsed.totalCost, 0.15, "persistState: totalCost preserved");
|
|
89
90
|
} finally {
|
|
90
91
|
rmSync(basePath, { recursive: true, force: true });
|
|
91
92
|
}
|
|
92
|
-
}
|
|
93
|
+
}
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
// Test 2: restoreState returns null for missing file
|
|
96
|
+
{
|
|
95
97
|
const basePath = makeTempDir();
|
|
96
98
|
try {
|
|
97
99
|
const result = restoreState(basePath);
|
|
98
|
-
|
|
100
|
+
assertEq(result, null, "restoreState: returns null when no state file");
|
|
99
101
|
} finally {
|
|
100
102
|
rmSync(basePath, { recursive: true, force: true });
|
|
101
103
|
}
|
|
102
|
-
}
|
|
104
|
+
}
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
// Test 3: restoreState filters dead PIDs
|
|
107
|
+
{
|
|
105
108
|
const basePath = makeTempDir();
|
|
106
109
|
try {
|
|
107
110
|
// PID 99999999 is almost certainly not alive
|
|
@@ -133,14 +136,15 @@ test('Test 3: restoreState filters dead PIDs', () => {
|
|
|
133
136
|
|
|
134
137
|
const result = restoreState(basePath);
|
|
135
138
|
// Both PIDs are dead, so result should be null and file should be cleaned up
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
assertEq(result, null, "restoreState: returns null when all PIDs dead");
|
|
140
|
+
assertTrue(!existsSync(stateFilePath(basePath)), "restoreState: cleans up state file when all dead");
|
|
138
141
|
} finally {
|
|
139
142
|
rmSync(basePath, { recursive: true, force: true });
|
|
140
143
|
}
|
|
141
|
-
}
|
|
144
|
+
}
|
|
142
145
|
|
|
143
|
-
|
|
146
|
+
// Test 4: restoreState keeps alive PIDs
|
|
147
|
+
{
|
|
144
148
|
const basePath = makeTempDir();
|
|
145
149
|
try {
|
|
146
150
|
// Use current process PID (definitely alive)
|
|
@@ -172,17 +176,18 @@ test('Test 4: restoreState keeps alive PIDs', () => {
|
|
|
172
176
|
writeStateFile(basePath, state);
|
|
173
177
|
|
|
174
178
|
const result = restoreState(basePath);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
assertTrue(result !== null, "restoreState: returns state when alive PID exists");
|
|
180
|
+
assertEq(result!.workers.length, 1, "restoreState: filters out dead PID");
|
|
181
|
+
assertEq(result!.workers[0].milestoneId, "M001", "restoreState: keeps alive worker");
|
|
182
|
+
assertEq(result!.workers[0].pid, process.pid, "restoreState: preserves PID");
|
|
183
|
+
assertEq(result!.workers[0].completedUnits, 5, "restoreState: preserves progress");
|
|
180
184
|
} finally {
|
|
181
185
|
rmSync(basePath, { recursive: true, force: true });
|
|
182
186
|
}
|
|
183
|
-
}
|
|
187
|
+
}
|
|
184
188
|
|
|
185
|
-
|
|
189
|
+
// Test 5: restoreState skips stopped/error workers even with alive PIDs
|
|
190
|
+
{
|
|
186
191
|
const basePath = makeTempDir();
|
|
187
192
|
try {
|
|
188
193
|
const state = makePersistedState({
|
|
@@ -202,13 +207,14 @@ test('Test 5: restoreState skips stopped/error workers even with alive PIDs', ()
|
|
|
202
207
|
writeStateFile(basePath, state);
|
|
203
208
|
|
|
204
209
|
const result = restoreState(basePath);
|
|
205
|
-
|
|
210
|
+
assertEq(result, null, "restoreState: skips stopped workers");
|
|
206
211
|
} finally {
|
|
207
212
|
rmSync(basePath, { recursive: true, force: true });
|
|
208
213
|
}
|
|
209
|
-
}
|
|
214
|
+
}
|
|
210
215
|
|
|
211
|
-
|
|
216
|
+
// Test 6: orphan detection finds stale sessions
|
|
217
|
+
{
|
|
212
218
|
const basePath = makeTempDir();
|
|
213
219
|
try {
|
|
214
220
|
// Write a session status with a dead PID
|
|
@@ -240,7 +246,7 @@ test('Test 6: orphan detection finds stale sessions', () => {
|
|
|
240
246
|
|
|
241
247
|
// Read all sessions — both should exist initially
|
|
242
248
|
const before = readAllSessionStatuses(basePath);
|
|
243
|
-
|
|
249
|
+
assertEq(before.length, 2, "orphan: both sessions exist before detection");
|
|
244
250
|
|
|
245
251
|
// Now simulate orphan detection logic (same as prepareParallelStart)
|
|
246
252
|
const sessions = readAllSessionStatuses(basePath);
|
|
@@ -259,33 +265,34 @@ test('Test 6: orphan detection finds stale sessions', () => {
|
|
|
259
265
|
}
|
|
260
266
|
}
|
|
261
267
|
|
|
262
|
-
|
|
268
|
+
assertTrue(orphans.length === 2, "orphan: detected both sessions");
|
|
263
269
|
const deadOrphan = orphans.find(o => o.milestoneId === "M001");
|
|
264
|
-
|
|
270
|
+
assertTrue(deadOrphan !== undefined && !deadOrphan.alive, "orphan: M001 detected as dead");
|
|
265
271
|
const aliveOrphan = orphans.find(o => o.milestoneId === "M002");
|
|
266
|
-
|
|
272
|
+
assertTrue(aliveOrphan !== undefined && aliveOrphan.alive, "orphan: M002 detected as alive");
|
|
267
273
|
|
|
268
274
|
// Dead session should be cleaned up
|
|
269
275
|
const after = readAllSessionStatuses(basePath);
|
|
270
|
-
|
|
271
|
-
|
|
276
|
+
assertEq(after.length, 1, "orphan: dead session cleaned up");
|
|
277
|
+
assertEq(after[0].milestoneId, "M002", "orphan: alive session remains");
|
|
272
278
|
} finally {
|
|
273
279
|
rmSync(basePath, { recursive: true, force: true });
|
|
274
280
|
}
|
|
275
|
-
}
|
|
281
|
+
}
|
|
276
282
|
|
|
277
|
-
|
|
283
|
+
// Test 7: restoreState handles corrupt JSON gracefully
|
|
284
|
+
{
|
|
278
285
|
const basePath = makeTempDir();
|
|
279
286
|
try {
|
|
280
287
|
writeFileSync(stateFilePath(basePath), "{ not valid json !!!", "utf-8");
|
|
281
288
|
const result = restoreState(basePath);
|
|
282
|
-
|
|
289
|
+
assertEq(result, null, "restoreState: returns null for corrupt JSON");
|
|
283
290
|
} finally {
|
|
284
291
|
rmSync(basePath, { recursive: true, force: true });
|
|
285
292
|
}
|
|
286
|
-
}
|
|
293
|
+
}
|
|
287
294
|
|
|
288
295
|
// Clean up module state
|
|
289
296
|
resetOrchestrator();
|
|
290
297
|
|
|
291
|
-
|
|
298
|
+
report();
|
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* 6. completedUnits counter increments on assistant message_end
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import assert from 'node:assert/strict';
|
|
14
13
|
import { describe, it, after } from "node:test";
|
|
15
14
|
import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "node:fs";
|
|
16
15
|
import { join } from "node:path";
|
|
17
16
|
import { tmpdir } from "node:os";
|
|
17
|
+
import { createTestContext } from "./test-helpers.ts";
|
|
18
|
+
|
|
18
19
|
// We test processWorkerLine indirectly via the module's exported state.
|
|
19
20
|
// To test the internal function, we use the exported accessors.
|
|
20
21
|
import {
|
|
@@ -26,6 +27,8 @@ import {
|
|
|
26
27
|
refreshWorkerStatuses,
|
|
27
28
|
} from "../parallel-orchestrator.ts";
|
|
28
29
|
|
|
30
|
+
const { assertEq, assertTrue, report } = createTestContext();
|
|
31
|
+
|
|
29
32
|
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
30
33
|
|
|
31
34
|
/** Create a minimal message_end NDJSON line with cost data. */
|
|
@@ -49,7 +52,7 @@ function makeMessageEndLine(cost: number, role = "assistant"): string {
|
|
|
49
52
|
describe("parallel-worker-monitoring", () => {
|
|
50
53
|
after(() => {
|
|
51
54
|
resetOrchestrator();
|
|
52
|
-
|
|
55
|
+
report();
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
// Note: processWorkerLine is not exported, so we test the observable effects
|
|
@@ -58,39 +61,39 @@ describe("parallel-worker-monitoring", () => {
|
|
|
58
61
|
|
|
59
62
|
it("isBudgetExceeded returns false when no state exists", () => {
|
|
60
63
|
resetOrchestrator();
|
|
61
|
-
|
|
64
|
+
assertTrue(!isBudgetExceeded(), "no state = not exceeded");
|
|
62
65
|
});
|
|
63
66
|
|
|
64
67
|
it("isBudgetExceeded returns false when no ceiling configured", () => {
|
|
65
68
|
resetOrchestrator();
|
|
66
69
|
// Can't directly set state without startParallel, so test the accessor
|
|
67
|
-
|
|
70
|
+
assertTrue(!isBudgetExceeded(), "no ceiling = not exceeded");
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
it("getAggregateCost returns 0 when no state exists", () => {
|
|
71
74
|
resetOrchestrator();
|
|
72
|
-
|
|
75
|
+
assertEq(getAggregateCost(), 0, "no state = zero cost");
|
|
73
76
|
});
|
|
74
77
|
|
|
75
78
|
it("isParallelActive returns false after reset", () => {
|
|
76
79
|
resetOrchestrator();
|
|
77
|
-
|
|
80
|
+
assertTrue(!isParallelActive(), "reset = not active");
|
|
78
81
|
});
|
|
79
82
|
|
|
80
83
|
it("getWorkerStatuses returns empty array when no state", () => {
|
|
81
84
|
resetOrchestrator();
|
|
82
|
-
|
|
85
|
+
assertEq(getWorkerStatuses().length, 0, "no state = empty workers");
|
|
83
86
|
});
|
|
84
87
|
|
|
85
88
|
it("NDJSON message_end format matches expected structure", () => {
|
|
86
89
|
// Verify the NDJSON line format we expect from workers
|
|
87
90
|
const line = makeMessageEndLine(0.05);
|
|
88
91
|
const parsed = JSON.parse(line);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
assertEq(parsed.type, "message_end", "type is message_end");
|
|
93
|
+
assertEq(parsed.message.role, "assistant", "role is assistant");
|
|
94
|
+
assertEq(parsed.message.usage.cost.total, 0.05, "cost.total is 0.05");
|
|
95
|
+
assertTrue(typeof parsed.message.usage.input === "number", "input is number");
|
|
96
|
+
assertTrue(typeof parsed.message.usage.output === "number", "output is number");
|
|
94
97
|
});
|
|
95
98
|
|
|
96
99
|
it("malformed JSON does not throw (tested via parse safety)", () => {
|
|
@@ -108,7 +111,7 @@ describe("parallel-worker-monitoring", () => {
|
|
|
108
111
|
JSON.parse(line);
|
|
109
112
|
} catch {
|
|
110
113
|
// Expected — processWorkerLine catches this silently
|
|
111
|
-
|
|
114
|
+
assertTrue(true, `malformed line "${line.slice(0, 20)}" handled`);
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
});
|
|
@@ -119,25 +122,25 @@ describe("parallel-worker-monitoring", () => {
|
|
|
119
122
|
let total = 0;
|
|
120
123
|
for (const c of costs) total += c;
|
|
121
124
|
// Floating point: round to 2 decimal places for comparison
|
|
122
|
-
|
|
125
|
+
assertEq(Math.round(total * 100) / 100, 0.28, "cost sum is correct");
|
|
123
126
|
});
|
|
124
127
|
|
|
125
128
|
it("budget ceiling comparison works with typical values", () => {
|
|
126
129
|
// Test the ceiling check pattern
|
|
127
130
|
const ceiling = 5.0;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
assertTrue(0 < ceiling, "0 is under ceiling");
|
|
132
|
+
assertTrue(4.99 < ceiling, "4.99 is under ceiling");
|
|
133
|
+
assertTrue(!(5.0 < ceiling), "5.0 is at ceiling");
|
|
134
|
+
assertTrue(!(5.01 < ceiling), "5.01 is over ceiling");
|
|
132
135
|
});
|
|
133
136
|
|
|
134
137
|
it("worker spawn args include --mode json", () => {
|
|
135
138
|
// Verify the spawn command includes JSON mode for NDJSON output.
|
|
136
139
|
// We can't easily test the actual spawn, but we verify the args pattern.
|
|
137
140
|
const expectedArgs = ["--mode", "json", "--print", "/gsd auto"];
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
assertTrue(expectedArgs.includes("--mode"), "args include --mode");
|
|
142
|
+
assertTrue(expectedArgs.includes("json"), "args include json");
|
|
143
|
+
assertTrue(expectedArgs.indexOf("--mode") < expectedArgs.indexOf("json"),
|
|
141
144
|
"--mode comes before json");
|
|
142
145
|
});
|
|
143
146
|
|
|
@@ -165,8 +168,8 @@ describe("parallel-worker-monitoring", () => {
|
|
|
165
168
|
}, null, 2));
|
|
166
169
|
refreshWorkerStatuses(base, { restoreIfNeeded: true });
|
|
167
170
|
const workers = getWorkerStatuses();
|
|
168
|
-
|
|
169
|
-
|
|
171
|
+
assertEq(workers.length, 1, "restored one worker");
|
|
172
|
+
assertEq(workers[0].milestoneId, "M001", "worker restored from persisted state");
|
|
170
173
|
} finally {
|
|
171
174
|
resetOrchestrator();
|
|
172
175
|
rmSync(base, { recursive: true, force: true });
|
|
@@ -190,8 +193,8 @@ describe("parallel-worker-monitoring", () => {
|
|
|
190
193
|
}, null, 2));
|
|
191
194
|
refreshWorkerStatuses(base, { restoreIfNeeded: true });
|
|
192
195
|
const workers = getWorkerStatuses();
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
assertEq(workers[0].state, "running", "live session status restored");
|
|
197
|
+
assertEq(workers[0].completedUnits, 3, "completed units restored from status file");
|
|
195
198
|
} finally {
|
|
196
199
|
resetOrchestrator();
|
|
197
200
|
rmSync(base, { recursive: true, force: true });
|