@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
package/dist/headless-recover.js
CHANGED
|
@@ -46,13 +46,20 @@ async function loadExtensionModules() {
|
|
|
46
46
|
const dbModule = await jiti.import(gsdExtensionPath('gsd-db.ts'), {});
|
|
47
47
|
const importerModule = await jiti.import(gsdExtensionPath('md-importer.ts'), {});
|
|
48
48
|
const dynamicToolsModule = await jiti.import(gsdExtensionPath('bootstrap/dynamic-tools.ts'), {});
|
|
49
|
+
const migrationCheckModule = await jiti.import(gsdExtensionPath('migration-auto-check.ts'), {});
|
|
50
|
+
const rendererModule = await jiti.import(gsdExtensionPath('markdown-renderer.ts'), {});
|
|
49
51
|
return {
|
|
50
52
|
ensureDbOpen: dynamicToolsModule.ensureDbOpen,
|
|
51
53
|
isDbAvailable: dbModule.isDbAvailable,
|
|
52
54
|
clearEngineHierarchy: dbModule.clearEngineHierarchy,
|
|
53
55
|
transaction: dbModule.transaction,
|
|
56
|
+
backupDatabaseSnapshot: dbModule.backupDatabaseSnapshot,
|
|
54
57
|
migrateHierarchyToDb: importerModule.migrateHierarchyToDb,
|
|
55
58
|
invalidateStateCache: stateModule.invalidateStateCache,
|
|
59
|
+
countDbHierarchy: migrationCheckModule.countDbHierarchy,
|
|
60
|
+
countMarkdownHierarchy: migrationCheckModule.countMarkdownHierarchy,
|
|
61
|
+
recoverWouldDeleteDbRows: migrationCheckModule.recoverWouldDeleteDbRows,
|
|
62
|
+
renderAllFromDb: rendererModule.renderAllFromDb,
|
|
56
63
|
};
|
|
57
64
|
}
|
|
58
65
|
export async function handleRecover(basePath) {
|
|
@@ -75,6 +82,24 @@ export async function handleRecover(basePath) {
|
|
|
75
82
|
process.stderr.write(`[headless] recover: failed to open or create the GSD database at ${basePath}\n`);
|
|
76
83
|
return { exitCode: 1 };
|
|
77
84
|
}
|
|
85
|
+
// Refuse a destructive recover that would delete authoritative DB rows the
|
|
86
|
+
// markdown lacks, unless explicitly allowed. The DB is the source of truth;
|
|
87
|
+
// re-projecting via rebuild is almost always what's wanted instead. The
|
|
88
|
+
// check is identity-based, so it also catches equal-count divergence (DB S99
|
|
89
|
+
// vs markdown S01) that a cardinality-only comparison would miss.
|
|
90
|
+
const markdown = modules.countMarkdownHierarchy(basePath);
|
|
91
|
+
const beforeDb = modules.countDbHierarchy();
|
|
92
|
+
const dataLoss = modules.recoverWouldDeleteDbRows(basePath);
|
|
93
|
+
const allowDataLoss = process.env.GSD_RECOVER_ALLOW_DATA_LOSS === '1';
|
|
94
|
+
if (dataLoss && !allowDataLoss) {
|
|
95
|
+
process.stderr.write(`[headless] recover refused: the DB (${beforeDb.milestones}M/${beforeDb.slices}S/${beforeDb.tasks}T) ` +
|
|
96
|
+
`holds rows the markdown (${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T) lacks; ` +
|
|
97
|
+
`recover would delete them. Set GSD_RECOVER_ALLOW_DATA_LOSS=1 to override, ` +
|
|
98
|
+
`or run a DB-to-markdown rebuild instead.\n`);
|
|
99
|
+
return { exitCode: 1 };
|
|
100
|
+
}
|
|
101
|
+
// Snapshot the DB before the destructive clear so recover is reversible.
|
|
102
|
+
const backupPath = modules.backupDatabaseSnapshot('pre-recover');
|
|
78
103
|
let counts;
|
|
79
104
|
try {
|
|
80
105
|
counts = modules.transaction(() => {
|
|
@@ -88,6 +113,36 @@ export async function handleRecover(basePath) {
|
|
|
88
113
|
return { exitCode: 1 };
|
|
89
114
|
}
|
|
90
115
|
modules.invalidateStateCache();
|
|
91
|
-
|
|
116
|
+
// Re-project markdown from the freshly imported DB so disk and DB agree.
|
|
117
|
+
// renderAllFromDb resolves even when individual artifacts fail, so inspect
|
|
118
|
+
// its error list — a silent projection failure must surface, not pass as a
|
|
119
|
+
// clean recover.
|
|
120
|
+
let projectionErrors = 0;
|
|
121
|
+
try {
|
|
122
|
+
const renderResult = await modules.renderAllFromDb(basePath);
|
|
123
|
+
projectionErrors = renderResult.errors.length;
|
|
124
|
+
if (projectionErrors > 0) {
|
|
125
|
+
process.stderr.write(`[headless] recover: ${projectionErrors} markdown projection(s) failed to render — markdown may be stale:\n`);
|
|
126
|
+
for (const e of renderResult.errors.slice(0, 10)) {
|
|
127
|
+
process.stderr.write(` - ${e}\n`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
133
|
+
process.stderr.write(`[headless] recover: re-render after import failed: ${msg}\n`);
|
|
134
|
+
projectionErrors = 1;
|
|
135
|
+
}
|
|
136
|
+
if (counts.milestones < markdown.milestones ||
|
|
137
|
+
counts.slices < markdown.slices ||
|
|
138
|
+
counts.tasks < markdown.tasks) {
|
|
139
|
+
process.stderr.write(`[headless] recover: imported fewer rows than markdown contained ` +
|
|
140
|
+
`(${markdown.milestones}M/${markdown.slices}S/${markdown.tasks}T on disk); some markdown may have failed to parse\n`);
|
|
141
|
+
}
|
|
142
|
+
if (backupPath) {
|
|
143
|
+
process.stderr.write(`[headless] recover: pre-recover snapshot saved to ${backupPath}\n`);
|
|
144
|
+
}
|
|
145
|
+
process.stderr.write(`gsd-recover: recovered ${counts.milestones}M/${counts.slices}S/${counts.tasks}T hierarchy` +
|
|
146
|
+
`${projectionErrors > 0 ? ` (${projectionErrors} projection error(s) — run rebuild markdown)` : ''}\n`);
|
|
92
147
|
return { exitCode: 0 };
|
|
93
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
fc4ebdcd3723ade9
|
|
@@ -435,11 +435,27 @@ function formatManagedBrowserError(toolName, error) {
|
|
|
435
435
|
return [
|
|
436
436
|
`gsd-browser engine or tool unavailable for ${toolName}: ${message}`,
|
|
437
437
|
"",
|
|
438
|
-
"
|
|
438
|
+
"The managed gsd-browser engine is enabled for this session but is unavailable.",
|
|
439
439
|
"Run /gsd doctor or reinstall dependencies so @opengsd/gsd-browser is available.",
|
|
440
|
-
"
|
|
440
|
+
"Unset GSD_BROWSER_ENGINE or set GSD_BROWSER_ENGINE=playwright to use the default Playwright engine.",
|
|
441
441
|
].join("\n");
|
|
442
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* Eagerly establish the managed gsd-browser connection so browser tools are
|
|
445
|
+
* ready before first use. Best-effort: returns the error instead of throwing so
|
|
446
|
+
* callers (e.g. session-start warm-up) can surface a warning without failing the
|
|
447
|
+
* session. Connecting only spawns the gsd-browser MCP daemon; it does not launch
|
|
448
|
+
* Chrome (that happens lazily on the first navigation).
|
|
449
|
+
*/
|
|
450
|
+
export async function warmUpManagedGsdBrowser(ctx, signal) {
|
|
451
|
+
try {
|
|
452
|
+
await getOrConnectManagedGsdBrowser(ctx, signal);
|
|
453
|
+
return { ok: true };
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
457
|
+
}
|
|
458
|
+
}
|
|
443
459
|
export function registerManagedGsdBrowserTools(pi) {
|
|
444
460
|
for (const tool of MANAGED_BROWSER_TOOLS) {
|
|
445
461
|
pi.registerTool({
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "browser-tools",
|
|
3
3
|
"name": "Browser Tools",
|
|
4
4
|
"version": "1.0.0",
|
|
5
|
-
"description": "GSD browser automation contract adapter backed by
|
|
5
|
+
"description": "GSD browser automation contract adapter backed by Playwright with optional managed gsd-browser support",
|
|
6
6
|
"tier": "bundled",
|
|
7
7
|
"requires": { "platform": ">=2.29.0" },
|
|
8
8
|
"provides": {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/** browser-tools — Pi Browser Automation Contract adapter. */
|
|
2
2
|
import { importExtensionModule } from "@gsd/pi-coding-agent";
|
|
3
|
-
import { closeManagedGsdBrowser, registerManagedGsdBrowserTools } from "./engine/managed-gsd-browser.js";
|
|
3
|
+
import { closeManagedGsdBrowser, registerManagedGsdBrowserTools, warmUpManagedGsdBrowser } from "./engine/managed-gsd-browser.js";
|
|
4
4
|
import { resolveBrowserEngineMode } from "./engine/selection.js";
|
|
5
|
+
import { setArtifactRootForCwd } from "./state.js";
|
|
6
|
+
import { detectWebApp } from "./web-app-detect.js";
|
|
5
7
|
let legacyRegistrationPromise = null;
|
|
6
8
|
let managedRegistrationPromise = null;
|
|
7
9
|
let registeredEngine = null;
|
|
@@ -83,28 +85,29 @@ async function registerLegacyBrowserTools(pi) {
|
|
|
83
85
|
sanitizeArtifactName: utils.sanitizeArtifactName,
|
|
84
86
|
formatArtifactTimestamp: utils.formatArtifactTimestamp,
|
|
85
87
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
88
|
+
const cwdScopedPi = withBrowserArtifactCwdScope(pi);
|
|
89
|
+
navigation.registerNavigationTools(cwdScopedPi, deps);
|
|
90
|
+
screenshot.registerScreenshotTools(cwdScopedPi, deps);
|
|
91
|
+
interaction.registerInteractionTools(cwdScopedPi, deps);
|
|
92
|
+
inspection.registerInspectionTools(cwdScopedPi, deps);
|
|
93
|
+
session.registerSessionTools(cwdScopedPi, deps);
|
|
94
|
+
assertions.registerAssertionTools(cwdScopedPi, deps);
|
|
95
|
+
refTools.registerRefTools(cwdScopedPi, deps);
|
|
96
|
+
wait.registerWaitTools(cwdScopedPi, deps);
|
|
97
|
+
pages.registerPageTools(cwdScopedPi, deps);
|
|
98
|
+
forms.registerFormTools(cwdScopedPi, deps);
|
|
99
|
+
intent.registerIntentTools(cwdScopedPi, deps);
|
|
100
|
+
pdf.registerPdfTools(cwdScopedPi, deps);
|
|
101
|
+
statePersistence.registerStatePersistenceTools(cwdScopedPi, deps);
|
|
102
|
+
networkMock.registerNetworkMockTools(cwdScopedPi, deps);
|
|
103
|
+
device.registerDeviceTools(cwdScopedPi, deps);
|
|
104
|
+
extract.registerExtractTools(cwdScopedPi, deps);
|
|
105
|
+
visualDiff.registerVisualDiffTools(cwdScopedPi, deps);
|
|
106
|
+
zoom.registerZoomTools(cwdScopedPi, deps);
|
|
107
|
+
codegen.registerCodegenTools(cwdScopedPi, deps);
|
|
108
|
+
actionCache.registerActionCacheTools(cwdScopedPi, deps);
|
|
109
|
+
injectionDetection.registerInjectionDetectionTools(cwdScopedPi, deps);
|
|
110
|
+
verify.registerVerifyTools(cwdScopedPi, deps);
|
|
108
111
|
})().catch((error) => {
|
|
109
112
|
legacyRegistrationPromise = null;
|
|
110
113
|
throw error;
|
|
@@ -112,6 +115,21 @@ async function registerLegacyBrowserTools(pi) {
|
|
|
112
115
|
}
|
|
113
116
|
return legacyRegistrationPromise;
|
|
114
117
|
}
|
|
118
|
+
function withBrowserArtifactCwdScope(pi) {
|
|
119
|
+
return {
|
|
120
|
+
...pi,
|
|
121
|
+
registerTool(definition) {
|
|
122
|
+
pi.registerTool({
|
|
123
|
+
...definition,
|
|
124
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
125
|
+
if (ctx?.cwd)
|
|
126
|
+
setArtifactRootForCwd(ctx.cwd);
|
|
127
|
+
return definition.execute(toolCallId, params, signal, onUpdate, ctx);
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
115
133
|
async function registerBrowserTools(pi) {
|
|
116
134
|
const engine = resolveBrowserEngineMode();
|
|
117
135
|
if (engine === "off")
|
|
@@ -147,6 +165,29 @@ async function registerBrowserTools(pi) {
|
|
|
147
165
|
throw error;
|
|
148
166
|
}
|
|
149
167
|
}
|
|
168
|
+
function isWarmUpDisabled() {
|
|
169
|
+
const value = process.env.GSD_BROWSER_WARMUP?.trim().toLowerCase();
|
|
170
|
+
return value === "0" || value === "false" || value === "off";
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Auto-initialize the managed gsd-browser engine only when explicitly selected
|
|
174
|
+
* for a web app. Best-effort and non-blocking: warm-up runs in the background
|
|
175
|
+
* and only surfaces a warning if it fails.
|
|
176
|
+
*/
|
|
177
|
+
function maybeWarmUpManagedEngine(pi, ctx) {
|
|
178
|
+
if (isWarmUpDisabled())
|
|
179
|
+
return;
|
|
180
|
+
if (resolveBrowserEngineMode() !== "gsd-browser")
|
|
181
|
+
return;
|
|
182
|
+
const projectRoot = ctx.cwd || process.cwd();
|
|
183
|
+
if (!detectWebApp(projectRoot))
|
|
184
|
+
return;
|
|
185
|
+
void warmUpManagedGsdBrowser(ctx).then((result) => {
|
|
186
|
+
if (!result.ok && ctx.hasUI) {
|
|
187
|
+
ctx.ui.notify(`gsd-browser auto-init failed: ${result.error}. Browser UAT tools will retry on first use; run /gsd doctor if this persists.`, "warning");
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
150
191
|
async function closeActiveBrowserEngines() {
|
|
151
192
|
await closeManagedGsdBrowser();
|
|
152
193
|
if (legacyRegistrationPromise) {
|
|
@@ -157,12 +198,15 @@ async function closeActiveBrowserEngines() {
|
|
|
157
198
|
export default function (pi) {
|
|
158
199
|
pi.on("session_start", async (_event, ctx) => {
|
|
159
200
|
if (ctx.hasUI) {
|
|
160
|
-
void registerBrowserTools(pi)
|
|
201
|
+
void registerBrowserTools(pi)
|
|
202
|
+
.then(() => maybeWarmUpManagedEngine(pi, ctx))
|
|
203
|
+
.catch((error) => {
|
|
161
204
|
ctx.ui.notify(`browser-tools failed to load: ${error instanceof Error ? error.message : String(error)}`, "warning");
|
|
162
205
|
});
|
|
163
206
|
return;
|
|
164
207
|
}
|
|
165
208
|
await registerBrowserTools(pi);
|
|
209
|
+
maybeWarmUpManagedEngine(pi, ctx);
|
|
166
210
|
});
|
|
167
211
|
pi.on("session_shutdown", async () => {
|
|
168
212
|
await closeActiveBrowserEngines();
|
|
@@ -18,6 +18,17 @@ export const HAR_FILENAME = "session.har";
|
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
19
19
|
// Mutable state variables — accessed only via get/set functions
|
|
20
20
|
// ---------------------------------------------------------------------------
|
|
21
|
+
// 0. artifactRoot
|
|
22
|
+
let _artifactRoot = ARTIFACT_ROOT;
|
|
23
|
+
export function getArtifactRoot() { return _artifactRoot; }
|
|
24
|
+
export function setArtifactRootForCwd(cwd) {
|
|
25
|
+
const newRoot = path.resolve(cwd, ".artifacts", "browser");
|
|
26
|
+
if (newRoot !== _artifactRoot) {
|
|
27
|
+
_artifactRoot = newRoot;
|
|
28
|
+
_sessionArtifactDir = null;
|
|
29
|
+
}
|
|
30
|
+
return _artifactRoot;
|
|
31
|
+
}
|
|
21
32
|
// 1. browser
|
|
22
33
|
let _browser = null;
|
|
23
34
|
export function getBrowser() { return _browser; }
|
|
@@ -102,6 +113,7 @@ export function setHarState(h) { _harState = h; }
|
|
|
102
113
|
// resetAllState — mirrors closeBrowser()'s reset logic
|
|
103
114
|
// ---------------------------------------------------------------------------
|
|
104
115
|
export function resetAllState() {
|
|
116
|
+
_artifactRoot = ARTIFACT_ROOT;
|
|
105
117
|
_browser = null;
|
|
106
118
|
_context = null;
|
|
107
119
|
pageRegistry.pages = [];
|
|
@@ -2,7 +2,7 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import { stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { formatTimelineEntries, buildFailureHypothesis, summarizeBrowserSession, } from "../core.js";
|
|
5
|
-
import {
|
|
5
|
+
import { HAR_FILENAME, getArtifactRoot, getPageRegistry, getConsoleLogs, getNetworkLogs, getDialogLogs, getActionTimeline, getActiveTraceSession, setActiveTraceSession, getHarState, setHarState, getSessionStartedAt, getSessionArtifactDir, } from "../state.js";
|
|
6
6
|
import { getActiveFrameMetadata, ensureDir, } from "../utils.js";
|
|
7
7
|
export function registerSessionTools(pi, deps) {
|
|
8
8
|
// -------------------------------------------------------------------------
|
|
@@ -289,7 +289,8 @@ export function registerSessionTools(pi, deps) {
|
|
|
289
289
|
const { page: p } = await deps.ensureBrowser();
|
|
290
290
|
const startedAt = Date.now();
|
|
291
291
|
const sessionDir = await deps.ensureSessionArtifactDir();
|
|
292
|
-
const
|
|
292
|
+
const bundleName = `${deps.formatArtifactTimestamp(startedAt)}-${deps.sanitizeArtifactName(params.name ?? "debug-bundle", "debug-bundle")}`;
|
|
293
|
+
const bundleDir = path.join(getArtifactRoot(), bundleName);
|
|
293
294
|
await ensureDir(bundleDir);
|
|
294
295
|
const pages = await deps.getLivePagesSnapshot();
|
|
295
296
|
const actionTimeline = getActionTimeline();
|
|
@@ -8,7 +8,7 @@ import { mkdir, stat, writeFile, copyFile } from "node:fs/promises";
|
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateHead, } from "@gsd/pi-coding-agent";
|
|
10
10
|
import { beginAction, finishAction, findAction, toActionParamsSummary, registryListPages, } from "./core.js";
|
|
11
|
-
import {
|
|
11
|
+
import { getActiveFrame, getArtifactRoot, getActiveTraceSession, getConsoleLogs, getDialogLogs, getHarState, getNetworkLogs, getSessionArtifactDir, getSessionStartedAt, setSessionArtifactDir, setSessionStartedAt, pageRegistry, actionTimeline, getPendingCriticalRequestsByPage, } from "./state.js";
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Text truncation
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
@@ -60,7 +60,7 @@ export async function ensureSessionArtifactDir() {
|
|
|
60
60
|
return existing;
|
|
61
61
|
}
|
|
62
62
|
const startedAt = ensureSessionStartedAt();
|
|
63
|
-
const dir = path.join(
|
|
63
|
+
const dir = path.join(getArtifactRoot(), `${formatArtifactTimestamp(startedAt)}-session`);
|
|
64
64
|
setSessionArtifactDir(dir);
|
|
65
65
|
await ensureDir(dir);
|
|
66
66
|
return dir;
|
|
@@ -95,7 +95,7 @@ export function getActiveFrameMetadata() {
|
|
|
95
95
|
}
|
|
96
96
|
export function getSessionArtifactMetadata() {
|
|
97
97
|
return {
|
|
98
|
-
artifactRoot:
|
|
98
|
+
artifactRoot: getArtifactRoot(),
|
|
99
99
|
sessionStartedAt: getSessionStartedAt(),
|
|
100
100
|
sessionArtifactDir: getSessionArtifactDir(),
|
|
101
101
|
activeTraceSession: getActiveTraceSession(),
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* web-app-detect — lightweight, synchronous heuristic for deciding whether the
|
|
3
|
+
* project under development is a web app. Used only when the optional managed
|
|
4
|
+
* gsd-browser engine is selected and can be warmed before first use.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
// Frontend frameworks / bundlers whose presence in dependencies indicates a
|
|
9
|
+
// browser-facing web app worth warming the optional managed engine for.
|
|
10
|
+
const WEB_DEPENDENCY_RE = /^(react|react-dom|next|nuxt|vue|@vue\/|svelte|@sveltejs\/|solid-js|astro|@remix-run\/|gatsby|preact|@angular\/core|vite|@vitejs\/|@builder\.io\/qwik|@web\/dev-server|@11ty\/eleventy)/;
|
|
11
|
+
// package.json scripts that imply a dev server / browser-facing build.
|
|
12
|
+
const WEB_SCRIPT_RE = /\b(vite|next|nuxt|astro|remix|webpack(-dev-server)?|parcel|ng serve|serve\b|http-server|live-server|gatsby)\b/;
|
|
13
|
+
function readPackageJson(projectRoot) {
|
|
14
|
+
const packageJsonPath = resolve(projectRoot, "package.json");
|
|
15
|
+
if (!existsSync(packageJsonPath))
|
|
16
|
+
return null;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
19
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function dependencyNames(pkg) {
|
|
26
|
+
return [
|
|
27
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
28
|
+
...Object.keys(pkg.devDependencies ?? {}),
|
|
29
|
+
...Object.keys(pkg.peerDependencies ?? {}),
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns true when the project looks like a browser-facing web app. Conservative
|
|
34
|
+
* and dependency-free: a false negative just means lazy connection (the prior
|
|
35
|
+
* behavior); a false positive only warms an idle engine connection.
|
|
36
|
+
*/
|
|
37
|
+
export function detectWebApp(projectRoot) {
|
|
38
|
+
const pkg = readPackageJson(projectRoot);
|
|
39
|
+
if (pkg) {
|
|
40
|
+
if (dependencyNames(pkg).some((name) => WEB_DEPENDENCY_RE.test(name)))
|
|
41
|
+
return true;
|
|
42
|
+
const scriptValues = Object.values(pkg.scripts ?? {}).filter((value) => typeof value === "string");
|
|
43
|
+
if (scriptValues.some((script) => WEB_SCRIPT_RE.test(script)))
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// No package.json signal — fall back to a top-level index.html (static sites).
|
|
47
|
+
if (existsSync(resolve(projectRoot, "index.html")))
|
|
48
|
+
return true;
|
|
49
|
+
if (existsSync(resolve(projectRoot, "public", "index.html")))
|
|
50
|
+
return true;
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
@@ -1106,7 +1106,7 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
1106
1106
|
unitId: iterData.unitId,
|
|
1107
1107
|
});
|
|
1108
1108
|
const finalizeReason = finalizeResult.action === "break" ? finalizeResult.reason : undefined;
|
|
1109
|
-
const finalizeStatus = finalizeReason === "step-wizard"
|
|
1109
|
+
const finalizeStatus = (finalizeReason === "step-wizard" || finalizeReason === "milestone-complete")
|
|
1110
1110
|
? "completed"
|
|
1111
1111
|
: finalizeResult.action === "next"
|
|
1112
1112
|
? "completed"
|
|
@@ -1172,7 +1172,9 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
1172
1172
|
stuckStatePersistedThisIteration = true;
|
|
1173
1173
|
finishTurn("completed");
|
|
1174
1174
|
if (finalizeDecision.action === "complete-and-break") {
|
|
1175
|
-
s.
|
|
1175
|
+
if (!s.completionStopInProgress) {
|
|
1176
|
+
s.preserveStepSurfaceAfterLoopExit = true;
|
|
1177
|
+
}
|
|
1176
1178
|
break;
|
|
1177
1179
|
}
|
|
1178
1180
|
}
|
|
@@ -16,6 +16,8 @@ import { detectStuck } from "./detect-stuck.js";
|
|
|
16
16
|
import { runUnit } from "./run-unit.js";
|
|
17
17
|
import { debugLog } from "../debug-logger.js";
|
|
18
18
|
import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
|
|
19
|
+
import { buildManualValidationGuidance } from "../worktree-manager.js";
|
|
20
|
+
import { relSliceFile } from "../paths.js";
|
|
19
21
|
import { classifyProject } from "../detection.js";
|
|
20
22
|
import { MergeConflictError } from "../git-service.js";
|
|
21
23
|
import { setCurrentPhase, clearCurrentPhase } from "../../shared/gsd-phase-state.js";
|
|
@@ -47,6 +49,7 @@ import { resolveSafetyHarnessConfig } from "../safety/safety-harness.js";
|
|
|
47
49
|
import { getContextPauseAction } from "../auto-budget.js";
|
|
48
50
|
import { getWorkflowTransportSupportError, getRequiredWorkflowToolsForAutoUnit, supportsStructuredQuestions, } from "../workflow-mcp.js";
|
|
49
51
|
import { prepareWorkflowMcpForProject } from "../workflow-mcp-auto-prep.js";
|
|
52
|
+
import { getToolBaselineSnapshot, applyThinkingLevelForModel, floorThinkingLevelForUnit } from "../auto-model-selection.js";
|
|
50
53
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
51
54
|
import { createWorktreeSafetyModule } from "../worktree-safety.js";
|
|
52
55
|
import { isSuspiciousGhostCompletion } from "../auto-unit-closeout.js";
|
|
@@ -302,6 +305,8 @@ async function validateSourceWriteWorktreeSafety(ic, unitType, unitId, milestone
|
|
|
302
305
|
// ─── Session timeout auto-resume state ────────────────────────────────────────
|
|
303
306
|
let consecutiveSessionTimeouts = 0;
|
|
304
307
|
const MAX_SESSION_TIMEOUT_AUTO_RESUMES = 3;
|
|
308
|
+
/** Maximum zero-tool-call retries before pausing — context exhaustion is deterministic. */
|
|
309
|
+
const MAX_ZERO_TOOL_RETRIES = 1;
|
|
305
310
|
export function resetSessionTimeoutState() {
|
|
306
311
|
consecutiveSessionTimeouts = 0;
|
|
307
312
|
}
|
|
@@ -388,7 +393,7 @@ async function generateMilestoneReport(s, ctx, milestoneId) {
|
|
|
388
393
|
async function closeoutAndStop(ctx, pi, s, deps, reason) {
|
|
389
394
|
if (s.currentUnit) {
|
|
390
395
|
await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
391
|
-
s.
|
|
396
|
+
s.clearCurrentUnit();
|
|
392
397
|
}
|
|
393
398
|
await deps.stopAuto(ctx, pi, reason);
|
|
394
399
|
}
|
|
@@ -576,7 +581,7 @@ async function failClosedOnFinalizeTimeout(ic, iterData, loopState, stage, start
|
|
|
576
581
|
});
|
|
577
582
|
ctx.ui.notify(`${stage === "pre" ? "postUnitPreVerification" : "postUnitPostVerification"} timed out after ${timeoutMs / 1000}s for ${unitType} ${unitId} (${loopState.consecutiveFinalizeTimeouts}/${MAX_FINALIZE_TIMEOUTS}) — pausing auto-mode for recovery.`, "warning");
|
|
578
583
|
await deps.pauseAuto(ctx, pi);
|
|
579
|
-
s.
|
|
584
|
+
s.clearCurrentUnit();
|
|
580
585
|
clearCurrentPhase();
|
|
581
586
|
drainLogs();
|
|
582
587
|
return { action: "break", reason: progressKind };
|
|
@@ -1024,7 +1029,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
1024
1029
|
deps.logCmuxEvent(prefs, `Milestone ${mid} complete.`, "success");
|
|
1025
1030
|
if (s.currentUnit) {
|
|
1026
1031
|
await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
1027
|
-
s.
|
|
1032
|
+
s.clearCurrentUnit();
|
|
1028
1033
|
}
|
|
1029
1034
|
await deps.stopAuto(ctx, pi, `Milestone ${mid} complete`, {
|
|
1030
1035
|
completionWidget: {
|
|
@@ -1070,7 +1075,13 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
1070
1075
|
const authMode = provider && typeof ctx.modelRegistry?.getProviderAuthMode === "function"
|
|
1071
1076
|
? ctx.modelRegistry.getProviderAuthMode(provider)
|
|
1072
1077
|
: undefined;
|
|
1073
|
-
|
|
1078
|
+
// Use the baseline snapshot rather than the live active-tool set: a prior
|
|
1079
|
+
// unit's per-provider narrowing (hook overrides, Groq 128-tool cap, etc.)
|
|
1080
|
+
// can strip required MCP tools from the live set even though
|
|
1081
|
+
// selectAndApplyModel will restore them before the unit is dispatched.
|
|
1082
|
+
// Checking a stale-narrowed set causes false transport-preflight warnings
|
|
1083
|
+
// that repeat on every /gsd auto resume (#477 follow-up).
|
|
1084
|
+
const activeTools = getToolBaselineSnapshot(pi);
|
|
1074
1085
|
// Deep planning intentionally keeps human checkpoints in plain chat. In
|
|
1075
1086
|
// Claude Code/local MCP transports, structured question requests can be
|
|
1076
1087
|
// cancelled outside the normal chat flow, which made approval gates easy to
|
|
@@ -1093,6 +1104,9 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
1093
1104
|
sessionContextWindow: ctx.model?.contextWindow,
|
|
1094
1105
|
sessionProvider: ctx.model?.provider,
|
|
1095
1106
|
modelRegistry: ctx.modelRegistry,
|
|
1107
|
+
activeTools,
|
|
1108
|
+
sessionBaseUrl: ctx.model?.baseUrl,
|
|
1109
|
+
sessionAuthMode: authMode,
|
|
1096
1110
|
});
|
|
1097
1111
|
if (isUnhandledPhaseWarning(dispatchResult)) {
|
|
1098
1112
|
deps.invalidateAllCaches();
|
|
@@ -1116,6 +1130,9 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
1116
1130
|
sessionContextWindow: ctx.model?.contextWindow,
|
|
1117
1131
|
sessionProvider: ctx.model?.provider,
|
|
1118
1132
|
modelRegistry: ctx.modelRegistry,
|
|
1133
|
+
activeTools,
|
|
1134
|
+
sessionBaseUrl: ctx.model?.baseUrl,
|
|
1135
|
+
sessionAuthMode: authMode,
|
|
1119
1136
|
});
|
|
1120
1137
|
}
|
|
1121
1138
|
if (dispatchResult.action === "stop") {
|
|
@@ -1695,9 +1712,16 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1695
1712
|
if (match) {
|
|
1696
1713
|
const ok = await pi.setModel(match, { persist: false });
|
|
1697
1714
|
if (ok) {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1715
|
+
// Apply the per-phase reasoning effort selectAndApplyModel resolved for
|
|
1716
|
+
// this unit — not the auto-start session snapshot — but route it through
|
|
1717
|
+
// the same floor + capability-clamp pipeline against the *hook* model
|
|
1718
|
+
// (ADR-026). The hook override can pick a different model family than the
|
|
1719
|
+
// one selectAndApplyModel clamped against, so re-clamping here prevents
|
|
1720
|
+
// sending an unsupported level; the floor fills in when no phase level
|
|
1721
|
+
// resolved so a hook-overridden execute-task still meets the floor.
|
|
1722
|
+
const hookThinkingBase = modelResult.appliedThinkingLevel
|
|
1723
|
+
?? floorThinkingLevelForUnit(unitType, s.autoModeStartThinkingLevel);
|
|
1724
|
+
applyThinkingLevelForModel(pi, hookThinkingBase, match, ctx);
|
|
1701
1725
|
s.currentUnitModel = match;
|
|
1702
1726
|
ctx.ui.notify(`Hook model override: ${match.provider}/${match.id}`, "info");
|
|
1703
1727
|
}
|
|
@@ -1766,7 +1790,21 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1766
1790
|
_resetLogs();
|
|
1767
1791
|
const unitStartedAt = Date.now();
|
|
1768
1792
|
s.unitDispatchCount.set(dispatchKey, nextDispatchCount);
|
|
1769
|
-
s.
|
|
1793
|
+
s.setCurrentUnit({ type: unitType, id: unitId, startedAt: unitStartedAt, workspaceRoot: s.basePath });
|
|
1794
|
+
if (unitType === "execute-task") {
|
|
1795
|
+
const { milestone, slice, task } = parseUnitId(unitId);
|
|
1796
|
+
if (milestone && slice && task && isDbAvailable()) {
|
|
1797
|
+
try {
|
|
1798
|
+
const taskRow = getTask(milestone, slice, task);
|
|
1799
|
+
if (taskRow)
|
|
1800
|
+
s.sourceObservations.observePlanTask(taskRow);
|
|
1801
|
+
}
|
|
1802
|
+
catch (err) {
|
|
1803
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1804
|
+
logWarning("prompt", `failed to preload source observations for ${unitId}: ${message}`);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1770
1808
|
s.rootWriteBaseline = isIsolatedWorktreeSession(s)
|
|
1771
1809
|
? captureRootDirtySnapshot(s.originalBasePath)
|
|
1772
1810
|
: null;
|
|
@@ -1852,7 +1890,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
1852
1890
|
category: "unknown",
|
|
1853
1891
|
isTransient: true,
|
|
1854
1892
|
});
|
|
1855
|
-
s.
|
|
1893
|
+
s.clearCurrentUnit();
|
|
1856
1894
|
await deps.pauseAuto(ctx, pi);
|
|
1857
1895
|
return { action: "break", reason: "ghost-completion" };
|
|
1858
1896
|
}
|
|
@@ -2059,13 +2097,23 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
2059
2097
|
});
|
|
2060
2098
|
}
|
|
2061
2099
|
else {
|
|
2100
|
+
const zeroToolKey = `${unitType}/${unitId}`;
|
|
2101
|
+
const attempt = (s.zeroToolRetryCount.get(zeroToolKey) ?? 0) + 1;
|
|
2062
2102
|
debugLog("runUnitPhase", {
|
|
2063
2103
|
phase: "zero-tool-calls",
|
|
2064
2104
|
unitType,
|
|
2065
2105
|
unitId,
|
|
2106
|
+
attempt,
|
|
2066
2107
|
warning: "Unit completed with 0 tool calls — likely context exhaustion, marking as failed",
|
|
2067
2108
|
});
|
|
2068
|
-
|
|
2109
|
+
if (attempt > MAX_ZERO_TOOL_RETRIES) {
|
|
2110
|
+
s.zeroToolRetryCount.delete(zeroToolKey);
|
|
2111
|
+
ctx.ui.notify(`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, pausing auto-mode after ${MAX_ZERO_TOOL_RETRIES} retry.`, "error");
|
|
2112
|
+
await deps.pauseAuto(ctx, pi);
|
|
2113
|
+
return { action: "break", reason: "zero-tool-calls-exhausted" };
|
|
2114
|
+
}
|
|
2115
|
+
s.zeroToolRetryCount.set(zeroToolKey, attempt);
|
|
2116
|
+
ctx.ui.notify(`${unitType} ${unitId} completed with 0 tool calls — context exhaustion, will retry (attempt ${attempt}/${MAX_ZERO_TOOL_RETRIES})`, "warning");
|
|
2069
2117
|
return {
|
|
2070
2118
|
action: "retry",
|
|
2071
2119
|
reason: "zero-tool-calls",
|
|
@@ -2087,6 +2135,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
2087
2135
|
if (artifactVerified) {
|
|
2088
2136
|
s.unitDispatchCount.delete(dispatchKey);
|
|
2089
2137
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
2138
|
+
s.zeroToolRetryCount.delete(dispatchKey);
|
|
2090
2139
|
}
|
|
2091
2140
|
// Write phase handoff anchor after successful research/planning completion
|
|
2092
2141
|
const anchorPhases = new Set(["research-milestone", "research-slice", "plan-milestone", "plan-slice"]);
|
|
@@ -2176,7 +2225,7 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
2176
2225
|
s.currentUnit?.type === preUnitSnapshot.type &&
|
|
2177
2226
|
s.currentUnit?.id === preUnitSnapshot.id &&
|
|
2178
2227
|
s.currentUnit?.startedAt === preUnitSnapshot.startedAt) {
|
|
2179
|
-
s.
|
|
2228
|
+
s.clearCurrentUnit();
|
|
2180
2229
|
}
|
|
2181
2230
|
s.rootWriteBaseline = null;
|
|
2182
2231
|
};
|
|
@@ -2232,7 +2281,21 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
2232
2281
|
}
|
|
2233
2282
|
}
|
|
2234
2283
|
if (pauseAfterUatDispatch) {
|
|
2235
|
-
|
|
2284
|
+
const pauseMid = iterData.mid;
|
|
2285
|
+
const pauseSliceId = pauseMid && iterData.unitId.startsWith(`${pauseMid}/`)
|
|
2286
|
+
? iterData.unitId.slice(pauseMid.length + 1)
|
|
2287
|
+
: undefined;
|
|
2288
|
+
const guidance = pauseMid
|
|
2289
|
+
? buildManualValidationGuidance(s.basePath, pauseMid, {
|
|
2290
|
+
uatPath: pauseSliceId
|
|
2291
|
+
? relSliceFile(s.basePath, pauseMid, pauseSliceId, "UAT")
|
|
2292
|
+
: undefined,
|
|
2293
|
+
})
|
|
2294
|
+
: null;
|
|
2295
|
+
const pauseMessage = guidance
|
|
2296
|
+
? `UAT requires human execution. Auto-mode will pause after this unit writes the result file.\n\n${guidance}`
|
|
2297
|
+
: "UAT requires human execution. Auto-mode will pause after this unit writes the result file.";
|
|
2298
|
+
ctx.ui.notify(pauseMessage, "info");
|
|
2236
2299
|
await deps.pauseAuto(ctx, pi);
|
|
2237
2300
|
debugLog("autoLoop", { phase: "exit", reason: "uat-pause" });
|
|
2238
2301
|
clearFinalizingUnit();
|
|
@@ -2397,5 +2460,17 @@ export async function runFinalize(ic, iterData, loopState, sidecarItem) {
|
|
|
2397
2460
|
ctx.ui.notify(formatForNotification(logs), severity);
|
|
2398
2461
|
}
|
|
2399
2462
|
}
|
|
2463
|
+
if (preUnitSnapshot?.type === "complete-milestone" && s.currentMilestoneId) {
|
|
2464
|
+
// cleanupAfterLoopExit skips gsd-progress when preserveCompletionSurface is true, so clear stale controls here.
|
|
2465
|
+
ctx.ui.setStatus?.("gsd-step", undefined);
|
|
2466
|
+
ctx.ui.setWidget?.("gsd-progress", undefined);
|
|
2467
|
+
await deps.stopAuto(ctx, pi, `Milestone ${s.currentMilestoneId} complete`, {
|
|
2468
|
+
completionWidget: {
|
|
2469
|
+
milestoneId: s.currentMilestoneId,
|
|
2470
|
+
milestoneTitle: iterData.midTitle,
|
|
2471
|
+
},
|
|
2472
|
+
});
|
|
2473
|
+
return { action: "break", reason: "milestone-complete" };
|
|
2474
|
+
}
|
|
2400
2475
|
return { action: "next", data: undefined };
|
|
2401
2476
|
}
|