@humwick/server 0.130.2 → 0.130.4
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/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-coordination.md +1 -0
- package/docs/guides/workflows.md +16 -0
- package/docs/openapi.json +175 -4
- package/package.json +8 -7
- package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-BOkmEvgZ.js} +2 -2
- package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-BkaDJp0r.js} +2 -2
- package/public/assets/{TraceView-Wimm0Czv.js → TraceView-B99Uu2yT.js} +2 -2
- package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DUIfTTFF.js} +2 -2
- package/public/assets/{activity-CrSurn-r.js → activity-ZIX0N1El.js} +2 -2
- package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-kq9TPYFw.js} +2 -2
- package/public/assets/agent-liveness-DSQY1Aa_.js +2 -0
- package/public/assets/{agent-name-DKbiIhBo.js → agent-name-C_7F4DFR.js} +2 -2
- package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-BNOcrGcY.js} +2 -2
- package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-B6yAh70a.js} +2 -2
- package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-CcrhmOzF.js} +2 -2
- package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CXSLrKiq.js} +2 -2
- package/public/assets/{agents-B-v66C-4.js → agents-DIZG97_X.js} +2 -2
- package/public/assets/{analytics-BqCb-LKi.js → analytics-rasmoPjR.js} +2 -2
- package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-tBpTrEPb.js} +2 -2
- package/public/assets/{artifacts-DJevXcvg.js → artifacts-BNkrynP1.js} +2 -2
- package/public/assets/{artifacts-D32zyw4Y.js → artifacts-Bjq-ZyBA.js} +2 -2
- package/public/assets/{automation-BpRajx_5.js → automation-Cx422L3L.js} +2 -2
- package/public/assets/{backlog-D_UjTdzX.js → backlog-RuFQ8PUu.js} +2 -2
- package/public/assets/{busy-health-N3VEh4ao.js → busy-health-BvNQ9g5x.js} +2 -2
- package/public/assets/{channels-9jopungq.js → channels-DNbKAS0I.js} +2 -2
- package/public/assets/{chat-CSXrTB3C.js → chat-Bp3Fx73h.js} +3 -3
- package/public/assets/{code-preview-p1NnmqK0.js → code-preview-KIRZA6cz.js} +2 -2
- package/public/assets/{connectors-CZdqlDNL.js → connectors-k7vO4vvc.js} +2 -2
- package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BuVoq1aw.js} +2 -2
- package/public/assets/{crate-agent-30aXTKva.js → crate-agent-irqlt4NH.js} +2 -2
- package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-D_rurNBz.js} +2 -2
- package/public/assets/{deploys-DoN6bAb5.js → deploys-yzZqIpxE.js} +2 -2
- package/public/assets/{display-BrKWFGJz.js → display-BemJG1f_.js} +2 -2
- package/public/assets/{files-D6XEu8Ng.js → files-DXWcrxOz.js} +2 -2
- package/public/assets/{fleet-C7jQWbw2.js → fleet-TEuOCZXE.js} +2 -2
- package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BGoDAFI-.js} +2 -2
- package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-BB9eq9nN.js} +2 -2
- package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-qy2nTD_1.js} +3 -3
- package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-BGPHxuwT.js} +2 -2
- package/public/assets/{index-CRHep3M9.js → index-BC5XZc0z.js} +5 -5
- package/public/assets/{index-MYAIwYTX.css → index-D8Rp9pz2.css} +1 -1
- package/public/assets/{insights-CzrtkpOE.js → insights-C-KQG0h-.js} +2 -2
- package/public/assets/{integrations-aVsUmigt.js → integrations-ClPRPyKU.js} +2 -2
- package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-DbH8J9Ak.js} +2 -2
- package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-PH4zVn24.js} +2 -2
- package/public/assets/{maintenance-NfjqFZAk.js → maintenance-5lV43uTL.js} +2 -2
- package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-BdgU35aX.js} +2 -2
- package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-DNT4OUwQ.js} +3 -3
- package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CnCcPy0A.js} +2 -2
- package/public/assets/{memory-DNsCl6UX.js → memory--GgWH1gH.js} +2 -2
- package/public/assets/{messages-DopU1L1X.js → messages-CzFl_97O.js} +2 -2
- package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-CVvJVkzv.js} +2 -2
- package/public/assets/overview-DsrZvE86.js +2 -0
- package/public/assets/{pairs-DE_m6rrE.js → pairs-D2d0d2py.js} +2 -2
- package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-_SMuSbYF.js} +2 -2
- package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-Apn15y43.js} +2 -2
- package/public/assets/{projects-Br2Bd2h1.js → projects-D3B6kto5.js} +2 -2
- package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-DnPB6Ez6.js} +2 -2
- package/public/assets/provider-display-bWwiuedV.js +2 -0
- package/public/assets/{registry-Cw38_6gW.js → registry-D790cIhN.js} +2 -2
- package/public/assets/run-card-BCro-Odj.js +2 -0
- package/public/assets/{secrets-DxI-vzSq.js → secrets-CVXvfvbU.js} +2 -2
- package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-D3Xxqb9w.js} +2 -2
- package/public/assets/{settings-CKZTVGIx.js → settings-CoUC7Jci.js} +2 -2
- package/public/assets/shipping-D_Lp9n_J.js +2 -0
- package/public/assets/{stats-DyUBKyWI.js → stats-CXiNjB9S.js} +2 -2
- package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-C703YIy1.js} +2 -2
- package/public/assets/store-BgDALGIX.js +9 -0
- package/public/assets/{tasks-Bh7Chr4-.js → tasks-DO0WpJCx.js} +2 -2
- package/public/assets/{teams-bowI7qVY.js → teams-FGkdi_tL.js} +2 -2
- package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-Dh8dSC7e.js} +3 -3
- package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-B5Zriip3.js} +2 -2
- package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-CRUVDvLC.js} +2 -2
- package/public/assets/{use-decisions-samMQhQf.js → use-decisions-CoaqRh4l.js} +2 -2
- package/public/assets/{use-project-list-59LheVP7.js → use-project-list-X-BgT53X.js} +2 -2
- package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-0X_UZkk-.js} +2 -2
- package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-CkLhVBGu.js} +2 -2
- package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-BkTi7eim.js} +2 -2
- package/public/assets/{work-queue-CSvpuNLz.js → work-queue-DDOLEyKo.js} +2 -2
- package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-CzOsB8BM.js} +2 -2
- package/public/assets/{workflows-DdmxRSyg.js → workflows-DJilvmRM.js} +2 -2
- package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CHcfbLR3.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +29 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-api.ts +1 -1
- 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/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- 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 +3 -2
- package/runner/src/runner-core.ts +14 -15
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -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/login-link.ts +35 -0
- 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 +3 -3
- package/src/branch-landed.ts +25 -23
- package/src/bus.ts +21 -19
- package/src/cd-deploy-notify.ts +2 -2
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +3 -3
- package/src/ci/transition-notify.ts +5 -5
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/index.ts +7 -1
- package/src/cli/init.ts +53 -0
- package/src/cli/orchestrator.ts +1 -7
- package/src/cli/setup.ts +6 -4
- package/src/cli/workflow.ts +12 -3
- package/src/commands-db.ts +4 -4
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +2 -2
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- 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/agents-async.ts +8 -5
- package/src/db/agents.ts +15 -12
- 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/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/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuations.ts +4 -4
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -3
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-refs-async.ts +4 -1
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs.ts +8 -8
- 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/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +20 -2
- package/src/db/maintenance-job-runs-async.ts +2 -2
- package/src/db/maintenance-job-write-ops.ts +1 -1
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +18 -1
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +10 -4
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +41 -48
- 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-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/read-op-marshaling-fixtures.ts +18 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- 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 +4 -1
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation.ts +3 -12
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +5 -3
- package/src/db/task-entity.ts +5 -4
- 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/token-db-write-ops.ts +2 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +6 -9
- 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-execution.ts +3 -3
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +31 -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 +42 -46
- package/src/dev.ts +12 -16
- 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-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/init.ts +299 -0
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/invite-link.ts +16 -9
- 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 +104 -98
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +3 -3
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/jobs.ts +29 -67
- 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 +18 -13
- package/src/maintenance/stalled-delivery-pager.ts +4 -4
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +17 -27
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +3 -3
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +8 -8
- package/src/mcp/output-descriptions.ts +1 -1
- package/src/mcp/presentation.ts +2 -1
- 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 +3 -2
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-workspace.ts +1 -1
- 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 +3 -3
- 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 +1 -1
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +5 -3
- 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/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +2 -5
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +8 -1
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +4 -3
- 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-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 +1 -1
- package/src/routes/agents.ts +17 -119
- package/src/routes/auth.ts +44 -17
- 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 +1 -1
- package/src/routes/commands.ts +29 -27
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-providers.ts +18 -0
- 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 +7 -3
- package/src/routes/integrations.ts +9 -7
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +3 -3
- 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 +3 -1
- package/src/routes/orchestrator-host-registration.ts +2 -0
- package/src/routes/orchestrator-host-utilization.ts +2 -2
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +27 -18
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +1 -1
- package/src/routes/project-trust.ts +1 -1
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +4 -5
- package/src/routes/secrets-import.ts +3 -4
- package/src/routes/secrets-vault.ts +12 -14
- package/src/routes/settings.ts +1 -1
- 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/team-templates.ts +7 -7
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +18 -17
- 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 +2 -2
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-push.ts +6 -6
- package/src/runtime-grant.ts +17 -11
- package/src/runtime-install.ts +30 -0
- package/src/runtime-tokens.ts +20 -28
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +3 -1
- 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 +1 -1
- package/src/server.ts +25 -26
- 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/auth-context.ts +6 -0
- 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 +9 -9
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +4 -4
- 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 +14 -13
- package/src/services/issue-refs.ts +4 -5
- package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +3 -3
- 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 +6 -5
- 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 +3 -3
- 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 +1 -1
- 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 +8 -3
- package/src/services/profile-trust.ts +2 -2
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-api-key.ts +73 -0
- 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/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 +17 -16
- 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-effort-grant.ts +5 -25
- package/src/services/send-message.ts +16 -33
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +12 -41
- package/src/services/spawn-chain-inspector.ts +1 -1
- 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-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +7 -8
- 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-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 +3 -4
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +5 -5
- 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 +22 -19
- 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 +2 -1
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.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 +1 -1
- package/src/services/workflow-effect-driver.ts +42 -19
- package/src/services/workflow-effects.ts +41 -27
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +1 -0
- 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 +4 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +34 -22
- package/src/services/workflow-supervisor-state.ts +21 -1
- package/src/services/workflow-supervisor.ts +4 -3
- package/src/services/workspace-recovery.ts +4 -3
- package/src/setup.ts +47 -8
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-placement.ts +27 -9
- package/src/spawn-targets.ts +8 -8
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +61 -57
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +2 -2
- package/src/task-dispatch-live.ts +5 -2
- package/src/task-dispatcher.ts +2 -2
- 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/utils.ts +7 -0
- 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 +24 -16
- 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 +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
- package/public/assets/overview-C1DCTzzV.js +0 -2
- package/public/assets/provider-display-DsuWMvVL.js +0 -2
- package/public/assets/run-card-CpKqRbhg.js +0 -2
- package/public/assets/shipping-B9YtnwtG.js +0 -2
- package/public/assets/store-DcClXLH0.js +0 -9
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/src/db/on-loop-write-transaction.ts +0 -34
|
@@ -1,29 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { updateRunAsync } from "./write-async";
|
|
2
|
+
import { sendMessageAsync } from "../db/message-send";
|
|
3
|
+
import { createCommandAsync } from "../commands-write";
|
|
4
|
+
|
|
5
|
+
import { getAgent, getTaskAsync, listAgents, listOrchestrators, updateTaskStatusAsync } from "../db";
|
|
3
6
|
import { renderTemplate } from "../prompt-resolver";
|
|
4
7
|
import { CLOSED_TASK_STATUS } from "./constants";
|
|
5
8
|
import { settleAutomationPrechecks } from "./precheck";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
getAutomation,
|
|
9
|
-
getAutomationRun,
|
|
10
|
-
rowToAutomationRun,
|
|
11
|
-
updateRun,
|
|
12
|
-
db,
|
|
13
|
-
} from "./storage";
|
|
9
|
+
import { listReconcilableRunsAsync } from "./read-async";
|
|
10
|
+
import { ensureAutomationTables, getAutomation, getAutomationRun } from "./storage";
|
|
14
11
|
import type { AutomationReconcileResult } from "./types";
|
|
15
12
|
import type { AgentCard, AutomationRun, AutomationRunStatus, AutomationRuntimeBudget, Command, Message, Task } from "../types";
|
|
16
13
|
|
|
17
14
|
export async function reconcileAutomationRuns(now = Date.now()): Promise<AutomationReconcileResult[]> {
|
|
18
15
|
ensureAutomationTables();
|
|
19
16
|
const results: AutomationReconcileResult[] = await settleAutomationPrechecks(now);
|
|
20
|
-
const
|
|
21
|
-
SELECT * FROM automation_runs
|
|
22
|
-
WHERE status IN ('scheduled', 'dispatching', 'waiting_agent', 'running') AND task_id IS NOT NULL
|
|
23
|
-
ORDER BY created_at ASC
|
|
24
|
-
`).all() as any[];
|
|
25
|
-
for (const row of rows) {
|
|
26
|
-
const run = rowToAutomationRun(row);
|
|
17
|
+
for (const run of await listReconcilableRunsAsync()) {
|
|
27
18
|
const task = run.taskId ? await getTaskAsync(run.taskId) : null;
|
|
28
19
|
if (!task) continue;
|
|
29
20
|
|
|
@@ -31,12 +22,12 @@ export async function reconcileAutomationRuns(now = Date.now()): Promise<Automat
|
|
|
31
22
|
const hasRuntimeMetaChange = hasMetaChanges(run.meta, runtimeMeta);
|
|
32
23
|
const nextOpenStatus: AutomationRunStatus = task.status === "open" ? "waiting_agent" : "running";
|
|
33
24
|
if ((task.claimedBy && task.claimedBy !== run.targetAgentId) || run.status !== nextOpenStatus || hasRuntimeMetaChange) {
|
|
34
|
-
|
|
25
|
+
(await updateRunAsync(run.id, {
|
|
35
26
|
status: nextOpenStatus,
|
|
36
27
|
targetAgentId: task.claimedBy ?? run.targetAgentId,
|
|
37
28
|
spawnedAgentId: run.spawnedAgentId ?? task.claimedBy,
|
|
38
29
|
meta: hasRuntimeMetaChange ? { ...run.meta, ...runtimeMeta } : undefined,
|
|
39
|
-
}, now);
|
|
30
|
+
}, now));
|
|
40
31
|
}
|
|
41
32
|
|
|
42
33
|
if (!CLOSED_TASK_STATUS.has(task.status)) {
|
|
@@ -52,22 +43,22 @@ export async function reconcileAutomationRuns(now = Date.now()): Promise<Automat
|
|
|
52
43
|
results.push(timedOut);
|
|
53
44
|
continue;
|
|
54
45
|
}
|
|
55
|
-
const warning = maybeWarnRuntimeBudget(updated, task, now);
|
|
46
|
+
const warning = (await maybeWarnRuntimeBudget(updated, task, now));
|
|
56
47
|
results.push({ run: getAutomationRun(run.id) ?? updated, task, message: warning });
|
|
57
48
|
continue;
|
|
58
49
|
}
|
|
59
50
|
|
|
60
51
|
const status: AutomationRunStatus = task.status === "done" ? "succeeded" : task.status === "canceled" ? "canceled" : "failed";
|
|
61
|
-
|
|
52
|
+
(await updateRunAsync(run.id, {
|
|
62
53
|
status,
|
|
63
54
|
finishedAt: now,
|
|
64
55
|
result: { taskStatus: task.status, result: task.result ?? null },
|
|
65
56
|
targetAgentId: task.claimedBy ?? run.targetAgentId,
|
|
66
57
|
spawnedAgentId: run.spawnedAgentId ?? task.claimedBy,
|
|
67
58
|
meta: hasMetaChanges(run.meta, runtimeMeta) ? { ...run.meta, ...runtimeMeta } : undefined,
|
|
68
|
-
}, now);
|
|
59
|
+
}, now));
|
|
69
60
|
const updated = getAutomationRun(run.id)!;
|
|
70
|
-
const command = maybeShutdownOnDemandAgent(updated, task, now);
|
|
61
|
+
const command = (await maybeShutdownOnDemandAgent(updated, task, now));
|
|
71
62
|
results.push({ run: getAutomationRun(run.id)!, task, command });
|
|
72
63
|
}
|
|
73
64
|
return results;
|
|
@@ -140,7 +131,7 @@ function runtimeWarningAt(run: AutomationRun, budget: AutomationRuntimeBudget):
|
|
|
140
131
|
return run.startedAt + budget.warnAtMs;
|
|
141
132
|
}
|
|
142
133
|
|
|
143
|
-
function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Message | undefined {
|
|
134
|
+
async function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Promise<Message | undefined> {
|
|
144
135
|
if (run.meta.runtimeBudgetWarnedAt) return undefined;
|
|
145
136
|
const budget = runtimeBudgetForRun(run);
|
|
146
137
|
if (!budget) return undefined;
|
|
@@ -150,7 +141,7 @@ function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Me
|
|
|
150
141
|
const target = runtimeBudgetMessageTarget(run, task);
|
|
151
142
|
if (!target) return undefined;
|
|
152
143
|
const remainingMinutes = Math.max(1, Math.ceil((deadline - now) / 60_000));
|
|
153
|
-
const message =
|
|
144
|
+
const message = (await sendMessageAsync({
|
|
154
145
|
from: "system",
|
|
155
146
|
to: target,
|
|
156
147
|
kind: "control",
|
|
@@ -173,15 +164,15 @@ function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Me
|
|
|
173
164
|
automationRunId: run.id,
|
|
174
165
|
runtimeBudgetWarning: true,
|
|
175
166
|
},
|
|
176
|
-
});
|
|
177
|
-
|
|
167
|
+
}));
|
|
168
|
+
(await updateRunAsync(run.id, {
|
|
178
169
|
meta: {
|
|
179
170
|
...run.meta,
|
|
180
171
|
runtimeBudgetWarnedAt: now,
|
|
181
172
|
runtimeBudgetWarningMessageId: message.id,
|
|
182
173
|
runtimeBudgetDeadlineAt: deadline,
|
|
183
174
|
},
|
|
184
|
-
}, now);
|
|
175
|
+
}, now));
|
|
185
176
|
return message;
|
|
186
177
|
}
|
|
187
178
|
|
|
@@ -205,7 +196,7 @@ async function maybeFailNeverReadyOfflineTarget(run: AutomationRun, task: Task,
|
|
|
205
196
|
},
|
|
206
197
|
}, { privileged: true });
|
|
207
198
|
const updatedTask = taskResult.task ?? (await getTaskAsync(task.id)) ?? task;
|
|
208
|
-
|
|
199
|
+
(await updateRunAsync(run.id, {
|
|
209
200
|
status: "failed",
|
|
210
201
|
finishedAt: now,
|
|
211
202
|
error: reason,
|
|
@@ -225,7 +216,7 @@ async function maybeFailNeverReadyOfflineTarget(run: AutomationRun, task: Task,
|
|
|
225
216
|
runtimeTargetOfflineAt: now,
|
|
226
217
|
runtimeTargetNeverReady: true,
|
|
227
218
|
},
|
|
228
|
-
}, now);
|
|
219
|
+
}, now));
|
|
229
220
|
return { run: getAutomationRun(run.id)!, task: (await getTaskAsync(task.id)) ?? updatedTask };
|
|
230
221
|
}
|
|
231
222
|
|
|
@@ -251,8 +242,8 @@ async function maybeTimeoutRuntimeBudget(run: AutomationRun, task: Task, now: nu
|
|
|
251
242
|
},
|
|
252
243
|
}, { privileged: true });
|
|
253
244
|
const updatedTask = taskResult.task ?? (await getTaskAsync(task.id)) ?? task;
|
|
254
|
-
const command = requestOnDemandAgentShutdown(run, updatedTask, now, "runtime-budget-timeout");
|
|
255
|
-
|
|
245
|
+
const command = (await requestOnDemandAgentShutdown(run, updatedTask, now, "runtime-budget-timeout"));
|
|
246
|
+
(await updateRunAsync(run.id, {
|
|
256
247
|
status: "timed_out",
|
|
257
248
|
finishedAt: now,
|
|
258
249
|
error: "Automation runtime budget elapsed",
|
|
@@ -273,7 +264,7 @@ async function maybeTimeoutRuntimeBudget(run: AutomationRun, task: Task, now: nu
|
|
|
273
264
|
runtimeBudgetDeadlineAt: deadline,
|
|
274
265
|
...(command ? { shutdownCommandId: command.id } : {}),
|
|
275
266
|
},
|
|
276
|
-
}, now);
|
|
267
|
+
}, now));
|
|
277
268
|
return { run: getAutomationRun(run.id)!, task: (await getTaskAsync(task.id)) ?? updatedTask, command };
|
|
278
269
|
}
|
|
279
270
|
|
|
@@ -285,19 +276,19 @@ function runtimeBudgetMessageTarget(run: AutomationRun, task: Task): string | un
|
|
|
285
276
|
return undefined;
|
|
286
277
|
}
|
|
287
278
|
|
|
288
|
-
function maybeShutdownOnDemandAgent(run: AutomationRun, task: Task, now: number): Command | undefined {
|
|
279
|
+
async function maybeShutdownOnDemandAgent(run: AutomationRun, task: Task, now: number): Promise<Command | undefined> {
|
|
289
280
|
if (run.shutdownRequestedAt) return undefined;
|
|
290
281
|
const automation = getAutomation(run.automationId);
|
|
291
282
|
if (!automation || automation.targetPolicy.mode !== "on_demand_agent" || automation.targetPolicy.keepAlive) return undefined;
|
|
292
|
-
const command = requestOnDemandAgentShutdown(run, task, now, "task-complete");
|
|
293
|
-
if (command)
|
|
283
|
+
const command = (await requestOnDemandAgentShutdown(run, task, now, "task-complete"));
|
|
284
|
+
if (command) (await updateRunAsync(run.id, { shutdownRequestedAt: now, meta: { ...run.meta, shutdownCommandId: command.id } }, now));
|
|
294
285
|
return command;
|
|
295
286
|
}
|
|
296
287
|
|
|
297
|
-
function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: number, reason: string): Command | undefined {
|
|
288
|
+
async function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: number, reason: string): Promise<Command | undefined> {
|
|
298
289
|
const agentId = task.claimedBy ?? run.targetAgentId ?? run.spawnedAgentId;
|
|
299
290
|
if (!agentId) return undefined;
|
|
300
|
-
return
|
|
291
|
+
return (await createCommandAsync({
|
|
301
292
|
type: "agent.shutdown",
|
|
302
293
|
source: "automation",
|
|
303
294
|
target: agentId,
|
|
@@ -310,5 +301,5 @@ function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: numbe
|
|
|
310
301
|
automationRunId: run.id,
|
|
311
302
|
reason,
|
|
312
303
|
},
|
|
313
|
-
});
|
|
304
|
+
}));
|
|
314
305
|
}
|
|
@@ -70,8 +70,8 @@ export function listAutomations(): Automation[] {
|
|
|
70
70
|
.map(rowToAutomation);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
/** Listing SQL, exported so the query-plan gate pins the production statement (#3799). */
|
|
74
|
+
export function buildListAutomationRunsQuery(filter: { automationId?: string; status?: string; limit?: number } = {}): { sql: string; params: (string | number)[] } {
|
|
75
75
|
const clauses: string[] = [];
|
|
76
76
|
const params: (string | number)[] = [];
|
|
77
77
|
if (filter.automationId) {
|
|
@@ -84,8 +84,13 @@ export function listAutomationRuns(filter: { automationId?: string; status?: str
|
|
|
84
84
|
}
|
|
85
85
|
const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
86
86
|
params.push(filter.limit ?? 100);
|
|
87
|
-
return
|
|
88
|
-
|
|
87
|
+
return { sql: `SELECT * FROM automation_runs ${where} ORDER BY created_at DESC LIMIT ?`, params };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function listAutomationRuns(filter: { automationId?: string; status?: string; limit?: number } = {}): AutomationRun[] {
|
|
91
|
+
ensureAutomationTables();
|
|
92
|
+
const { sql, params } = buildListAutomationRunsQuery(filter);
|
|
93
|
+
return (db().query(sql).all(...params) as any[]).map(rowToAutomationRun);
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
export function getAutomationRun(id: string): AutomationRun | null {
|
|
@@ -176,25 +181,43 @@ export function cancelActiveRuns(automationId: string, now: number, reason: stri
|
|
|
176
181
|
.run(now, reason, now, automationId, ...OPEN_RUN_STATUSES);
|
|
177
182
|
}
|
|
178
183
|
|
|
184
|
+
/** Enabled automations whose next fire time has passed; indexed on (enabled, next_run_at). */
|
|
185
|
+
export const DUE_AUTOMATIONS_SQL = "SELECT * FROM automations WHERE enabled = 1 AND next_run_at IS NOT NULL AND next_run_at <= ? ORDER BY next_run_at ASC LIMIT 25";
|
|
186
|
+
export function listDueAutomations(now: number): Automation[] {
|
|
187
|
+
return (db().query(DUE_AUTOMATIONS_SQL).all(now) as any[]).map(rowToAutomation);
|
|
188
|
+
}
|
|
189
|
+
|
|
179
190
|
export function rescheduleAutomation(automation: Automation, nextRunAt: number | undefined, now: number): void {
|
|
180
191
|
db().query("UPDATE automations SET next_run_at = ?, updated_at = ? WHERE id = ?").run(nextRunAt ?? null, now, automation.id);
|
|
181
192
|
}
|
|
182
193
|
|
|
183
194
|
/** #3175 — runs whose precheck command has been dispatched but not yet settled. */
|
|
184
|
-
export
|
|
185
|
-
return (db().query(`
|
|
195
|
+
export const PENDING_PRECHECK_RUNS_SQL = `
|
|
186
196
|
SELECT * FROM automation_runs
|
|
187
197
|
WHERE status = 'running' AND task_id IS NULL AND json_extract(meta, '$.precheck.status') = 'running'
|
|
188
198
|
ORDER BY created_at ASC LIMIT 100
|
|
189
|
-
|
|
199
|
+
`;
|
|
200
|
+
export function listPendingPrecheckRuns(): AutomationRun[] {
|
|
201
|
+
return (db().query(PENDING_PRECHECK_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Open runs bound to a task: the reconcile pass walks these against the task's live state. */
|
|
205
|
+
export const RECONCILABLE_RUNS_SQL = `
|
|
206
|
+
SELECT * FROM automation_runs
|
|
207
|
+
WHERE status IN ('scheduled', 'dispatching', 'waiting_agent', 'running') AND task_id IS NOT NULL
|
|
208
|
+
ORDER BY created_at ASC
|
|
209
|
+
`;
|
|
210
|
+
export function listReconcilableRuns(): AutomationRun[] {
|
|
211
|
+
return (db().query(RECONCILABLE_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
|
|
190
212
|
}
|
|
191
213
|
|
|
192
214
|
/** Queued runs ready to dispatch. A run whose precheck already reported hits was accepted while the
|
|
193
215
|
* automation was runnable (Run now works on disabled automations), so it continues regardless. */
|
|
194
|
-
export
|
|
195
|
-
return (db().query(`
|
|
216
|
+
export const DISPATCHABLE_QUEUED_RUNS_SQL = `
|
|
196
217
|
SELECT r.* FROM automation_runs r JOIN automations a ON a.id = r.automation_id
|
|
197
218
|
WHERE r.status = 'scheduled' AND (a.enabled = 1 OR json_extract(r.meta, '$.precheck.status') = 'hits')
|
|
198
219
|
ORDER BY r.scheduled_for ASC LIMIT 25
|
|
199
|
-
|
|
220
|
+
`;
|
|
221
|
+
export function listDispatchableQueuedRuns(): AutomationRun[] {
|
|
222
|
+
return (db().query(DISPATCHABLE_QUEUED_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
|
|
200
223
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { getGateway } from "../db/gateway";
|
|
3
|
+
import type { insertAutomation, updateAutomationNormalized } from "./persistence";
|
|
4
|
+
import type { Automation, AutomationRun } from "../types";
|
|
5
|
+
import type { insertRun, enqueueAutomationRun, updateRun, cancelActiveRuns, rescheduleAutomation } from "./storage";
|
|
6
|
+
|
|
7
|
+
export function insertAutomationAsync(normalized: Parameters<typeof insertAutomation>[0], now: number): Promise<Automation> {
|
|
8
|
+
return getGateway().write("automations.create", { normalized, now }, { idempotencyKey: randomUUID() }) as unknown as Promise<Automation>;
|
|
9
|
+
}
|
|
10
|
+
export function updateAutomationNormalizedAsync(id: string, normalized: Parameters<typeof updateAutomationNormalized>[1], expected: Automation, now: number): Promise<Automation> {
|
|
11
|
+
return getGateway().write("automations.update", { id, normalized, expected, now }, { idempotencyKey: randomUUID() }) as unknown as Promise<Automation>;
|
|
12
|
+
}
|
|
13
|
+
export function deleteAutomationAsync(id: string): Promise<boolean> {
|
|
14
|
+
return getGateway().write("automations.delete", { id }) as unknown as Promise<boolean>;
|
|
15
|
+
}
|
|
16
|
+
export function admitAutomationRunAsync(input: { automationId: string; now: number; manual?: boolean; queuedRunId?: string }): Promise<{ automation: Automation; run: AutomationRun } | null> {
|
|
17
|
+
return getGateway().write("automations.admitRun", input, { idempotencyKey: randomUUID() }) as unknown as Promise<{ automation: Automation; run: AutomationRun } | null>;
|
|
18
|
+
}
|
|
19
|
+
export function insertRunAsync(...args: Parameters<typeof insertRun>): Promise<ReturnType<typeof insertRun>> {
|
|
20
|
+
return getGateway().write("automations.insertRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof insertRun>>;
|
|
21
|
+
}
|
|
22
|
+
export function enqueueAutomationRunAsync(...args: Parameters<typeof enqueueAutomationRun>): Promise<ReturnType<typeof enqueueAutomationRun>> {
|
|
23
|
+
return getGateway().write("automations.enqueueRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof enqueueAutomationRun>>;
|
|
24
|
+
}
|
|
25
|
+
export function updateRunAsync(...args: Parameters<typeof updateRun>): Promise<void> {
|
|
26
|
+
return getGateway().write("automations.updateRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export function cancelActiveRunsAsync(...args: Parameters<typeof cancelActiveRuns>): Promise<void> {
|
|
29
|
+
return getGateway().write("automations.cancelRuns", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export function rescheduleAutomationAsync(...args: Parameters<typeof rescheduleAutomation>): Promise<void> {
|
|
32
|
+
return getGateway().write("automations.reschedule", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
|
|
33
|
+
}
|
|
@@ -15,7 +15,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
|
|
|
15
15
|
const verification = input.mergedSha && input.landVerifiedSha === input.mergedSha
|
|
16
16
|
? "confirmed" : await verifyPublishedLand(workspace.repoRoot, input.mergedSha, workspace.baseRef);
|
|
17
17
|
if (verification !== "confirmed") {
|
|
18
|
-
notifyLandUnconfirmed({ workspace, sha: input.mergedSha, targetRef: base.startsWith("origin/") ? base : `origin/${base}`, kind: verification });
|
|
18
|
+
await notifyLandUnconfirmed({ workspace, sha: input.mergedSha, targetRef: base.startsWith("origin/") ? base : `origin/${base}`, kind: verification });
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
const landedBranch = workspace.branch;
|
|
@@ -47,7 +47,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
|
|
|
47
47
|
: " Worktree reclaimed.";
|
|
48
48
|
// Durable (ttl null): the author's own branch landing must reach them even after they go
|
|
49
49
|
// offline (store-ahead #234) — not a bystander notice that goes stale.
|
|
50
|
-
const notices = routeNotification({
|
|
50
|
+
const notices = await routeNotification({
|
|
51
51
|
type: "branch.landed",
|
|
52
52
|
scope: { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
|
|
53
53
|
recipients: [author],
|
|
@@ -75,7 +75,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
|
|
|
75
75
|
const mainScope = { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id, teamId: landedTask?.teamId ?? (author ? getAgent(author)?.teamId : undefined), coordinatorAgentIds: [...new Set([resolveCoordinatorAgentId(author), landedTask && resolveTaskOwnerAgentId(getTaskDetail(landedTask.taskId))].filter((id): id is string => !!id && !isHumanAgentId(id)))] };
|
|
76
76
|
const branchLabel = landedBranch ? `\`${landedBranch}\`` : "A branch";
|
|
77
77
|
const authorLabel = author ? ` by \`${author}\`` : "";
|
|
78
|
-
const notices = routeNotification({
|
|
78
|
+
const notices = await routeNotification({
|
|
79
79
|
type: "branch.landed",
|
|
80
80
|
scope: mainScope, ...audienceWithTaskOwnerRole("branch.landed", mainScope, landedTask?.taskId), // #2862
|
|
81
81
|
ttlMs: INFORMATIONAL_TTL_MS,
|
package/src/branch-landed.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { insertLandingReceiptAsync } from "./db/runtime-tail-async";
|
|
2
|
+
import { createActivityEventAsync } from "./db/activity-async";
|
|
1
3
|
import { announceVerifiedLand } from "./branch-land-notice";
|
|
2
4
|
import { errMessage, isHumanAgentId, type BaseWorktreeSyncResult } from "@humwick/sdk";
|
|
3
5
|
import { emitRelayEvent } from "./events";
|
|
4
6
|
import { routeNotification, INFORMATIONAL_TTL_MS } from "./notification-router";
|
|
5
7
|
import { stampLifecycleSignal, taskSignalKey } from "./lifecycle-signal-registry";
|
|
6
8
|
import { registerDefaultAudienceRules, audiencePredicates } from "./notification-rules";
|
|
7
|
-
import {
|
|
9
|
+
import { getAgent, getOrchestrator, getProject, getTaskDetail, markWorkspaceLanded, patchWorkspaceMetadataAsync, resolveProjectForCwd, updateWorkspaceStatusAsync, markWorkspaceLandedAsync } from "./db";
|
|
8
10
|
import { renderTemplate } from "./prompt-resolver";
|
|
9
11
|
import { resolveCoordinatorAgentId } from "./steward-identity";
|
|
10
12
|
import { stewardFallbackTarget } from "./config";
|
|
@@ -209,9 +211,9 @@ function landedNotificationIdempotencyKey(input: BranchLandedInput, landedTask:
|
|
|
209
211
|
* the announcement; this combined entry preserves the original all-synchronous behavior for the
|
|
210
212
|
* maintenance reconcile path (reconcileLandedWorkspace) and direct callers/tests.
|
|
211
213
|
*/
|
|
212
|
-
export function notifyBranchLanded(input: BranchLandedInput): void {
|
|
213
|
-
recordLandingReceipt(input);
|
|
214
|
-
announceBranchLanded(input);
|
|
214
|
+
export async function notifyBranchLanded(input: BranchLandedInput): Promise<void> {
|
|
215
|
+
(await recordLandingReceipt(input));
|
|
216
|
+
await announceBranchLanded(input);
|
|
215
217
|
}
|
|
216
218
|
|
|
217
219
|
/**
|
|
@@ -222,7 +224,7 @@ export function notifyBranchLanded(input: BranchLandedInput): void {
|
|
|
222
224
|
* row with no receipt. The branch is already landed, so a receipt failure is loud (CRITICAL log) but
|
|
223
225
|
* can never unwind or mask it.
|
|
224
226
|
*/
|
|
225
|
-
export function recordLandingReceipt(input: BranchLandedInput): void {
|
|
227
|
+
export async function recordLandingReceipt(input: BranchLandedInput): Promise<void> {
|
|
226
228
|
const { workspace } = input;
|
|
227
229
|
// #1620 — a land that introduced ZERO commits is not a land: no receipt (see announceBranchLanded).
|
|
228
230
|
if (input.landedCommitCount === 0) return;
|
|
@@ -237,7 +239,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
|
|
|
237
239
|
const mergedSha = cleanRef(input.mergedSha);
|
|
238
240
|
const commitShas = [...new Set((input.commitShas ?? []).map(cleanRef).filter((sha): sha is string => Boolean(sha)))];
|
|
239
241
|
if (commitShas.length === 0 && mergedSha) commitShas.push(mergedSha);
|
|
240
|
-
|
|
242
|
+
(await insertLandingReceiptAsync({
|
|
241
243
|
...(landedTask?.projectId ?? project?.id ? { projectId: landedTask?.projectId ?? project!.id } : {}),
|
|
242
244
|
repo: landedTask?.repo ?? project?.issueRepo ?? repoFromGitRemote(workspace.repoRoot) ?? workspace.repoRoot,
|
|
243
245
|
ref: workspace.baseRef ?? "base",
|
|
@@ -253,7 +255,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
|
|
|
253
255
|
...(landedTask?.teamId ?? worker?.teamId ? { teamId: landedTask?.teamId ?? worker!.teamId } : {}),
|
|
254
256
|
...(workspace.orchestratorId ? { orchestratorId: workspace.orchestratorId } : {}),
|
|
255
257
|
...(orchestrator?.hostname ?? worker?.machine ?? worker?.rig ? { host: orchestrator?.hostname ?? worker?.machine ?? worker!.rig } : {}),
|
|
256
|
-
});
|
|
258
|
+
}));
|
|
257
259
|
} catch (error) {
|
|
258
260
|
console.error(`[landing-receipt] CRITICAL: failed to persist landed branch ${workspace.id}: ${errMessage(error)}`);
|
|
259
261
|
}
|
|
@@ -265,7 +267,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
|
|
|
265
267
|
* the issue/Task lifecycle drives. #1790 — the settle path DEFERS this off its synchronous critical
|
|
266
268
|
* path; the durable receipt is recorded separately + synchronously by {@link recordLandingReceipt}.
|
|
267
269
|
*/
|
|
268
|
-
export function announceBranchLanded(input: BranchLandedInput): void {
|
|
270
|
+
export async function announceBranchLanded(input: BranchLandedInput): Promise<void> {
|
|
269
271
|
const { workspace } = input;
|
|
270
272
|
const base = workspace.baseRef ?? "base";
|
|
271
273
|
// #1620 — a land that introduced ZERO commits is not a land. It happens when a reconciliation
|
|
@@ -365,10 +367,10 @@ export function announceBranchLanded(input: BranchLandedInput): void {
|
|
|
365
367
|
* the checkout. Human WIP is never auto-clobbered; `preservedWipPaths` flags paths to merge by
|
|
366
368
|
* hand rather than blind-restore.
|
|
367
369
|
*/
|
|
368
|
-
export function notifyBaseWorktreeStrand(input: {
|
|
370
|
+
export async function notifyBaseWorktreeStrand(input: {
|
|
369
371
|
workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
|
|
370
372
|
sync: BaseWorktreeSyncResult;
|
|
371
|
-
}): void {
|
|
373
|
+
}): Promise<void> {
|
|
372
374
|
const { workspace, sync } = input;
|
|
373
375
|
if (sync.reconciled) return;
|
|
374
376
|
const base = workspace.baseRef ?? "base";
|
|
@@ -397,7 +399,7 @@ export function notifyBaseWorktreeStrand(input: {
|
|
|
397
399
|
|
|
398
400
|
emitRelayEvent({ type: "workspace.base_checkout_strand", source: "server", subject: workspace.id, data: payload });
|
|
399
401
|
|
|
400
|
-
|
|
402
|
+
(await createActivityEventAsync({
|
|
401
403
|
clientId: `workspace-base-strand-${workspace.id}-${Date.now()}`,
|
|
402
404
|
kind: "state",
|
|
403
405
|
title: "Base checkout stranded after land (mixed state)",
|
|
@@ -406,13 +408,13 @@ export function notifyBaseWorktreeStrand(input: {
|
|
|
406
408
|
icon: "ti-alert-octagon",
|
|
407
409
|
view: "orchestrators",
|
|
408
410
|
metadata: { source: "server", maintenanceJobId: "workspace-base-strand", workspaceId: workspace.id, repoRoot: workspace.repoRoot, unsyncedPaths: unsynced, preservedWipPaths: preservedWip },
|
|
409
|
-
});
|
|
411
|
+
}));
|
|
410
412
|
|
|
411
413
|
// Durable (ttl null) push to the owner and its coordinator — whoever works in the shared
|
|
412
414
|
// checkout must learn it's stale before acting on it. Fallback steward covers a teamless land.
|
|
413
415
|
const recipients = [...new Set([owner, coordinator, fallback].filter((r): r is string => Boolean(r)))];
|
|
414
416
|
if (recipients.length) {
|
|
415
|
-
routeNotification({
|
|
417
|
+
await routeNotification({
|
|
416
418
|
type: "workspace.base_checkout_strand",
|
|
417
419
|
scope: { author: owner, parent: coordinator ?? undefined, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
|
|
418
420
|
recipients,
|
|
@@ -432,12 +434,12 @@ export function notifyBaseWorktreeStrand(input: {
|
|
|
432
434
|
* steward-task/conflict pings: it tells the worker that its post-ready idle wait ended without
|
|
433
435
|
* a completed land, so it can inspect/report instead of silently staying parked forever.
|
|
434
436
|
*/
|
|
435
|
-
export function notifyBranchLandFailed(input: {
|
|
437
|
+
export async function notifyBranchLandFailed(input: {
|
|
436
438
|
workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
|
|
437
439
|
commandId?: string;
|
|
438
440
|
recipients?: string[];
|
|
439
441
|
reason?: string;
|
|
440
|
-
}): void {
|
|
442
|
+
}): Promise<void> {
|
|
441
443
|
const { workspace } = input;
|
|
442
444
|
const base = workspace.baseRef ?? "base";
|
|
443
445
|
const author = workspace.ownerAgentId;
|
|
@@ -464,7 +466,7 @@ export function notifyBranchLandFailed(input: {
|
|
|
464
466
|
const recipients = withWorkspaceTaskOwnerRoles(input.recipients ?? [author, coordinator], workspace); // #2862
|
|
465
467
|
if (!recipients.length) return;
|
|
466
468
|
const branchLabel = workspace.branch ? `\`${workspace.branch}\`` : "Your branch";
|
|
467
|
-
routeNotification({
|
|
469
|
+
await routeNotification({
|
|
468
470
|
type: "landed-failure",
|
|
469
471
|
scope: { author, parent: coordinator ?? undefined, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
|
|
470
472
|
recipients,
|
|
@@ -494,7 +496,7 @@ export { notifyLandGateFailed, notifyLandGateWarnings, notifyLandGateSkipped } f
|
|
|
494
496
|
* The steward id is the managed steward's policy name (reachable via `policy:<name>`) or an
|
|
495
497
|
* elected steward's agent id, whichever the caller has in scope.
|
|
496
498
|
*/
|
|
497
|
-
export function notifyStewardHandoff(input: {
|
|
499
|
+
export async function notifyStewardHandoff(input: {
|
|
498
500
|
workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
|
|
499
501
|
/** The steward now holding the merge — managed steward policy name or elected agent id. */
|
|
500
502
|
stewardId: string;
|
|
@@ -502,7 +504,7 @@ export function notifyStewardHandoff(input: {
|
|
|
502
504
|
coordinatorAgentId?: string | null;
|
|
503
505
|
/** Why it was handed over ("conflict", "merge state unknown", auto-merge back-off, …). */
|
|
504
506
|
reason?: string;
|
|
505
|
-
}): void {
|
|
507
|
+
}): Promise<void> {
|
|
506
508
|
const { workspace } = input;
|
|
507
509
|
const base = workspace.baseRef ?? "base";
|
|
508
510
|
const owner = workspace.ownerAgentId;
|
|
@@ -527,7 +529,7 @@ export function notifyStewardHandoff(input: {
|
|
|
527
529
|
// thinking the branch silently failed. Durable (ttl null): the owner must learn this
|
|
528
530
|
// even if it went idle. Mirror the "don't touch main" guardrail of the landed-failure wake.
|
|
529
531
|
if (owner) {
|
|
530
|
-
routeNotification({
|
|
532
|
+
await routeNotification({
|
|
531
533
|
type: "workspace.steward_handoff",
|
|
532
534
|
scope: { author: owner, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
|
|
533
535
|
recipients: [owner],
|
|
@@ -550,7 +552,7 @@ export function notifyStewardHandoff(input: {
|
|
|
550
552
|
// (it spawned the branch agent and owns the merge landing). Skip when the coordinator IS
|
|
551
553
|
// the owner (no real lineage) to avoid a duplicate ping.
|
|
552
554
|
if (coordinator && coordinator !== owner) {
|
|
553
|
-
routeNotification({
|
|
555
|
+
await routeNotification({
|
|
554
556
|
type: "workspace.steward_handoff",
|
|
555
557
|
scope: { author: owner, parent: coordinator, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
|
|
556
558
|
recipients: [coordinator],
|
|
@@ -671,7 +673,7 @@ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: Wor
|
|
|
671
673
|
const closure = ownerAlive
|
|
672
674
|
? `owner \`${ws.ownerAgentId}\` is still running, so the workspace stays non-terminal and usable at ${nextStatus}${nextStatus === ws.status ? "" : ` (was ${ws.status} — out of the land queue, #1662)`} (#1631); steward/strand and no-progress bookkeeping cleared`
|
|
673
675
|
: `marking merged${landedCommitCount === 0 ? "; nothing was landed" : ""}`;
|
|
674
|
-
|
|
676
|
+
(await createActivityEventAsync({
|
|
675
677
|
clientId: "server-workspace-" + ws.id + "-merged-" + Date.now(),
|
|
676
678
|
kind: "state",
|
|
677
679
|
title: ownerAlive
|
|
@@ -682,9 +684,9 @@ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: Wor
|
|
|
682
684
|
icon: "ti-git-merge",
|
|
683
685
|
view: "orchestrators",
|
|
684
686
|
metadata: { source: "server", maintenanceJobId: "workspace-conflict-scan", workspaceId: ws.id, fromStatus: ws.status, toStatus: nextStatus, ...(ownerAlive ? { ownerAlive: true, keptLive: true } : {}), ...(sha ? { landedSha: sha } : {}), ...(landedCommitCount === 0 ? { landedCommitCount: 0 } : {}) },
|
|
685
|
-
});
|
|
687
|
+
}));
|
|
686
688
|
try {
|
|
687
|
-
notifyBranchLanded({ workspace: ws, mergedSha: sha, landVerifiedSha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
|
|
689
|
+
await notifyBranchLanded({ workspace: ws, mergedSha: sha, landVerifiedSha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
|
|
688
690
|
} catch {
|
|
689
691
|
// Notification is best-effort; the status change + activity event still stand.
|
|
690
692
|
}
|
package/src/bus.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { announceSpawnedAgentReady, registerAgent } from "./services/register-ag
|
|
|
11
11
|
import { authContextFromBus } from "./services/auth-context";
|
|
12
12
|
import { commandAuthorizationResource, dispatchCommandAsync } from "./services/dispatch-command";
|
|
13
13
|
import { withRelayEventDrain } from "./relay-event-drain";
|
|
14
|
-
import { runAsCaller } from "./hub-metrics";
|
|
14
|
+
import { framed, runAsCaller } from "./hub-metrics";
|
|
15
15
|
import { auditProviderStateTransition } from "./services/provider-state-audit";
|
|
16
16
|
import { agentProviderTimelineEvent, auditRunnerTimelineEvent } from "./provider-timeline-event";
|
|
17
17
|
import { auditProviderTurnEmpty, auditProviderTurnWatchdog, auditReconciledProviderTurn } from "./services/turn-reconcile-audit";
|
|
@@ -19,6 +19,7 @@ import { ServiceAuthError } from "./services/errors";
|
|
|
19
19
|
import { ShutdownAuthError, ShutdownTargetError, shutdownAgent, shutdownInputFromBusFrame } from "./services/shutdown-agent";
|
|
20
20
|
import { flushQueuedDirectMessages } from "./services/managed-running";
|
|
21
21
|
import { updateCommandFromBus } from "./services/bus-command-update";
|
|
22
|
+
import { heartbeatFromBus } from "./services/agent-heartbeat";
|
|
22
23
|
import { isAgentUnavailable, reservedAgentIdSql } from "./db/agent-predicates";
|
|
23
24
|
import { messageMatchesAgent, targetMatchesAgent } from "./agent-ref";
|
|
24
25
|
import { probeWorkspaceOnTurnEnd } from "./workspace-probe";
|
|
@@ -76,7 +77,7 @@ const liveBusSocketIds = new Set<string>();
|
|
|
76
77
|
// stalls unrelated agents.
|
|
77
78
|
const busFrameQueues = new Map<string, Promise<void>>();
|
|
78
79
|
|
|
79
|
-
subscribeRelayEvents(
|
|
80
|
+
subscribeRelayEvents(broadcastRelayEvent);
|
|
80
81
|
|
|
81
82
|
export function handleBusUpgrade(req: Request, server: Server<BusSocketData>): Response | undefined {
|
|
82
83
|
if (!isOriginAllowed(req)) {
|
|
@@ -95,11 +96,11 @@ export function handleBusUpgrade(req: Request, server: Server<BusSocketData>): R
|
|
|
95
96
|
return undefined;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
export
|
|
99
|
+
export const busHandleOpen = framed("WS open", (ws: BusWebSocket): void => {
|
|
99
100
|
liveBusSocketIds.add(ws.data.id);
|
|
100
101
|
// Registration is explicit. The socket is not visible to projections until
|
|
101
102
|
// a valid register frame establishes identity and subscriptions.
|
|
102
|
-
}
|
|
103
|
+
});
|
|
103
104
|
|
|
104
105
|
export function busHandleMessage(ws: BusWebSocket, data: string | Buffer): void {
|
|
105
106
|
if (!liveBusSocketIds.has(ws.data.id)) return;
|
|
@@ -127,7 +128,7 @@ export function busHandleMessage(ws: BusWebSocket, data: string | Buffer): void
|
|
|
127
128
|
busFrameQueues.set(ws.data.id, queued);
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
export
|
|
131
|
+
export const busHandleClose = framed("WS close", (ws: BusWebSocket): void => {
|
|
131
132
|
liveBusSocketIds.delete(ws.data.id);
|
|
132
133
|
busFrameQueues.delete(ws.data.id);
|
|
133
134
|
const conn = busConnections.get(ws.data.id);
|
|
@@ -145,7 +146,7 @@ export function busHandleClose(ws: BusWebSocket): void {
|
|
|
145
146
|
});
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
|
-
}
|
|
149
|
+
});
|
|
149
150
|
|
|
150
151
|
export function getBusConnectionCount(): number {
|
|
151
152
|
return busConnections.size;
|
|
@@ -210,7 +211,7 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
|
|
|
210
211
|
// #416 — flush queued messages if the agent transitioned from unavailable to available.
|
|
211
212
|
if (wasUnavailable) {
|
|
212
213
|
const after = getAgent(conn.agentId);
|
|
213
|
-
if (after && !isAgentUnavailable(after)) flushQueuedDirectMessages(conn.agentId);
|
|
214
|
+
if (after && !isAgentUnavailable(after)) (await flushQueuedDirectMessages(conn.agentId));
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
}
|
|
@@ -249,27 +250,27 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
|
|
|
249
250
|
const after = applied.after;
|
|
250
251
|
await auditProviderStateTransition(conn.agentId, before, after);
|
|
251
252
|
const timelineEvent = agentProviderTimelineEvent(after);
|
|
252
|
-
auditRunnerTimelineEvent(conn.agentId, timelineEvent);
|
|
253
|
+
(await auditRunnerTimelineEvent(conn.agentId, timelineEvent));
|
|
253
254
|
// #1621 — a turn the runner proved was cancelled out of band is a real state change the
|
|
254
255
|
// waiting coordinator has to hear about, not just an activity-feed row.
|
|
255
|
-
auditReconciledProviderTurn(conn.agentId, after, timelineEvent);
|
|
256
|
+
await auditReconciledProviderTurn(conn.agentId, after, timelineEvent);
|
|
256
257
|
// #1980 — the busy backstop is HOLDING a long turn it can't prove idle (not cancelling);
|
|
257
258
|
// tell the waiting coordinator the turn is still live rather than leaving it to guess.
|
|
258
259
|
// #2010 — but only when there's no positive busy evidence already saying so (see the
|
|
259
260
|
// busy-health gate inside auditProviderTurnWatchdog); a demonstrably working agent needs
|
|
260
261
|
// no wake.
|
|
261
|
-
auditProviderTurnWatchdog(conn.agentId, after, timelineEvent);
|
|
262
|
+
await auditProviderTurnWatchdog(conn.agentId, after, timelineEvent);
|
|
262
263
|
// #2389 — a turn that ended clean and produced nothing is the least visible failure of the
|
|
263
264
|
// three: the card reads healthy and idle. Tell the parent once the runner's own nudge has
|
|
264
265
|
// failed to recover it.
|
|
265
|
-
auditProviderTurnEmpty(conn.agentId, after, timelineEvent);
|
|
266
|
+
await auditProviderTurnEmpty(conn.agentId, after, timelineEvent);
|
|
266
267
|
// #2432 — a first ready that arrives over a status frame (children whose register kept the
|
|
267
268
|
// row not-ready, e.g. ox/opencode builders) must stamp readiness exactly like the HTTP and
|
|
268
269
|
// registration seams, or the child later reaps as a false `agent.spawn_failed`.
|
|
269
|
-
if (readyTransition) announceSpawnedAgentReady(conn.agentId, "bus-ready");
|
|
270
|
+
if (readyTransition) await announceSpawnedAgentReady(conn.agentId, "bus-ready");
|
|
270
271
|
// A parked continuation consumes one retry on a genuine ready/idle transition only.
|
|
271
272
|
const replayEpoch = continuationReplayEpoch(conn, before, after);
|
|
272
|
-
if (replayEpoch) replayParkedContinuationInjections(conn.agentId, replayEpoch);
|
|
273
|
+
if (replayEpoch) (await replayParkedContinuationInjections(conn.agentId, replayEpoch));
|
|
273
274
|
// A real PreCompact/SessionStart hook arrives as a timelineEvent in the
|
|
274
275
|
// merged meta — clears any pending stall watch (stale events ignored).
|
|
275
276
|
noteAgentTimelineEvent(conn.agentId, timelineEvent);
|
|
@@ -279,7 +280,7 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
|
|
|
279
280
|
// #633 — silent clean-exit: a runner that stays alive after its provider terminally exited
|
|
280
281
|
// marks the offline edge with `terminalProviderExit`; the owning service turns that into a
|
|
281
282
|
// terminal event + #636 diagnosis (and clears the hold on a genuine resume).
|
|
282
|
-
reconcileTerminalProviderExit(conn.agentId, before, after);
|
|
283
|
+
await reconcileTerminalProviderExit(conn.agentId, before, after);
|
|
283
284
|
});
|
|
284
285
|
return;
|
|
285
286
|
case "ack":
|
|
@@ -305,8 +306,9 @@ async function handleCommandFrame(
|
|
|
305
306
|
target: string,
|
|
306
307
|
params: Record<string, unknown>,
|
|
307
308
|
): Promise<void> {
|
|
309
|
+
if (commandType === "agent.heartbeat") return withRelayEventDrain(() => heartbeatFromBus(conn, target, params)).then((o) => sendCommandResult(ws, frameId, o.status, o.result, o.error));
|
|
308
310
|
if (commandType === "command.update") {
|
|
309
|
-
return withRelayEventDrain(() => updateCommandFromBus({ target, params, componentAuth: conn.componentAuth }))
|
|
311
|
+
return withRelayEventDrain(async () => (await updateCommandFromBus({ target, params, componentAuth: conn.componentAuth })))
|
|
310
312
|
.then((result) => sendCommandResult(ws, frameId, result.status, result.result, result.error))
|
|
311
313
|
.catch((error) => sendError(ws, frameId, "FRAME_FAILED", errMessage(error)));
|
|
312
314
|
}
|
|
@@ -333,10 +335,10 @@ async function handleCommandFrame(
|
|
|
333
335
|
// busCommandAuthorized gate), createCommand, and the "command.requested" emit. The bus
|
|
334
336
|
// adapter only translates the typed ServiceAuthError into a rejected result frame.
|
|
335
337
|
try {
|
|
336
|
-
const command = await withRelayEventDrain(() => dispatchCommandAsync(
|
|
338
|
+
const command = await withRelayEventDrain(async () => (await dispatchCommandAsync(
|
|
337
339
|
{ type: commandType, source: conn.agentId ?? conn.componentId, target, params },
|
|
338
340
|
authContextFromBus(conn.componentAuth),
|
|
339
|
-
));
|
|
341
|
+
)));
|
|
340
342
|
sendCommandResult(ws, frameId, "succeeded", { command });
|
|
341
343
|
} catch (e) {
|
|
342
344
|
if (e instanceof ServiceAuthError) {
|
|
@@ -385,7 +387,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
|
|
|
385
387
|
...(lifecycle === "transient" || lifecycle === "persistent" ? { lifecycle } : {}),
|
|
386
388
|
meta: payload.meta,
|
|
387
389
|
};
|
|
388
|
-
const agent = registerAgent(input, authContextFromBus(ws.data.componentAuth), { emitStatus: false });
|
|
390
|
+
const agent = await registerAgent(input, authContextFromBus(ws.data.componentAuth), { emitStatus: false });
|
|
389
391
|
epoch = agent.epoch;
|
|
390
392
|
}
|
|
391
393
|
|
|
@@ -429,7 +431,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
|
|
|
429
431
|
epoch,
|
|
430
432
|
cursor: getOutboxCursor(),
|
|
431
433
|
sessionId: ws.data.id,
|
|
432
|
-
features: { heartbeatAck: true },
|
|
434
|
+
features: { heartbeatAck: true, liveness: true },
|
|
433
435
|
},
|
|
434
436
|
});
|
|
435
437
|
}
|