@humwick/server 0.130.1 → 0.130.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-administration.md +4 -0
- package/docs/guides/tools-coordination.md +2 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +74 -0
- package/docs/openapi.json +486 -4
- package/package.json +10 -18
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/agent-profiles-cxtRBn6O.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-B_rFEbnL.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/index-CqqgOI5R.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/project-profile-instructions-DETKFn_E.js +2 -0
- package/public/assets/projects-M_m6AHws.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-V9Z-GxUd.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-CXU75HRF.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/use-project-list-CpWl6eHQ.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/versioned-prompt-editor-CIVg7XB1.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +31 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
- package/runner/src/adapters/claude-effort.ts +2 -4
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/codex-launch-config.ts +4 -5
- package/runner/src/adapters/codex.ts +1 -1
- package/runner/src/adapters/opencode-provider.ts +7 -22
- package/runner/src/adapters/opencode.ts +4 -4
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -4
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/bin/claude.ts +4 -0
- package/runner/src/bin/codex.ts +4 -0
- package/runner/src/bin/opencode.ts +4 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/index.ts +5 -2
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +35 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +32 -38
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/cd-config.ts +8 -0
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +31 -98
- package/src/bus.ts +40 -39
- package/src/cd-deploy-notify.ts +32 -4
- package/src/cd-host-lag-notify.ts +7 -6
- package/src/ci/incidents.ts +2 -2
- package/src/ci/monitor.ts +5 -8
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +4 -9
- package/src/ci/transition-notify.ts +12 -44
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/cd-pauses.ts +19 -0
- package/src/cli/orchestrator.ts +1 -1
- package/src/cli/state.ts +2 -19
- package/src/cli/task-edit.ts +22 -0
- package/src/cli/task.ts +3 -1
- package/src/cli/workflow.ts +19 -4
- package/src/commands-db.ts +7 -7
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/activity-async.ts +6 -1
- package/src/db/activity-write-ops.ts +12 -1
- package/src/db/activity.ts +1 -14
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agent-search.ts +1 -15
- package/src/db/agents-async.ts +59 -9
- package/src/db/agents-write-ops.ts +12 -3
- package/src/db/agents.ts +95 -65
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/config-store-write-ops.ts +7 -2
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +7 -0
- package/src/db/continuations.ts +6 -6
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/db-writer-worker.ts +8 -1
- package/src/db/deploy-events-async.ts +1 -0
- package/src/db/deploy-events-read-ops.ts +2 -1
- package/src/db/deploy-events.ts +35 -4
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/hosts-registration.ts +10 -2
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -17
- package/src/db/index.ts +2 -0
- package/src/db/integrations-async.ts +8 -0
- package/src/db/integrations-ops.ts +15 -0
- package/src/db/integrations.ts +15 -21
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +23 -0
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +15 -16
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/long-running-work.ts +2 -2
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +41 -2
- package/src/db/maintenance-job-reconcile.ts +61 -0
- package/src/db/maintenance-job-runs-async.ts +14 -0
- package/src/db/maintenance-job-write-ops.ts +9 -0
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +25 -16
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +14 -76
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +42 -61
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-profile-instructions.ts +50 -0
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/prompt-versions.ts +9 -2
- package/src/db/provider-config-history.ts +8 -3
- package/src/db/provider-model-seed.ts +34 -0
- package/src/db/read-op-marshaling-fixtures.ts +23 -0
- package/src/db/read-ops.ts +8 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/routing-policy.ts +2 -3
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +13 -4
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +9 -6
- package/src/db/task-entity.ts +28 -6
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/token-db-write-ops.ts +19 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +21 -20
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +37 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +58 -56
- package/src/dev.ts +8 -3
- package/src/dispatch-availability.ts +10 -6
- package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host/disk-alert.ts +121 -0
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/land-gate-notifications.ts +11 -10
- package/src/land-gate-queue-progress.ts +3 -3
- package/src/land-settle-dispatch.ts +52 -92
- package/src/lifecycle-context-pressure.ts +11 -10
- package/src/lifecycle-manager.ts +107 -100
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +19 -20
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +32 -69
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +98 -137
- package/src/maintenance/stalled-delivery-pager.ts +10 -9
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +18 -28
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +32 -28
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +12 -9
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +6 -5
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +4 -3
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +13 -12
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +5 -5
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +13 -4
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notification-types.ts +2 -1
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +23 -11
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +12 -1
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-catalog-store.ts +3 -49
- package/src/provider-config-store.ts +12 -11
- package/src/provider-model-seed.ts +1 -18
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-quota-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +6 -5
- package/src/repo-config-source.ts +10 -4
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +2 -2
- package/src/routes/agents.ts +19 -121
- package/src/routes/auth.ts +14 -15
- package/src/routes/authority-audit.ts +2 -2
- package/src/routes/automations.ts +6 -5
- package/src/routes/channel-binding-delete.ts +1 -1
- package/src/routes/channel-output.ts +3 -3
- package/src/routes/claude-api-budget.ts +5 -5
- package/src/routes/commands-listing.ts +5 -1
- package/src/routes/commands.ts +31 -29
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +12 -2
- package/src/routes/integrations.ts +32 -56
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +9 -9
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +2 -2
- package/src/routes/orchestrator-host-registration.ts +4 -2
- package/src/routes/orchestrator-host-utilization.ts +5 -3
- package/src/routes/orchestrator-proxy.ts +4 -4
- package/src/routes/orchestrator.ts +28 -19
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +3 -3
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-config.ts +6 -6
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +6 -6
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/stats.ts +6 -6
- package/src/routes/task-http.ts +15 -1
- package/src/routes/task-issues.ts +11 -26
- package/src/routes/tasks.ts +22 -53
- package/src/routes/team-templates.ts +12 -12
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +30 -22
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +22 -7
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-policy-push.ts +6 -6
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +21 -13
- package/src/runtime-tokens.ts +59 -35
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +16 -21
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +2 -2
- package/src/server.ts +26 -24
- package/src/services/agent-action.ts +12 -31
- package/src/services/agent-effort.ts +7 -32
- package/src/services/agent-hang-watchdog-job.ts +2 -2
- package/src/services/agent-heartbeat.ts +166 -0
- package/src/services/agent-reporting.ts +1 -1
- package/src/services/browser-inventory.ts +3 -3
- package/src/services/browser-session-state.ts +3 -2
- package/src/services/browser-session.ts +21 -27
- package/src/services/bus-command-update.ts +9 -9
- package/src/services/checkout-refresh-state.ts +1 -0
- package/src/services/checkout-refresh.test-fixture.ts +3 -2
- package/src/services/command-host.ts +7 -2
- package/src/services/coordinator-digest.ts +3 -2
- package/src/services/dispatch-command.ts +12 -13
- package/src/services/effective-launch-driver.ts +14 -9
- package/src/services/host-changed-paths.test-fixture.ts +5 -6
- package/src/services/host-project-readiness.ts +2 -2
- package/src/services/host-providers.ts +1 -1
- package/src/services/host-utilization.ts +27 -4
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +9 -10
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +69 -72
- package/src/services/issue-refs.ts +10 -15
- package/src/services/kernel-timers-cutover-chaos-worker.ts +11 -8
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +4 -4
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +25 -8
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +17 -53
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +9 -3
- package/src/services/profile-trust.ts +6 -5
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +74 -61
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +21 -34
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +25 -43
- package/src/services/spawn-chain-inspector.ts +7 -14
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +8 -9
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +8 -17
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +12 -11
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +25 -20
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +26 -13
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +5 -3
- package/src/services/workflow-effect-driver.ts +42 -17
- package/src/services/workflow-effects.ts +58 -37
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +14 -11
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +6 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +61 -33
- package/src/services/workflow-supervisor-state.ts +26 -1
- package/src/services/workflow-supervisor.ts +11 -6
- package/src/services/workspace-recovery.ts +4 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +28 -10
- package/src/spawn-targets.ts +9 -9
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +62 -57
- package/src/state-adoption/cd-cutover.ts +53 -7
- package/src/state-adoption/fleet-cutover.ts +35 -0
- package/src/state-adoption/fleet-plan.ts +36 -0
- package/src/state-adoption/index.ts +2 -2
- package/src/state-adoption/linux-plan.ts +2 -2
- package/src/state-adoption/linux.ts +2 -2
- package/src/state-adoption/macos-plan.ts +2 -2
- package/src/state-adoption/macos.ts +1 -1
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +9 -8
- package/src/task-dispatch-live.ts +6 -3
- package/src/task-dispatcher.ts +3 -3
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +26 -17
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +4 -4
- package/node_modules/@humwick/kernel/LICENSE +0 -167
- package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
- package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
- package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
- package/node_modules/@humwick/kernel/config.ts +0 -111
- package/node_modules/@humwick/kernel/contract.ts +0 -572
- package/node_modules/@humwick/kernel/control-authz.ts +0 -281
- package/node_modules/@humwick/kernel/control.ts +0 -645
- package/node_modules/@humwick/kernel/effects.ts +0 -493
- package/node_modules/@humwick/kernel/event-log.ts +0 -319
- package/node_modules/@humwick/kernel/http-transport.ts +0 -384
- package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
- package/node_modules/@humwick/kernel/identity.ts +0 -248
- package/node_modules/@humwick/kernel/index.ts +0 -28
- package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
- package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
- package/node_modules/@humwick/kernel/landing.ts +0 -953
- package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
- package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
- package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
- package/node_modules/@humwick/kernel/message-authority.ts +0 -281
- package/node_modules/@humwick/kernel/module-host.ts +0 -722
- package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
- package/node_modules/@humwick/kernel/package.json +0 -39
- package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
- package/node_modules/@humwick/kernel/persistence.ts +0 -510
- package/node_modules/@humwick/kernel/registry.ts +0 -60
- package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
- package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
- package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
- package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
- package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
- package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
- package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
- package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
- package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
- package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
- package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
- package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
- package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
- package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
- package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
- package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
- package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
- package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
- package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
- package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
- package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
- package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
- package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
- package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
- package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
- package/node_modules/@humwick/offload/LICENSE +0 -167
- package/node_modules/@humwick/offload/README.md +0 -57
- package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
- package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
- package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
- package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.js +0 -80
- package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
- package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/index.js +0 -5
- package/node_modules/@humwick/offload/dist/index.js.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
- package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
- package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/types.js +0 -176
- package/node_modules/@humwick/offload/dist/types.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
- package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
- package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.js +0 -1
- package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
- package/node_modules/@humwick/offload/package.json +0 -42
- package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
- package/node_modules/@humwick/offload/src/envelope.ts +0 -92
- package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
- package/node_modules/@humwick/offload/src/index.ts +0 -4
- package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
- package/node_modules/@humwick/offload/src/types.ts +0 -235
- package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
- package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
- package/node_modules/@humwick/offload/src/worker.ts +0 -5
- package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
- package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
- package/public/assets/index-B7ZerHLY.css +0 -2
- package/public/assets/index-BU3uWo2t.js +0 -15
- package/public/assets/projects-B_lmcqfO.js +0 -2
- package/public/assets/provider-display-DbLWpP3j.js +0 -2
- package/public/assets/run-card-CO_bguQf.js +0 -2
- package/public/assets/shipping-Bu8p1gEw.js +0 -2
- package/public/assets/store-BvtFdlGX.js +0 -9
- package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/db/on-loop-write-transaction.ts +0 -34
- package/src/routing-model-aliases.ts +0 -21
|
@@ -1,507 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { emptyBoundary, validateWorkflowSchema, validateWorkflowExpressions, workflowObject, workflowCondition } from "./workflow-values";
|
|
3
|
-
|
|
4
|
-
// #3045 — the declarative workflow format (`.agent-relay/workflows/<name>.yaml`) and its routing.
|
|
5
|
-
// Pure data: the src side reads the file at a landed commit; this module owns what it may say.
|
|
6
|
-
|
|
7
|
-
/** Built-in terminal steps: `land` clears the input Task's review hold and waits for the land;
|
|
8
|
-
* `escalate` hands the run, with its whole history, back to the coordinator. */
|
|
9
|
-
const WORKFLOW_TERMINALS = ["land", "close", "escalate"] as const;
|
|
10
|
-
/** The optional built-in step after `land`: the repo's CI on the landed commit, read from the CI monitor (#3045 H5). */
|
|
11
|
-
export const CI_MAIN_STEP = "ci-main";
|
|
12
|
-
const BUILT_IN_STEPS = [...WORKFLOW_TERMINALS, CI_MAIN_STEP, "done", "fail", "wait", "next"] as const;
|
|
13
|
-
const DISPOSITIONS = ["complete", "failed", "blocked", "needs-review"] as const;
|
|
14
|
-
const GATE_VERDICTS = ["pass", "fail"] as const;
|
|
15
|
-
/** #3166 — the outcome of a step whose agent exited without a delivery; unrouted, it escalates like any outcome. */
|
|
16
|
-
export const WORKFLOW_EXITED_OUTCOME = "exited";
|
|
17
|
-
const TOP_FIELDS = ["description", "steps", "routes", "land", CI_MAIN_STEP, "version", "inputs", "outputs", "return", "limits"] as const;
|
|
18
|
-
/** #3121 — what a step's agent may be pinned to, in its YAML step and per run at relay_workflow_start / resume.
|
|
19
|
-
* #3091 `profile` replaces the base profile the step's role extends. */
|
|
20
|
-
export const WORKFLOW_PIN_FIELDS = ["provider", "model", "effort", "orchestratorId", "profile"] as const;
|
|
21
|
-
const STEP_FIELDS = ["role", "task", "gate", "reap", "timeout", "crossProvider", ...WORKFLOW_PIN_FIELDS, "script", "on", "verify", "workflow", "inputs", "output-schema", "taskId", "for-each", "parallel", "if", "decision"] as const;
|
|
22
|
-
const LAND_FIELDS = ["timeout", "then"] as const;
|
|
23
|
-
const CI_MAIN_FIELDS = ["workflow", "timeout"] as const;
|
|
24
|
-
/** When the run shuts a step's agents down; `on-run-done` keeps the builder warm across fix rounds. */
|
|
25
|
-
export const WORKFLOW_REAP_POLICIES = ["on-step-done", "on-run-done", "never"] as const;
|
|
26
|
-
export type WorkflowReapPolicy = (typeof WORKFLOW_REAP_POLICIES)[number];
|
|
27
|
-
const BOUND_FIELDS = ["to", "max", "else"] as const;
|
|
28
|
-
const NAME = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
29
|
-
const DURATION = /^(\d+)\s*(s|m|h|d)$/;
|
|
30
|
-
const DURATION_UNIT_MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 } as const;
|
|
31
|
-
const MIN_TIMEOUT_MS = 60_000;
|
|
32
|
-
const MAX_TIMEOUT_MS = 30 * 86_400_000;
|
|
33
|
-
/** How long a wait may make no progress before the run escalates once and keeps waiting (#3045 H1). */
|
|
34
|
-
export const WORKFLOW_DEFAULT_TIMEOUT_MS = { input: 4 * 3_600_000, new: 2 * 3_600_000, land: 2 * 3_600_000, ci: 3_600_000 } as const;
|
|
35
|
-
|
|
36
|
-
const timeoutSchema = z.number().int().min(MIN_TIMEOUT_MS).max(MAX_TIMEOUT_MS);
|
|
37
|
-
const pinValue = z.string().min(1).optional();
|
|
38
|
-
export const workflowScriptSchema = z.object({
|
|
39
|
-
run: z.string().min(1).max(6000), host: z.string().min(1), everyMs: z.number().int().min(1000).optional(),
|
|
40
|
-
timeoutMs: z.number().int().min(1000).max(86_400_000), on: z.record(z.string(), z.string()),
|
|
41
|
-
});
|
|
42
|
-
export const workflowPinSchema = z.object({ provider: pinValue, model: pinValue, effort: pinValue, orchestratorId: pinValue, profile: pinValue });
|
|
43
|
-
/** A pin the coordinator set for one step at the start call or a later resume. */
|
|
44
|
-
export const workflowCallPinSchema = workflowPinSchema.extend({ by: z.enum(["start", "resume"]) });
|
|
45
|
-
const pinSource = z.enum(["start", "resume", "team", "global", "workflow"]).optional();
|
|
46
|
-
/** The pin a step's dispatch applies, and where each field came from (`workflow`: its YAML step). */
|
|
47
|
-
export const workflowAppliedPinSchema = workflowPinSchema.extend({ from: z.object({ provider: pinSource, model: pinSource, effort: pinSource, orchestratorId: pinSource, profile: pinSource }) });
|
|
48
|
-
export const workflowRoutingDefaultsSchema = z.object({
|
|
49
|
-
global: z.record(z.string(), workflowPinSchema).optional(),
|
|
50
|
-
team: z.record(z.string(), workflowPinSchema).optional(),
|
|
51
|
-
teamId: z.string().optional(),
|
|
52
|
-
});
|
|
53
|
-
export type WorkflowRoutingDefaults = z.output<typeof workflowRoutingDefaultsSchema>;
|
|
54
|
-
export const workflowDecisionSchema = z.object({
|
|
55
|
-
title: z.string().min(1), context: z.string().optional(), options: z.unknown().optional(),
|
|
56
|
-
"multi-select": z.unknown().optional(), answeredBy: z.enum(["coordinator", "operator"]).optional(), deadlineMs: timeoutSchema.optional(),
|
|
57
|
-
});
|
|
58
|
-
const actionSchema = workflowPinSchema.extend({
|
|
59
|
-
role: z.string().min(1), task: z.enum(["input", "new"]), gate: z.string().min(1).optional(), reap: z.enum(WORKFLOW_REAP_POLICIES).optional(),
|
|
60
|
-
timeoutMs: timeoutSchema.optional(),
|
|
61
|
-
/** #3105 — the step's agent prefers a provider other than this named step's agent's; with none live and with quota it runs on the same one. */
|
|
62
|
-
crossProvider: z.string().min(1).optional(),
|
|
63
|
-
script: workflowScriptSchema.optional(), decision: workflowDecisionSchema.optional(),
|
|
64
|
-
verify: z.boolean().optional(),
|
|
65
|
-
condition: z.union([z.boolean(), z.string()]).optional(),
|
|
66
|
-
workflow: z.string().optional(), inputs: workflowObject.optional(), outputSchema: workflowObject.optional(), taskId: z.unknown().optional(),
|
|
67
|
-
});
|
|
68
|
-
export type WorkflowStep = z.output<typeof actionSchema> & { forEach?: { items: unknown; concurrency: number; onFailure: "fail-fast" | "continue" | "escalate"; action: WorkflowStep; key?: unknown; needs?: unknown; branches?: Record<string, WorkflowStep>; join?: "all" | "any" } };
|
|
69
|
-
const stepSchema: z.ZodType<WorkflowStep> = actionSchema.extend({ forEach: z.lazy(() => z.object({ items: z.unknown(), concurrency: z.number().int().min(1).max(32), onFailure: z.enum(["fail-fast", "continue", "escalate"]), action: stepSchema, key: z.unknown().optional(), needs: z.unknown().optional(), branches: z.record(z.string(), stepSchema).optional(), join: z.enum(["all", "any"]).optional() })).optional() });
|
|
70
|
-
const boundedSchema = z.object({ to: z.string().min(1), max: z.number().int().min(1), else: z.string().min(1) });
|
|
71
|
-
|
|
72
|
-
const targetSchema = z.union([z.string().min(1), boundedSchema]);
|
|
73
|
-
const guardedSchema = z.array(z.object({ condition: z.union([z.string(), z.boolean()]).optional(), target: targetSchema }));
|
|
74
|
-
|
|
75
|
-
export const workflowDefinitionSchema = z.object({
|
|
76
|
-
version: z.literal(2).optional(),
|
|
77
|
-
inputs: workflowObject.optional(), outputs: workflowObject.optional(), returns: workflowObject.optional(),
|
|
78
|
-
limits: z.record(z.string(), z.number().int().positive()).optional(),
|
|
79
|
-
description: z.string().optional(),
|
|
80
|
-
/** The first declared step; it runs on the run's input Task. */
|
|
81
|
-
start: z.string().min(1),
|
|
82
|
-
steps: z.record(z.string(), stepSchema),
|
|
83
|
-
routes: z.record(z.string(), z.record(z.string(), z.union([z.string().min(1), boundedSchema, guardedSchema]))),
|
|
84
|
-
/** The built-in land step's wait. */
|
|
85
|
-
land: z.object({ timeoutMs: timeoutSchema.optional(), then: z.string().optional() }).optional(),
|
|
86
|
-
/** Wait for CI on the landed commit; `workflow` names one CI workflow, else every watched one counts.
|
|
87
|
-
* `timeoutMs` bounds the wait: past it without a verdict the result says "no CI". */
|
|
88
|
-
ciMain: z.object({ workflow: z.string().min(1).optional(), timeoutMs: timeoutSchema.optional() }).optional(),
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
export type WorkflowDefinition = z.output<typeof workflowDefinitionSchema>;
|
|
92
|
-
export type WorkflowPin = z.output<typeof workflowPinSchema>;
|
|
93
|
-
export type WorkflowCallPin = z.output<typeof workflowCallPinSchema>;
|
|
94
|
-
export type WorkflowAppliedPin = z.output<typeof workflowAppliedPinSchema>;
|
|
95
|
-
|
|
96
|
-
export function workflowItemAction(loop: NonNullable<WorkflowStep["forEach"]>, slot: { key?: string; item?: unknown }): WorkflowStep {
|
|
97
|
-
return loop.branches ? loop.branches[String(slot.key ?? slot.item)]! : loop.action;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export function workflowActions(definition: Pick<WorkflowDefinition, "steps">): WorkflowStep[] {
|
|
101
|
-
return workflowActionEntries(definition).map(([, step]) => step);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function workflowActionEntries(definition: Pick<WorkflowDefinition, "steps">): Array<[string, WorkflowStep]> {
|
|
105
|
-
return Object.entries(definition.steps).flatMap(([name, step]): Array<[string, WorkflowStep]> => [[name, step], ...(step.forEach ? workflowActionEntries({ steps: step.forEach.branches ? Object.fromEntries(Object.entries(step.forEach.branches).map(([key, action]) => [`${name}.${key}`, action])) : { [`${name}.item`]: step.forEach.action } }) : [])]);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export class WorkflowDefinitionError extends Error {}
|
|
109
|
-
|
|
110
|
-
function fail(message: string): never {
|
|
111
|
-
throw new WorkflowDefinitionError(message);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function isMapping(value: unknown): value is Record<string, unknown> {
|
|
115
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function onlyFields(value: Record<string, unknown>, allowed: readonly string[], where: string): void {
|
|
119
|
-
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
|
|
120
|
-
if (unknown.length) fail(`${where}: unknown field${unknown.length > 1 ? "s" : ""} ${unknown.map((key) => `"${key}"`).join(", ")}; allowed: ${allowed.join(", ")}`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function text(value: unknown, where: string): string {
|
|
124
|
-
if (typeof value !== "string" || !value.trim()) fail(`${where} must be a non-empty string`);
|
|
125
|
-
return value.trim();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** A YAML duration (`90s`, `30m`, `4h`, `2d`), between one minute and 30 days. */
|
|
129
|
-
function duration(value: unknown, where: string, min = MIN_TIMEOUT_MS, max = MAX_TIMEOUT_MS): number {
|
|
130
|
-
const match = typeof value === "string" ? DURATION.exec(value.trim()) : null;
|
|
131
|
-
if (!match) fail(`${where} must be a duration like 30m, 4h or 2d`);
|
|
132
|
-
const ms = Number(match[1]) * DURATION_UNIT_MS[match[2] as keyof typeof DURATION_UNIT_MS];
|
|
133
|
-
if (ms < min || ms > max) fail(`${where} must be between ${formatWorkflowDuration(min)} and ${formatWorkflowDuration(max)}`);
|
|
134
|
-
return ms;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** A duration in the file's own notation, in its largest whole unit. */
|
|
138
|
-
export function formatWorkflowDuration(ms: number): string {
|
|
139
|
-
const unit = (["d", "h", "m"] as const).find((u) => ms % DURATION_UNIT_MS[u] === 0) ?? "s";
|
|
140
|
-
return `${Math.round(ms / DURATION_UNIT_MS[unit])}${unit}`;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function routeTargets(route: WorkflowDefinition["routes"][string][string]): string[] {
|
|
144
|
-
return Array.isArray(route) ? route.flatMap(branch => routeTargets(branch.target)) : typeof route === "string" ? [route] : [route.to, route.else];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** The outcomes a step can route on: its delivery disposition, or for a gated step the gate's verdict, and its agent's exit. */
|
|
148
|
-
function stepOutcomes(step: WorkflowStep): readonly string[] {
|
|
149
|
-
return [...(step.condition !== undefined ? ["skipped"] : []), ...(step.workflow ? ["cancelled"] : []), ...(step.gate ? [...GATE_VERDICTS, ...DISPOSITIONS.filter((d) => d !== "complete")] : DISPOSITIONS), WORKFLOW_EXITED_OUTCOME];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function parseStep(name: string, value: unknown, version?: number, depth = 0): WorkflowStep {
|
|
153
|
-
const where = `steps.${name}`;
|
|
154
|
-
if (!NAME.test(name)) fail(`${where}: step names are letters, digits, - and _ (starting with a letter)`);
|
|
155
|
-
if ((BUILT_IN_STEPS as readonly string[]).includes(name)) fail(`${where}: "${name}" is a built-in step and cannot be declared`);
|
|
156
|
-
if (!isMapping(value)) fail(`${where} must be a mapping with role and task`);
|
|
157
|
-
onlyFields(value, STEP_FIELDS, where);
|
|
158
|
-
if (depth > 8) fail(`${where}: container depth exceeds 8`);
|
|
159
|
-
const data: Pick<WorkflowStep, "inputs" | "outputSchema" | "condition"> = {};
|
|
160
|
-
if (value.if !== undefined) {
|
|
161
|
-
if (version !== 2 || typeof value.if !== "boolean" && !(typeof value.if === "string" && value.if.startsWith("${{"))) fail(`${where}.if requires v2 and a boolean or expression`);
|
|
162
|
-
data.condition = value.if as string | boolean;
|
|
163
|
-
}
|
|
164
|
-
if (["role", "script", "workflow", "for-each", "parallel", "decision"].filter(key => value[key] !== undefined).length !== 1) fail(`${where}: declare exactly one action`);
|
|
165
|
-
if (value.inputs !== undefined) {
|
|
166
|
-
if (version !== 2 || !isMapping(value.inputs)) fail(`${where}.inputs requires v2 and an object`);
|
|
167
|
-
data.inputs = value.inputs;
|
|
168
|
-
}
|
|
169
|
-
if (value["output-schema"] !== undefined) {
|
|
170
|
-
if (version !== 2 || !isMapping(value["output-schema"])) fail(`${where}.output-schema requires v2 and an object`);
|
|
171
|
-
validateWorkflowSchema(value["output-schema"]);
|
|
172
|
-
data.outputSchema = value["output-schema"];
|
|
173
|
-
}
|
|
174
|
-
if (value.decision !== undefined) {
|
|
175
|
-
if (version !== 2) fail(`${where}.decision requires version: 2`);
|
|
176
|
-
onlyFields(value, ["decision", "inputs", "output-schema", "if"], where);
|
|
177
|
-
if (!isMapping(value.decision)) fail(`${where}.decision must be a mapping`);
|
|
178
|
-
const decision = value.decision;
|
|
179
|
-
onlyFields(decision, ["title", "context", "options", "multi-select", "deadline", "answeredBy"], `${where}.decision`);
|
|
180
|
-
if ((decision.options !== undefined) === (decision["multi-select"] !== undefined)) fail(`${where}.decision: declare options or multi-select`);
|
|
181
|
-
if (decision.answeredBy !== undefined && decision.answeredBy !== "operator" && decision.answeredBy !== "coordinator") fail(`${where}.decision.answeredBy must be coordinator or operator`);
|
|
182
|
-
const items = decision.options ?? decision["multi-select"];
|
|
183
|
-
if (!Array.isArray(items) && !(typeof items === "string" && items.startsWith("${{"))) fail(`${where}.decision choices must be an array or whole expression`);
|
|
184
|
-
return { role: "decision", task: "new", ...data, decision: { title: text(decision.title, `${where}.decision.title`),
|
|
185
|
-
...(decision.answeredBy !== undefined ? { answeredBy: decision.answeredBy as "coordinator" | "operator" } : {}),
|
|
186
|
-
...(decision.context !== undefined ? { context: text(decision.context, `${where}.decision.context`) } : {}),
|
|
187
|
-
...(decision.options !== undefined ? { options: decision.options } : { "multi-select": decision["multi-select"] }),
|
|
188
|
-
...(decision.deadline !== undefined ? { deadlineMs: duration(decision.deadline, `${where}.decision.deadline`) } : {}),
|
|
189
|
-
} };
|
|
190
|
-
}
|
|
191
|
-
if (value.parallel !== undefined) {
|
|
192
|
-
if (version !== 2) fail(`${where}.parallel requires version: 2`);
|
|
193
|
-
onlyFields(value, ["parallel", "timeout", "output-schema", "if"], where);
|
|
194
|
-
const group = value.parallel;
|
|
195
|
-
if (!isMapping(group)) fail(`${where}.parallel must be a mapping`);
|
|
196
|
-
onlyFields(group, ["join", "concurrency", "on-failure", "branches"], `${where}.parallel`);
|
|
197
|
-
const join = group.join ?? "all";
|
|
198
|
-
if (join !== "all" && join !== "any") fail(`${where}.parallel.join must be all or any`);
|
|
199
|
-
if (join === "any" && group["on-failure"] !== undefined) fail(`${where}.parallel: any cannot declare on-failure`);
|
|
200
|
-
if (!isMapping(group.branches) || !Object.keys(group.branches).length) fail(`${where}.parallel.branches must be nonempty`);
|
|
201
|
-
const branches = Object.fromEntries(Object.entries(group.branches).map(([key, action]) => [key, parseStep(key, action, version, depth + 1)]));
|
|
202
|
-
const lowered = parseStep(name, { "for-each": { items: Object.keys(branches), concurrency: group.concurrency ?? 32, "on-failure": join === "any" ? "continue" : group["on-failure"], do: Object.values(group.branches)[0] }, ...(value.timeout ? { timeout: value.timeout } : {}) }, version, depth);
|
|
203
|
-
return { ...lowered, ...data, role: "parallel", forEach: { ...lowered.forEach!, branches, join } };
|
|
204
|
-
}
|
|
205
|
-
if (value["for-each"] !== undefined) {
|
|
206
|
-
if (version !== 2) fail(`${where}.for-each requires version: 2`);
|
|
207
|
-
onlyFields(value, ["for-each", "timeout", "output-schema", "if"], where);
|
|
208
|
-
const loop = value["for-each"];
|
|
209
|
-
if (!isMapping(loop)) fail(`${where}.for-each must be a mapping`);
|
|
210
|
-
onlyFields(loop, ["items", "concurrency", "on-failure", "do", "key", "needs"], `${where}.for-each`);
|
|
211
|
-
if (!Array.isArray(loop.items) && !(typeof loop.items === "string" && loop.items.startsWith("${{"))) fail(`${where}.for-each.items must be an array or whole expression`);
|
|
212
|
-
const concurrency = loop.concurrency ?? 1;
|
|
213
|
-
if (typeof concurrency !== "number" || !Number.isInteger(concurrency) || concurrency < 1 || concurrency > 32) fail(`${where}.for-each.concurrency must be 1..32`);
|
|
214
|
-
const onFailure = loop["on-failure"] ?? "fail-fast";
|
|
215
|
-
if (onFailure !== "fail-fast" && onFailure !== "continue" && onFailure !== "escalate") fail(`${where}.for-each.on-failure must be fail-fast, continue or escalate`);
|
|
216
|
-
return { role: "for-each", task: "new", ...data, forEach: { items: loop.items, concurrency, onFailure, action: parseStep("item", loop.do, version, depth + 1), ...(loop.key !== undefined ? { key: loop.key } : {}), ...(loop.needs !== undefined ? { needs: loop.needs } : {}) }, timeoutMs: value.timeout === undefined ? 86400000 : duration(value.timeout, `${where}.timeout`) };
|
|
217
|
-
}
|
|
218
|
-
if (value.workflow !== undefined) {
|
|
219
|
-
if (version !== 2) fail(`${where}.workflow requires version: 2`);
|
|
220
|
-
onlyFields(value, ["workflow", "taskId", "inputs", "output-schema", "timeout", "if"], where);
|
|
221
|
-
const workflow = text(value.workflow, `${where}.workflow`);
|
|
222
|
-
if (!NAME.test(workflow)) fail(`${where}.workflow must name a workflow`);
|
|
223
|
-
return { role: "workflow", task: "new", workflow, ...data, ...(value.taskId !== undefined ? { taskId: value.taskId } : {}), timeoutMs: value.timeout === undefined ? 86400000 : duration(value.timeout, `${where}.timeout`) };
|
|
224
|
-
}
|
|
225
|
-
if (value.script !== undefined) {
|
|
226
|
-
onlyFields(value, ["script", "on", ...(version === 2 ? ["inputs", "output-schema", "if"] : [])], where);
|
|
227
|
-
if (!isMapping(value.script)) fail(`${where}.script must be a mapping`);
|
|
228
|
-
onlyFields(value.script, ["run", "host", "every", "timeout"], `${where}.script`);
|
|
229
|
-
const script = value.script;
|
|
230
|
-
const everyMs = script.every === undefined ? undefined : duration(script.every, `${where}.script.every`, 1000, 86_400_000);
|
|
231
|
-
if (!isMapping(value.on)) fail(`${where}.on must map exit codes to transitions`);
|
|
232
|
-
const on: Record<string, string> = {};
|
|
233
|
-
for (const [code, transition] of Object.entries(value.on)) {
|
|
234
|
-
if (code !== "default" && (!/^\d+$/.test(code) || Number(code) > 255)) fail(`${where}.on.${code}: expected exit code 0..255 or default`);
|
|
235
|
-
const action = text(transition, `${where}.on.${code}`);
|
|
236
|
-
if (!["next", "wait", "fail", "escalate"].includes(action) && !/^goto [A-Za-z][A-Za-z0-9_-]*$/.test(action)) fail(`${where}.on.${code}: use next, wait, fail, escalate or goto <step>`);
|
|
237
|
-
if (action === "wait" && !everyMs) fail(`${where}.on.${code}: wait requires script.every`);
|
|
238
|
-
on[code] = action;
|
|
239
|
-
}
|
|
240
|
-
return { role: "script", task: "new", ...data, script: {
|
|
241
|
-
run: text(script.run, `${where}.script.run`), host: script.host === undefined ? "owner" : text(script.host, `${where}.script.host`),
|
|
242
|
-
timeoutMs: duration(script.timeout, `${where}.script.timeout`, 1000, 86_400_000), ...(everyMs ? { everyMs } : {}), on,
|
|
243
|
-
} };
|
|
244
|
-
}
|
|
245
|
-
if (value.taskId !== undefined) fail(`${where}.taskId is only supported on a child workflow step`);
|
|
246
|
-
if (value.on !== undefined) fail(`${where}.on is only supported on a script step`);
|
|
247
|
-
const task = value.task;
|
|
248
|
-
if (task !== "input" && task !== "new") fail(`${where}.task must be input (the run's Task) or new (a fresh Task per entry)`);
|
|
249
|
-
const gate = value.gate === undefined ? undefined : text(value.gate, `${where}.gate`);
|
|
250
|
-
if (value.verify !== undefined && typeof value.verify !== "boolean") fail(`${where}.verify must be a boolean`);
|
|
251
|
-
if (value.verify && (task !== "new" || !gate)) fail(`${where}.verify requires task: new and a gate`);
|
|
252
|
-
const reap = value.reap;
|
|
253
|
-
if (reap !== undefined && !(WORKFLOW_REAP_POLICIES as readonly unknown[]).includes(reap)) fail(`${where}.reap must be ${WORKFLOW_REAP_POLICIES.join(", ")} (default on-run-done)`);
|
|
254
|
-
const timeoutMs = value.timeout === undefined ? undefined : duration(value.timeout, `${where}.timeout`);
|
|
255
|
-
const crossProvider = value.crossProvider === undefined ? undefined : text(value.crossProvider, `${where}.crossProvider`);
|
|
256
|
-
const pin: WorkflowPin = {};
|
|
257
|
-
for (const field of WORKFLOW_PIN_FIELDS) if (value[field] !== undefined) pin[field] = text(value[field], `${where}.${field}`);
|
|
258
|
-
return {
|
|
259
|
-
role: text(value.role, `${where}.role`), task, ...data, ...(gate ? { gate } : {}), ...(reap ? { reap: reap as WorkflowReapPolicy } : {}), ...(timeoutMs ? { timeoutMs } : {}),
|
|
260
|
-
...(crossProvider ? { crossProvider } : {}), ...(value.verify !== undefined ? { verify: value.verify as boolean } : {}), ...pin,
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/** #3121 — a start or resume call's pins, stamped with who set them; a step the workflow does not declare is refused. */
|
|
265
|
-
export function stampWorkflowPins(definition: WorkflowDefinition, pins: Record<string, WorkflowPin>, by: WorkflowCallPin["by"]): Record<string, WorkflowCallPin> {
|
|
266
|
-
const stamped: Record<string, WorkflowCallPin> = {};
|
|
267
|
-
for (const [step, pin] of Object.entries(pins)) {
|
|
268
|
-
if (!definition.steps[step]) fail(`pins.${step}: the workflow has no step "${step}"; pin one of ${Object.keys(definition.steps).join(", ")}`);
|
|
269
|
-
if (definition.steps[step]?.decision || definition.steps[step]?.script || definition.steps[step]?.workflow || definition.steps[step]?.forEach) fail(`pins.${step}: pin an agent step in the workflow`);
|
|
270
|
-
stamped[step] = { ...pin, by };
|
|
271
|
-
}
|
|
272
|
-
return stamped;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/** Fields merge in precedence order. Switching provider drops the lower layer's model and effort. */
|
|
276
|
-
export function workflowStepPin(definition: WorkflowDefinition, pins: Record<string, WorkflowCallPin> | undefined, step: string, defaults?: WorkflowRoutingDefaults): WorkflowAppliedPin | undefined {
|
|
277
|
-
const call = pins?.[step];
|
|
278
|
-
const declared = definition.steps[step];
|
|
279
|
-
const pin: WorkflowAppliedPin = { from: {} };
|
|
280
|
-
const layers = [[declared, "workflow"], [defaults?.global?.[declared?.role ?? ""], "global"], [defaults?.team?.[declared?.role ?? ""], "team"], [call, call?.by]] as const;
|
|
281
|
-
for (const [layer, source] of layers) {
|
|
282
|
-
if (!layer || !source) continue;
|
|
283
|
-
if (layer.provider && pin.provider && layer.provider !== pin.provider) {
|
|
284
|
-
for (const field of ["model", "effort"] as const) { delete pin[field]; delete pin.from[field]; }
|
|
285
|
-
}
|
|
286
|
-
for (const field of WORKFLOW_PIN_FIELDS) {
|
|
287
|
-
if (layer[field] === undefined) continue;
|
|
288
|
-
pin[field] = layer[field];
|
|
289
|
-
pin.from[field] = source;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return Object.keys(pin.from).length ? pin : undefined;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/** How long the wait of `step` (a declared step or `land`) may go without its delivery or land. */
|
|
296
|
-
export function waitTimeoutMs(definition: WorkflowDefinition, step: string): number {
|
|
297
|
-
if (step === "land") return definition.land?.timeoutMs ?? WORKFLOW_DEFAULT_TIMEOUT_MS.land;
|
|
298
|
-
if (step === CI_MAIN_STEP) return definition.ciMain?.timeoutMs ?? WORKFLOW_DEFAULT_TIMEOUT_MS.ci;
|
|
299
|
-
const declared = definition.steps[step];
|
|
300
|
-
if (declared?.script) return declared.script.timeoutMs;
|
|
301
|
-
return declared?.timeoutMs ?? WORKFLOW_DEFAULT_TIMEOUT_MS[declared?.task ?? "input"];
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/** A step's reap policy; an absent `reap` keeps its agents until the run ends. */
|
|
305
|
-
export function stepReap(step: WorkflowStep | undefined): WorkflowReapPolicy {
|
|
306
|
-
return step?.reap ?? "on-run-done";
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/** Presentation follows the actual land continuation, including built-in stations. */
|
|
310
|
-
export function workflowStations(definition: WorkflowDefinition): string[] {
|
|
311
|
-
const declared = Object.keys(definition.steps);
|
|
312
|
-
if (definition.version === 2) return declared;
|
|
313
|
-
const boundary = definition.land?.then ? declared.indexOf(definition.land.then) : declared.length;
|
|
314
|
-
const targets = Object.values(definition.routes).flatMap(routes => Object.values(routes).flatMap(route => routeTargets(route)));
|
|
315
|
-
targets.push(...Object.values(definition.steps).flatMap(step => Object.values(step.script?.on ?? {}).filter(action => action.startsWith("goto ")).map(action => action.slice(5))));
|
|
316
|
-
const closes = targets.includes("close");
|
|
317
|
-
if (!targets.includes("land")) return [...declared, ...(closes ? ["close"] : [])];
|
|
318
|
-
return [...declared.slice(0, boundary), "land", ...(definition.ciMain ? [CI_MAIN_STEP] : []), ...declared.slice(boundary), ...(closes ? ["close"] : [])];
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Validate a parsed YAML document. Every loop must be bounded: a route back to the same or an
|
|
323
|
-
* earlier step must be `{ to, max, else }`, and `else` must leave the loop.
|
|
324
|
-
*/
|
|
325
|
-
export function parseWorkflowDefinition(raw: unknown): WorkflowDefinition {
|
|
326
|
-
if (!isMapping(raw)) fail("the file must be a YAML mapping with steps and routes");
|
|
327
|
-
onlyFields(raw, TOP_FIELDS, "workflow");
|
|
328
|
-
if (raw.version !== undefined && raw.version !== 2) fail("version must be 2 or omitted");
|
|
329
|
-
const version = raw.version as 2 | undefined;
|
|
330
|
-
const top = raw;
|
|
331
|
-
if (!version && ["inputs", "outputs", "return", "limits"].some(field => top[field] !== undefined)) fail("typed boundaries require version: 2");
|
|
332
|
-
const boundary: Pick<WorkflowDefinition, "inputs" | "outputs" | "returns" | "limits"> = {};
|
|
333
|
-
if (version) {
|
|
334
|
-
for (const field of ["inputs", "outputs"] as const) {
|
|
335
|
-
const schema = raw[field] ?? emptyBoundary;
|
|
336
|
-
if (!isMapping(schema)) fail(`${field} must be a JSON Schema object`);
|
|
337
|
-
validateWorkflowSchema(schema, true);
|
|
338
|
-
boundary[field] = schema;
|
|
339
|
-
}
|
|
340
|
-
if (raw.return !== undefined && !isMapping(raw.return)) fail("return must be an object");
|
|
341
|
-
boundary.returns = raw.return as Record<string, unknown> | undefined ?? {};
|
|
342
|
-
if (raw.limits !== undefined) {
|
|
343
|
-
if (!isMapping(raw.limits)) fail("limits must be a mapping");
|
|
344
|
-
const defaults = { depth: 8, children: 256, treeChildren: 1024, activations: 4096, agents: 8, scripts: 8 };
|
|
345
|
-
boundary.limits = {};
|
|
346
|
-
for (const [key, value] of Object.entries(raw.limits)) {
|
|
347
|
-
if (!(key in defaults) || typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > defaults[key as keyof typeof defaults]) fail(`limits.${key} must lower a central default`);
|
|
348
|
-
boundary.limits[key] = value;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
const description = raw.description === undefined ? undefined : text(raw.description, "description");
|
|
353
|
-
if (Array.isArray(raw.steps)) {
|
|
354
|
-
const entries = raw.steps.map((step: unknown) => {
|
|
355
|
-
if (!isMapping(step)) fail("steps must contain named step mappings");
|
|
356
|
-
const { name, ...fields } = step;
|
|
357
|
-
return [text(name, "steps.name"), fields] as const;
|
|
358
|
-
});
|
|
359
|
-
if (new Set(entries.map(([name]) => name)).size !== entries.length) fail("steps have duplicate names");
|
|
360
|
-
raw = { ...raw, steps: Object.fromEntries(entries) };
|
|
361
|
-
}
|
|
362
|
-
if (!isMapping(raw) || !isMapping(raw.steps) || !Object.keys(raw.steps).length) fail("steps must map at least one step name to { role, task } or { script, on }");
|
|
363
|
-
const steps: Record<string, WorkflowStep> = {};
|
|
364
|
-
for (const [name, value] of Object.entries(raw.steps)) steps[name] = parseStep(name, value, version);
|
|
365
|
-
const order = Object.keys(steps);
|
|
366
|
-
if (version) {
|
|
367
|
-
validateWorkflowExpressions(boundary.returns, order);
|
|
368
|
-
for (const step of workflowActions({ steps })) { validateWorkflowExpressions(step.decision, order); validateWorkflowExpressions(step.condition, order); validateWorkflowExpressions(step.forEach?.key, order); validateWorkflowExpressions(step.forEach?.needs, order); validateWorkflowExpressions(step.inputs, order); validateWorkflowExpressions(step.taskId, order); if (typeof step.forEach?.items === "string") validateWorkflowExpressions(step.forEach.items, order); }
|
|
369
|
-
}
|
|
370
|
-
for (const [path, action] of workflowActionEntries({ steps })) {
|
|
371
|
-
if (path.includes(".") && action.script && Object.values(action.script.on).some(transition => transition.startsWith("goto "))) fail(`steps.${path}: a container body cannot goto another step; use a child workflow`);
|
|
372
|
-
}
|
|
373
|
-
const inputs = order.filter((name) => steps[name]!.task === "input");
|
|
374
|
-
const agents = order.filter((name) => !steps[name]!.decision && !steps[name]!.script && !steps[name]!.workflow && !steps[name]!.forEach);
|
|
375
|
-
if (!version && agents.length && (inputs.length !== 1 || inputs[0] !== agents[0])) fail(`exactly one step runs on the input Task (task: input), and it must be the first step; found ${inputs.length ? inputs.join(", ") : "none"}`);
|
|
376
|
-
for (const [name, step] of Object.entries(steps)) {
|
|
377
|
-
if (step.script) for (const action of Object.values(step.script.on)) {
|
|
378
|
-
if (!action.startsWith("goto ")) continue;
|
|
379
|
-
const to = action.slice(5);
|
|
380
|
-
if (to !== "land" && (!steps[to] || order.indexOf(to) <= order.indexOf(name))) fail(`steps.${name}.on: goto must name a later declared step or land`);
|
|
381
|
-
}
|
|
382
|
-
if (step.crossProvider !== undefined && (step.crossProvider === name || !steps[step.crossProvider])) fail(`steps.${name}.crossProvider must name another declared step, whose agent's provider this step avoids when it can`);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (raw.routes !== undefined && !isMapping(raw.routes)) fail("routes must map step names to { outcome: target }");
|
|
386
|
-
const routes: WorkflowDefinition["routes"] = {};
|
|
387
|
-
const target = (value: unknown, from: string, where: string): string => {
|
|
388
|
-
const to = text(value, where);
|
|
389
|
-
// #3660 — `done` ends a v1 run that lands nothing (a single-agent audit); `fail` stays v2.
|
|
390
|
-
if (!steps[to] && ![...WORKFLOW_TERMINALS, "done", ...(version ? ["fail"] : [])].includes(to)) fail(`${where}: unknown step "${to}"; use a declared step, land, done or escalate`);
|
|
391
|
-
if (steps[to] && order.indexOf(to) <= order.indexOf(from)) fail(`${where}: a loop back to ${to} must be bounded: { to: ${to}, max: N, else: escalate }`);
|
|
392
|
-
return to;
|
|
393
|
-
};
|
|
394
|
-
for (const [from, table] of Object.entries(raw.routes ?? {})) {
|
|
395
|
-
const step = steps[from];
|
|
396
|
-
if (!step) fail(`routes.${from}: no step named "${from}"`);
|
|
397
|
-
if (!isMapping(table)) fail(`routes.${from} must map outcomes to targets`);
|
|
398
|
-
const allowed = stepOutcomes(step);
|
|
399
|
-
routes[from] = {};
|
|
400
|
-
for (const [outcome, value] of Object.entries(table)) {
|
|
401
|
-
const where = `routes.${from}.${outcome}`;
|
|
402
|
-
if (!allowed.includes(outcome)) {
|
|
403
|
-
const gateNote = step.gate ? `step ${from} routes on its gate "${step.gate}"` : `step ${from} declares no gate`;
|
|
404
|
-
fail(`${where}: unknown outcome; ${gateNote}, so it routes on ${allowed.join(", ")}`);
|
|
405
|
-
}
|
|
406
|
-
const parseTarget = (value: unknown, where: string): z.output<typeof targetSchema> => {
|
|
407
|
-
if (!isMapping(value)) return target(value, from, where);
|
|
408
|
-
onlyFields(value, BOUND_FIELDS, where);
|
|
409
|
-
const to = text(value.to, `${where}.to`);
|
|
410
|
-
if (!steps[to]) fail(`${where}.to: unknown step "${to}"`);
|
|
411
|
-
if (typeof value.max !== "number" || !Number.isInteger(value.max) || value.max < 1) fail(`${where}.max must be a whole number of at least 1`);
|
|
412
|
-
return { to, max: value.max, else: target(value.else, from, `${where}.else`) };
|
|
413
|
-
};
|
|
414
|
-
if (Array.isArray(value)) {
|
|
415
|
-
if (!version || !value.length) fail(`${where}: guarded routes require v2 and a last else`);
|
|
416
|
-
routes[from][outcome] = value.map((entry, index) => {
|
|
417
|
-
if (!isMapping(entry)) fail(`${where}: expected guarded route`);
|
|
418
|
-
const last = index === value.length - 1;
|
|
419
|
-
onlyFields(entry, last ? ["else"] : ["if", "to"], where);
|
|
420
|
-
if (last) return { target: parseTarget(entry.else, where) };
|
|
421
|
-
if (typeof entry.if !== "boolean" && !(typeof entry.if === "string" && entry.if.startsWith("${{"))) fail(`${where}: if must be a boolean or expression`);
|
|
422
|
-
validateWorkflowExpressions(entry.if, order);
|
|
423
|
-
return { condition: entry.if as string | boolean, target: parseTarget(entry.to, where) };
|
|
424
|
-
});
|
|
425
|
-
} else routes[from][outcome] = parseTarget(value, where);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
const land = raw.land ?? {};
|
|
429
|
-
if (!isMapping(land)) fail("land must be a mapping: { timeout: 2h }");
|
|
430
|
-
onlyFields(land, LAND_FIELDS, "land");
|
|
431
|
-
const landTimeoutMs = land.timeout === undefined ? undefined : duration(land.timeout, "land.timeout");
|
|
432
|
-
const then = land.then === undefined ? undefined : text(land.then, "land.then");
|
|
433
|
-
if (then && (!steps[then] || then === order[0] || steps[then]!.task === "input")) fail("land.then must name a later declared step");
|
|
434
|
-
if (then) {
|
|
435
|
-
const seen = new Set<string>();
|
|
436
|
-
const pending = [then];
|
|
437
|
-
while (pending.length) {
|
|
438
|
-
const name = pending.pop()!;
|
|
439
|
-
if (seen.has(name)) continue;
|
|
440
|
-
seen.add(name);
|
|
441
|
-
if (name === "land" || (steps[name] && order.indexOf(name) < order.indexOf(then))) fail("land.then routes must stay after the land continuation");
|
|
442
|
-
const script = steps[name]?.script;
|
|
443
|
-
if (script) for (const action of Object.values(script.on)) {
|
|
444
|
-
if (action === "next") pending.push(order[order.indexOf(name) + 1] ?? "done");
|
|
445
|
-
if (action.startsWith("goto ")) pending.push(action.slice(5));
|
|
446
|
-
}
|
|
447
|
-
for (const route of Object.values(routes[name] ?? {})) pending.push(...(routeTargets(route)));
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return {
|
|
451
|
-
...(version ? { version, ...boundary } : {}), ...(description ? { description } : {}), start: order[0]!, steps, routes, ...(landTimeoutMs || then ? { land: { ...(landTimeoutMs ? { timeoutMs: landTimeoutMs } : {}), ...(then ? { then } : {}) } } : {}),
|
|
452
|
-
...(raw[CI_MAIN_STEP] !== undefined ? { ciMain: parseCiMain(raw[CI_MAIN_STEP]) } : {}),
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/** `ci-main: {}` (or `ci-main: { workflow: CI, timeout: 1h }`) adds the CI check after the land. */
|
|
457
|
-
function parseCiMain(value: unknown): NonNullable<WorkflowDefinition["ciMain"]> {
|
|
458
|
-
const ciMain = value ?? {};
|
|
459
|
-
if (!isMapping(ciMain)) fail(`${CI_MAIN_STEP} must be a mapping: { workflow: CI, timeout: 1h } (both optional)`);
|
|
460
|
-
onlyFields(ciMain, CI_MAIN_FIELDS, CI_MAIN_STEP);
|
|
461
|
-
const workflow = ciMain.workflow === undefined ? undefined : text(ciMain.workflow, `${CI_MAIN_STEP}.workflow`);
|
|
462
|
-
const timeoutMs = ciMain.timeout === undefined ? undefined : duration(ciMain.timeout, `${CI_MAIN_STEP}.timeout`);
|
|
463
|
-
return { ...(workflow ? { workflow } : {}), ...(timeoutMs ? { timeoutMs } : {}) };
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/** What a delivery means for a step: a gated step's `complete` is its gate verdict. */
|
|
467
|
-
export function stepOutcome(step: WorkflowStep, delivery: { disposition: string; gateStatus?: string }): string {
|
|
468
|
-
if (step.gate && delivery.disposition === "complete" && (delivery.gateStatus === "pass" || delivery.gateStatus === "fail")) return delivery.gateStatus;
|
|
469
|
-
return delivery.disposition;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
export interface RouteDecision {
|
|
473
|
-
target: string;
|
|
474
|
-
/** Times each bounded route was taken, keyed `<step>.<outcome>`. */
|
|
475
|
-
counters: Record<string, number>;
|
|
476
|
-
reason?: string;
|
|
477
|
-
outcome?: string;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/** Route one outcome. A bounded route's `max`-th use goes to `else`; an unrouted outcome escalates. */
|
|
481
|
-
export function routeOutcome(definition: WorkflowDefinition, from: string, outcome: string, counters: Record<string, number>, context: Record<string, unknown> = {}): RouteDecision {
|
|
482
|
-
const script = outcome === "skipped" ? undefined : definition.steps[from]?.script;
|
|
483
|
-
if (script) {
|
|
484
|
-
const action = outcome === "timeout" ? "escalate" : script.on[outcome] ?? script.on.default ?? "escalate";
|
|
485
|
-
const target = action === "next" ? Object.keys(definition.steps)[Object.keys(definition.steps).indexOf(from) + 1] ?? "done"
|
|
486
|
-
: action.startsWith("goto ") ? action.slice(5) : action;
|
|
487
|
-
if (definition.version !== 2 || action.startsWith("goto ") || action === "wait" || action === "escalate") return { target, counters, outcome: action === "fail" ? "failed" : "complete", reason: `script step ${from} returned ${outcome}` };
|
|
488
|
-
const normalized = action === "next" ? "complete" : "failed";
|
|
489
|
-
return { ...routeOutcome({ ...definition, steps: { ...definition.steps, [from]: { ...definition.steps[from]!, script: undefined } } }, from, normalized, counters, context), outcome: normalized };
|
|
490
|
-
}
|
|
491
|
-
const declared = definition.routes[from]?.[outcome];
|
|
492
|
-
const route = Array.isArray(declared) ? declared.find(branch => branch.condition === undefined || workflowCondition(branch.condition, context))?.target : declared;
|
|
493
|
-
if (route === undefined && definition.version === 2) return { target: outcome === "complete" || outcome === "pass" || outcome === "skipped" ? Object.keys(definition.steps)[Object.keys(definition.steps).indexOf(from) + 1] ?? "done" : outcome === "failed" || outcome === "cancelled" || outcome === "fail" ? "fail" : "escalate", counters };
|
|
494
|
-
if (route === undefined) return { target: "escalate", counters, reason: `step ${from} returned ${outcome}, which has no route` };
|
|
495
|
-
if (typeof route === "string") return { target: route, counters };
|
|
496
|
-
const key = `${from}.${outcome}`;
|
|
497
|
-
const taken = (counters[key] ?? 0) + 1;
|
|
498
|
-
const next = { ...counters, [key]: taken };
|
|
499
|
-
if (taken < route.max) return { target: route.to, counters: next };
|
|
500
|
-
return { target: route.else, counters: next, reason: `step ${from} returned ${outcome} ${taken} time(s); the bound is ${route.max}` };
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/** A route to the same or an earlier step starts a new round. */
|
|
504
|
-
export function isLoopBack(definition: WorkflowDefinition, from: string, to: string): boolean {
|
|
505
|
-
const order = Object.keys(definition.steps);
|
|
506
|
-
return order.includes(to) && order.indexOf(to) <= order.indexOf(from);
|
|
507
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { OpError, type ModuleCtx } from "./contract";
|
|
3
|
-
import { stepReap, workflowAppliedPinSchema } from "./workflow-definition";
|
|
4
|
-
import { ADMIN_GRANT, agentSchema, crossProviderSchema, stores, requireRun, type WorkflowEffect } from "./workflow-state";
|
|
5
|
-
import { releaseReservation } from "./workflow-composition";
|
|
6
|
-
|
|
7
|
-
export async function recordDispatchAgent(ctx: ModuleCtx, effect: WorkflowEffect, result: Record<string, unknown>): Promise<void> {
|
|
8
|
-
if (effect.kind !== "dispatch" || typeof result.taskId !== "number" || typeof result.spawnRequestId !== "string") return;
|
|
9
|
-
const run = await requireRun(ctx, effect.runId);
|
|
10
|
-
const step = String(effect.payload.step);
|
|
11
|
-
const pin = workflowAppliedPinSchema.safeParse(effect.payload.pin);
|
|
12
|
-
const crossProvider = crossProviderSchema.safeParse(result.crossProvider);
|
|
13
|
-
const routingSources = agentSchema.shape.routingSources.safeParse(result.routingSources);
|
|
14
|
-
const warnings = agentSchema.shape.warnings.safeParse(result.warnings);
|
|
15
|
-
const agent = await stores(ctx).agent.get(result.spawnRequestId);
|
|
16
|
-
const facts = {
|
|
17
|
-
...(typeof result.agentId === "string" && !agent?.agentId ? { agentId: result.agentId } : {}),
|
|
18
|
-
...(typeof result.provider === "string" ? { provider: result.provider } : {}),
|
|
19
|
-
...(routingSources.success && routingSources.data ? { routingSources: routingSources.data } : {}),
|
|
20
|
-
...(warnings.success && warnings.data ? { warnings: warnings.data } : {}),
|
|
21
|
-
...(crossProvider.success ? { crossProvider: crossProvider.data } : {}), ...(pin.success ? { pin: pin.data } : {}),
|
|
22
|
-
};
|
|
23
|
-
if (agent) await stores(ctx).agent.update(agent.id, facts);
|
|
24
|
-
else await stores(ctx).agent.create({ id: result.spawnRequestId, spawnRequestId: result.spawnRequestId, reservationId: effect.id,
|
|
25
|
-
runId: run.id, step, round: typeof effect.payload.round === "number" ? effect.payload.round : run.round, taskId: result.taskId,
|
|
26
|
-
reap: stepReap(run.definition.steps[step]), ...facts, createdAt: ctx.clock.now() });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const workflowDispatchOps = {
|
|
30
|
-
refuseDispatch: {
|
|
31
|
-
kind: "mutation", idempotent: true, grant: ADMIN_GRANT, summary: "Discard a provisional invocation proven never admitted by the effect driver.", expose: { http: false, mcp: false, cli: false },
|
|
32
|
-
input: z.object({ id: z.string() }), output: z.object({ refused: z.boolean() }),
|
|
33
|
-
handler: async (ctx: ModuleCtx, input: { id: string }) => {
|
|
34
|
-
const effect = await stores(ctx).effect.get(input.id);
|
|
35
|
-
if (!effect || effect.kind !== "dispatch" || typeof effect.payload.spawnRequestId !== "string") return { refused: false };
|
|
36
|
-
const run = await requireRun(ctx, effect.runId);
|
|
37
|
-
if (effect.status !== "failed" && !run.cancel) throw new OpError("conflict", 409, "dispatch can still be admitted");
|
|
38
|
-
const agent = await stores(ctx).agent.get(effect.payload.spawnRequestId);
|
|
39
|
-
if (agent?.agentId || agent?.readyAt) throw new OpError("conflict", 409, "invocation already registered");
|
|
40
|
-
if (agent) await stores(ctx).agent.delete(agent.id);
|
|
41
|
-
await releaseReservation(ctx, effect.id);
|
|
42
|
-
await stores(ctx).effect.update(effect.id, { payload: { ...effect.payload, refused: true } });
|
|
43
|
-
return { refused: true };
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
prepareDispatch: {
|
|
47
|
-
kind: "mutation", idempotent: true, grant: ADMIN_GRANT, summary: "Own a stable invocation before its external spawn is admitted.", expose: { http: false, mcp: false, cli: false },
|
|
48
|
-
input: z.object({ id: z.string(), taskId: z.number().int(), spawnRequestId: z.string() }), output: agentSchema,
|
|
49
|
-
handler: async (ctx: ModuleCtx, input: { id: string; taskId: number; spawnRequestId: string }) => {
|
|
50
|
-
const effect = await stores(ctx).effect.get(input.id);
|
|
51
|
-
if (!effect || effect.kind !== "dispatch") throw new OpError("not_found", 404, "dispatch intent not found");
|
|
52
|
-
const run = await requireRun(ctx, effect.runId);
|
|
53
|
-
if (run.cancel || run.status !== "running") throw new OpError("conflict", 409, "ROOT_STOPPED: dispatch is stale");
|
|
54
|
-
if (effect.payload.spawnRequestId && effect.payload.spawnRequestId !== input.spawnRequestId) throw new OpError("conflict", 409, "dispatch identity changed");
|
|
55
|
-
await recordDispatchAgent(ctx, effect, input);
|
|
56
|
-
await stores(ctx).effect.update(effect.id, { payload: { ...effect.payload, spawnTaskId: input.taskId, spawnRequestId: input.spawnRequestId } });
|
|
57
|
-
return (await stores(ctx).agent.get(input.spawnRequestId))!;
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
} as const;
|