@opengsd/gsd-pi 1.1.1-dev.a5a2de8 → 1.1.1-dev.b2556262
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-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +18 -2
- package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/index.js +68 -24
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +87 -12
- package/dist/resources/extensions/gsd/auto/session.js +22 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +81 -13
- package/dist/resources/extensions/gsd/auto-model-selection.js +154 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-timers.js +24 -10
- package/dist/resources/extensions/gsd/auto.js +40 -15
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +192 -77
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/config-overlay.js +1 -0
- package/dist/resources/extensions/gsd/context-masker.js +129 -5
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/guided-flow.js +4 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +111 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +15 -1
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +24 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +62 -406
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +38 -14
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -3
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- 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 +6 -6
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +174 -29
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +178 -54
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install/handoff.js +16 -3
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
- package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +75 -27
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
- package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +89 -15
- package/src/resources/extensions/gsd/auto/session.ts +24 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +117 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +190 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +25 -22
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-timers.ts +25 -9
- package/src/resources/extensions/gsd/auto.ts +41 -14
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +250 -78
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/config-overlay.ts +1 -0
- package/src/resources/extensions/gsd/context-masker.ts +152 -5
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/guided-flow.ts +4 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +113 -43
- package/src/resources/extensions/gsd/preferences-types.ts +47 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +2 -2
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +260 -5
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +29 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +41 -6
- package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +71 -489
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +38 -14
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -3
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{9y3LeeR2uGr2yRj9RjY3D → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -5,6 +5,7 @@ import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
|
5
5
|
|
|
6
6
|
import type { NextAction } from "../shared/next-action-ui.js";
|
|
7
7
|
import type { GSDState } from "./types.js";
|
|
8
|
+
import { setAutoOutcomeWidget } from "./auto-dashboard.js";
|
|
8
9
|
import { invalidateAllCaches } from "./cache.js";
|
|
9
10
|
import { mergeCompletedMilestone } from "./parallel-merge.js";
|
|
10
11
|
import { cleanupQuickBranch, detectStrandedQuickBranch, type StrandedQuickBranch } from "./quick.js";
|
|
@@ -21,6 +22,13 @@ export interface CloseoutContext {
|
|
|
21
22
|
unmergedMilestones: UnmergedMilestoneBlocker[];
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
const MILESTONE_MERGE_CLOSEOUT_COMMANDS = [
|
|
26
|
+
"/gsd status for overview",
|
|
27
|
+
"/gsd visualize to inspect",
|
|
28
|
+
"/gsd notifications for history",
|
|
29
|
+
"/gsd start for new work",
|
|
30
|
+
];
|
|
31
|
+
|
|
24
32
|
export async function loadCloseoutContext(basePath: string): Promise<CloseoutContext> {
|
|
25
33
|
const unmergedMilestones = await findUnmergedCompletedMilestones(basePath);
|
|
26
34
|
return {
|
|
@@ -91,6 +99,23 @@ export function buildIdleMenuSummary(state: GSDState, closeout: CloseoutContext)
|
|
|
91
99
|
return [state.nextAction || "No active milestone."];
|
|
92
100
|
}
|
|
93
101
|
|
|
102
|
+
export function showMilestoneMergeCloseout(
|
|
103
|
+
ctx: ExtensionCommandContext,
|
|
104
|
+
blocker: UnmergedMilestoneBlocker,
|
|
105
|
+
): void {
|
|
106
|
+
ctx.ui.setStatus?.("gsd-auto", undefined);
|
|
107
|
+
ctx.ui.setStatus?.("gsd-step", undefined);
|
|
108
|
+
ctx.ui.setWidget?.("gsd-progress", undefined);
|
|
109
|
+
|
|
110
|
+
setAutoOutcomeWidget(ctx, {
|
|
111
|
+
status: "complete",
|
|
112
|
+
title: `Milestone ${blocker.milestoneId} merged`,
|
|
113
|
+
detail: `Merged ${blocker.branch} into ${blocker.integrationBranch}. Product changes are now on ${blocker.integrationBranch}.`,
|
|
114
|
+
nextAction: "Review the closeout, then start the next milestone when ready.",
|
|
115
|
+
commands: MILESTONE_MERGE_CLOSEOUT_COMMANDS,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
94
119
|
export async function runMergeQuickTask(
|
|
95
120
|
ctx: ExtensionCommandContext,
|
|
96
121
|
basePath: string,
|
|
@@ -113,31 +138,23 @@ export async function runMergeQuickTask(
|
|
|
113
138
|
return false;
|
|
114
139
|
}
|
|
115
140
|
|
|
116
|
-
export async function
|
|
141
|
+
export async function runMergeMilestoneBlocker(
|
|
117
142
|
ctx: ExtensionCommandContext,
|
|
118
143
|
basePath: string,
|
|
119
|
-
|
|
144
|
+
blocker: UnmergedMilestoneBlocker,
|
|
120
145
|
): Promise<boolean> {
|
|
121
|
-
const blockers = await findUnmergedCompletedMilestones(basePath);
|
|
122
|
-
const blocker = milestoneId
|
|
123
|
-
? blockers.find((candidate) => candidate.milestoneId === milestoneId)
|
|
124
|
-
: blockers[0];
|
|
125
|
-
if (!blocker) {
|
|
126
|
-
ctx.ui.notify("No unmerged completed milestone found.", "warning");
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
146
|
ctx.ui.notify(
|
|
131
147
|
`Completing preserved milestone merge for ${blocker.milestoneId} from ${blocker.branch} into ${blocker.integrationBranch}.`,
|
|
132
148
|
"info",
|
|
133
149
|
);
|
|
134
150
|
const result = await mergeCompletedMilestone(basePath, blocker.milestoneId);
|
|
135
151
|
if (result.success) {
|
|
152
|
+
invalidateAllCaches();
|
|
153
|
+
showMilestoneMergeCloseout(ctx, blocker);
|
|
136
154
|
ctx.ui.notify(
|
|
137
|
-
`Milestone ${blocker.milestoneId} merged to ${blocker.integrationBranch}.
|
|
155
|
+
`Milestone ${blocker.milestoneId} merged to ${blocker.integrationBranch}. Closeout is complete.`,
|
|
138
156
|
"info",
|
|
139
157
|
);
|
|
140
|
-
invalidateAllCaches();
|
|
141
158
|
return true;
|
|
142
159
|
}
|
|
143
160
|
|
|
@@ -148,6 +165,23 @@ export async function runMergeMilestone(
|
|
|
148
165
|
return false;
|
|
149
166
|
}
|
|
150
167
|
|
|
168
|
+
export async function runMergeMilestone(
|
|
169
|
+
ctx: ExtensionCommandContext,
|
|
170
|
+
basePath: string,
|
|
171
|
+
milestoneId?: string,
|
|
172
|
+
): Promise<boolean> {
|
|
173
|
+
const blockers = await findUnmergedCompletedMilestones(basePath);
|
|
174
|
+
const blocker = milestoneId
|
|
175
|
+
? blockers.find((candidate) => candidate.milestoneId === milestoneId)
|
|
176
|
+
: blockers[0];
|
|
177
|
+
if (!blocker) {
|
|
178
|
+
ctx.ui.notify("No unmerged completed milestone found.", "warning");
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return runMergeMilestoneBlocker(ctx, basePath, blocker);
|
|
183
|
+
}
|
|
184
|
+
|
|
151
185
|
export async function handleCloseoutChoice(
|
|
152
186
|
ctx: ExtensionCommandContext,
|
|
153
187
|
basePath: string,
|
|
@@ -209,6 +209,15 @@ export async function handleAutoCommand(trimmed: string, ctx: ExtensionCommandCo
|
|
|
209
209
|
if (trimmed === "") {
|
|
210
210
|
if (!(await guardRemoteSession(ctx, pi))) return true;
|
|
211
211
|
const basePath = projectRoot();
|
|
212
|
+
// Cold start after /quit lands at the project root, not the worktree. If the
|
|
213
|
+
// active milestone has a live worktree, chdir back into it now so the agent
|
|
214
|
+
// doesn't have to search for it. Best-effort; resolves to a no-op otherwise.
|
|
215
|
+
try {
|
|
216
|
+
const { reenterActiveWorktreeIfNeeded } = await import("../../worktree-reentry.js");
|
|
217
|
+
await reenterActiveWorktreeIfNeeded(basePath, {
|
|
218
|
+
notify: (message) => ctx.ui.notify(message, "info"),
|
|
219
|
+
});
|
|
220
|
+
} catch { /* non-fatal */ }
|
|
212
221
|
const { hasGsdBootstrapArtifacts } = await import("../../detection.js");
|
|
213
222
|
const { gsdRoot } = await import("../../paths.js");
|
|
214
223
|
if (!hasGsdBootstrapArtifacts(gsdRoot(basePath))) {
|
|
@@ -19,7 +19,7 @@ import { handleSessionReport } from "../../commands-session-report.js";
|
|
|
19
19
|
import { handlePrBranch } from "../../commands-pr-branch.js";
|
|
20
20
|
import { currentDirectoryRoot, projectRoot } from "../context.js";
|
|
21
21
|
import { findUnmergedCompletedMilestones } from "../../unmerged-milestone-guard.js";
|
|
22
|
-
import {
|
|
22
|
+
import { runMergeMilestoneBlocker } from "../../closeout-wizard.js";
|
|
23
23
|
|
|
24
24
|
async function handleCompletedMilestoneRecovery(
|
|
25
25
|
phase: string,
|
|
@@ -37,22 +37,7 @@ async function handleCompletedMilestoneRecovery(
|
|
|
37
37
|
: blockers[0];
|
|
38
38
|
if (!blocker) return false;
|
|
39
39
|
|
|
40
|
-
ctx
|
|
41
|
-
`Completing preserved milestone merge for ${blocker.milestoneId} from ${blocker.branch} into ${blocker.integrationBranch}.`,
|
|
42
|
-
"info",
|
|
43
|
-
);
|
|
44
|
-
const result = await mergeCompletedMilestone(basePath, blocker.milestoneId);
|
|
45
|
-
if (result.success) {
|
|
46
|
-
ctx.ui.notify(
|
|
47
|
-
`Milestone ${blocker.milestoneId} merged to ${blocker.integrationBranch}. Run /gsd again when ready.`,
|
|
48
|
-
"info",
|
|
49
|
-
);
|
|
50
|
-
} else {
|
|
51
|
-
ctx.ui.notify(
|
|
52
|
-
`Milestone ${blocker.milestoneId} merge recovery failed: ${result.error}`,
|
|
53
|
-
"error",
|
|
54
|
-
);
|
|
55
|
-
}
|
|
40
|
+
await runMergeMilestoneBlocker(ctx, basePath, blocker);
|
|
56
41
|
return true;
|
|
57
42
|
}
|
|
58
43
|
|
|
@@ -481,6 +481,8 @@ export async function handleCleanupProjects(args: string, ctx: ExtensionCommandC
|
|
|
481
481
|
ctx.ui.notify(lines.join("\n"), "info");
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
type HierarchyCounts = { milestones: number; slices: number; tasks: number };
|
|
485
|
+
|
|
484
486
|
function recoverConfirmed(args: string): boolean {
|
|
485
487
|
return args
|
|
486
488
|
.split(/\s+/)
|
|
@@ -488,27 +490,82 @@ function recoverConfirmed(args: string): boolean {
|
|
|
488
490
|
.some((part) => part === "--confirm" || part === "--yes" || part === "confirm");
|
|
489
491
|
}
|
|
490
492
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
+
function recoverAllowsDataLoss(args: string): boolean {
|
|
494
|
+
return args
|
|
495
|
+
.split(/\s+/)
|
|
496
|
+
.map((part) => part.trim().toLowerCase())
|
|
497
|
+
.some((part) => part === "--allow-data-loss" || part === "--force");
|
|
498
|
+
}
|
|
493
499
|
|
|
500
|
+
async function confirmRecover(
|
|
501
|
+
ctx: ExtensionCommandContext,
|
|
502
|
+
args: string,
|
|
503
|
+
markdown: HierarchyCounts,
|
|
504
|
+
beforeDb: HierarchyCounts,
|
|
505
|
+
dataLoss: boolean,
|
|
506
|
+
): Promise<boolean> {
|
|
494
507
|
const warning = [
|
|
495
508
|
"gsd recover imports markdown into the database.",
|
|
496
509
|
"It clears and reconstructs milestone, slice, and task hierarchy rows from rendered markdown.",
|
|
497
510
|
"Use /gsd rebuild markdown for normal DB-to-markdown realignment.",
|
|
498
|
-
|
|
511
|
+
"",
|
|
512
|
+
` Markdown on disk: ${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T`,
|
|
513
|
+
` Current DB: ${beforeDb.milestones}M/${beforeDb.slices}S/${beforeDb.tasks}T`,
|
|
514
|
+
];
|
|
515
|
+
if (dataLoss) {
|
|
516
|
+
warning.push(
|
|
517
|
+
"",
|
|
518
|
+
"⚠ The DB holds rows the markdown lacks. Recover will permanently DELETE",
|
|
519
|
+
" those rows. A snapshot is written to .gsd/backups/ first, but if the DB",
|
|
520
|
+
" is the source of truth you almost certainly want /gsd rebuild markdown.",
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const warningText = warning.join("\n");
|
|
524
|
+
|
|
525
|
+
if (recoverConfirmed(args)) {
|
|
526
|
+
// Non-interactive --confirm still refuses a data-loss recover unless the
|
|
527
|
+
// caller explicitly opts in with --allow-data-loss / --force.
|
|
528
|
+
if (dataLoss && !recoverAllowsDataLoss(args)) {
|
|
529
|
+
ctx.ui.notify(
|
|
530
|
+
`${warningText}\n\nRefusing: this would delete authoritative DB rows. Re-run with ` +
|
|
531
|
+
`/gsd recover --confirm --allow-data-loss to proceed, or use /gsd rebuild markdown ` +
|
|
532
|
+
`to re-project markdown from the DB instead.`,
|
|
533
|
+
"error",
|
|
534
|
+
);
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
499
539
|
|
|
500
540
|
if (typeof ctx.ui.confirm === "function") {
|
|
501
541
|
const confirmed = await ctx.ui.confirm(
|
|
502
542
|
"Import markdown into the DB?",
|
|
503
|
-
`${
|
|
543
|
+
`${warningText}\n\nContinue only if the DB is lost or corrupt and markdown is the source you intend to import.`,
|
|
504
544
|
);
|
|
505
|
-
if (confirmed)
|
|
506
|
-
|
|
507
|
-
|
|
545
|
+
if (!confirmed) {
|
|
546
|
+
ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
// Data loss requires a second, explicit acknowledgement — the interactive
|
|
550
|
+
// equivalent of the --allow-data-loss opt-in the non-interactive paths
|
|
551
|
+
// demand. A single generic "yes" must not silently delete DB rows.
|
|
552
|
+
if (dataLoss) {
|
|
553
|
+
const acknowledged = await ctx.ui.confirm(
|
|
554
|
+
"Permanently delete DB rows the markdown lacks?",
|
|
555
|
+
"This recover will DELETE authoritative DB rows the markdown does not contain. " +
|
|
556
|
+
"A snapshot is saved to .gsd/backups/ first, but /gsd rebuild markdown is usually " +
|
|
557
|
+
"what you want. Proceed with the deletion?",
|
|
558
|
+
);
|
|
559
|
+
if (!acknowledged) {
|
|
560
|
+
ctx.ui.notify("gsd recover cancelled. No database changes made.", "info");
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return true;
|
|
508
565
|
}
|
|
509
566
|
|
|
510
567
|
ctx.ui.notify(
|
|
511
|
-
`${
|
|
568
|
+
`${warningText}\n\nNo database changes made. Re-run /gsd recover --confirm to proceed.`,
|
|
512
569
|
"warning",
|
|
513
570
|
);
|
|
514
571
|
return false;
|
|
@@ -524,18 +581,31 @@ async function confirmRecover(ctx: ExtensionCommandContext, args: string): Promi
|
|
|
524
581
|
* Prints counts of recovered items and the resulting project phase.
|
|
525
582
|
*/
|
|
526
583
|
export async function handleRecover(ctx: ExtensionCommandContext, basePath: string, args = ""): Promise<void> {
|
|
527
|
-
const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction } = await import("./gsd-db.js");
|
|
584
|
+
const { isDbAvailable: dbAvailable, clearEngineHierarchy, transaction: dbTransaction, backupDatabaseSnapshot } = await import("./gsd-db.js");
|
|
528
585
|
const { migrateHierarchyToDb } = await import("./md-importer.js");
|
|
529
586
|
const { invalidateStateCache } = await import("./state.js");
|
|
587
|
+
const { countDbHierarchy, countMarkdownHierarchy, recoverWouldDeleteDbRows } = await import("./migration-auto-check.js");
|
|
588
|
+
const { renderAllFromDb } = await import("./markdown-renderer.js");
|
|
530
589
|
|
|
531
590
|
if (!dbAvailable()) {
|
|
532
591
|
ctx.ui.notify("gsd recover: No database open. Run a GSD command first to initialize the DB.", "error");
|
|
533
592
|
return;
|
|
534
593
|
}
|
|
535
594
|
|
|
536
|
-
|
|
595
|
+
// Compare markdown-on-disk against the live DB so the confirmation prompt can
|
|
596
|
+
// surface exactly what recover will overwrite (and refuse silent data loss).
|
|
597
|
+
// The data-loss check is identity-based, not count-based: it flags any DB row
|
|
598
|
+
// markdown lacks, including equal-count divergence (DB S99 vs markdown S01).
|
|
599
|
+
const markdown = countMarkdownHierarchy(basePath);
|
|
600
|
+
const beforeDb = countDbHierarchy();
|
|
601
|
+
const dataLoss = recoverWouldDeleteDbRows(basePath);
|
|
602
|
+
|
|
603
|
+
if (!(await confirmRecover(ctx, args, markdown, beforeDb, dataLoss))) return;
|
|
537
604
|
|
|
538
605
|
try {
|
|
606
|
+
// 0. Snapshot the DB before the destructive clear so recover is reversible.
|
|
607
|
+
const backupPath = backupDatabaseSnapshot("pre-recover");
|
|
608
|
+
|
|
539
609
|
// 1. Delete + re-populate inside a single transaction for atomicity.
|
|
540
610
|
// clearEngineHierarchy() uses transaction() internally but transaction()
|
|
541
611
|
// is re-entrant, so wrapping in dbTransaction() keeps the whole
|
|
@@ -545,9 +615,16 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
|
|
|
545
615
|
return migrateHierarchyToDb(basePath);
|
|
546
616
|
});
|
|
547
617
|
|
|
548
|
-
//
|
|
618
|
+
// 2. Invalidate state cache so deriveState() picks up fresh DB data
|
|
549
619
|
invalidateStateCache();
|
|
550
620
|
|
|
621
|
+
// 3. Re-project markdown from the freshly imported DB so disk and DB agree
|
|
622
|
+
// immediately (otherwise the markdown still reflects the pre-import state
|
|
623
|
+
// and the next startup check would flag fresh drift). renderAllFromDb
|
|
624
|
+
// swallows per-artifact failures into its result, so inspect them — a
|
|
625
|
+
// silent projection failure must not be reported as a clean success.
|
|
626
|
+
const renderResult = await renderAllFromDb(basePath);
|
|
627
|
+
|
|
551
628
|
// 4. Derive state to verify sanity
|
|
552
629
|
const state = await deriveState(basePath);
|
|
553
630
|
|
|
@@ -560,6 +637,23 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
|
|
|
560
637
|
``,
|
|
561
638
|
` Phase: ${state.phase}`,
|
|
562
639
|
];
|
|
640
|
+
// Post-import verification: markdown that failed to parse imports as fewer
|
|
641
|
+
// rows than countMarkdownHierarchy saw on disk. Surface the shortfall.
|
|
642
|
+
if (
|
|
643
|
+
counts.milestones < markdown.milestones ||
|
|
644
|
+
counts.slices < markdown.slices ||
|
|
645
|
+
counts.tasks < markdown.tasks
|
|
646
|
+
) {
|
|
647
|
+
lines.push(
|
|
648
|
+
``,
|
|
649
|
+
` ⚠ Imported fewer rows than markdown contained ` +
|
|
650
|
+
`(${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T on disk). ` +
|
|
651
|
+
`Some markdown may have failed to parse — review before continuing.`,
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
if (backupPath) {
|
|
655
|
+
lines.push(``, ` Backup: ${backupPath}`);
|
|
656
|
+
}
|
|
563
657
|
if (state.activeMilestone) {
|
|
564
658
|
lines.push(` Active: ${state.activeMilestone.id}: ${state.activeMilestone.title}`);
|
|
565
659
|
}
|
|
@@ -570,10 +664,27 @@ export async function handleRecover(ctx: ExtensionCommandContext, basePath: stri
|
|
|
570
664
|
lines.push(` Task: ${state.activeTask.id}: ${state.activeTask.title}`);
|
|
571
665
|
}
|
|
572
666
|
|
|
667
|
+
// Surface markdown projection failures: renderAllFromDb resolves even when
|
|
668
|
+
// individual artifacts fail to render, so a clean exit here would otherwise
|
|
669
|
+
// hide a stale/partial projection.
|
|
670
|
+
const renderFailed = renderResult.errors.length > 0;
|
|
671
|
+
if (renderFailed) {
|
|
672
|
+
lines.push(
|
|
673
|
+
``,
|
|
674
|
+
` ⚠ ${renderResult.errors.length} markdown projection(s) failed to render — ` +
|
|
675
|
+
`markdown may be stale. Re-run /gsd rebuild markdown.`,
|
|
676
|
+
);
|
|
677
|
+
for (const e of renderResult.errors.slice(0, 5)) lines.push(` - ${e}`);
|
|
678
|
+
if (renderResult.errors.length > 5) {
|
|
679
|
+
lines.push(` …and ${renderResult.errors.length - 5} more`);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
573
683
|
process.stderr.write(
|
|
574
|
-
`gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy
|
|
684
|
+
`gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy` +
|
|
685
|
+
`${renderFailed ? ` (${renderResult.errors.length} projection errors)` : ""}\n`,
|
|
575
686
|
);
|
|
576
|
-
ctx.ui.notify(lines.join("\n"), "success");
|
|
687
|
+
ctx.ui.notify(lines.join("\n"), renderFailed ? "warning" : "success");
|
|
577
688
|
} catch (err) {
|
|
578
689
|
const msg = err instanceof Error ? err.message : String(err);
|
|
579
690
|
logWarning("command", `recover failed: ${msg}`);
|
|
@@ -73,7 +73,7 @@ export function formatMcpInitResult(
|
|
|
73
73
|
`Config: ${configPath}`,
|
|
74
74
|
"",
|
|
75
75
|
"MCP-capable clients can now load the GSD workflow and gsd-browser MCP servers from this folder.",
|
|
76
|
-
"Pi Providers use
|
|
76
|
+
"Pi Providers use built-in browser tools directly; this project config is for External MCP Clients.",
|
|
77
77
|
"Restart or reconnect any client that already has this project open.",
|
|
78
78
|
].join("\n");
|
|
79
79
|
}
|
|
@@ -1285,7 +1285,7 @@ async function configureHooks(ctx: ExtensionCommandContext, prefs: Record<string
|
|
|
1285
1285
|
if (geEnabled !== undefined) ge.enabled = geEnabled;
|
|
1286
1286
|
const currentSliceGates = Array.isArray(ge.slice_gates) ? ge.slice_gates as string[] : [];
|
|
1287
1287
|
const sgInput = await ctx.ui.input(
|
|
1288
|
-
`
|
|
1288
|
+
`Gate-evaluate slice gates (Q3,Q4; comma-separated, blank keeps)${currentSliceGates.length ? ` (current: ${currentSliceGates.join(", ")})` : " (default: Q3,Q4)"}:`,
|
|
1289
1289
|
currentSliceGates.join(", "),
|
|
1290
1290
|
);
|
|
1291
1291
|
if (sgInput !== null && sgInput !== undefined) {
|
|
@@ -1751,7 +1751,7 @@ export function serializePreferencesToFrontmatter(prefs: Record<string, unknown>
|
|
|
1751
1751
|
// Ordered keys for consistent output
|
|
1752
1752
|
const orderedKeys = [
|
|
1753
1753
|
"version", "mode", "always_use_skills", "prefer_skills", "avoid_skills",
|
|
1754
|
-
"skill_rules", "custom_instructions", "models", "skill_discovery",
|
|
1754
|
+
"skill_rules", "custom_instructions", "models", "thinking", "skill_discovery",
|
|
1755
1755
|
"skill_staleness_days", "auto_supervisor", "uat_dispatch", "unique_milestone_ids",
|
|
1756
1756
|
"budget_ceiling", "budget_enforcement", "context_pause_threshold",
|
|
1757
1757
|
"notifications", "cmux", "remote_questions", "git",
|
|
@@ -139,6 +139,7 @@ function collectConfigSections(): ConfigSection[] {
|
|
|
139
139
|
if (sup.model) supRows.push({ label: "Model", value: sup.model });
|
|
140
140
|
supRows.push({ label: "Soft timeout", value: `${sup.soft_timeout_minutes}m` });
|
|
141
141
|
supRows.push({ label: "Idle timeout", value: `${sup.idle_timeout_minutes}m` });
|
|
142
|
+
supRows.push({ label: "Stalled tool timeout", value: `${sup.stalled_tool_timeout_minutes}m` });
|
|
142
143
|
supRows.push({ label: "Hard timeout", value: `${sup.hard_timeout_minutes}m` });
|
|
143
144
|
sections.push({ title: "Auto Supervisor", rows: supRows });
|
|
144
145
|
}
|
|
@@ -5,10 +5,17 @@
|
|
|
5
5
|
* Reduces context bloat between compactions with zero LLM overhead.
|
|
6
6
|
* Preserves message ordering, roles, and all assistant/user messages.
|
|
7
7
|
*
|
|
8
|
-
* Operates on
|
|
8
|
+
* Operates on provider payloads after convertToLlm:
|
|
9
|
+
*
|
|
10
|
+
* pi-ai Message[] payloads:
|
|
9
11
|
* - toolResult messages: { role: "toolResult", content: TextContent[] }
|
|
10
12
|
* - bash results are already converted to: { role: "user", content: [{type:"text",text:"..."}] }
|
|
11
13
|
* and start with "Ran `" from bashExecutionToText.
|
|
14
|
+
*
|
|
15
|
+
* OpenAI/Codex Responses payloads:
|
|
16
|
+
* - conversation items live in `input`, not `messages`
|
|
17
|
+
* - tool results are { type: "function_call_output", output: string | content[] }
|
|
18
|
+
* - bash results are user items with input_text content starting with "Ran `"
|
|
12
19
|
*/
|
|
13
20
|
|
|
14
21
|
interface MaskableMessage {
|
|
@@ -20,6 +27,37 @@ interface MaskableMessage {
|
|
|
20
27
|
|
|
21
28
|
const MASK_PLACEHOLDER = "[result masked — within summarized history]";
|
|
22
29
|
const MASK_CONTENT_BLOCK = [{ type: "text" as const, text: MASK_PLACEHOLDER }];
|
|
30
|
+
const RESPONSES_MASK_CONTENT_BLOCK = [{ type: "input_text" as const, text: MASK_PLACEHOLDER }];
|
|
31
|
+
const TRUNCATION_MARKER = "\n…[truncated]";
|
|
32
|
+
|
|
33
|
+
type TextLikeBlock = {
|
|
34
|
+
type?: string;
|
|
35
|
+
text?: unknown;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
interface ResponsesInputItem {
|
|
40
|
+
role?: string;
|
|
41
|
+
type?: string;
|
|
42
|
+
content?: unknown;
|
|
43
|
+
output?: unknown;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isTextLikeBlock(block: unknown): block is TextLikeBlock {
|
|
48
|
+
return Boolean(block && typeof block === "object" && "text" in block);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function firstTextFromContent(content: unknown): string | undefined {
|
|
52
|
+
if (typeof content === "string") return content;
|
|
53
|
+
if (!Array.isArray(content)) return undefined;
|
|
54
|
+
const first = content.find(isTextLikeBlock);
|
|
55
|
+
return typeof first?.text === "string" ? first.text : undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isBashResultText(text: string | undefined): boolean {
|
|
59
|
+
return typeof text === "string" && text.startsWith("Ran `");
|
|
60
|
+
}
|
|
23
61
|
|
|
24
62
|
function findTurnBoundary(messages: MaskableMessage[], keepRecentTurns: number): number {
|
|
25
63
|
let turnsSeen = 0;
|
|
@@ -43,10 +81,8 @@ function findTurnBoundary(messages: MaskableMessage[], keepRecentTurns: number):
|
|
|
43
81
|
* The bashExecutionToText format always starts with "Ran `".
|
|
44
82
|
*/
|
|
45
83
|
function isBashResultUserMessage(m: MaskableMessage): boolean {
|
|
46
|
-
if (m.role !== "user"
|
|
47
|
-
|
|
48
|
-
return first && typeof first === "object" && "text" in first &&
|
|
49
|
-
typeof first.text === "string" && first.text.startsWith("Ran `");
|
|
84
|
+
if (m.role !== "user") return false;
|
|
85
|
+
return isBashResultText(firstTextFromContent(m.content));
|
|
50
86
|
}
|
|
51
87
|
|
|
52
88
|
function isMaskableMessage(m: MaskableMessage): boolean {
|
|
@@ -72,3 +108,114 @@ export function createObservationMask(keepRecentTurns: number = 8) {
|
|
|
72
108
|
});
|
|
73
109
|
};
|
|
74
110
|
}
|
|
111
|
+
|
|
112
|
+
function isResponsesBashResultUserItem(item: ResponsesInputItem): boolean {
|
|
113
|
+
if (item.role !== "user") return false;
|
|
114
|
+
return isBashResultText(firstTextFromContent(item.content));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function findResponsesTurnBoundary(items: ResponsesInputItem[], keepRecentTurns: number): number {
|
|
118
|
+
let turnsSeen = 0;
|
|
119
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
120
|
+
const item = items[i];
|
|
121
|
+
if (item.role === "user" && !isResponsesBashResultUserItem(item)) {
|
|
122
|
+
turnsSeen++;
|
|
123
|
+
if (turnsSeen >= keepRecentTurns) return i;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Observation masking for OpenAI/Codex Responses API payloads.
|
|
131
|
+
*
|
|
132
|
+
* Responses payloads store the conversation under `input` instead of
|
|
133
|
+
* `messages`, with tool results as `function_call_output` items. Keep this
|
|
134
|
+
* separate from createObservationMask so each payload shape stays explicit.
|
|
135
|
+
*/
|
|
136
|
+
export function createResponsesInputObservationMask(keepRecentTurns: number = 8) {
|
|
137
|
+
return (items: ResponsesInputItem[]): ResponsesInputItem[] => {
|
|
138
|
+
const boundary = findResponsesTurnBoundary(items, keepRecentTurns);
|
|
139
|
+
if (boundary === 0) return items;
|
|
140
|
+
|
|
141
|
+
return items.map((item, i) => {
|
|
142
|
+
if (i >= boundary) return item;
|
|
143
|
+
if (item.type === "function_call_output") {
|
|
144
|
+
return { ...item, output: MASK_PLACEHOLDER };
|
|
145
|
+
}
|
|
146
|
+
if (isResponsesBashResultUserItem(item)) {
|
|
147
|
+
return { ...item, content: RESPONSES_MASK_CONTENT_BLOCK };
|
|
148
|
+
}
|
|
149
|
+
return item;
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function truncateText(text: string, maxChars: number): string {
|
|
155
|
+
if (text.length <= maxChars) return text;
|
|
156
|
+
return text.slice(0, maxChars) + TRUNCATION_MARKER;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function truncateTextBlocks(content: unknown, maxChars: number): unknown {
|
|
160
|
+
if (typeof content === "string") {
|
|
161
|
+
return truncateText(content, maxChars);
|
|
162
|
+
}
|
|
163
|
+
if (!Array.isArray(content)) return content;
|
|
164
|
+
|
|
165
|
+
let remaining = maxChars;
|
|
166
|
+
let didTruncate = false;
|
|
167
|
+
const nextBlocks: unknown[] = [];
|
|
168
|
+
|
|
169
|
+
for (const block of content) {
|
|
170
|
+
if (!isTextLikeBlock(block) || typeof block.text !== "string") {
|
|
171
|
+
nextBlocks.push(block);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (remaining <= 0) {
|
|
176
|
+
didTruncate = true;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const text = block.text;
|
|
181
|
+
if (text.length <= remaining) {
|
|
182
|
+
nextBlocks.push(block);
|
|
183
|
+
remaining -= text.length;
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
nextBlocks.push({ ...block, text: truncateText(text, remaining) });
|
|
188
|
+
remaining = 0;
|
|
189
|
+
didTruncate = true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return didTruncate ? nextBlocks : content;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function normalizedMaxChars(maxChars: number): number {
|
|
196
|
+
return Number.isFinite(maxChars) && maxChars > 0 ? Math.floor(maxChars) : 800;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function truncateContextResultMessages(messages: MaskableMessage[], maxChars: number = 800): MaskableMessage[] {
|
|
200
|
+
const limit = normalizedMaxChars(maxChars);
|
|
201
|
+
return messages.map((message) => {
|
|
202
|
+
if (!isMaskableMessage(message)) return message;
|
|
203
|
+
const content = truncateTextBlocks(message.content, limit);
|
|
204
|
+
return content === message.content ? message : { ...message, content };
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function truncateResponsesInputResultItems(items: ResponsesInputItem[], maxChars: number = 800): ResponsesInputItem[] {
|
|
209
|
+
const limit = normalizedMaxChars(maxChars);
|
|
210
|
+
return items.map((item) => {
|
|
211
|
+
if (item.type === "function_call_output") {
|
|
212
|
+
const output = truncateTextBlocks(item.output, limit);
|
|
213
|
+
return output === item.output ? item : { ...item, output };
|
|
214
|
+
}
|
|
215
|
+
if (isResponsesBashResultUserItem(item)) {
|
|
216
|
+
const content = truncateTextBlocks(item.content, limit);
|
|
217
|
+
return content === item.content ? item : { ...item, content };
|
|
218
|
+
}
|
|
219
|
+
return item;
|
|
220
|
+
});
|
|
221
|
+
}
|
|
@@ -452,6 +452,44 @@ export function _resetDecisionSaveLock(): void {
|
|
|
452
452
|
_decisionSaveLock = Promise.resolve();
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Re-project root DECISIONS.md from the authoritative decision records, with no
|
|
457
|
+
* new decision being added. Mirrors the projection saveDecisionToDb performs
|
|
458
|
+
* after a save, but over the full set — so a DB → markdown re-projection
|
|
459
|
+
* (recover, rebuild, reconcile) re-derives DECISIONS.md and never leaves it
|
|
460
|
+
* showing a stale subset (e.g. after a worktree merge that accepted one
|
|
461
|
+
* branch's DECISIONS.md while the DB holds the union of both branches'
|
|
462
|
+
* decisions). DB stays the single source of truth; this only writes markdown.
|
|
463
|
+
*/
|
|
464
|
+
export async function regenerateDecisionsMarkdown(basePath: string): Promise<void> {
|
|
465
|
+
const { getAllDecisionsFromMemories } = await import('./context-store.js');
|
|
466
|
+
const allDecisions: Decision[] = getAllDecisionsFromMemories();
|
|
467
|
+
|
|
468
|
+
const filePath = resolveGsdRootFile(basePath, 'DECISIONS');
|
|
469
|
+
let existingContent: string | null = null;
|
|
470
|
+
if (existsSync(filePath)) {
|
|
471
|
+
existingContent = readFileSync(filePath, 'utf-8');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Nothing to project: no decisions in the DB and no file to normalize.
|
|
475
|
+
if (allDecisions.length === 0 && existingContent === null) return;
|
|
476
|
+
|
|
477
|
+
let md: string;
|
|
478
|
+
if (existingContent && !isDecisionsTableFormat(existingContent)) {
|
|
479
|
+
// Preserve freeform content; refresh only the appended decisions table.
|
|
480
|
+
const marker = '---\n\n## Decisions Table';
|
|
481
|
+
const markerIdx = existingContent.indexOf(marker);
|
|
482
|
+
const freeformPart = markerIdx >= 0
|
|
483
|
+
? existingContent.substring(0, markerIdx).trimEnd()
|
|
484
|
+
: existingContent.trimEnd();
|
|
485
|
+
md = freeformPart + '\n' + generateDecisionsAppendBlock(allDecisions);
|
|
486
|
+
} else {
|
|
487
|
+
md = generateDecisionsMd(allDecisions);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
await saveFile(filePath, md);
|
|
491
|
+
}
|
|
492
|
+
|
|
455
493
|
// ─── Save Decision to DB + Regenerate Markdown ────────────────────────────
|
|
456
494
|
|
|
457
495
|
export interface SaveDecisionFields {
|