@opengsd/gsd-pi 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist/onboarding.js +11 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +20 -25
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +118 -53
- package/dist/resources/extensions/cursor-cli/index.js +16 -0
- package/dist/resources/extensions/cursor-cli/models.js +63 -0
- package/dist/resources/extensions/cursor-cli/package.json +11 -0
- package/dist/resources/extensions/cursor-cli/readiness.js +128 -0
- package/dist/resources/extensions/cursor-cli/stream-adapter.js +353 -0
- package/dist/resources/extensions/gsd/activity-log.js +4 -1
- package/dist/resources/extensions/gsd/artifact-verification.js +25 -9
- package/dist/resources/extensions/gsd/auto/closeout.js +45 -42
- package/dist/resources/extensions/gsd/auto/finalize.js +9 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +1 -1
- package/dist/resources/extensions/gsd/auto/run-unit.js +5 -2
- package/dist/resources/extensions/gsd/auto/schedule-wakeup.js +3 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +15 -5
- package/dist/resources/extensions/gsd/auto-model-selection.js +36 -18
- package/dist/resources/extensions/gsd/auto-prompts.js +76 -2
- package/dist/resources/extensions/gsd/auto-start.js +4 -3
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +38 -11
- package/dist/resources/extensions/gsd/auto.js +23 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +114 -5
- package/dist/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.js +58 -9
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +10 -2
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +14 -1
- package/dist/resources/extensions/gsd/codebase-generator.js +157 -19
- package/dist/resources/extensions/gsd/commands/handlers/core.js +40 -4
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +153 -1
- package/dist/resources/extensions/gsd/commands-worktree.js +11 -2
- package/dist/resources/extensions/gsd/db/queries.js +39 -0
- package/dist/resources/extensions/gsd/discussion-handoff.js +8 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +206 -14
- package/dist/resources/extensions/gsd/doctor-providers.js +38 -10
- package/dist/resources/extensions/gsd/doctor.js +93 -3
- package/dist/resources/extensions/gsd/exec-sandbox.js +6 -2
- package/dist/resources/extensions/gsd/flat-phase-migration.js +74 -23
- package/dist/resources/extensions/gsd/git-service.js +14 -18
- package/dist/resources/extensions/gsd/gsd-db.js +52 -0
- package/dist/resources/extensions/gsd/guidance.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow.js +40 -2
- package/dist/resources/extensions/gsd/key-manager.js +1 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +25 -8
- package/dist/resources/extensions/gsd/migrate-external.js +24 -7
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +3 -3
- package/dist/resources/extensions/gsd/preferences-diagnostics.js +24 -1
- package/dist/resources/extensions/gsd/preferences-models.js +6 -4
- package/dist/resources/extensions/gsd/preferences-validation.js +25 -2
- package/dist/resources/extensions/gsd/preferences.js +29 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/dist/resources/extensions/gsd/redact-secrets.js +37 -0
- package/dist/resources/extensions/gsd/repo-identity.js +16 -0
- package/dist/resources/extensions/gsd/repository-registry.js +6 -1
- package/dist/resources/extensions/gsd/root-write-leak-guard.js +4 -2
- package/dist/resources/extensions/gsd/safe-fs.js +23 -2
- package/dist/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +76 -8
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +5 -4
- package/dist/resources/extensions/gsd/unit-registry.js +27 -2
- package/dist/resources/extensions/gsd/unit-runtime.js +21 -0
- package/dist/resources/extensions/gsd/workspace.js +26 -8
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +67 -5
- package/dist/resources/extensions/gsd/worktree-manager.js +97 -4
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- 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/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +8 -1
- package/integrations/hermes/CONTEXT.md +47 -0
- package/integrations/hermes/README.md +21 -0
- package/integrations/hermes/__init__.py +31 -0
- package/integrations/hermes/docs/issue-1162-grilling.md +197 -0
- package/integrations/hermes/docs/setup.md +4 -0
- package/integrations/hermes/open_gsd_hermes/commands.py +141 -0
- package/integrations/hermes/open_gsd_hermes/config.py +2 -0
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +594 -31
- package/integrations/hermes/open_gsd_hermes/notifications.py +10 -1
- package/integrations/hermes/plugin.yaml +4 -0
- package/integrations/hermes/tests/test_config.py +6 -0
- package/integrations/hermes/tests/test_directory_loader.py +37 -0
- package/integrations/hermes/tests/test_gsd_client_cache.py +3 -0
- package/integrations/hermes/tests/test_gsd_client_execute.py +35 -0
- package/integrations/hermes/tests/test_gsd_client_process_cwd.py +22 -0
- package/integrations/hermes/tests/test_gsd_client_timeout.py +98 -0
- package/integrations/hermes/tests/test_milestone_client.py +447 -0
- package/integrations/hermes/tests/test_new_milestone_command.py +313 -0
- package/integrations/hermes/tests/test_supervisor_fsm.py +40 -0
- package/package.json +8 -8
- package/packages/cloud-mcp-gateway/dist/auth-store.d.ts +1 -0
- package/packages/cloud-mcp-gateway/dist/auth-store.d.ts.map +1 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.js +21 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.js.map +1 -1
- package/packages/cloud-mcp-gateway/dist/auth-store.test.js +34 -0
- package/packages/cloud-mcp-gateway/dist/auth-store.test.js.map +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/cloud-runtime.d.ts +2 -0
- package/packages/daemon/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/daemon/dist/cloud-runtime.js +25 -1
- package/packages/daemon/dist/cloud-runtime.js.map +1 -1
- package/packages/daemon/dist/cloud-runtime.test.js +51 -0
- package/packages/daemon/dist/cloud-runtime.test.js.map +1 -1
- package/packages/daemon/dist/message-batcher.d.ts +7 -0
- package/packages/daemon/dist/message-batcher.d.ts.map +1 -1
- package/packages/daemon/dist/message-batcher.js +13 -0
- package/packages/daemon/dist/message-batcher.js.map +1 -1
- package/packages/daemon/dist/message-batcher.test.js +48 -0
- package/packages/daemon/dist/message-batcher.test.js.map +1 -1
- package/packages/daemon/dist/session-manager.js +1 -1
- package/packages/daemon/dist/session-manager.js.map +1 -1
- package/packages/daemon/package.json +5 -5
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts +13 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +15 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js +4 -1
- package/packages/gsd-agent-core/dist/session/agent-session-navigation.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/server.d.ts +18 -5
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +46 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/session-manager.js +1 -1
- package/packages/mcp-server/dist/session-manager.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/env-api-keys.d.ts.map +1 -1
- package/packages/pi-ai/dist/env-api-keys.js +3 -0
- package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -2
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +3 -0
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/dist/rpc-client.js +1 -1
- package/packages/rpc-client/dist/rpc-client.js.map +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/link-workspace-packages.cjs +14 -4
- package/src/resources/GSD-WORKFLOW.md +20 -25
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +130 -51
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +371 -39
- package/src/resources/extensions/cursor-cli/index.ts +18 -0
- package/src/resources/extensions/cursor-cli/models.ts +65 -0
- package/src/resources/extensions/cursor-cli/package.json +11 -0
- package/src/resources/extensions/cursor-cli/readiness.ts +143 -0
- package/src/resources/extensions/cursor-cli/stream-adapter.ts +440 -0
- package/src/resources/extensions/cursor-cli/tests/index.test.ts +54 -0
- package/src/resources/extensions/cursor-cli/tests/readiness.test.ts +29 -0
- package/src/resources/extensions/cursor-cli/tests/stream-adapter.test.ts +166 -0
- package/src/resources/extensions/gsd/activity-log.ts +4 -1
- package/src/resources/extensions/gsd/artifact-verification.ts +25 -9
- package/src/resources/extensions/gsd/auto/closeout.ts +54 -56
- package/src/resources/extensions/gsd/auto/finalize.ts +8 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +1 -1
- package/src/resources/extensions/gsd/auto/run-unit.ts +5 -2
- package/src/resources/extensions/gsd/auto/schedule-wakeup.ts +8 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +17 -5
- package/src/resources/extensions/gsd/auto-model-selection.ts +49 -18
- package/src/resources/extensions/gsd/auto-prompts.ts +73 -2
- package/src/resources/extensions/gsd/auto-start.ts +4 -3
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +50 -11
- package/src/resources/extensions/gsd/auto.ts +22 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +128 -5
- package/src/resources/extensions/gsd/bootstrap/schedule-wakeup-tool.ts +80 -12
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +12 -2
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +23 -1
- package/src/resources/extensions/gsd/codebase-generator.ts +179 -18
- package/src/resources/extensions/gsd/commands/handlers/core.ts +39 -3
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +135 -1
- package/src/resources/extensions/gsd/commands-worktree.ts +13 -2
- package/src/resources/extensions/gsd/db/queries.ts +40 -0
- package/src/resources/extensions/gsd/discussion-handoff.ts +10 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +269 -18
- package/src/resources/extensions/gsd/doctor-providers.ts +39 -10
- package/src/resources/extensions/gsd/doctor-types.ts +5 -1
- package/src/resources/extensions/gsd/doctor.ts +95 -3
- package/src/resources/extensions/gsd/exec-sandbox.ts +6 -2
- package/src/resources/extensions/gsd/flat-phase-migration.ts +98 -22
- package/src/resources/extensions/gsd/git-service.ts +14 -17
- package/src/resources/extensions/gsd/gsd-db.ts +72 -0
- package/src/resources/extensions/gsd/guidance.ts +2 -0
- package/src/resources/extensions/gsd/guided-flow.ts +45 -2
- package/src/resources/extensions/gsd/key-manager.ts +1 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +25 -7
- package/src/resources/extensions/gsd/migrate-external.ts +23 -6
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +4 -4
- package/src/resources/extensions/gsd/model-router.ts +4 -5
- package/src/resources/extensions/gsd/preferences-diagnostics.ts +24 -0
- package/src/resources/extensions/gsd/preferences-models.ts +6 -3
- package/src/resources/extensions/gsd/preferences-validation.ts +28 -2
- package/src/resources/extensions/gsd/preferences.ts +38 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
- package/src/resources/extensions/gsd/redact-secrets.ts +40 -0
- package/src/resources/extensions/gsd/repo-identity.ts +17 -0
- package/src/resources/extensions/gsd/repository-registry.ts +7 -1
- package/src/resources/extensions/gsd/root-write-leak-guard.ts +3 -2
- package/src/resources/extensions/gsd/safe-fs.ts +22 -2
- package/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md +7 -9
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +131 -5
- package/src/resources/extensions/gsd/tests/auto-migrating-recovery.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +178 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/auto-session-scope.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/auto-timeout-recovery-harness-abort.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/batch-task-query.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +365 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +138 -1
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +397 -5
- package/src/resources/extensions/gsd/tests/doctor-workspace.test.ts +207 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +87 -19
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/migrate-external-worktree.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +152 -22
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/pending-autostart-scope.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +50 -6
- package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +264 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +150 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/redact-secrets.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/register-hooks-flat-phase-migration.test.ts +73 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +41 -2
- package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/root-write-leak-guard.test.ts +31 -9
- package/src/resources/extensions/gsd/tests/schedule-wakeup-tool.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/status-per-repo.test.ts +94 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +66 -18
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/validator-scope-parity.test.ts +53 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +208 -1
- package/src/resources/extensions/gsd/tests/workspace.test.ts +18 -4
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +32 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +107 -9
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +58 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +11 -5
- package/src/resources/extensions/gsd/unit-registry.ts +34 -2
- package/src/resources/extensions/gsd/unit-runtime.ts +42 -0
- package/src/resources/extensions/gsd/workspace.ts +42 -8
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +135 -11
- package/src/resources/extensions/gsd/worktree-manager.ts +143 -5
- /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → bCg3aYrFN1DKZr2dqgE7L}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zQLcXm0Za8lexoXtgDpMG → bCg3aYrFN1DKZr2dqgE7L}/_ssgManifest.js +0 -0
|
@@ -21,6 +21,8 @@ import { existsSync, readFileSync, unlinkSync } from "node:fs";
|
|
|
21
21
|
import { randomUUID } from "node:crypto";
|
|
22
22
|
import { join } from "node:path";
|
|
23
23
|
|
|
24
|
+
import type { PreflightResult, PostflightResult } from "./clean-root-preflight.js";
|
|
25
|
+
|
|
24
26
|
import type { AutoSession } from "./auto/session.js";
|
|
25
27
|
import { debugLog } from "./debug-logger.js";
|
|
26
28
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -153,11 +155,11 @@ export interface WorktreeLifecycleDeps {
|
|
|
153
155
|
/**
|
|
154
156
|
* Milestone Merge Transaction Module runner.
|
|
155
157
|
*
|
|
156
|
-
* The field name
|
|
157
|
-
*
|
|
158
|
-
*
|
|
158
|
+
* The field name describes the lifecycle seam; production wiring supplies
|
|
159
|
+
* the named transaction wrapper rather than the raw legacy
|
|
160
|
+
* auto-worktree primitive directly.
|
|
159
161
|
*/
|
|
160
|
-
|
|
162
|
+
mergeMilestone: MilestoneMergeTransactionRunner;
|
|
161
163
|
|
|
162
164
|
// ADR-016 phase 2 / C1 + C2 + C3 + C4 inlined the following fields as
|
|
163
165
|
// direct imports — leaf primitives that did not vary across callers:
|
|
@@ -238,7 +240,106 @@ export interface StrandedMilestoneAdoptionOptions {
|
|
|
238
240
|
|
|
239
241
|
export type ExitResult =
|
|
240
242
|
| { ok: true; merged: boolean; codeFilesChanged: boolean }
|
|
241
|
-
| {
|
|
243
|
+
| {
|
|
244
|
+
ok: false;
|
|
245
|
+
reason:
|
|
246
|
+
| "merge-conflict"
|
|
247
|
+
| "teardown-failed"
|
|
248
|
+
| "preflight-dirty-overlap"
|
|
249
|
+
| "preflight-unmerged-conflicts"
|
|
250
|
+
| "merge-failed"
|
|
251
|
+
| "postflight-stash-restore-failed";
|
|
252
|
+
cause?: unknown;
|
|
253
|
+
postflight?: PostflightResult;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
export interface GuardedMilestoneMergeDeps {
|
|
257
|
+
preflightCleanRoot: (
|
|
258
|
+
basePath: string,
|
|
259
|
+
milestoneId: string,
|
|
260
|
+
notify: NotifyCtx["notify"],
|
|
261
|
+
) => PreflightResult;
|
|
262
|
+
postflightPopStash: (
|
|
263
|
+
basePath: string,
|
|
264
|
+
milestoneId: string,
|
|
265
|
+
stashMarker: string | undefined,
|
|
266
|
+
notify: NotifyCtx["notify"],
|
|
267
|
+
) => PostflightResult;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Optional `exitMilestone(..., { merge: true, guardedMerge })` contract for callers
|
|
272
|
+
* that need root-clean preflight and postflight stash restoration around the
|
|
273
|
+
* lifecycle-owned merge attempt. `projectRoot` is the workspace root whose
|
|
274
|
+
* user changes are protected by the supplied guard functions.
|
|
275
|
+
*/
|
|
276
|
+
export interface GuardedMilestoneMergeOptions extends GuardedMilestoneMergeDeps {
|
|
277
|
+
projectRoot: string;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
type GuardedMilestoneMergeResult = ExitResult;
|
|
281
|
+
|
|
282
|
+
function preflightBlockedMergeReason(
|
|
283
|
+
blockedReason: PreflightResult["blockedReason"],
|
|
284
|
+
): Extract<ExitResult, { ok: false }>["reason"] {
|
|
285
|
+
if (blockedReason?.startsWith("unmerged-conflicts")) {
|
|
286
|
+
return "preflight-unmerged-conflicts";
|
|
287
|
+
}
|
|
288
|
+
return "preflight-dirty-overlap";
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Run a milestone merge behind the Worktree Lifecycle seam with the root-clean
|
|
293
|
+
* stash guard that protects user changes around merge.
|
|
294
|
+
*
|
|
295
|
+
* The helper owns the invariant ordering (preflight -> merge callback ->
|
|
296
|
+
* postflight on every attempted merge path) and returns the same typed result
|
|
297
|
+
* shape as `exitMilestone`. Auto closeout remains responsible for translating
|
|
298
|
+
* that result into loop policy (pause vs. stop, visible transcript
|
|
299
|
+
* preservation, projection rebuild).
|
|
300
|
+
*/
|
|
301
|
+
function runGuardedMilestoneMerge(request: {
|
|
302
|
+
merge: () => ExitResult;
|
|
303
|
+
guard: GuardedMilestoneMergeOptions;
|
|
304
|
+
milestoneId: string;
|
|
305
|
+
notify: NotifyCtx["notify"];
|
|
306
|
+
}): GuardedMilestoneMergeResult {
|
|
307
|
+
const { merge, guard, milestoneId, notify } = request;
|
|
308
|
+
const preflight = guard.preflightCleanRoot(guard.projectRoot, milestoneId, notify);
|
|
309
|
+
if (preflight.blocked) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
reason: preflightBlockedMergeReason(preflight.blockedReason),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
let mergeError: unknown = null;
|
|
317
|
+
const exitResult = merge();
|
|
318
|
+
if (!exitResult.ok) {
|
|
319
|
+
mergeError = exitResult.cause ?? new Error(`exit ${exitResult.reason}`);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let postflight: PostflightResult | undefined;
|
|
323
|
+
if (preflight.stashPushed) {
|
|
324
|
+
postflight = guard.postflightPopStash(
|
|
325
|
+
guard.projectRoot,
|
|
326
|
+
milestoneId,
|
|
327
|
+
preflight.stashMarker,
|
|
328
|
+
notify,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (mergeError instanceof MergeConflictError) {
|
|
333
|
+
return { ok: false, reason: "merge-conflict", cause: mergeError, postflight };
|
|
334
|
+
}
|
|
335
|
+
if (mergeError) {
|
|
336
|
+
return { ok: false, reason: "merge-failed", cause: mergeError, postflight };
|
|
337
|
+
}
|
|
338
|
+
if (postflight?.needsManualRecovery) {
|
|
339
|
+
return { ok: false, reason: "postflight-stash-restore-failed", postflight };
|
|
340
|
+
}
|
|
341
|
+
return exitResult;
|
|
342
|
+
}
|
|
242
343
|
|
|
243
344
|
/**
|
|
244
345
|
* Session-less merge entry context. Per ADR-016 phase 2 / A1 (#5616), the
|
|
@@ -1046,7 +1147,7 @@ function _mergeWorktreeModeImpl(
|
|
|
1046
1147
|
};
|
|
1047
1148
|
}
|
|
1048
1149
|
|
|
1049
|
-
const mergeResult = deps.
|
|
1150
|
+
const mergeResult = deps.mergeMilestone(
|
|
1050
1151
|
originalBasePath,
|
|
1051
1152
|
milestoneId,
|
|
1052
1153
|
roadmapResolution.content,
|
|
@@ -1213,7 +1314,7 @@ function _mergeBranchModeImpl(
|
|
|
1213
1314
|
};
|
|
1214
1315
|
}
|
|
1215
1316
|
|
|
1216
|
-
const mergeResult = deps.
|
|
1317
|
+
const mergeResult = deps.mergeMilestone(
|
|
1217
1318
|
worktreeBasePath,
|
|
1218
1319
|
milestoneId,
|
|
1219
1320
|
roadmapResolution.content,
|
|
@@ -1444,18 +1545,41 @@ export class WorktreeLifecycle {
|
|
|
1444
1545
|
* With `opts.merge === false`, runs auto-commit and teardown without
|
|
1445
1546
|
* merging to main.
|
|
1446
1547
|
*
|
|
1548
|
+
* When `opts.guardedMerge` is present with `opts.merge === true`, the
|
|
1549
|
+
* lifecycle verb also owns the root-clean guard around the merge: preflight
|
|
1550
|
+
* runs before the inner merge, postflight stash restore runs after every
|
|
1551
|
+
* attempted merge path, and guard failures are returned as typed
|
|
1552
|
+
* `ExitResult` reasons.
|
|
1553
|
+
*
|
|
1447
1554
|
* Returns a typed `ExitResult`. `MergeConflictError` is surfaced as
|
|
1448
1555
|
* `{ ok: false, reason: "merge-conflict", cause }` instead of thrown,
|
|
1449
|
-
* giving callers a typed branch for the expected failure path.
|
|
1450
|
-
*
|
|
1451
|
-
*
|
|
1556
|
+
* giving callers a typed branch for the expected failure path. Guarded merge
|
|
1557
|
+
* failures surface as `preflight-dirty-overlap`,
|
|
1558
|
+
* `preflight-unmerged-conflicts`, `merge-failed`, or
|
|
1559
|
+
* `postflight-stash-restore-failed`. Unexpected failures (filesystem, git
|
|
1560
|
+
* permissions, etc.) are wrapped as
|
|
1561
|
+
* `{ ok: false, reason: "teardown-failed", cause }` so callers always
|
|
1452
1562
|
* receive a discriminated union — no exceptions for any expected outcome.
|
|
1453
1563
|
*/
|
|
1454
1564
|
exitMilestone(
|
|
1455
1565
|
milestoneId: string,
|
|
1456
|
-
opts: {
|
|
1566
|
+
opts: {
|
|
1567
|
+
merge: boolean;
|
|
1568
|
+
preserveBranch?: boolean;
|
|
1569
|
+
preserveWorktree?: boolean;
|
|
1570
|
+
guardedMerge?: GuardedMilestoneMergeOptions;
|
|
1571
|
+
},
|
|
1457
1572
|
ctx: NotifyCtx,
|
|
1458
1573
|
): ExitResult {
|
|
1574
|
+
if (opts.merge && opts.guardedMerge) {
|
|
1575
|
+
return runGuardedMilestoneMerge({
|
|
1576
|
+
merge: () => this.exitMilestone(milestoneId, { merge: true }, ctx),
|
|
1577
|
+
guard: opts.guardedMerge,
|
|
1578
|
+
milestoneId,
|
|
1579
|
+
notify: ctx.notify,
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1459
1583
|
if (opts.merge) {
|
|
1460
1584
|
try {
|
|
1461
1585
|
const merged = this._mergeAndExit(milestoneId, ctx);
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* 4. remove() — git worktree remove + branch cleanup
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, statSync, unlinkSync } from "node:fs";
|
|
22
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
23
23
|
import { execFileSync } from "node:child_process";
|
|
24
24
|
import { join, resolve, sep } from "node:path";
|
|
25
25
|
import { GSDError, GSD_PARSE_ERROR, GSD_STALE_STATE, GSD_LOCK_HELD, GSD_GIT_ERROR, GSD_MERGE_CONFLICT } from "./errors.js";
|
|
@@ -227,6 +227,113 @@ function isRegisteredGitWorktreeAtPath(basePath: string, wtPath: string): boolea
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
function inspectUncommittedWorktreeState(wtPath: string): { dirty: boolean; status: string } {
|
|
231
|
+
try {
|
|
232
|
+
const status = execFileSync(
|
|
233
|
+
"git",
|
|
234
|
+
["status", "--porcelain=v1", "--untracked-files=all"],
|
|
235
|
+
{ cwd: wtPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
236
|
+
).trimEnd();
|
|
237
|
+
return { dirty: status.length > 0, status };
|
|
238
|
+
} catch (err) {
|
|
239
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
240
|
+
logWarning(
|
|
241
|
+
"worktree",
|
|
242
|
+
`dirty worktree inspection failed for ${wtPath}: ${message}`,
|
|
243
|
+
);
|
|
244
|
+
// Fail closed: unknown state must quarantine rather than force-remove.
|
|
245
|
+
return { dirty: true, status: `git status failed: ${message}` };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function timestampForPath(): string {
|
|
250
|
+
return new Date().toISOString().replace(/[:.]/g, "-");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function uniqueQuarantinePath(basePath: string, name: string): string {
|
|
254
|
+
const root = join(basePath, ".gsd", "quarantine", "worktrees");
|
|
255
|
+
const baseName = `${name}-${timestampForPath()}`;
|
|
256
|
+
let candidate = join(root, baseName);
|
|
257
|
+
let suffix = 2;
|
|
258
|
+
while (existsSync(candidate)) {
|
|
259
|
+
candidate = join(root, `${baseName}-${suffix}`);
|
|
260
|
+
suffix++;
|
|
261
|
+
}
|
|
262
|
+
return candidate;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function quarantineDirtyWorktree(
|
|
266
|
+
basePath: string,
|
|
267
|
+
name: string,
|
|
268
|
+
branch: string,
|
|
269
|
+
wtPath: string,
|
|
270
|
+
status: string,
|
|
271
|
+
): string | null {
|
|
272
|
+
const quarantinePath = uniqueQuarantinePath(basePath, name);
|
|
273
|
+
mkdirSync(join(basePath, ".gsd", "quarantine", "worktrees"), { recursive: true });
|
|
274
|
+
|
|
275
|
+
let moved = false;
|
|
276
|
+
try {
|
|
277
|
+
renameSync(wtPath, quarantinePath);
|
|
278
|
+
moved = true;
|
|
279
|
+
} catch (renameErr) {
|
|
280
|
+
logWarning(
|
|
281
|
+
"worktree",
|
|
282
|
+
`dirty worktree rename quarantine failed for ${name}: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}; trying copy snapshot`,
|
|
283
|
+
);
|
|
284
|
+
try {
|
|
285
|
+
cpSync(wtPath, quarantinePath, { recursive: true, force: false, errorOnExist: true });
|
|
286
|
+
} catch (copyErr) {
|
|
287
|
+
logWarning(
|
|
288
|
+
"reconcile",
|
|
289
|
+
`Dirty worktree quarantine failed; preserving original worktree ${wtPath}: ${copyErr instanceof Error ? copyErr.message : String(copyErr)}`,
|
|
290
|
+
{ worktree: name, path: wtPath },
|
|
291
|
+
);
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
const gitFile = join(quarantinePath, ".git");
|
|
298
|
+
if (existsSync(gitFile) && lstatSync(gitFile).isFile()) {
|
|
299
|
+
unlinkSync(gitFile);
|
|
300
|
+
}
|
|
301
|
+
} catch (err) {
|
|
302
|
+
logWarning(
|
|
303
|
+
"worktree",
|
|
304
|
+
`failed to remove quarantined worktree git pointer: ${err instanceof Error ? err.message : String(err)}`,
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
writeFileSync(
|
|
310
|
+
join(quarantinePath, ".gsd-quarantine.json"),
|
|
311
|
+
JSON.stringify({
|
|
312
|
+
kind: "dirty-worktree",
|
|
313
|
+
worktree: name,
|
|
314
|
+
branch,
|
|
315
|
+
originalPath: wtPath,
|
|
316
|
+
moved,
|
|
317
|
+
quarantinedAt: new Date().toISOString(),
|
|
318
|
+
status,
|
|
319
|
+
}, null, 2) + "\n",
|
|
320
|
+
"utf-8",
|
|
321
|
+
);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
logWarning(
|
|
324
|
+
"worktree",
|
|
325
|
+
`failed to write worktree quarantine metadata: ${err instanceof Error ? err.message : String(err)}`,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
logWarning(
|
|
330
|
+
"reconcile",
|
|
331
|
+
`Quarantined dirty worktree ${name} at ${quarantinePath} before removal. Branch ${branch} was preserved.`,
|
|
332
|
+
{ worktree: name, path: quarantinePath, branch },
|
|
333
|
+
);
|
|
334
|
+
return quarantinePath;
|
|
335
|
+
}
|
|
336
|
+
|
|
230
337
|
/** True when `wtPath` has a git worktree checkout marker (`.git` file with gitdir pointer). */
|
|
231
338
|
export function isLiveGitWorktreeCheckout(wtPath: string): boolean {
|
|
232
339
|
const gitPath = join(wtPath, ".git");
|
|
@@ -730,12 +837,13 @@ export function removeWorktree(
|
|
|
730
837
|
basePath: string,
|
|
731
838
|
name: string,
|
|
732
839
|
opts: { deleteBranch?: boolean; force?: boolean; branch?: string } = {},
|
|
733
|
-
):
|
|
840
|
+
): boolean {
|
|
734
841
|
basePath = normalizeBasePathForWorktreeOps(basePath);
|
|
735
842
|
|
|
736
843
|
let wtPath = worktreePath(basePath, name);
|
|
737
844
|
const branch = opts.branch ?? worktreeBranchName(name);
|
|
738
845
|
const { deleteBranch = true, force = true } = opts;
|
|
846
|
+
let deleteBranchAfterRemoval = deleteBranch;
|
|
739
847
|
|
|
740
848
|
// Resolve the ACTUAL worktree path from git's worktree list.
|
|
741
849
|
// The computed path may differ when .gsd/ is (or was) a symlink to an
|
|
@@ -788,10 +896,10 @@ export function removeWorktree(
|
|
|
788
896
|
|
|
789
897
|
if (!existsSync(wtPath)) {
|
|
790
898
|
nativeWorktreePrune(basePath);
|
|
791
|
-
if (
|
|
899
|
+
if (deleteBranchAfterRemoval) {
|
|
792
900
|
deleteBranchIfPresent(basePath, branch, "nativeBranchDelete failed");
|
|
793
901
|
}
|
|
794
|
-
return;
|
|
902
|
+
return true;
|
|
795
903
|
}
|
|
796
904
|
|
|
797
905
|
// Submodule safety (#2337): detect submodules with uncommitted changes
|
|
@@ -873,6 +981,35 @@ export function removeWorktree(
|
|
|
873
981
|
}
|
|
874
982
|
}
|
|
875
983
|
|
|
984
|
+
// Dirty-worktree quarantine (#2365): once submodule (#2337) and nested-.git
|
|
985
|
+
// (#2616) rescue have run — they commit/clean the tree first — quarantine any
|
|
986
|
+
// uncommitted state that remains instead of force-deleting it. Gate on a live
|
|
987
|
+
// git checkout so a stale local directory left behind by state-sync (which
|
|
988
|
+
// has no `.git` file and is not a registered worktree) is removed normally
|
|
989
|
+
// rather than quarantined; otherwise its branch would never be deleted and
|
|
990
|
+
// the worktree would never be unregistered (#1852).
|
|
991
|
+
if (force && resolvedPathSafe && isLiveGitWorktreeCheckout(resolvedWtPath)) {
|
|
992
|
+
const dirtyState = inspectUncommittedWorktreeState(resolvedWtPath);
|
|
993
|
+
if (dirtyState.dirty) {
|
|
994
|
+
const quarantinePath = quarantineDirtyWorktree(
|
|
995
|
+
basePath,
|
|
996
|
+
name,
|
|
997
|
+
branch,
|
|
998
|
+
resolvedWtPath,
|
|
999
|
+
dirtyState.status,
|
|
1000
|
+
);
|
|
1001
|
+
if (!quarantinePath) {
|
|
1002
|
+
return false;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
deleteBranchAfterRemoval = false;
|
|
1006
|
+
if (!existsSync(resolvedWtPath)) {
|
|
1007
|
+
nativeWorktreePrune(basePath);
|
|
1008
|
+
return true;
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
876
1013
|
// Remove worktree — only use force/rmSync when the path is safely contained
|
|
877
1014
|
if (resolvedPathSafe) {
|
|
878
1015
|
// Remove worktree: try non-force first when submodules have changes,
|
|
@@ -923,9 +1060,10 @@ export function removeWorktree(
|
|
|
923
1060
|
// Prune stale entries so git knows the worktree is gone
|
|
924
1061
|
nativeWorktreePrune(basePath);
|
|
925
1062
|
|
|
926
|
-
if (
|
|
1063
|
+
if (deleteBranchAfterRemoval) {
|
|
927
1064
|
deleteBranchIfPresent(basePath, branch, "final branch delete failed");
|
|
928
1065
|
}
|
|
1066
|
+
return true;
|
|
929
1067
|
}
|
|
930
1068
|
|
|
931
1069
|
/**
|
|
File without changes
|
|
File without changes
|