@opengsd/gsd-pi 1.4.0-dev.c18009cd → 1.5.0-dev.4fb2d460
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/gsd/auto/closeout.js +97 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
- 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 +12 -3
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
- package/dist/resources/extensions/gsd/auto-start.js +4 -3
- 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 +9 -3
- 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/db/queries.js +9 -9
- package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
- 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/markdown-renderer.js +15 -3
- package/dist/resources/extensions/gsd/md-importer.js +89 -23
- 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 +17 -3
- 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 +82 -0
- 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/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/tool-contract.js +14 -0
- 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/unit-registry.js +12 -2
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
- 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/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 +8 -8
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
- 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/integrations/hermes/open_gsd_hermes/gsd_client.py +24 -35
- 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/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/gsd/auto/closeout.ts +114 -7
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
- 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 +12 -3
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
- package/src/resources/extensions/gsd/auto-start.ts +5 -3
- 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 +11 -17
- 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/db/queries.ts +9 -9
- package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
- 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/markdown-renderer.ts +15 -3
- package/src/resources/extensions/gsd/md-importer.ts +93 -22
- 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 +21 -3
- package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
- package/src/resources/extensions/gsd/preferences-types.ts +30 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +69 -0
- 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/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/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-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-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/completed-units-metrics-sync.test.ts +1 -1
- 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 +25 -1
- 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/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-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/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/reopen-slice.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
- 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/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-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/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/reopen-slice.ts +5 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
- 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/validation-block-guard.ts +2 -1
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
- 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/interview-ui.ts +58 -11
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
- /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → gXoWec4UNqcR0tkuHwYCr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → gXoWec4UNqcR0tkuHwYCr}/_ssgManifest.js +0 -0
|
@@ -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.
|
|
@@ -352,17 +352,17 @@ export function insertTask(t) {
|
|
|
352
352
|
ON CONFLICT(milestone_id, slice_id, id) DO UPDATE SET
|
|
353
353
|
title = CASE WHEN NULLIF(:title, '') IS NOT NULL THEN :title ELSE tasks.title END,
|
|
354
354
|
status = :status,
|
|
355
|
-
one_liner = :one_liner,
|
|
356
|
-
narrative = :narrative,
|
|
357
|
-
verification_result = :verification_result,
|
|
358
|
-
duration = :duration,
|
|
359
|
-
completed_at = :completed_at,
|
|
360
|
-
blocker_discovered = :blocker_discovered,
|
|
361
|
-
deviations = :deviations,
|
|
362
|
-
known_issues = :known_issues,
|
|
363
|
-
key_files = :key_files,
|
|
364
|
-
key_decisions = :key_decisions,
|
|
365
|
-
full_summary_md = :full_summary_md,
|
|
355
|
+
one_liner = CASE WHEN :preserve_completion = 1 AND NULLIF(:one_liner, '') IS NULL THEN tasks.one_liner ELSE :one_liner END,
|
|
356
|
+
narrative = CASE WHEN :preserve_completion = 1 AND NULLIF(:narrative, '') IS NULL THEN tasks.narrative ELSE :narrative END,
|
|
357
|
+
verification_result = CASE WHEN :preserve_completion = 1 AND NULLIF(:verification_result, '') IS NULL THEN tasks.verification_result ELSE :verification_result END,
|
|
358
|
+
duration = CASE WHEN :preserve_completion = 1 AND NULLIF(:duration, '') IS NULL THEN tasks.duration ELSE :duration END,
|
|
359
|
+
completed_at = CASE WHEN :preserve_completion = 1 AND tasks.completed_at IS NOT NULL THEN tasks.completed_at ELSE :completed_at END,
|
|
360
|
+
blocker_discovered = CASE WHEN :preserve_completion = 1 AND :blocker_discovered = 0 THEN tasks.blocker_discovered ELSE :blocker_discovered END,
|
|
361
|
+
deviations = CASE WHEN :preserve_completion = 1 AND NULLIF(:deviations, '') IS NULL THEN tasks.deviations ELSE :deviations END,
|
|
362
|
+
known_issues = CASE WHEN :preserve_completion = 1 AND NULLIF(:known_issues, '') IS NULL THEN tasks.known_issues ELSE :known_issues END,
|
|
363
|
+
key_files = CASE WHEN :preserve_completion = 1 AND NULLIF(:key_files, '[]') IS NULL THEN tasks.key_files ELSE :key_files END,
|
|
364
|
+
key_decisions = CASE WHEN :preserve_completion = 1 AND NULLIF(:key_decisions, '[]') IS NULL THEN tasks.key_decisions ELSE :key_decisions END,
|
|
365
|
+
full_summary_md = CASE WHEN :preserve_completion = 1 AND NULLIF(:full_summary_md, '') IS NULL THEN tasks.full_summary_md ELSE :full_summary_md END,
|
|
366
366
|
description = CASE WHEN NULLIF(:description, '') IS NOT NULL THEN :description ELSE tasks.description END,
|
|
367
367
|
estimate = CASE WHEN NULLIF(:estimate, '') IS NOT NULL THEN :estimate ELSE tasks.estimate END,
|
|
368
368
|
files = CASE WHEN NULLIF(:files, '[]') IS NOT NULL THEN :files ELSE tasks.files END,
|
|
@@ -401,6 +401,7 @@ export function insertTask(t) {
|
|
|
401
401
|
":observability_impact": t.planning?.observabilityImpact ?? "",
|
|
402
402
|
":full_plan_md": t.planning?.fullPlanMd ?? "",
|
|
403
403
|
":sequence": t.sequence ?? 0,
|
|
404
|
+
":preserve_completion": t.preserveCompletionMetadata && (t.status === "complete" || t.status === "done") ? 1 : 0,
|
|
404
405
|
":target_repositories": JSON.stringify(t.planning?.targetRepositories ?? []),
|
|
405
406
|
":raw_target_repositories": t.planning && "targetRepositories" in t.planning
|
|
406
407
|
? JSON.stringify(t.planning.targetRepositories ?? [])
|
|
@@ -1000,6 +1001,17 @@ export function deleteArtifactByPath(path) {
|
|
|
1000
1001
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1001
1002
|
getDbOrNull().prepare("DELETE FROM artifacts WHERE path = :path").run({ ":path": path });
|
|
1002
1003
|
}
|
|
1004
|
+
/** Delete artifact rows whose paths share a DB-relative prefix. */
|
|
1005
|
+
export function deleteArtifactsByPathPrefix(prefix) {
|
|
1006
|
+
if (!getDbOrNull())
|
|
1007
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1008
|
+
return transaction(() => {
|
|
1009
|
+
const likePrefix = `${prefix}%`;
|
|
1010
|
+
const countRow = getDbOrNull().prepare("SELECT COUNT(*) AS count FROM artifacts WHERE path LIKE :prefix").get({ ":prefix": likePrefix });
|
|
1011
|
+
getDbOrNull().prepare("DELETE FROM artifacts WHERE path LIKE :prefix").run({ ":prefix": likePrefix });
|
|
1012
|
+
return Number(countRow?.["count"] ?? 0);
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1003
1015
|
/**
|
|
1004
1016
|
* Drop hierarchy rows in dependency order inside a transaction. Used by
|
|
1005
1017
|
* `gsd recover --confirm` to rebuild engine state from markdown.
|
|
@@ -27,8 +27,8 @@ import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.j
|
|
|
27
27
|
import { nativeAddAll, nativeCommit, nativeHasCommittedHead, nativeIsRepo, nativeInit } from "./native-git-bridge.js";
|
|
28
28
|
import { isInheritedRepo } from "./repo-identity.js";
|
|
29
29
|
import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
|
|
30
|
-
import { getIsolationMode, loadEffectiveGSDPreferences } from "./preferences.js";
|
|
31
|
-
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
30
|
+
import { getIsolationMode, loadEffectiveGSDPreferences, renderLanguageDirectiveForPrompt } from "./preferences.js";
|
|
31
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
32
32
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
33
33
|
import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
|
|
34
34
|
import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
|
|
@@ -50,7 +50,7 @@ import { getCachedWorkflowMcpProbe, probeAndCacheWorkflowMcp, warmWorkflowMcpPro
|
|
|
50
50
|
import { probeCoversRequiredWorkflowTools } from "./tool-surface-readiness.js";
|
|
51
51
|
import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
|
|
52
52
|
import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
|
|
53
|
-
import {
|
|
53
|
+
import { getUnitWorkflowDispatchReadinessErrorForModel } from "./tool-contract.js";
|
|
54
54
|
import { runPreparation, formatCodebaseBrief, formatPriorContextBrief, } from "./preparation.js";
|
|
55
55
|
import { verifyExpectedArtifact } from "./auto-recovery.js";
|
|
56
56
|
import { countPlanMilestoneRoadmapSlices } from "./artifact-verification.js";
|
|
@@ -491,7 +491,7 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
|
|
|
491
491
|
const loadPreferences = resolvedOptions.deps?.loadPreferences ?? loadEffectiveGSDPreferences;
|
|
492
492
|
const selectModel = resolvedOptions.deps?.selectModel ?? selectAndApplyModel;
|
|
493
493
|
const getDispatchReadinessError = resolvedOptions.deps?.getDispatchReadinessError
|
|
494
|
-
??
|
|
494
|
+
?? getUnitWorkflowDispatchReadinessErrorForModel;
|
|
495
495
|
// Route through the dynamic routing pipeline (complexity classification,
|
|
496
496
|
// tier downgrade, fallback chains) — same path as auto-mode dispatches (#2958).
|
|
497
497
|
if (ctx && unitType) {
|
|
@@ -506,16 +506,12 @@ async function dispatchWorkflow(pi, note, customType = "gsd-run", ctx, unitType,
|
|
|
506
506
|
});
|
|
507
507
|
}
|
|
508
508
|
const compatibilityError = getDispatchReadinessError({
|
|
509
|
-
|
|
509
|
+
model: result.appliedModel,
|
|
510
|
+
fallbackModel: ctx.model,
|
|
511
|
+
getProviderAuthMode: (provider) => ctx.modelRegistry.getProviderAuthMode(provider),
|
|
510
512
|
projectRoot,
|
|
511
513
|
surface: "guided flow",
|
|
512
514
|
unitType,
|
|
513
|
-
authMode: result.appliedModel?.provider
|
|
514
|
-
? ctx.modelRegistry.getProviderAuthMode(result.appliedModel.provider)
|
|
515
|
-
: ctx.model?.provider
|
|
516
|
-
? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
|
|
517
|
-
: undefined,
|
|
518
|
-
baseUrl: result.appliedModel?.baseUrl ?? ctx.model?.baseUrl,
|
|
519
515
|
// Guided flow starts the MCP workflow server as part of dispatch, so the
|
|
520
516
|
// parent session's activeTools doesn't include MCP tools yet. The MCP
|
|
521
517
|
// launch config check (detectWorkflowMcpLaunchConfig) is the right gate
|
|
@@ -646,7 +642,7 @@ function resolveAvailableModel(modelId, availableModels, currentProvider) {
|
|
|
646
642
|
* Build the discuss-and-plan prompt for a new milestone.
|
|
647
643
|
* Used by all three "new milestone" paths (first ever, no active, all complete).
|
|
648
644
|
*/
|
|
649
|
-
function buildDiscussPrompt(nextId, preamble,
|
|
645
|
+
function buildDiscussPrompt(nextId, preamble, basePath, pi, ctx, preparationContext) {
|
|
650
646
|
const milestoneRel = `.gsd/milestones/${nextId}`;
|
|
651
647
|
const structuredQuestionsAvailable = getStructuredQuestionsAvailability(pi, ctx);
|
|
652
648
|
const inlinedTemplates = [
|
|
@@ -656,7 +652,7 @@ function buildDiscussPrompt(nextId, preamble, _basePath, pi, ctx, preparationCon
|
|
|
656
652
|
inlineTemplate("roadmap", "Roadmap"),
|
|
657
653
|
inlineTemplate("decisions", "Decisions"),
|
|
658
654
|
].join("\n\n---\n\n");
|
|
659
|
-
return loadPrompt("discuss", {
|
|
655
|
+
return prependLanguageDirective(basePath, loadPrompt("discuss", {
|
|
660
656
|
milestoneId: nextId,
|
|
661
657
|
preamble,
|
|
662
658
|
preparationContext: preparationContext ?? "",
|
|
@@ -666,13 +662,22 @@ function buildDiscussPrompt(nextId, preamble, _basePath, pi, ctx, preparationCon
|
|
|
666
662
|
inlinedTemplates,
|
|
667
663
|
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
|
|
668
664
|
multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
|
|
669
|
-
});
|
|
665
|
+
}));
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Prepend the configured response-language directive to a dispatched discuss
|
|
669
|
+
* prompt so the discuss/QA conversation is held in the language set in
|
|
670
|
+
* PREFERENCES.md (#1210). No-op when no language is configured.
|
|
671
|
+
*/
|
|
672
|
+
function prependLanguageDirective(basePath, prompt) {
|
|
673
|
+
const directive = renderLanguageDirectiveForPrompt(loadEffectiveGSDPreferences(basePath)?.preferences);
|
|
674
|
+
return directive ? `${directive}\n\n${prompt}` : prompt;
|
|
670
675
|
}
|
|
671
676
|
/**
|
|
672
677
|
* Build the discuss prompt for headless milestone creation.
|
|
673
678
|
* Uses the discuss-headless prompt template with seed context injected.
|
|
674
679
|
*/
|
|
675
|
-
function buildHeadlessDiscussPrompt(nextId, seedContext,
|
|
680
|
+
function buildHeadlessDiscussPrompt(nextId, seedContext, basePath) {
|
|
676
681
|
const milestoneRel = `.gsd/milestones/${nextId}`;
|
|
677
682
|
const inlinedTemplates = [
|
|
678
683
|
inlineTemplate("project", "Project"),
|
|
@@ -681,7 +686,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
|
|
|
681
686
|
inlineTemplate("roadmap", "Roadmap"),
|
|
682
687
|
inlineTemplate("decisions", "Decisions"),
|
|
683
688
|
].join("\n\n---\n\n");
|
|
684
|
-
return loadPrompt("discuss-headless", {
|
|
689
|
+
return prependLanguageDirective(basePath, loadPrompt("discuss-headless", {
|
|
685
690
|
milestoneId: nextId,
|
|
686
691
|
seedContext,
|
|
687
692
|
contextPath: `${milestoneRel}/${nextId}-CONTEXT.md`,
|
|
@@ -689,7 +694,7 @@ function buildHeadlessDiscussPrompt(nextId, seedContext, _basePath) {
|
|
|
689
694
|
inlinedTemplates,
|
|
690
695
|
commitInstruction: buildDocsCommitInstruction(`docs(${nextId}): context, requirements, and roadmap`),
|
|
691
696
|
multiMilestoneCommitInstruction: buildDocsCommitInstruction("docs: project plan — N milestones"),
|
|
692
|
-
});
|
|
697
|
+
}));
|
|
693
698
|
}
|
|
694
699
|
/**
|
|
695
700
|
* Run preparation phase if enabled, then build the discuss prompt.
|
|
@@ -1045,9 +1045,21 @@ export async function renderReplanFromDb(basePath, milestoneId, sliceId, replanD
|
|
|
1045
1045
|
return { replanPath: absPath, content };
|
|
1046
1046
|
}
|
|
1047
1047
|
export async function renderAssessmentFromDb(basePath, milestoneId, sliceId, assessmentData) {
|
|
1048
|
-
// Flat-phase: assessment file lives in the phase dir
|
|
1049
|
-
|
|
1050
|
-
|
|
1048
|
+
// Flat-phase: the assessment file lives in the phase dir, NOT in a slices/SID/
|
|
1049
|
+
// subdir. resolveSlicePath() detects a slices/SID/ dir unconditionally, so a
|
|
1050
|
+
// stray slices/SID/ created by an earlier planning step would send this write
|
|
1051
|
+
// to a hybrid path (wrong dir, flat filename) that verification cannot find.
|
|
1052
|
+
// Guard with the same legacy-base check relSlicePath() uses so flat-phase
|
|
1053
|
+
// milestones always target the phase dir.
|
|
1054
|
+
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
1055
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
1056
|
+
const isLegacyLayout = mDir
|
|
1057
|
+
? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
|
|
1058
|
+
: false;
|
|
1059
|
+
const fallbackDir = join(milestonesDir(basePath), canonicalPhaseDirName(milestoneId, getMilestone(milestoneId)?.title));
|
|
1060
|
+
const slicePath = isLegacyLayout
|
|
1061
|
+
? (resolveSlicePath(basePath, milestoneId, sliceId) ?? fallbackDir)
|
|
1062
|
+
: (mDir ?? fallbackDir);
|
|
1051
1063
|
const phaseNum = milestoneIdToPhaseNum(milestoneId);
|
|
1052
1064
|
const planNum = sliceIdToPlanNum(sliceId);
|
|
1053
1065
|
const absPath = join(slicePath, planFileName(phaseNum, planNum, "ASSESSMENT"));
|