gsd-pi 2.73.1-dev.d987996 → 2.74.0-dev.14c45ac
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/cli-web-branch.d.ts +4 -3
- package/dist/cli-web-branch.js +10 -7
- package/dist/cli.js +184 -206
- package/dist/headless-query.js +4 -1
- package/dist/help-text.js +23 -0
- package/dist/logo.d.ts +1 -1
- package/dist/logo.js +1 -1
- package/dist/onboarding.js +59 -53
- package/dist/resource-loader.js +2 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +68 -4
- package/dist/resources/extensions/gsd/activity-log.js +16 -0
- package/dist/resources/extensions/gsd/auto/detect-stuck.js +11 -4
- package/dist/resources/extensions/gsd/auto/loop.js +147 -10
- package/dist/resources/extensions/gsd/auto/phases.js +173 -13
- package/dist/resources/extensions/gsd/auto/session.js +10 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +22 -4
- package/dist/resources/extensions/gsd/auto-model-selection.js +105 -16
- package/dist/resources/extensions/gsd/auto-post-unit.js +254 -15
- package/dist/resources/extensions/gsd/auto-prompts.js +12 -0
- package/dist/resources/extensions/gsd/auto-start.js +23 -6
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +13 -0
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +18 -0
- package/dist/resources/extensions/gsd/auto-verification.js +186 -3
- package/dist/resources/extensions/gsd/auto.js +65 -12
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +21 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +26 -1
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +25 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +68 -9
- package/dist/resources/extensions/gsd/commands-add-tests.js +111 -0
- package/dist/resources/extensions/gsd/commands-backlog.js +140 -0
- package/dist/resources/extensions/gsd/commands-do.js +79 -0
- package/dist/resources/extensions/gsd/commands-extract-learnings.js +225 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +8 -2
- package/dist/resources/extensions/gsd/commands-maintenance.js +6 -6
- package/dist/resources/extensions/gsd/commands-pr-branch.js +180 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands-session-report.js +82 -0
- package/dist/resources/extensions/gsd/commands-ship.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +3 -5
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +15 -2
- package/dist/resources/extensions/gsd/git-service.js +49 -1
- package/dist/resources/extensions/gsd/graph-context.js +157 -0
- package/dist/resources/extensions/gsd/gsd-db.js +581 -2
- package/dist/resources/extensions/gsd/guided-flow.js +23 -0
- package/dist/resources/extensions/gsd/index.js +15 -2
- package/dist/resources/extensions/gsd/init-wizard.js +1 -0
- package/dist/resources/extensions/gsd/journal.js +27 -0
- package/dist/resources/extensions/gsd/md-importer.js +3 -4
- package/dist/resources/extensions/gsd/memory-store.js +19 -51
- package/dist/resources/extensions/gsd/metrics.js +19 -0
- package/dist/resources/extensions/gsd/milestone-validation-gates.js +13 -12
- package/dist/resources/extensions/gsd/native-git-bridge.js +7 -4
- package/dist/resources/extensions/gsd/notification-widget.js +2 -2
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +33 -1
- package/dist/resources/extensions/gsd/preferences-models.js +63 -3
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +130 -2
- package/dist/resources/extensions/gsd/preferences.js +26 -0
- package/dist/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +12 -2
- package/dist/resources/extensions/gsd/state.js +66 -15
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +39 -4
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +3 -14
- package/dist/resources/extensions/gsd/triage-resolution.js +2 -5
- package/dist/resources/extensions/gsd/unit-ownership.js +1 -1
- package/dist/resources/extensions/gsd/uok/audit-toggle.js +7 -0
- package/dist/resources/extensions/gsd/uok/audit.js +40 -0
- package/dist/resources/extensions/gsd/uok/contracts.js +1 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +179 -0
- package/dist/resources/extensions/gsd/uok/flags.js +29 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +109 -0
- package/dist/resources/extensions/gsd/uok/gitops.js +53 -0
- package/dist/resources/extensions/gsd/uok/kernel.js +80 -0
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +133 -0
- package/dist/resources/extensions/gsd/uok/model-policy.js +66 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +132 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +22 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +8 -69
- package/dist/resources/extensions/gsd/workflow-migration.js +21 -22
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -1
- package/dist/resources/extensions/gsd/workflow-reconcile.js +14 -11
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -0
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +13 -5
- package/dist/update-cmd.js +4 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- 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/required-server-files.json +1 -1
- 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 +11 -11
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- 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/server.js +1 -1
- package/package.json +3 -3
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/dist/index.d.ts +3 -0
- package/packages/mcp-server/dist/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/index.js +3 -0
- package/packages/mcp-server/dist/index.js.map +1 -1
- package/packages/mcp-server/dist/readers/graph.d.ts +87 -0
- package/packages/mcp-server/dist/readers/graph.d.ts.map +1 -0
- package/packages/mcp-server/dist/readers/graph.js +655 -0
- package/packages/mcp-server/dist/readers/graph.js.map +1 -0
- package/packages/mcp-server/dist/readers/index.d.ts +2 -0
- package/packages/mcp-server/dist/readers/index.d.ts.map +1 -1
- package/packages/mcp-server/dist/readers/index.js +1 -0
- package/packages/mcp-server/dist/readers/index.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +65 -0
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/index.ts +15 -0
- package/packages/mcp-server/src/readers/graph.test.ts +604 -0
- package/packages/mcp-server/src/readers/graph.ts +855 -0
- package/packages/mcp-server/src/readers/index.ts +12 -0
- package/packages/mcp-server/src/server.ts +83 -0
- package/packages/mcp-server/tsconfig.json +1 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -0
- package/packages/native/package.json +2 -2
- package/packages/native/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.json +1 -0
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -0
- 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/utils/overflow.d.ts.map +1 -1
- package/packages/pi-ai/dist/utils/overflow.js +12 -0
- package/packages/pi-ai/dist/utils/overflow.js.map +1 -1
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts +2 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js +50 -0
- package/packages/pi-ai/dist/utils/tests/overflow.test.js.map +1 -0
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +4 -0
- package/packages/pi-ai/src/utils/overflow.ts +14 -1
- package/packages/pi-ai/src/utils/tests/overflow.test.ts +58 -0
- package/packages/pi-ai/tsconfig.json +1 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +511 -8
- package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction/utils.js +5 -5
- package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js +45 -0
- package/packages/pi-coding-agent/dist/core/compaction-utils.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js +52 -0
- package/packages/pi-coding-agent/dist/core/model-registry-env-fallback.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +12 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +61 -28
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js +9 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +52 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +165 -20
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +11 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +620 -8
- package/packages/pi-coding-agent/src/core/compaction/utils.ts +5 -5
- package/packages/pi-coding-agent/src/core/compaction-utils.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/model-registry-env-fallback.test.ts +59 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +2 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +74 -32
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +73 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.ts +9 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +189 -25
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +11 -3
- package/packages/pi-coding-agent/src/types/ambient-modules.d.ts +69 -0
- package/packages/pi-coding-agent/tsconfig.json +3 -2
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -0
- package/packages/pi-tui/dist/__tests__/tui.test.js +60 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +8 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +32 -3
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/tui.test.ts +76 -1
- package/packages/pi-tui/src/tui.ts +31 -3
- package/packages/pi-tui/tsconfig.json +1 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -0
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.json +1 -0
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +107 -5
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +111 -2
- package/src/resources/extensions/gsd/activity-log.ts +21 -0
- package/src/resources/extensions/gsd/auto/detect-stuck.ts +12 -4
- package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -0
- package/src/resources/extensions/gsd/auto/loop.ts +159 -10
- package/src/resources/extensions/gsd/auto/phases.ts +213 -13
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +26 -10
- package/src/resources/extensions/gsd/auto-model-selection.ts +151 -16
- package/src/resources/extensions/gsd/auto-post-unit.ts +278 -16
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -0
- package/src/resources/extensions/gsd/auto-start.ts +30 -6
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +17 -0
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +25 -1
- package/src/resources/extensions/gsd/auto-verification.ts +225 -3
- package/src/resources/extensions/gsd/auto.ts +72 -16
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +26 -1
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +25 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +74 -9
- package/src/resources/extensions/gsd/commands-add-tests.ts +137 -0
- package/src/resources/extensions/gsd/commands-backlog.ts +182 -0
- package/src/resources/extensions/gsd/commands-do.ts +109 -0
- package/src/resources/extensions/gsd/commands-extract-learnings.ts +304 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +8 -2
- package/src/resources/extensions/gsd/commands-maintenance.ts +6 -6
- package/src/resources/extensions/gsd/commands-pr-branch.ts +234 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands-session-report.ts +101 -0
- package/src/resources/extensions/gsd/commands-ship.ts +219 -0
- package/src/resources/extensions/gsd/db-writer.ts +3 -5
- package/src/resources/extensions/gsd/docs/preferences-reference.md +15 -2
- package/src/resources/extensions/gsd/git-service.ts +68 -0
- package/src/resources/extensions/gsd/graph-context.ts +212 -0
- package/src/resources/extensions/gsd/gsd-db.ts +788 -3
- package/src/resources/extensions/gsd/guided-flow.ts +32 -0
- package/src/resources/extensions/gsd/index.ts +18 -2
- package/src/resources/extensions/gsd/init-wizard.ts +3 -2
- package/src/resources/extensions/gsd/journal.ts +30 -0
- package/src/resources/extensions/gsd/md-importer.ts +3 -5
- package/src/resources/extensions/gsd/memory-store.ts +31 -62
- package/src/resources/extensions/gsd/metrics.ts +26 -0
- package/src/resources/extensions/gsd/milestone-validation-gates.ts +13 -14
- package/src/resources/extensions/gsd/native-git-bridge.ts +11 -12
- package/src/resources/extensions/gsd/notification-widget.ts +2 -2
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +40 -1
- package/src/resources/extensions/gsd/preferences-models.ts +61 -3
- package/src/resources/extensions/gsd/preferences-types.ts +44 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +130 -2
- package/src/resources/extensions/gsd/preferences.ts +28 -0
- package/src/resources/extensions/gsd/prompts/add-tests.md +35 -0
- package/src/resources/extensions/gsd/session-lock.ts +14 -2
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +20 -1
- package/src/resources/extensions/gsd/state.ts +80 -17
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +18 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +9 -5
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +51 -2
- package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/commands-backlog.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/commands-do.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +340 -0
- package/src/resources/extensions/gsd/tests/commands-pr-branch.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/commands-session-report.test.ts +82 -0
- package/src/resources/extensions/gsd/tests/commands-ship.test.ts +71 -0
- package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +142 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +68 -8
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +154 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +10 -7
- package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +137 -1
- package/src/resources/extensions/gsd/tests/graph-context.test.ts +337 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +68 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -2
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +91 -2
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +9 -6
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +101 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/uok-flags.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +167 -0
- package/src/resources/extensions/gsd/tests/uok-preferences.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +179 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +223 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +48 -3
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +3 -11
- package/src/resources/extensions/gsd/triage-resolution.ts +2 -7
- package/src/resources/extensions/gsd/types.ts +1 -1
- package/src/resources/extensions/gsd/unit-ownership.ts +2 -2
- package/src/resources/extensions/gsd/uok/audit-toggle.ts +9 -0
- package/src/resources/extensions/gsd/uok/audit.ts +51 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +135 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +241 -0
- package/src/resources/extensions/gsd/uok/flags.ts +45 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +146 -0
- package/src/resources/extensions/gsd/uok/gitops.ts +75 -0
- package/src/resources/extensions/gsd/uok/kernel.ts +105 -0
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +162 -0
- package/src/resources/extensions/gsd/uok/model-policy.ts +112 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +156 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +25 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +9 -104
- package/src/resources/extensions/gsd/workflow-migration.ts +21 -29
- package/src/resources/extensions/gsd/workflow-projections.ts +8 -1
- package/src/resources/extensions/gsd/workflow-reconcile.ts +15 -15
- package/src/resources/extensions/ttsr/ttsr-manager.ts +10 -5
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → ZMKM0OI0CrTgzKWbgfPOg}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{cGmbVq2su4f9tMpgIkG8u → ZMKM0OI0CrTgzKWbgfPOg}/_ssgManifest.js +0 -0
|
@@ -23,6 +23,9 @@ import { invalidateStateCache } from "../state.js";
|
|
|
23
23
|
import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
|
|
24
24
|
import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
|
|
25
25
|
import { logWarning } from "../workflow-logger.js";
|
|
26
|
+
import { UokGateRunner } from "../uok/gate-runner.js";
|
|
27
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
28
|
+
import { resolveUokFlags } from "../uok/flags.js";
|
|
26
29
|
|
|
27
30
|
export interface ValidateMilestoneParams {
|
|
28
31
|
milestoneId: string;
|
|
@@ -43,6 +46,12 @@ export interface ValidateMilestoneResult {
|
|
|
43
46
|
validationPath: string;
|
|
44
47
|
}
|
|
45
48
|
|
|
49
|
+
export interface ValidateMilestoneOptions {
|
|
50
|
+
uokGatesEnabled?: boolean;
|
|
51
|
+
traceId?: string;
|
|
52
|
+
turnId?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
46
55
|
function renderValidationMarkdown(params: ValidateMilestoneParams): string {
|
|
47
56
|
let md = `---
|
|
48
57
|
verdict: ${params.verdict}
|
|
@@ -81,6 +90,7 @@ ${params.verdictRationale}
|
|
|
81
90
|
export async function handleValidateMilestone(
|
|
82
91
|
params: ValidateMilestoneParams,
|
|
83
92
|
basePath: string,
|
|
93
|
+
opts?: ValidateMilestoneOptions,
|
|
84
94
|
): Promise<ValidateMilestoneResult | { error: string }> {
|
|
85
95
|
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
86
96
|
return { error: "milestoneId is required and must be a non-empty string" };
|
|
@@ -108,6 +118,8 @@ export async function handleValidateMilestone(
|
|
|
108
118
|
// rendering can regenerate. The inverse (file exists, no DB row) is
|
|
109
119
|
// harder to detect and recover from (#2725).
|
|
110
120
|
const validatedAt = new Date().toISOString();
|
|
121
|
+
const slices = getMilestoneSlices(params.milestoneId);
|
|
122
|
+
const gateSliceId = slices.length > 0 ? slices[0].id : "_milestone";
|
|
111
123
|
|
|
112
124
|
transaction(() => {
|
|
113
125
|
insertAssessment({
|
|
@@ -123,11 +135,9 @@ export async function handleValidateMilestone(
|
|
|
123
135
|
// #2945 Bug 4: persist quality_gates records alongside the assessment.
|
|
124
136
|
// Previously only the assessment was written, leaving M002+ milestones
|
|
125
137
|
// with zero quality_gate records despite passing validation.
|
|
126
|
-
const slices = getMilestoneSlices(params.milestoneId);
|
|
127
|
-
const sliceId = slices.length > 0 ? slices[0].id : "_milestone";
|
|
128
138
|
insertMilestoneValidationGates(
|
|
129
139
|
params.milestoneId,
|
|
130
|
-
|
|
140
|
+
gateSliceId,
|
|
131
141
|
params.verdict,
|
|
132
142
|
validatedAt,
|
|
133
143
|
);
|
|
@@ -147,6 +157,41 @@ export async function handleValidateMilestone(
|
|
|
147
157
|
clearPathCache();
|
|
148
158
|
clearParseCache();
|
|
149
159
|
|
|
160
|
+
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
161
|
+
const gatesEnabled = opts?.uokGatesEnabled ?? resolveUokFlags(prefs).gates;
|
|
162
|
+
if (gatesEnabled) {
|
|
163
|
+
try {
|
|
164
|
+
const gateRunner = new UokGateRunner();
|
|
165
|
+
const nonPassVerdict = params.verdict !== "pass";
|
|
166
|
+
gateRunner.register({
|
|
167
|
+
id: "milestone-validation-gates",
|
|
168
|
+
type: "verification",
|
|
169
|
+
execute: async () => ({
|
|
170
|
+
outcome: nonPassVerdict ? "manual-attention" : "pass",
|
|
171
|
+
failureClass: nonPassVerdict ? "manual-attention" : "none",
|
|
172
|
+
rationale: `milestone validation verdict: ${params.verdict}`,
|
|
173
|
+
findings: nonPassVerdict
|
|
174
|
+
? [params.verdictRationale, params.remediationPlan ?? ""].filter(Boolean).join("\n")
|
|
175
|
+
: "",
|
|
176
|
+
}),
|
|
177
|
+
});
|
|
178
|
+
await gateRunner.run("milestone-validation-gates", {
|
|
179
|
+
basePath,
|
|
180
|
+
traceId: opts?.traceId ?? `validate-milestone:${params.milestoneId}`,
|
|
181
|
+
turnId: opts?.turnId ?? `${params.milestoneId}:validate`,
|
|
182
|
+
milestoneId: params.milestoneId,
|
|
183
|
+
sliceId: gateSliceId,
|
|
184
|
+
unitType: "validate-milestone",
|
|
185
|
+
unitId: params.milestoneId,
|
|
186
|
+
});
|
|
187
|
+
} catch (err) {
|
|
188
|
+
logWarning(
|
|
189
|
+
"tool",
|
|
190
|
+
`validate_milestone — failed to persist UOK gate result: ${(err as Error).message}`,
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
150
195
|
return {
|
|
151
196
|
milestoneId: params.milestoneId,
|
|
152
197
|
verdict: params.verdict,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getMilestone,
|
|
6
6
|
getSliceStatusSummary,
|
|
7
7
|
getSliceTaskCounts,
|
|
8
|
-
|
|
8
|
+
readTransaction,
|
|
9
9
|
saveGateResult,
|
|
10
10
|
} from "../gsd-db.js";
|
|
11
11
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
@@ -616,12 +616,9 @@ export async function executeMilestoneStatus(
|
|
|
616
616
|
};
|
|
617
617
|
}
|
|
618
618
|
|
|
619
|
-
|
|
620
|
-
adapter.exec("BEGIN");
|
|
621
|
-
try {
|
|
619
|
+
return readTransaction(() => {
|
|
622
620
|
const milestone = getMilestone(params.milestoneId);
|
|
623
621
|
if (!milestone) {
|
|
624
|
-
adapter.exec("COMMIT");
|
|
625
622
|
return {
|
|
626
623
|
content: [{ type: "text", text: `Milestone ${params.milestoneId} not found in database.` }],
|
|
627
624
|
details: { operation: "milestone_status", milestoneId: params.milestoneId, found: false },
|
|
@@ -635,8 +632,6 @@ export async function executeMilestoneStatus(
|
|
|
635
632
|
taskCounts: getSliceTaskCounts(params.milestoneId, s.id),
|
|
636
633
|
}));
|
|
637
634
|
|
|
638
|
-
adapter.exec("COMMIT");
|
|
639
|
-
|
|
640
635
|
const result = {
|
|
641
636
|
milestoneId: milestone.id,
|
|
642
637
|
title: milestone.title,
|
|
@@ -651,10 +646,7 @@ export async function executeMilestoneStatus(
|
|
|
651
646
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
652
647
|
details: { operation: "milestone_status", milestoneId: milestone.id, sliceCount: slices.length },
|
|
653
648
|
};
|
|
654
|
-
}
|
|
655
|
-
try { adapter.exec("ROLLBACK"); } catch { /* swallow */ }
|
|
656
|
-
throw txErr;
|
|
657
|
-
}
|
|
649
|
+
});
|
|
658
650
|
} catch (err) {
|
|
659
651
|
const msg = err instanceof Error ? err.message : String(err);
|
|
660
652
|
logWarning("tool", `gsd_milestone_status tool failed: ${msg}`);
|
|
@@ -111,14 +111,9 @@ export function executeReplan(
|
|
|
111
111
|
// Also write replan_triggered_at column for DB-backed detection
|
|
112
112
|
try {
|
|
113
113
|
const req = createRequire(import.meta.url);
|
|
114
|
-
const { isDbAvailable,
|
|
114
|
+
const { isDbAvailable, setSliceReplanTriggeredAt } = req("./gsd-db.js");
|
|
115
115
|
if (isDbAvailable()) {
|
|
116
|
-
|
|
117
|
-
if (adapter) {
|
|
118
|
-
adapter.prepare(
|
|
119
|
-
"UPDATE slices SET replan_triggered_at = :ts WHERE milestone_id = :mid AND id = :sid",
|
|
120
|
-
).run({ ":ts": ts, ":mid": mid, ":sid": sid });
|
|
121
|
-
}
|
|
116
|
+
setSliceReplanTriggeredAt(mid, sid, ts);
|
|
122
117
|
}
|
|
123
118
|
} catch {
|
|
124
119
|
// DB write is best-effort — disk file is the primary trigger for fallback path
|
|
@@ -306,7 +306,7 @@ export interface HookDispatchResult {
|
|
|
306
306
|
|
|
307
307
|
export type BudgetEnforcementMode = "warn" | "pause" | "halt";
|
|
308
308
|
|
|
309
|
-
export type TokenProfile = "budget" | "balanced" | "quality";
|
|
309
|
+
export type TokenProfile = "budget" | "balanced" | "quality" | "burn-max";
|
|
310
310
|
|
|
311
311
|
export type InlineLevel = "full" | "standard" | "minimal";
|
|
312
312
|
|
|
@@ -46,8 +46,8 @@ let loadAttempted = false;
|
|
|
46
46
|
|
|
47
47
|
function suppressSqliteWarning(): void {
|
|
48
48
|
const origEmit = process.emit;
|
|
49
|
-
//
|
|
50
|
-
process.emit = function (event: string, ...args: unknown[]): boolean {
|
|
49
|
+
// Override via loose cast: Node's overloaded emit signature is not directly assignable.
|
|
50
|
+
(process as any).emit = function (event: string, ...args: unknown[]): boolean {
|
|
51
51
|
if (
|
|
52
52
|
event === "warning" &&
|
|
53
53
|
args[0] &&
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const AUDIT_ENV_KEY = "GSD_UOK_AUDIT_UNIFIED";
|
|
2
|
+
|
|
3
|
+
export function setUnifiedAuditEnabled(enabled: boolean): void {
|
|
4
|
+
process.env[AUDIT_ENV_KEY] = enabled ? "1" : "0";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function isUnifiedAuditEnabled(): boolean {
|
|
8
|
+
return process.env[AUDIT_ENV_KEY] === "1";
|
|
9
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
import { gsdRoot } from "../paths.js";
|
|
6
|
+
import { isDbAvailable, insertAuditEvent } from "../gsd-db.js";
|
|
7
|
+
import type { AuditEventEnvelope } from "./contracts.js";
|
|
8
|
+
|
|
9
|
+
function auditLogPath(basePath: string): string {
|
|
10
|
+
return join(gsdRoot(basePath), "audit", "events.jsonl");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function ensureAuditDir(basePath: string): void {
|
|
14
|
+
mkdirSync(join(gsdRoot(basePath), "audit"), { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function buildAuditEnvelope(args: {
|
|
18
|
+
traceId: string;
|
|
19
|
+
turnId?: string;
|
|
20
|
+
causedBy?: string;
|
|
21
|
+
category: AuditEventEnvelope["category"];
|
|
22
|
+
type: string;
|
|
23
|
+
payload?: Record<string, unknown>;
|
|
24
|
+
}): AuditEventEnvelope {
|
|
25
|
+
return {
|
|
26
|
+
eventId: randomUUID(),
|
|
27
|
+
traceId: args.traceId,
|
|
28
|
+
turnId: args.turnId,
|
|
29
|
+
causedBy: args.causedBy,
|
|
30
|
+
category: args.category,
|
|
31
|
+
type: args.type,
|
|
32
|
+
ts: new Date().toISOString(),
|
|
33
|
+
payload: args.payload ?? {},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function emitUokAuditEvent(basePath: string, event: AuditEventEnvelope): void {
|
|
38
|
+
try {
|
|
39
|
+
ensureAuditDir(basePath);
|
|
40
|
+
appendFileSync(auditLogPath(basePath), `${JSON.stringify(event)}\n`, "utf-8");
|
|
41
|
+
} catch {
|
|
42
|
+
// Best-effort: audit writes must never break orchestration.
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!isDbAvailable()) return;
|
|
46
|
+
try {
|
|
47
|
+
insertAuditEvent(event);
|
|
48
|
+
} catch {
|
|
49
|
+
// Projection failures are non-fatal while legacy readers are still active.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
export type FailureClass =
|
|
2
|
+
| "none"
|
|
3
|
+
| "policy"
|
|
4
|
+
| "input"
|
|
5
|
+
| "execution"
|
|
6
|
+
| "artifact"
|
|
7
|
+
| "verification"
|
|
8
|
+
| "closeout"
|
|
9
|
+
| "git"
|
|
10
|
+
| "timeout"
|
|
11
|
+
| "manual-attention"
|
|
12
|
+
| "unknown";
|
|
13
|
+
|
|
14
|
+
export type GateOutcome = "pass" | "fail" | "retry" | "manual-attention";
|
|
15
|
+
|
|
16
|
+
export interface GateResult {
|
|
17
|
+
gateId: string;
|
|
18
|
+
gateType: string;
|
|
19
|
+
outcome: GateOutcome;
|
|
20
|
+
failureClass: FailureClass;
|
|
21
|
+
rationale?: string;
|
|
22
|
+
findings?: string;
|
|
23
|
+
attempt: number;
|
|
24
|
+
maxAttempts: number;
|
|
25
|
+
retryable: boolean;
|
|
26
|
+
evaluatedAt: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type TurnPhase =
|
|
30
|
+
| "pre-dispatch"
|
|
31
|
+
| "dispatch"
|
|
32
|
+
| "unit"
|
|
33
|
+
| "finalize"
|
|
34
|
+
| "guard"
|
|
35
|
+
| "custom-engine";
|
|
36
|
+
|
|
37
|
+
export type TurnStatus =
|
|
38
|
+
| "completed"
|
|
39
|
+
| "failed"
|
|
40
|
+
| "paused"
|
|
41
|
+
| "stopped"
|
|
42
|
+
| "skipped"
|
|
43
|
+
| "retry";
|
|
44
|
+
|
|
45
|
+
export interface TurnContract {
|
|
46
|
+
traceId: string;
|
|
47
|
+
turnId: string;
|
|
48
|
+
iteration: number;
|
|
49
|
+
basePath: string;
|
|
50
|
+
unitType?: string;
|
|
51
|
+
unitId?: string;
|
|
52
|
+
sidecarKind?: string;
|
|
53
|
+
startedAt: string;
|
|
54
|
+
metadata?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TurnCloseoutRecord {
|
|
58
|
+
traceId: string;
|
|
59
|
+
turnId: string;
|
|
60
|
+
unitType?: string;
|
|
61
|
+
unitId?: string;
|
|
62
|
+
status: TurnStatus;
|
|
63
|
+
failureClass: FailureClass;
|
|
64
|
+
gitAction: "commit" | "snapshot" | "status-only";
|
|
65
|
+
gitPushed: boolean;
|
|
66
|
+
activityFile?: string;
|
|
67
|
+
finishedAt: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface TurnResult {
|
|
71
|
+
traceId: string;
|
|
72
|
+
turnId: string;
|
|
73
|
+
iteration: number;
|
|
74
|
+
unitType?: string;
|
|
75
|
+
unitId?: string;
|
|
76
|
+
status: TurnStatus;
|
|
77
|
+
failureClass: FailureClass;
|
|
78
|
+
phaseResults: Array<{
|
|
79
|
+
phase: TurnPhase;
|
|
80
|
+
action: string;
|
|
81
|
+
ts: string;
|
|
82
|
+
data?: Record<string, unknown>;
|
|
83
|
+
}>;
|
|
84
|
+
gateResults?: GateResult[];
|
|
85
|
+
closeout?: TurnCloseoutRecord;
|
|
86
|
+
error?: string;
|
|
87
|
+
startedAt: string;
|
|
88
|
+
finishedAt: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface AuditEventEnvelope {
|
|
92
|
+
eventId: string;
|
|
93
|
+
traceId: string;
|
|
94
|
+
turnId?: string;
|
|
95
|
+
causedBy?: string;
|
|
96
|
+
category:
|
|
97
|
+
| "orchestration"
|
|
98
|
+
| "gate"
|
|
99
|
+
| "model-policy"
|
|
100
|
+
| "gitops"
|
|
101
|
+
| "verification"
|
|
102
|
+
| "metrics"
|
|
103
|
+
| "plan"
|
|
104
|
+
| "execution";
|
|
105
|
+
type: string;
|
|
106
|
+
ts: string;
|
|
107
|
+
payload: Record<string, unknown>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type UokNodeKind =
|
|
111
|
+
| "unit"
|
|
112
|
+
| "hook"
|
|
113
|
+
| "subagent"
|
|
114
|
+
| "team-worker"
|
|
115
|
+
| "verification"
|
|
116
|
+
| "reprocess";
|
|
117
|
+
|
|
118
|
+
export interface UokGraphNode {
|
|
119
|
+
id: string;
|
|
120
|
+
kind: UokNodeKind;
|
|
121
|
+
dependsOn: string[];
|
|
122
|
+
writes?: string[];
|
|
123
|
+
reads?: string[];
|
|
124
|
+
metadata?: Record<string, unknown>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface UokTurnObserver {
|
|
128
|
+
onTurnStart(contract: TurnContract): void;
|
|
129
|
+
onPhaseResult(
|
|
130
|
+
phase: TurnPhase,
|
|
131
|
+
action: string,
|
|
132
|
+
data?: Record<string, unknown>,
|
|
133
|
+
): void;
|
|
134
|
+
onTurnResult(result: TurnResult): void;
|
|
135
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import type { UokGraphNode } from "./contracts.js";
|
|
2
|
+
import type { DerivedTaskNode } from "../types.js";
|
|
3
|
+
import type { SidecarItem } from "../auto/session.js";
|
|
4
|
+
|
|
5
|
+
export interface ExecutionGraphRunOptions {
|
|
6
|
+
parallel?: boolean;
|
|
7
|
+
maxWorkers?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ExecutionGraphResult {
|
|
11
|
+
order: string[];
|
|
12
|
+
conflicts: Array<{ nodeA: string; nodeB: string; file: string }>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ExecutionNodeHandler = (node: UokGraphNode) => Promise<void>;
|
|
16
|
+
|
|
17
|
+
export interface ConflictFreeBatchInput {
|
|
18
|
+
orderedIds: string[];
|
|
19
|
+
maxParallel: number;
|
|
20
|
+
hasConflict: (leftId: string, rightId: string) => boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReactiveDispatchSelectionInput {
|
|
24
|
+
graph: Array<Pick<DerivedTaskNode, "id" | "dependsOn" | "outputFiles">>;
|
|
25
|
+
readyIds: string[];
|
|
26
|
+
maxParallel: number;
|
|
27
|
+
inFlightOutputs?: Set<string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface ReactiveDispatchSelectionResult {
|
|
31
|
+
selected: string[];
|
|
32
|
+
conflicts: Array<{ nodeA: string; nodeB: string; file: string }>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function selectConflictFreeBatch({
|
|
36
|
+
orderedIds,
|
|
37
|
+
maxParallel,
|
|
38
|
+
hasConflict,
|
|
39
|
+
}: ConflictFreeBatchInput): string[] {
|
|
40
|
+
if (maxParallel <= 0 || orderedIds.length === 0) return [];
|
|
41
|
+
const selected: string[] = [];
|
|
42
|
+
for (const candidate of orderedIds) {
|
|
43
|
+
if (selected.length >= maxParallel) break;
|
|
44
|
+
const conflictsExisting = selected.some((existing) => hasConflict(candidate, existing));
|
|
45
|
+
if (conflictsExisting) continue;
|
|
46
|
+
selected.push(candidate);
|
|
47
|
+
}
|
|
48
|
+
return selected;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildReactiveNodes(
|
|
52
|
+
graph: Array<Pick<DerivedTaskNode, "id" | "dependsOn" | "outputFiles">>,
|
|
53
|
+
): UokGraphNode[] {
|
|
54
|
+
return graph.map((node) => ({
|
|
55
|
+
id: node.id,
|
|
56
|
+
kind: "unit",
|
|
57
|
+
dependsOn: [...node.dependsOn],
|
|
58
|
+
writes: [...node.outputFiles],
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function selectReactiveDispatchBatch(
|
|
63
|
+
input: ReactiveDispatchSelectionInput,
|
|
64
|
+
): ReactiveDispatchSelectionResult {
|
|
65
|
+
const nodeMap = new Map(buildReactiveNodes(input.graph).map((n) => [n.id, n]));
|
|
66
|
+
const readyNodes = input.readyIds
|
|
67
|
+
.map((id) => nodeMap.get(id))
|
|
68
|
+
.filter((node): node is UokGraphNode => !!node);
|
|
69
|
+
const conflicts = detectFileConflicts(readyNodes);
|
|
70
|
+
if (readyNodes.length === 0 || input.maxParallel <= 0) {
|
|
71
|
+
return { selected: [], conflicts };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const claimed = new Set(input.inFlightOutputs ?? []);
|
|
75
|
+
const selected: string[] = [];
|
|
76
|
+
const selectedSet = new Set<string>();
|
|
77
|
+
const readySet = new Set(input.readyIds);
|
|
78
|
+
|
|
79
|
+
for (const id of input.readyIds) {
|
|
80
|
+
if (selected.length >= input.maxParallel) break;
|
|
81
|
+
const node = nodeMap.get(id);
|
|
82
|
+
if (!node) continue;
|
|
83
|
+
|
|
84
|
+
const hasUnmetReadyDependency = node.dependsOn.some(
|
|
85
|
+
(dep) => readySet.has(dep) && !selectedSet.has(dep),
|
|
86
|
+
);
|
|
87
|
+
if (hasUnmetReadyDependency) continue;
|
|
88
|
+
|
|
89
|
+
const writes = node.writes ?? [];
|
|
90
|
+
const conflictsWithClaimed = writes.some((file) => claimed.has(file));
|
|
91
|
+
if (conflictsWithClaimed) continue;
|
|
92
|
+
|
|
93
|
+
selected.push(node.id);
|
|
94
|
+
selectedSet.add(node.id);
|
|
95
|
+
for (const file of writes) claimed.add(file);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { selected, conflicts };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function sidecarToNodeKind(kind: SidecarItem["kind"]): UokGraphNode["kind"] {
|
|
102
|
+
if (kind === "hook") return "hook";
|
|
103
|
+
if (kind === "triage") return "verification";
|
|
104
|
+
return "team-worker";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function buildSidecarQueueNodes(queue: SidecarItem[]): UokGraphNode[] {
|
|
108
|
+
return queue.map((item, index) => ({
|
|
109
|
+
id: `sidecar-${String(index).padStart(4, "0")}:${item.kind}:${item.unitType}:${item.unitId}`,
|
|
110
|
+
kind: sidecarToNodeKind(item.kind),
|
|
111
|
+
dependsOn: index > 0 ? [`sidecar-${String(index - 1).padStart(4, "0")}:${queue[index - 1].kind}:${queue[index - 1].unitType}:${queue[index - 1].unitId}`] : [],
|
|
112
|
+
metadata: { index },
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function scheduleSidecarQueue(queue: SidecarItem[]): Promise<SidecarItem[]> {
|
|
117
|
+
if (queue.length <= 1) return [...queue];
|
|
118
|
+
const nodes = buildSidecarQueueNodes(queue);
|
|
119
|
+
const scheduler = new ExecutionGraphScheduler();
|
|
120
|
+
const orderedIndexes: number[] = [];
|
|
121
|
+
const seenKinds = new Set<UokGraphNode["kind"]>(nodes.map((n) => n.kind));
|
|
122
|
+
|
|
123
|
+
for (const kind of seenKinds) {
|
|
124
|
+
scheduler.registerHandler(kind, async (node) => {
|
|
125
|
+
const idx = Number(node.metadata?.index);
|
|
126
|
+
if (Number.isInteger(idx) && idx >= 0) orderedIndexes.push(idx);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
await scheduler.run(nodes, { parallel: false });
|
|
131
|
+
return orderedIndexes.map((idx) => queue[idx]).filter((item): item is SidecarItem => !!item);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export class ExecutionGraphScheduler {
|
|
135
|
+
private readonly handlers = new Map<string, ExecutionNodeHandler>();
|
|
136
|
+
|
|
137
|
+
registerHandler(kind: UokGraphNode["kind"], handler: ExecutionNodeHandler): void {
|
|
138
|
+
this.handlers.set(kind, handler);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async run(nodes: UokGraphNode[], options?: ExecutionGraphRunOptions): Promise<ExecutionGraphResult> {
|
|
142
|
+
const sorted = topologicalSort(nodes);
|
|
143
|
+
const conflicts = detectFileConflicts(nodes);
|
|
144
|
+
|
|
145
|
+
// Default deterministic serial execution remains the reference path.
|
|
146
|
+
if (!options?.parallel) {
|
|
147
|
+
for (const node of sorted) {
|
|
148
|
+
const handler = this.handlers.get(node.kind);
|
|
149
|
+
if (handler) await handler(node);
|
|
150
|
+
}
|
|
151
|
+
return { order: sorted.map((n) => n.id), conflicts };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Parallel mode only for nodes whose dependencies are already satisfied.
|
|
155
|
+
const maxWorkers = Math.max(1, Math.min(8, options.maxWorkers ?? 2));
|
|
156
|
+
const remaining = new Map(nodes.map((n) => [n.id, n]));
|
|
157
|
+
const done = new Set<string>();
|
|
158
|
+
const order: string[] = [];
|
|
159
|
+
|
|
160
|
+
while (remaining.size > 0) {
|
|
161
|
+
const ready = Array.from(remaining.values()).filter((node) =>
|
|
162
|
+
node.dependsOn.every((dep) => done.has(dep)),
|
|
163
|
+
);
|
|
164
|
+
ready.sort((a, b) => a.id.localeCompare(b.id));
|
|
165
|
+
if (ready.length === 0) {
|
|
166
|
+
throw new Error("Execution graph deadlock detected: no ready nodes and graph not complete");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const batch = ready.slice(0, maxWorkers);
|
|
170
|
+
await Promise.all(
|
|
171
|
+
batch.map(async (node) => {
|
|
172
|
+
const handler = this.handlers.get(node.kind);
|
|
173
|
+
if (handler) await handler(node);
|
|
174
|
+
done.add(node.id);
|
|
175
|
+
order.push(node.id);
|
|
176
|
+
remaining.delete(node.id);
|
|
177
|
+
}),
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { order, conflicts };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function topologicalSort(nodes: UokGraphNode[]): UokGraphNode[] {
|
|
186
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
187
|
+
const inDegree = new Map(nodes.map((n) => [n.id, 0]));
|
|
188
|
+
|
|
189
|
+
for (const node of nodes) {
|
|
190
|
+
for (const dep of node.dependsOn) {
|
|
191
|
+
if (nodeMap.has(dep)) {
|
|
192
|
+
inDegree.set(node.id, (inDegree.get(node.id) ?? 0) + 1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const queue = nodes
|
|
198
|
+
.filter((n) => (inDegree.get(n.id) ?? 0) === 0)
|
|
199
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
200
|
+
const ordered: UokGraphNode[] = [];
|
|
201
|
+
|
|
202
|
+
while (queue.length > 0) {
|
|
203
|
+
const current = queue.shift()!;
|
|
204
|
+
ordered.push(current);
|
|
205
|
+
|
|
206
|
+
for (const next of nodes) {
|
|
207
|
+
if (!next.dependsOn.includes(current.id)) continue;
|
|
208
|
+
const deg = (inDegree.get(next.id) ?? 0) - 1;
|
|
209
|
+
inDegree.set(next.id, deg);
|
|
210
|
+
if (deg === 0) {
|
|
211
|
+
queue.push(next);
|
|
212
|
+
queue.sort((a, b) => a.id.localeCompare(b.id));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (ordered.length !== nodes.length) {
|
|
218
|
+
throw new Error("Execution graph has cyclic dependencies");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return ordered;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function detectFileConflicts(nodes: UokGraphNode[]): Array<{ nodeA: string; nodeB: string; file: string }> {
|
|
225
|
+
const conflicts: Array<{ nodeA: string; nodeB: string; file: string }> = [];
|
|
226
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
227
|
+
const a = nodes[i];
|
|
228
|
+
const writesA = new Set(a.writes ?? []);
|
|
229
|
+
if (writesA.size === 0) continue;
|
|
230
|
+
|
|
231
|
+
for (let j = i + 1; j < nodes.length; j++) {
|
|
232
|
+
const b = nodes[j];
|
|
233
|
+
for (const file of b.writes ?? []) {
|
|
234
|
+
if (writesA.has(file)) {
|
|
235
|
+
conflicts.push({ nodeA: a.id, nodeB: b.id, file });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return conflicts;
|
|
241
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { GSDPreferences } from "../preferences.js";
|
|
2
|
+
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
3
|
+
|
|
4
|
+
export interface UokFlags {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
legacyFallback: boolean;
|
|
7
|
+
gates: boolean;
|
|
8
|
+
modelPolicy: boolean;
|
|
9
|
+
executionGraph: boolean;
|
|
10
|
+
gitops: boolean;
|
|
11
|
+
gitopsTurnAction: "commit" | "snapshot" | "status-only";
|
|
12
|
+
gitopsTurnPush: boolean;
|
|
13
|
+
auditUnified: boolean;
|
|
14
|
+
planV2: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function envForcesLegacyFallback(): boolean {
|
|
18
|
+
const raw = process.env.GSD_UOK_FORCE_LEGACY ?? process.env.GSD_UOK_LEGACY_FALLBACK;
|
|
19
|
+
if (!raw) return false;
|
|
20
|
+
const normalized = raw.trim().toLowerCase();
|
|
21
|
+
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function resolveUokFlags(prefs: GSDPreferences | undefined): UokFlags {
|
|
25
|
+
const uok = prefs?.uok;
|
|
26
|
+
const legacyFallback = uok?.legacy_fallback?.enabled === true || envForcesLegacyFallback();
|
|
27
|
+
const enabledByPreference = uok?.enabled ?? true;
|
|
28
|
+
return {
|
|
29
|
+
enabled: enabledByPreference && !legacyFallback,
|
|
30
|
+
legacyFallback,
|
|
31
|
+
gates: uok?.gates?.enabled === true,
|
|
32
|
+
modelPolicy: uok?.model_policy?.enabled === true,
|
|
33
|
+
executionGraph: uok?.execution_graph?.enabled === true,
|
|
34
|
+
gitops: uok?.gitops?.enabled === true,
|
|
35
|
+
gitopsTurnAction: uok?.gitops?.turn_action ?? "status-only",
|
|
36
|
+
gitopsTurnPush: uok?.gitops?.turn_push === true,
|
|
37
|
+
auditUnified: uok?.audit_unified?.enabled === true,
|
|
38
|
+
planV2: uok?.plan_v2?.enabled === true,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function loadUokFlags(): UokFlags {
|
|
43
|
+
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
44
|
+
return resolveUokFlags(prefs);
|
|
45
|
+
}
|