@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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { OFFLINE_PRUNE_MS, REAP_INTERVAL_MS } from "../config";
|
|
2
|
+
import { pruneOfflineAgentsAsync } from "../db/agents-async";
|
|
3
|
+
import { emitAgentRemoved } from "../sse";
|
|
4
|
+
import { emitWorkFinalityResult } from "../services/work-finality";
|
|
5
|
+
import type { MaintenanceJobDefinition } from "./types";
|
|
6
|
+
|
|
7
|
+
export const OFFLINE_AGENT_PRUNE_JOB: MaintenanceJobDefinition = {
|
|
8
|
+
id: "offline-agent-prune",
|
|
9
|
+
critical: false,
|
|
10
|
+
title: "Offline agent prune",
|
|
11
|
+
description: "Delete long-offline provider agents and release their claims.",
|
|
12
|
+
intervalMs: REAP_INTERVAL_MS,
|
|
13
|
+
runOnStart: false,
|
|
14
|
+
async handler(context) {
|
|
15
|
+
if (context.signal?.aborted) return { prunedAgentIds: [], aborted: true };
|
|
16
|
+
// #1084 crash-final-loss fix-forward — defense-in-depth: `notifyAgentOffline` is the primary
|
|
17
|
+
// flush point when an agent first goes offline, so this is normally a no-op by the time an
|
|
18
|
+
// agent reaches prune horizon; the async facade snapshots its held queue and performs the DB
|
|
19
|
+
// finalization in the SAME worker transaction before deleting the agent row.
|
|
20
|
+
let archivePurgeFailures = 0;
|
|
21
|
+
const prunedAgentIds = await pruneOfflineAgentsAsync(OFFLINE_PRUNE_MS, {
|
|
22
|
+
onFinality: emitWorkFinalityResult,
|
|
23
|
+
onArchivePurgeFailure: () => { archivePurgeFailures++; },
|
|
24
|
+
});
|
|
25
|
+
for (const id of prunedAgentIds) emitAgentRemoved(id);
|
|
26
|
+
return { prunedAgentIds, archivePurgeFailures };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createCommandAsync } from "../commands-write";
|
|
2
|
+
import { listCommands } from "../commands-db";
|
|
2
3
|
import { createActivityEventAsync, getAgent, listOrchestrators } from "../db";
|
|
3
4
|
import type { Command, ManagedAgent } from "../types";
|
|
4
5
|
import { orphanGraceMs, orphanReapCooldownMs, orphanReapEnabled } from "./constants";
|
|
@@ -44,7 +45,7 @@ export async function reapOrphanedSessions(context: { signal?: AbortSignal } = {
|
|
|
44
45
|
let orphaned = 0;
|
|
45
46
|
|
|
46
47
|
for (const orch of listOrchestrators()) {
|
|
47
|
-
// #1819 — checkpoint per orchestrator and per managed session: a reap is `
|
|
48
|
+
// #1819 — checkpoint per orchestrator and per managed session: a reap is `createCommandAsync` +
|
|
48
49
|
// `emitCommandEventIfAbsent` + activity event + `lastReapAt` stamp, indivisible once started.
|
|
49
50
|
if (signal?.aborted) break;
|
|
50
51
|
if (orch.status !== "online") continue;
|
|
@@ -70,7 +71,7 @@ export async function reapOrphanedSessions(context: { signal?: AbortSignal } = {
|
|
|
70
71
|
// logical orphan reap has one command id and one command.requested event.
|
|
71
72
|
const pending = listCommands({ target: orch.agentId, type: "agent.shutdown", limit: 500 })
|
|
72
73
|
.find((command) => isPendingReapForSession(command, session));
|
|
73
|
-
const command = pending ??
|
|
74
|
+
const command = pending ?? (await createCommandAsync({
|
|
74
75
|
type: "agent.shutdown",
|
|
75
76
|
source: "system",
|
|
76
77
|
target: orch.agentId,
|
|
@@ -89,7 +90,7 @@ export async function reapOrphanedSessions(context: { signal?: AbortSignal } = {
|
|
|
89
90
|
requestedAt: now,
|
|
90
91
|
orchestratorId: orch.id,
|
|
91
92
|
},
|
|
92
|
-
});
|
|
93
|
+
}));
|
|
93
94
|
// The command is durable but not externally observable until its audit row commits. A failed
|
|
94
95
|
// audit must never let an orchestrator execute an unaudited reap (#1912 S3.2 class B).
|
|
95
96
|
await createActivityEventAsync({
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resumeMaintenanceJobAsync, pauseMaintenanceJobAsync } from "../db/runtime-tail-async";
|
|
1
2
|
// #1645 — behavior layer for maintenance-job pause/resume: validation, audit, and the drift report.
|
|
2
3
|
//
|
|
3
4
|
// Persistence is src/db/maintenance-pauses.ts; the scheduler gate reads from there. This module is
|
|
@@ -6,14 +7,7 @@
|
|
|
6
7
|
// #1638 pause's justification existed only in one agent's session context and one memory file.
|
|
7
8
|
|
|
8
9
|
import { errMessage } from "@humwick/sdk";
|
|
9
|
-
import {
|
|
10
|
-
createActivityEventAsync,
|
|
11
|
-
latestSuccessfulDeployAsync,
|
|
12
|
-
listMaintenanceJobPauses,
|
|
13
|
-
pauseMaintenanceJob,
|
|
14
|
-
resumeMaintenanceJob,
|
|
15
|
-
type MaintenanceJobPauseRecord,
|
|
16
|
-
} from "../db";
|
|
10
|
+
import { createActivityEventAsync, latestSuccessfulDeployAsync, listMaintenanceJobPauses, type MaintenanceJobPauseRecord } from "../db";
|
|
17
11
|
import { openRestartEpochsAsync } from "../db/restart-epoch-async.ts";
|
|
18
12
|
import { ValidationError } from "../db/connection.ts";
|
|
19
13
|
import { definitions } from "./jobs";
|
|
@@ -61,7 +55,7 @@ export async function pauseJob(input: PauseJobRequest): Promise<PauseJobResult>
|
|
|
61
55
|
throw new ValidationError("pass either ttlMs or indefinite, not both");
|
|
62
56
|
}
|
|
63
57
|
|
|
64
|
-
const result =
|
|
58
|
+
const result = (await pauseMaintenanceJobAsync({ ...input, reason }));
|
|
65
59
|
if (!result.ok) return { ok: false, conflict: true, pause: result.pause };
|
|
66
60
|
|
|
67
61
|
const ownedRestartEpoch = await ownedOpenRestartEpoch(definition.id);
|
|
@@ -126,7 +120,7 @@ export interface ResumeJobResult {
|
|
|
126
120
|
export async function resumeJobAsync(opts: { jobId?: string; id?: string; now?: number }): Promise<ResumeJobResult> {
|
|
127
121
|
if (opts.jobId) requireKnownJob(opts.jobId);
|
|
128
122
|
const now = opts.now ?? Date.now();
|
|
129
|
-
const released =
|
|
123
|
+
const released = (await resumeMaintenanceJobAsync({ jobId: opts.jobId, id: opts.id }));
|
|
130
124
|
if (!released) return { resumed: false };
|
|
131
125
|
const heldForMs = Math.max(0, now - released.createdAt);
|
|
132
126
|
const lapsed = released.expiresAt !== undefined && released.expiresAt <= now;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { relayEnv } from "@humwick/sdk/env";
|
|
3
|
+
import { getGateway } from "../db/gateway";
|
|
4
|
+
import { getPlan, listPlansByTeam } from "../db/plans";
|
|
5
|
+
import type { DueReadyNodes, ReadyPlanScan } from "../db/plan-ready-notices";
|
|
6
|
+
import { listActiveTeams } from "../db/teams";
|
|
7
|
+
import { routeNotification } from "../notification-router";
|
|
8
|
+
import { compactText, liveFrontier } from "../services/plan-wake-digest";
|
|
9
|
+
|
|
10
|
+
const DEFAULT_READY_NOTICE_MINUTES = 30;
|
|
11
|
+
|
|
12
|
+
/** #3660 — minutes a ready node may sit unstarted before the coordinator hears about it. */
|
|
13
|
+
export function planReadyNoticeMs(): number {
|
|
14
|
+
const minutes = Number(relayEnv(process.env, "AGENT_RELAY_PLAN_READY_NOTICE_MINUTES"));
|
|
15
|
+
return (Number.isFinite(minutes) && minutes > 0 ? minutes : DEFAULT_READY_NOTICE_MINUTES) * 60_000;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Ready (all prerequisites landed), still pending after the Task projection, and nobody owns it. */
|
|
19
|
+
function scanTeamPlans(teamId: string, signal: AbortSignal): Array<ReadyPlanScan & { title: string }> {
|
|
20
|
+
const scans: Array<ReadyPlanScan & { title: string }> = [];
|
|
21
|
+
let cursor: string | undefined;
|
|
22
|
+
do {
|
|
23
|
+
const page = listPlansByTeam(teamId, { limit: 100, cursor });
|
|
24
|
+
for (const summary of page.plans) {
|
|
25
|
+
if (signal.aborted) return scans;
|
|
26
|
+
if (!summary.nodeCount || summary.completion === "done") continue;
|
|
27
|
+
const stored = getPlan(summary.id);
|
|
28
|
+
if (!stored) continue;
|
|
29
|
+
const { frontier } = liveFrontier(stored);
|
|
30
|
+
scans.push({ planId: stored.id, title: stored.title ?? "Untitled", nodeIds: frontier.ready.filter(node => !node.ownerRef).map(node => node.id) });
|
|
31
|
+
}
|
|
32
|
+
cursor = page.nextCursor;
|
|
33
|
+
} while (cursor);
|
|
34
|
+
return scans;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function noticeUnstartedReadyNodes(signal: AbortSignal, now = Date.now()): Promise<Record<string, unknown>> {
|
|
38
|
+
const scans: Array<ReadyPlanScan & { title: string; teamId: string }> = [];
|
|
39
|
+
for (const team of listActiveTeams()) {
|
|
40
|
+
if (signal.aborted) return { notices: 0 };
|
|
41
|
+
if (team.coordinatorId) scans.push(...scanTeamPlans(team.id, signal).map(scan => ({ ...scan, teamId: team.id })));
|
|
42
|
+
}
|
|
43
|
+
if (signal.aborted) return { notices: 0 };
|
|
44
|
+
const due = await getGateway().write("plans.readyNotices.sync", { scans: scans.map(({ planId, nodeIds }) => ({ planId, nodeIds })), now, dueMs: planReadyNoticeMs() }) as unknown as DueReadyNodes[];
|
|
45
|
+
const byPlan = new Map(scans.map(scan => [scan.planId, scan]));
|
|
46
|
+
let notices = 0;
|
|
47
|
+
for (const item of due) {
|
|
48
|
+
const scan = byPlan.get(item.planId)!;
|
|
49
|
+
if (signal.aborted) break;
|
|
50
|
+
const nodeIds = item.nodes.map(node => node.nodeId);
|
|
51
|
+
const minutes = Math.round(planReadyNoticeMs() / 60_000);
|
|
52
|
+
const key = createHash("sha1").update(item.nodes.map(node => `${node.nodeId}@${node.readySince}`).join(",")).digest("hex").slice(0, 12);
|
|
53
|
+
await routeNotification({
|
|
54
|
+
type: "team.idle", scope: { teamId: scan.teamId }, recipients: [`coordinator:${scan.teamId}`],
|
|
55
|
+
message: { kind: "system", from: "system", subject: "Plan nodes ready but not started", replyExpected: false,
|
|
56
|
+
body: `${compactText(scan.title, 56)} (${scan.planId}): ready for ${minutes}+ min, not started: ${nodeIds.slice(0, 8).map(id => compactText(id, 32)).join(",")}${nodeIds.length > 8 ? `,+${nodeIds.length - 8}` : ""}. Start them or mark them blocked (relay_plan_get mode=resume).`,
|
|
57
|
+
payload: { kind: "plan.ready-unstarted", teamId: scan.teamId, planId: scan.planId, nodeIds },
|
|
58
|
+
idempotencyKey: `plan-ready:${scan.planId}:${key}` },
|
|
59
|
+
});
|
|
60
|
+
await getGateway().write("plans.readyNotices.mark", { planId: item.planId, nodeIds, now });
|
|
61
|
+
notices++;
|
|
62
|
+
}
|
|
63
|
+
return { notices };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const PLAN_READY_NOTICE_JOB = {
|
|
67
|
+
id: "plan-ready-notice", title: "Ready Plan nodes not started", critical: false,
|
|
68
|
+
description: "Tell each coordinator once when a Plan node has been ready with nothing started for the notice window.",
|
|
69
|
+
intervalMs: 5 * 60_000, deadlineMs: 60_000, runOnStart: false,
|
|
70
|
+
handler: (context: { signal: AbortSignal }) => noticeUnstartedReadyNodes(context.signal),
|
|
71
|
+
} satisfies import("./types").MaintenanceJobDefinition;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { rescheduleRunOnStartJobsAsync, claimMaintenanceRunAsync, finishMaintenanceRunAsync, heartbeatMaintenanceRunAsync, ensureMaintenanceJobsAsync, reclaimDeadLeasesAsync } from "../db/maintenance-job-runs-async";
|
|
1
2
|
import { timePostBindPhase } from "../post-bind-startup";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { errMessage, isRecord } from "@humwick/sdk";
|
|
4
5
|
import { classifyPidLiveness } from "@humwick/sdk/process-utils";
|
|
5
|
-
import { CRITICAL_MAINTENANCE_PROGRESS_STALE_MS, createActivityEventAsync, getDb,
|
|
6
|
-
import {
|
|
6
|
+
import { CRITICAL_MAINTENANCE_PROGRESS_STALE_MS, createActivityEventAsync, getDb, MAINTENANCE_RUN_AUTORESET_GUARD_SQL, recordDrainConvoy, writeTransaction } from "../db";
|
|
7
|
+
import { reclaimDeadLeases, upsertMaintenanceJobs } from "../db/maintenance-job-reconcile";
|
|
8
|
+
import type { DeadLease, MaintenanceJobSpec } from "../db/maintenance-job-reconcile";
|
|
7
9
|
import type { MaintenanceRunOutcome } from "../db/maintenance-job-runs";
|
|
8
10
|
import { withAbortDeadline } from "../async-deadline";
|
|
9
11
|
import { MAINTENANCE_BREAKER_LAG_MS } from "../config";
|
|
10
12
|
import { findPauseByJobId, getMaintenanceJobPause, notPausedSql } from "../db/maintenance-pauses";
|
|
11
13
|
import { setLagBreakerObserver } from "../event-loop-lag";
|
|
14
|
+
import { framed, runInFrame } from "../hub-metrics";
|
|
12
15
|
import { resetRateLimitResumeTrackerForTests } from "../services/rate-limit-resume";
|
|
13
16
|
import { resetTransientTrackerForTests } from "../services/transient-agent-reaper";
|
|
14
17
|
import { isEphemeralMode } from "../execution-mode";
|
|
@@ -76,7 +79,7 @@ const MAINTENANCE_PROGRESS_HEARTBEAT_MS = 60_000;
|
|
|
76
79
|
// 3. HARD BLAST-RADIUS CAP: at most ONE new auto-pause per lag sample (operator Q4). If several
|
|
77
80
|
// qualify, pause the single largest in-gap block and warn about the rest. One freeze may never
|
|
78
81
|
// pause a fleet.
|
|
79
|
-
setLagBreakerObserver((_gapStartAt, gapEndAt, lagMs) => {
|
|
82
|
+
setLagBreakerObserver(async (_gapStartAt, gapEndAt, lagMs) => {
|
|
80
83
|
const reason = `blocked the event loop ~${Math.round(lagMs)}ms (measured block)`;
|
|
81
84
|
// #1725 P1 F-A — the ACTUATOR uses the TIGHTENED window `[gapEndAt - lagMs, gapEndAt]`, the actual
|
|
82
85
|
// freeze interval, NOT the sampler's diagnostic window `[_gapStartAt, gapEndAt]`. The sampler builds
|
|
@@ -140,7 +143,7 @@ setLagBreakerObserver((_gapStartAt, gapEndAt, lagMs) => {
|
|
|
140
143
|
const blamed = strikable.reduce((worst, entry) => (entry.overlapMs > worst.overlapMs ? entry : worst));
|
|
141
144
|
if (isRunActive(blamed.run.runId)) abortRun(blamed.run.runId, new MaintenanceBreakerError(`aborted by circuit breaker: ${reason}`));
|
|
142
145
|
const critical = definitions.find((job) => job.id === blamed.run.jobId)?.critical ?? false;
|
|
143
|
-
recordBreakerStrike({ runId: blamed.run.runId, jobId: blamed.run.jobId, critical, kind: "lag", reason });
|
|
146
|
+
(await recordBreakerStrike({ runId: blamed.run.runId, jobId: blamed.run.jobId, critical, kind: "lag", reason }));
|
|
144
147
|
const others = strikable.filter((entry) => entry !== blamed);
|
|
145
148
|
if (others.length > 0) {
|
|
146
149
|
console.warn(`[relay] maintenance circuit breaker: ${strikable.length} runs each blocked >=${Math.round(shareThresholdMs)}ms of this ${Math.round(lagMs)}ms freeze — struck ${blamed.run.jobId} (in-freeze block ${Math.round(blamed.overlapMs)}ms), one-per-sample cap; not struck: ${others.map((entry) => `${entry.run.jobId} (${Math.round(entry.overlapMs)}ms)`).join(", ")}`);
|
|
@@ -163,8 +166,8 @@ const runBlockTotalMs = (run: MaintenanceRunRecord): number => Math.round((run.b
|
|
|
163
166
|
/** Exposes the internal `runJob` directly, bypassing the `definitions` lookup `runMaintenanceJobNow`
|
|
164
167
|
* does, so tests can drive the run-registry/timeout/crash paths with a synthetic handler.
|
|
165
168
|
* Production code never calls this name. */
|
|
166
|
-
export const runMaintenanceJobForTests = (definition: MaintenanceJobDefinition, options: { force?: boolean; overridePause?: boolean } = {}) =>
|
|
167
|
-
runJob(definition, options);
|
|
169
|
+
export const runMaintenanceJobForTests = async (definition: MaintenanceJobDefinition, options: { force?: boolean; overridePause?: boolean } = {}) =>
|
|
170
|
+
(await runJob(definition, options));
|
|
168
171
|
|
|
169
172
|
export function resetOrphanTrackerForTests(): void {
|
|
170
173
|
resetOrphanSessionTrackerForTests();
|
|
@@ -173,41 +176,41 @@ export function resetOrphanTrackerForTests(): void {
|
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
export function startMaintenanceScheduler(): void {
|
|
176
|
-
//
|
|
177
|
-
//
|
|
179
|
+
// #1870 S7: the boot reconcile, run-on-start reschedule and dead-lease reclaim are writer ops. The first
|
|
180
|
+
// tick waits for them, so a due run-on-start job is never claimed before its reschedule lands.
|
|
181
|
+
void bootMaintenanceJobs().then(() => runDueMaintenanceJobs())
|
|
182
|
+
.catch((error) => console.warn(`maintenance tick failed: ${errMessage(error)}`));
|
|
183
|
+
// Floated ticks are wrapped defensively: runDueMaintenanceJobs already catches
|
|
184
|
+
// its own errors (#1481), but a stray rejection from a floated promise must
|
|
185
|
+
// never bubble to an unhandledRejection that exits the relay process.
|
|
186
|
+
if (timer) return;
|
|
187
|
+
timer = setInterval(
|
|
188
|
+
framed("timer maintenance", () => runDueMaintenanceJobs().catch((error) => console.warn(`maintenance tick failed: ${errMessage(error)}`))),
|
|
189
|
+
SCHEDULER_TICK_MS,
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function bootMaintenanceJobs(): Promise<void> {
|
|
194
|
+
// A transient SQLITE_BUSY here must not abort startup: every scheduler tick runs the reconcile again.
|
|
178
195
|
try {
|
|
179
|
-
|
|
180
|
-
scheduleRunOnStartJobs();
|
|
196
|
+
await ensureMaintenanceJobsAsync(jobSpecs());
|
|
181
197
|
} catch (error) {
|
|
182
198
|
console.warn(`maintenance job reconcile at startup failed (will retry on next tick): ${errMessage(error)}`);
|
|
183
|
-
void ensureMaintenanceJobsResilient()
|
|
184
|
-
.then(() => {
|
|
185
|
-
scheduleRunOnStartJobs();
|
|
186
|
-
return runDueMaintenanceJobs();
|
|
187
|
-
})
|
|
188
|
-
.catch((retryError) => console.warn(`maintenance startup retry failed (will retry on next tick): ${errMessage(retryError)}`));
|
|
189
199
|
}
|
|
190
|
-
// #1493 — a relay restart orphans the maintenance-job lease its own dying
|
|
191
|
-
// process held moments earlier: lease_owner still names the dead PID and
|
|
192
|
-
// lease_until is still in the future, so the claim guard in runJob/
|
|
193
|
-
// runDueMaintenanceJobs (lease_until IS NULL OR lease_until <= now) blocks
|
|
194
|
-
// the job — e.g. the CD watcher — until the lease's TTL self-expires (up to
|
|
195
|
-
// deadlineMs + 5s). Reclaim any lease whose owner PID is no longer alive so
|
|
196
|
-
// maintenance resumes immediately after a restart instead of stalling.
|
|
197
200
|
try {
|
|
198
|
-
|
|
201
|
+
await rescheduleRunOnStartJobsAsync();
|
|
202
|
+
} catch (error) {
|
|
203
|
+
// The next tick retries it, so run-on-start jobs do not wait a full interval (#1870 S7).
|
|
204
|
+
runOnStartPending = true;
|
|
205
|
+
console.warn(`maintenance run-on-start reschedule failed (will retry on next tick): ${errMessage(error)}`);
|
|
206
|
+
}
|
|
207
|
+
// #1493 — a restart orphans the lease its dying process held: lease_owner still names the dead PID and
|
|
208
|
+
// lease_until is still in the future, which blocks the job (e.g. the CD watcher) until the TTL expires.
|
|
209
|
+
try {
|
|
210
|
+
await reclaimDeadLeasesAsync(findDeadLeases());
|
|
199
211
|
} catch (error) {
|
|
200
212
|
console.warn(`dead-PID maintenance lease reclaim at startup failed (will retry on next tick): ${errMessage(error)}`);
|
|
201
213
|
}
|
|
202
|
-
// Floated ticks are wrapped defensively: runDueMaintenanceJobs already catches
|
|
203
|
-
// its own errors (#1481), but a stray rejection from a floated promise must
|
|
204
|
-
// never bubble to an unhandledRejection that exits the relay process.
|
|
205
|
-
void runDueMaintenanceJobs().catch((error) => console.warn(`maintenance tick failed: ${errMessage(error)}`));
|
|
206
|
-
if (timer) return;
|
|
207
|
-
timer = setInterval(
|
|
208
|
-
() => void runDueMaintenanceJobs().catch((error) => console.warn(`maintenance tick failed: ${errMessage(error)}`)),
|
|
209
|
-
SCHEDULER_TICK_MS,
|
|
210
|
-
);
|
|
211
214
|
}
|
|
212
215
|
|
|
213
216
|
/**
|
|
@@ -218,33 +221,41 @@ export function startMaintenanceScheduler(): void {
|
|
|
218
221
|
* doing it from the periodic reconcile would make run-on-start jobs run every
|
|
219
222
|
* scheduler tick.
|
|
220
223
|
*/
|
|
221
|
-
export function scheduleRunOnStartJobs(now: number = Date.now()): void {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
export async function scheduleRunOnStartJobs(now: number = Date.now()): Promise<void> {
|
|
225
|
+
(await rescheduleRunOnStartJobsAsync(now));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function readMaintenanceJobs(): MaintenanceJob[] {
|
|
229
|
+
const rows = getDb().query("SELECT * FROM maintenance_jobs ORDER BY title COLLATE NOCASE ASC").all() as MaintenanceJobRow[];
|
|
230
|
+
const now = Date.now();
|
|
231
|
+
const currentIds = new Set(definitions.map((definition) => definition.id));
|
|
232
|
+
return rows.filter((row) => currentIds.has(row.id)).map((row) => rowToJob(row, now));
|
|
227
233
|
}
|
|
228
234
|
|
|
235
|
+
// A transient lock while reconciling must not fail a listing; return the current rows (a later reconcile catches up). #1481.
|
|
229
236
|
export function listMaintenanceJobs(): MaintenanceJob[] {
|
|
230
237
|
try {
|
|
231
238
|
ensureMaintenanceJobs();
|
|
232
239
|
} catch (error) {
|
|
233
|
-
// A transient lock while reconciling must not fail a read-only listing; fall
|
|
234
|
-
// through and return the current rows (a later reconcile catches up). #1481.
|
|
235
240
|
console.warn(`maintenance job reconcile during list failed: ${errMessage(error)}`);
|
|
236
241
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
242
|
+
return readMaintenanceJobs();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export async function listMaintenanceJobsAsync(): Promise<MaintenanceJob[]> {
|
|
246
|
+
try {
|
|
247
|
+
await ensureMaintenanceJobsAsync(jobSpecs());
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.warn(`maintenance job reconcile during list failed: ${errMessage(error)}`);
|
|
250
|
+
}
|
|
251
|
+
return readMaintenanceJobs();
|
|
241
252
|
}
|
|
242
253
|
|
|
243
254
|
export async function runMaintenanceJobNow(id: string, options: { overridePause?: boolean } = {}): Promise<MaintenanceJobRun> {
|
|
244
|
-
await
|
|
255
|
+
await ensureMaintenanceJobsAsync(jobSpecs());
|
|
245
256
|
const definition = definitions.find((job) => job.id === id);
|
|
246
257
|
if (!definition) throw new Error("maintenance job not found");
|
|
247
|
-
return runJob(definition, { force: true, overridePause: options.overridePause });
|
|
258
|
+
return (await runJob(definition, { force: true, overridePause: options.overridePause }));
|
|
248
259
|
}
|
|
249
260
|
|
|
250
261
|
export async function runLegacyMaintenanceReaper(): Promise<Record<string, unknown>> {
|
|
@@ -266,6 +277,7 @@ async function runMaintenanceJobsNow(ids: string[]): Promise<MaintenanceJobRun[]
|
|
|
266
277
|
// no-op (the still-open tick, or the one after, picks up whatever came due). Combined with the
|
|
267
278
|
// serialized drain below, this is the "one job at a time from a queue" the design (§5.4) calls for.
|
|
268
279
|
let tickInFlight = false;
|
|
280
|
+
let runOnStartPending = false;
|
|
269
281
|
|
|
270
282
|
export async function runDueMaintenanceJobs(): Promise<void> {
|
|
271
283
|
if (tickInFlight) return;
|
|
@@ -274,7 +286,11 @@ export async function runDueMaintenanceJobs(): Promise<void> {
|
|
|
274
286
|
// is guarded: a transient SQLITE_BUSY (or any other failure) reconciling or
|
|
275
287
|
// querying the job table is logged and the tick is skipped — the next tick retries.
|
|
276
288
|
try {
|
|
277
|
-
await
|
|
289
|
+
await ensureMaintenanceJobsAsync(jobSpecs());
|
|
290
|
+
if (runOnStartPending) {
|
|
291
|
+
await rescheduleRunOnStartJobsAsync();
|
|
292
|
+
runOnStartPending = false;
|
|
293
|
+
}
|
|
278
294
|
const now = Date.now();
|
|
279
295
|
const progressStaleAt = now - CRITICAL_MAINTENANCE_PROGRESS_STALE_MS;
|
|
280
296
|
const rows = getDb().query(`
|
|
@@ -363,84 +379,28 @@ export function drainDueMaintenanceJobsForTests(dueDefinitions: MaintenanceJobDe
|
|
|
363
379
|
* otherwise leave it latched, wedging every later test's tick). Production never calls this. */
|
|
364
380
|
export function resetSchedulerTickGuardForTests(): void {
|
|
365
381
|
tickInFlight = false;
|
|
382
|
+
runOnStartPending = false;
|
|
366
383
|
}
|
|
367
384
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
async function ensureMaintenanceJobsResilient(): Promise<void> {
|
|
380
|
-
for (let attempt = 1; ; attempt++) {
|
|
381
|
-
try {
|
|
382
|
-
ensureMaintenanceJobs();
|
|
383
|
-
return;
|
|
384
|
-
} catch (error) {
|
|
385
|
-
if (attempt < ENSURE_BUSY_RETRY_ATTEMPTS && isSqliteBusyError(error)) {
|
|
386
|
-
const cap = Math.min(ENSURE_BUSY_RETRY_MAX_MS, ENSURE_BUSY_RETRY_BASE_MS * 2 ** (attempt - 1));
|
|
387
|
-
const delay = cap / 2 + Math.random() * (cap / 2);
|
|
388
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
throw error;
|
|
392
|
-
}
|
|
393
|
-
}
|
|
385
|
+
function jobSpecs(): MaintenanceJobSpec[] {
|
|
386
|
+
return definitions.map((definition) => ({
|
|
387
|
+
id: definition.id,
|
|
388
|
+
title: definition.title,
|
|
389
|
+
description: definition.description,
|
|
390
|
+
intervalMs: definition.intervalMs,
|
|
391
|
+
deadlineMs: definition.deadlineMs ?? DEFAULT_DEADLINE_MS,
|
|
392
|
+
enabled: !isEphemeralMode() || definition.instanceSafe === true,
|
|
393
|
+
critical: definition.critical === true,
|
|
394
|
+
runOnStart: definition.runOnStart === true,
|
|
395
|
+
}));
|
|
394
396
|
}
|
|
395
397
|
|
|
398
|
+
// Boot/test twin of `ensureMaintenanceJobsAsync`: one BEGIN IMMEDIATE so busy_timeout governs a single lock
|
|
399
|
+
// acquisition (#1481). The listing read path and tests use it; the running scheduler uses the writer op.
|
|
396
400
|
function ensureMaintenanceJobs(): void {
|
|
397
|
-
const
|
|
401
|
+
const specs = jobSpecs();
|
|
398
402
|
const now = Date.now();
|
|
399
|
-
|
|
400
|
-
// CODE-owned and therefore self-healing. Before this it was set only on INSERT and deliberately
|
|
401
|
-
// omitted from the conflict clause, because the one column doubled as the operator's "stop" lever
|
|
402
|
-
// and a redeploy would have clobbered their intent. Operator intent now lives in
|
|
403
|
-
// `maintenance_job_pauses` (holder, reason, expiry), so re-asserting `enabled` overrides nobody —
|
|
404
|
-
// and a hand-written `UPDATE maintenance_jobs SET enabled=0` recovers at the next boot instead of
|
|
405
|
-
// persisting until someone writes more raw SQL (nine hours of deploy blackout, #1645).
|
|
406
|
-
//
|
|
407
|
-
// PRECONDITION: convertManualJobDisablesToPauses() (src/db/migrations.ts) must have run first, or
|
|
408
|
-
// this silently switches back on a job an operator deliberately stopped.
|
|
409
|
-
const stmt = db.query(`
|
|
410
|
-
INSERT INTO maintenance_jobs (id, title, description, interval_ms, timeout_ms, enabled, critical, run_on_start, next_run_at, updated_at)
|
|
411
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
412
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
413
|
-
title = excluded.title,
|
|
414
|
-
description = excluded.description,
|
|
415
|
-
interval_ms = excluded.interval_ms,
|
|
416
|
-
timeout_ms = excluded.timeout_ms,
|
|
417
|
-
run_on_start = excluded.run_on_start,
|
|
418
|
-
enabled = excluded.enabled, -- #1645: code-owned, see the note above this query
|
|
419
|
-
critical = excluded.critical,
|
|
420
|
-
next_run_at = COALESCE(maintenance_jobs.next_run_at, excluded.next_run_at),
|
|
421
|
-
updated_at = excluded.updated_at
|
|
422
|
-
`);
|
|
423
|
-
// Batch the upserts into a single BEGIN IMMEDIATE write so busy_timeout governs
|
|
424
|
-
// ONE lock acquisition (SQLite waits) instead of one per definition, cutting the
|
|
425
|
-
// lock churn that made this loop the crash site under contention (#1481).
|
|
426
|
-
writeTransaction(() => {
|
|
427
|
-
for (const definition of definitions) {
|
|
428
|
-
stmt.run(
|
|
429
|
-
definition.id,
|
|
430
|
-
definition.title,
|
|
431
|
-
definition.description,
|
|
432
|
-
definition.intervalMs,
|
|
433
|
-
// #1728: the DB column stays `timeout_ms` — renaming it is a migration, not asked for here.
|
|
434
|
-
// Code-side this is `deadlineMs`: see MaintenanceJobDefinition for why.
|
|
435
|
-
definition.deadlineMs ?? DEFAULT_DEADLINE_MS,
|
|
436
|
-
!isEphemeralMode() || definition.instanceSafe === true ? 1 : 0,
|
|
437
|
-
definition.critical ? 1 : 0,
|
|
438
|
-
definition.runOnStart ? 1 : 0,
|
|
439
|
-
definition.runOnStart ? now : now + definition.intervalMs,
|
|
440
|
-
now,
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
});
|
|
403
|
+
writeTransaction(() => upsertMaintenanceJobs(specs, now));
|
|
444
404
|
}
|
|
445
405
|
|
|
446
406
|
// #1493 — reclaim current-schema maintenance_jobs leases whose owner PID is proven dead.
|
|
@@ -455,23 +415,19 @@ function ensureMaintenanceJobs(): void {
|
|
|
455
415
|
// #3645: the crash is not a job failure — it neither bumps consecutive_failures nor replaces an existing
|
|
456
416
|
// last_error (a non-null one belongs to the live failure streak; success clears it). The page-only guard remains on every
|
|
457
417
|
// deadline-based reclaim/claim path, where that positive evidence is unavailable.
|
|
458
|
-
|
|
459
|
-
const
|
|
460
|
-
const
|
|
461
|
-
const leased = db.query(`
|
|
462
|
-
SELECT id, lease_owner FROM maintenance_jobs
|
|
463
|
-
WHERE lease_owner IS NOT NULL
|
|
464
|
-
`).all() as Array<{ id: string; lease_owner: string }>;
|
|
418
|
+
function findDeadLeases(): DeadLease[] {
|
|
419
|
+
const leased = getDb().query("SELECT id, lease_owner FROM maintenance_jobs WHERE lease_owner IS NOT NULL").all() as Array<{ id: string; lease_owner: string }>;
|
|
420
|
+
const dead: DeadLease[] = [];
|
|
465
421
|
for (const row of leased) {
|
|
466
422
|
const pid = parseLeaseOwnerPid(row.lease_owner);
|
|
467
|
-
if (pid
|
|
468
|
-
db.query(`
|
|
469
|
-
UPDATE maintenance_jobs
|
|
470
|
-
SET lease_owner = NULL, lease_until = NULL, last_status = 'failed',
|
|
471
|
-
last_error = COALESCE(last_error, ?), run_token = NULL, last_progress_at = ?, updated_at = ?
|
|
472
|
-
WHERE id = ? AND lease_owner = ?
|
|
473
|
-
`).run(`reclaimed stale lease at startup: owner pid ${pid} is confirmed dead`, now, now, row.id, row.lease_owner);
|
|
423
|
+
if (pid !== null && classifyPidLiveness(pid) === "dead") dead.push({ id: row.id, owner: row.lease_owner, pid });
|
|
474
424
|
}
|
|
425
|
+
return dead;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export function reclaimDeadPidLeases(): void {
|
|
429
|
+
const dead = findDeadLeases();
|
|
430
|
+
if (dead.length) writeTransaction(() => reclaimDeadLeases(dead, Date.now()));
|
|
475
431
|
}
|
|
476
432
|
|
|
477
433
|
function parseLeaseOwnerPid(owner: string): number | null {
|
|
@@ -494,7 +450,12 @@ async function persistRunOutcome(outcome: MaintenanceRunOutcome): Promise<boolea
|
|
|
494
450
|
}
|
|
495
451
|
}
|
|
496
452
|
|
|
497
|
-
|
|
453
|
+
/** #3798 — each run is its own hub-metrics frame, so a job's main-thread CPU is named per job. */
|
|
454
|
+
function runJob(definition: MaintenanceJobDefinition, options: { force?: boolean; overridePause?: boolean } = {}): Promise<MaintenanceJobRun> {
|
|
455
|
+
return runInFrame({ callsite: `job ${definition.id}` }, () => executeJob(definition, options));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
async function executeJob(definition: MaintenanceJobDefinition, options: { force?: boolean; overridePause?: boolean }): Promise<MaintenanceJobRun> {
|
|
498
459
|
const startedAt = Date.now();
|
|
499
460
|
// One execution boundary covers ticks, forced runs and already-queued definitions.
|
|
500
461
|
if (isEphemeralMode() && definition.instanceSafe !== true) {
|
|
@@ -527,7 +488,7 @@ async function runJob(definition: MaintenanceJobDefinition, options: { force?: b
|
|
|
527
488
|
const progressStaleAt = startedAt - CRITICAL_MAINTENANCE_PROGRESS_STALE_MS;
|
|
528
489
|
const claimed = await claimMaintenanceRunAsync({ id: definition.id, owner, runToken, startedAt, leaseUntil, progressStaleAt, force: options.force === true });
|
|
529
490
|
if (!claimed) {
|
|
530
|
-
const state =
|
|
491
|
+
const state = readMaintenanceJobs().find((job) => job.id === definition.id);
|
|
531
492
|
return { id: definition.id, status: "skipped", startedAt, finishedAt: Date.now(), durationMs: 0, result: { reason: "not due or already running", state } };
|
|
532
493
|
}
|
|
533
494
|
|
|
@@ -628,7 +589,7 @@ async function runJob(definition: MaintenanceJobDefinition, options: { force?: b
|
|
|
628
589
|
if (persisted && (isTimeout || breakerAborted)) {
|
|
629
590
|
// A breaker abort is a lag event that the lag observer has usually already struck (deduped by
|
|
630
591
|
// runId here); a timeout is its own consecutive-overrun signal.
|
|
631
|
-
recordBreakerStrike({ runId: run.runId, jobId: definition.id, critical: definition.critical, kind: isTimeout ? "timeout" : "lag", reason: isTimeout ? `timed out after ${deadlineMs}ms` : message });
|
|
592
|
+
(await recordBreakerStrike({ runId: run.runId, jobId: definition.id, critical: definition.critical, kind: isTimeout ? "timeout" : "lag", reason: isTimeout ? `timed out after ${deadlineMs}ms` : message }));
|
|
632
593
|
}
|
|
633
594
|
if (definition.logRuns) console.warn(`[relay] maintenance job ${definition.id} ${status} in ${durationMs}ms: ${message}`);
|
|
634
595
|
return { id: definition.id, status, startedAt, finishedAt, durationMs, error: message, ...(result ? { result } : {}) };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { errMessage } from "@humwick/sdk";
|
|
2
|
-
import { getConfig
|
|
2
|
+
import { getConfig } from "../config-store";
|
|
3
|
+
import { setConfigAsync } from "../config-store-write";
|
|
3
4
|
import { getStalledDeliverySignalAsync } from "../db/stats-async.ts";
|
|
4
5
|
import { notifyWorkspaceHumanEscalation } from "../workspace-human-escalation";
|
|
5
6
|
import type { MaintenanceJobDefinition } from "./types";
|
|
@@ -56,8 +57,8 @@ export async function runStalledDeliveryPager(now: number = Date.now()): Promise
|
|
|
56
57
|
}
|
|
57
58
|
let alerted = false;
|
|
58
59
|
let recovered = false;
|
|
59
|
-
const persist = () => {
|
|
60
|
-
if (JSON.stringify(state) !== JSON.stringify(prior))
|
|
60
|
+
const persist = async () => {
|
|
61
|
+
if (JSON.stringify(state) !== JSON.stringify(prior)) await setConfigAsync(STATE_NAMESPACE, STATE_KEY, state, "stalled-delivery-pager");
|
|
61
62
|
};
|
|
62
63
|
|
|
63
64
|
const { check } = signal;
|
|
@@ -68,7 +69,7 @@ export async function runStalledDeliveryPager(now: number = Date.now()): Promise
|
|
|
68
69
|
state = { ...state, failStreak: 0, okStreak: state.stalled ? state.okStreak + 1 : 0 };
|
|
69
70
|
if (state.stalled && state.okStreak >= STALL_PAGE_CONFIRM_CHECKS) {
|
|
70
71
|
if (state.alerted) {
|
|
71
|
-
const result = notifyWorkspaceHumanEscalation({
|
|
72
|
+
const result = (await notifyWorkspaceHumanEscalation({
|
|
72
73
|
subject: "Message delivery recovered",
|
|
73
74
|
body: `Messages are being delivered to live agents again. The stall began ${new Date(state.since).toISOString()}.`,
|
|
74
75
|
priority: "default",
|
|
@@ -76,7 +77,7 @@ export async function runStalledDeliveryPager(now: number = Date.now()): Promise
|
|
|
76
77
|
source: "stalled-delivery-pager",
|
|
77
78
|
payload: { kind: "message-delivery.recovered", since: state.since, recoveredAt: now },
|
|
78
79
|
idempotencyKey: `stalled-delivery:${state.since}:recovered`,
|
|
79
|
-
});
|
|
80
|
+
}));
|
|
80
81
|
recovered = result.accepted;
|
|
81
82
|
if (!result.accepted) console.warn(`[relay] #3014 message delivery recovered — operator NOT paged: ${result.reason}`);
|
|
82
83
|
}
|
|
@@ -87,8 +88,8 @@ export async function runStalledDeliveryPager(now: number = Date.now()): Promise
|
|
|
87
88
|
if (!state.stalled && state.failStreak >= STALL_PAGE_CONFIRM_CHECKS) state = { ...state, stalled: true, since: now, alerted: false };
|
|
88
89
|
if (state.stalled && !state.alerted) {
|
|
89
90
|
// Persist the episode first so a crash after the send re-sends under the same key.
|
|
90
|
-
persist();
|
|
91
|
-
const result = notifyWorkspaceHumanEscalation({
|
|
91
|
+
await persist();
|
|
92
|
+
const result = (await notifyWorkspaceHumanEscalation({
|
|
92
93
|
subject: "Message delivery stalled",
|
|
93
94
|
body: [
|
|
94
95
|
`${check.subjects?.length ?? 0} live, idle agents have had mail unattempted for over 2 minutes and no turn was delivered to any agent in 5 minutes.`,
|
|
@@ -101,13 +102,13 @@ export async function runStalledDeliveryPager(now: number = Date.now()): Promise
|
|
|
101
102
|
source: "stalled-delivery-pager",
|
|
102
103
|
payload: { kind: "message-delivery.stalled", since: state.since, count: check.count, subjects: check.subjects },
|
|
103
104
|
idempotencyKey: `stalled-delivery:${state.since}:alert`,
|
|
104
|
-
});
|
|
105
|
+
}));
|
|
105
106
|
alerted = result.accepted;
|
|
106
107
|
if (!result.accepted) console.warn(`[relay] #3014 message delivery stalled — operator NOT paged: ${result.reason}`);
|
|
107
108
|
state = { ...state, alerted: true };
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
|
-
persist();
|
|
111
|
+
await persist();
|
|
111
112
|
return { state: state.stalled ? "stalled" : "ok", alerted, recovered };
|
|
112
113
|
}
|
|
113
114
|
|