gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714
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 +1 -1
- package/dist/claude-cli-check.js +5 -1
- 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 +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/gsd/auto/loop.js +43 -0
- package/dist/resources/extensions/gsd/auto/phases.js +15 -21
- package/dist/resources/extensions/gsd/auto/session.js +0 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
- package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
- package/dist/resources/extensions/gsd/auto-start.js +34 -24
- 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 +31 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -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/detection.js +49 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- 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 +17 -5
- 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/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/prompts/complete-milestone.md +6 -2
- 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-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state.js +44 -33
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- 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/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
- 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 +5 -5
- 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 +5 -5
- 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/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/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 +80 -39
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- 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/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/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/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/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/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/dynamic-border.test.ts +26 -20
- 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 +36 -12
- 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/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 +41 -12
- 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/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +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 +5 -1
- 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/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
- package/src/resources/extensions/gsd/auto/loop.ts +47 -0
- package/src/resources/extensions/gsd/auto/phases.ts +16 -20
- package/src/resources/extensions/gsd/auto/session.ts +0 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
- package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
- package/src/resources/extensions/gsd/auto-start.ts +54 -6
- 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 +43 -22
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -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/detection.ts +58 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -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 +133 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +20 -5
- 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/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/prompts/complete-milestone.md +6 -2
- 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-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state.ts +49 -44
- 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/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 +94 -289
- 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-retry-mcp-churn-fixes.test.ts +8 -197
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- 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-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/crash-recovery.test.ts +50 -1
- 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 -3
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
- 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/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
- 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/interrupted-session-ui.test.ts +6 -9
- 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 -62
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -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 -49
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
- 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/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/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/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/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-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- 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/test-helpers.test.ts +12 -61
- package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
- 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-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/validate-milestone.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
- 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/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/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/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
- 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 -144
- 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 -75
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
- 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 -130
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
|
@@ -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 {
|
|
@@ -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,8 +446,9 @@ Continue from step 2.
|
|
|
446
446
|
|
|
447
447
|
const state2 = await deriveState(base2);
|
|
448
448
|
|
|
449
|
-
assert.deepStrictEqual(state2.phase, '
|
|
450
|
-
assert.deepStrictEqual(state2.activeSlice
|
|
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');
|
|
451
452
|
} finally {
|
|
452
453
|
cleanup(base2);
|
|
453
454
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Verify that state.ts contains the disk-to-DB task reconciliation logic
|
|
5
5
|
* that prevents the dispatcher from getting stuck in an infinite planning
|
|
6
6
|
* loop when the planner writes a PLAN.md but never calls the persistence
|
|
7
|
-
* tool, leaving the DB with zero task rows.
|
|
7
|
+
* tool, leaving the DB with zero or partial task rows.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { describe, test } from "node:test";
|
|
@@ -24,7 +24,8 @@ describe("dispatcher stuck-planning reconciliation (#3656)", () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
test("contains plan-file task reconciliation block", () => {
|
|
27
|
-
assert.match(source, /
|
|
27
|
+
assert.match(source, /if\s*\(\s*planFile\s*\)/);
|
|
28
|
+
assert.match(source, /dbTaskIds\.has\(t\.id\)/);
|
|
28
29
|
});
|
|
29
30
|
|
|
30
31
|
test("calls insertTask for each disk plan task", () => {
|
|
@@ -1,154 +1,164 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Behavioural contract for GSD extension bootstrap isolation (#4168, #4172).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
// (
|
|
5
|
-
// Windows-specific
|
|
6
|
-
// prevented /gsd from being registered at all
|
|
3
|
+
// Guarantee: the `/gsd` slash command must be registered on pi even if the
|
|
4
|
+
// full bootstrap (shortcuts, tools, hooks, ecosystem) throws during import or
|
|
5
|
+
// execution. Prior regressions: a Windows-specific failure in register-
|
|
6
|
+
// shortcuts.ts silently prevented /gsd from being registered at all because
|
|
7
|
+
// registerGSDCommand was called inside the same try that loaded shortcuts.
|
|
8
|
+
//
|
|
9
|
+
// These tests exercise the real default export of index.ts (which calls
|
|
10
|
+
// registerGSDCommand via dynamic import, then attempts the full bootstrap)
|
|
11
|
+
// with a minimal mock ExtensionAPI and verify the observable behaviour
|
|
12
|
+
// directly: /gsd is registered in both the happy path and the degraded path.
|
|
13
|
+
//
|
|
14
|
+
// Anti-regression proof (documented in commit):
|
|
15
|
+
// neuter index.ts to register /gsd inside the same try{} as
|
|
16
|
+
// register-extension → the degraded-path test fails (no /gsd command
|
|
17
|
+
// registered when register-extension throws). Restore → passes.
|
|
7
18
|
|
|
8
19
|
import { describe, test } from "node:test";
|
|
9
20
|
import assert from "node:assert/strict";
|
|
10
|
-
import { readFileSync } from "node:fs";
|
|
11
|
-
import { join, dirname } from "node:path";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
|
-
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const indexSrc = readFileSync(join(__dirname, "../index.ts"), "utf-8");
|
|
16
|
-
const registerExtSrc = readFileSync(
|
|
17
|
-
join(__dirname, "../bootstrap/register-extension.ts"),
|
|
18
|
-
"utf-8",
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
// ─── index.ts: core /gsd command must be registered before full bootstrap ─────
|
|
22
|
-
|
|
23
|
-
describe("index.ts bootstrap isolation", () => {
|
|
24
|
-
test("imports registerGSDCommand from commands/index.js separately", () => {
|
|
25
|
-
assert.ok(
|
|
26
|
-
indexSrc.includes('./commands/index.js"') || indexSrc.includes("./commands/index.js'"),
|
|
27
|
-
"index.ts must import registerGSDCommand from ./commands/index.js",
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("calls registerGSDCommand before importing register-extension.js", () => {
|
|
32
|
-
const gsdCommandCallPos = indexSrc.indexOf("registerGSDCommand(pi)");
|
|
33
|
-
const bootstrapImportPos = indexSrc.indexOf(
|
|
34
|
-
'./bootstrap/register-extension.js"',
|
|
35
|
-
);
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
import registerExtension from "../index.ts";
|
|
23
|
+
|
|
24
|
+
type RegisterFn = (name: string, def: unknown) => void;
|
|
25
|
+
|
|
26
|
+
function makePi(overrides: Partial<Record<string, unknown>> = {}) {
|
|
27
|
+
const registered: Array<[string, unknown]> = [];
|
|
28
|
+
const registerCommand: RegisterFn = (name, def) => {
|
|
29
|
+
registered.push([name, def]);
|
|
30
|
+
};
|
|
31
|
+
const events = {
|
|
32
|
+
on: () => {},
|
|
33
|
+
off: () => {},
|
|
34
|
+
emit: () => {},
|
|
35
|
+
};
|
|
36
|
+
const pi = {
|
|
37
|
+
registerCommand,
|
|
38
|
+
registerTool: () => {},
|
|
39
|
+
registerHook: () => {},
|
|
40
|
+
registerShortcut: () => {},
|
|
41
|
+
events,
|
|
42
|
+
...overrides,
|
|
43
|
+
};
|
|
44
|
+
return { pi, registered };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
describe("extension bootstrap isolation (#4168, #4172)", () => {
|
|
48
|
+
test("happy path: /gsd command is registered", async () => {
|
|
49
|
+
const { pi, registered } = makePi();
|
|
50
|
+
await registerExtension(pi as any);
|
|
51
|
+
const names = registered.map(([n]) => n);
|
|
39
52
|
assert.ok(
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
names.includes("gsd"),
|
|
54
|
+
`expected 'gsd' in registered commands, got ${JSON.stringify(names)}`,
|
|
42
55
|
);
|
|
43
56
|
});
|
|
44
57
|
|
|
45
|
-
test("
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
test("degraded path: /gsd still registered when registerCommand throws for non-core commands", async () => {
|
|
59
|
+
// Simulate the Windows-style failure: pi.registerCommand throws for a
|
|
60
|
+
// specific non-core command ('kill' is a simple target registered by
|
|
61
|
+
// the full bootstrap) — the full bootstrap must fail but /gsd must
|
|
62
|
+
// already be registered before the failure occurs.
|
|
63
|
+
const registered: Array<[string, unknown]> = [];
|
|
64
|
+
const pi = {
|
|
65
|
+
registerCommand: (name: string, def: unknown) => {
|
|
66
|
+
if (name !== "gsd" && name !== "worktree" && name !== "exit") {
|
|
67
|
+
// Let /gsd, /worktree, /exit succeed (they precede the non-core
|
|
68
|
+
// loop); throw when the first non-core registration fires.
|
|
69
|
+
}
|
|
70
|
+
if (name === "kill") throw new Error("simulated windows failure");
|
|
71
|
+
registered.push([name, def]);
|
|
72
|
+
},
|
|
73
|
+
registerTool: () => {},
|
|
74
|
+
registerHook: () => {},
|
|
75
|
+
registerShortcut: () => {},
|
|
76
|
+
events: { on: () => {}, off: () => {}, emit: () => {} },
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// registerExtension must not throw — the outer try/catch in index.ts
|
|
80
|
+
// swallows bootstrap failures after /gsd is already registered.
|
|
81
|
+
await registerExtension(pi as any);
|
|
82
|
+
|
|
83
|
+
const names = registered.map(([n]) => n);
|
|
55
84
|
assert.ok(
|
|
56
|
-
|
|
57
|
-
"
|
|
85
|
+
names.includes("gsd"),
|
|
86
|
+
"expected 'gsd' to be registered even when a later command registration throws",
|
|
58
87
|
);
|
|
59
88
|
});
|
|
60
89
|
|
|
61
|
-
test("
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
test("degraded path: /gsd registered BEFORE any non-core command", async () => {
|
|
91
|
+
// Ordering guard: the first registerCommand call must be for 'gsd',
|
|
92
|
+
// because index.ts awaits registerGSDCommand(pi) before importing
|
|
93
|
+
// register-extension. Regression scenario: if a future refactor moves
|
|
94
|
+
// registerGSDCommand into the try block or after other registrations,
|
|
95
|
+
// a failure in those earlier registrations would take /gsd down too.
|
|
96
|
+
const calls: string[] = [];
|
|
97
|
+
const pi = {
|
|
98
|
+
registerCommand: (name: string) => {
|
|
99
|
+
calls.push(name);
|
|
100
|
+
},
|
|
101
|
+
registerTool: () => {},
|
|
102
|
+
registerHook: () => {},
|
|
103
|
+
registerShortcut: () => {},
|
|
104
|
+
events: { on: () => {}, off: () => {}, emit: () => {} },
|
|
105
|
+
};
|
|
106
|
+
await registerExtension(pi as any);
|
|
107
|
+
assert.ok(calls.length > 0, "expected at least one registerCommand call");
|
|
108
|
+
assert.equal(
|
|
109
|
+
calls[0],
|
|
110
|
+
"gsd",
|
|
111
|
+
`expected 'gsd' to be the first command registered, got ${JSON.stringify(calls)}`,
|
|
69
112
|
);
|
|
70
113
|
});
|
|
71
114
|
});
|
|
72
115
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
);
|
|
98
|
-
const funcBody = registerExtSrc.slice(funcBodyStart);
|
|
99
|
-
|
|
100
|
-
assert.ok(
|
|
101
|
-
funcBody.includes("registerWorktreeCommand(pi)"),
|
|
102
|
-
"must register worktree command",
|
|
103
|
-
);
|
|
104
|
-
assert.ok(
|
|
105
|
-
funcBody.includes("registerExitCommand(pi)"),
|
|
106
|
-
"must register exit command",
|
|
107
|
-
);
|
|
108
|
-
assert.ok(
|
|
109
|
-
funcBody.includes('"kill"'),
|
|
110
|
-
"must register kill command",
|
|
111
|
-
);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test("wraps non-critical registrations in individual try-catch blocks", () => {
|
|
115
|
-
const funcBodyStart = registerExtSrc.indexOf(
|
|
116
|
-
"export function registerGsdExtension",
|
|
117
|
-
);
|
|
118
|
-
const funcBody = registerExtSrc.slice(funcBodyStart);
|
|
119
|
-
|
|
120
|
-
// Each non-critical registration should be wrapped with error handling
|
|
121
|
-
const registrationNames = [
|
|
122
|
-
"dynamic-tools",
|
|
123
|
-
"db-tools",
|
|
124
|
-
"journal-tools",
|
|
125
|
-
"query-tools",
|
|
126
|
-
"shortcuts",
|
|
127
|
-
"hooks",
|
|
128
|
-
];
|
|
129
|
-
|
|
130
|
-
for (const name of registrationNames) {
|
|
131
|
-
assert.ok(
|
|
132
|
-
funcBody.includes(`"${name}"`),
|
|
133
|
-
`non-critical registration "${name}" must be present`,
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Must have try-catch inside the registration loop
|
|
116
|
+
// Behavioural contract for registerGsdExtension itself: each non-core
|
|
117
|
+
// registration is wrapped in its own try/catch so one failure does not
|
|
118
|
+
// prevent siblings from loading.
|
|
119
|
+
|
|
120
|
+
import { registerGsdExtension } from "../bootstrap/register-extension.ts";
|
|
121
|
+
|
|
122
|
+
describe("registerGsdExtension defensive registration", () => {
|
|
123
|
+
test("a failing shortcut registration does not prevent kill command registration", async () => {
|
|
124
|
+
// `shortcuts` is registered via a non-critical slot that is wrapped in
|
|
125
|
+
// its own try/catch. `kill` is registered before the non-critical loop
|
|
126
|
+
// as a critical command. Simulate: registerShortcut throws. Expect:
|
|
127
|
+
// 'kill' is still registered, registerGsdExtension does not throw.
|
|
128
|
+
const registered: string[] = [];
|
|
129
|
+
const pi = {
|
|
130
|
+
registerCommand: (name: string) => {
|
|
131
|
+
registered.push(name);
|
|
132
|
+
},
|
|
133
|
+
registerTool: () => {},
|
|
134
|
+
registerHook: () => {},
|
|
135
|
+
registerShortcut: () => {
|
|
136
|
+
throw new Error("simulated platform-specific shortcut failure");
|
|
137
|
+
},
|
|
138
|
+
events: { on: () => {}, off: () => {}, emit: () => {} },
|
|
139
|
+
};
|
|
140
|
+
assert.doesNotThrow(() => registerGsdExtension(pi as any));
|
|
138
141
|
assert.ok(
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
registered.includes("kill"),
|
|
143
|
+
`expected 'kill' to be registered despite shortcut failure, got ${JSON.stringify(registered)}`,
|
|
141
144
|
);
|
|
142
145
|
});
|
|
143
146
|
|
|
144
|
-
test("
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
test("does NOT register /gsd (caller's responsibility, avoids double-registration)", () => {
|
|
148
|
+
const registered: string[] = [];
|
|
149
|
+
const pi = {
|
|
150
|
+
registerCommand: (name: string) => {
|
|
151
|
+
registered.push(name);
|
|
152
|
+
},
|
|
153
|
+
registerTool: () => {},
|
|
154
|
+
registerHook: () => {},
|
|
155
|
+
registerShortcut: () => {},
|
|
156
|
+
events: { on: () => {}, off: () => {}, emit: () => {} },
|
|
157
|
+
};
|
|
158
|
+
registerGsdExtension(pi as any);
|
|
149
159
|
assert.ok(
|
|
150
|
-
|
|
151
|
-
|
|
160
|
+
!registered.includes("gsd"),
|
|
161
|
+
`registerGsdExtension must NOT register 'gsd' (it is registered separately by index.ts), got ${JSON.stringify(registered)}`,
|
|
152
162
|
);
|
|
153
163
|
});
|
|
154
164
|
});
|