@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
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { existsSync, readdirSync, readFileSync, type Dirent } from "node:fs";
|
|
12
|
-
import { homedir } from "node:os";
|
|
13
12
|
import { join } from "node:path";
|
|
13
|
+
import { getSkillDirectories } from "@gsd/pi-coding-agent";
|
|
14
14
|
import { gsdHome } from "./gsd-home.js";
|
|
15
15
|
import { getInstalledSkills, normalizeSkillName } from "./skills.js";
|
|
16
16
|
|
|
@@ -20,28 +20,47 @@ export interface DiscoveredSkill {
|
|
|
20
20
|
location: string;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Snapshot state. `searchDirs` is captured at snapshot time so every detection
|
|
25
|
+
* pass during the session scans the same project + user dirs (the bug fix:
|
|
26
|
+
* previously only user dirs were scanned, so skills installed into the project
|
|
27
|
+
* mid-session were silently missed).
|
|
28
|
+
*/
|
|
29
|
+
interface SkillSnapshotState {
|
|
30
|
+
baselineNames: Set<string>;
|
|
31
|
+
searchDirs: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let snapshot: SkillSnapshotState | null = null;
|
|
25
35
|
|
|
26
36
|
/**
|
|
27
37
|
* Snapshot the current installed skill catalog. Call at auto-mode start.
|
|
38
|
+
* `cwd` is the project base path; skills dropped into `<cwd>/.agents/skills/`,
|
|
39
|
+
* `<cwd>/.claude/skills/`, or `<cwd>/.gsd/skills/` mid-session are detected.
|
|
28
40
|
*/
|
|
29
|
-
export function snapshotSkills(): void {
|
|
30
|
-
|
|
41
|
+
export function snapshotSkills(options?: { cwd?: string }): void {
|
|
42
|
+
const searchDirs = getSkillDirectories({
|
|
43
|
+
cwd: options?.cwd ?? process.cwd(),
|
|
44
|
+
gsdHome: gsdHome(),
|
|
45
|
+
}).map((entry) => entry.path);
|
|
46
|
+
snapshot = {
|
|
47
|
+
baselineNames: snapshotCurrentSkillNames(searchDirs),
|
|
48
|
+
searchDirs,
|
|
49
|
+
};
|
|
31
50
|
}
|
|
32
51
|
|
|
33
52
|
/**
|
|
34
53
|
* Clear the snapshot. Call when auto-mode stops.
|
|
35
54
|
*/
|
|
36
55
|
export function clearSkillSnapshot(): void {
|
|
37
|
-
|
|
56
|
+
snapshot = null;
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
/**
|
|
41
60
|
* Check if a snapshot is active (auto-mode is running with discovery).
|
|
42
61
|
*/
|
|
43
62
|
export function hasSkillSnapshot(): boolean {
|
|
44
|
-
return
|
|
63
|
+
return snapshot !== null;
|
|
45
64
|
}
|
|
46
65
|
|
|
47
66
|
/**
|
|
@@ -49,12 +68,12 @@ export function hasSkillSnapshot(): boolean {
|
|
|
49
68
|
* Returns skill metadata for any new skills found in the loader catalog or on disk.
|
|
50
69
|
*/
|
|
51
70
|
export function detectNewSkills(): DiscoveredSkill[] {
|
|
52
|
-
if (!
|
|
71
|
+
if (!snapshot) return [];
|
|
53
72
|
|
|
54
73
|
const newSkills: DiscoveredSkill[] = [];
|
|
55
|
-
for (const skill of getCurrentSkillsForDiscovery()) {
|
|
74
|
+
for (const skill of getCurrentSkillsForDiscovery(snapshot.searchDirs)) {
|
|
56
75
|
const normalized = normalizeSkillName(skill.name);
|
|
57
|
-
if (
|
|
76
|
+
if (snapshot.baselineNames.has(normalized)) continue;
|
|
58
77
|
newSkills.push(skill);
|
|
59
78
|
}
|
|
60
79
|
|
|
@@ -84,7 +103,13 @@ export async function refreshCatalogForNewSkills(options?: {
|
|
|
84
103
|
}
|
|
85
104
|
}
|
|
86
105
|
|
|
87
|
-
|
|
106
|
+
// Re-snapshot, preserving the search dirs captured at auto-mode start.
|
|
107
|
+
if (snapshot) {
|
|
108
|
+
snapshot = {
|
|
109
|
+
baselineNames: snapshotCurrentSkillNames(),
|
|
110
|
+
searchDirs: snapshot.searchDirs,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
88
113
|
const names = newSkills.map((skill) => skill.name).join(", ");
|
|
89
114
|
options?.notify?.(`GSD: loaded new skills: ${names}`, "info");
|
|
90
115
|
return newSkills;
|
|
@@ -132,19 +157,18 @@ function escapeXml(value: string): string {
|
|
|
132
157
|
});
|
|
133
158
|
}
|
|
134
159
|
|
|
135
|
-
function
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
];
|
|
160
|
+
function snapshotCurrentSkillNames(searchDirsOverride?: string[]): Set<string> {
|
|
161
|
+
// Uses explicit dirs, the snapshot's search dirs when active, or user-only dirs
|
|
162
|
+
// (no project context) when called before a snapshot is taken.
|
|
163
|
+
const searchDirs = searchDirsOverride ?? snapshot?.searchDirs ?? defaultSearchDirs();
|
|
164
|
+
return new Set(getCurrentSkillsForDiscovery(searchDirs).map(skill => normalizeSkillName(skill.name)));
|
|
141
165
|
}
|
|
142
166
|
|
|
143
|
-
function
|
|
144
|
-
return
|
|
167
|
+
function defaultSearchDirs(): string[] {
|
|
168
|
+
return getSkillDirectories({ cwd: process.cwd(), gsdHome: gsdHome() }).map((entry) => entry.path);
|
|
145
169
|
}
|
|
146
170
|
|
|
147
|
-
function getCurrentSkillsForDiscovery(): DiscoveredSkill[] {
|
|
171
|
+
function getCurrentSkillsForDiscovery(searchDirs: string[]): DiscoveredSkill[] {
|
|
148
172
|
const skills = new Map<string, DiscoveredSkill>();
|
|
149
173
|
for (const skill of getInstalledSkills()) {
|
|
150
174
|
const normalized = normalizeSkillName(skill.name);
|
|
@@ -155,7 +179,7 @@ function getCurrentSkillsForDiscovery(): DiscoveredSkill[] {
|
|
|
155
179
|
});
|
|
156
180
|
}
|
|
157
181
|
|
|
158
|
-
for (const skill of getDiskSkills()) {
|
|
182
|
+
for (const skill of getDiskSkills(searchDirs)) {
|
|
159
183
|
const normalized = normalizeSkillName(skill.name);
|
|
160
184
|
if (!skills.has(normalized)) skills.set(normalized, skill);
|
|
161
185
|
}
|
|
@@ -163,9 +187,9 @@ function getCurrentSkillsForDiscovery(): DiscoveredSkill[] {
|
|
|
163
187
|
return [...skills.values()];
|
|
164
188
|
}
|
|
165
189
|
|
|
166
|
-
function getDiskSkills(): DiscoveredSkill[] {
|
|
190
|
+
function getDiskSkills(searchDirs: string[]): DiscoveredSkill[] {
|
|
167
191
|
const skills = new Map<string, DiscoveredSkill>();
|
|
168
|
-
for (const dir of
|
|
192
|
+
for (const dir of searchDirs) {
|
|
169
193
|
if (!existsSync(dir)) continue;
|
|
170
194
|
let entries: Dirent[];
|
|
171
195
|
try {
|
|
@@ -30,7 +30,9 @@ import { isAbsolute, join, dirname, resolve } from "node:path";
|
|
|
30
30
|
import { fileURLToPath } from "node:url";
|
|
31
31
|
import { gsdRoot } from "./paths.js";
|
|
32
32
|
import { createWorktree, worktreePath, removeWorktree } from "./worktree-manager.js";
|
|
33
|
-
import { autoWorktreeBranch
|
|
33
|
+
import { autoWorktreeBranch } from "./auto-worktree-branch-lifecycle.js";
|
|
34
|
+
import { syncGsdStateToWorktreeByScope } from "./auto-worktree-sync.js";
|
|
35
|
+
import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
|
|
34
36
|
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
35
37
|
import {
|
|
36
38
|
writeSessionStatus,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: DB-backed GSD state derivation pipeline stage.
|
|
3
3
|
|
|
4
|
-
import type { ActiveRef, GSDState, MilestoneRegistryEntry } from '../../types.js';
|
|
4
|
+
import type { ActiveRef, GSDState, MilestoneRegistryEntry, Phase } from '../../types.js';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { existsSync } from 'node:fs';
|
|
7
7
|
import { isClosedStatus, isDeferredStatus } from '../../status-guards.js';
|
|
@@ -41,6 +41,59 @@ import {
|
|
|
41
41
|
|
|
42
42
|
const isStatusDone = isClosedStatus;
|
|
43
43
|
|
|
44
|
+
type MilestoneProgress = { done: number; total: number };
|
|
45
|
+
type SliceProgress = { done: number; total: number };
|
|
46
|
+
type TaskProgress = { done: number; total: number };
|
|
47
|
+
|
|
48
|
+
interface DerivedStateContext {
|
|
49
|
+
activeMilestone: ActiveRef | null;
|
|
50
|
+
activeSlice?: ActiveRef | null;
|
|
51
|
+
activeTask?: ActiveRef | null;
|
|
52
|
+
registry: MilestoneRegistryEntry[];
|
|
53
|
+
requirements: GSDState["requirements"];
|
|
54
|
+
milestoneProgress: MilestoneProgress;
|
|
55
|
+
sliceProgress?: SliceProgress;
|
|
56
|
+
taskProgress?: TaskProgress;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface DerivedStateOptions {
|
|
60
|
+
blockers?: string[];
|
|
61
|
+
lastCompletedMilestone?: ActiveRef | null;
|
|
62
|
+
includeActiveWorkspace?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function buildProgress(context: DerivedStateContext): NonNullable<GSDState["progress"]> {
|
|
66
|
+
return {
|
|
67
|
+
milestones: context.milestoneProgress,
|
|
68
|
+
...(context.sliceProgress ? { slices: context.sliceProgress } : {}),
|
|
69
|
+
...(context.taskProgress ? { tasks: context.taskProgress } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildDerivedState(
|
|
74
|
+
context: DerivedStateContext,
|
|
75
|
+
phase: Phase,
|
|
76
|
+
nextAction: string,
|
|
77
|
+
options: DerivedStateOptions = {},
|
|
78
|
+
): GSDState {
|
|
79
|
+
return {
|
|
80
|
+
activeMilestone: context.activeMilestone,
|
|
81
|
+
activeSlice: context.activeSlice ?? null,
|
|
82
|
+
activeTask: context.activeTask ?? null,
|
|
83
|
+
phase,
|
|
84
|
+
recentDecisions: [],
|
|
85
|
+
blockers: options.blockers ?? [],
|
|
86
|
+
nextAction,
|
|
87
|
+
...(options.lastCompletedMilestone !== undefined
|
|
88
|
+
? { lastCompletedMilestone: options.lastCompletedMilestone }
|
|
89
|
+
: {}),
|
|
90
|
+
...(options.includeActiveWorkspace ? { activeWorkspace: undefined } : {}),
|
|
91
|
+
registry: context.registry,
|
|
92
|
+
requirements: context.requirements,
|
|
93
|
+
progress: buildProgress(context),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
44
97
|
function stripMilestonePrefix(title: string): string {
|
|
45
98
|
return title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '') || title;
|
|
46
99
|
}
|
|
@@ -182,58 +235,47 @@ function handleNoActiveMilestone(
|
|
|
182
235
|
const pendingEntries = registry.filter(e => e.status === 'pending');
|
|
183
236
|
const parkedEntries = registry.filter(e => e.status === 'parked');
|
|
184
237
|
|
|
238
|
+
const context: DerivedStateContext = {
|
|
239
|
+
activeMilestone: null,
|
|
240
|
+
registry,
|
|
241
|
+
requirements,
|
|
242
|
+
milestoneProgress,
|
|
243
|
+
};
|
|
244
|
+
|
|
185
245
|
if (pendingEntries.length > 0) {
|
|
186
246
|
const blockerDetails = pendingEntries
|
|
187
247
|
.filter(e => e.dependsOn && e.dependsOn.length > 0)
|
|
188
248
|
.map(e => `${e.id} is waiting on unmet deps: ${e.dependsOn!.join(', ')}`);
|
|
189
|
-
return {
|
|
190
|
-
|
|
191
|
-
phase: 'blocked',
|
|
192
|
-
recentDecisions: [], blockers: blockerDetails.length > 0
|
|
249
|
+
return buildDerivedState(context, 'blocked', 'Resolve milestone dependencies before proceeding.', {
|
|
250
|
+
blockers: blockerDetails.length > 0
|
|
193
251
|
? blockerDetails
|
|
194
252
|
: ['All remaining milestones are dep-blocked but no deps listed — check CONTEXT.md files'],
|
|
195
|
-
|
|
196
|
-
registry, requirements,
|
|
197
|
-
progress: { milestones: milestoneProgress },
|
|
198
|
-
};
|
|
253
|
+
});
|
|
199
254
|
}
|
|
200
255
|
|
|
201
256
|
if (parkedEntries.length > 0) {
|
|
202
257
|
const parkedIds = parkedEntries.map(e => e.id).join(', ');
|
|
203
|
-
return
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
registry, requirements,
|
|
209
|
-
progress: { milestones: milestoneProgress },
|
|
210
|
-
};
|
|
258
|
+
return buildDerivedState(
|
|
259
|
+
context,
|
|
260
|
+
'pre-planning',
|
|
261
|
+
`All remaining milestones are parked (${parkedIds}). Run /gsd unpark <id> or create a new milestone.`,
|
|
262
|
+
);
|
|
211
263
|
}
|
|
212
264
|
|
|
213
265
|
if (registry.length === 0) {
|
|
214
|
-
return
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
registry: [], requirements,
|
|
220
|
-
progress: { milestones: { done: 0, total: 0 } },
|
|
221
|
-
};
|
|
266
|
+
return buildDerivedState(
|
|
267
|
+
{ ...context, registry: [], milestoneProgress: { done: 0, total: 0 } },
|
|
268
|
+
'pre-planning',
|
|
269
|
+
'No milestones found. Run /gsd to create one.',
|
|
270
|
+
);
|
|
222
271
|
}
|
|
223
272
|
|
|
224
273
|
const lastEntry = registry[registry.length - 1];
|
|
225
274
|
const unmappedActive = countUnmappedActiveRequirements();
|
|
226
275
|
const completionNote = formatCompletePhaseNextAction(unmappedActive);
|
|
227
|
-
return {
|
|
228
|
-
activeMilestone: null,
|
|
276
|
+
return buildDerivedState(context, 'complete', completionNote, {
|
|
229
277
|
lastCompletedMilestone: lastEntry ? { id: lastEntry.id, title: lastEntry.title } : null,
|
|
230
|
-
|
|
231
|
-
phase: 'complete',
|
|
232
|
-
recentDecisions: [], blockers: [],
|
|
233
|
-
nextAction: completionNote,
|
|
234
|
-
registry, requirements,
|
|
235
|
-
progress: { milestones: milestoneProgress },
|
|
236
|
-
};
|
|
278
|
+
});
|
|
237
279
|
}
|
|
238
280
|
|
|
239
281
|
async function handleAllSlicesDone(
|
|
@@ -248,52 +290,48 @@ async function handleAllSlicesDone(
|
|
|
248
290
|
const verdict = typeof validation?.status === "string" ? validation.status : undefined;
|
|
249
291
|
const validationTerminal = verdict != null && verdict !== "";
|
|
250
292
|
|
|
293
|
+
const context: DerivedStateContext = {
|
|
294
|
+
activeMilestone,
|
|
295
|
+
registry,
|
|
296
|
+
requirements,
|
|
297
|
+
milestoneProgress,
|
|
298
|
+
sliceProgress,
|
|
299
|
+
};
|
|
300
|
+
|
|
251
301
|
if (!validationTerminal) {
|
|
252
|
-
return
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
registry, requirements,
|
|
258
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
259
|
-
};
|
|
302
|
+
return buildDerivedState(
|
|
303
|
+
context,
|
|
304
|
+
'validating-milestone',
|
|
305
|
+
`Validate milestone ${activeMilestone.id} before completion.`,
|
|
306
|
+
);
|
|
260
307
|
}
|
|
261
308
|
|
|
262
309
|
// All roadmap slices are done (enforced by caller) and verdict is
|
|
263
310
|
// needs-remediation — remediation cannot progress without new slices.
|
|
264
311
|
// Return blocked instead of re-dispatching validate-milestone (#4506).
|
|
265
312
|
if (verdict === 'needs-attention') {
|
|
266
|
-
return
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
blockers: [formatNeedsAttentionBlocker(activeMilestone.id)],
|
|
271
|
-
|
|
272
|
-
registry, requirements,
|
|
273
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
274
|
-
};
|
|
313
|
+
return buildDerivedState(
|
|
314
|
+
context,
|
|
315
|
+
'blocked',
|
|
316
|
+
`Resolve ${activeMilestone.id} validation attention before proceeding.`,
|
|
317
|
+
{ blockers: [formatNeedsAttentionBlocker(activeMilestone.id)] },
|
|
318
|
+
);
|
|
275
319
|
}
|
|
276
320
|
|
|
277
321
|
if (verdict === 'needs-remediation') {
|
|
278
|
-
return
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
blockers: [formatNeedsRemediationBlocker(activeMilestone.id)],
|
|
283
|
-
|
|
284
|
-
registry, requirements,
|
|
285
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
286
|
-
};
|
|
322
|
+
return buildDerivedState(
|
|
323
|
+
context,
|
|
324
|
+
'blocked',
|
|
325
|
+
`Resolve ${activeMilestone.id} remediation before proceeding.`,
|
|
326
|
+
{ blockers: [formatNeedsRemediationBlocker(activeMilestone.id)] },
|
|
327
|
+
);
|
|
287
328
|
}
|
|
288
329
|
|
|
289
|
-
return
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
registry, requirements,
|
|
295
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
296
|
-
};
|
|
330
|
+
return buildDerivedState(
|
|
331
|
+
context,
|
|
332
|
+
'completing-milestone',
|
|
333
|
+
`All slices complete in ${activeMilestone.id}. Write milestone summary.`,
|
|
334
|
+
);
|
|
297
335
|
}
|
|
298
336
|
|
|
299
337
|
function resolveSliceDependencies(activeMilestoneSlices: SliceRow[]): { activeSlice: ActiveRef | null, activeSliceRow: SliceRow | null } {
|
|
@@ -356,13 +394,16 @@ export async function deriveStateFromDb(
|
|
|
356
394
|
: allMilestones;
|
|
357
395
|
|
|
358
396
|
if (milestones.length === 0) {
|
|
359
|
-
return
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
397
|
+
return buildDerivedState(
|
|
398
|
+
{
|
|
399
|
+
activeMilestone: null,
|
|
400
|
+
registry: [],
|
|
401
|
+
requirements,
|
|
402
|
+
milestoneProgress: { done: 0, total: 0 },
|
|
403
|
+
},
|
|
404
|
+
'pre-planning',
|
|
405
|
+
'No milestones found. Run /gsd to create one.',
|
|
406
|
+
);
|
|
366
407
|
}
|
|
367
408
|
|
|
368
409
|
const { completeMilestoneIds, parkedMilestoneIds } = buildCompletenessSet(basePath, milestones);
|
|
@@ -384,12 +425,11 @@ export async function deriveStateFromDb(
|
|
|
384
425
|
const nextAction = activeMilestoneHasDraft
|
|
385
426
|
? `Discuss draft context for milestone ${activeMilestone.id}.`
|
|
386
427
|
: `Plan milestone ${activeMilestone.id}.`;
|
|
387
|
-
return
|
|
388
|
-
activeMilestone,
|
|
389
|
-
phase,
|
|
390
|
-
nextAction,
|
|
391
|
-
|
|
392
|
-
};
|
|
428
|
+
return buildDerivedState(
|
|
429
|
+
{ activeMilestone, registry, requirements, milestoneProgress },
|
|
430
|
+
phase,
|
|
431
|
+
nextAction,
|
|
432
|
+
);
|
|
393
433
|
}
|
|
394
434
|
|
|
395
435
|
const allSlicesDone = activeMilestoneSlices.every(s => isStatusDone(s.status));
|
|
@@ -397,6 +437,13 @@ export async function deriveStateFromDb(
|
|
|
397
437
|
done: activeMilestoneSlices.filter(s => isStatusDone(s.status)).length,
|
|
398
438
|
total: activeMilestoneSlices.length,
|
|
399
439
|
};
|
|
440
|
+
const sliceStateContext: DerivedStateContext = {
|
|
441
|
+
activeMilestone,
|
|
442
|
+
registry,
|
|
443
|
+
requirements,
|
|
444
|
+
milestoneProgress,
|
|
445
|
+
sliceProgress,
|
|
446
|
+
};
|
|
400
447
|
|
|
401
448
|
if (allSlicesDone) {
|
|
402
449
|
return handleAllSlicesDone(basePath, activeMilestone, registry, requirements, milestoneProgress, sliceProgress);
|
|
@@ -407,21 +454,19 @@ export async function deriveStateFromDb(
|
|
|
407
454
|
// If locked slice wasn't found, it returns null but logs warning, we need to return 'blocked'
|
|
408
455
|
const sliceLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_SLICE_LOCK : undefined;
|
|
409
456
|
if (sliceLock) {
|
|
410
|
-
return
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
};
|
|
457
|
+
return buildDerivedState(
|
|
458
|
+
sliceStateContext,
|
|
459
|
+
'blocked',
|
|
460
|
+
'Slice lock references a non-existent slice — check orchestrator dispatch.',
|
|
461
|
+
{ blockers: [`GSD_SLICE_LOCK=${sliceLock} not found in active milestone slices`] },
|
|
462
|
+
);
|
|
417
463
|
}
|
|
418
|
-
return
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
};
|
|
464
|
+
return buildDerivedState(
|
|
465
|
+
sliceStateContext,
|
|
466
|
+
'blocked',
|
|
467
|
+
'Resolve dependency blockers or plan next slice.',
|
|
468
|
+
{ blockers: ['No slice eligible — check dependency ordering'] },
|
|
469
|
+
);
|
|
425
470
|
}
|
|
426
471
|
const { activeSlice } = activeSliceContext;
|
|
427
472
|
const activeSliceRow = activeSliceContext.activeSliceRow;
|
|
@@ -432,13 +477,11 @@ export async function deriveStateFromDb(
|
|
|
432
477
|
// PLAN.md and preference flags are projections/configuration and are
|
|
433
478
|
// deliberately not used to infer whether the slice itself is a sketch.
|
|
434
479
|
if (activeSliceRow?.is_sketch === 1) {
|
|
435
|
-
return
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
441
|
-
};
|
|
480
|
+
return buildDerivedState(
|
|
481
|
+
{ ...sliceStateContext, activeSlice },
|
|
482
|
+
'refining',
|
|
483
|
+
`Refine sketch slice ${activeSlice.id} (${activeSlice.title}) using prior slice context.`,
|
|
484
|
+
);
|
|
442
485
|
}
|
|
443
486
|
|
|
444
487
|
const tasks = getSliceTasks(activeMilestone.id, activeSlice.id);
|
|
@@ -447,30 +490,35 @@ export async function deriveStateFromDb(
|
|
|
447
490
|
done: tasks.filter(t => isStatusDone(t.status)).length,
|
|
448
491
|
total: tasks.length,
|
|
449
492
|
};
|
|
493
|
+
const taskStateContext: DerivedStateContext = {
|
|
494
|
+
...sliceStateContext,
|
|
495
|
+
activeSlice,
|
|
496
|
+
taskProgress,
|
|
497
|
+
};
|
|
450
498
|
|
|
451
499
|
const activeTaskRow = tasks.find(t => !isStatusDone(t.status));
|
|
452
500
|
|
|
453
501
|
if (!activeTaskRow && tasks.length > 0) {
|
|
454
|
-
return
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
460
|
-
};
|
|
502
|
+
return buildDerivedState(
|
|
503
|
+
taskStateContext,
|
|
504
|
+
'summarizing',
|
|
505
|
+
`All tasks done in ${activeSlice.id}. Write slice summary and complete slice.`,
|
|
506
|
+
);
|
|
461
507
|
}
|
|
462
508
|
|
|
463
509
|
if (!activeTaskRow) {
|
|
464
|
-
return
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
470
|
-
};
|
|
510
|
+
return buildDerivedState(
|
|
511
|
+
taskStateContext,
|
|
512
|
+
'planning',
|
|
513
|
+
`Slice ${activeSlice.id} has no DB tasks. Plan slice tasks before execution.`,
|
|
514
|
+
);
|
|
471
515
|
}
|
|
472
516
|
|
|
473
517
|
const activeTask: ActiveRef = { id: activeTaskRow.id, title: activeTaskRow.title };
|
|
518
|
+
const activeTaskStateContext: DerivedStateContext = {
|
|
519
|
+
...taskStateContext,
|
|
520
|
+
activeTask,
|
|
521
|
+
};
|
|
474
522
|
|
|
475
523
|
// ── Quality gate evaluation check ──────────────────────────────────
|
|
476
524
|
// Pause before execution only when gates owned by the `gate-evaluate`
|
|
@@ -485,28 +533,26 @@ export async function deriveStateFromDb(
|
|
|
485
533
|
"gate-evaluate",
|
|
486
534
|
);
|
|
487
535
|
if (pendingGateCount > 0) {
|
|
488
|
-
return
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
494
|
-
};
|
|
536
|
+
return buildDerivedState(
|
|
537
|
+
taskStateContext,
|
|
538
|
+
'evaluating-gates',
|
|
539
|
+
`Evaluate ${pendingGateCount} quality gate(s) for ${activeSlice.id} before execution.`,
|
|
540
|
+
);
|
|
495
541
|
}
|
|
496
542
|
|
|
497
543
|
const blockerTaskId = await detectBlockers(basePath, activeMilestone.id, activeSlice.id, tasks);
|
|
498
544
|
if (blockerTaskId) {
|
|
499
545
|
const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
|
|
500
546
|
if (replanHistory.length === 0) {
|
|
501
|
-
return
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
547
|
+
return buildDerivedState(
|
|
548
|
+
activeTaskStateContext,
|
|
549
|
+
'replanning-slice',
|
|
550
|
+
`Task ${blockerTaskId} reported blocker_discovered. Replan slice ${activeSlice.id} before continuing.`,
|
|
551
|
+
{
|
|
552
|
+
blockers: [`Task ${blockerTaskId} discovered a blocker requiring slice replan`],
|
|
553
|
+
includeActiveWorkspace: true,
|
|
554
|
+
},
|
|
555
|
+
);
|
|
510
556
|
}
|
|
511
557
|
}
|
|
512
558
|
|
|
@@ -522,15 +568,15 @@ export async function deriveStateFromDb(
|
|
|
522
568
|
// and the user's prior resolution never lands.
|
|
523
569
|
const escalatingTaskId = detectPendingEscalation(tasks, basePath);
|
|
524
570
|
if (escalatingTaskId) {
|
|
525
|
-
return
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
571
|
+
return buildDerivedState(
|
|
572
|
+
activeTaskStateContext,
|
|
573
|
+
'escalating-task',
|
|
574
|
+
`Run /gsd escalate show ${escalatingTaskId} to review, then /gsd escalate resolve ${escalatingTaskId} <choice> to proceed.`,
|
|
575
|
+
{
|
|
576
|
+
blockers: [`Task ${escalatingTaskId} requires a user decision before the loop can proceed`],
|
|
577
|
+
includeActiveWorkspace: true,
|
|
578
|
+
},
|
|
579
|
+
);
|
|
534
580
|
}
|
|
535
581
|
|
|
536
582
|
if (!blockerTaskId) {
|
|
@@ -538,24 +584,22 @@ export async function deriveStateFromDb(
|
|
|
538
584
|
if (isTriggered) {
|
|
539
585
|
const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
|
|
540
586
|
if (replanHistory.length === 0) {
|
|
541
|
-
return
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
587
|
+
return buildDerivedState(
|
|
588
|
+
activeTaskStateContext,
|
|
589
|
+
'replanning-slice',
|
|
590
|
+
`Triage replan triggered for slice ${activeSlice.id}. Replan before continuing.`,
|
|
591
|
+
{
|
|
592
|
+
blockers: ['Triage replan trigger detected — slice replan required'],
|
|
593
|
+
includeActiveWorkspace: true,
|
|
594
|
+
},
|
|
595
|
+
);
|
|
550
596
|
}
|
|
551
597
|
}
|
|
552
598
|
}
|
|
553
599
|
|
|
554
|
-
return
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
560
|
-
};
|
|
600
|
+
return buildDerivedState(
|
|
601
|
+
activeTaskStateContext,
|
|
602
|
+
'executing',
|
|
603
|
+
`Execute ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}.`,
|
|
604
|
+
);
|
|
561
605
|
}
|