gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00
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 +53 -17
- package/dist/claude-cli-check.js +46 -10
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/github-sync/templates.js +103 -0
- package/dist/resources/extensions/google-search/index.js +3 -2
- package/dist/resources/extensions/gsd/auto/loop.js +124 -2
- package/dist/resources/extensions/gsd/auto/phases.js +57 -39
- package/dist/resources/extensions/gsd/auto/session.js +6 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
- package/dist/resources/extensions/gsd/auto-start.js +107 -29
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +76 -21
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/context-store.js +23 -7
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +39 -13
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
- package/dist/resources/extensions/gsd/state.js +69 -58
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
- package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
- package/dist/resources/extensions/gsd/uok/writer.js +82 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- 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 +11 -11
- 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/api/git/route.js +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 +11 -11
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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 +2 -3
- package/packages/daemon/package.json +2 -2
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +15 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
- package/packages/mcp-server/src/workflow-tools.ts +19 -6
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +2 -2
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- 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-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -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 +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
- 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 +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- 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 +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/templates.ts +151 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
- package/src/resources/extensions/google-search/index.ts +3 -2
- package/src/resources/extensions/gsd/auto/loop.ts +142 -2
- package/src/resources/extensions/gsd/auto/phases.ts +62 -38
- package/src/resources/extensions/gsd/auto/session.ts +7 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
- package/src/resources/extensions/gsd/auto-start.ts +127 -9
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +90 -23
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/context-store.ts +25 -8
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +149 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +57 -14
- package/src/resources/extensions/gsd/journal.ts +11 -1
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
- package/src/resources/extensions/gsd/state.ts +76 -66
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
- package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
- package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
- package/src/resources/extensions/gsd/uok/writer.ts +113 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
|
@@ -627,4 +627,83 @@ Integration tests mock external services.
|
|
|
627
627
|
|
|
628
628
|
assert.strictEqual(result, '', 'empty content returns empty string');
|
|
629
629
|
});
|
|
630
|
+
|
|
631
|
+
// ── Regression: issue #4719 — single-H2 with many H3 entries ──────────────
|
|
632
|
+
// A KNOWLEDGE.md structured as one top-level H2 with many H3 entries must
|
|
633
|
+
// filter at H3 granularity; otherwise one keyword match against the H2
|
|
634
|
+
// header or first paragraph returns the entire file.
|
|
635
|
+
test("single H2 with many H3 entries filters at H3 level (issue #4719)", async () => {
|
|
636
|
+
const singleH2Knowledge = `# Project Knowledge
|
|
637
|
+
|
|
638
|
+
## Patterns
|
|
639
|
+
|
|
640
|
+
### Database: prepared statements
|
|
641
|
+
Always use prepared statements with SQLite.
|
|
642
|
+
|
|
643
|
+
### API: versioned paths
|
|
644
|
+
Use /v1/resource style versioning.
|
|
645
|
+
|
|
646
|
+
### Testing: node:test
|
|
647
|
+
Prefer node:test over external frameworks.
|
|
648
|
+
|
|
649
|
+
### Deployment: blue-green
|
|
650
|
+
Blue-green deployment for zero-downtime releases.
|
|
651
|
+
`;
|
|
652
|
+
|
|
653
|
+
const result = await queryKnowledge(singleH2Knowledge, ['database']);
|
|
654
|
+
|
|
655
|
+
// Should include only the matching H3 entry, not the whole file
|
|
656
|
+
assert.match(result, /Database: prepared statements/, 'includes matching H3 entry');
|
|
657
|
+
assert.ok(
|
|
658
|
+
!result.includes('API: versioned paths'),
|
|
659
|
+
'does not include non-matching H3 entry',
|
|
660
|
+
);
|
|
661
|
+
assert.ok(
|
|
662
|
+
!result.includes('Testing: node:test'),
|
|
663
|
+
'does not include non-matching H3 entry',
|
|
664
|
+
);
|
|
665
|
+
assert.ok(
|
|
666
|
+
!result.includes('Deployment: blue-green'),
|
|
667
|
+
'does not include non-matching H3 entry',
|
|
668
|
+
);
|
|
669
|
+
// The returned payload must be dramatically smaller than the full content
|
|
670
|
+
assert.ok(
|
|
671
|
+
result.length < singleH2Knowledge.length / 2,
|
|
672
|
+
`scoped result (${result.length} chars) should be <50% of full content (${singleH2Knowledge.length} chars)`,
|
|
673
|
+
);
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
test("single H2 with H3 entries returns empty when no H3 matches (issue #4719)", async () => {
|
|
677
|
+
const singleH2Knowledge = `# Project Knowledge
|
|
678
|
+
|
|
679
|
+
## Patterns
|
|
680
|
+
|
|
681
|
+
### Database: prepared statements
|
|
682
|
+
Always use prepared statements with SQLite.
|
|
683
|
+
|
|
684
|
+
### API: versioned paths
|
|
685
|
+
Use /v1/resource style versioning.
|
|
686
|
+
`;
|
|
687
|
+
|
|
688
|
+
const result = await queryKnowledge(singleH2Knowledge, ['nonexistent']);
|
|
689
|
+
|
|
690
|
+
assert.strictEqual(result, '', 'no H3 match returns empty string');
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
test("falls back to H2 when no H3 headings exist at all", async () => {
|
|
694
|
+
// Backwards-compat: files with only H2 topic headers must still filter.
|
|
695
|
+
const h2OnlyKnowledge = `# Project Knowledge
|
|
696
|
+
|
|
697
|
+
## Database Patterns
|
|
698
|
+
Use prepared statements.
|
|
699
|
+
|
|
700
|
+
## API Design
|
|
701
|
+
REST with OpenAPI.
|
|
702
|
+
`;
|
|
703
|
+
|
|
704
|
+
const result = await queryKnowledge(h2OnlyKnowledge, ['database']);
|
|
705
|
+
|
|
706
|
+
assert.match(result, /Database Patterns/, 'H2-only file falls back to H2 filtering');
|
|
707
|
+
assert.ok(!result.includes('API Design'), 'non-matching H2 section excluded');
|
|
708
|
+
});
|
|
630
709
|
});
|
|
@@ -2,6 +2,7 @@ import test from "node:test";
|
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
+
import { extractSourceRegion } from "./test-helpers.ts";
|
|
5
6
|
|
|
6
7
|
test("copyPlanningArtifacts skips when source and destination .gsd resolve to the same path", () => {
|
|
7
8
|
const srcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
|
|
@@ -10,7 +11,7 @@ test("copyPlanningArtifacts skips when source and destination .gsd resolve to th
|
|
|
10
11
|
const fnIdx = src.indexOf("function copyPlanningArtifacts");
|
|
11
12
|
assert.ok(fnIdx !== -1, "copyPlanningArtifacts function exists");
|
|
12
13
|
|
|
13
|
-
const fnBody = src
|
|
14
|
+
const fnBody = extractSourceRegion(src, "function copyPlanningArtifacts");
|
|
14
15
|
|
|
15
16
|
const guardIdx = fnBody.indexOf("if (isSamePath(srcGsd, dstGsd)) return;");
|
|
16
17
|
const copyIdx = fnBody.indexOf("safeCopyRecursive(join(srcGsd, \"milestones\")");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from "../interrupted-session.ts";
|
|
22
22
|
import { gsdRoot } from "../paths.ts";
|
|
23
23
|
import type { GSDState } from "../types.ts";
|
|
24
|
+
import { _synthesizePausedSessionRecoveryForTest } from "../auto.ts";
|
|
24
25
|
|
|
25
26
|
function makeTmpBase(): string {
|
|
26
27
|
const base = join(tmpdir(), `gsd-test-${randomUUID()}`);
|
|
@@ -167,6 +168,54 @@ test("readPausedSessionMetadata reads paused-session metadata when present", ()
|
|
|
167
168
|
}
|
|
168
169
|
});
|
|
169
170
|
|
|
171
|
+
test("paused session recovery consumes JSONL without deleting the evidence file", (t) => {
|
|
172
|
+
const base = makeTmpBase();
|
|
173
|
+
t.after(() => cleanup(base));
|
|
174
|
+
|
|
175
|
+
const sessionFile = join(base, "paused-session.jsonl");
|
|
176
|
+
writeFileSync(
|
|
177
|
+
sessionFile,
|
|
178
|
+
[
|
|
179
|
+
JSON.stringify({ type: "session", id: "session-1" }),
|
|
180
|
+
JSON.stringify({
|
|
181
|
+
type: "message",
|
|
182
|
+
message: {
|
|
183
|
+
role: "assistant",
|
|
184
|
+
content: [
|
|
185
|
+
{
|
|
186
|
+
type: "toolCall",
|
|
187
|
+
name: "bash",
|
|
188
|
+
id: "tool-1",
|
|
189
|
+
arguments: { command: "echo paused" },
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
}),
|
|
194
|
+
JSON.stringify({
|
|
195
|
+
type: "message",
|
|
196
|
+
message: {
|
|
197
|
+
role: "toolResult",
|
|
198
|
+
toolCallId: "tool-1",
|
|
199
|
+
toolName: "bash",
|
|
200
|
+
isError: false,
|
|
201
|
+
content: "paused\n",
|
|
202
|
+
},
|
|
203
|
+
}),
|
|
204
|
+
].join("\n"),
|
|
205
|
+
"utf-8",
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const recovery = _synthesizePausedSessionRecoveryForTest(
|
|
209
|
+
base,
|
|
210
|
+
"execute-task",
|
|
211
|
+
"M001/S01/T01",
|
|
212
|
+
sessionFile,
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
assert.equal(recovery?.trace.toolCallCount, 1);
|
|
216
|
+
assert.equal(existsSync(sessionFile), true, "paused JSONL must remain available after synthesis");
|
|
217
|
+
});
|
|
218
|
+
|
|
170
219
|
test("readPausedSessionMetadata preserves unitType and unitId through round-trip", () => {
|
|
171
220
|
const base = makeTmpBase();
|
|
172
221
|
try {
|
|
@@ -481,6 +481,165 @@ describe("Custom engine loop integration", () => {
|
|
|
481
481
|
);
|
|
482
482
|
});
|
|
483
483
|
|
|
484
|
+
it("stops custom workflow after repeated verification retries", async () => {
|
|
485
|
+
_resetPendingResolve();
|
|
486
|
+
|
|
487
|
+
const runDir = makeTmpDir();
|
|
488
|
+
const graph = makeGraph([makeStep({ id: "retry-step" })], "retry-exhaustion");
|
|
489
|
+
writeGraph(runDir, graph);
|
|
490
|
+
writeFileSync(join(runDir, "DEFINITION.yaml"), stringify({
|
|
491
|
+
version: 1,
|
|
492
|
+
name: "retry-exhaustion",
|
|
493
|
+
steps: [{
|
|
494
|
+
id: "retry-step",
|
|
495
|
+
name: "retry-step",
|
|
496
|
+
prompt: "Do retry-step",
|
|
497
|
+
produces: "retry-step/output.md",
|
|
498
|
+
verify: { policy: "shell-command", command: "exit 1" },
|
|
499
|
+
}],
|
|
500
|
+
}));
|
|
501
|
+
|
|
502
|
+
const ctx = makeMockCtx();
|
|
503
|
+
const pi = makeMockPi();
|
|
504
|
+
const s = makeLoopSession({
|
|
505
|
+
activeEngineId: "custom",
|
|
506
|
+
activeRunDir: runDir,
|
|
507
|
+
basePath: runDir,
|
|
508
|
+
});
|
|
509
|
+
const deps = makeMockDeps({
|
|
510
|
+
stopAuto: async (_ctx, _pi, reason) => {
|
|
511
|
+
deps.callLog.push(`stopAuto:${reason ?? "no-reason"}`);
|
|
512
|
+
s.active = false;
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
const resolver = setInterval(() => {
|
|
517
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
518
|
+
}, 25);
|
|
519
|
+
let timeout: NodeJS.Timeout | undefined;
|
|
520
|
+
try {
|
|
521
|
+
await Promise.race([
|
|
522
|
+
autoLoop(ctx, pi, s, deps),
|
|
523
|
+
new Promise((_, reject) =>
|
|
524
|
+
timeout = setTimeout(() => {
|
|
525
|
+
s.active = false;
|
|
526
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
527
|
+
reject(new Error(
|
|
528
|
+
`autoLoop did not stop after verification retry exhaustion; calls=${pi.calls.length}; log=${deps.callLog.join(",")}`,
|
|
529
|
+
));
|
|
530
|
+
}, 3_000),
|
|
531
|
+
),
|
|
532
|
+
]);
|
|
533
|
+
} finally {
|
|
534
|
+
clearInterval(resolver);
|
|
535
|
+
if (timeout) clearTimeout(timeout);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
assert.equal(pi.calls.length, 4, "verification retry should be capped after four dispatched attempts");
|
|
539
|
+
const stopEntry = deps.callLog.find((e: string) => e.startsWith("stopAuto:"));
|
|
540
|
+
assert.match(stopEntry ?? "", /requested retry 4 times without passing/);
|
|
541
|
+
const finalGraph = readGraph(runDir);
|
|
542
|
+
assert.equal(finalGraph.steps[0]?.status, "active", "failed verification must not reconcile the step complete");
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it("persists custom verification retry budget across a session restart", async () => {
|
|
546
|
+
_resetPendingResolve();
|
|
547
|
+
|
|
548
|
+
const runDir = makeTmpDir();
|
|
549
|
+
const graph = makeGraph([makeStep({ id: "retry-step" })], "retry-restart");
|
|
550
|
+
writeGraph(runDir, graph);
|
|
551
|
+
writeFileSync(join(runDir, "DEFINITION.yaml"), stringify({
|
|
552
|
+
version: 1,
|
|
553
|
+
name: "retry-restart",
|
|
554
|
+
steps: [{
|
|
555
|
+
id: "retry-step",
|
|
556
|
+
name: "retry-step",
|
|
557
|
+
prompt: "Do retry-step",
|
|
558
|
+
produces: "retry-step/output.md",
|
|
559
|
+
verify: { policy: "shell-command", command: "exit 1" },
|
|
560
|
+
}],
|
|
561
|
+
}));
|
|
562
|
+
|
|
563
|
+
const ctx1 = makeMockCtx();
|
|
564
|
+
const pi1 = makeMockPi();
|
|
565
|
+
const s1 = makeLoopSession({
|
|
566
|
+
activeEngineId: "custom",
|
|
567
|
+
activeRunDir: runDir,
|
|
568
|
+
basePath: runDir,
|
|
569
|
+
});
|
|
570
|
+
const deps1 = makeMockDeps();
|
|
571
|
+
const resolver1 = setInterval(() => {
|
|
572
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
573
|
+
if (pi1.calls.length >= 2) {
|
|
574
|
+
s1.active = false;
|
|
575
|
+
}
|
|
576
|
+
}, 25);
|
|
577
|
+
let timeout1: NodeJS.Timeout | undefined;
|
|
578
|
+
try {
|
|
579
|
+
await Promise.race([
|
|
580
|
+
autoLoop(ctx1, pi1, s1, deps1),
|
|
581
|
+
new Promise((_, reject) =>
|
|
582
|
+
timeout1 = setTimeout(() => {
|
|
583
|
+
s1.active = false;
|
|
584
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
585
|
+
reject(new Error(
|
|
586
|
+
`first autoLoop did not pause after two retry attempts; calls=${pi1.calls.length}; log=${deps1.callLog.join(",")}`,
|
|
587
|
+
));
|
|
588
|
+
}, 3_000),
|
|
589
|
+
),
|
|
590
|
+
]);
|
|
591
|
+
} finally {
|
|
592
|
+
clearInterval(resolver1);
|
|
593
|
+
if (timeout1) clearTimeout(timeout1);
|
|
594
|
+
}
|
|
595
|
+
assert.equal(pi1.calls.length, 2, "first session should consume two retry attempts");
|
|
596
|
+
assert.equal(
|
|
597
|
+
deps1.callLog.some((e: string) => e.startsWith("stopAuto:")),
|
|
598
|
+
false,
|
|
599
|
+
"first session should stop because the session deactivated, not because retry budget exhausted",
|
|
600
|
+
);
|
|
601
|
+
|
|
602
|
+
_resetPendingResolve();
|
|
603
|
+
const ctx2 = makeMockCtx();
|
|
604
|
+
const pi2 = makeMockPi();
|
|
605
|
+
const s2 = makeLoopSession({
|
|
606
|
+
activeEngineId: "custom",
|
|
607
|
+
activeRunDir: runDir,
|
|
608
|
+
basePath: runDir,
|
|
609
|
+
});
|
|
610
|
+
const deps2 = makeMockDeps({
|
|
611
|
+
stopAuto: async (_ctx, _pi, reason) => {
|
|
612
|
+
deps2.callLog.push(`stopAuto:${reason ?? "no-reason"}`);
|
|
613
|
+
s2.active = false;
|
|
614
|
+
},
|
|
615
|
+
});
|
|
616
|
+
const resolver2 = setInterval(() => {
|
|
617
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
618
|
+
}, 25);
|
|
619
|
+
let timeout2: NodeJS.Timeout | undefined;
|
|
620
|
+
try {
|
|
621
|
+
await Promise.race([
|
|
622
|
+
autoLoop(ctx2, pi2, s2, deps2),
|
|
623
|
+
new Promise((_, reject) =>
|
|
624
|
+
timeout2 = setTimeout(() => {
|
|
625
|
+
s2.active = false;
|
|
626
|
+
resolveAgentEnd({ messages: [{ role: "assistant" }] });
|
|
627
|
+
reject(new Error(
|
|
628
|
+
`second autoLoop did not stop after persisted retry exhaustion; calls=${pi2.calls.length}; log=${deps2.callLog.join(",")}`,
|
|
629
|
+
));
|
|
630
|
+
}, 3_000),
|
|
631
|
+
),
|
|
632
|
+
]);
|
|
633
|
+
} finally {
|
|
634
|
+
clearInterval(resolver2);
|
|
635
|
+
if (timeout2) clearTimeout(timeout2);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
assert.equal(pi2.calls.length, 2, "second session should exhaust after attempts 3 and 4");
|
|
639
|
+
const stopEntry = deps2.callLog.find((e: string) => e.startsWith("stopAuto:"));
|
|
640
|
+
assert.match(stopEntry ?? "", /requested retry 4 times without passing/);
|
|
641
|
+
});
|
|
642
|
+
|
|
484
643
|
it("GRAPH.yaml step stays pending when session deactivates before reconcile", async () => {
|
|
485
644
|
_resetPendingResolve();
|
|
486
645
|
|
|
@@ -50,6 +50,7 @@ test("doctor-heal.md contains DB access guardrail naming gsd_milestone_status",
|
|
|
50
50
|
const prompt = readPrompt("doctor-heal");
|
|
51
51
|
assert.match(prompt, /gsd_milestone_status/, "doctor-heal.md must name gsd_milestone_status as the DB inspection tool");
|
|
52
52
|
assert.match(prompt, /Do NOT query.*\.gsd\/gsd\.db/i, "doctor-heal.md must prohibit direct DB queries");
|
|
53
|
+
assert.doesNotMatch(prompt, /\{\{milestoneId\}\}/, "doctor-heal.md must not declare unprovided milestoneId template variables");
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
test("forensics.md contains DB inspection guardrail", () => {
|
|
@@ -351,9 +351,9 @@ skills_used: []
|
|
|
351
351
|
const dbState = await deriveStateFromDb(base);
|
|
352
352
|
|
|
353
353
|
assertStatesEqual(dbState, fileState, 'E-blocked');
|
|
354
|
-
|
|
355
|
-
assert.deepStrictEqual(dbState.
|
|
356
|
-
assert.ok(dbState.
|
|
354
|
+
assert.deepStrictEqual(dbState.phase, 'blocked', 'E-blocked: phase is blocked when no slice deps are satisfied');
|
|
355
|
+
assert.deepStrictEqual(dbState.activeSlice, null, 'E-blocked: no activeSlice is selected through unmet deps');
|
|
356
|
+
assert.ok(dbState.blockers.some(b => b.includes('No slice eligible')), 'E-blocked: blocker explains no eligible slice');
|
|
357
357
|
|
|
358
358
|
closeDatabase();
|
|
359
359
|
} finally {
|
|
@@ -112,6 +112,46 @@ async function main(): Promise<void> {
|
|
|
112
112
|
cleanup(base);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
console.log("\n=== #4974: summary-only disk milestones keep parsed title ===");
|
|
116
|
+
|
|
117
|
+
{
|
|
118
|
+
const summaryOnlyBase = createFixtureBase();
|
|
119
|
+
const summaryOnlyDbPath = join(summaryOnlyBase, ".gsd", "gsd.db");
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
openDatabase(summaryOnlyDbPath);
|
|
123
|
+
insertMilestone({ id: "M001", title: "M001: Existing DB Milestone", status: "complete", depends_on: [] });
|
|
124
|
+
|
|
125
|
+
writeFile(
|
|
126
|
+
summaryOnlyBase,
|
|
127
|
+
"milestones/M002/SUMMARY.md",
|
|
128
|
+
`---\nid: M002\nstatus: complete\n---\n\n# M002: Summary-Only Milestone\n\nComplete.`,
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
invalidateStateCache();
|
|
132
|
+
const state = await deriveStateFromDb(summaryOnlyBase);
|
|
133
|
+
const m002Entry = state.registry.find((m) => m.id === "M002");
|
|
134
|
+
|
|
135
|
+
assertTrue(
|
|
136
|
+
m002Entry !== undefined,
|
|
137
|
+
"M002 summary-only disk milestone should appear in state.registry (#4974)",
|
|
138
|
+
);
|
|
139
|
+
assertEq(
|
|
140
|
+
m002Entry?.title,
|
|
141
|
+
"Summary-Only Milestone",
|
|
142
|
+
"M002 summary-only disk milestone should use parsed SUMMARY title (#4974)",
|
|
143
|
+
);
|
|
144
|
+
assertEq(
|
|
145
|
+
m002Entry?.status,
|
|
146
|
+
"complete",
|
|
147
|
+
"M002 summary-only disk milestone should reconcile as complete (#4974)",
|
|
148
|
+
);
|
|
149
|
+
} finally {
|
|
150
|
+
closeDatabase();
|
|
151
|
+
cleanup(summaryOnlyBase);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
115
155
|
report();
|
|
116
156
|
}
|
|
117
157
|
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
getAllMilestones,
|
|
15
15
|
insertSlice,
|
|
16
16
|
insertTask,
|
|
17
|
+
getSliceTasks,
|
|
17
18
|
updateTaskStatus,
|
|
18
19
|
} from '../gsd-db.ts';
|
|
19
20
|
// ─── Fixture Helpers ───────────────────────────────────────────────────────
|
|
@@ -270,6 +271,93 @@ describe('derive-state-db', async () => {
|
|
|
270
271
|
}
|
|
271
272
|
});
|
|
272
273
|
|
|
274
|
+
test('derive-state-db: partial task rows reconcile missing plan tasks before summarizing', async (t) => {
|
|
275
|
+
const base = createFixtureBase();
|
|
276
|
+
t.after(() => {
|
|
277
|
+
closeDatabase();
|
|
278
|
+
cleanup(base);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const partialTaskPlan = `# S01: First Slice
|
|
282
|
+
|
|
283
|
+
**Goal:** Test partial task DB reconciliation.
|
|
284
|
+
**Demo:** Tests pass.
|
|
285
|
+
|
|
286
|
+
## Tasks
|
|
287
|
+
|
|
288
|
+
- [x] **T01: Existing Complete** \`est:10m\`
|
|
289
|
+
Already complete in DB.
|
|
290
|
+
|
|
291
|
+
- [ ] **T02: Missing Pending** \`est:10m\`
|
|
292
|
+
Missing from DB but present in the plan.
|
|
293
|
+
`;
|
|
294
|
+
writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
|
|
295
|
+
writeFile(base, 'milestones/M001/slices/S01/S01-PLAN.md', partialTaskPlan);
|
|
296
|
+
writeFile(base, 'milestones/M001/slices/S01/tasks/.gitkeep', '');
|
|
297
|
+
writeFile(base, 'milestones/M001/slices/S01/tasks/T01-PLAN.md', '# T01 Plan');
|
|
298
|
+
writeFile(base, 'milestones/M001/slices/S01/tasks/T02-PLAN.md', '# T02 Plan');
|
|
299
|
+
|
|
300
|
+
openDatabase(':memory:');
|
|
301
|
+
insertMilestone({ id: 'M001', title: 'Test Milestone', status: 'active' });
|
|
302
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'First Slice', status: 'active', risk: 'low', depends: [] });
|
|
303
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', title: 'Existing Complete', status: 'complete' });
|
|
304
|
+
|
|
305
|
+
invalidateStateCache();
|
|
306
|
+
const state = await deriveState(base);
|
|
307
|
+
|
|
308
|
+
const dbTasks = getSliceTasks('M001', 'S01');
|
|
309
|
+
assert.deepStrictEqual(dbTasks.length, 2, 'partial-task-db: missing T02 imported from plan');
|
|
310
|
+
assert.deepStrictEqual(dbTasks.find(t => t.id === 'T01')?.status, 'complete', 'partial-task-db: existing complete T01 preserved');
|
|
311
|
+
assert.deepStrictEqual(dbTasks.find(t => t.id === 'T02')?.status, 'pending', 'partial-task-db: missing T02 inserted pending');
|
|
312
|
+
assert.deepStrictEqual(state.phase, 'executing', 'partial-task-db: phase remains executing, not summarizing');
|
|
313
|
+
assert.deepStrictEqual(state.activeTask?.id, 'T02', 'partial-task-db: activeTask is missing plan task T02');
|
|
314
|
+
assert.deepStrictEqual(state.progress?.tasks, { done: 1, total: 2 }, 'partial-task-db: task progress includes reconciled plan task');
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test('derive-state-db: empty DB disk import preserves milestone completion and dependencies', async (t) => {
|
|
318
|
+
const base = createFixtureBase();
|
|
319
|
+
t.after(() => {
|
|
320
|
+
closeDatabase();
|
|
321
|
+
cleanup(base);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
writeFile(base, 'milestones/M001/M001-ROADMAP.md', `# M001: Foundation
|
|
325
|
+
|
|
326
|
+
**Vision:** Foundation.
|
|
327
|
+
|
|
328
|
+
## Slices
|
|
329
|
+
|
|
330
|
+
- [x] **S01: Done** \`risk:low\` \`depends:[]\`
|
|
331
|
+
> After this: Done.
|
|
332
|
+
`);
|
|
333
|
+
writeFile(base, 'milestones/M001/M001-VALIDATION.md', '---\nverdict: pass\nremediation_round: 0\n---\n\nPassed.');
|
|
334
|
+
writeFile(base, 'milestones/M001/M001-SUMMARY.md', '# M001 Summary\n\nDone.');
|
|
335
|
+
writeFile(base, 'milestones/M002/M002-CONTEXT.md', '---\ndepends_on:\n - M001\n---\n\n# M002: Dependent\n');
|
|
336
|
+
writeFile(base, 'milestones/M002/M002-ROADMAP.md', `# M002: Dependent
|
|
337
|
+
|
|
338
|
+
**Vision:** Active work.
|
|
339
|
+
|
|
340
|
+
## Slices
|
|
341
|
+
|
|
342
|
+
- [ ] **S01: Work** \`risk:low\` \`depends:[]\`
|
|
343
|
+
> After this: Done.
|
|
344
|
+
`);
|
|
345
|
+
writeFile(base, 'milestones/M003/M003-CONTEXT.md', '---\ndepends_on:\n - M002\n---\n\n# M003: Blocked\n');
|
|
346
|
+
|
|
347
|
+
openDatabase(':memory:');
|
|
348
|
+
|
|
349
|
+
invalidateStateCache();
|
|
350
|
+
const state = await deriveState(base);
|
|
351
|
+
|
|
352
|
+
const milestones = getAllMilestones();
|
|
353
|
+
assert.deepStrictEqual(milestones.find(m => m.id === 'M001')?.status, 'complete', 'disk-import: terminal summary imports M001 as complete');
|
|
354
|
+
assert.deepStrictEqual(milestones.find(m => m.id === 'M002')?.depends_on, ['M001'], 'disk-import: M002 depends_on imported from CONTEXT');
|
|
355
|
+
assert.deepStrictEqual(milestones.find(m => m.id === 'M003')?.depends_on, ['M002'], 'disk-import: M003 depends_on imported from CONTEXT');
|
|
356
|
+
assert.deepStrictEqual(state.activeMilestone?.id, 'M002', 'disk-import: M002 is active because M001 completion satisfies dependency');
|
|
357
|
+
assert.deepStrictEqual(state.registry.find(e => e.id === 'M001')?.status, 'complete', 'disk-import: M001 registry status is complete');
|
|
358
|
+
assert.deepStrictEqual(state.registry.find(e => e.id === 'M003')?.status, 'pending', 'disk-import: M003 stays pending on unmet M002 dependency');
|
|
359
|
+
});
|
|
360
|
+
|
|
273
361
|
// ─── Test 5: Requirements counting from disk (DB no longer used for content) ─
|
|
274
362
|
test('derive-state-db: requirements from disk content', async () => {
|
|
275
363
|
const base = createFixtureBase();
|
|
@@ -616,10 +704,10 @@ describe('derive-state-db', async () => {
|
|
|
616
704
|
invalidateStateCache();
|
|
617
705
|
const dbState = await deriveStateFromDb(base);
|
|
618
706
|
|
|
619
|
-
|
|
620
|
-
assert.deepStrictEqual(dbState.phase, 'planning', 'blocked-db: phase is planning (fallback picks a slice)');
|
|
707
|
+
assert.deepStrictEqual(dbState.phase, 'blocked', 'blocked-db: phase is blocked when no slice deps are satisfied');
|
|
621
708
|
assert.deepStrictEqual(dbState.phase, fileState.phase, 'blocked-db: phase matches filesystem');
|
|
622
|
-
assert.
|
|
709
|
+
assert.deepStrictEqual(dbState.activeSlice, null, 'blocked-db: no activeSlice is selected through unmet deps');
|
|
710
|
+
assert.ok(dbState.blockers.some(b => b.includes('No slice eligible')), 'blocked-db: blocker explains no eligible slice');
|
|
623
711
|
|
|
624
712
|
closeDatabase();
|
|
625
713
|
} finally {
|
|
@@ -431,7 +431,7 @@ Continue from step 2.
|
|
|
431
431
|
cleanup(base1);
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
// Case B: S01 depends on nonexistent S99
|
|
434
|
+
// Case B: S01 depends on nonexistent S99 -> no slice is eligible
|
|
435
435
|
const base2 = createFixtureBase();
|
|
436
436
|
try {
|
|
437
437
|
writeRoadmap(base2, 'M001', `# M001: Test Milestone
|
|
@@ -446,9 +446,9 @@ Continue from step 2.
|
|
|
446
446
|
|
|
447
447
|
const state2 = await deriveState(base2);
|
|
448
448
|
|
|
449
|
-
|
|
450
|
-
assert.deepStrictEqual(state2.
|
|
451
|
-
assert.
|
|
449
|
+
assert.deepStrictEqual(state2.phase, 'blocked', 'blocked-B: phase is blocked when dependency is unsatisfied');
|
|
450
|
+
assert.deepStrictEqual(state2.activeSlice, null, 'blocked-B: no activeSlice selected through unmet deps');
|
|
451
|
+
assert.ok(state2.blockers.some(b => b.includes('No slice eligible')), 'blocked-B: blocker explains no eligible slice');
|
|
452
452
|
} finally {
|
|
453
453
|
cleanup(base2);
|
|
454
454
|
}
|
|
@@ -11,6 +11,7 @@ import { describe, it } from 'node:test'
|
|
|
11
11
|
import assert from 'node:assert/strict'
|
|
12
12
|
import { readFileSync } from 'node:fs'
|
|
13
13
|
import { resolve } from 'node:path'
|
|
14
|
+
import { extractSourceRegion } from "./test-helpers.ts";
|
|
14
15
|
|
|
15
16
|
const template = readFileSync(
|
|
16
17
|
resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'prompts', 'guided-discuss-slice.md'),
|
|
@@ -37,7 +38,7 @@ describe('discuss-slice structuredQuestionsAvailable template variable', () => {
|
|
|
37
38
|
const falseIdx = template.indexOf('`{{structuredQuestionsAvailable}}` is `false`')
|
|
38
39
|
assert.ok(falseIdx !== -1)
|
|
39
40
|
|
|
40
|
-
const afterFalse = template
|
|
41
|
+
const afterFalse = extractSourceRegion(template, '`{{structuredQuestionsAvailable}}` is `false`')
|
|
41
42
|
assert.ok(
|
|
42
43
|
afterFalse.includes('plain text'),
|
|
43
44
|
'when structuredQuestionsAvailable is false, questions should be in plain text',
|
|
@@ -22,6 +22,7 @@ import { join, dirname } from "node:path";
|
|
|
22
22
|
import { fileURLToPath } from "node:url";
|
|
23
23
|
|
|
24
24
|
import { DISCUSS_TOOLS_ALLOWLIST } from "../constants.ts";
|
|
25
|
+
import { extractSourceRegion } from "./test-helpers.ts";
|
|
25
26
|
|
|
26
27
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
27
28
|
const guidedFlowSource = readFileSync(join(__dirname, "..", "guided-flow.ts"), "utf-8");
|
|
@@ -58,7 +59,7 @@ describe("#3616 — discuss tool scoping must not leak across sessions", () => {
|
|
|
58
59
|
);
|
|
59
60
|
const newSessionStart = agentSessionSource.indexOf("async newSession(options?:");
|
|
60
61
|
assert.ok(newSessionStart >= 0, "should find newSession");
|
|
61
|
-
const body = agentSessionSource
|
|
62
|
+
const body = extractSourceRegion(agentSessionSource, "async newSession(options?:");
|
|
62
63
|
|
|
63
64
|
// Both branches (cwd-changed and cwd-unchanged) must include extension tools
|
|
64
65
|
assert.ok(
|
|
@@ -55,6 +55,11 @@ describe("completing-milestone dispatch guard (#4324)", () => {
|
|
|
55
55
|
|
|
56
56
|
const classifyCall = source.indexOf("classifyMilestoneSummaryContent", summaryGuard);
|
|
57
57
|
assert.ok(classifyCall > -1, "SUMMARY mismatch handling should classify summary content");
|
|
58
|
+
const dbGateBeforeClassify = source.indexOf("existingSummary && isDbAvailable()", summaryGuard);
|
|
59
|
+
assert.ok(
|
|
60
|
+
dbGateBeforeClassify === -1 || dbGateBeforeClassify > classifyCall,
|
|
61
|
+
"SUMMARY classification must not be gated on DB availability",
|
|
62
|
+
);
|
|
58
63
|
|
|
59
64
|
const reconcileCall = source.indexOf('updateMilestoneStatus(mid, "complete"', summaryGuard);
|
|
60
65
|
assert.ok(reconcileCall > -1, "successful SUMMARY should reconcile DB to complete");
|
|
@@ -255,6 +255,31 @@ test("dispatch guard skips completed milestone with SUMMARY even if it has unche
|
|
|
255
255
|
);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
+
test("dispatch guard does not skip failed milestone SUMMARY without blocker prose", (t) => {
|
|
259
|
+
const repo = setupRepo();
|
|
260
|
+
t.after(() => teardownRepo(repo));
|
|
261
|
+
|
|
262
|
+
mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
|
|
263
|
+
mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
|
|
264
|
+
|
|
265
|
+
insertMilestone({ id: "M001", title: "Previous" });
|
|
266
|
+
insertSlice({ id: "S01", milestoneId: "M001", title: "Core", status: "complete", depends: [], sequence: 1 });
|
|
267
|
+
insertSlice({ id: "S02", milestoneId: "M001", title: "Unfinished", status: "pending", depends: ["S01"], sequence: 2 });
|
|
268
|
+
|
|
269
|
+
insertMilestone({ id: "M002", title: "Current" });
|
|
270
|
+
insertSlice({ id: "S01", milestoneId: "M002", title: "Start", status: "pending", depends: [], sequence: 1 });
|
|
271
|
+
|
|
272
|
+
writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
|
|
273
|
+
writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-SUMMARY.md"),
|
|
274
|
+
"---\nstatus: failed\n---\n# M001 Summary\nRecovery stopped.\n");
|
|
275
|
+
writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
|
|
276
|
+
|
|
277
|
+
assert.equal(
|
|
278
|
+
getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M002/S01"),
|
|
279
|
+
"Cannot dispatch plan-slice M002/S01: earlier slice M001/S02 is not complete.",
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
|
|
258
283
|
test("dispatch guard works without git repo", (t) => {
|
|
259
284
|
const repo = setupRepo();
|
|
260
285
|
t.after(() => teardownRepo(repo));
|
|
@@ -57,6 +57,17 @@ function scaffoldSlicePlan(basePath: string, mid: string, sid: string): void {
|
|
|
57
57
|
].join("\n"));
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
function scaffoldMilestoneContext(basePath: string, mid: string): void {
|
|
61
|
+
const dir = join(basePath, ".gsd", "milestones", mid);
|
|
62
|
+
mkdirSync(dir, { recursive: true });
|
|
63
|
+
writeFileSync(join(dir, `${mid}-CONTEXT.md`), [
|
|
64
|
+
`# ${mid}: Test Milestone`,
|
|
65
|
+
"",
|
|
66
|
+
"Context for dispatch recovery tests.",
|
|
67
|
+
"",
|
|
68
|
+
].join("\n"));
|
|
69
|
+
}
|
|
70
|
+
|
|
60
71
|
function scaffoldTaskPlan(basePath: string, mid: string, sid: string, tid: string): void {
|
|
61
72
|
const dir = join(basePath, ".gsd", "milestones", mid, "slices", sid, "tasks");
|
|
62
73
|
mkdirSync(dir, { recursive: true });
|
|
@@ -76,6 +87,7 @@ test("dispatch: missing task plan triggers plan-slice (not stop) — issue #909"
|
|
|
76
87
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
77
88
|
|
|
78
89
|
// Slice plan exists with tasks, but tasks/ directory is empty
|
|
90
|
+
scaffoldMilestoneContext(tmp, "M002");
|
|
79
91
|
scaffoldSlicePlan(tmp, "M002", "S03");
|
|
80
92
|
|
|
81
93
|
const ctx = makeContext(tmp);
|
|
@@ -92,6 +104,7 @@ test("dispatch: present task plan proceeds to execute-task normally", async (t)
|
|
|
92
104
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-909-ok-"));
|
|
93
105
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
94
106
|
|
|
107
|
+
scaffoldMilestoneContext(tmp, "M002");
|
|
95
108
|
scaffoldSlicePlan(tmp, "M002", "S03");
|
|
96
109
|
scaffoldTaskPlan(tmp, "M002", "S03", "T01");
|
|
97
110
|
|
|
@@ -111,6 +124,7 @@ test("dispatch: plan-slice recovery loop — second call after plan-slice still
|
|
|
111
124
|
const tmp = mkdtempSync(join(tmpdir(), "gsd-909-loop-"));
|
|
112
125
|
t.after(() => rmSync(tmp, { recursive: true, force: true }));
|
|
113
126
|
|
|
127
|
+
scaffoldMilestoneContext(tmp, "M002");
|
|
114
128
|
scaffoldSlicePlan(tmp, "M002", "S03");
|
|
115
129
|
|
|
116
130
|
const ctx = makeContext(tmp);
|