gsd-pi 2.77.0-dev.1d17f366c → 2.77.0-dev.2daa994b6
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/dist/headless.js +25 -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/gsd/auto/phases.js +5 -18
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +37 -8
- package/dist/resources/extensions/gsd/auto-post-unit.js +79 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-start.js +75 -24
- package/dist/resources/extensions/gsd/auto.js +34 -0
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -1
- 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/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gsd-db.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +2 -4
- 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/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 +5 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- 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/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 +334 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +51 -0
- 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 +17 -17
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- 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 +1 -3
- 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/workflow-tools.test.ts +80 -39
- 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/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 +29 -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/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 +39 -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/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/__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/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/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.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/image.test.ts +10 -5
- 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/tests/stream-adapter.test.ts +80 -72
- 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/phases.ts +6 -17
- package/src/resources/extensions/gsd/auto/session.ts +7 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +40 -8
- package/src/resources/extensions/gsd/auto-post-unit.ts +81 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-start.ts +97 -4
- package/src/resources/extensions/gsd/auto.ts +37 -0
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -1
- 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/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/git-service.ts +16 -0
- package/src/resources/extensions/gsd/gsd-db.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +2 -4
- 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/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- 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 +5 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- 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/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +25 -292
- 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-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 +8 -4
- 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/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/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/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/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/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 +1 -1
- 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/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/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/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 +22 -16
- 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/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/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/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/smart-entry-draft.test.ts +2 -1
- 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-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/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +203 -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 -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/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +492 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +53 -0
- 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/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vidAVJkURvTJ0_V2-64ro → gYYky7yfxW8txb9vU2TrJ}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice-cadence collapse — #4765.
|
|
3
|
+
*
|
|
4
|
+
* When `git.collapse_cadence: "slice"` is set, each slice's commits are
|
|
5
|
+
* squash-merged from the milestone branch to main as soon as the slice
|
|
6
|
+
* passes validation. Shrinks the orphan window (#4761) from milestone-size
|
|
7
|
+
* to slice-size and surfaces merge conflicts per-slice rather than all at
|
|
8
|
+
* once at milestone end.
|
|
9
|
+
*
|
|
10
|
+
* This module is deliberately focused and narrower than mergeMilestoneToMain:
|
|
11
|
+
* - No worktree teardown (worktree is reused for the next slice)
|
|
12
|
+
* - No DB reconciliation (modern worktrees share the main DB via path resolver)
|
|
13
|
+
* - No roadmap/summary/gate handling (that's still the milestone's job)
|
|
14
|
+
* - Fails loudly on dirty main — caller is responsible for cleanliness
|
|
15
|
+
*
|
|
16
|
+
* Kernighan: the v1 surface handles the happy path + conflict. Edge cases
|
|
17
|
+
* that mergeMilestoneToMain covers (concurrent merges, shared DB paths,
|
|
18
|
+
* submodules) are explicit non-goals; users opt in via preference and early-
|
|
19
|
+
* adopter scenarios are scoped narrow.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { execFileSync } from "node:child_process";
|
|
24
|
+
import { GSDError, GSD_GIT_ERROR } from "./errors.js";
|
|
25
|
+
import { MergeConflictError } from "./git-service.js";
|
|
26
|
+
import { nativeBranchForceReset, nativeCheckoutBranch, nativeCommit, nativeCommitCountBetween, nativeConflictFiles, nativeDetectMainBranch, nativeMergeSquash, } from "./native-git-bridge.js";
|
|
27
|
+
import { resolveGitDir } from "./worktree-manager.js";
|
|
28
|
+
import { logWarning } from "./workflow-logger.js";
|
|
29
|
+
import { emitSliceMerged, emitMilestoneResquash } from "./worktree-telemetry.js";
|
|
30
|
+
/**
|
|
31
|
+
* Auto-worktree milestone branch name. Must match autoWorktreeBranch() in
|
|
32
|
+
* auto-worktree.ts; duplicated here to avoid a cyclic import.
|
|
33
|
+
*/
|
|
34
|
+
function milestoneBranchName(milestoneId) {
|
|
35
|
+
return `milestone/${milestoneId}`;
|
|
36
|
+
}
|
|
37
|
+
function cleanupMergeArtifacts(projectRoot) {
|
|
38
|
+
try {
|
|
39
|
+
const gitDir = resolveGitDir(projectRoot);
|
|
40
|
+
for (const f of ["SQUASH_MSG", "MERGE_MSG", "MERGE_HEAD"]) {
|
|
41
|
+
const p = join(gitDir, f);
|
|
42
|
+
if (existsSync(p))
|
|
43
|
+
unlinkSync(p);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
logWarning("worktree", `merge artifact cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Squash-merge one slice's commits from the milestone branch to main.
|
|
52
|
+
*
|
|
53
|
+
* Preconditions:
|
|
54
|
+
* - Caller is on the milestone branch inside the worktree
|
|
55
|
+
* - `projectRoot` points at the real project root (not the worktree)
|
|
56
|
+
*
|
|
57
|
+
* Post-conditions on success:
|
|
58
|
+
* - Slice's commits are a single squash commit on main
|
|
59
|
+
* - `milestone/<MID>` is fast-forwarded to main (so next slice's work
|
|
60
|
+
* starts from a clean base)
|
|
61
|
+
* - caller's process.cwd is restored
|
|
62
|
+
*
|
|
63
|
+
* Throws MergeConflictError on conflicts; caller should surface and stop.
|
|
64
|
+
* Throws GSDError on dirty main / detection failures.
|
|
65
|
+
*/
|
|
66
|
+
export function mergeSliceToMain(projectRoot, milestoneId, sliceId) {
|
|
67
|
+
const started = Date.now();
|
|
68
|
+
const worktreeCwd = process.cwd();
|
|
69
|
+
const milestoneBranch = milestoneBranchName(milestoneId);
|
|
70
|
+
const mainBranch = nativeDetectMainBranch(projectRoot);
|
|
71
|
+
// Fast path: if the milestone branch has no commits ahead of main, there
|
|
72
|
+
// is nothing to merge. Return a skip result instead of no-op'ing silently
|
|
73
|
+
// so the caller's telemetry shows the decision.
|
|
74
|
+
let commitsAhead = 0;
|
|
75
|
+
try {
|
|
76
|
+
commitsAhead = nativeCommitCountBetween(projectRoot, mainBranch, milestoneBranch);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// If we can't count, assume there's work and let the merge proceed —
|
|
80
|
+
// a failing merge is more informative than a silent skip.
|
|
81
|
+
commitsAhead = 1;
|
|
82
|
+
}
|
|
83
|
+
if (commitsAhead === 0) {
|
|
84
|
+
// Do NOT emit slice-merged here — this is a no-op, not a merge. Emitting
|
|
85
|
+
// would inflate slicesMerged in telemetry/forensics and distort the
|
|
86
|
+
// conflict rate denominator.
|
|
87
|
+
return {
|
|
88
|
+
commitSha: null,
|
|
89
|
+
mainBranch,
|
|
90
|
+
milestoneBranch,
|
|
91
|
+
durationMs: Date.now() - started,
|
|
92
|
+
skipped: true,
|
|
93
|
+
skippedReason: "no-commits-ahead",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
process.chdir(projectRoot);
|
|
97
|
+
try {
|
|
98
|
+
// Dirty-main check — v1 fails loudly rather than auto-stashing. Users
|
|
99
|
+
// running slice-cadence opt in knowing main stays clean between merges.
|
|
100
|
+
const status = execFileSync("git", ["status", "--porcelain"], {
|
|
101
|
+
cwd: projectRoot,
|
|
102
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
103
|
+
encoding: "utf-8",
|
|
104
|
+
}).trim();
|
|
105
|
+
if (status) {
|
|
106
|
+
throw new GSDError(GSD_GIT_ERROR, `slice-cadence merge requires a clean project root; uncommitted changes detected. ` +
|
|
107
|
+
`Commit or stash at ${projectRoot} before retrying. Status:\n${status}`);
|
|
108
|
+
}
|
|
109
|
+
nativeCheckoutBranch(projectRoot, mainBranch);
|
|
110
|
+
// Clean any stale merge artifacts before attempting the squash (#2912 pattern)
|
|
111
|
+
cleanupMergeArtifacts(projectRoot);
|
|
112
|
+
const mergeResult = nativeMergeSquash(projectRoot, milestoneBranch);
|
|
113
|
+
if (!mergeResult.success) {
|
|
114
|
+
const conflictedFiles = mergeResult.conflicts.length > 0
|
|
115
|
+
? mergeResult.conflicts
|
|
116
|
+
: nativeConflictFiles(projectRoot);
|
|
117
|
+
cleanupMergeArtifacts(projectRoot);
|
|
118
|
+
try {
|
|
119
|
+
emitSliceMerged(projectRoot, milestoneId, sliceId, {
|
|
120
|
+
durationMs: Date.now() - started,
|
|
121
|
+
conflict: true,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch { /* silent */ }
|
|
125
|
+
throw new MergeConflictError(conflictedFiles, "squash", milestoneBranch, mainBranch);
|
|
126
|
+
}
|
|
127
|
+
// Commit the squash with a slice-scoped message
|
|
128
|
+
const commitSha = nativeCommit(projectRoot, `gsd: merge ${sliceId} of ${milestoneId} (slice-cadence)`);
|
|
129
|
+
// Advance the milestone branch to main so the next slice's commits start
|
|
130
|
+
// from a clean base. Force-reset is safe because we just merged this
|
|
131
|
+
// branch's entire delta.
|
|
132
|
+
nativeBranchForceReset(projectRoot, milestoneBranch, mainBranch);
|
|
133
|
+
const durationMs = Date.now() - started;
|
|
134
|
+
try {
|
|
135
|
+
emitSliceMerged(projectRoot, milestoneId, sliceId, {
|
|
136
|
+
durationMs,
|
|
137
|
+
conflict: false,
|
|
138
|
+
commitSha: commitSha ?? undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
catch { /* silent */ }
|
|
142
|
+
return {
|
|
143
|
+
commitSha,
|
|
144
|
+
mainBranch,
|
|
145
|
+
milestoneBranch,
|
|
146
|
+
durationMs,
|
|
147
|
+
skipped: false,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
// Always restore cwd even if anything above threw.
|
|
152
|
+
try {
|
|
153
|
+
process.chdir(worktreeCwd);
|
|
154
|
+
}
|
|
155
|
+
catch { /* best-effort */ }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Re-squash per-slice commits on main into a single milestone commit.
|
|
160
|
+
*
|
|
161
|
+
* Runs at milestone completion when `collapse_cadence: "slice"` AND
|
|
162
|
+
* `milestone_resquash: true`. The `startSha` is the SHA of main immediately
|
|
163
|
+
* before the milestone's first slice merge — the caller is responsible for
|
|
164
|
+
* recording this (AutoSession field, git ref, or DB row).
|
|
165
|
+
*
|
|
166
|
+
* Strategy: soft-reset main to startSha, then commit the net diff. The
|
|
167
|
+
* N slice commits between startSha and HEAD are collapsed into one.
|
|
168
|
+
*
|
|
169
|
+
* No-op (returns false) if startSha equals HEAD (nothing to re-squash).
|
|
170
|
+
*/
|
|
171
|
+
export function resquashMilestoneOnMain(projectRoot, milestoneId, startSha) {
|
|
172
|
+
const mainBranch = nativeDetectMainBranch(projectRoot);
|
|
173
|
+
const worktreeCwd = process.cwd();
|
|
174
|
+
process.chdir(projectRoot);
|
|
175
|
+
try {
|
|
176
|
+
nativeCheckoutBranch(projectRoot, mainBranch);
|
|
177
|
+
// Verify the startSha..HEAD range contains ONLY this milestone's slice-
|
|
178
|
+
// cadence commits. If any unrelated commits landed on main since the
|
|
179
|
+
// milestone started (e.g. concurrent work, cherry-picks, hotfixes), a
|
|
180
|
+
// blind `git reset --soft` would fold them into the re-squash and rewrite
|
|
181
|
+
// their attribution. Fail closed — the user can resolve manually.
|
|
182
|
+
const expectedSuffix = `(slice-cadence)`;
|
|
183
|
+
const expectedMilestoneToken = ` of ${milestoneId} `;
|
|
184
|
+
let subjectsRaw = "";
|
|
185
|
+
try {
|
|
186
|
+
subjectsRaw = execFileSync("git", ["log", "--format=%s", `${startSha}..HEAD`], { cwd: projectRoot, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return { resquashed: false, newSha: null };
|
|
190
|
+
}
|
|
191
|
+
const subjects = subjectsRaw.split("\n").filter((s) => s.length > 0);
|
|
192
|
+
const sliceCount = subjects.length;
|
|
193
|
+
if (sliceCount === 0) {
|
|
194
|
+
return { resquashed: false, newSha: null };
|
|
195
|
+
}
|
|
196
|
+
const foreign = subjects.filter((s) => !(s.endsWith(expectedSuffix) && s.includes(expectedMilestoneToken)));
|
|
197
|
+
if (foreign.length > 0) {
|
|
198
|
+
logWarning("worktree", `slice-cadence: skipping milestone resquash for ${milestoneId} — ` +
|
|
199
|
+
`${foreign.length} non-slice-cadence commit(s) in ${startSha}..HEAD ` +
|
|
200
|
+
`would be folded in. First: "${foreign[0]}". Resolve history manually.`);
|
|
201
|
+
return { resquashed: false, newSha: null };
|
|
202
|
+
}
|
|
203
|
+
// Safe to collapse: all commits in the range are this milestone's slices.
|
|
204
|
+
execFileSync("git", ["reset", "--soft", startSha], {
|
|
205
|
+
cwd: projectRoot,
|
|
206
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
207
|
+
encoding: "utf-8",
|
|
208
|
+
});
|
|
209
|
+
const newSha = nativeCommit(projectRoot, `gsd: complete milestone ${milestoneId} (${sliceCount} slices re-squashed)`, { allowEmpty: true });
|
|
210
|
+
try {
|
|
211
|
+
emitMilestoneResquash(projectRoot, milestoneId, {
|
|
212
|
+
sliceCount,
|
|
213
|
+
startSha,
|
|
214
|
+
endSha: newSha ?? undefined,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch { /* silent */ }
|
|
218
|
+
return { resquashed: true, newSha };
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
try {
|
|
222
|
+
process.chdir(worktreeCwd);
|
|
223
|
+
}
|
|
224
|
+
catch { /* best-effort */ }
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Read the effective collapse cadence from validated preferences. Accepts
|
|
229
|
+
* a raw preferences object (the shape loadEffectiveGSDPreferences returns).
|
|
230
|
+
*/
|
|
231
|
+
export function getCollapseCadence(prefs) {
|
|
232
|
+
return prefs?.git?.collapse_cadence ?? "milestone";
|
|
233
|
+
}
|
|
234
|
+
export function getMilestoneResquash(prefs) {
|
|
235
|
+
// Default true when cadence is slice — resquash preserves the milestone-
|
|
236
|
+
// level history shape users expect.
|
|
237
|
+
return prefs?.git?.milestone_resquash !== false;
|
|
238
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { transaction, insertAssessment, deleteAssessmentByScope, getMilestoneSlices, } from "../gsd-db.js";
|
|
13
13
|
import { resolveMilestonePath, clearPathCache } from "../paths.js";
|
|
14
|
+
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
14
15
|
import { saveFile, clearParseCache } from "../files.js";
|
|
15
16
|
import { invalidateStateCache } from "../state.js";
|
|
16
17
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
@@ -59,14 +60,18 @@ export async function handleValidateMilestone(params, basePath, opts) {
|
|
|
59
60
|
return { error: `verdict must be one of: ${VALIDATION_VERDICTS.join(", ")}` };
|
|
60
61
|
}
|
|
61
62
|
// ── Resolve paths and render markdown ────────────────────────────────
|
|
63
|
+
// #4761: route through the canonical-root resolver so that when a live
|
|
64
|
+
// worktree exists for this milestone, validation reads/writes the
|
|
65
|
+
// worktree's artifacts instead of stale project-root state.
|
|
62
66
|
const validationMd = renderValidationMarkdown(params);
|
|
67
|
+
const canonicalBase = resolveCanonicalMilestoneRoot(basePath, params.milestoneId);
|
|
63
68
|
let validationPath;
|
|
64
|
-
const milestoneDir = resolveMilestonePath(
|
|
69
|
+
const milestoneDir = resolveMilestonePath(canonicalBase, params.milestoneId);
|
|
65
70
|
if (milestoneDir) {
|
|
66
71
|
validationPath = join(milestoneDir, `${params.milestoneId}-VALIDATION.md`);
|
|
67
72
|
}
|
|
68
73
|
else {
|
|
69
|
-
const gsdDir = join(
|
|
74
|
+
const gsdDir = join(canonicalBase, ".gsd");
|
|
70
75
|
const manualDir = join(gsdDir, "milestones", params.milestoneId);
|
|
71
76
|
validationPath = join(manualDir, `${params.milestoneId}-VALIDATION.md`);
|
|
72
77
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// GSD-2 — UnitContextComposer (#4782 phase 2).
|
|
2
|
+
//
|
|
3
|
+
// Reads a unit type's manifest and orchestrates artifact inlining through
|
|
4
|
+
// a caller-provided resolver. Returns a joined context block suitable for
|
|
5
|
+
// substitution into the unit's prompt template.
|
|
6
|
+
//
|
|
7
|
+
// Design rationale:
|
|
8
|
+
// - Pure dependency on the manifest module — no circular import with
|
|
9
|
+
// `auto-prompts.ts` where the per-artifact-key resolver lives.
|
|
10
|
+
// - Caller-supplied resolver means the composer can be unit-tested with
|
|
11
|
+
// trivial mocks; production wiring in `auto-prompts.ts` dispatches to
|
|
12
|
+
// the existing `inlineFile` / `inline*FromDb` helpers.
|
|
13
|
+
// - Null-returning resolvers are skipped silently: they model the
|
|
14
|
+
// "artifact is optional / missing / not applicable to this milestone"
|
|
15
|
+
// case. The composer never errors on a missing artifact.
|
|
16
|
+
//
|
|
17
|
+
// Scope: phase 2 pilot shipped `composeInlinedContext` for static-key
|
|
18
|
+
// inlining. Phase 3.5 (#4924) adds the v2 surface — `composeUnitContext`
|
|
19
|
+
// — which also handles excerpts, computed artifacts, and prepended blocks.
|
|
20
|
+
// `composeInlinedContext` stays for backward compatibility with the
|
|
21
|
+
// already-migrated simple builders.
|
|
22
|
+
//
|
|
23
|
+
// ─── Composer boundary invariant (#4924) ─────────────────────────────────
|
|
24
|
+
//
|
|
25
|
+
// The composer is allowed to:
|
|
26
|
+
// - order named sections per the manifest's declared sequence
|
|
27
|
+
// - resolve registered artifacts (static / computed / excerpt / on-demand)
|
|
28
|
+
// - apply typed policies (knowledge / memory / codebase-map / preferences)
|
|
29
|
+
//
|
|
30
|
+
// The composer must NOT grow:
|
|
31
|
+
// - arbitrary conditionals on unit state
|
|
32
|
+
// - loops over caller-supplied data
|
|
33
|
+
// - string templating beyond section composition (join + separator)
|
|
34
|
+
//
|
|
35
|
+
// Logic that needs those belongs in a typed computed-artifact builder
|
|
36
|
+
// owned by the unit, not in the composer. Reviews must enforce this — it
|
|
37
|
+
// is the difference between an orchestrator and a runaway DSL.
|
|
38
|
+
import { resolveManifest, } from "./unit-context-manifest.js";
|
|
39
|
+
/**
|
|
40
|
+
* Produce the inlined-context portion of a unit's system prompt by
|
|
41
|
+
* walking the manifest's `artifacts.inline` list in order and calling
|
|
42
|
+
* the provided resolver for each key.
|
|
43
|
+
*
|
|
44
|
+
* Returns an empty string when the unit type has no manifest registered,
|
|
45
|
+
* so callers can guard their wiring with a simple truthy check. Unknown
|
|
46
|
+
* unit types do not error — this mirrors `resolveManifest`'s contract.
|
|
47
|
+
*
|
|
48
|
+
* The separator between inlined blocks matches the in-tree convention
|
|
49
|
+
* (`\n\n---\n\n`) so composer output slots into existing prompt templates
|
|
50
|
+
* without visible diff.
|
|
51
|
+
*/
|
|
52
|
+
export async function composeInlinedContext(unitType, resolveArtifact) {
|
|
53
|
+
const manifest = resolveManifest(unitType);
|
|
54
|
+
if (!manifest)
|
|
55
|
+
return "";
|
|
56
|
+
const blocks = [];
|
|
57
|
+
for (const key of manifest.artifacts.inline) {
|
|
58
|
+
const body = await resolveArtifact(key);
|
|
59
|
+
if (body !== null && body.length > 0) {
|
|
60
|
+
blocks.push(body);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return blocks.join("\n\n---\n\n");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Convenience helper returning the manifest's declared budget so callers
|
|
67
|
+
* can telemetry a mismatch between actual prompt size and declared budget.
|
|
68
|
+
* Returns null for unknown unit types.
|
|
69
|
+
*/
|
|
70
|
+
export function manifestBudgetChars(unitType) {
|
|
71
|
+
const manifest = resolveManifest(unitType);
|
|
72
|
+
return manifest ? manifest.maxSystemPromptChars : null;
|
|
73
|
+
}
|
|
74
|
+
const SECTION_SEPARATOR = "\n\n---\n\n";
|
|
75
|
+
/**
|
|
76
|
+
* Compose all manifest-declared context for a unit type using the v2
|
|
77
|
+
* surface. Walks `prepend` first (computed-only), then the `inline` list
|
|
78
|
+
* (static keys via `resolveArtifact`), then `excerpt` (via `resolveExcerpt`),
|
|
79
|
+
* then `artifacts.computed` (via the typed registry). Order within each
|
|
80
|
+
* section follows the manifest's declared sequence.
|
|
81
|
+
*
|
|
82
|
+
* Unknown unit types return empty strings for both sections — callers can
|
|
83
|
+
* fall back to existing imperative wiring without a special case.
|
|
84
|
+
*
|
|
85
|
+
* Resolver / registry omissions: if the manifest declares an entry but no
|
|
86
|
+
* resolver / registry entry is provided, the composer skips it silently.
|
|
87
|
+
* This matches the v1 contract where a null body is a no-op, and lets
|
|
88
|
+
* partial migrations land without forcing every consumer to register
|
|
89
|
+
* every artifact class up-front.
|
|
90
|
+
*/
|
|
91
|
+
export async function composeUnitContext(unitType, opts) {
|
|
92
|
+
const manifest = resolveManifest(unitType);
|
|
93
|
+
if (!manifest)
|
|
94
|
+
return { prepend: "", inline: "" };
|
|
95
|
+
// Single-source `unitType`: the manifest is resolved against the
|
|
96
|
+
// function arg, but computed builders read it from `base.unitType`.
|
|
97
|
+
// If those ever diverge (caller passes one type to composeUnitContext
|
|
98
|
+
// but a different one in opts.base), the composer would silently
|
|
99
|
+
// mix one unit's manifest with another unit's computed context.
|
|
100
|
+
// Normalize here so the composer dispatches a consistent identity
|
|
101
|
+
// through to every builder.
|
|
102
|
+
const normalizedOpts = {
|
|
103
|
+
...opts,
|
|
104
|
+
base: { ...opts.base, unitType },
|
|
105
|
+
};
|
|
106
|
+
const prependBlocks = await runComputed(manifest.prepend ?? [], normalizedOpts);
|
|
107
|
+
const inlineBlocks = [];
|
|
108
|
+
for (const key of manifest.artifacts.inline) {
|
|
109
|
+
if (!normalizedOpts.resolveArtifact)
|
|
110
|
+
break;
|
|
111
|
+
const body = await normalizedOpts.resolveArtifact(key);
|
|
112
|
+
if (body && body.length > 0)
|
|
113
|
+
inlineBlocks.push(body);
|
|
114
|
+
}
|
|
115
|
+
for (const key of manifest.artifacts.excerpt) {
|
|
116
|
+
if (!normalizedOpts.resolveExcerpt)
|
|
117
|
+
break;
|
|
118
|
+
const body = await normalizedOpts.resolveExcerpt(key);
|
|
119
|
+
if (body && body.length > 0)
|
|
120
|
+
inlineBlocks.push(body);
|
|
121
|
+
}
|
|
122
|
+
inlineBlocks.push(...await runComputed(manifest.artifacts.computed ?? [], normalizedOpts));
|
|
123
|
+
return {
|
|
124
|
+
prepend: prependBlocks.join(SECTION_SEPARATOR),
|
|
125
|
+
inline: inlineBlocks.join(SECTION_SEPARATOR),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Invoke the registered builder for each declared computed id, in order.
|
|
130
|
+
* Missing registry entries (manifest declares the id but caller didn't
|
|
131
|
+
* register it) are skipped silently — see composeUnitContext rationale.
|
|
132
|
+
*/
|
|
133
|
+
async function runComputed(ids, opts) {
|
|
134
|
+
if (ids.length === 0 || !opts.computed)
|
|
135
|
+
return [];
|
|
136
|
+
const registry = opts.computed;
|
|
137
|
+
const out = [];
|
|
138
|
+
for (const id of ids) {
|
|
139
|
+
const entry = registry[id];
|
|
140
|
+
if (!entry)
|
|
141
|
+
continue;
|
|
142
|
+
const body = await entry.build(entry.inputs, opts.base);
|
|
143
|
+
if (body && body.length > 0)
|
|
144
|
+
out.push(body);
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|