gsd-pi 2.80.0-dev.2848d9009 → 2.80.0-dev.3065f7bfa
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 +4 -2
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +32 -1
- package/dist/resources/extensions/gsd/auto/phases.js +178 -108
- package/dist/resources/extensions/gsd/auto/resolve.js +17 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +20 -30
- package/dist/resources/extensions/gsd/auto/session.js +8 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -4
- package/dist/resources/extensions/gsd/auto-prompts.js +103 -16
- package/dist/resources/extensions/gsd/auto-recovery.js +43 -1
- package/dist/resources/extensions/gsd/auto-start.js +197 -6
- package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +111 -1
- package/dist/resources/extensions/gsd/auto.js +86 -26
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +42 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +49 -36
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +33 -20
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +7 -1
- package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +259 -28
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
- package/dist/resources/extensions/gsd/clean-root-preflight.js +24 -6
- package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
- package/dist/resources/extensions/gsd/context-budget.js +37 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
- package/dist/resources/extensions/gsd/db/unit-dispatches.js +39 -0
- package/dist/resources/extensions/gsd/db-base-schema.js +4 -2
- package/dist/resources/extensions/gsd/db-migration-steps.js +6 -0
- package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
- package/dist/resources/extensions/gsd/git-service.js +36 -4
- package/dist/resources/extensions/gsd/gsd-db.js +46 -13
- package/dist/resources/extensions/gsd/guided-flow.js +99 -38
- package/dist/resources/extensions/gsd/memory-store.js +69 -12
- package/dist/resources/extensions/gsd/migrate/command.js +40 -1
- package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +32 -8
- package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
- package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
- package/dist/resources/extensions/gsd/pre-execution-checks.js +22 -0
- package/dist/resources/extensions/gsd/prompt-loader.js +28 -2
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/dist/resources/extensions/gsd/quick.js +34 -2
- package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
- package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
- package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +1 -1
- package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
- package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
- package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +68 -21
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +3 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +22 -17
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
- package/packages/mcp-server/src/workflow-tools.ts +30 -16
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/index.d.ts +1 -0
- package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/index.js +2 -0
- package/packages/pi-agent-core/dist/index.js.map +1 -1
- package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
- package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
- package/packages/pi-agent-core/dist/token-audit.js +221 -0
- package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
- package/packages/pi-agent-core/dist/types.d.ts +9 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-agent-core/src/agent.ts +8 -0
- package/packages/pi-agent-core/src/index.ts +2 -0
- package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
- package/packages/pi-agent-core/src/token-audit.ts +287 -0
- package/packages/pi-agent-core/src/types.ts +14 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +32 -0
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +18 -0
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +44 -7
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
- package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
- package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
- package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.js +6 -6
- package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +5 -3
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +39 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
- package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +74 -2
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +20 -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 +25 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
- package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +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 +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.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 +13 -5
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +53 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.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 +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +10 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +36 -0
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +25 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +48 -7
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +3 -1
- package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
- package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
- package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +5 -3
- package/packages/pi-coding-agent/src/core/extensions/runner.ts +8 -5
- package/packages/pi-coding-agent/src/core/extensions/types.ts +42 -1
- package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
- package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +85 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +39 -1
- package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +4 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +22 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +3 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +14 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +18 -8
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/tui.ts +20 -8
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -2
- package/src/resources/extensions/gsd/auto/loop.ts +50 -8
- package/src/resources/extensions/gsd/auto/phases.ts +251 -172
- package/src/resources/extensions/gsd/auto/resolve.ts +23 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +25 -30
- package/src/resources/extensions/gsd/auto/session.ts +8 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
- package/src/resources/extensions/gsd/auto-dispatch.ts +16 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -4
- package/src/resources/extensions/gsd/auto-prompts.ts +112 -15
- package/src/resources/extensions/gsd/auto-recovery.ts +54 -0
- package/src/resources/extensions/gsd/auto-start.ts +230 -9
- package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +123 -0
- package/src/resources/extensions/gsd/auto.ts +98 -21
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +49 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +50 -36
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +16 -5
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +34 -19
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +8 -1
- package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +10 -3
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +9 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +305 -28
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
- package/src/resources/extensions/gsd/clean-root-preflight.ts +32 -7
- package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
- package/src/resources/extensions/gsd/context-budget.ts +44 -2
- package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
- package/src/resources/extensions/gsd/db/unit-dispatches.ts +41 -0
- package/src/resources/extensions/gsd/db-base-schema.ts +4 -2
- package/src/resources/extensions/gsd/db-migration-steps.ts +8 -0
- package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
- package/src/resources/extensions/gsd/git-service.ts +46 -8
- package/src/resources/extensions/gsd/gsd-db.ts +50 -13
- package/src/resources/extensions/gsd/guided-flow.ts +123 -45
- package/src/resources/extensions/gsd/memory-store.ts +77 -12
- package/src/resources/extensions/gsd/migrate/command.ts +47 -1
- package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +39 -6
- package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
- package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
- package/src/resources/extensions/gsd/pre-execution-checks.ts +23 -0
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompt-loader.ts +27 -2
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +16 -13
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
- package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -2
- package/src/resources/extensions/gsd/quick.ts +37 -2
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +417 -10
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +56 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +168 -6
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +15 -6
- package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
- package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +239 -1
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
- package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
- package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +38 -17
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +291 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +136 -4
- package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +167 -4
- package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
- package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
- package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
- package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +1 -1
- package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
- package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
- package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +85 -19
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +0 -97
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vaQ47E8aNlbbNEDoeME6G → O2WvnXROue6l7nAp_4dhC}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for opt-in GSD tool surface reduction.
|
|
3
|
+
|
|
4
|
+
import assert from "node:assert/strict";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import { buildMinimalAutoGsdToolSet, buildMinimalGsdToolSet, buildMinimalGsdWorkflowToolSet, buildRequestScopedGsdToolSet, MINIMAL_AUTO_BASE_TOOL_NAMES, MINIMAL_GSD_TOOL_NAMES, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "../bootstrap/register-hooks.ts";
|
|
8
|
+
|
|
9
|
+
test("buildMinimalGsdToolSet preserves non-GSD tools and replaces broad GSD surface", () => {
|
|
10
|
+
const result = buildMinimalGsdToolSet([
|
|
11
|
+
"bash",
|
|
12
|
+
"read",
|
|
13
|
+
"browser_open",
|
|
14
|
+
"gsd_plan_milestone",
|
|
15
|
+
"gsd_task_complete",
|
|
16
|
+
"gsd_exec",
|
|
17
|
+
"gsd_exec_search",
|
|
18
|
+
"gsd_resume",
|
|
19
|
+
"gsd_milestone_status",
|
|
20
|
+
"gsd_checkpoint_db",
|
|
21
|
+
"memory_query",
|
|
22
|
+
"capture_thought",
|
|
23
|
+
"gsd_graph",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
assert.ok(result.includes("bash"));
|
|
27
|
+
assert.ok(result.includes("read"));
|
|
28
|
+
assert.ok(result.includes("browser_open"));
|
|
29
|
+
for (const toolName of MINIMAL_GSD_TOOL_NAMES) {
|
|
30
|
+
assert.ok(result.includes(toolName), `expected ${toolName}`);
|
|
31
|
+
}
|
|
32
|
+
assert.ok(!result.includes("gsd_plan_milestone"));
|
|
33
|
+
assert.ok(!result.includes("gsd_task_complete"));
|
|
34
|
+
assert.ok(!result.includes("gsd_graph"));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("buildMinimalGsdToolSet deduplicates preserved and minimal tools", () => {
|
|
38
|
+
const result = buildMinimalGsdToolSet(["bash", "bash", "memory_query"]);
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(result.filter((toolName) => toolName === "bash"), ["bash"]);
|
|
41
|
+
assert.deepEqual(result.filter((toolName) => toolName === "memory_query"), ["memory_query"]);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("buildMinimalGsdToolSet does not reintroduce provider-filtered GSD tools", () => {
|
|
45
|
+
const result = buildMinimalGsdToolSet(["bash", "read", "memory_query"]);
|
|
46
|
+
|
|
47
|
+
assert.deepEqual(result, ["bash", "read", "memory_query"]);
|
|
48
|
+
assert.ok(!result.includes("gsd_exec"));
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("buildMinimalAutoGsdToolSet keeps unit-specific completion tools without aliases", () => {
|
|
52
|
+
const result = buildMinimalAutoGsdToolSet([
|
|
53
|
+
"ask_user_questions",
|
|
54
|
+
"bash",
|
|
55
|
+
"read",
|
|
56
|
+
"lsp",
|
|
57
|
+
"browser_click",
|
|
58
|
+
"gsd_task_complete",
|
|
59
|
+
"gsd_complete_task",
|
|
60
|
+
"gsd_exec",
|
|
61
|
+
"gsd_exec_search",
|
|
62
|
+
"gsd_resume",
|
|
63
|
+
"gsd_milestone_status",
|
|
64
|
+
"gsd_checkpoint_db",
|
|
65
|
+
"gsd_slice_complete",
|
|
66
|
+
"gsd_complete_slice",
|
|
67
|
+
"memory_query",
|
|
68
|
+
"capture_thought",
|
|
69
|
+
], "execute-task");
|
|
70
|
+
|
|
71
|
+
assert.ok(result.includes("ask_user_questions"));
|
|
72
|
+
assert.ok(result.includes("bash"));
|
|
73
|
+
assert.ok(result.includes("read"));
|
|
74
|
+
assert.ok(result.includes("gsd_task_complete"));
|
|
75
|
+
assert.ok(result.includes("memory_query"));
|
|
76
|
+
assert.ok(!result.includes("lsp"));
|
|
77
|
+
assert.ok(!result.includes("browser_click"));
|
|
78
|
+
assert.ok(!result.includes("gsd_complete_task"));
|
|
79
|
+
assert.ok(!result.includes("gsd_slice_complete"));
|
|
80
|
+
assert.ok(!result.includes("gsd_complete_slice"));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("buildMinimalAutoGsdToolSet keeps only the auto base non-GSD tools", () => {
|
|
84
|
+
const result = buildMinimalAutoGsdToolSet([
|
|
85
|
+
"ask_user_questions",
|
|
86
|
+
"bash",
|
|
87
|
+
"bg_shell",
|
|
88
|
+
"browser_wait_for",
|
|
89
|
+
"edit",
|
|
90
|
+
"glob",
|
|
91
|
+
"grep",
|
|
92
|
+
"lsp",
|
|
93
|
+
"ls",
|
|
94
|
+
"mac_find",
|
|
95
|
+
"read",
|
|
96
|
+
"subagent",
|
|
97
|
+
"write",
|
|
98
|
+
"gsd_exec",
|
|
99
|
+
"gsd_exec_search",
|
|
100
|
+
"gsd_resume",
|
|
101
|
+
"gsd_milestone_status",
|
|
102
|
+
"gsd_checkpoint_db",
|
|
103
|
+
"memory_query",
|
|
104
|
+
"capture_thought",
|
|
105
|
+
], "execute-task");
|
|
106
|
+
|
|
107
|
+
for (const toolName of MINIMAL_AUTO_BASE_TOOL_NAMES) {
|
|
108
|
+
assert.ok(result.includes(toolName), `expected ${toolName}`);
|
|
109
|
+
}
|
|
110
|
+
assert.ok(!result.includes("browser_wait_for"));
|
|
111
|
+
assert.ok(!result.includes("lsp"));
|
|
112
|
+
assert.ok(!result.includes("mac_find"));
|
|
113
|
+
assert.ok(!result.includes("subagent"));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("buildMinimalAutoGsdToolSet includes closeout tool for complete-slice", () => {
|
|
117
|
+
const result = buildMinimalAutoGsdToolSet([
|
|
118
|
+
"bash",
|
|
119
|
+
"read",
|
|
120
|
+
"subagent",
|
|
121
|
+
"gsd_exec",
|
|
122
|
+
"gsd_exec_search",
|
|
123
|
+
"gsd_resume",
|
|
124
|
+
"gsd_milestone_status",
|
|
125
|
+
"gsd_checkpoint_db",
|
|
126
|
+
"gsd_task_complete",
|
|
127
|
+
"gsd_slice_complete",
|
|
128
|
+
"gsd_complete_slice",
|
|
129
|
+
"memory_query",
|
|
130
|
+
"capture_thought",
|
|
131
|
+
], "complete-slice");
|
|
132
|
+
|
|
133
|
+
assert.ok(result.includes("gsd_slice_complete"));
|
|
134
|
+
assert.ok(result.includes("subagent"));
|
|
135
|
+
assert.ok(result.includes("capture_thought"));
|
|
136
|
+
assert.ok(!result.includes("gsd_task_complete"));
|
|
137
|
+
assert.ok(!result.includes("gsd_complete_slice"));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("buildMinimalAutoGsdToolSet covers execute-task-simple", () => {
|
|
141
|
+
const result = buildMinimalAutoGsdToolSet([
|
|
142
|
+
"bash",
|
|
143
|
+
"read",
|
|
144
|
+
"gsd_task_complete",
|
|
145
|
+
"gsd_decision_save",
|
|
146
|
+
"gsd_plan_task",
|
|
147
|
+
"memory_query",
|
|
148
|
+
"capture_thought",
|
|
149
|
+
], "execute-task-simple");
|
|
150
|
+
|
|
151
|
+
assert.ok(result.includes("gsd_task_complete"));
|
|
152
|
+
assert.ok(result.includes("gsd_decision_save"));
|
|
153
|
+
assert.ok(!result.includes("gsd_plan_task"));
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("buildMinimalGsdWorkflowToolSet keeps workflow GSD tools but drops broad non-GSD tools", () => {
|
|
157
|
+
const result = buildMinimalGsdWorkflowToolSet([
|
|
158
|
+
"ask_user_questions",
|
|
159
|
+
"bash",
|
|
160
|
+
"bg_shell",
|
|
161
|
+
"browser_wait_for",
|
|
162
|
+
"edit",
|
|
163
|
+
"lsp",
|
|
164
|
+
"mac_find",
|
|
165
|
+
"read",
|
|
166
|
+
"subagent",
|
|
167
|
+
"write",
|
|
168
|
+
"gsd_plan_milestone",
|
|
169
|
+
"gsd_complete_milestone",
|
|
170
|
+
"gsd_task_complete",
|
|
171
|
+
"gsd_summary_save",
|
|
172
|
+
"memory_query",
|
|
173
|
+
"capture_thought",
|
|
174
|
+
"gsd_exec",
|
|
175
|
+
"gsd_exec_search",
|
|
176
|
+
"gsd_resume",
|
|
177
|
+
"gsd_milestone_status",
|
|
178
|
+
"gsd_checkpoint_db",
|
|
179
|
+
"gsd_graph",
|
|
180
|
+
]);
|
|
181
|
+
|
|
182
|
+
assert.ok(result.includes("ask_user_questions"));
|
|
183
|
+
assert.ok(result.includes("bash"));
|
|
184
|
+
assert.ok(result.includes("bg_shell"));
|
|
185
|
+
assert.ok(result.includes("read"));
|
|
186
|
+
assert.ok(result.includes("write"));
|
|
187
|
+
assert.ok(result.includes("gsd_plan_milestone"));
|
|
188
|
+
assert.ok(result.includes("gsd_complete_milestone"));
|
|
189
|
+
assert.ok(result.includes("gsd_task_complete"));
|
|
190
|
+
assert.ok(result.includes("gsd_summary_save"));
|
|
191
|
+
assert.ok(!result.includes("browser_wait_for"));
|
|
192
|
+
assert.ok(!result.includes("lsp"));
|
|
193
|
+
assert.ok(!result.includes("mac_find"));
|
|
194
|
+
assert.ok(!result.includes("subagent"));
|
|
195
|
+
assert.ok(!result.includes("gsd_graph"));
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test("buildRequestScopedGsdToolSet scopes queued workflow custom-message requests", () => {
|
|
199
|
+
const result = buildRequestScopedGsdToolSet([
|
|
200
|
+
"ask_user_questions",
|
|
201
|
+
"bash",
|
|
202
|
+
"browser_wait_for",
|
|
203
|
+
"lsp",
|
|
204
|
+
"read",
|
|
205
|
+
"write",
|
|
206
|
+
"gsd_plan_milestone",
|
|
207
|
+
"gsd_complete_milestone",
|
|
208
|
+
"gsd_task_complete",
|
|
209
|
+
"gsd_graph",
|
|
210
|
+
"memory_query",
|
|
211
|
+
"capture_thought",
|
|
212
|
+
], [{ customType: "gsd-run" }, { customType: "gsd-memory" }]);
|
|
213
|
+
|
|
214
|
+
assert.ok(result);
|
|
215
|
+
assert.ok(result.includes("ask_user_questions"));
|
|
216
|
+
assert.ok(result.includes("bash"));
|
|
217
|
+
assert.ok(result.includes("read"));
|
|
218
|
+
assert.ok(result.includes("write"));
|
|
219
|
+
assert.ok(result.includes("gsd_plan_milestone"));
|
|
220
|
+
assert.ok(result.includes("gsd_complete_milestone"));
|
|
221
|
+
assert.ok(!result.includes("browser_wait_for"));
|
|
222
|
+
assert.ok(!result.includes("lsp"));
|
|
223
|
+
assert.ok(!result.includes("gsd_graph"));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("buildRequestScopedGsdToolSet ignores stale workflow messages outside the current request tail", () => {
|
|
227
|
+
assert.equal(buildRequestScopedGsdToolSet(["bash", "gsd_plan_milestone"], []), undefined);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("scopeGsdWorkflowToolsForDispatch applies and restores per-unit skill visibility", () => {
|
|
231
|
+
const calls: Array<{ kind: "tools" | "skills"; value: string[] | undefined }> = [];
|
|
232
|
+
let activeTools = [
|
|
233
|
+
"bash",
|
|
234
|
+
"read",
|
|
235
|
+
"lsp",
|
|
236
|
+
"gsd_plan_milestone",
|
|
237
|
+
"gsd_decision_save",
|
|
238
|
+
"memory_query",
|
|
239
|
+
"capture_thought",
|
|
240
|
+
];
|
|
241
|
+
let visibleSkills: string[] | undefined = ["previous-skill"];
|
|
242
|
+
|
|
243
|
+
const state = scopeGsdWorkflowToolsForDispatch({
|
|
244
|
+
getActiveTools: () => activeTools,
|
|
245
|
+
setActiveTools: (names) => {
|
|
246
|
+
activeTools = names;
|
|
247
|
+
calls.push({ kind: "tools", value: names });
|
|
248
|
+
},
|
|
249
|
+
getVisibleSkills: () => visibleSkills,
|
|
250
|
+
setVisibleSkills: (names) => {
|
|
251
|
+
visibleSkills = names;
|
|
252
|
+
calls.push({ kind: "skills", value: names });
|
|
253
|
+
},
|
|
254
|
+
}, "plan-milestone");
|
|
255
|
+
|
|
256
|
+
assert.ok(state);
|
|
257
|
+
assert.deepEqual(visibleSkills, [
|
|
258
|
+
"write-milestone-brief",
|
|
259
|
+
"decompose-into-slices",
|
|
260
|
+
"design-an-interface",
|
|
261
|
+
"grill-me",
|
|
262
|
+
"write-docs",
|
|
263
|
+
"api-design",
|
|
264
|
+
"tdd",
|
|
265
|
+
"verify-before-complete",
|
|
266
|
+
]);
|
|
267
|
+
assert.ok(!activeTools.includes("lsp"));
|
|
268
|
+
|
|
269
|
+
restoreGsdWorkflowTools({
|
|
270
|
+
setActiveTools: (names) => {
|
|
271
|
+
activeTools = names;
|
|
272
|
+
calls.push({ kind: "tools", value: names });
|
|
273
|
+
},
|
|
274
|
+
setVisibleSkills: (names) => {
|
|
275
|
+
visibleSkills = names;
|
|
276
|
+
calls.push({ kind: "skills", value: names });
|
|
277
|
+
},
|
|
278
|
+
}, state);
|
|
279
|
+
|
|
280
|
+
assert.deepEqual(activeTools, [
|
|
281
|
+
"bash",
|
|
282
|
+
"read",
|
|
283
|
+
"lsp",
|
|
284
|
+
"gsd_plan_milestone",
|
|
285
|
+
"gsd_decision_save",
|
|
286
|
+
"memory_query",
|
|
287
|
+
"capture_thought",
|
|
288
|
+
]);
|
|
289
|
+
assert.deepEqual(visibleSkills, ["previous-skill"]);
|
|
290
|
+
assert.equal(calls.filter((call) => call.kind === "skills").length, 2);
|
|
291
|
+
});
|
|
@@ -21,12 +21,18 @@ import type {
|
|
|
21
21
|
ComputedArtifactRegistry,
|
|
22
22
|
UnitContextManifest,
|
|
23
23
|
} from "../unit-context-manifest.ts";
|
|
24
|
-
import { UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
-
import {
|
|
24
|
+
import { KNOWN_UNIT_TYPES, UNIT_MANIFESTS } from "../unit-context-manifest.ts";
|
|
25
|
+
import {
|
|
26
|
+
buildExecuteTaskPrompt,
|
|
27
|
+
buildGateEvaluatePrompt,
|
|
28
|
+
buildReassessRoadmapPrompt,
|
|
29
|
+
buildWorkflowPreferencesPrompt,
|
|
30
|
+
} from "../auto-prompts.ts";
|
|
26
31
|
import { invalidateAllCaches } from "../cache.ts";
|
|
27
32
|
import {
|
|
28
33
|
openDatabase,
|
|
29
34
|
closeDatabase,
|
|
35
|
+
insertGateRow,
|
|
30
36
|
insertMilestone,
|
|
31
37
|
upsertMilestonePlanning,
|
|
32
38
|
insertSlice,
|
|
@@ -121,7 +127,7 @@ test("Context Mode composer: standalone output starts with heading and includes
|
|
|
121
127
|
assert.ok(out.startsWith("## Context Mode"));
|
|
122
128
|
assert.match(out, /execution lane/i);
|
|
123
129
|
assert.match(out, /`gsd_exec`/);
|
|
124
|
-
assert.match(out, /
|
|
130
|
+
assert.match(out, /builds, tests, and diagnostics/);
|
|
125
131
|
assert.match(out, /`gsd_exec_search`/);
|
|
126
132
|
assert.match(out, /before reruns/);
|
|
127
133
|
assert.match(out, /`gsd_resume`/);
|
|
@@ -136,7 +142,45 @@ test("Context Mode composer: nested output is compact single sentence", () => {
|
|
|
136
142
|
assert.match(out, /`gsd_exec`/);
|
|
137
143
|
assert.match(out, /`gsd_exec_search`/);
|
|
138
144
|
assert.match(out, /`gsd_resume`/);
|
|
139
|
-
assert.ok(out.length <
|
|
145
|
+
assert.ok(out.length < 240, `nested guidance should stay compact, got ${out.length} chars`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const laneLabelByMode: Record<string, string> = {
|
|
149
|
+
interview: "interview",
|
|
150
|
+
research: "research",
|
|
151
|
+
planning: "planning",
|
|
152
|
+
execution: "execution",
|
|
153
|
+
verification: "verification",
|
|
154
|
+
orchestration: "orchestration",
|
|
155
|
+
docs: "documentation",
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
test("Context Mode composer: every known eligible unit renders its configured lane and required tools", () => {
|
|
159
|
+
for (const unitType of KNOWN_UNIT_TYPES) {
|
|
160
|
+
const manifest = UNIT_MANIFESTS[unitType];
|
|
161
|
+
assert.ok(manifest, `missing manifest for ${unitType}`);
|
|
162
|
+
const out = composeContextModeInstructions(unitType, { enabled: true, renderMode: "standalone" });
|
|
163
|
+
if (manifest.contextMode === "none") {
|
|
164
|
+
assert.strictEqual(out, "", `${unitType} should not render Context Mode`);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
assert.ok(out.startsWith("## Context Mode"), `${unitType} should render standalone Context Mode heading`);
|
|
168
|
+
assert.match(out, new RegExp(`Lane: \\*\\*${laneLabelByMode[manifest.contextMode]} lane\\*\\*\\.`, "i"));
|
|
169
|
+
assert.match(out, /`gsd_exec`/, `${unitType} should mention gsd_exec`);
|
|
170
|
+
assert.match(out, /`gsd_exec_search`/, `${unitType} should mention gsd_exec_search`);
|
|
171
|
+
assert.match(out, /`gsd_resume`/, `${unitType} should mention gsd_resume`);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("Context Mode composer: workflow-preferences and research-decision render no Context Mode block", () => {
|
|
176
|
+
assert.strictEqual(
|
|
177
|
+
composeContextModeInstructions("workflow-preferences", { enabled: true, renderMode: "standalone" }),
|
|
178
|
+
"",
|
|
179
|
+
);
|
|
180
|
+
assert.strictEqual(
|
|
181
|
+
composeContextModeInstructions("research-decision", { enabled: true, renderMode: "standalone" }),
|
|
182
|
+
"",
|
|
183
|
+
);
|
|
140
184
|
});
|
|
141
185
|
|
|
142
186
|
// ─── Integration: migrated buildReassessRoadmapPrompt ─────────────────────
|
|
@@ -220,6 +264,94 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
|
|
|
220
264
|
assert.ok(!prompt.includes("Slice Context (from discussion)"));
|
|
221
265
|
});
|
|
222
266
|
|
|
267
|
+
test("Context Mode resume injection: eligible prompts include one bounded snapshot block above inlined context", async (t) => {
|
|
268
|
+
const base = makeFixtureBase();
|
|
269
|
+
t.after(() => cleanup(base));
|
|
270
|
+
invalidateAllCaches();
|
|
271
|
+
|
|
272
|
+
seed(base, "M001");
|
|
273
|
+
writeArtifacts(base);
|
|
274
|
+
writeFileSync(
|
|
275
|
+
join(base, ".gsd", "last-snapshot.md"),
|
|
276
|
+
"# GSD context snapshot\n\nResume evidence.\n",
|
|
277
|
+
"utf-8",
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
281
|
+
|
|
282
|
+
assert.equal(prompt.match(/## Context Snapshot/g)?.length, 1);
|
|
283
|
+
assert.match(prompt, /Source: `\.gsd\/last-snapshot\.md`/);
|
|
284
|
+
assert.match(prompt, /Resume evidence/);
|
|
285
|
+
assert.ok(prompt.indexOf("## Context Mode") < prompt.indexOf("## Context Snapshot"));
|
|
286
|
+
assert.ok(prompt.indexOf("## Context Snapshot") < prompt.indexOf("## Inlined Context"));
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("Context Mode resume injection: missing snapshot does not add an empty block", async (t) => {
|
|
290
|
+
const base = makeFixtureBase();
|
|
291
|
+
t.after(() => cleanup(base));
|
|
292
|
+
invalidateAllCaches();
|
|
293
|
+
|
|
294
|
+
seed(base, "M001");
|
|
295
|
+
writeArtifacts(base);
|
|
296
|
+
|
|
297
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
298
|
+
|
|
299
|
+
assert.match(prompt, /## Context Mode/);
|
|
300
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("Context Mode resume injection: disabled mode suppresses guidance and snapshot reads", async (t) => {
|
|
304
|
+
const base = makeFixtureBase();
|
|
305
|
+
t.after(() => cleanup(base));
|
|
306
|
+
invalidateAllCaches();
|
|
307
|
+
|
|
308
|
+
seed(base, "M001");
|
|
309
|
+
writeArtifacts(base);
|
|
310
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
311
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
312
|
+
|
|
313
|
+
const prompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
314
|
+
|
|
315
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
316
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
317
|
+
assert.doesNotMatch(prompt, /Do not inject/);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("Context Mode resume injection: none-mode units do not inject snapshots", async () => {
|
|
321
|
+
const base = makeFixtureBase();
|
|
322
|
+
try {
|
|
323
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nNo lane.\n", "utf-8");
|
|
324
|
+
const prompt = await buildWorkflowPreferencesPrompt(base);
|
|
325
|
+
assert.doesNotMatch(prompt, /## Context Mode/);
|
|
326
|
+
assert.doesNotMatch(prompt, /## Context Snapshot/);
|
|
327
|
+
assert.doesNotMatch(prompt, /No lane/);
|
|
328
|
+
} finally {
|
|
329
|
+
cleanup(base);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test("Context Mode prompt suppression: disabled inlined, phase-anchor, and nested prompts omit Context Mode", async (t) => {
|
|
334
|
+
const base = makeFixtureBase();
|
|
335
|
+
t.after(() => cleanup(base));
|
|
336
|
+
invalidateAllCaches();
|
|
337
|
+
|
|
338
|
+
seed(base, "M001");
|
|
339
|
+
writeArtifacts(base);
|
|
340
|
+
insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
|
|
341
|
+
writeFileSync(join(base, ".gsd", "PREFERENCES.md"), "---\ncontext_mode:\n enabled: false\n---\n", "utf-8");
|
|
342
|
+
writeFileSync(join(base, ".gsd", "last-snapshot.md"), "# GSD context snapshot\n\nDo not inject.\n", "utf-8");
|
|
343
|
+
|
|
344
|
+
const inlinedPrompt = await buildReassessRoadmapPrompt("M001", "Test", "S01", base);
|
|
345
|
+
assert.doesNotMatch(inlinedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
346
|
+
|
|
347
|
+
const phaseAnchorPrompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
|
|
348
|
+
assert.doesNotMatch(phaseAnchorPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
349
|
+
|
|
350
|
+
const nestedPrompt = await buildGateEvaluatePrompt("M001", "Test", "S01", "First", base);
|
|
351
|
+
assert.match(nestedPrompt, /Use this as the prompt for a `subagent` call/);
|
|
352
|
+
assert.doesNotMatch(nestedPrompt, /## Context Mode|Context Mode \(|## Context Snapshot/);
|
|
353
|
+
});
|
|
354
|
+
|
|
223
355
|
// ─── v2 surface (#4924) ───────────────────────────────────────────────────
|
|
224
356
|
|
|
225
357
|
const fakeBase: BaseResolverContext = {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
markFailed,
|
|
22
22
|
markStuck,
|
|
23
23
|
markCanceled,
|
|
24
|
+
markLatestActiveForWorkerCanceled,
|
|
24
25
|
getRecentForUnit,
|
|
25
26
|
getLatestForUnit,
|
|
26
27
|
} from "../db/unit-dispatches.ts";
|
|
@@ -196,6 +197,35 @@ test("markStuck and markCanceled set their respective statuses", (t) => {
|
|
|
196
197
|
assert.equal(getLatestForUnit("M001/S01/T01")!.status, "canceled");
|
|
197
198
|
});
|
|
198
199
|
|
|
200
|
+
test("markLatestActiveForWorkerCanceled cancels only the latest active dispatch for a worker", (t) => {
|
|
201
|
+
const base = makeBase();
|
|
202
|
+
t.after(() => cleanup(base));
|
|
203
|
+
const { workerId, leaseToken } = setup(base);
|
|
204
|
+
|
|
205
|
+
const first = recordDispatchClaim({
|
|
206
|
+
traceId: "tc-1", workerId, milestoneLeaseToken: leaseToken,
|
|
207
|
+
milestoneId: "M001", unitType: "plan-slice", unitId: "M001/S01",
|
|
208
|
+
});
|
|
209
|
+
assert.equal(first.ok, true);
|
|
210
|
+
if (!first.ok) return;
|
|
211
|
+
markCompleted(first.dispatchId);
|
|
212
|
+
|
|
213
|
+
const second = recordDispatchClaim({
|
|
214
|
+
traceId: "tc-2", workerId, milestoneLeaseToken: leaseToken,
|
|
215
|
+
milestoneId: "M001", unitType: "run-task", unitId: "M001/S01/T01",
|
|
216
|
+
});
|
|
217
|
+
assert.equal(second.ok, true);
|
|
218
|
+
if (!second.ok) return;
|
|
219
|
+
markRunning(second.dispatchId);
|
|
220
|
+
|
|
221
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), true);
|
|
222
|
+
assert.equal(getLatestForUnit("M001/S01")!.status, "completed");
|
|
223
|
+
const latest = getLatestForUnit("M001/S01/T01")!;
|
|
224
|
+
assert.equal(latest.status, "canceled");
|
|
225
|
+
assert.equal(latest.exit_reason, "signal-exit");
|
|
226
|
+
assert.equal(markLatestActiveForWorkerCanceled(workerId, "signal-exit"), false);
|
|
227
|
+
});
|
|
228
|
+
|
|
199
229
|
test("terminal transitions do not overwrite an already terminal dispatch", (t) => {
|
|
200
230
|
const base = makeBase();
|
|
201
231
|
t.after(() => cleanup(base));
|
|
@@ -5,9 +5,11 @@ import {
|
|
|
5
5
|
clearUnitRuntimeRecord,
|
|
6
6
|
formatExecuteTaskRecoveryStatus,
|
|
7
7
|
inspectExecuteTaskDurability,
|
|
8
|
+
isInFlightRuntimePhase,
|
|
8
9
|
readUnitRuntimeRecord,
|
|
9
10
|
writeUnitRuntimeRecord,
|
|
10
11
|
} from "../unit-runtime.ts";
|
|
12
|
+
import { closeDatabase, insertMilestone, insertSlice, insertTask, openDatabase } from "../gsd-db.ts";
|
|
11
13
|
import { clearPathCache } from '../paths.ts';
|
|
12
14
|
import { test } from 'node:test';
|
|
13
15
|
import assert from 'node:assert/strict';
|
|
@@ -22,6 +24,12 @@ writeFileSync(
|
|
|
22
24
|
"utf-8",
|
|
23
25
|
);
|
|
24
26
|
|
|
27
|
+
console.log("\n=== in-flight runtime phases ===");
|
|
28
|
+
{
|
|
29
|
+
assert.equal(isInFlightRuntimePhase("crashed"), true, "crashed records remain recoverable");
|
|
30
|
+
assert.equal(isInFlightRuntimePhase("finalized"), false, "finalized records are terminal");
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
console.log("\n=== runtime record write/read/update ===");
|
|
26
34
|
{
|
|
27
35
|
const first = writeUnitRuntimeRecord(base, "execute-task", "M100/S02/T09", 1000, { phase: "dispatched" });
|
|
@@ -65,6 +73,35 @@ console.log("\n=== runtime record cleanup ===");
|
|
|
65
73
|
assert.deepStrictEqual(loaded, null, "record removed");
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
console.log("\n=== execute-task durability trusts closed DB task status ===");
|
|
77
|
+
{
|
|
78
|
+
const dbBase = mkdtempSync(join(tmpdir(), "gsd-unit-runtime-db-test-"));
|
|
79
|
+
mkdirSync(join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "tasks"), { recursive: true });
|
|
80
|
+
try {
|
|
81
|
+
openDatabase(join(dbBase, ".gsd", "gsd.db"));
|
|
82
|
+
insertMilestone({ id: "M300", title: "DB Milestone", status: "active" });
|
|
83
|
+
insertSlice({ id: "S01", milestoneId: "M300", title: "DB Slice", status: "in_progress" });
|
|
84
|
+
insertTask({ id: "T01", milestoneId: "M300", sliceId: "S01", title: "DB Task", status: "complete" });
|
|
85
|
+
writeFileSync(
|
|
86
|
+
join(dbBase, ".gsd", "milestones", "M300", "slices", "S01", "S01-PLAN.md"),
|
|
87
|
+
"# S01\n\n## Tasks\n\n- [ ] **T01: DB Task** `est:10m`\n",
|
|
88
|
+
"utf-8",
|
|
89
|
+
);
|
|
90
|
+
writeFileSync(join(dbBase, ".gsd", "STATE.md"), "## Next Action\nExecute T01 for S01: DB task\n", "utf-8");
|
|
91
|
+
|
|
92
|
+
const status = await inspectExecuteTaskDurability(dbBase, "M300/S01/T01");
|
|
93
|
+
assert.ok(status !== null, "db-complete: status exists");
|
|
94
|
+
assert.equal(status!.dbComplete, true, "db-complete: closed DB status is captured");
|
|
95
|
+
assert.equal(status!.summaryExists, false, "db-complete: summary can still be missing");
|
|
96
|
+
assert.equal(status!.taskChecked, false, "db-complete: checkbox can still be unchecked");
|
|
97
|
+
assert.equal(status!.nextActionAdvanced, false, "db-complete: next action can still point at task");
|
|
98
|
+
assert.equal(formatExecuteTaskRecoveryStatus(status!), "DB task status is closed");
|
|
99
|
+
} finally {
|
|
100
|
+
closeDatabase();
|
|
101
|
+
rmSync(dbBase, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
68
105
|
console.log("\n=== hook unit type sanitization (slash in unitType) ===");
|
|
69
106
|
{
|
|
70
107
|
// Hook units have unitType like "hook/code-review" with a slash
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// GSD-2
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Regression test for unstructured continue task-context injection.
|
|
2
3
|
// Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -55,12 +56,12 @@ describe("#3615 — structural: fallback exists with correct guards", () => {
|
|
|
55
56
|
);
|
|
56
57
|
});
|
|
57
58
|
|
|
58
|
-
test("fallback is intent-gated via
|
|
59
|
+
test("fallback is intent-gated via isLowEntropyResumePrompt", () => {
|
|
59
60
|
const afterFallback = fnBody.indexOf("// Fallback:");
|
|
60
61
|
const fallbackSection = fnBody.slice(afterFallback);
|
|
61
62
|
assert.ok(
|
|
62
|
-
fallbackSection.includes("
|
|
63
|
-
"fallback must check
|
|
63
|
+
fallbackSection.includes("isLowEntropyResumePrompt(prompt)"),
|
|
64
|
+
"fallback must check isLowEntropyResumePrompt before deriveState",
|
|
64
65
|
);
|
|
65
66
|
});
|
|
66
67
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for capped GSD workflow protocol and doctor-heal payload helpers.
|
|
3
|
+
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
buildDoctorHealIssuePayload,
|
|
9
|
+
buildDoctorHealSummary,
|
|
10
|
+
buildWorkflowDispatchContent,
|
|
11
|
+
buildWorkflowProtocolExcerpt,
|
|
12
|
+
} from "../workflow-protocol.ts";
|
|
13
|
+
|
|
14
|
+
test("workflow protocol helper emits capped excerpt plus source path", () => {
|
|
15
|
+
const workflow = `# Protocol\n${"FULL_WORKFLOW_BODY ".repeat(500)}`;
|
|
16
|
+
const excerpt = buildWorkflowProtocolExcerpt(workflow, "/tmp/GSD-WORKFLOW.md", { maxChars: 1200 });
|
|
17
|
+
|
|
18
|
+
assert.match(excerpt, /Source: `\/tmp\/GSD-WORKFLOW\.md`/);
|
|
19
|
+
assert.match(excerpt, /\[Workflow Protocol Truncated\]/);
|
|
20
|
+
assert.ok(excerpt.length < workflow.length);
|
|
21
|
+
assert.ok(excerpt.length < 1600);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("workflow dispatch uses excerpt instead of full workflow body", () => {
|
|
25
|
+
const workflow = `# Protocol\n${"FULL_WORKFLOW_BODY ".repeat(500)}`;
|
|
26
|
+
const content = buildWorkflowDispatchContent({
|
|
27
|
+
workflow,
|
|
28
|
+
workflowPath: "/tmp/GSD-WORKFLOW.md",
|
|
29
|
+
task: "Run the selected unit.",
|
|
30
|
+
maxProtocolChars: 1200,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
assert.match(content, /## GSD Workflow Protocol Excerpt/);
|
|
34
|
+
assert.match(content, /## Your Task/);
|
|
35
|
+
assert.match(content, /Run the selected unit/);
|
|
36
|
+
assert.ok(content.length < workflow.length);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("workflow protocol excerpt includes late verification and advance rules", () => {
|
|
40
|
+
const workflow = [
|
|
41
|
+
"# GSD Workflow",
|
|
42
|
+
"intro",
|
|
43
|
+
"## Quick Start",
|
|
44
|
+
"quick",
|
|
45
|
+
"## File Format Reference",
|
|
46
|
+
"format ".repeat(400),
|
|
47
|
+
"## The Phases",
|
|
48
|
+
"phase overview",
|
|
49
|
+
"### Phase 4: Execute",
|
|
50
|
+
"execute rules",
|
|
51
|
+
"### Phase 5: Verify",
|
|
52
|
+
"verification rules",
|
|
53
|
+
"### Phase 7: Advance",
|
|
54
|
+
"advance rules",
|
|
55
|
+
].join("\n");
|
|
56
|
+
|
|
57
|
+
const excerpt = buildWorkflowProtocolExcerpt(workflow, "/tmp/GSD-WORKFLOW.md", { maxChars: 1300 });
|
|
58
|
+
|
|
59
|
+
assert.match(excerpt, /Quick Start/);
|
|
60
|
+
assert.match(excerpt, /Phase 5: Verify/);
|
|
61
|
+
assert.match(excerpt, /Phase 7: Advance/);
|
|
62
|
+
assert.doesNotMatch(excerpt, /format format format format format/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("doctor heal summary omits duplicated full report body", () => {
|
|
66
|
+
const report = [
|
|
67
|
+
"# GSD doctor heal prep.",
|
|
68
|
+
"Scope: M001",
|
|
69
|
+
"Status: warning",
|
|
70
|
+
"Warnings: 9",
|
|
71
|
+
"",
|
|
72
|
+
"VERY_LONG_FULL_REPORT_BODY ".repeat(300),
|
|
73
|
+
].join("\n");
|
|
74
|
+
|
|
75
|
+
const summary = buildDoctorHealSummary(report, { maxChars: 900 });
|
|
76
|
+
|
|
77
|
+
assert.match(summary, /GSD doctor heal prep/);
|
|
78
|
+
assert.match(summary, /Warnings: 9/);
|
|
79
|
+
assert.ok(summary.length <= 900);
|
|
80
|
+
assert.doesNotMatch(summary, /VERY_LONG_FULL_REPORT_BODY VERY_LONG_FULL_REPORT_BODY VERY_LONG_FULL_REPORT_BODY/);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("doctor heal issue payload keeps top actionable issues and caps detail", () => {
|
|
84
|
+
const issues = Array.from({ length: 20 }, (_, index) =>
|
|
85
|
+
`### Issue ${index + 1}\n${`detail ${index + 1} `.repeat(80)}`,
|
|
86
|
+
).join("\n");
|
|
87
|
+
|
|
88
|
+
const payload = buildDoctorHealIssuePayload(issues, {
|
|
89
|
+
maxIssues: 3,
|
|
90
|
+
maxIssueChars: 180,
|
|
91
|
+
maxChars: 900,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
assert.match(payload, /Issue 1/);
|
|
95
|
+
assert.match(payload, /Issue 3/);
|
|
96
|
+
assert.doesNotMatch(payload, /Issue 4/);
|
|
97
|
+
assert.match(payload, /17 additional actionable issue/);
|
|
98
|
+
assert.ok(payload.length <= 900);
|
|
99
|
+
});
|