@opengsd/gsd-pi 1.5.0 → 1.6.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 +10 -10
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
- package/dist/resources/extensions/gsd/activity-log.js +1 -1
- package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +20 -13
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
- package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
- package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
- package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
- package/dist/resources/extensions/gsd/auto-start.js +57 -33
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
- package/dist/resources/extensions/gsd/auto-timers.js +9 -2
- package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
- package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
- package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
- package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
- package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
- package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
- package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
- package/dist/resources/extensions/gsd/auto.js +106 -34
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
- package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
- package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
- package/dist/resources/extensions/gsd/config-overlay.js +7 -2
- package/dist/resources/extensions/gsd/db/engine.js +33 -0
- package/dist/resources/extensions/gsd/db/queries.js +9 -9
- package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
- package/dist/resources/extensions/gsd/db-adapter.js +30 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
- package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
- package/dist/resources/extensions/gsd/git-service.js +45 -0
- package/dist/resources/extensions/gsd/gsd-db.js +23 -11
- package/dist/resources/extensions/gsd/guided-flow.js +22 -17
- package/dist/resources/extensions/gsd/journal.js +1 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +34 -79
- package/dist/resources/extensions/gsd/md-importer.js +89 -23
- package/dist/resources/extensions/gsd/metrics.js +2 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
- package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
- package/dist/resources/extensions/gsd/paths.js +87 -52
- package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
- package/dist/resources/extensions/gsd/preferences-models.js +66 -15
- package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +148 -10
- package/dist/resources/extensions/gsd/preferences.js +20 -0
- package/dist/resources/extensions/gsd/prompts/system.md +6 -6
- package/dist/resources/extensions/gsd/quick.js +12 -3
- package/dist/resources/extensions/gsd/rule-registry.js +106 -10
- package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
- package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
- package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
- package/dist/resources/extensions/gsd/unit-registry.js +12 -2
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
- package/dist/resources/extensions/gsd/uok/audit.js +3 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
- package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
- package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
- package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
- package/dist/resources/extensions/gsd/workspace.js +5 -14
- package/dist/resources/extensions/gsd/worktree-command.js +1 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
- package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
- package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
- package/dist/resources/extensions/shared/interview-ui.js +62 -9
- 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 +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +9 -9
- package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/dist/worktree-cli-create.d.ts +10 -0
- package/dist/worktree-cli-create.js +11 -0
- package/dist/worktree-cli-format.d.ts +12 -0
- package/dist/worktree-cli-format.js +38 -0
- package/dist/worktree-cli-plan.d.ts +16 -0
- package/dist/worktree-cli-plan.js +19 -0
- package/dist/worktree-cli-session.d.ts +13 -0
- package/dist/worktree-cli-session.js +18 -0
- package/dist/worktree-cli-status.d.ts +35 -0
- package/dist/worktree-cli-status.js +54 -0
- package/dist/worktree-cli.d.ts +1 -16
- package/dist/worktree-cli.js +28 -122
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +25 -36
- package/integrations/hermes/pyproject.toml +1 -1
- package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
- package/package.json +6 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
- package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-agent.js +113 -0
- package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.js +137 -0
- package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
- package/packages/daemon/dist/orchestrator.d.ts +4 -56
- package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
- package/packages/daemon/dist/orchestrator.js +13 -303
- package/packages/daemon/dist/orchestrator.js.map +1 -1
- package/packages/daemon/dist/orchestrator.test.js +11 -1
- package/packages/daemon/dist/orchestrator.test.js.map +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +14 -9
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
- package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
- package/packages/pi-ai/dist/tool-result-content.js +62 -0
- package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
- package/packages/pi-ai/dist/types.d.ts +8 -20
- 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/package-manager.d.ts +9 -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 +74 -53
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -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 +30 -2
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +4 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/core/export-html/template.js +53 -4
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
- package/src/resources/extensions/gsd/activity-log.ts +1 -1
- package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
- package/src/resources/extensions/gsd/auto/orchestrator.ts +21 -14
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
- package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
- package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
- package/src/resources/extensions/gsd/auto-start.ts +62 -31
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
- package/src/resources/extensions/gsd/auto-timers.ts +9 -2
- package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
- package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
- package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
- package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
- package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
- package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
- package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
- package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
- package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
- package/src/resources/extensions/gsd/auto.ts +114 -47
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
- package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
- package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
- package/src/resources/extensions/gsd/config-overlay.ts +7 -1
- package/src/resources/extensions/gsd/db/engine.ts +36 -0
- package/src/resources/extensions/gsd/db/queries.ts +9 -9
- package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
- package/src/resources/extensions/gsd/db-adapter.ts +29 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
- package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +53 -0
- package/src/resources/extensions/gsd/gsd-db.ts +33 -11
- package/src/resources/extensions/gsd/guided-flow.ts +26 -18
- package/src/resources/extensions/gsd/journal.ts +1 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +52 -91
- package/src/resources/extensions/gsd/md-importer.ts +93 -22
- package/src/resources/extensions/gsd/metrics.ts +2 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/paths.ts +108 -51
- package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
- package/src/resources/extensions/gsd/preferences-models.ts +74 -20
- package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
- package/src/resources/extensions/gsd/preferences-types.ts +54 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +146 -9
- package/src/resources/extensions/gsd/preferences.ts +20 -0
- package/src/resources/extensions/gsd/prompts/system.md +6 -6
- package/src/resources/extensions/gsd/quick.ts +11 -3
- package/src/resources/extensions/gsd/rule-registry.ts +111 -9
- package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
- package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +46 -1
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
- package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
- package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
- package/src/resources/extensions/gsd/tool-contract.ts +29 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
- package/src/resources/extensions/gsd/types.ts +23 -4
- package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
- package/src/resources/extensions/gsd/unit-registry.ts +16 -2
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
- package/src/resources/extensions/gsd/uok/audit.ts +2 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
- package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
- package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
- package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
- package/src/resources/extensions/gsd/workspace.ts +5 -21
- package/src/resources/extensions/gsd/worktree-command.ts +1 -1
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
- package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
- package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
- package/src/resources/extensions/shared/interview-ui.ts +58 -11
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
- /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_ssgManifest.js +0 -0
|
@@ -98,6 +98,50 @@ export function writeCompatMarker(basePath, marker) {
|
|
|
98
98
|
writeFileSync(tmp, JSON.stringify(marker, null, 2), "utf-8");
|
|
99
99
|
renameSync(tmp, path);
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Remove projection entries whose backing file no longer exists on disk.
|
|
103
|
+
*
|
|
104
|
+
* gsd-pi never deletes marker entries on its own: both drift detectors skip
|
|
105
|
+
* files missing from disk (`if (!existsSync(abs)) continue;`) and the write-time
|
|
106
|
+
* flush only ever adds or refreshes entries. So when a phase directory is
|
|
107
|
+
* renamed or removed (e.g. `phases/29-new-milestone-m029/` →
|
|
108
|
+
* `phases/29-frontend-code-debt-cleanup/`), the old projection paths linger in
|
|
109
|
+
* `.compat.json` forever as phantom entries pointing at directories that no
|
|
110
|
+
* longer exist (#1257). They never reconcile, and `.compat.json` keeps drifting
|
|
111
|
+
* from disk reality so `git status` stops being a reliable proxy for "did the
|
|
112
|
+
* engine touch my plans?".
|
|
113
|
+
*
|
|
114
|
+
* This prunes those orphaned entries across the `.gsd/` projections and the
|
|
115
|
+
* `.planning/` projections/passthrough maps. It is safe: a missing-file entry is
|
|
116
|
+
* inert (every detector already ignores it), and if the file is later
|
|
117
|
+
* re-projected the write-time flush / unseeded-file detection re-seeds an
|
|
118
|
+
* accurate baseline.
|
|
119
|
+
*
|
|
120
|
+
* Returns the number of entries removed; when nothing is orphaned the marker is
|
|
121
|
+
* left untouched (no needless write, no `lastProjectedAt` churn).
|
|
122
|
+
*/
|
|
123
|
+
export function pruneOrphanedProjectionEntries(basePath) {
|
|
124
|
+
if (!existsSync(compatMarkerPath(basePath)))
|
|
125
|
+
return 0;
|
|
126
|
+
const marker = readCompatMarker(basePath);
|
|
127
|
+
let removed = 0;
|
|
128
|
+
const pruneMap = (map, root) => {
|
|
129
|
+
for (const relPath of Object.keys(map)) {
|
|
130
|
+
if (!existsSync(join(basePath, root, relPath))) {
|
|
131
|
+
delete map[relPath];
|
|
132
|
+
removed++;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
pruneMap(marker.projections, ".gsd");
|
|
137
|
+
if (marker.planning) {
|
|
138
|
+
pruneMap(marker.planning.projections, ".planning");
|
|
139
|
+
pruneMap(marker.planning.passthrough, ".planning");
|
|
140
|
+
}
|
|
141
|
+
if (removed > 0)
|
|
142
|
+
writeCompatMarker(basePath, marker);
|
|
143
|
+
return removed;
|
|
144
|
+
}
|
|
101
145
|
function quarantine(basePath, raw) {
|
|
102
146
|
const path = compatMarkerPath(basePath);
|
|
103
147
|
const badPath = `${path}.bad-${Date.now()}`;
|
|
@@ -121,8 +121,13 @@ function collectConfigSections(options) {
|
|
|
121
121
|
if (prefs?.auto_supervisor) {
|
|
122
122
|
const sup = resolveAutoSupervisorConfig();
|
|
123
123
|
const supRows = [];
|
|
124
|
-
if (sup.model)
|
|
125
|
-
|
|
124
|
+
if (sup.model) {
|
|
125
|
+
let modelVal = sup.model;
|
|
126
|
+
if (sup.modelFallbacks && sup.modelFallbacks.length > 0) {
|
|
127
|
+
modelVal += ` \u2192 ${sup.modelFallbacks.join(" \u2192 ")}`;
|
|
128
|
+
}
|
|
129
|
+
supRows.push({ label: "Model", value: modelVal });
|
|
130
|
+
}
|
|
126
131
|
supRows.push({ label: "Soft timeout", value: `${sup.soft_timeout_minutes}m` });
|
|
127
132
|
supRows.push({ label: "Idle timeout", value: `${sup.idle_timeout_minutes}m` });
|
|
128
133
|
supRows.push({ label: "Stalled tool timeout", value: `${sup.stalled_tool_timeout_minutes}m` });
|
|
@@ -801,3 +801,36 @@ export function getDb() {
|
|
|
801
801
|
export function getDbOrNull() {
|
|
802
802
|
return currentDb;
|
|
803
803
|
}
|
|
804
|
+
/**
|
|
805
|
+
* Confirm the open handle can actually write, not just that it opened.
|
|
806
|
+
*
|
|
807
|
+
* A schema-current database performs zero writes during open, so a handle that
|
|
808
|
+
* opened successfully but is not writable (read-only file, WAL/SHM permission
|
|
809
|
+
* mismatch, or a stale/moved handle → SQLITE_READONLY_DBMOVED) otherwise passes
|
|
810
|
+
* the open-only availability check and only fails much later at the first real
|
|
811
|
+
* write. The probe forces a genuine page write by re-writing the current
|
|
812
|
+
* `PRAGMA user_version` value back inside an IMMEDIATE transaction: a bare
|
|
813
|
+
* `BEGIN IMMEDIATE; ROLLBACK` is not sufficient because a moved handle does not
|
|
814
|
+
* fail until a page is actually dirtied. The value is unchanged, so the probe
|
|
815
|
+
* is idempotent, and the transaction is rolled back so nothing persists.
|
|
816
|
+
*/
|
|
817
|
+
export function probeDbWritable() {
|
|
818
|
+
const db = currentDb;
|
|
819
|
+
if (!db)
|
|
820
|
+
return { ok: false, detail: "No database is open." };
|
|
821
|
+
try {
|
|
822
|
+
const row = db.prepare("PRAGMA user_version").get();
|
|
823
|
+
const current = typeof row?.user_version === "number" ? row.user_version : 0;
|
|
824
|
+
db.exec("BEGIN IMMEDIATE");
|
|
825
|
+
try {
|
|
826
|
+
db.exec(`PRAGMA user_version = ${current}`);
|
|
827
|
+
}
|
|
828
|
+
finally {
|
|
829
|
+
db.exec("ROLLBACK");
|
|
830
|
+
}
|
|
831
|
+
return { ok: true };
|
|
832
|
+
}
|
|
833
|
+
catch (err) {
|
|
834
|
+
return { ok: false, detail: err.message };
|
|
835
|
+
}
|
|
836
|
+
}
|
|
@@ -218,7 +218,7 @@ export function getMilestone(id) {
|
|
|
218
218
|
export function getActiveMilestoneFromDb() {
|
|
219
219
|
if (!getDbOrNull())
|
|
220
220
|
return null;
|
|
221
|
-
const row = getDbOrNull().prepare(
|
|
221
|
+
const row = getDbOrNull().prepare(`SELECT * FROM milestones WHERE status NOT IN (${TERMINAL_STATUS_SQL}, 'parked') ORDER BY id LIMIT 1`).get();
|
|
222
222
|
if (!row)
|
|
223
223
|
return null;
|
|
224
224
|
return rowToMilestone(row);
|
|
@@ -230,11 +230,11 @@ export function getActiveSliceFromDb(milestoneId) {
|
|
|
230
230
|
// Uses json_each() to expand the JSON depends array and checks each dep is complete.
|
|
231
231
|
const row = getDbOrNull().prepare(`SELECT s.* FROM slices s
|
|
232
232
|
WHERE s.milestone_id = :mid
|
|
233
|
-
AND s.status NOT IN (
|
|
233
|
+
AND s.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
234
234
|
AND NOT EXISTS (
|
|
235
235
|
SELECT 1 FROM json_each(s.depends) AS dep
|
|
236
236
|
WHERE dep.value NOT IN (
|
|
237
|
-
SELECT id FROM slices WHERE milestone_id = :mid AND status IN (
|
|
237
|
+
SELECT id FROM slices WHERE milestone_id = :mid AND status IN (${TERMINAL_STATUS_SQL})
|
|
238
238
|
)
|
|
239
239
|
)
|
|
240
240
|
ORDER BY s.sequence, s.id
|
|
@@ -246,7 +246,7 @@ export function getActiveSliceFromDb(milestoneId) {
|
|
|
246
246
|
export function getActiveTaskFromDb(milestoneId, sliceId) {
|
|
247
247
|
if (!getDbOrNull())
|
|
248
248
|
return null;
|
|
249
|
-
const row = getDbOrNull().prepare(
|
|
249
|
+
const row = getDbOrNull().prepare(`SELECT * FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND status NOT IN (${TERMINAL_STATUS_SQL}) ORDER BY sequence, id LIMIT 1`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
250
250
|
if (!row)
|
|
251
251
|
return null;
|
|
252
252
|
return rowToTask(row);
|
|
@@ -265,7 +265,7 @@ export function getParallelMonitorSliceProgress(milestoneId) {
|
|
|
265
265
|
s.id AS id,
|
|
266
266
|
s.status AS status,
|
|
267
267
|
COUNT(t.id) AS total,
|
|
268
|
-
COALESCE(SUM(CASE WHEN t.status
|
|
268
|
+
COALESCE(SUM(CASE WHEN t.status IN (${TERMINAL_STATUS_SQL}) THEN 1 ELSE 0 END), 0) AS done
|
|
269
269
|
FROM slices s
|
|
270
270
|
LEFT JOIN tasks t ON s.milestone_id=t.milestone_id AND s.id=t.slice_id
|
|
271
271
|
WHERE s.milestone_id=:mid
|
|
@@ -417,7 +417,7 @@ export function getSliceScopedArtifacts(milestoneId, sliceId) {
|
|
|
417
417
|
export function getActiveMilestoneIdFromDb() {
|
|
418
418
|
if (!getDbOrNull())
|
|
419
419
|
return null;
|
|
420
|
-
const row = getDbOrNull().prepare(
|
|
420
|
+
const row = getDbOrNull().prepare(`SELECT id, status FROM milestones WHERE status NOT IN (${TERMINAL_STATUS_SQL}, 'parked') ORDER BY id LIMIT 1`).get();
|
|
421
421
|
if (!row)
|
|
422
422
|
return null;
|
|
423
423
|
return rowToIdStatusSummary(row);
|
|
@@ -432,7 +432,7 @@ export function getSliceStatusSummary(milestoneId) {
|
|
|
432
432
|
export function getActiveTaskIdFromDb(milestoneId, sliceId) {
|
|
433
433
|
if (!getDbOrNull())
|
|
434
434
|
return null;
|
|
435
|
-
const row = getDbOrNull().prepare(
|
|
435
|
+
const row = getDbOrNull().prepare(`SELECT id, status, title FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND status NOT IN (${TERMINAL_STATUS_SQL}) ORDER BY sequence, id LIMIT 1`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
436
436
|
if (!row)
|
|
437
437
|
return null;
|
|
438
438
|
return rowToActiveTaskSummary(row);
|
|
@@ -443,8 +443,8 @@ export function getSliceTaskCounts(milestoneId, sliceId) {
|
|
|
443
443
|
return emptyTaskStatusCounts();
|
|
444
444
|
const row = getDbOrNull().prepare(`SELECT
|
|
445
445
|
COUNT(*) as total,
|
|
446
|
-
SUM(CASE WHEN status IN (
|
|
447
|
-
SUM(CASE WHEN status NOT IN (
|
|
446
|
+
SUM(CASE WHEN status IN (${TERMINAL_STATUS_SQL}) THEN 1 ELSE 0 END) as done,
|
|
447
|
+
SUM(CASE WHEN status NOT IN (${TERMINAL_STATUS_SQL}) THEN 1 ELSE 0 END) as pending
|
|
448
448
|
FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
449
449
|
return rowToTaskStatusCounts(row);
|
|
450
450
|
}
|
|
@@ -24,6 +24,17 @@ function requireDb() {
|
|
|
24
24
|
* completion timestamps cleared, in one commit. Folds the hand-rolled
|
|
25
25
|
* transaction-plus-cascade previously in tools/reopen-slice.ts. Guards run
|
|
26
26
|
* inside the transaction (TOCTOU-safe).
|
|
27
|
+
*
|
|
28
|
+
* A closed slice is always reopenable. An open slice is only reopenable when it
|
|
29
|
+
* carries a completed-task state desync (#1205): a UAT→planning fallback can
|
|
30
|
+
* leave the slice "pending" while *all* its tasks stay "complete", which
|
|
31
|
+
* deadlocks every recovery path (plan-slice/replan-slice/complete-task all
|
|
32
|
+
* reject the still-closed tasks, and slice_reopen historically rejected the
|
|
33
|
+
* still-open slice). Resetting those tasks to pending gives the planner the
|
|
34
|
+
* clean slate it needs. An open slice that still has any unfinished
|
|
35
|
+
* (pending/in-progress) task is a normal in-flight slice, not the desync, and
|
|
36
|
+
* stays rejected as "slice-not-complete" so a full reset can't wipe its
|
|
37
|
+
* legitimate progress.
|
|
27
38
|
*/
|
|
28
39
|
export function reopenSliceCascade(milestoneId, sliceId) {
|
|
29
40
|
requireDb();
|
|
@@ -43,11 +54,18 @@ export function reopenSliceCascade(milestoneId, sliceId) {
|
|
|
43
54
|
outcome = { ok: false, reason: "slice-not-found" };
|
|
44
55
|
return;
|
|
45
56
|
}
|
|
46
|
-
|
|
57
|
+
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
58
|
+
// A closed slice is always reopenable. An open slice is only the #1205
|
|
59
|
+
// desync when EVERY task is already closed (a UAT→planning fallback left the
|
|
60
|
+
// slice open with all tasks still "complete"). Requiring *all* tasks closed
|
|
61
|
+
// (not merely one) means a normal in-flight slice — which keeps at least one
|
|
62
|
+
// pending/in-progress task — is rejected, so a full reset can't wipe its
|
|
63
|
+
// legitimate progress.
|
|
64
|
+
const allTasksClosed = tasks.length > 0 && tasks.every((t) => isClosedStatus(t.status));
|
|
65
|
+
if (!isClosedStatus(slice.status) && !allTasksClosed) {
|
|
47
66
|
outcome = { ok: false, reason: "slice-not-complete", status: slice.status };
|
|
48
67
|
return;
|
|
49
68
|
}
|
|
50
|
-
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
51
69
|
getDbOrNull().prepare(`UPDATE slices SET status = 'in_progress', completed_at = NULL WHERE milestone_id = :mid AND id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
52
70
|
getDbOrNull().prepare(`UPDATE tasks SET status = 'pending', completed_at = NULL WHERE milestone_id = :mid AND slice_id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
53
71
|
outcome = { ok: true, tasksReset: tasks.length };
|
|
@@ -11,19 +11,46 @@ export function normalizeDbRow(row) {
|
|
|
11
11
|
export function normalizeDbRows(rows) {
|
|
12
12
|
return rows.map((row) => normalizeDbRow(row));
|
|
13
13
|
}
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
if (value === null || typeof value !== "object")
|
|
16
|
+
return false;
|
|
17
|
+
const proto = Object.getPrototypeOf(value);
|
|
18
|
+
return proto === Object.prototype || proto === null;
|
|
19
|
+
}
|
|
20
|
+
// node:sqlite accepts binding-object keys with or without the ':'/'@'/'$'
|
|
21
|
+
// prefix, but better-sqlite3 accepts only bare keys — strip the prefix so
|
|
22
|
+
// call sites written against node:sqlite also work on the fallback provider.
|
|
23
|
+
function normalizeBindParams(params) {
|
|
24
|
+
return params.map((param) => {
|
|
25
|
+
if (!isPlainObject(param))
|
|
26
|
+
return param;
|
|
27
|
+
let changed = false;
|
|
28
|
+
const normalized = {};
|
|
29
|
+
for (const [key, value] of Object.entries(param)) {
|
|
30
|
+
if (key.length > 1 && (key[0] === ":" || key[0] === "@" || key[0] === "$")) {
|
|
31
|
+
normalized[key.slice(1)] = value;
|
|
32
|
+
changed = true;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
normalized[key] = value;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return changed ? normalized : param;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
14
41
|
export function createDbAdapter(rawDb) {
|
|
15
42
|
const db = rawDb;
|
|
16
43
|
const stmtCache = new Map();
|
|
17
44
|
function wrapStmt(raw) {
|
|
18
45
|
return {
|
|
19
46
|
run(...params) {
|
|
20
|
-
return raw.run(...params);
|
|
47
|
+
return raw.run(...normalizeBindParams(params));
|
|
21
48
|
},
|
|
22
49
|
get(...params) {
|
|
23
|
-
return normalizeDbRow(raw.get(...params));
|
|
50
|
+
return normalizeDbRow(raw.get(...normalizeBindParams(params)));
|
|
24
51
|
},
|
|
25
52
|
all(...params) {
|
|
26
|
-
return normalizeDbRows(raw.all(...params));
|
|
53
|
+
return normalizeDbRows(raw.all(...normalizeBindParams(params)));
|
|
27
54
|
},
|
|
28
55
|
};
|
|
29
56
|
}
|
|
@@ -138,7 +138,7 @@ Diagnostics record the file path, scope (global/project), severity (error/warnin
|
|
|
138
138
|
- `off` — skill discovery is disabled entirely.
|
|
139
139
|
|
|
140
140
|
- `auto_supervisor`: configures the auto-mode supervisor that monitors agent progress and enforces timeouts. Keys:
|
|
141
|
-
- `model`: model
|
|
141
|
+
- `model`: model to use for the supervisor process (defaults to the currently active model). Accepts a bare model ID **or** the same `{ model, provider?, fallbacks? }` object form as `models.<phase>`, so it honors `fallbacks[]` on a transient provider trip.
|
|
142
142
|
- `soft_timeout_minutes`: minutes before the supervisor issues a soft warning (default: 20).
|
|
143
143
|
- `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).
|
|
144
144
|
- `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).
|
|
@@ -228,7 +228,7 @@ In `"parent"` mode, slice/task `targetRepositories` default to the declared chil
|
|
|
228
228
|
- `enabled`: boolean — set `false` to force sequential task execution. Default: `true`.
|
|
229
229
|
- `max_parallel`: number — maximum tasks to dispatch in one batch, range `1`-`8`. Default: `2`.
|
|
230
230
|
- `isolation_mode`: `"same-tree"` — currently the only supported value.
|
|
231
|
-
- `subagent_model`:
|
|
231
|
+
- `subagent_model`: optional model override for reactive task subagents. Accepts a bare model ID **or** the `{ model, provider?, fallbacks? }` object form (parity with `models.<phase>`). Falls back to the `models.subagent` routing when omitted.
|
|
232
232
|
|
|
233
233
|
- `remote_questions`: route interactive questions to Slack/Discord for headless auto-mode. Keys:
|
|
234
234
|
- `channel`: `"slack"` or `"discord"` — channel type.
|
|
@@ -326,7 +326,7 @@ In `"parent"` mode, slice/task `targetRepositories` default to the declared chil
|
|
|
326
326
|
- `after`: string[] — unit types that trigger this hook (e.g., `["execute-task"]`).
|
|
327
327
|
- `prompt`: string — prompt sent to the LLM. Supports `{milestoneId}`, `{sliceId}`, `{taskId}` substitutions.
|
|
328
328
|
- `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).
|
|
329
|
-
- `model`:
|
|
329
|
+
- `model`: optional model override. Accepts a bare model ID **or** the same `{ model, provider?, fallbacks? }` object form as `models.<phase>`. With `fallbacks[]`, a transient trip of the primary provider falls back to the next entry instead of hard-failing the hook — which, for a `blocking` hook with `on_block: { action: pause }`, would otherwise pause the whole run.
|
|
330
330
|
- `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).
|
|
331
331
|
- `criticality`: `"advisory"` or `"blocking"` — advisory preserves current best-effort behavior; blocking requires clean hook completion plus a valid outcome verdict before auto-mode advances. Default: `"advisory"`.
|
|
332
332
|
- `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.
|
|
@@ -3,7 +3,7 @@ import { isAbsolute, join, relative, sep } from "node:path";
|
|
|
3
3
|
import { deleteArtifactByPath, getAllMilestones, getMilestoneSlices, getSliceTasks, isDbAvailable, isMemoriesFtsAvailable, repairTaskCompletionFromSummary, _getAdapter, } from "./gsd-db.js";
|
|
4
4
|
import { MEMORIES_FTS_REBUILT_KEY } from "./db-memory-fts-schema.js";
|
|
5
5
|
import { isAfter, latestExplicitReopenAt } from "./milestone-reopen-events.js";
|
|
6
|
-
import { gsdProjectionRoot, gsdRoot, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "./paths.js";
|
|
6
|
+
import { buildTaskFileName, gsdProjectionRoot, gsdRoot, resolveGsdPathContract, resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, } from "./paths.js";
|
|
7
7
|
import { deriveState } from "./state.js";
|
|
8
8
|
import { isClosedStatus } from "./status-guards.js";
|
|
9
9
|
import { workflowEventLogPath } from "./workflow-event-ledger.js";
|
|
@@ -12,6 +12,7 @@ import { flushWorkflowProjections } from "./projection-flush.js";
|
|
|
12
12
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
13
13
|
import { parsePlan } from "./parsers-legacy.js";
|
|
14
14
|
import { parseSummary } from "./files.js";
|
|
15
|
+
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
15
16
|
const USER_AUTHORED_ARTIFACT_TYPES = new Set(["CONTEXT", "RESEARCH"]);
|
|
16
17
|
function escapeRegExp(value) {
|
|
17
18
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -113,10 +114,10 @@ function isClearedByMilestoneShellProjectionFlush(basePath, issue, reRenderedMil
|
|
|
113
114
|
return false;
|
|
114
115
|
return issue.file === relativeFile(basePath, roadmapPath);
|
|
115
116
|
}
|
|
116
|
-
function artifactExistsOnDisk(basePath, artifactPath) {
|
|
117
|
-
return resolveArtifactDiskPath(basePath, artifactPath) !== null;
|
|
117
|
+
function artifactExistsOnDisk(basePath, artifactPath, row) {
|
|
118
|
+
return resolveArtifactDiskPath(basePath, artifactPath, row) !== null;
|
|
118
119
|
}
|
|
119
|
-
function
|
|
120
|
+
function resolveLiteralArtifactDiskPath(basePath, artifactPath) {
|
|
120
121
|
const relativeArtifactPath = artifactPathRelativeToGsd(artifactPath);
|
|
121
122
|
if (isAbsolute(relativeArtifactPath)) {
|
|
122
123
|
return existsSync(relativeArtifactPath) ? relativeArtifactPath : null;
|
|
@@ -128,6 +129,48 @@ function resolveArtifactDiskPath(basePath, artifactPath) {
|
|
|
128
129
|
}
|
|
129
130
|
return null;
|
|
130
131
|
}
|
|
132
|
+
function relativeToGsdRoot(basePath, diskPath) {
|
|
133
|
+
for (const root of [gsdProjectionRoot(basePath), gsdRoot(basePath)]) {
|
|
134
|
+
if (!isPathInside(root, diskPath))
|
|
135
|
+
continue;
|
|
136
|
+
return relative(root, diskPath).split("\\").join("/");
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function isFlatPhaseDiskPath(basePath, diskPath) {
|
|
141
|
+
return relativeToGsdRoot(basePath, diskPath)?.startsWith(`${LAYOUT_SEGMENTS.level1}/`) ?? false;
|
|
142
|
+
}
|
|
143
|
+
function hasFlatPhaseLayout(basePath) {
|
|
144
|
+
return existsSync(join(gsdProjectionRoot(basePath), LAYOUT_SEGMENTS.level1));
|
|
145
|
+
}
|
|
146
|
+
function resolveFlatPhaseArtifactDiskPath(basePath, row) {
|
|
147
|
+
if (!hasFlatPhaseLayout(basePath))
|
|
148
|
+
return null;
|
|
149
|
+
if (!row.milestone_id)
|
|
150
|
+
return null;
|
|
151
|
+
const artifactType = normalizedArtifactType(row.artifact_type);
|
|
152
|
+
if (!artifactType)
|
|
153
|
+
return null;
|
|
154
|
+
if (row.slice_id && row.task_id) {
|
|
155
|
+
const phaseDir = resolveMilestonePath(basePath, row.milestone_id);
|
|
156
|
+
if (!phaseDir || !isFlatPhaseDiskPath(basePath, phaseDir))
|
|
157
|
+
return null;
|
|
158
|
+
const candidate = join(phaseDir, buildTaskFileName(row.task_id, artifactType));
|
|
159
|
+
return existsSync(candidate) ? candidate : null;
|
|
160
|
+
}
|
|
161
|
+
const candidate = row.slice_id
|
|
162
|
+
? resolveSliceFile(basePath, row.milestone_id, row.slice_id, artifactType)
|
|
163
|
+
: resolveMilestoneFile(basePath, row.milestone_id, artifactType);
|
|
164
|
+
return candidate && isFlatPhaseDiskPath(basePath, candidate) ? candidate : null;
|
|
165
|
+
}
|
|
166
|
+
function resolveArtifactDiskPath(basePath, artifactPath, row) {
|
|
167
|
+
if (row && isMilestonesArtifactPath(row.path)) {
|
|
168
|
+
const flatPath = resolveFlatPhaseArtifactDiskPath(basePath, row);
|
|
169
|
+
if (flatPath)
|
|
170
|
+
return flatPath;
|
|
171
|
+
}
|
|
172
|
+
return resolveLiteralArtifactDiskPath(basePath, artifactPath);
|
|
173
|
+
}
|
|
131
174
|
function taskExistsInPlan(basePath, milestoneId, sliceId, taskId) {
|
|
132
175
|
const planPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
133
176
|
if (!planPath || !existsSync(planPath))
|
|
@@ -156,7 +199,7 @@ function readTaskCompletionEvidenceFromSummary(basePath, row) {
|
|
|
156
199
|
if (!row.task_status && Number(row.task_count) > 0 && !taskExistsInPlan(basePath, row.milestone_id, row.slice_id, row.task_id)) {
|
|
157
200
|
return null;
|
|
158
201
|
}
|
|
159
|
-
const diskPath = resolveArtifactDiskPath(basePath, row.path);
|
|
202
|
+
const diskPath = resolveArtifactDiskPath(basePath, row.path, { ...row, artifact_type: "SUMMARY" });
|
|
160
203
|
if (!diskPath)
|
|
161
204
|
return null;
|
|
162
205
|
try {
|
|
@@ -256,6 +299,43 @@ function hasPresentMilestonesReplacement(basePath, row, artifactRows) {
|
|
|
256
299
|
sameArtifactIdentity(row, other) &&
|
|
257
300
|
artifactExistsOnDisk(basePath, other.path));
|
|
258
301
|
}
|
|
302
|
+
function hasPresentFlatPhaseReplacement(basePath, row, artifactRows) {
|
|
303
|
+
if (resolveFlatPhaseArtifactDiskPath(basePath, row))
|
|
304
|
+
return true;
|
|
305
|
+
return artifactRows.some((other) => other.path !== row.path &&
|
|
306
|
+
!isMilestonesArtifactPath(other.path) &&
|
|
307
|
+
sameArtifactIdentity(row, other) &&
|
|
308
|
+
artifactExistsOnDisk(basePath, other.path, other));
|
|
309
|
+
}
|
|
310
|
+
function hasNoFlatPhaseFileEquivalent(row) {
|
|
311
|
+
const artifactType = normalizedArtifactType(row.artifact_type);
|
|
312
|
+
if (row.slice_id && row.task_id) {
|
|
313
|
+
return artifactType === "PLAN" || artifactType === "SUMMARY";
|
|
314
|
+
}
|
|
315
|
+
return Boolean(row.slice_id && !row.task_id && artifactType === "SUMMARY");
|
|
316
|
+
}
|
|
317
|
+
function staleMilestonesArtifactRowFixable(basePath, row, artifactRows) {
|
|
318
|
+
if (!isMilestonesArtifactPath(row.path))
|
|
319
|
+
return false;
|
|
320
|
+
if (!hasFlatPhaseLayout(basePath))
|
|
321
|
+
return false;
|
|
322
|
+
if (hasPresentFlatPhaseReplacement(basePath, row, artifactRows))
|
|
323
|
+
return true;
|
|
324
|
+
return hasNoFlatPhaseFileEquivalent(row) && !resolveLiteralArtifactDiskPath(basePath, row.path);
|
|
325
|
+
}
|
|
326
|
+
function stalePhasesArtifactRowFixable(basePath, row, artifactRows) {
|
|
327
|
+
const issuePath = artifactPathRelativeToGsd(row.path);
|
|
328
|
+
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) && hasPresentMilestonesReplacement(basePath, row, artifactRows);
|
|
329
|
+
}
|
|
330
|
+
function staleArtifactRowFixable(basePath, row, artifactRows) {
|
|
331
|
+
return staleMilestonesArtifactRowFixable(basePath, row, artifactRows) ||
|
|
332
|
+
stalePhasesArtifactRowFixable(basePath, row, artifactRows);
|
|
333
|
+
}
|
|
334
|
+
function staleArtifactPruneMessage(row) {
|
|
335
|
+
return isMilestonesArtifactPath(row.path)
|
|
336
|
+
? `pruned stale legacy artifact row ${row.path}`
|
|
337
|
+
: `pruned stale flat-phase artifact row ${row.path}`;
|
|
338
|
+
}
|
|
259
339
|
export async function checkEngineHealth(basePath, issues, fixesApplied, options) {
|
|
260
340
|
const dbPath = resolveGsdPathContract(basePath).projectDb;
|
|
261
341
|
if (!isDbAvailable() && existsSync(dbPath)) {
|
|
@@ -456,18 +536,20 @@ export async function checkEngineHealth(basePath, issues, fixesApplied, options)
|
|
|
456
536
|
ORDER BY path`)
|
|
457
537
|
.all();
|
|
458
538
|
for (const row of artifactRows) {
|
|
459
|
-
if (artifactExistsOnDisk(basePath, row.path))
|
|
460
|
-
continue;
|
|
461
539
|
const unitId = artifactUnitId(row);
|
|
462
540
|
const issuePath = artifactPathRelativeToGsd(row.path);
|
|
463
|
-
if (
|
|
541
|
+
if (artifactExistsOnDisk(basePath, row.path))
|
|
542
|
+
continue;
|
|
543
|
+
if (options?.repair && staleArtifactRowFixable(basePath, row, artifactRows)) {
|
|
464
544
|
// Route the write through the Single Writer owner (gsd-db.ts) instead
|
|
465
545
|
// of issuing raw DELETE SQL here — doctor is a read-only consumer and
|
|
466
546
|
// the single-writer invariant forbids write SQL outside the allowlist.
|
|
467
547
|
deleteArtifactByPath(row.path);
|
|
468
|
-
fixesApplied.push(
|
|
548
|
+
fixesApplied.push(staleArtifactPruneMessage(row));
|
|
469
549
|
continue;
|
|
470
550
|
}
|
|
551
|
+
if (artifactExistsOnDisk(basePath, row.path, row))
|
|
552
|
+
continue;
|
|
471
553
|
if (isUserAuthoredArtifactType(row.artifact_type)) {
|
|
472
554
|
const artifactType = normalizedArtifactType(row.artifact_type);
|
|
473
555
|
missingUserContentArtifacts.push({ path: issuePath, artifactType });
|
|
@@ -489,7 +571,7 @@ export async function checkEngineHealth(basePath, issues, fixesApplied, options)
|
|
|
489
571
|
unitId,
|
|
490
572
|
message: `Artifact ${issuePath} is recorded in the database as ${row.artifact_type || "UNKNOWN"} but no matching file exists on disk`,
|
|
491
573
|
file: issuePath,
|
|
492
|
-
fixable:
|
|
574
|
+
fixable: staleArtifactRowFixable(basePath, row, artifactRows),
|
|
493
575
|
});
|
|
494
576
|
}
|
|
495
577
|
}
|
|
@@ -518,7 +600,7 @@ export async function checkEngineHealth(basePath, issues, fixesApplied, options)
|
|
|
518
600
|
.all();
|
|
519
601
|
const seen = new Set();
|
|
520
602
|
for (const row of rows) {
|
|
521
|
-
if (!artifactExistsOnDisk(basePath, row.path))
|
|
603
|
+
if (!artifactExistsOnDisk(basePath, row.path, row))
|
|
522
604
|
continue;
|
|
523
605
|
const reopenAt = latestExplicitReopenAt(basePath, row.milestone_id);
|
|
524
606
|
if (!isAfter(row.imported_at, reopenAt))
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { renderAllFromDb, renderRoadmapFromDb } from "./markdown-renderer.js";
|
|
7
|
-
import { getAllMilestones, getMilestoneSlices } from "./gsd-db.js";
|
|
7
|
+
import { deleteArtifactsByPathPrefix, getAllMilestones, getMilestoneSlices } from "./gsd-db.js";
|
|
8
8
|
import { migrateFromMarkdown } from "./md-importer.js";
|
|
9
9
|
import { countDbHierarchy } from "./migration-auto-check.js";
|
|
10
10
|
import { logWarning } from "./workflow-logger.js";
|
|
@@ -78,15 +78,33 @@ function rollbackPartialMigration(basePath, backupDir, migratingPath) {
|
|
|
78
78
|
catch (removeErr) {
|
|
79
79
|
logWarning("migration", `rollback: could not remove partial ${LAYOUT_SEGMENTS.level1}/: ${removeErr.message}`);
|
|
80
80
|
}
|
|
81
|
+
// Only the standalone .gsd-backups/migrate-<ts>/ copy is disposable once the
|
|
82
|
+
// restore succeeds. When resuming an interrupted migration, backupDir IS the
|
|
83
|
+
// preserved migrating tree (the sole surviving data source) and must never be
|
|
84
|
+
// removed here. Deleting the backup after a successful rollback keeps the gate
|
|
85
|
+
// from leaking one .gsd-backups/migrate-<ts>/ per session_start.
|
|
86
|
+
const isDisposableBackup = Boolean(backupDir) && backupDir !== migratingPath;
|
|
87
|
+
const cleanupBackup = () => {
|
|
88
|
+
if (!isDisposableBackup || !existsSync(backupDir))
|
|
89
|
+
return;
|
|
90
|
+
try {
|
|
91
|
+
removePathWithRetries(backupDir);
|
|
92
|
+
}
|
|
93
|
+
catch (cleanupErr) {
|
|
94
|
+
logWarning("migration", `rollback: could not clean backup ${backupDir}: ${cleanupErr.message}`);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
81
97
|
// Restore milestones/ — prefer renaming the preserved migrating copy back.
|
|
82
98
|
const milestonesPath = join(basePath, ".gsd", "milestones");
|
|
83
99
|
try {
|
|
84
100
|
if (migratingPath && existsSync(migratingPath) && !existsSync(milestonesPath)) {
|
|
85
101
|
movePathWithCopyDeleteFallback(migratingPath, milestonesPath);
|
|
102
|
+
cleanupBackup();
|
|
86
103
|
return;
|
|
87
104
|
}
|
|
88
105
|
if (existsSync(backupDir)) {
|
|
89
106
|
cpSync(backupDir, milestonesPath, { recursive: true });
|
|
107
|
+
cleanupBackup();
|
|
90
108
|
}
|
|
91
109
|
if (migratingPath && existsSync(migratingPath)) {
|
|
92
110
|
removePathWithRetries(migratingPath);
|
|
@@ -163,7 +181,8 @@ export function pruneStaleFlatPhaseBackups(basePath) {
|
|
|
163
181
|
* 2. Rename .gsd/milestones/ aside so path resolvers target phases/
|
|
164
182
|
* 3. Render flat-phase from the DB (which already has the data)
|
|
165
183
|
* 4. Verify counts match
|
|
166
|
-
* 5.
|
|
184
|
+
* 5. Prune legacy milestones/ artifact rows
|
|
185
|
+
* 6. Remove the renamed legacy tree
|
|
167
186
|
*
|
|
168
187
|
* Idempotent: if .gsd/milestones/ doesn't exist, returns immediately.
|
|
169
188
|
*/
|
|
@@ -262,7 +281,17 @@ export async function migrateToFlatPhase(basePath) {
|
|
|
262
281
|
rollbackPartialMigration(basePath, backupDir, migratingPath);
|
|
263
282
|
throw new Error("flat-phase migration verification failed: no artifacts rendered");
|
|
264
283
|
}
|
|
265
|
-
// 6. Verified —
|
|
284
|
+
// 6. Verified — prune legacy artifact rows now that renderAllFromDb has
|
|
285
|
+
// re-inserted flat-phase rows for artifacts that still have files.
|
|
286
|
+
try {
|
|
287
|
+
deleteArtifactsByPathPrefix("milestones/");
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
logWarning("migration", `flat-phase migration could not prune legacy artifact rows: ${err.message}`);
|
|
291
|
+
rollbackPartialMigration(basePath, backupDir, migratingPath);
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
294
|
+
// 7. Remove the renamed legacy tree (backup already on disk).
|
|
266
295
|
try {
|
|
267
296
|
removePathWithRetries(migratingPath);
|
|
268
297
|
}
|
|
@@ -24,7 +24,7 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
24
24
|
import { gsdRoot } from "./paths.js";
|
|
25
25
|
import { isDbAvailable, getHierarchyCompletionCounts } from "./gsd-db.js";
|
|
26
26
|
import { formatDuration } from "../shared/format-utils.js";
|
|
27
|
-
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
27
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
28
28
|
import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
29
29
|
import { showNextAction } from "../shared/tui.js";
|
|
30
30
|
import { isInteractiveCommandContext, notifyForensicsNeedsInteractiveMenu, } from "./command-feedback.js";
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// File Purpose: Shared auto-resolution of safe merge conflict paths.
|
|
3
3
|
import { logWarning } from "./workflow-logger.js";
|
|
4
4
|
import { nativeAddPaths, nativeCheckoutTheirs, nativeRmForce, } from "./native-git-bridge.js";
|
|
5
|
-
import { isSafeToAutoResolve } from "./auto-worktree.js";
|
|
6
|
-
export { isSafeToAutoResolve } from "./auto-worktree.js";
|
|
5
|
+
import { isSafeToAutoResolve } from "./auto-worktree-conflict-auto-resolve.js";
|
|
6
|
+
export { isSafeToAutoResolve } from "./auto-worktree-conflict-auto-resolve.js";
|
|
7
7
|
/**
|
|
8
8
|
* Auto-resolve paths that are safe to accept from the milestone side
|
|
9
9
|
* (.gsd/ state and build artifacts).
|
|
@@ -519,6 +519,51 @@ export function runGit(basePath, args, options = {}) {
|
|
|
519
519
|
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${filterGitSvnNoise(message)}`);
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Arguments for creating a task/workflow branch.
|
|
524
|
+
*
|
|
525
|
+
* When the current branch is a leftover GSD task branch (workflow template,
|
|
526
|
+
* quick task, or slice), the new branch starts from `baseBranch` — the
|
|
527
|
+
* caller's resolved integration branch, normally `GitServiceImpl.getMainBranch()`
|
|
528
|
+
* so `main_branch` preference, milestone integration branch, and worktree base
|
|
529
|
+
* all take priority over repo-default detection. Branching from HEAD there
|
|
530
|
+
* silently stacks consecutive workflow branches on top of each other, so every
|
|
531
|
+
* new gsd/* branch (and its eventual PR) drags along the previous workflow's
|
|
532
|
+
* commits.
|
|
533
|
+
*
|
|
534
|
+
* On any other branch (a user's feature branch, a worktree base, the main
|
|
535
|
+
* branch itself) the legacy branch-from-HEAD behavior is kept: basing new work
|
|
536
|
+
* on the branch the user chose to stand on is intentional there.
|
|
537
|
+
*
|
|
538
|
+
* Falls back to branch-from-HEAD, with a logged warning, when the base branch
|
|
539
|
+
* has no local ref or the working tree is still dirty (a start point that
|
|
540
|
+
* changes the tree would abort the checkout or strand in-flight changes).
|
|
541
|
+
* The base is the local ref — deliberately no fetch, so branch creation stays
|
|
542
|
+
* offline-safe even if the local base is behind its remote.
|
|
543
|
+
*/
|
|
544
|
+
export function taskBranchArgs(basePath, branchName, currentBranch, baseBranch) {
|
|
545
|
+
const args = ["checkout", "-b", branchName];
|
|
546
|
+
const onTaskBranch = WORKFLOW_BRANCH_RE.test(currentBranch) ||
|
|
547
|
+
QUICK_BRANCH_RE.test(currentBranch) ||
|
|
548
|
+
SLICE_BRANCH_RE.test(currentBranch);
|
|
549
|
+
if (!onTaskBranch || !baseBranch || baseBranch === currentBranch)
|
|
550
|
+
return args;
|
|
551
|
+
try {
|
|
552
|
+
if (!nativeBranchExists(basePath, baseBranch)) {
|
|
553
|
+
logWarning("engine", `taskBranchArgs: base branch "${baseBranch}" has no local ref — branching ${branchName} from HEAD (${currentBranch})`, { file: "git-service.ts" });
|
|
554
|
+
return args;
|
|
555
|
+
}
|
|
556
|
+
if (nativeHasChanges(basePath)) {
|
|
557
|
+
logWarning("engine", `taskBranchArgs: working tree still dirty after auto-commit — branching ${branchName} from HEAD (${currentBranch}) to preserve in-flight changes`, { file: "git-service.ts" });
|
|
558
|
+
return args;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
catch {
|
|
562
|
+
return args;
|
|
563
|
+
}
|
|
564
|
+
args.push(baseBranch);
|
|
565
|
+
return args;
|
|
566
|
+
}
|
|
522
567
|
// ─── Commit Type Inference ─────────────────────────────────────────────────
|
|
523
568
|
/**
|
|
524
569
|
* Keyword-to-commit-type mapping. Order matters — first match wins.
|