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
|
@@ -107,7 +107,8 @@ describe("auditOrphanedMilestoneBranches", () => {
|
|
|
107
107
|
assert.ok(branches.includes("milestone/M001"), "unmerged branch must be preserved");
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
-
test("skips active (
|
|
110
|
+
test("skips active milestone branch with no commits ahead of main (nothing to recover)", () => {
|
|
111
|
+
// Branch created from main with zero divergence — no live work, nothing to warn about.
|
|
111
112
|
run("git branch milestone/M001", dir);
|
|
112
113
|
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
113
114
|
|
|
@@ -116,11 +117,67 @@ describe("auditOrphanedMilestoneBranches", () => {
|
|
|
116
117
|
assert.deepStrictEqual(result.recovered, []);
|
|
117
118
|
assert.deepStrictEqual(result.warnings, []);
|
|
118
119
|
|
|
119
|
-
// Branch should still exist
|
|
120
|
+
// Branch should still exist (data safety — user may intend to use it)
|
|
120
121
|
const branches = run("git branch --list milestone/M001", dir);
|
|
121
122
|
assert.ok(branches.includes("milestone/M001"), "active milestone branch should be preserved");
|
|
122
123
|
});
|
|
123
124
|
|
|
125
|
+
test("#4762 — warns about in-progress milestone with unmerged commits ahead of main", () => {
|
|
126
|
+
// Simulates the primary #4761 scenario: auto-mode was interrupted mid-milestone.
|
|
127
|
+
// DB status = active/in_progress, branch has real work, main is behind.
|
|
128
|
+
run("git checkout -b milestone/M001", dir);
|
|
129
|
+
writeFileSync(join(dir, "feature.txt"), "in-progress work\n");
|
|
130
|
+
run("git add feature.txt", dir);
|
|
131
|
+
run("git commit -m \"in-progress work on M001\"", dir);
|
|
132
|
+
run("git checkout main", dir);
|
|
133
|
+
|
|
134
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
135
|
+
|
|
136
|
+
const result = auditOrphanedMilestoneBranches(dir, "worktree");
|
|
137
|
+
|
|
138
|
+
// Must NOT recover/delete (data safety — work is live)
|
|
139
|
+
assert.deepStrictEqual(result.recovered, [], "must not delete a branch with live in-progress work");
|
|
140
|
+
|
|
141
|
+
// Must surface a warning so the user knows the worktree holds uncollapsed work
|
|
142
|
+
assert.ok(result.warnings.length > 0, "should warn about in-progress orphan");
|
|
143
|
+
assert.ok(
|
|
144
|
+
result.warnings.some(w => w.includes("milestone/M001") && w.includes("in-progress")),
|
|
145
|
+
`warning should mention milestone/M001 and in-progress state; got: ${JSON.stringify(result.warnings)}`,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
// Branch must still exist
|
|
149
|
+
const branches = run("git branch --list milestone/M001", dir);
|
|
150
|
+
assert.ok(branches.includes("milestone/M001"), "in-progress branch must be preserved");
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("#4762 — also surfaces worktree directory for in-progress orphan when present", () => {
|
|
154
|
+
// In-progress + unmerged + physical worktree directory — the full primary scenario.
|
|
155
|
+
run("git checkout -b milestone/M001", dir);
|
|
156
|
+
writeFileSync(join(dir, "feature.txt"), "in-progress work\n");
|
|
157
|
+
run("git add feature.txt", dir);
|
|
158
|
+
run("git commit -m \"in-progress work on M001\"", dir);
|
|
159
|
+
run("git checkout main", dir);
|
|
160
|
+
|
|
161
|
+
// Simulate a leftover worktree directory
|
|
162
|
+
const wtDir = join(dir, ".gsd", "worktrees", "M001");
|
|
163
|
+
mkdirSync(wtDir, { recursive: true });
|
|
164
|
+
writeFileSync(join(wtDir, ".git"), `gitdir: ${join(dir, ".git", "worktrees", "M001")}\n`);
|
|
165
|
+
|
|
166
|
+
insertMilestone({ id: "M001", title: "Test", status: "active" });
|
|
167
|
+
|
|
168
|
+
const result = auditOrphanedMilestoneBranches(dir, "worktree");
|
|
169
|
+
|
|
170
|
+
// Must preserve everything for data safety
|
|
171
|
+
assert.deepStrictEqual(result.recovered, [], "must not touch worktree or branch with live work");
|
|
172
|
+
assert.ok(existsSync(wtDir), "worktree directory must be preserved");
|
|
173
|
+
|
|
174
|
+
// Warning should mention the worktree path so the user can find the work
|
|
175
|
+
assert.ok(
|
|
176
|
+
result.warnings.some(w => w.includes(".gsd/worktrees/M001") || w.includes("worktree")),
|
|
177
|
+
`warning should reference the worktree location; got: ${JSON.stringify(result.warnings)}`,
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
124
181
|
test("cleans up orphaned worktree directory for merged milestone", () => {
|
|
125
182
|
// Create milestone branch (merged — same as main)
|
|
126
183
|
run("git branch milestone/M001", dir);
|
|
@@ -1,165 +1,308 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* parallel-research-dispatch.test.ts — behaviour tests for the
|
|
3
|
+
* "planning (multiple slices need research) → parallel-research-slices"
|
|
4
|
+
* dispatch rule and its prompt builder.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
6
|
+
* These tests invoke the real functions (resolveDispatch,
|
|
7
|
+
* buildParallelResearchSlicesPrompt) against on-disk fixtures. They do
|
|
8
|
+
* not read source files and string-match identifiers.
|
|
9
|
+
*
|
|
10
|
+
* See #4784 for why the previous source-grep version of this file was
|
|
11
|
+
* replaced.
|
|
5
12
|
*/
|
|
6
13
|
|
|
7
|
-
import test,
|
|
14
|
+
import { describe, test, beforeEach, afterEach, after } from "node:test";
|
|
8
15
|
import assert from "node:assert/strict";
|
|
9
|
-
import { mkdtempSync, mkdirSync,
|
|
10
|
-
import { join
|
|
16
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { join } from "node:path";
|
|
11
18
|
import { tmpdir } from "node:os";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
19
|
|
|
14
|
-
|
|
20
|
+
// Point GSD_HOME at a throwaway directory *before* the prompt-loader
|
|
21
|
+
// module is imported (via the dynamic imports below) so templates
|
|
22
|
+
// resolve from the in-tree prompts/ directory instead of a developer's
|
|
23
|
+
// ~/.gsd/ copy (which may be a stale cached version from a prior
|
|
24
|
+
// install — see #4784 fallout). Static imports above are hoisted, so
|
|
25
|
+
// `tmpdir` and `join` are already available at this point; the dynamic
|
|
26
|
+
// imports below observe the value we set here. The previous value is
|
|
27
|
+
// captured and restored in an after() hook to avoid leaking module-scope
|
|
28
|
+
// env mutation into other suites if the runner ever moves to a shared
|
|
29
|
+
// process model.
|
|
30
|
+
const previousGsdHome = process.env.GSD_HOME;
|
|
31
|
+
process.env.GSD_HOME = process.env.GSD_HOME_TEST_OVERRIDE
|
|
32
|
+
?? join(tmpdir(), `gsd-test-home-${process.pid}-${Date.now()}`);
|
|
15
33
|
|
|
16
|
-
|
|
34
|
+
after(() => {
|
|
35
|
+
if (previousGsdHome === undefined) {
|
|
36
|
+
delete process.env.GSD_HOME;
|
|
37
|
+
} else {
|
|
38
|
+
process.env.GSD_HOME = previousGsdHome;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
17
41
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const templatePath = join(__dirname, "..", "prompts", "parallel-research-slices.md");
|
|
21
|
-
const templateSrc = readFileSync(templatePath, "utf-8");
|
|
42
|
+
const { resolveDispatch } = await import("../auto-dispatch.ts");
|
|
43
|
+
const { buildParallelResearchSlicesPrompt } = await import("../auto-prompts.ts");
|
|
22
44
|
|
|
23
|
-
|
|
45
|
+
type DispatchState = Parameters<typeof resolveDispatch>[0]["state"];
|
|
24
46
|
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
47
|
+
function writeRoadmap(
|
|
48
|
+
base: string,
|
|
49
|
+
mid: string,
|
|
50
|
+
slices: Array<{ id: string; title: string; done?: boolean; depends?: string[] }>,
|
|
51
|
+
): void {
|
|
52
|
+
const milestoneDir = join(base, ".gsd", "milestones", mid);
|
|
29
53
|
mkdirSync(milestoneDir, { recursive: true });
|
|
54
|
+
const lines = [
|
|
55
|
+
`# ${mid}: Parallel Research Milestone`,
|
|
56
|
+
"",
|
|
57
|
+
"**Vision:** Research-ready slices.",
|
|
58
|
+
"",
|
|
59
|
+
"**Success Criteria:**",
|
|
60
|
+
"- Research all slices",
|
|
61
|
+
"",
|
|
62
|
+
"## Slices",
|
|
63
|
+
"",
|
|
64
|
+
];
|
|
65
|
+
for (const s of slices) {
|
|
66
|
+
const box = s.done ? "x" : " ";
|
|
67
|
+
const deps = s.depends ? `depends:[${s.depends.join(",")}]` : "depends:[]";
|
|
68
|
+
lines.push(`- [${box}] **${s.id}: ${s.title}** \`risk:low\` \`${deps}\``);
|
|
69
|
+
}
|
|
70
|
+
lines.push("", "## Boundary Map", "");
|
|
30
71
|
writeFileSync(
|
|
31
|
-
join(milestoneDir,
|
|
32
|
-
|
|
33
|
-
"# M001: Parallel Research Milestone",
|
|
34
|
-
"",
|
|
35
|
-
"**Vision:** Research-ready slices.",
|
|
36
|
-
"",
|
|
37
|
-
"**Success Criteria:**",
|
|
38
|
-
"- Research both slices",
|
|
39
|
-
"",
|
|
40
|
-
"## Slices",
|
|
41
|
-
"",
|
|
42
|
-
"- [ ] **S01: Alpha** `risk:low` `depends:[]`",
|
|
43
|
-
"- [ ] **S02: Beta** `risk:low` `depends:[]`",
|
|
44
|
-
"",
|
|
45
|
-
"## Boundary Map",
|
|
46
|
-
"",
|
|
47
|
-
].join("\n"),
|
|
72
|
+
join(milestoneDir, `${mid}-ROADMAP.md`),
|
|
73
|
+
lines.join("\n"),
|
|
48
74
|
"utf-8",
|
|
49
75
|
);
|
|
50
|
-
return base;
|
|
51
76
|
}
|
|
52
77
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
78
|
+
function assertNotParallelResearchDispatch(
|
|
79
|
+
action: Awaited<ReturnType<typeof resolveDispatch>>,
|
|
80
|
+
mid = "M001",
|
|
81
|
+
): void {
|
|
82
|
+
if (action.action === "dispatch") {
|
|
83
|
+
assert.notEqual(action.unitId, `${mid}/parallel-research`);
|
|
60
84
|
}
|
|
61
|
-
|
|
62
|
-
});
|
|
85
|
+
}
|
|
63
86
|
|
|
64
|
-
|
|
87
|
+
function baseState(activeSliceId = "S01", activeSliceTitle = "Alpha"): DispatchState {
|
|
88
|
+
return {
|
|
89
|
+
phase: "planning",
|
|
90
|
+
activeMilestone: { id: "M001", title: "Parallel Research Milestone", status: "active" },
|
|
91
|
+
activeSlice: { id: activeSliceId, title: activeSliceTitle },
|
|
92
|
+
activeTask: null,
|
|
93
|
+
registry: [],
|
|
94
|
+
blockers: [],
|
|
95
|
+
} as unknown as DispatchState;
|
|
96
|
+
}
|
|
65
97
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
dispatchSrc.includes("parallel-research-slices"),
|
|
69
|
-
"dispatch table should have parallel-research-slices rule",
|
|
70
|
-
);
|
|
71
|
-
});
|
|
98
|
+
describe("parallel-research-slices dispatch rule", () => {
|
|
99
|
+
let base: string;
|
|
72
100
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"rule should require at least 2 slices for parallel dispatch",
|
|
77
|
-
);
|
|
78
|
-
});
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
base = mkdtempSync(join(tmpdir(), "parallel-research-"));
|
|
103
|
+
});
|
|
79
104
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
assert.ok(
|
|
84
|
-
ruleBlock.includes("skip_research") || dispatchSrc.slice(ruleIdx - 300, ruleIdx).includes("skip_research"),
|
|
85
|
-
"rule should check skip_research preference",
|
|
86
|
-
);
|
|
87
|
-
});
|
|
105
|
+
afterEach(() => {
|
|
106
|
+
rmSync(base, { recursive: true, force: true });
|
|
107
|
+
});
|
|
88
108
|
|
|
89
|
-
|
|
109
|
+
test("dispatches parallel research when 2+ slices need research", async () => {
|
|
110
|
+
writeRoadmap(base, "M001", [
|
|
111
|
+
{ id: "S01", title: "Alpha" },
|
|
112
|
+
{ id: "S02", title: "Beta" },
|
|
113
|
+
]);
|
|
90
114
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
115
|
+
const action = await resolveDispatch({
|
|
116
|
+
basePath: base,
|
|
117
|
+
mid: "M001",
|
|
118
|
+
midTitle: "Parallel Research Milestone",
|
|
119
|
+
state: baseState(),
|
|
120
|
+
prefs: undefined,
|
|
121
|
+
});
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
123
|
+
assert.equal(action.action, "dispatch");
|
|
124
|
+
if (action.action === "dispatch") {
|
|
125
|
+
assert.equal(action.unitType, "research-slice");
|
|
126
|
+
assert.equal(action.unitId, "M001/parallel-research");
|
|
127
|
+
}
|
|
128
|
+
});
|
|
104
129
|
|
|
105
|
-
|
|
130
|
+
test("does not dispatch parallel research with only one ready slice", async () => {
|
|
131
|
+
writeRoadmap(base, "M001", [{ id: "S01", title: "Alpha" }]);
|
|
106
132
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
const action = await resolveDispatch({
|
|
134
|
+
basePath: base,
|
|
135
|
+
mid: "M001",
|
|
136
|
+
midTitle: "Parallel Research Milestone",
|
|
137
|
+
state: baseState(),
|
|
138
|
+
prefs: undefined,
|
|
139
|
+
});
|
|
112
140
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// agent to write a BLOCKER note on the second failure rather than looping.
|
|
116
|
-
// Without this, a timing-out subagent causes the orchestrating agent to
|
|
117
|
-
// retry indefinitely (issue #4068 / #4355).
|
|
118
|
-
assert.ok(
|
|
119
|
-
templateSrc.includes("once") || templateSrc.includes("one retry") || templateSrc.match(/retry.{0,20}once/),
|
|
120
|
-
"template should cap subagent retries at one",
|
|
121
|
-
);
|
|
122
|
-
assert.ok(
|
|
123
|
-
templateSrc.toLowerCase().includes("blocker"),
|
|
124
|
-
"template should instruct writing a BLOCKER note instead of infinite retries",
|
|
125
|
-
);
|
|
126
|
-
assert.ok(
|
|
127
|
-
!templateSrc.match(/re-run it individually\s*\n/),
|
|
128
|
-
"template must not have unbounded re-run instruction without a retry cap",
|
|
129
|
-
);
|
|
130
|
-
});
|
|
141
|
+
assertNotParallelResearchDispatch(action);
|
|
142
|
+
});
|
|
131
143
|
|
|
132
|
-
|
|
144
|
+
test("does not dispatch parallel research when skip_research is set", async () => {
|
|
145
|
+
writeRoadmap(base, "M001", [
|
|
146
|
+
{ id: "S01", title: "Alpha" },
|
|
147
|
+
{ id: "S02", title: "Beta" },
|
|
148
|
+
]);
|
|
133
149
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
const action = await resolveDispatch({
|
|
151
|
+
basePath: base,
|
|
152
|
+
mid: "M001",
|
|
153
|
+
midTitle: "Parallel Research Milestone",
|
|
154
|
+
state: baseState(),
|
|
155
|
+
prefs: { phases: { skip_research: true } } as Parameters<typeof resolveDispatch>[0]["prefs"],
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
assertNotParallelResearchDispatch(action);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test("does not dispatch parallel research when skip_slice_research is set", async () => {
|
|
162
|
+
writeRoadmap(base, "M001", [
|
|
163
|
+
{ id: "S01", title: "Alpha" },
|
|
164
|
+
{ id: "S02", title: "Beta" },
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
const action = await resolveDispatch({
|
|
168
|
+
basePath: base,
|
|
169
|
+
mid: "M001",
|
|
170
|
+
midTitle: "Parallel Research Milestone",
|
|
171
|
+
state: baseState(),
|
|
172
|
+
prefs: { phases: { skip_slice_research: true } } as Parameters<typeof resolveDispatch>[0]["prefs"],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
assertNotParallelResearchDispatch(action);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("does not dispatch when a PARALLEL-BLOCKER placeholder exists (#4414)", async () => {
|
|
179
|
+
writeRoadmap(base, "M001", [
|
|
180
|
+
{ id: "S01", title: "Alpha" },
|
|
181
|
+
{ id: "S02", title: "Beta" },
|
|
182
|
+
]);
|
|
183
|
+
const milestoneDir = join(base, ".gsd", "milestones", "M001");
|
|
184
|
+
writeFileSync(
|
|
185
|
+
join(milestoneDir, "M001-PARALLEL-BLOCKER.md"),
|
|
186
|
+
"# Parallel research escalated\nPrevious dispatch failed; need per-slice fallback.\n",
|
|
187
|
+
"utf-8",
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const action = await resolveDispatch({
|
|
191
|
+
basePath: base,
|
|
192
|
+
mid: "M001",
|
|
193
|
+
midTitle: "Parallel Research Milestone",
|
|
194
|
+
state: baseState(),
|
|
195
|
+
prefs: undefined,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
assertNotParallelResearchDispatch(action);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("excludes slices that already have a RESEARCH file (falls back to <2)", async () => {
|
|
202
|
+
writeRoadmap(base, "M001", [
|
|
203
|
+
{ id: "S01", title: "Alpha" },
|
|
204
|
+
{ id: "S02", title: "Beta" },
|
|
205
|
+
]);
|
|
206
|
+
// S01 already has research → only S02 remains → <2 ready → no parallel dispatch
|
|
207
|
+
const s01Dir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
|
|
208
|
+
mkdirSync(s01Dir, { recursive: true });
|
|
209
|
+
writeFileSync(
|
|
210
|
+
join(s01Dir, "S01-RESEARCH.md"),
|
|
211
|
+
"# Research\n",
|
|
212
|
+
"utf-8",
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const action = await resolveDispatch({
|
|
216
|
+
basePath: base,
|
|
217
|
+
mid: "M001",
|
|
218
|
+
midTitle: "Parallel Research Milestone",
|
|
219
|
+
state: baseState(),
|
|
220
|
+
prefs: undefined,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
assertNotParallelResearchDispatch(action);
|
|
224
|
+
});
|
|
140
225
|
});
|
|
141
226
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
midTitle: "Parallel Research Milestone",
|
|
149
|
-
state: {
|
|
150
|
-
phase: "planning",
|
|
151
|
-
activeMilestone: { id: "M001", title: "Parallel Research Milestone", status: "active" },
|
|
152
|
-
activeSlice: { id: "S01", title: "Alpha" },
|
|
153
|
-
activeTask: null,
|
|
154
|
-
registry: [],
|
|
155
|
-
blockers: [],
|
|
156
|
-
} as any,
|
|
157
|
-
prefs: undefined,
|
|
227
|
+
describe("buildParallelResearchSlicesPrompt", () => {
|
|
228
|
+
let base: string;
|
|
229
|
+
|
|
230
|
+
beforeEach(() => {
|
|
231
|
+
base = mkdtempSync(join(tmpdir(), "parallel-research-prompt-"));
|
|
232
|
+
mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
|
|
158
233
|
});
|
|
159
234
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
235
|
+
afterEach(() => {
|
|
236
|
+
rmSync(base, { recursive: true, force: true });
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("renders slice count and every slice title into the prompt", async () => {
|
|
240
|
+
const prompt = await buildParallelResearchSlicesPrompt(
|
|
241
|
+
"M001",
|
|
242
|
+
"Parallel Research Milestone",
|
|
243
|
+
[
|
|
244
|
+
{ id: "S01", title: "Alpha slice title" },
|
|
245
|
+
{ id: "S02", title: "Beta slice title" },
|
|
246
|
+
{ id: "S03", title: "Gamma slice title" },
|
|
247
|
+
],
|
|
248
|
+
base,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
assert.match(
|
|
252
|
+
prompt,
|
|
253
|
+
/\b3\b[^.\n]{0,40}\bslices?\b/i,
|
|
254
|
+
"prompt should include slice count 3 in slice context",
|
|
255
|
+
);
|
|
256
|
+
assert.match(prompt, /Alpha slice title/);
|
|
257
|
+
assert.match(prompt, /Beta slice title/);
|
|
258
|
+
assert.match(prompt, /Gamma slice title/);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("#4068: prompt caps subagent retries at one and instructs writing a BLOCKER on second failure", async () => {
|
|
262
|
+
// Regression for infinite-retry loop (#4068 / #4355 / #4570). A correct
|
|
263
|
+
// fix must both cap retries AND instruct the agent to escalate to a
|
|
264
|
+
// BLOCKER note on the second failure.
|
|
265
|
+
const prompt = await buildParallelResearchSlicesPrompt(
|
|
266
|
+
"M001",
|
|
267
|
+
"Parallel Research Milestone",
|
|
268
|
+
[
|
|
269
|
+
{ id: "S01", title: "Alpha" },
|
|
270
|
+
{ id: "S02", title: "Beta" },
|
|
271
|
+
],
|
|
272
|
+
base,
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
// Cap: the rendered prompt must bound retries. "once" alone is too
|
|
276
|
+
// permissive — the word appears for unrelated reasons across a ~10KB
|
|
277
|
+
// rendered prompt — so the pattern must require retry-context
|
|
278
|
+
// pairing: either "retry ... once" within 30 chars, or the phrase
|
|
279
|
+
// "one retry", or "retry it once".
|
|
280
|
+
assert.match(
|
|
281
|
+
prompt,
|
|
282
|
+
/\bone retry\b|retry[^.?!]{0,30}\bonce\b|retry it \*{0,2}once/i,
|
|
283
|
+
"rendered prompt should cap retries to one",
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
// Escalation: on second failure the agent must write a BLOCKER
|
|
287
|
+
// rather than loop. Bare /blocker/i is too permissive — require
|
|
288
|
+
// retry/failure context within the same sentence so a stray
|
|
289
|
+
// "blocker" elsewhere in the ~10KB prompt cannot satisfy the
|
|
290
|
+
// assertion.
|
|
291
|
+
assert.match(
|
|
292
|
+
prompt,
|
|
293
|
+
/blocker[^.?!]{0,100}(second|retry|fail)|(second|retry|fail)[^.?!]{0,100}blocker/i,
|
|
294
|
+
"rendered prompt should instruct writing a BLOCKER on repeated failure",
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Anti-pattern: the unbounded "re-run it individually" instruction
|
|
298
|
+
// that caused the original infinite loop must not appear on its own.
|
|
299
|
+
// The negative lookahead is bounded to the surrounding 100
|
|
300
|
+
// characters so a later unrelated "once" elsewhere in the prompt
|
|
301
|
+
// cannot falsely satisfy the "paired with a retry bound" exception.
|
|
302
|
+
assert.doesNotMatch(
|
|
303
|
+
prompt,
|
|
304
|
+
/re-run it individually(?![\s\S]{0,100}\bonce\b)/i,
|
|
305
|
+
"rendered prompt must not contain the unbounded re-run instruction",
|
|
306
|
+
);
|
|
307
|
+
});
|
|
165
308
|
});
|