@opengsd/gsd-pi 1.5.0-dev.553dc518 → 1.5.0-dev.c4c8885f
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/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +1 -1
- package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
- package/dist/resources/extensions/gsd/activity-log.js +1 -1
- package/dist/resources/extensions/gsd/auto/orchestrator.js +16 -10
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +7 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
- package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
- package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
- package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
- package/dist/resources/extensions/gsd/auto-start.js +54 -31
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
- package/dist/resources/extensions/gsd/auto-timers.js +9 -2
- package/dist/resources/extensions/gsd/auto.js +97 -31
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +67 -6
- package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
- package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
- package/dist/resources/extensions/gsd/config-overlay.js +7 -2
- package/dist/resources/extensions/gsd/db/engine.js +33 -0
- package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
- package/dist/resources/extensions/gsd/db-adapter.js +30 -3
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/dist/resources/extensions/gsd/flat-phase-migration.js +18 -0
- package/dist/resources/extensions/gsd/gsd-db.js +12 -11
- package/dist/resources/extensions/gsd/guided-flow.js +16 -7
- package/dist/resources/extensions/gsd/journal.js +1 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +34 -91
- package/dist/resources/extensions/gsd/md-importer.js +89 -23
- package/dist/resources/extensions/gsd/metrics.js +2 -2
- package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
- package/dist/resources/extensions/gsd/paths.js +87 -52
- package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
- package/dist/resources/extensions/gsd/preferences-models.js +66 -15
- package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
- package/dist/resources/extensions/gsd/preferences-validation.js +66 -10
- package/dist/resources/extensions/gsd/preferences.js +20 -0
- package/dist/resources/extensions/gsd/rule-registry.js +106 -10
- package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
- package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
- package/dist/resources/extensions/gsd/uok/audit.js +3 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
- package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
- package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
- package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
- package/dist/resources/extensions/gsd/workspace.js +5 -14
- package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
- package/dist/resources/extensions/shared/interview-ui.js +62 -9
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/worktree-cli-create.d.ts +10 -0
- package/dist/worktree-cli-create.js +11 -0
- package/dist/worktree-cli-format.d.ts +12 -0
- package/dist/worktree-cli-format.js +38 -0
- package/dist/worktree-cli-plan.d.ts +16 -0
- package/dist/worktree-cli-plan.js +19 -0
- package/dist/worktree-cli-session.d.ts +13 -0
- package/dist/worktree-cli-session.js +18 -0
- package/dist/worktree-cli-status.d.ts +35 -0
- package/dist/worktree-cli-status.js +54 -0
- package/dist/worktree-cli.d.ts +1 -16
- package/dist/worktree-cli.js +28 -122
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
- package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-agent.js +113 -0
- package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
- package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
- package/packages/daemon/dist/orchestrator-tools.js +137 -0
- package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
- package/packages/daemon/dist/orchestrator.d.ts +4 -56
- package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
- package/packages/daemon/dist/orchestrator.js +13 -303
- package/packages/daemon/dist/orchestrator.js.map +1 -1
- package/packages/daemon/dist/orchestrator.test.js +11 -1
- package/packages/daemon/dist/orchestrator.test.js.map +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- 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/package.json +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/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +1 -1
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
- package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
- package/src/resources/extensions/gsd/activity-log.ts +1 -1
- package/src/resources/extensions/gsd/auto/orchestrator.ts +17 -11
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +9 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
- package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
- package/src/resources/extensions/gsd/auto-start.ts +58 -29
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
- package/src/resources/extensions/gsd/auto-timers.ts +9 -2
- package/src/resources/extensions/gsd/auto.ts +103 -30
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +66 -6
- package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
- package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
- package/src/resources/extensions/gsd/config-overlay.ts +7 -1
- package/src/resources/extensions/gsd/db/engine.ts +36 -0
- package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
- package/src/resources/extensions/gsd/db-adapter.ts +29 -3
- package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
- package/src/resources/extensions/gsd/flat-phase-migration.ts +20 -0
- package/src/resources/extensions/gsd/gsd-db.ts +20 -11
- package/src/resources/extensions/gsd/guided-flow.ts +19 -7
- package/src/resources/extensions/gsd/journal.ts +1 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +52 -103
- package/src/resources/extensions/gsd/md-importer.ts +93 -22
- package/src/resources/extensions/gsd/metrics.ts +2 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
- package/src/resources/extensions/gsd/paths.ts +108 -51
- package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
- package/src/resources/extensions/gsd/preferences-models.ts +74 -20
- package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
- package/src/resources/extensions/gsd/preferences-types.ts +24 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +77 -9
- package/src/resources/extensions/gsd/preferences.ts +20 -0
- package/src/resources/extensions/gsd/rule-registry.ts +111 -9
- package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
- package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
- package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
- package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
- package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
- package/src/resources/extensions/gsd/types.ts +23 -4
- package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
- package/src/resources/extensions/gsd/uok/audit.ts +2 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
- package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
- package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
- package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
- package/src/resources/extensions/gsd/workspace.ts +5 -21
- package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
- package/src/resources/extensions/shared/interview-ui.ts +58 -11
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
- /package/dist/web/standalone/.next/static/{ZpFDazP-38PXBPiI_LdZf → NPMNi2HV8BuK3baQsEUhk}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ZpFDazP-38PXBPiI_LdZf → NPMNi2HV8BuK3baQsEUhk}/_ssgManifest.js +0 -0
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { readdirSync, existsSync, realpathSync, statSync, Dirent } from "node:fs";
|
|
14
|
-
import { join, dirname, normalize, resolve } from "node:path";
|
|
14
|
+
import { join, dirname, normalize, relative, resolve } from "node:path";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
import { spawnSync } from "node:child_process";
|
|
17
17
|
import { nativeScanGsdTree, type GsdTreeEntry } from "./native-parser-bridge.js";
|
|
@@ -379,21 +379,26 @@ export function resolveGsdPathContract(
|
|
|
379
379
|
const resolvedWorkRoot = resolve(workRoot || process.cwd());
|
|
380
380
|
const isWorktree = isGsdWorktreePath(resolvedWorkRoot);
|
|
381
381
|
if (isWorktree && !originalProjectRoot?.trim()) {
|
|
382
|
-
const
|
|
383
|
-
if (
|
|
382
|
+
const rawProjectGsd = resolveExternalStateProjectGsdFromWorktreePath(resolvedWorkRoot);
|
|
383
|
+
if (rawProjectGsd) {
|
|
384
|
+
// Canonicalize the `.gsd` root so the DB path matches what every other
|
|
385
|
+
// accessor (gsdRoot/gsdProjectionRoot) returns — otherwise an unresolved
|
|
386
|
+
// symlink (e.g. `/mnt/c/.../.gsd` → native ext4 on WSL) selects the wrong
|
|
387
|
+
// journal mode and yields a fragile, move-prone handle. See issue #1239.
|
|
388
|
+
const projectGsd = normalizeRealPath(rawProjectGsd);
|
|
384
389
|
return {
|
|
385
390
|
projectRoot: dirname(dirname(projectGsd)),
|
|
386
391
|
workRoot: resolvedWorkRoot,
|
|
387
392
|
projectGsd,
|
|
388
|
-
worktreeGsd: join(resolvedWorkRoot, ".gsd"),
|
|
393
|
+
worktreeGsd: normalizeRealPath(join(resolvedWorkRoot, ".gsd")),
|
|
389
394
|
projectDb: join(projectGsd, "gsd.db"),
|
|
390
395
|
isWorktree,
|
|
391
396
|
};
|
|
392
397
|
}
|
|
393
398
|
}
|
|
394
399
|
const projectRoot = resolve(resolveWorktreeProjectRoot(resolvedWorkRoot, originalProjectRoot));
|
|
395
|
-
const projectGsd = join(projectRoot, ".gsd");
|
|
396
|
-
const worktreeGsd = isWorktree ? join(resolvedWorkRoot, ".gsd") : null;
|
|
400
|
+
const projectGsd = normalizeRealPath(join(projectRoot, ".gsd"));
|
|
401
|
+
const worktreeGsd = isWorktree ? normalizeRealPath(join(resolvedWorkRoot, ".gsd")) : null;
|
|
397
402
|
|
|
398
403
|
return {
|
|
399
404
|
projectRoot,
|
|
@@ -696,7 +701,16 @@ function pickPreferredPhaseDir(phasesDir: string, matches: string[]): string {
|
|
|
696
701
|
return best;
|
|
697
702
|
}
|
|
698
703
|
|
|
699
|
-
function
|
|
704
|
+
function slugLooksLikeTeamSuffixProjection(slugPart: string): boolean {
|
|
705
|
+
return /^[a-z0-9]{6}(-|$)/.test(slugPart);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function phaseDirMatchesMilestoneId(
|
|
709
|
+
dirName: string,
|
|
710
|
+
milestoneId: string,
|
|
711
|
+
phaseNum: number,
|
|
712
|
+
allowTeamSuffixSlugs = false,
|
|
713
|
+
): boolean {
|
|
700
714
|
const numMatch = dirName.match(/^(\d+)-(.*)$/);
|
|
701
715
|
if (!numMatch || parseInt(numMatch[1]!, 10) !== phaseNum) return false;
|
|
702
716
|
const slugPart = numMatch[2]!;
|
|
@@ -704,8 +718,8 @@ function phaseDirMatchesMilestoneId(dirName: string, milestoneId: string, phaseN
|
|
|
704
718
|
if (suffix) {
|
|
705
719
|
return slugPart === suffix || slugPart.startsWith(`${suffix}-`);
|
|
706
720
|
}
|
|
707
|
-
|
|
708
|
-
return
|
|
721
|
+
if (slugLooksLikeTeamSuffixProjection(slugPart) && !allowTeamSuffixSlugs) return false;
|
|
722
|
+
return true;
|
|
709
723
|
}
|
|
710
724
|
|
|
711
725
|
function resolvePhaseDir(basePath: string, milestoneId: string): string | null {
|
|
@@ -726,6 +740,15 @@ function resolvePhaseDir(basePath: string, milestoneId: string): string | null {
|
|
|
726
740
|
matches.push(entry.name);
|
|
727
741
|
}
|
|
728
742
|
}
|
|
743
|
+
// Bare milestone ids may only have a suffixed team-mode projection on disk.
|
|
744
|
+
if (matches.length === 0 && !milestoneIdUniqueSuffix(milestoneId)) {
|
|
745
|
+
for (const entry of readdirSync(phasesDir, { withFileTypes: true })) {
|
|
746
|
+
if (!entry.isDirectory()) continue;
|
|
747
|
+
if (phaseDirMatchesMilestoneId(entry.name, milestoneId, phaseNum, true)) {
|
|
748
|
+
matches.push(entry.name);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
729
752
|
} catch {
|
|
730
753
|
// unreadable — fall through
|
|
731
754
|
}
|
|
@@ -898,10 +921,24 @@ export function resolveTaskFile(
|
|
|
898
921
|
basePath: string, milestoneId: string, sliceId: string,
|
|
899
922
|
taskId: string, suffix: string
|
|
900
923
|
): string | null {
|
|
924
|
+
const phaseDir = resolveMilestonePath(basePath, milestoneId);
|
|
925
|
+
if (!phaseDir) return null;
|
|
926
|
+
|
|
927
|
+
const legacyBase = legacyMilestonesDir(basePath);
|
|
928
|
+
const isLegacy = phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\");
|
|
929
|
+
|
|
930
|
+
if (suffix !== "PLAN" && !isLegacy) {
|
|
931
|
+
const flatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
|
|
932
|
+
return existsSync(flatPath) ? flatPath : null;
|
|
933
|
+
}
|
|
934
|
+
|
|
901
935
|
const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
|
|
902
|
-
if (
|
|
903
|
-
|
|
904
|
-
|
|
936
|
+
if (tDir) {
|
|
937
|
+
const file = resolveFile(tDir, taskId, suffix);
|
|
938
|
+
if (file) return join(tDir, file);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
return null;
|
|
905
942
|
}
|
|
906
943
|
|
|
907
944
|
// ─── Relative Path Builders (for prompts — .gsd/milestones/...) ────────────
|
|
@@ -936,31 +973,41 @@ export function relMilestonePath(basePath: string, milestoneId: string, title?:
|
|
|
936
973
|
}
|
|
937
974
|
|
|
938
975
|
/**
|
|
939
|
-
* Build
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
* name when the file doesn't exist yet.
|
|
976
|
+
* Build the canonical absolute write target for a milestone file.
|
|
977
|
+
* Existing compatibility filenames are intentionally ignored; readers that need
|
|
978
|
+
* to preserve an existing file should call resolveMilestoneFile first.
|
|
943
979
|
*/
|
|
944
|
-
export function
|
|
945
|
-
basePath: string, milestoneId: string, suffix: string
|
|
980
|
+
export function targetMilestoneFile(
|
|
981
|
+
basePath: string, milestoneId: string, suffix: string, title?: string
|
|
946
982
|
): string {
|
|
947
|
-
const mRel = relMilestonePath(basePath, milestoneId);
|
|
948
|
-
// resolveMilestoneFile checks NN-SUFFIX.md (flat-phase) and MID-SUFFIX.md (legacy).
|
|
949
|
-
const absFile = resolveMilestoneFile(basePath, milestoneId, suffix);
|
|
950
|
-
if (absFile) {
|
|
951
|
-
const fileName = absFile.split(/[/\\]/).pop()!;
|
|
952
|
-
return `${mRel}/${fileName}`;
|
|
953
|
-
}
|
|
954
|
-
// File doesn't exist yet — use layout-aware fallback filename.
|
|
955
983
|
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
956
984
|
const legacyBase = legacyMilestonesDir(basePath);
|
|
957
985
|
const isLegacy = mDir
|
|
958
986
|
? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
|
|
959
|
-
:
|
|
987
|
+
: isLegacyMilestonesLayout(basePath);
|
|
988
|
+
const dir = mDir ?? join(
|
|
989
|
+
isLegacy ? legacyBase : milestonesDir(basePath),
|
|
990
|
+
isLegacy ? milestoneId : canonicalPhaseDirName(milestoneId, title),
|
|
991
|
+
);
|
|
960
992
|
const fileName = isLegacy
|
|
961
993
|
? `${milestoneId}-${suffix}.md`
|
|
962
994
|
: `${String(milestoneIdToPhaseNum(milestoneId)).padStart(2, "0")}-${suffix}.md`;
|
|
963
|
-
return
|
|
995
|
+
return join(dir, fileName);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Build relative .gsd/ path to a milestone file.
|
|
1000
|
+
* Preserves an existing compatibility filename when present; otherwise falls
|
|
1001
|
+
* back to the canonical write target.
|
|
1002
|
+
*/
|
|
1003
|
+
export function relMilestoneFile(
|
|
1004
|
+
basePath: string, milestoneId: string, suffix: string, title?: string
|
|
1005
|
+
): string {
|
|
1006
|
+
const rel = relative(
|
|
1007
|
+
gsdProjectionRoot(basePath),
|
|
1008
|
+
resolveMilestoneFile(basePath, milestoneId, suffix) ?? targetMilestoneFile(basePath, milestoneId, suffix, title),
|
|
1009
|
+
).replace(/\\/g, "/");
|
|
1010
|
+
return `.gsd/${rel}`;
|
|
964
1011
|
}
|
|
965
1012
|
|
|
966
1013
|
/**
|
|
@@ -992,34 +1039,44 @@ export function relSlicePath(
|
|
|
992
1039
|
}
|
|
993
1040
|
|
|
994
1041
|
/**
|
|
995
|
-
* Build
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
* @param milestoneTitle - Optional milestone title forwarded to relSlicePath /
|
|
999
|
-
* relMilestonePath for title-aware flat-phase fallback dir naming. Only used
|
|
1000
|
-
* when the phase directory does not yet exist on disk.
|
|
1042
|
+
* Build the canonical absolute write target for a slice file.
|
|
1043
|
+
* Existing compatibility filenames are intentionally ignored; readers that need
|
|
1044
|
+
* to preserve an existing file should call resolveSliceFile first.
|
|
1001
1045
|
*/
|
|
1002
|
-
export function
|
|
1046
|
+
export function targetSliceFile(
|
|
1003
1047
|
basePath: string, milestoneId: string, sliceId: string, suffix: string, milestoneTitle?: string
|
|
1004
1048
|
): string {
|
|
1005
|
-
const sRel = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
|
|
1006
|
-
const absPath = resolveSliceFile(basePath, milestoneId, sliceId, suffix);
|
|
1007
|
-
if (absPath) {
|
|
1008
|
-
const fileName = absPath.split(/[/\\]/).pop()!;
|
|
1009
|
-
return `${sRel}/${fileName}`;
|
|
1010
|
-
}
|
|
1011
|
-
// Fallback when file doesn't exist yet — use layout-aware filename.
|
|
1012
1049
|
const mDir = resolveMilestonePath(basePath, milestoneId);
|
|
1013
1050
|
const legacyBase = legacyMilestonesDir(basePath);
|
|
1014
1051
|
const isLegacy = mDir
|
|
1015
1052
|
? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
|
|
1016
|
-
:
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1053
|
+
: isLegacyMilestonesLayout(basePath);
|
|
1054
|
+
const milestoneDir = mDir
|
|
1055
|
+
?? dirname(targetMilestoneFile(basePath, milestoneId, "ROADMAP", milestoneTitle));
|
|
1056
|
+
const slicesDir = join(milestoneDir, "slices");
|
|
1057
|
+
const dir = isLegacy
|
|
1058
|
+
? join(slicesDir, resolveDir(slicesDir, sliceId) ?? sliceId)
|
|
1059
|
+
: milestoneDir;
|
|
1060
|
+
const fileName = isLegacy
|
|
1061
|
+
? `${sliceId}-${suffix}.md`
|
|
1062
|
+
: planFileName(milestoneIdToPhaseNum(milestoneId), sliceIdToPlanNum(sliceId), suffix);
|
|
1063
|
+
return join(dir, fileName);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
/**
|
|
1067
|
+
* Build relative .gsd/ path to a slice file.
|
|
1068
|
+
* Preserves an existing compatibility filename when present; otherwise falls
|
|
1069
|
+
* back to the canonical write target.
|
|
1070
|
+
*/
|
|
1071
|
+
export function relSliceFile(
|
|
1072
|
+
basePath: string, milestoneId: string, sliceId: string, suffix: string, milestoneTitle?: string
|
|
1073
|
+
): string {
|
|
1074
|
+
const rel = relative(
|
|
1075
|
+
gsdProjectionRoot(basePath),
|
|
1076
|
+
resolveSliceFile(basePath, milestoneId, sliceId, suffix)
|
|
1077
|
+
?? targetSliceFile(basePath, milestoneId, sliceId, suffix, milestoneTitle),
|
|
1078
|
+
).replace(/\\/g, "/");
|
|
1079
|
+
return `.gsd/${rel}`;
|
|
1023
1080
|
}
|
|
1024
1081
|
|
|
1025
1082
|
/**
|
|
@@ -1031,7 +1088,7 @@ export function relSliceFile(
|
|
|
1031
1088
|
*/
|
|
1032
1089
|
export function relTaskFile(
|
|
1033
1090
|
basePath: string, milestoneId: string, sliceId: string,
|
|
1034
|
-
taskId: string, suffix: string
|
|
1091
|
+
taskId: string, suffix: string, milestoneTitle?: string
|
|
1035
1092
|
): string {
|
|
1036
1093
|
const sDir = resolveSlicePath(basePath, milestoneId, sliceId);
|
|
1037
1094
|
const phaseDir = resolveMilestonePath(basePath, milestoneId);
|
|
@@ -1044,6 +1101,6 @@ export function relTaskFile(
|
|
|
1044
1101
|
if (suffix === "PLAN") {
|
|
1045
1102
|
return relSliceFile(basePath, milestoneId, sliceId, "PLAN");
|
|
1046
1103
|
}
|
|
1047
|
-
const relS = relSlicePath(basePath, milestoneId, sliceId);
|
|
1104
|
+
const relS = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
|
|
1048
1105
|
return `${relS}/${buildTaskFileName(taskId, suffix)}`;
|
|
1049
1106
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
HookStatusEntry,
|
|
12
12
|
PostUnitGateBlock,
|
|
13
13
|
} from "./types.js";
|
|
14
|
+
import type { SidecarItem } from "./auto/session.js";
|
|
14
15
|
import { getOrCreateRegistry, resolveHookArtifactPath } from "./rule-registry.js";
|
|
15
16
|
|
|
16
17
|
// Re-export resolveHookArtifactPath so existing importers still work.
|
|
@@ -75,6 +76,37 @@ export function restoreHookState(basePath: string): void {
|
|
|
75
76
|
getOrCreateRegistry().restoreState(basePath);
|
|
76
77
|
}
|
|
77
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Reconcile a restored `activeHook` against the session's sidecar queue.
|
|
81
|
+
*
|
|
82
|
+
* The registry persists `activeHook` to disk but the pending hook *dispatch*
|
|
83
|
+
* lives only on the non-persisted `s.sidecarQueue`. After a pause/resume or
|
|
84
|
+
* crash-recovery, `restoreHookState` re-hydrates `activeHook` while the dispatch
|
|
85
|
+
* is gone, so the registry believes a hook is in-flight but nothing will ever
|
|
86
|
+
* complete it — and the next unrelated unit's close-out is falsely charged
|
|
87
|
+
* against the stale hook and blocked. Re-enqueue the missing dispatch so the
|
|
88
|
+
* hook actually runs, restoring the invariant that a persisted `activeHook`
|
|
89
|
+
* always has a live dispatch (#1246).
|
|
90
|
+
*/
|
|
91
|
+
export function reconcileRestoredHookDispatch(
|
|
92
|
+
basePath: string,
|
|
93
|
+
sidecarQueue: SidecarItem[],
|
|
94
|
+
): void {
|
|
95
|
+
const dispatch = getOrCreateRegistry().getPendingHookDispatch(basePath);
|
|
96
|
+
if (!dispatch) return;
|
|
97
|
+
const alreadyQueued = sidecarQueue.some(
|
|
98
|
+
item => item.kind === "hook" && item.unitType === dispatch.unitType,
|
|
99
|
+
);
|
|
100
|
+
if (alreadyQueued) return;
|
|
101
|
+
sidecarQueue.push({
|
|
102
|
+
kind: "hook",
|
|
103
|
+
unitType: dispatch.unitType,
|
|
104
|
+
unitId: dispatch.unitId,
|
|
105
|
+
prompt: dispatch.prompt,
|
|
106
|
+
model: dispatch.model,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
78
110
|
export function clearPersistedHookState(basePath: string): void {
|
|
79
111
|
getOrCreateRegistry().clearPersistedState(basePath);
|
|
80
112
|
}
|
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
GSDModelPhaseKey,
|
|
24
24
|
GSDThinkingConfig,
|
|
25
25
|
ResolvedModelConfig,
|
|
26
|
-
|
|
26
|
+
ResolvedAutoSupervisorConfig,
|
|
27
27
|
} from "./preferences-types.js";
|
|
28
28
|
import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
29
29
|
import { getUnitPhaseChain } from "./unit-registry.js";
|
|
@@ -86,6 +86,40 @@ function resolveWinningPhase(
|
|
|
86
86
|
return undefined;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Normalize a single model field into a {@link ResolvedModelConfig}.
|
|
91
|
+
*
|
|
92
|
+
* Accepts either the legacy bare-string form or the extended object form
|
|
93
|
+
* (`{ model, provider?, fallbacks? }`). This is the shared normalization used
|
|
94
|
+
* for phase buckets so sibling single-model fields — `post_unit_hooks[].model`,
|
|
95
|
+
* `auto_supervisor.model`, and `reactive_execution.subagent_model` — honor
|
|
96
|
+
* `fallbacks[]` identically rather than accepting a bare string only (#1229).
|
|
97
|
+
*
|
|
98
|
+
* Returns undefined for an unset, blank, or model-less field.
|
|
99
|
+
*/
|
|
100
|
+
export function normalizeModelFieldConfig(
|
|
101
|
+
field: string | GSDPhaseModelConfig | undefined,
|
|
102
|
+
): ResolvedModelConfig | undefined {
|
|
103
|
+
if (!field) return undefined;
|
|
104
|
+
if (typeof field === "string") {
|
|
105
|
+
return field.trim() ? { primary: field, fallbacks: [] } : undefined;
|
|
106
|
+
}
|
|
107
|
+
if (!field.model) return undefined;
|
|
108
|
+
// When provider is explicitly set, prepend it to the model ID so the
|
|
109
|
+
// resolution code in auto.ts can do an explicit provider match.
|
|
110
|
+
const primary = field.provider && !field.model.includes("/")
|
|
111
|
+
? `${field.provider}/${field.model}`
|
|
112
|
+
: field.model;
|
|
113
|
+
// Carry the per-field `thinking` sub-field through so the dispatch site can
|
|
114
|
+
// prefer it over the session/floor level, mirroring phase-inline thinking
|
|
115
|
+
// (#1269). `undefined` is preserved as absent so behavior is unchanged.
|
|
116
|
+
return {
|
|
117
|
+
primary,
|
|
118
|
+
fallbacks: field.fallbacks ?? [],
|
|
119
|
+
...(field.thinking ? { thinking: field.thinking } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
89
123
|
/**
|
|
90
124
|
* Resolve model and fallbacks for a given auto-mode unit type.
|
|
91
125
|
* Returns the primary model and ordered fallbacks, or undefined if not configured.
|
|
@@ -93,6 +127,15 @@ function resolveWinningPhase(
|
|
|
93
127
|
* Supports both legacy string format and extended object format:
|
|
94
128
|
* - Legacy: `planning: claude-opus-4-6`
|
|
95
129
|
* - Extended: `planning: { model: claude-opus-4-6, fallbacks: [glm-5, minimax-m2.5] }`
|
|
130
|
+
*
|
|
131
|
+
* Hook unit types (`hook/<name>`) resolve against the matching
|
|
132
|
+
* `post_unit_hooks[]` entry's `model` field so hook sessions honor the same
|
|
133
|
+
* `fallbacks[]` chain as phase buckets — the recovery path can then switch to
|
|
134
|
+
* a fallback provider instead of hard-failing (and potentially pausing) the
|
|
135
|
+
* run on a transient provider trip (#1229).
|
|
136
|
+
*
|
|
137
|
+
* The synthetic `supervisor` unit type resolves against `auto_supervisor.model`
|
|
138
|
+
* for supervisor interventions (wrap-up warnings, timeout recovery).
|
|
96
139
|
*/
|
|
97
140
|
export function resolveModelWithFallbacksForUnit(
|
|
98
141
|
unitType: string,
|
|
@@ -107,27 +150,26 @@ export function resolveModelWithFallbacksForUnit(
|
|
|
107
150
|
...(skipProfileDefaults ? { skipProfileDefaults: true } : {}),
|
|
108
151
|
};
|
|
109
152
|
const prefs = loadEffectiveGSDPreferences(basePath, loadOpts);
|
|
110
|
-
const chain = phaseChainForUnit(unitType);
|
|
111
|
-
if (!chain) return undefined;
|
|
112
|
-
const winner = resolveWinningPhase(prefs?.preferences?.models as GSDModelConfigV2 | undefined, chain);
|
|
113
|
-
if (!winner) return undefined;
|
|
114
|
-
const phaseConfig = winner.config;
|
|
115
153
|
|
|
116
|
-
//
|
|
117
|
-
if (
|
|
118
|
-
return
|
|
154
|
+
// Supervisor interventions resolve against `auto_supervisor.model` (#1229).
|
|
155
|
+
if (unitType === "supervisor") {
|
|
156
|
+
return normalizeModelFieldConfig(prefs?.preferences?.auto_supervisor?.model);
|
|
119
157
|
}
|
|
120
158
|
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
159
|
+
// Hook sessions resolve against their own `post_unit_hooks[].model` field,
|
|
160
|
+
// which now shares the phase-bucket object form (#1229).
|
|
161
|
+
if (unitType.startsWith("hook/")) {
|
|
162
|
+
const hookName = unitType.slice("hook/".length);
|
|
163
|
+
const hooks = prefs?.preferences?.post_unit_hooks;
|
|
164
|
+
const hook = Array.isArray(hooks) ? hooks.find((h) => h.name === hookName) : undefined;
|
|
165
|
+
return normalizeModelFieldConfig(hook?.model);
|
|
166
|
+
}
|
|
126
167
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
168
|
+
const chain = phaseChainForUnit(unitType);
|
|
169
|
+
if (!chain) return undefined;
|
|
170
|
+
const winner = resolveWinningPhase(prefs?.preferences?.models as GSDModelConfigV2 | undefined, chain);
|
|
171
|
+
if (!winner) return undefined;
|
|
172
|
+
return normalizeModelFieldConfig(winner.config);
|
|
131
173
|
}
|
|
132
174
|
|
|
133
175
|
/**
|
|
@@ -157,6 +199,14 @@ export function resolveThinkingLevelForUnit(
|
|
|
157
199
|
basePath?: string,
|
|
158
200
|
availableModelIds?: string[],
|
|
159
201
|
): GSDThinkingLevel | undefined {
|
|
202
|
+
// Single-field configs — `auto_supervisor.model` and `post_unit_hooks[].model`
|
|
203
|
+
// — carry their own inline `thinking` on the object model form and have no
|
|
204
|
+
// phase-bucket chain, so the walk below never covers them. Resolve their
|
|
205
|
+
// per-field level directly (#1269).
|
|
206
|
+
if (unitType === "supervisor" || unitType.startsWith("hook/")) {
|
|
207
|
+
return resolveModelWithFallbacksForUnit(unitType, basePath, availableModelIds)?.thinking;
|
|
208
|
+
}
|
|
209
|
+
|
|
160
210
|
const loadOpts = availableModelIds !== undefined ? { availableModelIds } : undefined;
|
|
161
211
|
const prefs = loadEffectiveGSDPreferences(basePath, loadOpts)?.preferences;
|
|
162
212
|
if (!prefs) return undefined;
|
|
@@ -425,16 +475,20 @@ export function resolveDynamicRoutingConfig(): DynamicRoutingConfig {
|
|
|
425
475
|
};
|
|
426
476
|
}
|
|
427
477
|
|
|
428
|
-
export function resolveAutoSupervisorConfig():
|
|
478
|
+
export function resolveAutoSupervisorConfig(): ResolvedAutoSupervisorConfig {
|
|
429
479
|
const prefs = loadEffectiveGSDPreferences();
|
|
430
480
|
const configured = prefs?.preferences.auto_supervisor ?? {};
|
|
431
481
|
|
|
482
|
+
const modelConfig = normalizeModelFieldConfig(configured.model);
|
|
483
|
+
|
|
432
484
|
return {
|
|
433
485
|
soft_timeout_minutes: configured.soft_timeout_minutes ?? 20,
|
|
434
486
|
idle_timeout_minutes: configured.idle_timeout_minutes ?? 10,
|
|
435
487
|
hard_timeout_minutes: configured.hard_timeout_minutes ?? 30,
|
|
436
488
|
stalled_tool_timeout_minutes: configured.stalled_tool_timeout_minutes ?? 5,
|
|
437
|
-
...(
|
|
489
|
+
...(modelConfig
|
|
490
|
+
? { model: modelConfig.primary, modelFallbacks: modelConfig.fallbacks }
|
|
491
|
+
: {}),
|
|
438
492
|
};
|
|
439
493
|
}
|
|
440
494
|
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* to absolute filesystem paths, plus skill discovery and staleness config.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { existsSync, readdirSync } from "node:fs";
|
|
8
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { isAbsolute, join } from "node:path";
|
|
11
|
+
import { getSkillDirectories } from "@gsd/pi-coding-agent";
|
|
11
12
|
import { gsdHome } from "./gsd-home.js";
|
|
12
|
-
import { statSync } from "node:fs";
|
|
13
13
|
|
|
14
14
|
import type {
|
|
15
15
|
GSDPreferences,
|
|
@@ -25,26 +25,20 @@ export type { GSDSkillRule, SkillDiscoveryMode, SkillResolution, SkillResolution
|
|
|
25
25
|
/**
|
|
26
26
|
* Known skill directories for **preference reference resolution** (bare skill names).
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* 4. ~/.claude/skills/ and .claude/skills/ (Claude Code compatibility)
|
|
28
|
+
* Sourced from the shared taxonomy (`@gsd/pi-coding-agent` `getSkillDirectories`)
|
|
29
|
+
* so preference resolution, mid-session discovery, and the PackageManager
|
|
30
|
+
* catalog all agree on which directories exist. The `method` is derived from
|
|
31
|
+
* each entry's scope.
|
|
33
32
|
*
|
|
34
33
|
* Note: the ResourceLoader catalog uses PackageManager precedence instead —
|
|
35
34
|
* project `.gsd/skills` and `.agents/skills` can override bundled GSD skills
|
|
36
35
|
* on name collision. See docs/dev/what-is-pi/09-the-customization-stack.md.
|
|
37
36
|
*/
|
|
38
37
|
export function getSkillSearchDirs(cwd: string): Array<{ dir: string; method: SkillResolution["method"] }> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// Claude Code official skill directories
|
|
44
|
-
{ dir: join(homedir(), ".claude", "skills"), method: "user-skill" },
|
|
45
|
-
{ dir: join(cwd, ".claude", "skills"), method: "project-skill" },
|
|
46
|
-
];
|
|
47
|
-
return dirs;
|
|
38
|
+
return getSkillDirectories({ cwd, gsdHome: gsdHome() }).map((entry) => ({
|
|
39
|
+
dir: entry.path,
|
|
40
|
+
method: entry.scope === "project" ? "project-skill" : "user-skill",
|
|
41
|
+
}));
|
|
48
42
|
}
|
|
49
43
|
|
|
50
44
|
/**
|
|
@@ -312,12 +312,24 @@ export interface GSDModelConfigV2 {
|
|
|
312
312
|
export interface ResolvedModelConfig {
|
|
313
313
|
primary: string;
|
|
314
314
|
fallbacks: string[];
|
|
315
|
+
/**
|
|
316
|
+
* Per-field reasoning level carried from the object model form's `thinking`
|
|
317
|
+
* sub-field (e.g. `{ model, thinking: high }` on `post_unit_hooks[].model`,
|
|
318
|
+
* `auto_supervisor.model`, or `reactive_execution.subagent_model`). Applied at
|
|
319
|
+
* the dispatch site in preference to the session/floor level (#1269).
|
|
320
|
+
*/
|
|
321
|
+
thinking?: GSDThinkingLevel;
|
|
315
322
|
}
|
|
316
323
|
|
|
317
324
|
export type SkillDiscoveryMode = "auto" | "suggest" | "off";
|
|
318
325
|
|
|
319
326
|
export interface AutoSupervisorConfig {
|
|
320
|
-
|
|
327
|
+
/**
|
|
328
|
+
* Model ID for the supervisor process. Accepts a bare model ID or the
|
|
329
|
+
* extended `{ model, provider?, fallbacks? }` object form for parity with
|
|
330
|
+
* phase buckets (#1229). Resolution normalizes it to the primary model ID.
|
|
331
|
+
*/
|
|
332
|
+
model?: string | GSDPhaseModelConfig;
|
|
321
333
|
soft_timeout_minutes?: number;
|
|
322
334
|
idle_timeout_minutes?: number;
|
|
323
335
|
hard_timeout_minutes?: number;
|
|
@@ -331,6 +343,17 @@ export interface AutoSupervisorConfig {
|
|
|
331
343
|
stalled_tool_timeout_minutes?: number;
|
|
332
344
|
}
|
|
333
345
|
|
|
346
|
+
/**
|
|
347
|
+
* The supervisor config after resolution by `resolveAutoSupervisorConfig`.
|
|
348
|
+
* Identical to {@link AutoSupervisorConfig} except `model` is always the
|
|
349
|
+
* normalized primary model ID string and `modelFallbacks` carries the ordered
|
|
350
|
+
* fallback chain from the object form accepted in preferences (#1229).
|
|
351
|
+
*/
|
|
352
|
+
export type ResolvedAutoSupervisorConfig = Omit<AutoSupervisorConfig, "model"> & {
|
|
353
|
+
model?: string;
|
|
354
|
+
modelFallbacks?: string[];
|
|
355
|
+
};
|
|
356
|
+
|
|
334
357
|
export interface RemoteQuestionsConfig {
|
|
335
358
|
channel: "slack" | "discord" | "telegram";
|
|
336
359
|
channel_id: string | number;
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
SKILL_ACTIONS,
|
|
23
23
|
type WorkflowMode,
|
|
24
24
|
type GSDPreferences,
|
|
25
|
+
type GSDPhaseModelConfig,
|
|
25
26
|
type GSDSkillRule,
|
|
26
27
|
type GSDThinkingLevel,
|
|
27
28
|
} from "./preferences-types.js";
|
|
@@ -41,6 +42,62 @@ const VALID_UOK_TURN_ACTIONS = new Set<"commit" | "snapshot" | "status-only">([
|
|
|
41
42
|
"snapshot",
|
|
42
43
|
"status-only",
|
|
43
44
|
]);
|
|
45
|
+
/**
|
|
46
|
+
* Sanitize a single model field that accepts either a bare model ID or the
|
|
47
|
+
* extended `{ model, provider?, fallbacks? }` object form used by phase buckets
|
|
48
|
+
* (#1229). Returns the sanitized value, or undefined when unset/invalid (in
|
|
49
|
+
* which case an error describing `label` is pushed onto `errors`).
|
|
50
|
+
*/
|
|
51
|
+
function sanitizeModelField(
|
|
52
|
+
raw: unknown,
|
|
53
|
+
label: string,
|
|
54
|
+
errors: string[],
|
|
55
|
+
warnings?: string[],
|
|
56
|
+
): string | GSDPhaseModelConfig | undefined {
|
|
57
|
+
if (raw === undefined) return undefined;
|
|
58
|
+
if (typeof raw === "string") {
|
|
59
|
+
const trimmed = raw.trim();
|
|
60
|
+
if (!trimmed) {
|
|
61
|
+
errors.push(`${label} must not be an empty string`);
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return trimmed;
|
|
65
|
+
}
|
|
66
|
+
if (raw && typeof raw === "object") {
|
|
67
|
+
const obj = raw as Record<string, unknown>;
|
|
68
|
+
const model = typeof obj.model === "string" ? obj.model.trim() : "";
|
|
69
|
+
if (!model) {
|
|
70
|
+
errors.push(`${label} object form requires a non-empty "model"`);
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const sanitized: GSDPhaseModelConfig = { model };
|
|
74
|
+
if (typeof obj.provider === "string" && obj.provider.trim()) {
|
|
75
|
+
sanitized.provider = obj.provider.trim();
|
|
76
|
+
}
|
|
77
|
+
if (obj.fallbacks !== undefined) {
|
|
78
|
+
const fallbacks = normalizeStringArray(obj.fallbacks);
|
|
79
|
+
if (fallbacks.length > 0) sanitized.fallbacks = fallbacks;
|
|
80
|
+
}
|
|
81
|
+
// Preserve the object form's `thinking` sub-field so the dispatch site can
|
|
82
|
+
// pin the hook/supervisor/subagent reasoning level (#1269). An illegal level
|
|
83
|
+
// is warned-and-stripped, mirroring inline per-phase thinking, so a typo can't
|
|
84
|
+
// reach the resolver and be treated as explicit configuration.
|
|
85
|
+
if (obj.thinking !== undefined) {
|
|
86
|
+
if (VALID_THINKING_LEVELS.has(obj.thinking as GSDThinkingLevel)) {
|
|
87
|
+
sanitized.thinking = obj.thinking as GSDThinkingLevel;
|
|
88
|
+
} else {
|
|
89
|
+
warnings?.push(
|
|
90
|
+
`${label} thinking "${String(obj.thinking)}" is not a valid thinking level ` +
|
|
91
|
+
`(off, minimal, low, medium, high, xhigh) — ignored`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return sanitized;
|
|
96
|
+
}
|
|
97
|
+
errors.push(`${label} must be a string or an object with a "model" field`);
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
44
101
|
const VALID_POST_UNIT_HOOK_CRITICALITIES = new Set(["advisory", "blocking"]);
|
|
45
102
|
const VALID_POST_UNIT_HOOK_ON_BLOCK_ACTIONS = new Set([
|
|
46
103
|
"retry-unit",
|
|
@@ -476,7 +533,15 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
476
533
|
// ─── Auto Supervisor ────────────────────────────────────────────────
|
|
477
534
|
if (preferences.auto_supervisor !== undefined) {
|
|
478
535
|
if (preferences.auto_supervisor && typeof preferences.auto_supervisor === "object") {
|
|
479
|
-
|
|
536
|
+
// Validate `model` through the shared sanitizer so the
|
|
537
|
+
// `{ model, provider?, fallbacks? }` object form is rejected on the same
|
|
538
|
+
// terms as its post_unit_hooks / reactive_execution siblings (#1229).
|
|
539
|
+
// Other supervisor fields pass through unchanged.
|
|
540
|
+
const supervisor = { ...preferences.auto_supervisor };
|
|
541
|
+
if (supervisor.model !== undefined) {
|
|
542
|
+
supervisor.model = sanitizeModelField(supervisor.model, "auto_supervisor.model", errors, warnings);
|
|
543
|
+
}
|
|
544
|
+
validated.auto_supervisor = supervisor;
|
|
480
545
|
} else {
|
|
481
546
|
errors.push("auto_supervisor must be an object");
|
|
482
547
|
}
|
|
@@ -568,8 +633,9 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
568
633
|
const mc = typeof hook.max_cycles === "number" ? hook.max_cycles : Number(hook.max_cycles);
|
|
569
634
|
validHook.max_cycles = Number.isFinite(mc) ? Math.max(1, Math.min(10, Math.round(mc))) : 1;
|
|
570
635
|
}
|
|
571
|
-
|
|
572
|
-
|
|
636
|
+
const hookModel = sanitizeModelField(hook.model, `post_unit_hooks "${name}" model`, errors, warnings);
|
|
637
|
+
if (hookModel !== undefined) {
|
|
638
|
+
validHook.model = hookModel;
|
|
573
639
|
}
|
|
574
640
|
if (typeof hook.artifact === "string" && hook.artifact.trim()) {
|
|
575
641
|
validHook.artifact = hook.artifact.trim();
|
|
@@ -1021,12 +1087,14 @@ export function validatePreferences(preferences: GSDPreferences): {
|
|
|
1021
1087
|
}
|
|
1022
1088
|
}
|
|
1023
1089
|
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1090
|
+
const subagentModel = sanitizeModelField(
|
|
1091
|
+
re.subagent_model,
|
|
1092
|
+
"reactive_execution.subagent_model",
|
|
1093
|
+
errors,
|
|
1094
|
+
warnings,
|
|
1095
|
+
);
|
|
1096
|
+
if (subagentModel !== undefined) {
|
|
1097
|
+
validRe.subagent_model = subagentModel;
|
|
1030
1098
|
}
|
|
1031
1099
|
|
|
1032
1100
|
const knownReKeys = new Set(["enabled", "max_parallel", "isolation_mode", "subagent_model"]);
|