gsd-pi 2.44.0 → 2.45.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 +30 -12
- package/dist/resources/extensions/gsd/activity-log.js +7 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +37 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +31 -2
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/repo-identity.js +45 -7
- package/dist/resources/extensions/gsd/rethink.js +115 -0
- package/dist/resources/extensions/gsd/state.js +41 -3
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +32 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- 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/react-loadable-manifest.json +2 -2
- 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 +1 -1
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.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_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.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_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.js +1 -1
- 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_client-reference-manifest.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_client-reference-manifest.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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +1 -1
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/{page-7e9530a7122506c5.js → page-12dd5ece0df4badc.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
- package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
- package/package.json +1 -1
- package/packages/native/dist/stream-process/index.js +2 -2
- package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
- package/packages/native/src/stream-process/index.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- 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 +24 -26
- 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 +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- 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 +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +46 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +39 -2
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/repo-identity.ts +46 -7
- package/src/resources/extensions/gsd/rethink.ts +154 -0
- package/src/resources/extensions/gsd/state.ts +41 -1
- 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 +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- 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 +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +43 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
- package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
1
3
|
/**
|
|
2
4
|
* Tests for dashboard budget indicator rendering.
|
|
3
5
|
*
|
|
@@ -18,10 +20,6 @@ import {
|
|
|
18
20
|
getProjectTotals,
|
|
19
21
|
formatTokenCount,
|
|
20
22
|
} from "../metrics.js";
|
|
21
|
-
import { createTestContext } from './test-helpers.ts';
|
|
22
|
-
|
|
23
|
-
const { assertEq, assertTrue, assertMatch, assertNoMatch, report } = createTestContext();
|
|
24
|
-
|
|
25
23
|
// ─── Test helpers ─────────────────────────────────────────────────────────────
|
|
26
24
|
|
|
27
25
|
function makeUnit(overrides: Partial<UnitMetrics> = {}): UnitMetrics {
|
|
@@ -102,245 +100,230 @@ function renderModelContextWindow(units: UnitMetrics[], modelName: string): stri
|
|
|
102
100
|
|
|
103
101
|
// ─── Completed section: budget indicators ─────────────────────────────────────
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
{
|
|
134
|
-
// Unit with continue-here only — no truncation marker
|
|
135
|
-
const ledgerUnits = [
|
|
136
|
-
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 0, continueHereFired: true }),
|
|
137
|
-
];
|
|
138
|
-
const markers = renderCompletedBudgetMarkers(
|
|
139
|
-
{ type: "execute-task", id: "M001/S01/T01" },
|
|
140
|
-
ledgerUnits,
|
|
141
|
-
);
|
|
142
|
-
assertNoMatch(markers, /▼/, "completed: no ▼ when truncationSections=0");
|
|
143
|
-
assertMatch(markers, /→ wrap-up/, "completed: shows → wrap-up");
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ─── Completed section: missing ledger match ──────────────────────────────────
|
|
147
|
-
|
|
148
|
-
console.log("\n=== Completed section: missing ledger match ===");
|
|
149
|
-
|
|
150
|
-
{
|
|
151
|
-
// Completed unit with no matching ledger entry — no crash, no markers
|
|
152
|
-
const ledgerUnits = [
|
|
153
|
-
makeUnit({ type: "execute-task", id: "M001/S01/T99", truncationSections: 3 }),
|
|
154
|
-
];
|
|
155
|
-
const markers = renderCompletedBudgetMarkers(
|
|
156
|
-
{ type: "execute-task", id: "M001/S01/T01" },
|
|
157
|
-
ledgerUnits,
|
|
158
|
-
);
|
|
159
|
-
assertEq(markers, "", "missing match: empty markers when no ledger entry matches");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
{
|
|
163
|
-
// Empty ledger — no crash, no markers
|
|
164
|
-
const markers = renderCompletedBudgetMarkers(
|
|
165
|
-
{ type: "execute-task", id: "M001/S01/T01" },
|
|
166
|
-
[],
|
|
167
|
-
);
|
|
168
|
-
assertEq(markers, "", "empty ledger: empty markers");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// ─── Completed section: retry handling (last entry wins) ──────────────────────
|
|
172
|
-
|
|
173
|
-
console.log("\n=== Completed section: retry handling ===");
|
|
174
|
-
|
|
175
|
-
{
|
|
176
|
-
// Two ledger entries for same unit (retry) — last entry wins
|
|
177
|
-
const ledgerUnits = [
|
|
178
|
-
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 1 }),
|
|
179
|
-
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 7 }),
|
|
180
|
-
];
|
|
181
|
-
const markers = renderCompletedBudgetMarkers(
|
|
182
|
-
{ type: "execute-task", id: "M001/S01/T01" },
|
|
183
|
-
ledgerUnits,
|
|
184
|
-
);
|
|
185
|
-
assertMatch(markers, /▼7/, "retry: last entry's truncation count (7) wins over first (1)");
|
|
186
|
-
assertNoMatch(markers, /▼1/, "retry: first entry's count (1) is not shown");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// ─── By Model section: context window display ─────────────────────────────────
|
|
190
|
-
|
|
191
|
-
console.log("\n=== By Model section: context window ===");
|
|
192
|
-
|
|
193
|
-
{
|
|
194
|
-
// Model with context window — shows formatted token count
|
|
195
|
-
const units = [
|
|
196
|
-
makeUnit({ model: "claude-sonnet-4-20250514", contextWindowTokens: 200000 }),
|
|
197
|
-
];
|
|
198
|
-
const label = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
199
|
-
assertEq(label, "[200.0k]", "by model: shows [200.0k] for 200000 context window");
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
{
|
|
203
|
-
// Model without context window — no label
|
|
204
|
-
const units = [
|
|
205
|
-
makeUnit({ model: "claude-sonnet-4-20250514" }),
|
|
206
|
-
];
|
|
207
|
-
const label = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
208
|
-
assertEq(label, null, "by model: null when no contextWindowTokens");
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
{
|
|
212
|
-
// Multiple models — each gets its own context window
|
|
213
|
-
const units = [
|
|
214
|
-
makeUnit({ model: "claude-sonnet-4-20250514", contextWindowTokens: 200000, cost: 0.05 }),
|
|
215
|
-
makeUnit({ model: "claude-opus-4-20250514", contextWindowTokens: 200000, cost: 0.30 }),
|
|
216
|
-
];
|
|
217
|
-
const sonnetLabel = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
218
|
-
const opusLabel = renderModelContextWindow(units, "claude-opus-4-20250514");
|
|
219
|
-
assertEq(sonnetLabel, "[200.0k]", "by model multi: sonnet has context window");
|
|
220
|
-
assertEq(opusLabel, "[200.0k]", "by model multi: opus has context window");
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ─── By Model section: single model visibility ───────────────────────────────
|
|
224
|
-
|
|
225
|
-
console.log("\n=== By Model section: single model visibility ===");
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
// With guard changed to >= 1, single model aggregation should produce results
|
|
229
|
-
const units = [
|
|
230
|
-
makeUnit({ model: "claude-sonnet-4-20250514" }),
|
|
231
|
-
];
|
|
232
|
-
const models = aggregateByModel(units);
|
|
233
|
-
assertTrue(models.length >= 1, "single model: aggregateByModel returns >= 1 entry");
|
|
234
|
-
assertEq(models.length, 1, "single model: exactly 1 model aggregate");
|
|
235
|
-
assertEq(models[0].model, "claude-sonnet-4-20250514", "single model: correct model name");
|
|
236
|
-
// The guard `models.length >= 1` (changed from > 1) means this section now renders
|
|
237
|
-
assertTrue(models.length >= 1, "single model: passes >= 1 guard (section will render)");
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ─── Cost & Usage: aggregate budget line ──────────────────────────────────────
|
|
241
|
-
|
|
242
|
-
console.log("\n=== Cost & Usage: aggregate budget line ===");
|
|
243
|
-
|
|
244
|
-
{
|
|
245
|
-
// Units with truncation and continue-here — both stats appear
|
|
246
|
-
const units = [
|
|
247
|
-
makeUnit({ truncationSections: 3, continueHereFired: true }),
|
|
248
|
-
makeUnit({ truncationSections: 2, continueHereFired: false }),
|
|
249
|
-
makeUnit({ truncationSections: 1, continueHereFired: true }),
|
|
250
|
-
];
|
|
251
|
-
const line = renderCostBudgetLine(units);
|
|
252
|
-
assertTrue(line !== null, "cost budget: line rendered when budget data exists");
|
|
253
|
-
assertMatch(line!, /6 sections truncated/, "cost budget: shows total truncation count (3+2+1=6)");
|
|
254
|
-
assertMatch(line!, /2 continue-here fired/, "cost budget: shows continue-here count");
|
|
255
|
-
}
|
|
103
|
+
describe('dashboard-budget', () => {
|
|
104
|
+
test('Completed section: truncation + continue-here markers', () => {
|
|
105
|
+
// Unit with truncation and continue-here — both markers appear
|
|
106
|
+
const ledgerUnits = [
|
|
107
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 3, continueHereFired: true }),
|
|
108
|
+
];
|
|
109
|
+
const markers = renderCompletedBudgetMarkers(
|
|
110
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
111
|
+
ledgerUnits,
|
|
112
|
+
);
|
|
113
|
+
assert.match(markers, /▼3/, "completed: shows ▼3 for 3 truncation sections");
|
|
114
|
+
assert.match(markers, /→ wrap-up/, "completed: shows → wrap-up when continueHereFired");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
{
|
|
118
|
+
// Unit with truncation only — no wrap-up marker
|
|
119
|
+
const ledgerUnits = [
|
|
120
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 5, continueHereFired: false }),
|
|
121
|
+
];
|
|
122
|
+
const markers = renderCompletedBudgetMarkers(
|
|
123
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
124
|
+
ledgerUnits,
|
|
125
|
+
);
|
|
126
|
+
assert.match(markers, /▼5/, "completed: shows ▼5 truncation only");
|
|
127
|
+
assert.doesNotMatch(markers, /wrap-up/, "completed: no wrap-up when continueHereFired=false");
|
|
128
|
+
}
|
|
256
129
|
|
|
257
|
-
{
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
130
|
+
{
|
|
131
|
+
// Unit with continue-here only — no truncation marker
|
|
132
|
+
const ledgerUnits = [
|
|
133
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 0, continueHereFired: true }),
|
|
134
|
+
];
|
|
135
|
+
const markers = renderCompletedBudgetMarkers(
|
|
136
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
137
|
+
ledgerUnits,
|
|
138
|
+
);
|
|
139
|
+
assert.doesNotMatch(markers, /▼/, "completed: no ▼ when truncationSections=0");
|
|
140
|
+
assert.match(markers, /→ wrap-up/, "completed: shows → wrap-up");
|
|
141
|
+
}
|
|
267
142
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
143
|
+
// ─── Completed section: missing ledger match ──────────────────────────────────
|
|
144
|
+
|
|
145
|
+
test('Completed section: missing ledger match', () => {
|
|
146
|
+
// Completed unit with no matching ledger entry — no crash, no markers
|
|
147
|
+
const ledgerUnits = [
|
|
148
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T99", truncationSections: 3 }),
|
|
149
|
+
];
|
|
150
|
+
const markers = renderCompletedBudgetMarkers(
|
|
151
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
152
|
+
ledgerUnits,
|
|
153
|
+
);
|
|
154
|
+
assert.deepStrictEqual(markers, "", "missing match: empty markers when no ledger entry matches");
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
{
|
|
158
|
+
// Empty ledger — no crash, no markers
|
|
159
|
+
const markers = renderCompletedBudgetMarkers(
|
|
160
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
161
|
+
[],
|
|
162
|
+
);
|
|
163
|
+
assert.deepStrictEqual(markers, "", "empty ledger: empty markers");
|
|
164
|
+
}
|
|
278
165
|
|
|
279
|
-
// ───
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
166
|
+
// ─── Completed section: retry handling (last entry wins) ──────────────────────
|
|
167
|
+
|
|
168
|
+
test('Completed section: retry handling', () => {
|
|
169
|
+
// Two ledger entries for same unit (retry) — last entry wins
|
|
170
|
+
const ledgerUnits = [
|
|
171
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 1 }),
|
|
172
|
+
makeUnit({ type: "execute-task", id: "M001/S01/T01", truncationSections: 7 }),
|
|
173
|
+
];
|
|
174
|
+
const markers = renderCompletedBudgetMarkers(
|
|
175
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
176
|
+
ledgerUnits,
|
|
177
|
+
);
|
|
178
|
+
assert.match(markers, /▼7/, "retry: last entry's truncation count (7) wins over first (1)");
|
|
179
|
+
assert.doesNotMatch(markers, /▼1/, "retry: first entry's count (1) is not shown");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// ─── By Model section: context window display ─────────────────────────────────
|
|
183
|
+
|
|
184
|
+
test('By Model section: context window', () => {
|
|
185
|
+
// Model with context window — shows formatted token count
|
|
186
|
+
const units = [
|
|
187
|
+
makeUnit({ model: "claude-sonnet-4-20250514", contextWindowTokens: 200000 }),
|
|
188
|
+
];
|
|
189
|
+
const label = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
190
|
+
assert.deepStrictEqual(label, "[200.0k]", "by model: shows [200.0k] for 200000 context window");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
{
|
|
194
|
+
// Model without context window — no label
|
|
195
|
+
const units = [
|
|
196
|
+
makeUnit({ model: "claude-sonnet-4-20250514" }),
|
|
197
|
+
];
|
|
198
|
+
const label = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
199
|
+
assert.deepStrictEqual(label, null, "by model: null when no contextWindowTokens");
|
|
200
|
+
}
|
|
313
201
|
|
|
314
|
-
|
|
202
|
+
{
|
|
203
|
+
// Multiple models — each gets its own context window
|
|
204
|
+
const units = [
|
|
205
|
+
makeUnit({ model: "claude-sonnet-4-20250514", contextWindowTokens: 200000, cost: 0.05 }),
|
|
206
|
+
makeUnit({ model: "claude-opus-4-20250514", contextWindowTokens: 200000, cost: 0.30 }),
|
|
207
|
+
];
|
|
208
|
+
const sonnetLabel = renderModelContextWindow(units, "claude-sonnet-4-20250514");
|
|
209
|
+
const opusLabel = renderModelContextWindow(units, "claude-opus-4-20250514");
|
|
210
|
+
assert.deepStrictEqual(sonnetLabel, "[200.0k]", "by model multi: sonnet has context window");
|
|
211
|
+
assert.deepStrictEqual(opusLabel, "[200.0k]", "by model multi: opus has context window");
|
|
212
|
+
}
|
|
315
213
|
|
|
316
|
-
|
|
214
|
+
// ─── By Model section: single model visibility ───────────────────────────────
|
|
215
|
+
|
|
216
|
+
test('By Model section: single model visibility', () => {
|
|
217
|
+
// With guard changed to >= 1, single model aggregation should produce results
|
|
218
|
+
const units = [
|
|
219
|
+
makeUnit({ model: "claude-sonnet-4-20250514" }),
|
|
220
|
+
];
|
|
221
|
+
const models = aggregateByModel(units);
|
|
222
|
+
assert.ok(models.length >= 1, "single model: aggregateByModel returns >= 1 entry");
|
|
223
|
+
assert.deepStrictEqual(models.length, 1, "single model: exactly 1 model aggregate");
|
|
224
|
+
assert.deepStrictEqual(models[0].model, "claude-sonnet-4-20250514", "single model: correct model name");
|
|
225
|
+
// The guard `models.length >= 1` (changed from > 1) means this section now renders
|
|
226
|
+
assert.ok(models.length >= 1, "single model: passes >= 1 guard (section will render)");
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// ─── Cost & Usage: aggregate budget line ──────────────────────────────────────
|
|
230
|
+
|
|
231
|
+
test('Cost & Usage: aggregate budget line', () => {
|
|
232
|
+
// Units with truncation and continue-here — both stats appear
|
|
233
|
+
const units = [
|
|
234
|
+
makeUnit({ truncationSections: 3, continueHereFired: true }),
|
|
235
|
+
makeUnit({ truncationSections: 2, continueHereFired: false }),
|
|
236
|
+
makeUnit({ truncationSections: 1, continueHereFired: true }),
|
|
237
|
+
];
|
|
238
|
+
const line = renderCostBudgetLine(units);
|
|
239
|
+
assert.ok(line !== null, "cost budget: line rendered when budget data exists");
|
|
240
|
+
assert.match(line!, /6 sections truncated/, "cost budget: shows total truncation count (3+2+1=6)");
|
|
241
|
+
assert.match(line!, /2 continue-here fired/, "cost budget: shows continue-here count");
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
// Only truncation, no continue-here
|
|
246
|
+
const units = [
|
|
247
|
+
makeUnit({ truncationSections: 4, continueHereFired: false }),
|
|
248
|
+
];
|
|
249
|
+
const line = renderCostBudgetLine(units);
|
|
250
|
+
assert.ok(line !== null, "cost budget truncation-only: line rendered");
|
|
251
|
+
assert.match(line!, /4 sections truncated/, "cost budget truncation-only: shows count");
|
|
252
|
+
assert.doesNotMatch(line!, /continue-here/, "cost budget truncation-only: no continue-here text");
|
|
253
|
+
}
|
|
317
254
|
|
|
318
|
-
{
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
255
|
+
{
|
|
256
|
+
// Only continue-here, no truncation
|
|
257
|
+
const units = [
|
|
258
|
+
makeUnit({ truncationSections: 0, continueHereFired: true }),
|
|
259
|
+
];
|
|
260
|
+
const line = renderCostBudgetLine(units);
|
|
261
|
+
assert.ok(line !== null, "cost budget continue-only: line rendered");
|
|
262
|
+
assert.doesNotMatch(line!, /truncated/, "cost budget continue-only: no truncation text");
|
|
263
|
+
assert.match(line!, /1 continue-here fired/, "cost budget continue-only: shows count");
|
|
264
|
+
}
|
|
325
265
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
266
|
+
// ─── Backward compat: no budget fields ────────────────────────────────────────
|
|
267
|
+
|
|
268
|
+
test('Backward compat: no budget data', () => {
|
|
269
|
+
// Old-format units without budget fields — no indicators anywhere
|
|
270
|
+
const oldUnits = [
|
|
271
|
+
makeUnit(), // no budget fields
|
|
272
|
+
makeUnit({ id: "M001/S01/T02" }),
|
|
273
|
+
];
|
|
274
|
+
|
|
275
|
+
// Completed section: no markers
|
|
276
|
+
const markers = renderCompletedBudgetMarkers(
|
|
277
|
+
{ type: "execute-task", id: "M001/S01/T01" },
|
|
278
|
+
oldUnits,
|
|
279
|
+
);
|
|
280
|
+
assert.doesNotMatch(markers, /▼/, "backward compat completed: no truncation marker");
|
|
281
|
+
assert.doesNotMatch(markers, /wrap-up/, "backward compat completed: no wrap-up marker");
|
|
282
|
+
assert.deepStrictEqual(markers, "", "backward compat completed: empty markers string");
|
|
283
|
+
|
|
284
|
+
// By Model section: no context window label
|
|
285
|
+
const label = renderModelContextWindow(oldUnits, "claude-sonnet-4-20250514");
|
|
286
|
+
assert.deepStrictEqual(label, null, "backward compat by-model: no context window label");
|
|
287
|
+
|
|
288
|
+
// Cost & Usage: no budget line
|
|
289
|
+
const line = renderCostBudgetLine(oldUnits);
|
|
290
|
+
assert.deepStrictEqual(line, null, "backward compat cost: no budget summary line");
|
|
291
|
+
|
|
292
|
+
// Aggregation still works
|
|
293
|
+
const totals = getProjectTotals(oldUnits);
|
|
294
|
+
assert.deepStrictEqual(totals.totalTruncationSections, 0, "backward compat: truncation total = 0");
|
|
295
|
+
assert.deepStrictEqual(totals.continueHereFiredCount, 0, "backward compat: continueHere count = 0");
|
|
296
|
+
assert.deepStrictEqual(totals.units, 2, "backward compat: unit count correct");
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// ─── Edge cases ───────────────────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
test('Edge cases', () => {
|
|
302
|
+
// formatTokenCount for context window values
|
|
303
|
+
assert.deepStrictEqual(formatTokenCount(200000), "200.0k", "format: 200000 → 200.0k");
|
|
304
|
+
assert.deepStrictEqual(formatTokenCount(128000), "128.0k", "format: 128000 → 128.0k");
|
|
305
|
+
assert.deepStrictEqual(formatTokenCount(1000000), "1.00M", "format: 1000000 → 1.00M");
|
|
306
|
+
assert.deepStrictEqual(formatTokenCount(32000), "32.0k", "format: 32000 → 32.0k");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
{
|
|
310
|
+
// Completed unit key includes type — different types don't collide
|
|
311
|
+
const ledgerUnits = [
|
|
312
|
+
makeUnit({ type: "research-slice", id: "M001/S01", truncationSections: 2 }),
|
|
313
|
+
makeUnit({ type: "plan-slice", id: "M001/S01", truncationSections: 5 }),
|
|
314
|
+
];
|
|
315
|
+
const researchMarkers = renderCompletedBudgetMarkers(
|
|
316
|
+
{ type: "research-slice", id: "M001/S01" },
|
|
317
|
+
ledgerUnits,
|
|
318
|
+
);
|
|
319
|
+
const planMarkers = renderCompletedBudgetMarkers(
|
|
320
|
+
{ type: "plan-slice", id: "M001/S01" },
|
|
321
|
+
ledgerUnits,
|
|
322
|
+
);
|
|
323
|
+
assert.match(researchMarkers, /▼2/, "type-keying: research unit gets its own truncation count");
|
|
324
|
+
assert.match(planMarkers, /▼5/, "type-keying: plan unit gets its own truncation count");
|
|
325
|
+
}
|
|
343
326
|
|
|
344
|
-
// ─── Summary ──────────────────────────────────────────────────────────────────
|
|
327
|
+
// ─── Summary ──────────────────────────────────────────────────────────────────
|
|
345
328
|
|
|
346
|
-
|
|
329
|
+
});
|