gsd-pi 2.41.0 → 2.42.0-dev.eedc83f
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 +92 -29
- package/dist/cli-web-branch.d.ts +6 -0
- package/dist/cli-web-branch.js +17 -0
- package/dist/cli.js +15 -1
- package/dist/onboarding.js +2 -1
- package/dist/resource-loader.js +39 -6
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +52 -4
- package/dist/resources/extensions/gsd/auto/loop.js +89 -1
- package/dist/resources/extensions/gsd/auto/phases.js +28 -10
- package/dist/resources/extensions/gsd/auto/session.js +6 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
- package/dist/resources/extensions/gsd/auto-start.js +8 -3
- package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
- package/dist/resources/extensions/gsd/auto.js +64 -2
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
- package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +25 -3
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
- package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
- package/dist/resources/extensions/gsd/context-injector.js +74 -0
- package/dist/resources/extensions/gsd/context-store.js +4 -3
- package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
- package/dist/resources/extensions/gsd/custom-verification.js +145 -0
- package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
- package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
- package/dist/resources/extensions/gsd/db-writer.js +5 -2
- package/dist/resources/extensions/gsd/definition-loader.js +352 -0
- package/dist/resources/extensions/gsd/detection.js +20 -1
- package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
- package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
- package/dist/resources/extensions/gsd/doctor-checks.js +31 -1
- package/dist/resources/extensions/gsd/doctor-providers.js +10 -0
- package/dist/resources/extensions/gsd/doctor.js +11 -1
- package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
- package/dist/resources/extensions/gsd/engine-types.js +8 -0
- package/dist/resources/extensions/gsd/execution-policy.js +8 -0
- package/dist/resources/extensions/gsd/exit-command.js +12 -2
- package/dist/resources/extensions/gsd/export.js +9 -13
- package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
- package/dist/resources/extensions/gsd/files.js +28 -11
- package/dist/resources/extensions/gsd/forensics.js +94 -3
- package/dist/resources/extensions/gsd/git-constants.js +1 -0
- package/dist/resources/extensions/gsd/git-service.js +73 -3
- package/dist/resources/extensions/gsd/graph.js +225 -0
- package/dist/resources/extensions/gsd/gsd-db.js +25 -8
- package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
- package/dist/resources/extensions/gsd/guided-flow.js +7 -3
- package/dist/resources/extensions/gsd/journal.js +85 -0
- package/dist/resources/extensions/gsd/md-importer.js +5 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
- package/dist/resources/extensions/gsd/native-git-bridge.js +3 -2
- package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences.js +60 -8
- package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +92 -7
- package/dist/resources/extensions/gsd/rule-registry.js +489 -0
- package/dist/resources/extensions/gsd/rule-types.js +6 -0
- package/dist/resources/extensions/gsd/run-manager.js +134 -0
- package/dist/resources/extensions/gsd/service-tier.js +147 -0
- package/dist/resources/extensions/gsd/session-lock.js +2 -2
- package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
- package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
- package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
- package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
- package/dist/resources/extensions/gsd/worktree-resolver.js +21 -4
- package/dist/resources/extensions/mcp-client/index.js +2 -1
- package/dist/resources/extensions/search-the-web/tool-search.js +3 -3
- package/dist/resources/extensions/subagent/index.js +7 -3
- package/dist/resources/extensions/voice/index.js +4 -4
- package/dist/resources/skills/create-workflow/SKILL.md +103 -0
- package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/chunks/229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.d.ts +4 -0
- package/dist/web-mode.js +69 -11
- package/package.json +1 -1
- package/packages/native/src/__tests__/text.test.mjs +33 -0
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +6 -0
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/src/agent.test.ts +53 -0
- package/packages/pi-agent-core/src/agent.ts +3 -0
- package/packages/pi-agent-core/src/types.ts +6 -0
- package/packages/pi-agent-core/tsconfig.json +1 -1
- package/packages/pi-ai/dist/models.d.ts +5 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +801 -1468
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +1135 -1588
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js +60 -2
- package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +1543 -0
- package/packages/pi-ai/src/models.generated.ts +1140 -1593
- package/packages/pi-ai/src/models.ts +7 -4
- package/packages/pi-ai/src/utils/oauth/github-copilot.ts +74 -2
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +8 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +60 -0
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/client.js +23 -0
- package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +63 -11
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +20 -6
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -5
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +34 -10
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +7 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +68 -0
- package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -2
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +18 -0
- package/packages/pi-coding-agent/src/core/lsp/client.ts +29 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +3 -0
- package/packages/pi-coding-agent/src/core/package-manager.ts +99 -58
- package/packages/pi-coding-agent/src/core/resource-loader.ts +24 -6
- package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -6
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +36 -11
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +40 -4
- package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
- package/src/resources/extensions/gsd/auto/loop.ts +101 -1
- package/src/resources/extensions/gsd/auto/phases.ts +30 -10
- package/src/resources/extensions/gsd/auto/session.ts +6 -0
- package/src/resources/extensions/gsd/auto/types.ts +4 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
- package/src/resources/extensions/gsd/auto-start.ts +8 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
- package/src/resources/extensions/gsd/auto.ts +71 -2
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
- package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +25 -4
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
- package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
- package/src/resources/extensions/gsd/context-injector.ts +100 -0
- package/src/resources/extensions/gsd/context-store.ts +4 -3
- package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
- package/src/resources/extensions/gsd/custom-verification.ts +180 -0
- package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
- package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
- package/src/resources/extensions/gsd/db-writer.ts +6 -2
- package/src/resources/extensions/gsd/definition-loader.ts +462 -0
- package/src/resources/extensions/gsd/detection.ts +20 -1
- package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
- package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +32 -1
- package/src/resources/extensions/gsd/doctor-providers.ts +13 -0
- package/src/resources/extensions/gsd/doctor-types.ts +1 -0
- package/src/resources/extensions/gsd/doctor.ts +12 -1
- package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
- package/src/resources/extensions/gsd/engine-types.ts +71 -0
- package/src/resources/extensions/gsd/execution-policy.ts +43 -0
- package/src/resources/extensions/gsd/exit-command.ts +14 -2
- package/src/resources/extensions/gsd/export.ts +8 -15
- package/src/resources/extensions/gsd/extension-manifest.json +2 -2
- package/src/resources/extensions/gsd/files.ts +29 -12
- package/src/resources/extensions/gsd/forensics.ts +101 -3
- package/src/resources/extensions/gsd/git-constants.ts +1 -0
- package/src/resources/extensions/gsd/git-service.ts +76 -6
- package/src/resources/extensions/gsd/graph.ts +312 -0
- package/src/resources/extensions/gsd/gsd-db.ts +37 -8
- package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
- package/src/resources/extensions/gsd/guided-flow.ts +7 -3
- package/src/resources/extensions/gsd/journal.ts +134 -0
- package/src/resources/extensions/gsd/md-importer.ts +6 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +3 -2
- package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
- package/src/resources/extensions/gsd/preferences-types.ts +6 -0
- package/src/resources/extensions/gsd/preferences.ts +63 -6
- package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/prompts/queue.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +95 -7
- package/src/resources/extensions/gsd/rule-registry.ts +599 -0
- package/src/resources/extensions/gsd/rule-types.ts +68 -0
- package/src/resources/extensions/gsd/run-manager.ts +180 -0
- package/src/resources/extensions/gsd/service-tier.ts +184 -0
- package/src/resources/extensions/gsd/session-lock.ts +2 -2
- package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
- package/src/resources/extensions/gsd/templates/decisions.md +2 -2
- package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
- package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
- package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
- package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
- package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +133 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
- package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/journal.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
- package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +156 -263
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +135 -0
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +203 -106
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
- package/src/resources/extensions/gsd/types.ts +3 -0
- package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
- package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
- package/src/resources/extensions/gsd/worktree-resolver.ts +32 -11
- package/src/resources/extensions/mcp-client/index.ts +5 -1
- package/src/resources/extensions/search-the-web/tool-search.ts +3 -3
- package/src/resources/extensions/subagent/index.ts +7 -3
- package/src/resources/extensions/voice/index.ts +4 -4
- package/src/resources/skills/create-workflow/SKILL.md +103 -0
- package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
- package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
- package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
- package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
- package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
- package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
- package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
- package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
- package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
- /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → JUBX5FUR73jiViQU5a-Cx}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → JUBX5FUR73jiViQU5a-Cx}/_ssgManifest.js +0 -0
|
@@ -13,6 +13,7 @@ import { runUnit } from "./run-unit.js";
|
|
|
13
13
|
import { debugLog } from "../debug-logger.js";
|
|
14
14
|
import { gsdRoot } from "../paths.js";
|
|
15
15
|
import { atomicWriteSync } from "../atomic-write.js";
|
|
16
|
+
import { PROJECT_FILES } from "../detection.js";
|
|
16
17
|
import { join } from "node:path";
|
|
17
18
|
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
18
19
|
/**
|
|
@@ -121,6 +122,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
121
122
|
});
|
|
122
123
|
// ── Milestone transition ────────────────────────────────────────────
|
|
123
124
|
if (mid && s.currentMilestoneId && mid !== s.currentMilestoneId) {
|
|
125
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "milestone-transition", data: { from: s.currentMilestoneId, to: mid } });
|
|
124
126
|
ctx.ui.notify(`Milestone ${s.currentMilestoneId} complete. Advancing to ${mid}: ${midTitle}.`, "info");
|
|
125
127
|
deps.sendDesktopNotification("GSD", `Milestone ${s.currentMilestoneId} complete!`, "success", "milestone");
|
|
126
128
|
deps.logCmuxEvent(prefs, `Milestone ${s.currentMilestoneId} complete. Advancing to ${mid}.`, "success");
|
|
@@ -248,6 +250,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
248
250
|
await deps.stopAuto(ctx, pi, `No active milestone — ${incomplete.length} incomplete (${ids}), see diagnostic above`);
|
|
249
251
|
}
|
|
250
252
|
debugLog("autoLoop", { phase: "exit", reason: "no-active-milestone" });
|
|
253
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "no-active-milestone" } });
|
|
251
254
|
return { action: "break", reason: "no-active-milestone" };
|
|
252
255
|
}
|
|
253
256
|
if (!midTitle) {
|
|
@@ -295,6 +298,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
295
298
|
deps.logCmuxEvent(prefs, `Milestone ${mid} complete.`, "success");
|
|
296
299
|
await closeoutAndStop(ctx, pi, s, deps, `Milestone ${mid} complete`);
|
|
297
300
|
debugLog("autoLoop", { phase: "exit", reason: "milestone-complete" });
|
|
301
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "milestone-complete", milestoneId: mid } });
|
|
298
302
|
return { action: "break", reason: "milestone-complete" };
|
|
299
303
|
}
|
|
300
304
|
// Terminal: blocked
|
|
@@ -305,6 +309,7 @@ export async function runPreDispatch(ic, loopState) {
|
|
|
305
309
|
deps.sendDesktopNotification("GSD", blockerMsg, "error", "attention");
|
|
306
310
|
deps.logCmuxEvent(prefs, blockerMsg, "error");
|
|
307
311
|
debugLog("autoLoop", { phase: "exit", reason: "blocked" });
|
|
312
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "terminal", data: { reason: "blocked", blockers: state.blockers } });
|
|
308
313
|
return { action: "break", reason: "blocked" };
|
|
309
314
|
}
|
|
310
315
|
return { action: "next", data: { state, mid, midTitle } };
|
|
@@ -328,6 +333,7 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
328
333
|
session: s,
|
|
329
334
|
});
|
|
330
335
|
if (dispatchResult.action === "stop") {
|
|
336
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "dispatch-stop", rule: dispatchResult.matchedRule, data: { reason: dispatchResult.reason } });
|
|
331
337
|
await closeoutAndStop(ctx, pi, s, deps, dispatchResult.reason);
|
|
332
338
|
debugLog("autoLoop", { phase: "exit", reason: "dispatch-stop" });
|
|
333
339
|
return { action: "break", reason: "dispatch-stop" };
|
|
@@ -337,6 +343,7 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
337
343
|
await new Promise((r) => setImmediate(r));
|
|
338
344
|
return { action: "continue" };
|
|
339
345
|
}
|
|
346
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "dispatch-match", rule: dispatchResult.matchedRule, data: { unitType: dispatchResult.unitType, unitId: dispatchResult.unitId } });
|
|
340
347
|
let unitType = dispatchResult.unitType;
|
|
341
348
|
let unitId = dispatchResult.unitId;
|
|
342
349
|
let prompt = dispatchResult.prompt;
|
|
@@ -402,6 +409,7 @@ export async function runDispatch(ic, preData, loopState) {
|
|
|
402
409
|
const preDispatchResult = deps.runPreDispatchHooks(unitType, unitId, prompt, s.basePath);
|
|
403
410
|
if (preDispatchResult.firedHooks.length > 0) {
|
|
404
411
|
ctx.ui.notify(`Pre-dispatch hook${preDispatchResult.firedHooks.length > 1 ? "s" : ""}: ${preDispatchResult.firedHooks.join(", ")}`, "info");
|
|
412
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "pre-dispatch-hook", data: { firedHooks: preDispatchResult.firedHooks, action: preDispatchResult.action } });
|
|
405
413
|
}
|
|
406
414
|
if (preDispatchResult.action === "skip") {
|
|
407
415
|
ctx.ui.notify(`Skipping ${unitType} ${unitId} (pre-dispatch hook).`, "info");
|
|
@@ -544,25 +552,27 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
544
552
|
unitType,
|
|
545
553
|
unitId,
|
|
546
554
|
});
|
|
547
|
-
// ── Worktree health check (#1833)
|
|
555
|
+
// ── Worktree health check (#1833, #1843) ────────────────────────────
|
|
548
556
|
// Verify the working directory is a valid git checkout with project
|
|
549
557
|
// files before dispatching work. A broken worktree causes agents to
|
|
550
558
|
// hallucinate summaries since they cannot read or write any files.
|
|
559
|
+
// Uses the shared PROJECT_FILES list from detection.ts to support all
|
|
560
|
+
// ecosystems (Rust, Go, Python, Java, etc.), not just JS.
|
|
551
561
|
if (s.basePath && unitType === "execute-task") {
|
|
552
562
|
const gitMarker = join(s.basePath, ".git");
|
|
553
563
|
const hasGit = deps.existsSync(gitMarker);
|
|
554
|
-
const hasPackageJson = deps.existsSync(join(s.basePath, "package.json"));
|
|
555
|
-
const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
|
|
556
564
|
if (!hasGit) {
|
|
557
565
|
const msg = `Worktree health check failed: ${s.basePath} has no .git — refusing to dispatch ${unitType} ${unitId}`;
|
|
558
|
-
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasGit
|
|
566
|
+
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasGit });
|
|
559
567
|
ctx.ui.notify(msg, "error");
|
|
560
568
|
await deps.stopAuto(ctx, pi, msg);
|
|
561
569
|
return { action: "break", reason: "worktree-invalid" };
|
|
562
570
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
571
|
+
const hasProjectFile = PROJECT_FILES.some((f) => deps.existsSync(join(s.basePath, f)));
|
|
572
|
+
const hasSrcDir = deps.existsSync(join(s.basePath, "src"));
|
|
573
|
+
if (!hasProjectFile && !hasSrcDir) {
|
|
574
|
+
const msg = `Worktree health check failed: ${s.basePath} has no recognized project files — refusing to dispatch ${unitType} ${unitId}`;
|
|
575
|
+
debugLog("runUnitPhase", { phase: "worktree-health-fail", basePath: s.basePath, hasProjectFile, hasSrcDir });
|
|
566
576
|
ctx.ui.notify(msg, "error");
|
|
567
577
|
await deps.stopAuto(ctx, pi, msg);
|
|
568
578
|
return { action: "break", reason: "worktree-invalid" };
|
|
@@ -574,6 +584,8 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
574
584
|
s.currentUnit.id === unitId);
|
|
575
585
|
const previousTier = s.currentUnitRouting?.tier;
|
|
576
586
|
s.currentUnit = { type: unitType, id: unitId, startedAt: Date.now() };
|
|
587
|
+
const unitStartSeq = ic.nextSeq();
|
|
588
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: unitStartSeq, eventType: "unit-start", data: { unitType, unitId } });
|
|
577
589
|
deps.captureAvailableSkills();
|
|
578
590
|
deps.writeUnitRuntimeRecord(s.basePath, unitType, unitId, s.currentUnit.startedAt, {
|
|
579
591
|
phase: "dispatched",
|
|
@@ -683,7 +695,12 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
683
695
|
unitId,
|
|
684
696
|
prefs,
|
|
685
697
|
buildSnapshotOpts: () => deps.buildSnapshotOpts(unitType, unitId),
|
|
686
|
-
buildRecoveryContext: () => ({
|
|
698
|
+
buildRecoveryContext: () => ({
|
|
699
|
+
basePath: s.basePath,
|
|
700
|
+
verbose: s.verbose,
|
|
701
|
+
currentUnitStartedAt: s.currentUnit?.startedAt ?? Date.now(),
|
|
702
|
+
unitRecoveryCount: s.unitRecoveryCount,
|
|
703
|
+
}),
|
|
687
704
|
pauseAuto: deps.pauseAuto,
|
|
688
705
|
});
|
|
689
706
|
// Write preliminary lock (no session path yet — runUnit creates a new session).
|
|
@@ -759,8 +776,8 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
759
776
|
if (s.currentUnitRouting) {
|
|
760
777
|
deps.recordOutcome(unitType, s.currentUnitRouting.tier, true);
|
|
761
778
|
}
|
|
762
|
-
const
|
|
763
|
-
const artifactVerified =
|
|
779
|
+
const skipArtifactVerification = unitType.startsWith("hook/") || unitType === "custom-step";
|
|
780
|
+
const artifactVerified = skipArtifactVerification ||
|
|
764
781
|
deps.verifyExpectedArtifact(unitType, unitId, s.basePath);
|
|
765
782
|
if (artifactVerified) {
|
|
766
783
|
s.completedUnits.push({
|
|
@@ -783,6 +800,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|
|
783
800
|
s.unitDispatchCount.delete(`${unitType}/${unitId}`);
|
|
784
801
|
s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
|
|
785
802
|
}
|
|
803
|
+
deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
|
|
786
804
|
return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
|
|
787
805
|
}
|
|
788
806
|
// ─── runFinalize ──────────────────────────────────────────────────────────────
|
|
@@ -27,6 +27,8 @@ export class AutoSession {
|
|
|
27
27
|
paused = false;
|
|
28
28
|
stepMode = false;
|
|
29
29
|
verbose = false;
|
|
30
|
+
activeEngineId = null;
|
|
31
|
+
activeRunDir = null;
|
|
30
32
|
cmdCtx = null;
|
|
31
33
|
// ── Paths ────────────────────────────────────────────────────────────────
|
|
32
34
|
basePath = "";
|
|
@@ -113,6 +115,8 @@ export class AutoSession {
|
|
|
113
115
|
this.paused = false;
|
|
114
116
|
this.stepMode = false;
|
|
115
117
|
this.verbose = false;
|
|
118
|
+
this.activeEngineId = null;
|
|
119
|
+
this.activeRunDir = null;
|
|
116
120
|
this.cmdCtx = null;
|
|
117
121
|
// Paths
|
|
118
122
|
this.basePath = "";
|
|
@@ -156,6 +160,8 @@ export class AutoSession {
|
|
|
156
160
|
paused: this.paused,
|
|
157
161
|
stepMode: this.stepMode,
|
|
158
162
|
basePath: this.basePath,
|
|
163
|
+
activeEngineId: this.activeEngineId,
|
|
164
|
+
activeRunDir: this.activeRunDir,
|
|
159
165
|
currentMilestoneId: this.currentMilestoneId,
|
|
160
166
|
currentUnit: this.currentUnit,
|
|
161
167
|
completedUnits: this.completedUnits.length,
|
|
@@ -18,6 +18,7 @@ import { GLYPH, INDENT } from "../shared/mod.js";
|
|
|
18
18
|
import { computeProgressScore } from "./progress-score.js";
|
|
19
19
|
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
20
20
|
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
21
|
+
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
21
22
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
22
23
|
/**
|
|
23
24
|
* Extract the target slice ID from a run-uat unit ID (e.g. "M001/S01" → "S01").
|
|
@@ -45,6 +46,7 @@ export function unitVerb(unitType) {
|
|
|
45
46
|
case "rewrite-docs": return "rewriting";
|
|
46
47
|
case "reassess-roadmap": return "reassessing";
|
|
47
48
|
case "run-uat": return "running UAT";
|
|
49
|
+
case "custom-step": return "executing workflow step";
|
|
48
50
|
default: return unitType;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -63,6 +65,7 @@ export function unitPhaseLabel(unitType) {
|
|
|
63
65
|
case "rewrite-docs": return "REWRITE";
|
|
64
66
|
case "reassess-roadmap": return "REASSESS";
|
|
65
67
|
case "run-uat": return "UAT";
|
|
68
|
+
case "custom-step": return "WORKFLOW";
|
|
66
69
|
default: return unitType.toUpperCase();
|
|
67
70
|
}
|
|
68
71
|
}
|
|
@@ -370,6 +373,8 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
370
373
|
}
|
|
371
374
|
// Pre-fetch last commit for display
|
|
372
375
|
refreshLastCommit(accessors.getBasePath());
|
|
376
|
+
// Cache the effective service tier at widget creation time (reads preferences)
|
|
377
|
+
const effectiveServiceTier = getEffectiveServiceTier();
|
|
373
378
|
ctx.ui.setWidget("gsd-progress", (tui, theme) => {
|
|
374
379
|
let pulseBright = true;
|
|
375
380
|
let cachedLines;
|
|
@@ -471,9 +476,10 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
471
476
|
// Model display — shown in context section, not stats
|
|
472
477
|
const modelId = cmdCtx?.model?.id ?? "";
|
|
473
478
|
const modelProvider = cmdCtx?.model?.provider ?? "";
|
|
474
|
-
const
|
|
479
|
+
const tierIcon = resolveServiceTierIcon(effectiveServiceTier, modelId);
|
|
480
|
+
const modelDisplay = (modelProvider && modelId
|
|
475
481
|
? `${modelProvider}/${modelId}`
|
|
476
|
-
: modelId;
|
|
482
|
+
: modelId) + (tierIcon ? ` ${tierIcon}` : "");
|
|
477
483
|
// ── Mode: off — return empty ──────────────────────────────────
|
|
478
484
|
if (widgetMode === "off") {
|
|
479
485
|
cachedLines = [];
|
|
@@ -24,7 +24,7 @@ function missingSliceStop(mid, phase) {
|
|
|
24
24
|
// ─── Rewrite Circuit Breaker ──────────────────────────────────────────────
|
|
25
25
|
const MAX_REWRITE_ATTEMPTS = 3;
|
|
26
26
|
// ─── Rules ────────────────────────────────────────────────────────────────
|
|
27
|
-
const DISPATCH_RULES = [
|
|
27
|
+
export const DISPATCH_RULES = [
|
|
28
28
|
{
|
|
29
29
|
name: "rewrite-docs (override gate)",
|
|
30
30
|
match: async ({ mid, midTitle, state, basePath, session }) => {
|
|
@@ -480,22 +480,39 @@ const DISPATCH_RULES = [
|
|
|
480
480
|
},
|
|
481
481
|
},
|
|
482
482
|
];
|
|
483
|
+
import { getRegistry } from "./rule-registry.js";
|
|
483
484
|
// ─── Resolver ─────────────────────────────────────────────────────────────
|
|
484
485
|
/**
|
|
485
486
|
* Evaluate dispatch rules in order. Returns the first matching action,
|
|
486
487
|
* or a "stop" action if no rule matches (unhandled phase).
|
|
488
|
+
*
|
|
489
|
+
* Delegates to the RuleRegistry when initialized; falls back to inline
|
|
490
|
+
* loop over DISPATCH_RULES for backward compatibility (tests that import
|
|
491
|
+
* resolveDispatch directly without registry initialization).
|
|
487
492
|
*/
|
|
488
493
|
export async function resolveDispatch(ctx) {
|
|
494
|
+
// Delegate to registry when available
|
|
495
|
+
try {
|
|
496
|
+
const registry = getRegistry();
|
|
497
|
+
return await registry.evaluateDispatch(ctx);
|
|
498
|
+
}
|
|
499
|
+
catch {
|
|
500
|
+
// Registry not initialized — fall back to inline loop
|
|
501
|
+
}
|
|
489
502
|
for (const rule of DISPATCH_RULES) {
|
|
490
503
|
const result = await rule.match(ctx);
|
|
491
|
-
if (result)
|
|
504
|
+
if (result) {
|
|
505
|
+
if (result.action !== "skip")
|
|
506
|
+
result.matchedRule = rule.name;
|
|
492
507
|
return result;
|
|
508
|
+
}
|
|
493
509
|
}
|
|
494
510
|
// No rule matched — unhandled phase
|
|
495
511
|
return {
|
|
496
512
|
action: "stop",
|
|
497
513
|
reason: `Unhandled phase "${ctx.state.phase}" — run /gsd doctor to diagnose.`,
|
|
498
514
|
level: "info",
|
|
515
|
+
matchedRule: "<no-match>",
|
|
499
516
|
};
|
|
500
517
|
}
|
|
501
518
|
/** Exposed for testing — returns the rule names in evaluation order. */
|
|
@@ -31,6 +31,7 @@ import { existsSync, unlinkSync } from "node:fs";
|
|
|
31
31
|
import { join } from "node:path";
|
|
32
32
|
import { uncheckTaskInPlan } from "./undo.js";
|
|
33
33
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
34
|
+
import { _resetHasChangesCache } from "./native-git-bridge.js";
|
|
34
35
|
/** Throttle STATE.md rebuilds — at most once per 30 seconds */
|
|
35
36
|
const STATE_REBUILD_MIN_INTERVAL_MS = 30_000;
|
|
36
37
|
/**
|
|
@@ -103,6 +104,12 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
107
|
+
// Invalidate the nativeHasChanges cache before auto-commit (#1853).
|
|
108
|
+
// The cache has a 10-second TTL and is keyed by basePath. A stale
|
|
109
|
+
// `false` result causes autoCommit to skip staging entirely, leaving
|
|
110
|
+
// code files only in the working tree where they are destroyed by
|
|
111
|
+
// `git worktree remove --force` during teardown.
|
|
112
|
+
_resetHasChangesCache();
|
|
106
113
|
const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
|
|
107
114
|
if (commitMsg) {
|
|
108
115
|
ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
|
|
@@ -849,7 +849,7 @@ export async function buildPlanSlicePrompt(mid, _midTitle, sid, sTitle, base, le
|
|
|
849
849
|
const prefs = loadEffectiveGSDPreferences();
|
|
850
850
|
const commitDocsEnabled = prefs?.preferences?.git?.commit_docs !== false;
|
|
851
851
|
const commitInstruction = commitDocsEnabled
|
|
852
|
-
? `Commit the plan files only: \`git add ${relSlicePath(base, mid, sid)}/ .gsd/DECISIONS.md .gitignore && git commit -m "docs(${sid}): add slice plan"\`. Do not stage .gsd/STATE.md or other runtime files — the system manages those.`
|
|
852
|
+
? `Commit the plan files only: \`git add --force ${relSlicePath(base, mid, sid)}/ .gsd/DECISIONS.md .gitignore && git commit -m "docs(${sid}): add slice plan"\`. Do not stage .gsd/STATE.md or other runtime files — the system manages those.`
|
|
853
853
|
: "Do not commit — planning docs are not tracked in git for this project.";
|
|
854
854
|
return loadPrompt("plan-slice", {
|
|
855
855
|
workingDirectory: base,
|
|
@@ -263,10 +263,15 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
263
263
|
// plan has no tasks, creating an infinite skip loop (#699).
|
|
264
264
|
if (unitType === "plan-slice") {
|
|
265
265
|
const planContent = readFileSync(absPath, "utf-8");
|
|
266
|
-
|
|
266
|
+
// Accept checkbox-style (- [x] **T01: ...) or heading-style (### T01 -- / ### T01: / ### T01 —)
|
|
267
|
+
const hasCheckboxTask = /^- \[[xX ]\] \*\*T\d+:/m.test(planContent);
|
|
268
|
+
const hasHeadingTask = /^#{2,4}\s+T\d+\s*(?:--|—|:)/m.test(planContent);
|
|
269
|
+
if (!hasCheckboxTask && !hasHeadingTask)
|
|
267
270
|
return false;
|
|
268
271
|
}
|
|
269
|
-
// execute-task must also have its checkbox marked [x] in the slice plan
|
|
272
|
+
// execute-task must also have its checkbox marked [x] in the slice plan.
|
|
273
|
+
// Heading-style plans (### T01 -- Title) have no checkbox — the task summary
|
|
274
|
+
// file existence (checked above via resolveExpectedArtifactPath) is sufficient.
|
|
270
275
|
if (unitType === "execute-task") {
|
|
271
276
|
const parts = unitId.split("/");
|
|
272
277
|
const mid = parts[0];
|
|
@@ -277,8 +282,11 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|
|
277
282
|
if (planAbs && existsSync(planAbs)) {
|
|
278
283
|
const planContent = readFileSync(planAbs, "utf-8");
|
|
279
284
|
const escapedTid = tid.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
280
|
-
const
|
|
281
|
-
|
|
285
|
+
const cbRe = new RegExp(`^- \\[[xX]\\] \\*\\*${escapedTid}:`, "m");
|
|
286
|
+
const hdRe = new RegExp(`^#{2,4}\\s+${escapedTid}\\s*(?:--|—|:)`, "m");
|
|
287
|
+
// Heading-style entries count as verified (no checkbox to toggle);
|
|
288
|
+
// checkbox-style entries require [x].
|
|
289
|
+
if (!cbRe.test(planContent) && !hdRe.test(planContent))
|
|
282
290
|
return false;
|
|
283
291
|
}
|
|
284
292
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { deriveState } from "./state.js";
|
|
12
12
|
import { loadFile, getManifestStatus } from "./files.js";
|
|
13
13
|
import { loadEffectiveGSDPreferences, resolveSkillDiscoveryMode, getIsolationMode, } from "./preferences.js";
|
|
14
|
-
import { ensureGsdSymlink, validateProjectId } from "./repo-identity.js";
|
|
14
|
+
import { ensureGsdSymlink, isInheritedRepo, validateProjectId } from "./repo-identity.js";
|
|
15
15
|
import { migrateToExternalState, recoverFailedMigration } from "./migrate-external.js";
|
|
16
16
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
17
17
|
import { gsdRoot, resolveMilestoneFile } from "./paths.js";
|
|
@@ -69,8 +69,13 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
69
69
|
ctx.ui.notify(`GSD_PROJECT_ID must contain only alphanumeric characters, hyphens, and underscores. Got: "${customProjectId}"`, "error");
|
|
70
70
|
return releaseLockAndReturn();
|
|
71
71
|
}
|
|
72
|
-
// Ensure git repo exists
|
|
73
|
-
if
|
|
72
|
+
// Ensure git repo exists.
|
|
73
|
+
// Guard against inherited repos: if `base` is a subdirectory of another
|
|
74
|
+
// git repo that has no .gsd (i.e. the parent project was never initialised
|
|
75
|
+
// with GSD), create a fresh git repo at `base` so it gets its own identity
|
|
76
|
+
// hash. Without this, repoIdentity() resolves to the parent repo's hash
|
|
77
|
+
// and loads milestones from an unrelated project (#1639).
|
|
78
|
+
if (!nativeIsRepo(base) || isInheritedRepo(base)) {
|
|
74
79
|
const mainBranch = loadEffectiveGSDPreferences()?.preferences?.git?.main_branch || "main";
|
|
75
80
|
nativeInit(base, mainBranch);
|
|
76
81
|
}
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
* manual `/worktree` which uses `worktree/<name>` branches). This module
|
|
6
6
|
* manages create, enter, detect, and teardown for auto-mode worktrees.
|
|
7
7
|
*/
|
|
8
|
-
import { existsSync, cpSync, readFileSync, readdirSync, mkdirSync, realpathSync, unlinkSync, lstatSync as lstatSyncFn, } from "node:fs";
|
|
8
|
+
import { existsSync, cpSync, readFileSync, readdirSync, mkdirSync, realpathSync, rmSync, unlinkSync, lstatSync as lstatSyncFn, } from "node:fs";
|
|
9
9
|
import { isAbsolute, join } from "node:path";
|
|
10
10
|
import { GSDError, GSD_IO_ERROR, GSD_GIT_ERROR } from "./errors.js";
|
|
11
11
|
import { copyWorktreeDb, reconcileWorktreeDb, isDbAvailable, } from "./gsd-db.js";
|
|
12
12
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
13
|
-
import {
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
14
14
|
import { safeCopy, safeCopyRecursive } from "./safe-fs.js";
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
16
|
-
import { createWorktree, removeWorktree, worktreePath, } from "./worktree-manager.js";
|
|
16
|
+
import { createWorktree, removeWorktree, resolveGitDir, worktreePath, } from "./worktree-manager.js";
|
|
17
17
|
import { detectWorktreeName, nudgeGitBranchCache, } from "./worktree.js";
|
|
18
18
|
import { MergeConflictError, readIntegrationBranch, RUNTIME_EXCLUSION_PATHS } from "./git-service.js";
|
|
19
19
|
import { debugLog } from "./debug-logger.js";
|
|
20
20
|
import { parseRoadmap } from "./files.js";
|
|
21
21
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
22
|
-
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeCheckoutTheirs, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchExists, nativeDiffNumstat, } from "./native-git-bridge.js";
|
|
22
|
+
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeWorkingTreeStatus, nativeAddAllWithExclusions, nativeCommit, nativeCheckoutBranch, nativeMergeSquash, nativeConflictFiles, nativeCheckoutTheirs, nativeAddPaths, nativeRmForce, nativeBranchDelete, nativeBranchExists, nativeDiffNumstat, nativeUpdateRef, nativeIsAncestor, } from "./native-git-bridge.js";
|
|
23
23
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
24
24
|
/** Original project root before chdir into auto-worktree. */
|
|
25
25
|
let originalBase = null;
|
|
@@ -133,7 +133,7 @@ export function syncGsdStateToWorktree(mainBasePath, worktreePath_) {
|
|
|
133
133
|
const mainMilestones = readdirSync(mainMilestonesDir, {
|
|
134
134
|
withFileTypes: true,
|
|
135
135
|
})
|
|
136
|
-
.filter((d) => d.isDirectory()
|
|
136
|
+
.filter((d) => d.isDirectory())
|
|
137
137
|
.map((d) => d.name);
|
|
138
138
|
for (const mid of mainMilestones) {
|
|
139
139
|
const srcDir = join(mainMilestonesDir, mid);
|
|
@@ -287,7 +287,7 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|
|
287
287
|
return { synced };
|
|
288
288
|
try {
|
|
289
289
|
const wtMilestones = readdirSync(wtMilestonesDir, { withFileTypes: true })
|
|
290
|
-
.filter((d) => d.isDirectory()
|
|
290
|
+
.filter((d) => d.isDirectory())
|
|
291
291
|
.map((d) => d.name);
|
|
292
292
|
for (const mid of wtMilestones) {
|
|
293
293
|
syncMilestoneDir(wtGsd, mainGsd, mid, synced);
|
|
@@ -405,13 +405,24 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|
|
405
405
|
}
|
|
406
406
|
if (!hookPath)
|
|
407
407
|
return null;
|
|
408
|
-
// Resolve relative paths against the source project root
|
|
409
|
-
|
|
408
|
+
// Resolve relative paths against the source project root.
|
|
409
|
+
// On Windows, convert 8.3 short paths (e.g. RUNNER~1) to long paths
|
|
410
|
+
// so execFileSync can locate the file correctly.
|
|
411
|
+
let resolved = isAbsolute(hookPath) ? hookPath : join(sourceDir, hookPath);
|
|
410
412
|
if (!existsSync(resolved)) {
|
|
411
413
|
return `Worktree post-create hook not found: ${resolved}`;
|
|
412
414
|
}
|
|
415
|
+
if (process.platform === "win32") {
|
|
416
|
+
try {
|
|
417
|
+
resolved = realpathSync.native(resolved);
|
|
418
|
+
}
|
|
419
|
+
catch { /* keep original */ }
|
|
420
|
+
}
|
|
413
421
|
try {
|
|
414
|
-
|
|
422
|
+
// .bat/.cmd files on Windows require shell mode — execFileSync cannot
|
|
423
|
+
// spawn them directly (EINVAL).
|
|
424
|
+
const needsShell = process.platform === "win32" && /\.(bat|cmd)$/i.test(resolved);
|
|
425
|
+
execFileSync(resolved, [], {
|
|
415
426
|
cwd: worktreeDir,
|
|
416
427
|
env: {
|
|
417
428
|
...process.env,
|
|
@@ -421,6 +432,7 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|
|
421
432
|
stdio: ["ignore", "pipe", "pipe"],
|
|
422
433
|
encoding: "utf-8",
|
|
423
434
|
timeout: 30_000, // 30 second timeout
|
|
435
|
+
shell: needsShell,
|
|
424
436
|
});
|
|
425
437
|
return null;
|
|
426
438
|
}
|
|
@@ -661,6 +673,22 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
661
673
|
branch,
|
|
662
674
|
deleteBranch: !preserveBranch,
|
|
663
675
|
});
|
|
676
|
+
// Verify cleanup succeeded — warn if the worktree directory is still on disk.
|
|
677
|
+
// On Windows, bash-based cleanup can silently fail when paths contain
|
|
678
|
+
// backslashes (#1436), leaving ~1 GB+ orphaned directories.
|
|
679
|
+
const wtDir = worktreePath(originalBasePath, milestoneId);
|
|
680
|
+
if (existsSync(wtDir)) {
|
|
681
|
+
console.error(`[GSD] WARNING: Worktree directory still exists after teardown: ${wtDir}\n` +
|
|
682
|
+
` This is likely an orphaned directory consuming disk space.\n` +
|
|
683
|
+
` Remove it manually with: rm -rf "${wtDir.replaceAll("\\", "/")}"`);
|
|
684
|
+
// Attempt a direct filesystem removal as a fallback
|
|
685
|
+
try {
|
|
686
|
+
rmSync(wtDir, { recursive: true, force: true });
|
|
687
|
+
}
|
|
688
|
+
catch {
|
|
689
|
+
// Non-fatal — the warning above tells the user how to clean up
|
|
690
|
+
}
|
|
691
|
+
}
|
|
664
692
|
}
|
|
665
693
|
/**
|
|
666
694
|
* Detect if the process is currently inside an auto-worktree.
|
|
@@ -858,6 +886,56 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
858
886
|
body = `\n\nCompleted slices:\n${sliceLines}\n\nBranch: ${milestoneBranch}`;
|
|
859
887
|
}
|
|
860
888
|
const commitMessage = subject + body;
|
|
889
|
+
// 6b. Reconcile worktree HEAD with milestone branch ref (#1846).
|
|
890
|
+
// When the worktree HEAD detaches and advances past the named branch,
|
|
891
|
+
// the branch ref becomes stale. Squash-merging the stale ref silently
|
|
892
|
+
// orphans all commits between the branch ref and the actual worktree HEAD.
|
|
893
|
+
// Fix: fast-forward the branch ref to the worktree HEAD before merging.
|
|
894
|
+
// Only applies when merging from an actual worktree (worktreeCwd differs
|
|
895
|
+
// from originalBasePath_).
|
|
896
|
+
if (worktreeCwd !== originalBasePath_) {
|
|
897
|
+
try {
|
|
898
|
+
const worktreeHead = execFileSync("git", ["rev-parse", "HEAD"], {
|
|
899
|
+
cwd: worktreeCwd,
|
|
900
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
901
|
+
encoding: "utf-8",
|
|
902
|
+
}).trim();
|
|
903
|
+
const branchHead = execFileSync("git", ["rev-parse", milestoneBranch], {
|
|
904
|
+
cwd: originalBasePath_,
|
|
905
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
906
|
+
encoding: "utf-8",
|
|
907
|
+
}).trim();
|
|
908
|
+
if (worktreeHead && branchHead && worktreeHead !== branchHead) {
|
|
909
|
+
if (nativeIsAncestor(originalBasePath_, branchHead, worktreeHead)) {
|
|
910
|
+
// Worktree HEAD is strictly ahead — fast-forward the branch ref
|
|
911
|
+
nativeUpdateRef(originalBasePath_, `refs/heads/${milestoneBranch}`, worktreeHead);
|
|
912
|
+
debugLog("mergeMilestoneToMain", {
|
|
913
|
+
action: "fast-forward-branch-ref",
|
|
914
|
+
milestoneBranch,
|
|
915
|
+
oldRef: branchHead.slice(0, 8),
|
|
916
|
+
newRef: worktreeHead.slice(0, 8),
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
// Diverged — fail loudly rather than silently losing commits
|
|
921
|
+
process.chdir(previousCwd);
|
|
922
|
+
throw new GSDError(GSD_GIT_ERROR, `Worktree HEAD (${worktreeHead.slice(0, 8)}) diverged from ` +
|
|
923
|
+
`${milestoneBranch} (${branchHead.slice(0, 8)}). ` +
|
|
924
|
+
`Manual reconciliation required before merge.`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
catch (err) {
|
|
929
|
+
// Re-throw GSDError (divergence); swallow rev-parse failures
|
|
930
|
+
// (e.g. worktree dir already removed by external cleanup)
|
|
931
|
+
if (err instanceof GSDError)
|
|
932
|
+
throw err;
|
|
933
|
+
debugLog("mergeMilestoneToMain", {
|
|
934
|
+
action: "reconcile-skipped",
|
|
935
|
+
reason: String(err),
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
}
|
|
861
939
|
// 7. Squash merge — auto-resolve .gsd/ state file conflicts (#530)
|
|
862
940
|
const mergeResult = nativeMergeSquash(originalBasePath_, milestoneBranch);
|
|
863
941
|
if (!mergeResult.success) {
|
|
@@ -905,6 +983,17 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
905
983
|
// 8. Commit (handle nothing-to-commit gracefully)
|
|
906
984
|
const commitResult = nativeCommit(originalBasePath_, commitMessage);
|
|
907
985
|
const nothingToCommit = commitResult === null;
|
|
986
|
+
// 8a. Clean up SQUASH_MSG left by git merge --squash (#1853).
|
|
987
|
+
// git only removes SQUASH_MSG when the commit reads it directly (plain
|
|
988
|
+
// `git commit`). nativeCommit uses `-F -` (stdin) or libgit2, neither
|
|
989
|
+
// of which trigger git's SQUASH_MSG cleanup. If left on disk, doctor
|
|
990
|
+
// reports `corrupt_merge_state` on every subsequent run.
|
|
991
|
+
try {
|
|
992
|
+
const squashMsgPath = join(resolveGitDir(originalBasePath_), "SQUASH_MSG");
|
|
993
|
+
if (existsSync(squashMsgPath))
|
|
994
|
+
unlinkSync(squashMsgPath);
|
|
995
|
+
}
|
|
996
|
+
catch { /* best-effort */ }
|
|
908
997
|
// 8b. Safety check (#1792): if nothing was committed, verify the milestone
|
|
909
998
|
// work is already on the integration branch before allowing teardown.
|
|
910
999
|
// Compare only non-.gsd/ paths — .gsd/ state files diverge normally and
|
|
@@ -920,12 +1009,27 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
920
1009
|
`Aborting worktree teardown to prevent data loss.`);
|
|
921
1010
|
}
|
|
922
1011
|
}
|
|
1012
|
+
// 8c. Detect whether any non-.gsd/ code files were actually merged (#1906).
|
|
1013
|
+
// When a milestone only produced .gsd/ metadata (summaries, roadmaps) but no
|
|
1014
|
+
// real code, the user sees "milestone complete" but nothing changed in their
|
|
1015
|
+
// codebase. Surface this so the caller can warn the user.
|
|
1016
|
+
let codeFilesChanged = false;
|
|
1017
|
+
if (!nothingToCommit) {
|
|
1018
|
+
try {
|
|
1019
|
+
const mergedFiles = nativeDiffNumstat(originalBasePath_, "HEAD~1", "HEAD");
|
|
1020
|
+
codeFilesChanged = mergedFiles.some((entry) => !entry.path.startsWith(".gsd/"));
|
|
1021
|
+
}
|
|
1022
|
+
catch {
|
|
1023
|
+
// If HEAD~1 doesn't exist (first commit), assume code was changed
|
|
1024
|
+
codeFilesChanged = true;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
923
1027
|
// 9. Auto-push if enabled
|
|
924
1028
|
let pushed = false;
|
|
925
1029
|
if (prefs.auto_push === true && !nothingToCommit) {
|
|
926
1030
|
const remote = prefs.remote ?? "origin";
|
|
927
1031
|
try {
|
|
928
|
-
|
|
1032
|
+
execFileSync("git", ["push", remote, mainBranch], {
|
|
929
1033
|
cwd: originalBasePath_,
|
|
930
1034
|
stdio: ["ignore", "pipe", "pipe"],
|
|
931
1035
|
encoding: "utf-8",
|
|
@@ -943,13 +1047,19 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
943
1047
|
const prTarget = prefs.pr_target_branch ?? mainBranch;
|
|
944
1048
|
try {
|
|
945
1049
|
// Push the milestone branch to remote first
|
|
946
|
-
|
|
1050
|
+
execFileSync("git", ["push", remote, milestoneBranch], {
|
|
947
1051
|
cwd: originalBasePath_,
|
|
948
1052
|
stdio: ["ignore", "pipe", "pipe"],
|
|
949
1053
|
encoding: "utf-8",
|
|
950
1054
|
});
|
|
951
1055
|
// Create PR via gh CLI
|
|
952
|
-
|
|
1056
|
+
execFileSync("gh", [
|
|
1057
|
+
"pr", "create",
|
|
1058
|
+
"--base", prTarget,
|
|
1059
|
+
"--head", milestoneBranch,
|
|
1060
|
+
"--title", `Milestone ${milestoneId} complete`,
|
|
1061
|
+
"--body", "Auto-created by GSD on milestone completion.",
|
|
1062
|
+
], {
|
|
953
1063
|
cwd: originalBasePath_,
|
|
954
1064
|
stdio: ["ignore", "pipe", "pipe"],
|
|
955
1065
|
encoding: "utf-8",
|
|
@@ -963,6 +1073,30 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
963
1073
|
// 10. Guard removed — step 8b (#1792) now handles this with a smarter check:
|
|
964
1074
|
// throws only when the milestone has unanchored code changes, passes
|
|
965
1075
|
// through when the code is genuinely already on the integration branch.
|
|
1076
|
+
// 10a. Pre-teardown safety net (#1853): if the worktree still has uncommitted
|
|
1077
|
+
// changes (e.g. nativeHasChanges cache returned stale false, or auto-commit
|
|
1078
|
+
// silently failed), force one final commit so code is not destroyed by
|
|
1079
|
+
// `git worktree remove --force`.
|
|
1080
|
+
if (existsSync(worktreeCwd)) {
|
|
1081
|
+
try {
|
|
1082
|
+
const dirtyCheck = nativeWorkingTreeStatus(worktreeCwd);
|
|
1083
|
+
if (dirtyCheck) {
|
|
1084
|
+
debugLog("mergeMilestoneToMain", {
|
|
1085
|
+
phase: "pre-teardown-dirty",
|
|
1086
|
+
worktreeCwd,
|
|
1087
|
+
status: dirtyCheck.slice(0, 200),
|
|
1088
|
+
});
|
|
1089
|
+
nativeAddAllWithExclusions(worktreeCwd, RUNTIME_EXCLUSION_PATHS);
|
|
1090
|
+
nativeCommit(worktreeCwd, "chore: pre-teardown auto-commit of uncommitted worktree changes");
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
catch (e) {
|
|
1094
|
+
debugLog("mergeMilestoneToMain", {
|
|
1095
|
+
phase: "pre-teardown-commit-error",
|
|
1096
|
+
error: String(e),
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
966
1100
|
// 11. Remove worktree directory first (must happen before branch deletion)
|
|
967
1101
|
try {
|
|
968
1102
|
removeWorktree(originalBasePath_, milestoneId, {
|
|
@@ -983,5 +1117,5 @@ export function mergeMilestoneToMain(originalBasePath_, milestoneId, roadmapCont
|
|
|
983
1117
|
// 13. Clear module state
|
|
984
1118
|
originalBase = null;
|
|
985
1119
|
nudgeGitBranchCache(previousCwd);
|
|
986
|
-
return { commitMessage, pushed, prCreated };
|
|
1120
|
+
return { commitMessage, pushed, prCreated, codeFilesChanged };
|
|
987
1121
|
}
|