@humwick/server 0.130.0 → 0.130.2
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/docs/guides/tools-administration.md +6 -1
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +58 -0
- package/docs/openapi.json +414 -1
- package/package.json +8 -17
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-BWLqMGKG.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-3TlIQpjk.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-Wimm0Czv.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-Bau_vNax.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-CrSurn-r.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-CknAJKcb.js} +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-DKbiIhBo.js} +2 -2
- package/public/assets/agent-profiles-DwF6EQ4R.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-Diz4Sjjb.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-CRhpRQza.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-LrUEU3lB.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-B-v66C-4.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-BqCb-LKi.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-kf4pGuAR.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-D32zyw4Y.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-DJevXcvg.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BpRajx_5.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-D_UjTdzX.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-N3VEh4ao.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-9jopungq.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-CSXrTB3C.js} +2 -2
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-p1NnmqK0.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-CZdqlDNL.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BgdsE4dG.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-30aXTKva.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-B_jvw2GE.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-DoN6bAb5.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-BrKWFGJz.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-D6XEu8Ng.js} +2 -2
- package/public/assets/fleet-C7jQWbw2.js +2 -0
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BiDs3MLx.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-CQBwc1fb.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-DyG0WsQS.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-DKaW31dN.js} +2 -2
- package/public/assets/index-CRHep3M9.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-CzrtkpOE.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-aVsUmigt.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-BnSlM_95.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-qe7Ee47Z.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-NfjqFZAk.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-BiH0HgaE.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-BixaT3Xr.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-DNGlWIS3.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-DNsCl6UX.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-DopU1L1X.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Cq7ckLQT.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-C1DCTzzV.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-DE_m6rrE.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-B3rfh77F.js} +2 -2
- package/public/assets/project-profile-instructions-DQWZE0kA.js +2 -0
- package/public/assets/projects-Br2Bd2h1.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-BKvFsvGD.js} +2 -2
- package/public/assets/provider-display-DsuWMvVL.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-Cw38_6gW.js} +2 -2
- package/public/assets/run-card-CpKqRbhg.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-DxI-vzSq.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-D9s_VJbd.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CKZTVGIx.js} +2 -2
- package/public/assets/{shipping-Bu8p1gEw.js → shipping-B9YtnwtG.js} +2 -2
- package/public/assets/{stats-V9Z-GxUd.js → stats-DyUBKyWI.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-DYqlEUhJ.js} +2 -2
- package/public/assets/{store-BvtFdlGX.js → store-DcClXLH0.js} +3 -3
- package/public/assets/{tasks-CXU75HRF.js → tasks-Bh7Chr4-.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-bowI7qVY.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-BgVLHdsU.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-Dz22UPy6.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-DSQQ-iY7.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-samMQhQf.js} +2 -2
- package/public/assets/use-project-list-59LheVP7.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BZa25xEB.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-DHxlvUvV.js} +2 -2
- package/public/assets/versioned-prompt-editor-BmED5DnJ.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-CSvpuNLz.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-DAZcj5qt.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-DdmxRSyg.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-BxeKfVuF.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/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/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +0 -2
- 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/index.ts +5 -2
- package/runner/src/provider-setup.ts +34 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +18 -23
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/scripts/cd-config.ts +24 -3
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +7 -76
- package/src/bus.ts +19 -20
- package/src/cd-deploy-notify.ts +30 -2
- 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/root-missing.ts +2 -7
- package/src/ci/transition-notify.ts +7 -39
- 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 +8 -2
- package/src/commands-db.ts +10 -6
- package/src/commands-write.ts +8 -0
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- package/src/db/activity-async.ts +6 -1
- package/src/db/activity-write-ops.ts +13 -1
- package/src/db/activity.ts +1 -14
- package/src/db/agent-lifecycle-write-ops.ts +1 -0
- package/src/db/agent-meta.ts +2 -2
- package/src/db/agent-ownership-write-ops.ts +4 -0
- package/src/db/agent-search.ts +1 -15
- package/src/db/agents-async.ts +58 -7
- package/src/db/agents-write-ops.ts +28 -5
- package/src/db/agents.ts +81 -54
- package/src/db/artifacts-write-ops.ts +8 -3
- package/src/db/bus-outbox-write-ops.ts +1 -0
- package/src/db/channels-write-ops.ts +4 -0
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/claude-api-budget-ops.ts +5 -5
- package/src/db/claude-app-oauth.ts +4 -4
- package/src/db/codex-reset-consumes-write-ops.ts +3 -0
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/commands-write-ops.ts +21 -0
- package/src/db/config-store-write-ops.ts +9 -2
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +9 -0
- package/src/db/continuations.ts +2 -2
- package/src/db/db-writer-worker.ts +8 -1
- package/src/db/delivery-write-ops.ts +5 -0
- 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/hosts-registration.ts +10 -2
- package/src/db/hosts-write-ops.ts +14 -0
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox-write-ops.ts +4 -0
- package/src/db/inbox.ts +0 -14
- package/src/db/index.ts +2 -0
- package/src/db/insights-write-ops.ts +1 -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-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +20 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +7 -8
- package/src/db/long-running-work.ts +2 -2
- package/src/db/macos-privacy.ts +1 -1
- package/src/db/main-connection-writes.ts +23 -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/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/message-reads-write-ops.ts +3 -0
- package/src/db/message-write-ops.ts +4 -0
- package/src/db/migrations.ts +7 -15
- package/src/db/orchestrators-async.ts +7 -3
- package/src/db/orchestrators-write-ops.ts +7 -1
- package/src/db/orchestrators.ts +21 -77
- package/src/db/pairs.ts +1 -13
- package/src/db/project-profile-instructions.ts +50 -0
- package/src/db/prompt-versions-ops.ts +1 -0
- package/src/db/prompt-versions.ts +9 -2
- package/src/db/provider-catalog-write-ops.ts +4 -4
- package/src/db/provider-config-history.ts +8 -3
- package/src/db/provider-flap-messages-write-ops.ts +1 -0
- package/src/db/provider-model-seed.ts +34 -0
- package/src/db/provider-quota-lease-write-ops.ts +1 -0
- package/src/db/provider-quota-write-ops.ts +2 -0
- package/src/db/provisioning-write-ops.ts +9 -8
- package/src/db/read-op-marshaling-fixtures.ts +5 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/routing-policy.ts +3 -4
- package/src/db/schema.ts +9 -3
- package/src/db/secrets-broker-write-ops.ts +5 -5
- package/src/db/secrets-vault-write.ts +7 -7
- package/src/db/services-write-ops.ts +3 -0
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/spawn-tree-cleanup.ts +3 -0
- package/src/db/stats-async.ts +4 -3
- package/src/db/task-entity.ts +23 -2
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/team-spawn-delegation.ts +1 -1
- package/src/db/teams-write-ops.ts +4 -4
- package/src/db/timer-cutover-write-ops.ts +7 -0
- package/src/db/timer-ingress-write-ops.ts +9 -0
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/timer-operator-write-ops.ts +14 -0
- package/src/db/timer-transfer-write-ops.ts +4 -0
- package/src/db/timer-write-ops.ts +14 -0
- package/src/db/token-db-write-ops.ts +21 -0
- package/src/db/token-standing.ts +15 -11
- package/src/db/user-settings-write-ops.ts +1 -0
- package/src/db/vault-backup.ts +2 -2
- package/src/db/vault-expiry.ts +2 -2
- package/src/db/vault-health.ts +3 -3
- package/src/db/vault-token-ops.ts +8 -8
- package/src/db/web-tool-call-ops.ts +3 -3
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/write-ops.ts +15 -1
- package/src/db/writer-fault-seam.ts +5 -2
- package/src/db/writer-gateway.ts +21 -12
- 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/host/disk-alert.ts +121 -0
- package/src/lifecycle-manager.ts +3 -2
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/critical-job-watchdog.ts +16 -17
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +3 -2
- package/src/maintenance/scheduler.ts +84 -128
- package/src/maintenance/stalled-delivery-pager.ts +6 -5
- package/src/maintenance/workspaces.ts +1 -1
- package/src/managed-policy.ts +31 -27
- package/src/mcp/index.ts +5 -2
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +4 -4
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/tool-groups.ts +1 -1
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-host-tools.ts +1 -1
- package/src/mcp-issue-ref-tools.ts +12 -11
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-profile-trust-tools.ts +4 -4
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-workflow-tools.ts +10 -3
- package/src/notification-types.ts +2 -1
- package/src/operator-alarm.ts +26 -11
- package/src/package-pack.ts +42 -39
- package/src/project-instructions.ts +4 -0
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- 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-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/recipe-runner.ts +2 -2
- package/src/repo-config-source.ts +10 -4
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +6 -6
- package/src/routes/commands-listing.ts +4 -0
- package/src/routes/commands.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/host-resource-control.ts +4 -1
- package/src/routes/index.ts +10 -1
- package/src/routes/integrations.ts +24 -50
- package/src/routes/issue-refs.ts +7 -7
- package/src/routes/orchestrator-bootstrap.ts +3 -3
- package/src/routes/orchestrator-host-registration.ts +2 -2
- package/src/routes/orchestrator-host-utilization.ts +3 -1
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +4 -4
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +2 -2
- package/src/routes/provider-config.ts +9 -8
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/settings.ts +5 -5
- 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 +5 -5
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/tokens.ts +12 -5
- package/src/routes/workflows.ts +20 -5
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +4 -2
- package/src/runtime-tokens.ts +50 -9
- package/src/security.ts +13 -20
- package/src/server-background.ts +1 -1
- package/src/server.ts +5 -2
- package/src/services/host-utilization.ts +23 -0
- package/src/services/idle-epics.ts +5 -6
- package/src/services/issue-lifecycle.ts +57 -61
- package/src/services/issue-refs.ts +9 -13
- package/src/services/kernel-timers-cutover-chaos-worker.ts +12 -7
- package/src/services/kernel-timers-ingress.ts +1 -1
- package/src/services/kernel-timers-request-key-migration-chaos-worker.ts +4 -1
- package/src/services/landed-ancestry.ts +19 -3
- package/src/services/memory-areas.ts +15 -51
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-wake-digest.ts +1 -0
- package/src/services/profile-trust.ts +4 -3
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/restart-spawn.ts +61 -49
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +5 -1
- package/src/services/spawn-agent.ts +13 -2
- package/src/services/spawn-chain-inspector.ts +6 -13
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-tree-cleanup.ts +2 -2
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-state-reconcile.ts +6 -14
- package/src/services/team-templates.ts +9 -8
- package/src/services/transient-agent-reaper.ts +3 -1
- package/src/services/workflow-auto-start.ts +25 -13
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-deferred-cleanup.ts +4 -2
- package/src/services/workflow-effect-driver.ts +2 -0
- package/src/services/workflow-effects.ts +18 -11
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-reconcile.ts +13 -11
- package/src/services/workflow-run-view.ts +2 -0
- package/src/services/workflow-runs.ts +29 -13
- package/src/services/workflow-supervisor-state.ts +5 -0
- package/src/services/workflow-supervisor.ts +7 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +1 -1
- package/src/spawn-targets.ts +1 -1
- package/src/startup-context-injection.ts +1 -0
- 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.ts +7 -6
- package/src/task-dispatch-live.ts +1 -1
- package/src/task-dispatcher.ts +1 -1
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/workspace-command-settle.ts +2 -1
- package/src/workspace-steward-wake.ts +2 -2
- 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 -47
- 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 -46
- 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/fleet-BL4UXS_k.js +0 -2
- package/public/assets/index-B7ZerHLY.css +0 -2
- package/public/assets/index-BK0WV6hF.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/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/routing-model-aliases.ts +0 -21
|
@@ -19,6 +19,8 @@ import { applyIdleSelfCare } from "./idle-self-care";
|
|
|
19
19
|
// write (none of these are) would need `idempotent: false` plus a caller-supplied key.
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
|
+
applyAgentLifecycleUpdateInternal,
|
|
23
|
+
type AgentLifecycleWriteArgs,
|
|
22
24
|
clearAgentMetaKeys,
|
|
23
25
|
deleteAgentInternal,
|
|
24
26
|
heartbeat,
|
|
@@ -41,6 +43,7 @@ import {
|
|
|
41
43
|
import { pruneOfflineAgentsWithFinality, type AgentsPruneOfflineOpArgs } from "./agents-prune-write-op.ts";
|
|
42
44
|
import { setAgentKeepState } from "./agent-keep.ts";
|
|
43
45
|
import type { AgentCard, AgentKeep, AgentSessionGuard, ContextState, ManagedSessionExitDiagnostics, ProviderCapabilities, QuotaState, RegisterAgentInput } from "../types";
|
|
46
|
+
import type { OrphanedTokenPage } from "./agents.ts";
|
|
44
47
|
import type { LineageRevokeReason } from "./token-standing.ts";
|
|
45
48
|
import type { LifecycleWriteOutcome } from "./lifecycle-seq.ts";
|
|
46
49
|
import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
|
|
@@ -69,31 +72,36 @@ export interface AgentsHeartbeatOpArgs {
|
|
|
69
72
|
export interface AgentsRecordContextSnapshotOpArgs { agentId: string; context: ContextState }
|
|
70
73
|
export interface AgentsReapStaleOpArgs { ttlMs: number; lagGraceMs: number; protectedIds?: string[]; seq: number }
|
|
71
74
|
export interface AgentsDeleteOpArgs { id: string }
|
|
72
|
-
export interface AgentsRevokeOrphanedTokensOpArgs { graceMs: number; lagGraceMs: number }
|
|
75
|
+
export interface AgentsRevokeOrphanedTokensOpArgs { graceMs: number; lagGraceMs: number; afterId?: string; limit?: number }
|
|
73
76
|
export interface AgentsRevokeTokensForAgentOpArgs { agentId: string; reason?: LineageRevokeReason }
|
|
74
77
|
|
|
75
78
|
export const AGENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
76
|
-
"agents.pruneIdentityArchive": { idempotent: true, fn: (_args: Record<string, never>, ctx: WriterOpContext) => pruneAgentIdentityArchive(ctx.now) },
|
|
77
|
-
"agents.idleSelfCare": { idempotent: false, fn: (args: { id: string; epoch: number }, ctx: WriterOpContext) => applyIdleSelfCare(args, ctx.now) },
|
|
79
|
+
"agents.pruneIdentityArchive": { offLoop: true, idempotent: true, fn: (_args: Record<string, never>, ctx: WriterOpContext) => pruneAgentIdentityArchive(ctx.now) },
|
|
80
|
+
"agents.idleSelfCare": { offLoop: true, idempotent: false, fn: (args: { id: string; epoch: number }, ctx: WriterOpContext) => applyIdleSelfCare(args, ctx.now) },
|
|
78
81
|
"agents.upsert": {
|
|
82
|
+
offLoop: true,
|
|
79
83
|
idempotent: true,
|
|
80
84
|
fn: (args: AgentsUpsertOpArgs, ctx: WriterOpContext): UpsertAgentTxResult =>
|
|
81
85
|
upsertAgentInternal(args.input, args.opts, ctx.now, args.seq),
|
|
82
86
|
},
|
|
83
87
|
"agents.setLabel": {
|
|
88
|
+
offLoop: true,
|
|
84
89
|
idempotent: true,
|
|
85
90
|
fn: (args: AgentsSetLabelOpArgs): boolean => setLabel(args.id, args.label),
|
|
86
91
|
},
|
|
87
92
|
"agents.setKeep": {
|
|
93
|
+
offLoop: true,
|
|
88
94
|
idempotent: true,
|
|
89
95
|
fn: (args: { id: string; keep: AgentKeep | null }): boolean => setAgentKeepState(args.id, args.keep),
|
|
90
96
|
},
|
|
91
97
|
"agents.setTeam": {
|
|
98
|
+
offLoop: true,
|
|
92
99
|
idempotent: true,
|
|
93
100
|
fn: (args: AgentsSetTeamOpArgs, ctx: WriterOpContext): AgentCard | null =>
|
|
94
101
|
setAgentTeam(args.agentId, args.teamId, ctx.now),
|
|
95
102
|
},
|
|
96
103
|
"agents.setTags": {
|
|
104
|
+
offLoop: true,
|
|
97
105
|
idempotent: true,
|
|
98
106
|
fn: (args: AgentsSetTagsOpArgs, ctx: WriterOpContext): AgentCard | null =>
|
|
99
107
|
setTags(args.id, args.tags, ctx.now),
|
|
@@ -102,6 +110,12 @@ export const AGENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.f
|
|
|
102
110
|
// coalescing window buffered them) and return a tri-state: `superseded` means a later-submitted
|
|
103
111
|
// lifecycle write already landed, which is a SUCCESS for the caller and must not be mistaken for a
|
|
104
112
|
// missing agent. See lifecycle-seq.ts.
|
|
113
|
+
"agents.applyLifecycleUpdate": {
|
|
114
|
+
// #1870 S7: bus status frame and heartbeat bypass; a replay of the same `seq` is a no-op on the fenced columns.
|
|
115
|
+
offLoop: true,
|
|
116
|
+
idempotent: true,
|
|
117
|
+
fn: (args: AgentLifecycleWriteArgs) => applyAgentLifecycleUpdateInternal(args),
|
|
118
|
+
},
|
|
105
119
|
"agents.setStatus": {
|
|
106
120
|
offLoop: true,
|
|
107
121
|
idempotent: true,
|
|
@@ -115,16 +129,19 @@ export const AGENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.f
|
|
|
115
129
|
markReady(args.id, args.ready, args.guard, ctx.now, args.seq),
|
|
116
130
|
},
|
|
117
131
|
"agents.mergeMeta": {
|
|
132
|
+
offLoop: true,
|
|
118
133
|
idempotent: true,
|
|
119
134
|
fn: (args: AgentsMergeMetaOpArgs, ctx: WriterOpContext): boolean =>
|
|
120
135
|
mergeAgentMeta(args.id, args.meta, args.guard, ctx.now),
|
|
121
136
|
},
|
|
122
137
|
"agents.markReadyNotified": {
|
|
138
|
+
offLoop: true,
|
|
123
139
|
idempotent: true,
|
|
124
140
|
fn: (args: AgentsMarkReadyNotifiedOpArgs, ctx: WriterOpContext): boolean =>
|
|
125
141
|
markAgentReadyNotified(args.id, ctx.now),
|
|
126
142
|
},
|
|
127
143
|
"agents.clearMetaKeys": {
|
|
144
|
+
offLoop: true,
|
|
128
145
|
idempotent: true,
|
|
129
146
|
fn: (args: AgentsClearMetaKeysOpArgs): boolean => clearAgentMetaKeys(args.id, args.keys),
|
|
130
147
|
},
|
|
@@ -135,11 +152,13 @@ export const AGENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.f
|
|
|
135
152
|
recordAgentExitDiagnosticsInternal(args.id, args.diagnostics, ctx.now, args.seq),
|
|
136
153
|
},
|
|
137
154
|
"agents.heartbeat": {
|
|
155
|
+
offLoop: true,
|
|
138
156
|
idempotent: true,
|
|
139
157
|
fn: (args: AgentsHeartbeatOpArgs, ctx: WriterOpContext): boolean =>
|
|
140
158
|
heartbeat(args.id, args.guard, args.runtime, ctx.now),
|
|
141
159
|
},
|
|
142
160
|
"agents.recordContextSnapshot": {
|
|
161
|
+
offLoop: true,
|
|
143
162
|
idempotent: true,
|
|
144
163
|
fn: (args: AgentsRecordContextSnapshotOpArgs, ctx: WriterOpContext): null => {
|
|
145
164
|
recordContextSnapshot(args.agentId, args.context, ctx.now);
|
|
@@ -147,26 +166,30 @@ export const AGENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.f
|
|
|
147
166
|
},
|
|
148
167
|
},
|
|
149
168
|
"agents.reapStale": {
|
|
169
|
+
offLoop: true,
|
|
150
170
|
idempotent: true,
|
|
151
171
|
fn: (args: AgentsReapStaleOpArgs, ctx: WriterOpContext): string[] =>
|
|
152
172
|
reapStaleAgentsInternal(args.ttlMs, args.lagGraceMs, ctx.now, args.protectedIds, args.seq),
|
|
153
173
|
},
|
|
154
174
|
"agents.pruneOffline": {
|
|
175
|
+
offLoop: true,
|
|
155
176
|
idempotent: true,
|
|
156
177
|
fn: (args: AgentsPruneOfflineOpArgs, ctx: WriterOpContext) =>
|
|
157
178
|
pruneOfflineAgentsWithFinality(args, ctx.now),
|
|
158
179
|
},
|
|
159
180
|
"agents.delete": {
|
|
181
|
+
offLoop: true,
|
|
160
182
|
idempotent: true,
|
|
161
183
|
fn: (args: AgentsDeleteOpArgs, ctx: WriterOpContext): boolean => deleteAgentInternal(args.id, ctx.now),
|
|
162
184
|
},
|
|
163
185
|
"agents.revokeOrphanedTokens": {
|
|
164
186
|
offLoop: true,
|
|
165
187
|
idempotent: true,
|
|
166
|
-
fn: (args: AgentsRevokeOrphanedTokensOpArgs, ctx: WriterOpContext):
|
|
167
|
-
revokeOrphanedRuntimeTokens(args.graceMs, args.lagGraceMs, ctx.now),
|
|
188
|
+
fn: (args: AgentsRevokeOrphanedTokensOpArgs, ctx: WriterOpContext): OrphanedTokenPage =>
|
|
189
|
+
revokeOrphanedRuntimeTokens(args.graceMs, args.lagGraceMs, ctx.now, { afterId: args.afterId, limit: args.limit }),
|
|
168
190
|
},
|
|
169
191
|
"agents.revokeTokensForAgent": {
|
|
192
|
+
offLoop: true,
|
|
170
193
|
idempotent: true,
|
|
171
194
|
fn: (args: AgentsRevokeTokensForAgentOpArgs, ctx: WriterOpContext): string[] =>
|
|
172
195
|
revokeRuntimeTokensForAgent(args.agentId, ctx.now, args.reason),
|
package/src/db/agents.ts
CHANGED
|
@@ -479,28 +479,51 @@ export function applyAgentLifecycleUpdate(
|
|
|
479
479
|
guard?: AgentSessionGuard,
|
|
480
480
|
now: number = Date.now(),
|
|
481
481
|
): AgentLifecycleUpdateResult {
|
|
482
|
-
const
|
|
483
|
-
const before =
|
|
484
|
-
if (!before) return
|
|
485
|
-
|
|
482
|
+
const seq = nextLifecycleSeq();
|
|
483
|
+
const before = prepareAgentLifecycleUpdate(id, update, guard);
|
|
484
|
+
if (!before) return { ok: false, changed: false, metaWriteBytes: 0, before: null, after: null };
|
|
485
|
+
return { ok: true, before, ...inWriteTransaction(() => applyAgentLifecycleUpdateInternal(agentLifecycleWriteArgs(before, update, seq, now))) };
|
|
486
|
+
}
|
|
486
487
|
|
|
488
|
+
/** The writer-op args for one lifecycle delta (#1870 S7). `seq` is taken at the caller's entry (lifecycle-seq.ts
|
|
489
|
+
* rule 1); `expectedEpoch` fences the write to the instance `before` was read from across the writer hop. */
|
|
490
|
+
export interface AgentLifecycleWriteArgs {
|
|
491
|
+
id: string;
|
|
492
|
+
update: AgentLifecycleUpdate;
|
|
493
|
+
seq: number;
|
|
494
|
+
now: number;
|
|
495
|
+
expectedEpoch: number;
|
|
496
|
+
before: { instanceId?: string; spawnRequestId: string; terminalProviderExit?: unknown };
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export function agentLifecycleWriteArgs(before: AgentCard, update: AgentLifecycleUpdate, seq: number, now: number): AgentLifecycleWriteArgs {
|
|
500
|
+
return { id: before.id, update, seq, now, expectedEpoch: before.epoch, before: { instanceId: before.instanceId, spawnRequestId: String(before.meta?.spawnRequestId ?? ""), terminalProviderExit: before.meta?.terminalProviderExit } };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** The main-thread half of a lifecycle delta: guard, `before` snapshot, transition handlers and presence
|
|
504
|
+
* eviction (main-thread state), all before the write is submitted. Null when the guard rejects. */
|
|
505
|
+
export function prepareAgentLifecycleUpdate(id: string, update: AgentLifecycleUpdate, guard?: AgentSessionGuard): AgentCard | null {
|
|
506
|
+
const before = getPersistedAgentRuntimeCard(id);
|
|
507
|
+
if (!before || !agentSessionGuardResult(before, guard).ok) return null;
|
|
487
508
|
const nextStatus = update.status;
|
|
488
|
-
// Pre-transition handlers
|
|
489
|
-
// and must run BEFORE the write lands, exactly as `setStatus` does.
|
|
509
|
+
// Pre-transition handlers must run BEFORE the write lands, exactly as `setStatus` does.
|
|
490
510
|
if (nextStatus !== undefined && nextStatus !== before.status) runBeforeAgentStatusTransitionHandlers(before, nextStatus);
|
|
491
511
|
// #1468 — a terminal transition evicts any buffered beat so a coalesced advance cannot later
|
|
492
512
|
// resurrect a gone agent at flush.
|
|
493
513
|
if (nextStatus === "offline" || nextStatus === "stale") evictPendingPresence(id);
|
|
514
|
+
return before;
|
|
515
|
+
}
|
|
494
516
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const seq =
|
|
517
|
+
/** Op body (`agents.applyLifecycleUpdate`): the fenced UPDATE, its effects, and the offline post-commit, in the
|
|
518
|
+
* caller's transaction. #2111 review BLOCKER 1 — each written column's ordinal is raised, so a lifecycle write
|
|
519
|
+
* the coalescing window deferred cannot commit afterwards and undo it. */
|
|
520
|
+
export function applyAgentLifecycleUpdateInternal(args: AgentLifecycleWriteArgs): Omit<AgentLifecycleUpdateResult, "ok" | "before"> {
|
|
521
|
+
const { id, update, seq, now, before } = args;
|
|
522
|
+
const nextStatus = update.status;
|
|
500
523
|
// Named params throughout: the fenced-column fragments repeat `$seq`, which positional `?` could
|
|
501
524
|
// only express by counting placeholders across a dynamically-built SET list.
|
|
502
525
|
const sets: string[] = ["last_seen = $now"];
|
|
503
|
-
const params: Record<string, unknown> = { $now: now, $seq: seq, $id: id };
|
|
526
|
+
const params: Record<string, unknown> = { $now: now, $seq: seq, $id: id, $epoch: args.expectedEpoch };
|
|
504
527
|
let metaWriteBytes = 0;
|
|
505
528
|
if (nextStatus !== undefined) {
|
|
506
529
|
sets.push(fencedColumnSql("status", "$status", "$seq"));
|
|
@@ -558,16 +581,10 @@ export function applyAgentLifecycleUpdate(
|
|
|
558
581
|
params.$qs = runtime?.quota ? JSON.stringify(runtime.quota) : null;
|
|
559
582
|
}
|
|
560
583
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const terminalLaunch = terminalProviderLaunchId(update.meta?.terminalProviderExit ?? before.meta?.terminalProviderExit);
|
|
566
|
-
if (applied && nextStatus === "offline" && terminalLaunch) revokeVaultTokens(id, now, "provider_terminal_exit", before.instanceId, String(before.meta?.spawnRequestId ?? ""), terminalLaunch);
|
|
567
|
-
if (applied && contextState) recordContextSnapshot(id, contextState, now);
|
|
568
|
-
return applied;
|
|
569
|
-
});
|
|
570
|
-
|
|
584
|
+
const changed = getDb().query(`UPDATE agents SET ${sets.join(", ")} WHERE id = $id AND epoch = $epoch`).run(params as never).changes > 0;
|
|
585
|
+
const terminalLaunch = terminalProviderLaunchId(update.meta?.terminalProviderExit ?? before.terminalProviderExit);
|
|
586
|
+
if (changed && nextStatus === "offline" && terminalLaunch) revokeVaultTokens(id, now, "provider_terminal_exit", before.instanceId, before.spawnRequestId, terminalLaunch);
|
|
587
|
+
if (changed && contextState) recordContextSnapshot(id, contextState, now);
|
|
571
588
|
// NOTE (from setStatus): `offline` is a LIVENESS observation, not a confirmed death — it re-elects
|
|
572
589
|
// stewards and closes pairs but must NOT release a steward's workspace claim (#1789 part 2, F2).
|
|
573
590
|
// Gated on the requested status, not on a status CHANGE, matching setStatus's own condition.
|
|
@@ -575,7 +592,7 @@ export function applyAgentLifecycleUpdate(
|
|
|
575
592
|
closeOpenPairsForAgent(id, now);
|
|
576
593
|
electWorkspaceStewards();
|
|
577
594
|
}
|
|
578
|
-
return {
|
|
595
|
+
return { changed, metaWriteBytes, after: getPersistedAgentRuntimeCard(id) };
|
|
579
596
|
}
|
|
580
597
|
|
|
581
598
|
export function mergeAgentMeta(id: string, meta: Record<string, unknown>, guard?: AgentSessionGuard, now: number = Date.now()): boolean {
|
|
@@ -828,21 +845,27 @@ export function heartbeat(
|
|
|
828
845
|
// withBufferedPresence / bufferedLiveAgentIds) live in the leaf module ./presence-buffer.ts so every
|
|
829
846
|
// liveness reader can fold in the buffer without an import cycle (agents.ts imports channels.ts).
|
|
830
847
|
|
|
848
|
+
/** Heartbeat: buffers the steady-state liveness advance (flushed by `flushPresence`), writes presence-critical
|
|
849
|
+
* transitions at once. False if the session guard rejects or the agent is gone. Sync twin for tests; the
|
|
850
|
+
* transports use `recordHeartbeatAsync`, which writes the bypass on the writer thread (#1870 S7). */
|
|
851
|
+
export function recordHeartbeat(id: string, opts: HeartbeatInput = {}): boolean {
|
|
852
|
+
const beat = bufferOrBypassHeartbeat(id, opts);
|
|
853
|
+
return typeof beat === "boolean" ? beat : applyAgentLifecycleUpdate(id, beat, opts.guard, opts.now ?? Date.now()).changed;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
export interface HeartbeatInput {
|
|
857
|
+
guard?: AgentSessionGuard;
|
|
858
|
+
/** Semantic status reported by the beat (bus path); undefined for the runtime-less API path. */
|
|
859
|
+
status?: AgentCard["status"];
|
|
860
|
+
runtime?: { providerCapabilities?: ProviderCapabilities; context?: ContextState; quota?: QuotaState };
|
|
861
|
+
now?: number;
|
|
862
|
+
}
|
|
863
|
+
|
|
831
864
|
/**
|
|
832
|
-
*
|
|
833
|
-
*
|
|
834
|
-
* presence-critical transitions. Returns false if the session guard rejects or the agent is gone.
|
|
865
|
+
* The shared decision of `recordHeartbeat` and `recordHeartbeatAsync`: buffer a steady-state beat (returns
|
|
866
|
+
* the result) or hand back the lifecycle delta a presence-critical beat must write now.
|
|
835
867
|
*/
|
|
836
|
-
export function
|
|
837
|
-
id: string,
|
|
838
|
-
opts: {
|
|
839
|
-
guard?: AgentSessionGuard;
|
|
840
|
-
/** Semantic status reported by the beat (bus path); undefined for the runtime-less API path. */
|
|
841
|
-
status?: AgentCard["status"];
|
|
842
|
-
runtime?: { providerCapabilities?: ProviderCapabilities; context?: ContextState; quota?: QuotaState };
|
|
843
|
-
now?: number;
|
|
844
|
-
} = {},
|
|
845
|
-
): boolean {
|
|
868
|
+
export function bufferOrBypassHeartbeat(id: string, opts: HeartbeatInput): boolean | AgentLifecycleUpdate {
|
|
846
869
|
if (!validateAgentSession(id, opts.guard).ok) return false;
|
|
847
870
|
const current = getAgent(id);
|
|
848
871
|
if (!current) return false;
|
|
@@ -861,9 +884,9 @@ export function recordHeartbeat(
|
|
|
861
884
|
opts.runtime.context.lifecycleState !== current.context?.lifecycleState;
|
|
862
885
|
const prev = pendingPresence.get(id);
|
|
863
886
|
if (resurrection || statusChanged || lifecycleTransition) {
|
|
864
|
-
// Merge any buffered-but-unflushed runtime cols into this
|
|
865
|
-
//
|
|
866
|
-
//
|
|
887
|
+
// Merge any buffered-but-unflushed runtime cols into this write so the bypass never DISCARDS a
|
|
888
|
+
// coalesced advance (a beat that carried context but was buffered, then a status change arrives
|
|
889
|
+
// carrying none). Per column: this beat wins, else the pending value.
|
|
867
890
|
const runtime = prev
|
|
868
891
|
? {
|
|
869
892
|
providerCapabilities: opts.runtime?.providerCapabilities ?? prev.providerCapabilities,
|
|
@@ -871,16 +894,10 @@ export function recordHeartbeat(
|
|
|
871
894
|
quota: opts.runtime?.quota ?? prev.quota,
|
|
872
895
|
}
|
|
873
896
|
: opts.runtime;
|
|
874
|
-
pendingPresence.delete(id); // this
|
|
875
|
-
// #2111 —
|
|
876
|
-
//
|
|
877
|
-
|
|
878
|
-
return applyAgentLifecycleUpdate(
|
|
879
|
-
id,
|
|
880
|
-
{ status: statusChanged ? opts.status : undefined, resurrectOnBeat: true, runtime },
|
|
881
|
-
opts.guard,
|
|
882
|
-
now,
|
|
883
|
-
).changed;
|
|
897
|
+
pendingPresence.delete(id); // this write supersedes any buffered advance
|
|
898
|
+
// #2111 — one consolidated update carries both the beat and the explicit status, which overrides
|
|
899
|
+
// the resurrection CASE.
|
|
900
|
+
return { status: statusChanged ? opts.status : undefined, resurrectOnBeat: true, runtime };
|
|
884
901
|
}
|
|
885
902
|
|
|
886
903
|
// Steady state: buffer. Merge context advisory markers now (matches heartbeat()'s per-beat merge),
|
|
@@ -1192,6 +1209,10 @@ export function deleteAgent(id: string): { ok: boolean; error?: string } {
|
|
|
1192
1209
|
return deleted ? { ok: true } : { ok: false, error: "agent not found" };
|
|
1193
1210
|
}
|
|
1194
1211
|
|
|
1212
|
+
export type OrphanedTokenRevocation = { agentId: string; jtis: string[] };
|
|
1213
|
+
/** One page of the orphan sweep: agents after `afterId` in id order, up to `limit` (#3776: one short write each). */
|
|
1214
|
+
export type OrphanedTokenPage = { revoked: OrphanedTokenRevocation[]; nextAfterId: string | null };
|
|
1215
|
+
|
|
1195
1216
|
// #1057(1) — close the orphan-token window #1051 left open. A dead runner with no replacement
|
|
1196
1217
|
// used to keep its token valid until the 24h offline prune (~720× the pre-#1051 ~2min horizon).
|
|
1197
1218
|
// This sweep revokes ("stale", re-mintable — #484) the runtime tokens of agents whose process the
|
|
@@ -1204,12 +1225,18 @@ export function deleteAgent(id: string): { ok: boolean; error?: string } {
|
|
|
1204
1225
|
// `lagGraceMs` mirrors the stale reaper's #1048/#1055 discipline: while the relay's own event
|
|
1205
1226
|
// loop was stalled, a live claimant's heartbeats may not have been processed yet, so the window
|
|
1206
1227
|
// widens by the observed lag rather than misreading the backlog as post-mortem silence.
|
|
1207
|
-
export function revokeOrphanedRuntimeTokens(
|
|
1228
|
+
export function revokeOrphanedRuntimeTokens(
|
|
1229
|
+
graceMs: number = STALE_TTL_MS,
|
|
1230
|
+
lagGraceMs = 0,
|
|
1231
|
+
now = Date.now(),
|
|
1232
|
+
page: { afterId?: string; limit?: number } = {},
|
|
1233
|
+
): OrphanedTokenPage {
|
|
1208
1234
|
const cutoff = now - graceMs - Math.max(0, lagGraceMs);
|
|
1235
|
+
const limit = page.limit ?? -1;
|
|
1209
1236
|
const rows = getDb()
|
|
1210
|
-
.query(`SELECT id, meta, last_seen FROM agents WHERE status = 'offline' AND meta LIKE '%lastExitReceivedAt%' AND NOT ${reservedAgentIdSql()}
|
|
1211
|
-
.all() as Array<{ id: string; meta: string | null; last_seen: number }>;
|
|
1212
|
-
const revoked:
|
|
1237
|
+
.query(`SELECT id, meta, last_seen FROM agents WHERE status = 'offline' AND meta LIKE '%lastExitReceivedAt%' AND NOT ${reservedAgentIdSql()} AND id > ? ORDER BY id LIMIT ?`)
|
|
1238
|
+
.all(page.afterId ?? "", limit) as Array<{ id: string; meta: string | null; last_seen: number }>;
|
|
1239
|
+
const revoked: OrphanedTokenRevocation[] = [];
|
|
1213
1240
|
for (const row of rows) {
|
|
1214
1241
|
const meta = parseJson<Record<string, unknown>>(row.meta ?? "{}", {});
|
|
1215
1242
|
const receivedAt = typeof meta.lastExitReceivedAt === "number" ? meta.lastExitReceivedAt : undefined;
|
|
@@ -1218,7 +1245,7 @@ export function revokeOrphanedRuntimeTokens(graceMs: number = STALE_TTL_MS, lagG
|
|
|
1218
1245
|
const jtis = revokeProviderRuntimeTokensByJti(runtimeTokenJtisFromMeta(meta), "stale", now);
|
|
1219
1246
|
if (jtis.length > 0) revoked.push({ agentId: row.id, jtis });
|
|
1220
1247
|
}
|
|
1221
|
-
return revoked;
|
|
1248
|
+
return { revoked, nextAfterId: limit > 0 && rows.length === limit ? rows[rows.length - 1]!.id : null };
|
|
1222
1249
|
}
|
|
1223
1250
|
|
|
1224
1251
|
// #484: `reason` is stamped on each revocation so a stale-on-restart revocation
|
|
@@ -13,6 +13,7 @@ import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
|
|
|
13
13
|
|
|
14
14
|
export const ARTIFACTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
15
15
|
"artifacts.upsertBlob": {
|
|
16
|
+
offLoop: true,
|
|
16
17
|
idempotent: true,
|
|
17
18
|
fn: (args: { input: Parameters<typeof upsertArtifactBlob>[0] }, ctx: WriterOpContext) =>
|
|
18
19
|
upsertArtifactBlob({ ...args.input, createdAt: args.input.createdAt ?? ctx.now }),
|
|
@@ -22,23 +23,27 @@ export const ARTIFACTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Objec
|
|
|
22
23
|
idempotent: false,
|
|
23
24
|
fn: (args: { input: Parameters<typeof createArtifact>[0] }, ctx: WriterOpContext) => createArtifact(args.input, ctx.now),
|
|
24
25
|
},
|
|
25
|
-
"artifacts.pin": { idempotent: true, fn: (args: { id: string; pinned: boolean; readScope?: import("./artifacts").ArtifactReadScope }) => setArtifactPinned(args.id, args.pinned, args.readScope) },
|
|
26
|
-
"artifacts.delete": { idempotent: true, fn: (args: { id: string }) => deleteArtifact(args.id, false) },
|
|
27
|
-
"artifacts.deleteBlob": { idempotent: true, fn: (args: { digest: string }) => deleteArtifactBlob(args.digest) },
|
|
26
|
+
"artifacts.pin": { offLoop: true, idempotent: true, fn: (args: { id: string; pinned: boolean; readScope?: import("./artifacts").ArtifactReadScope }) => setArtifactPinned(args.id, args.pinned, args.readScope) },
|
|
27
|
+
"artifacts.delete": { offLoop: true, idempotent: true, fn: (args: { id: string }) => deleteArtifact(args.id, false) },
|
|
28
|
+
"artifacts.deleteBlob": { offLoop: true, idempotent: true, fn: (args: { digest: string }) => deleteArtifactBlob(args.digest) },
|
|
28
29
|
"artifacts.link": {
|
|
30
|
+
offLoop: true,
|
|
29
31
|
idempotent: true,
|
|
30
32
|
fn: (args: { input: Parameters<typeof linkArtifact>[0] }, ctx: WriterOpContext) => linkArtifact(args.input, ctx.now),
|
|
31
33
|
},
|
|
32
34
|
"artifacts.linkExistingEntity": {
|
|
35
|
+
offLoop: true,
|
|
33
36
|
idempotent: true,
|
|
34
37
|
fn: (args: { input: Parameters<typeof linkArtifactToExistingEntity>[0] }, ctx: WriterOpContext) => linkArtifactToExistingEntity(args.input, ctx.now),
|
|
35
38
|
},
|
|
36
39
|
"artifacts.deleteLinksForEntity": {
|
|
40
|
+
offLoop: true,
|
|
37
41
|
idempotent: true,
|
|
38
42
|
fn: (args: { entityType: Parameters<typeof deleteArtifactLinksForEntity>[0]; entityId: string | number }) =>
|
|
39
43
|
deleteArtifactLinksForEntity(args.entityType, args.entityId),
|
|
40
44
|
},
|
|
41
45
|
"artifacts.sweep": {
|
|
46
|
+
offLoop: true,
|
|
42
47
|
idempotent: true,
|
|
43
48
|
fn: (args: { input?: Parameters<typeof sweepArtifacts>[0] }, ctx: WriterOpContext) =>
|
|
44
49
|
sweepArtifacts({ ...args.input, now: args.input?.now ?? ctx.now }, false),
|
|
@@ -49,6 +49,7 @@ export const BUS_OUTBOX_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Obje
|
|
|
49
49
|
// the same end state (no rows older than the threshold), so it is idempotent and needs no key. `ctx.now`
|
|
50
50
|
// is the submission-time wall-clock (H6).
|
|
51
51
|
"bus.prune": {
|
|
52
|
+
offLoop: true,
|
|
52
53
|
idempotent: true,
|
|
53
54
|
fn: (args: BusPruneOpArgs, ctx: WriterOpContext): { changes: number } => ({
|
|
54
55
|
changes: pruneOutbox(args.retentionMs, ctx.now),
|
|
@@ -14,15 +14,18 @@ import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
|
|
|
14
14
|
|
|
15
15
|
export const CHANNELS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
16
16
|
"channels.deleteBinding": {
|
|
17
|
+
offLoop: true,
|
|
17
18
|
idempotent: true,
|
|
18
19
|
fn: (args: { id: string; fence: ChannelBindingSessionFence }) => deleteChannelBindingBody(args.id, args.fence),
|
|
19
20
|
},
|
|
20
21
|
"channels.upsertBinding": {
|
|
22
|
+
offLoop: true,
|
|
21
23
|
idempotent: true,
|
|
22
24
|
fn: (args: { input: UpsertChannelBindingInput; presence?: PresenceSnapshot; fence?: ChannelBindingSessionFence }, ctx: WriterOpContext) =>
|
|
23
25
|
upsertChannelBindingBody(args.input, ctx.now, args.presence, args.fence),
|
|
24
26
|
},
|
|
25
27
|
"channels.registerAgent": {
|
|
28
|
+
offLoop: true,
|
|
26
29
|
idempotent: true,
|
|
27
30
|
fn: (args: { agentId: string; expectedEpoch: number; presence?: PresenceSnapshot }, ctx: WriterOpContext) => {
|
|
28
31
|
// Re-read under this operation's BEGIN IMMEDIATE. A card captured before an await may now be
|
|
@@ -36,6 +39,7 @@ export const CHANNELS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object
|
|
|
36
39
|
},
|
|
37
40
|
},
|
|
38
41
|
"channels.evaluatePoolBindings": {
|
|
42
|
+
offLoop: true,
|
|
39
43
|
idempotent: true,
|
|
40
44
|
fn: (args: { presence?: PresenceSnapshot }, ctx: WriterOpContext) => evaluatePoolBindingsBody(ctx.now, args.presence),
|
|
41
45
|
},
|
|
@@ -35,15 +35,15 @@ const write = <T>(op: string, args: unknown, idempotencyKey?: string): Promise<T
|
|
|
35
35
|
export function upsertWatchStateAsync(input: Parameters<typeof upsertWatchState>[0]): Promise<ReturnType<typeof upsertWatchState>> {
|
|
36
36
|
return write("ciIncidents.watch.upsert", input);
|
|
37
37
|
}
|
|
38
|
-
/** One gateway writer transaction for the complete watch + incident lifecycle decision. */
|
|
39
|
-
export function ingestCiObservationTransitionAsync(input: CiObservationTransitionInput): Promise<CiObservationTransitionResult> {
|
|
40
|
-
return write("ciIncidents.observation.ingest", input);
|
|
38
|
+
/** One gateway writer transaction for the complete watch + incident lifecycle decision. `now` pins a test clock. */
|
|
39
|
+
export function ingestCiObservationTransitionAsync(input: CiObservationTransitionInput, now?: number): Promise<CiObservationTransitionResult> {
|
|
40
|
+
return write("ciIncidents.observation.ingest", now === undefined ? input : { ...input, now });
|
|
41
41
|
}
|
|
42
42
|
export function markCiWatchNeverMatchedNotifiedAsync(watchKey: string): Promise<ReturnType<typeof markCiWatchNeverMatchedNotified>> {
|
|
43
43
|
return write("ciIncidents.watch.markNeverMatched", { watchKey });
|
|
44
44
|
}
|
|
45
|
-
export function markCiRootMissingNotifiedAsync(repository: string): Promise<ReturnType<typeof markCiRootMissingNotified>> {
|
|
46
|
-
return write("ciIncidents.root.markMissing", { repository });
|
|
45
|
+
export function markCiRootMissingNotifiedAsync(repository: string, now?: number): Promise<ReturnType<typeof markCiRootMissingNotified>> {
|
|
46
|
+
return write("ciIncidents.root.markMissing", now === undefined ? { repository } : { repository, now });
|
|
47
47
|
}
|
|
48
48
|
export function openOrDedupeIncidentAsync(input: Parameters<typeof openOrDedupeIncident>[0]): Promise<ReturnType<typeof openOrDedupeIncident>> {
|
|
49
49
|
return write("ciIncidents.openOrDedupe", input);
|
|
@@ -27,7 +27,7 @@ export const CI_INCIDENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Ob
|
|
|
27
27
|
"ciIncidents.observation.ingest": {
|
|
28
28
|
offLoop: true,
|
|
29
29
|
idempotent: true,
|
|
30
|
-
fn: (a: Parameters<typeof applyCiObservationTransitionInternal>[0], ctx) => applyCiObservationTransitionInternal(a, ctx.now),
|
|
30
|
+
fn: (a: Parameters<typeof applyCiObservationTransitionInternal>[0] & { now?: number }, ctx) => applyCiObservationTransitionInternal(a, a.now ?? ctx.now),
|
|
31
31
|
},
|
|
32
32
|
"ciIncidents.gateRun.record": { offLoop: true, idempotent: true, fn: (a: Parameters<typeof recordCiGateRuns>[0]) => recordCiGateRuns(a) },
|
|
33
33
|
"ciIncidents.gateBackfill.start": { offLoop: true, idempotent: true, fn: (a: Parameters<typeof startCiGateBackfill>[0]) => startCiGateBackfill(a) },
|
|
@@ -36,7 +36,7 @@ export const CI_INCIDENTS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Ob
|
|
|
36
36
|
"ciIncidents.sha.prune": { offLoop: true, idempotent: true, fn: (_a: { now: number }, ctx) => pruneCiShaObservations(ctx.now) },
|
|
37
37
|
"ciIncidents.watch.upsert": { offLoop: true, idempotent: true, fn: (a: Parameters<typeof upsertWatchState>[0], ctx) => upsertWatchState(a, ctx.now) },
|
|
38
38
|
"ciIncidents.watch.markNeverMatched": { offLoop: true, idempotent: true, fn: (a: { watchKey: string }, ctx) => markCiWatchNeverMatchedNotified(a.watchKey, ctx.now) },
|
|
39
|
-
"ciIncidents.root.markMissing": { offLoop: true, idempotent: true, fn: (a: { repository: string }, ctx) => markCiRootMissingNotified(a.repository, ctx.now) },
|
|
39
|
+
"ciIncidents.root.markMissing": { offLoop: true, idempotent: true, fn: (a: { repository: string; now?: number }, ctx) => markCiRootMissingNotified(a.repository, a.now ?? ctx.now) },
|
|
40
40
|
"ciIncidents.openOrDedupe": { offLoop: true, idempotent: true, fn: (a: Parameters<typeof openOrDedupeIncidentInternal>[0], ctx) => openOrDedupeIncidentInternal(a, ctx.now, false) },
|
|
41
41
|
// Guarded transitions throw after they have advanced; use the durable retry ledger rather than
|
|
42
42
|
// misclassifying that as safe replay. Distinct steward attempts carry distinct request ids.
|
|
@@ -7,9 +7,9 @@ export const CLAUDE_API_BUDGET_READ_OPS = {
|
|
|
7
7
|
"apiBudget.status": (args: { now: number; budgetId?: ApiBudgetId }) => apiBudgetStatus(args.now, args.budgetId),
|
|
8
8
|
};
|
|
9
9
|
export const CLAUDE_API_BUDGET_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = {
|
|
10
|
-
"apiBudget.reconcile": { idempotent: true, fn: (args: { now: number }) => reconcileApiBudgetSessions(args.now) },
|
|
11
|
-
"apiBudget.pace": { idempotent: true, fn: (args: { leadTimeMs: number; now: number; budgetId?: ApiBudgetId }) => apiBudgetPace(args.leadTimeMs, args.now, args.budgetId) },
|
|
12
|
-
"apiBudget.configure": { idempotent: true, fn: (args: { input: ApiBudgetConfig; now: number }) => configureApiBudget(args.input, args.now) },
|
|
13
|
-
"apiBudget.reserve": { idempotent: true, fn: (args: { input: ApiBudgetReserve; now: number }) => reserveApiBudget(args.input, args.now) },
|
|
14
|
-
"apiBudget.report": { idempotent: true, fn: (args: { input: ApiBudgetReport; now: number }) => reportApiBudget(args.input, args.now) },
|
|
10
|
+
"apiBudget.reconcile": { offLoop: true, idempotent: true, fn: (args: { now: number }) => reconcileApiBudgetSessions(args.now) },
|
|
11
|
+
"apiBudget.pace": { offLoop: true, idempotent: true, fn: (args: { leadTimeMs: number; now: number; budgetId?: ApiBudgetId }) => apiBudgetPace(args.leadTimeMs, args.now, args.budgetId) },
|
|
12
|
+
"apiBudget.configure": { offLoop: true, idempotent: true, fn: (args: { input: ApiBudgetConfig; now: number }) => configureApiBudget(args.input, args.now) },
|
|
13
|
+
"apiBudget.reserve": { offLoop: true, idempotent: true, fn: (args: { input: ApiBudgetReserve; now: number }) => reserveApiBudget(args.input, args.now) },
|
|
14
|
+
"apiBudget.report": { offLoop: true, idempotent: true, fn: (args: { input: ApiBudgetReport; now: number }) => reportApiBudget(args.input, args.now) },
|
|
15
15
|
};
|
|
@@ -44,13 +44,13 @@ function put(args: Put): boolean {
|
|
|
44
44
|
|
|
45
45
|
export const CLAUDE_APP_OAUTH_READ_OPS = { "claudeAppOAuth.get": get };
|
|
46
46
|
export const CLAUDE_APP_OAUTH_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = {
|
|
47
|
-
"claudeAppOAuth.put": { idempotent: false, fn: put },
|
|
48
|
-
"claudeAppOAuth.take": { idempotent: false, fn: (args: Key) => {
|
|
47
|
+
"claudeAppOAuth.put": { offLoop: true, idempotent: false, fn: put },
|
|
48
|
+
"claudeAppOAuth.take": { offLoop: true, idempotent: false, fn: (args: Key) => {
|
|
49
49
|
const value = get(args);
|
|
50
50
|
getDb().query("DELETE FROM claude_app_oauth WHERE resource=? AND kind=? AND key=?").run(args.resource, args.kind, args.key);
|
|
51
51
|
return value;
|
|
52
52
|
} },
|
|
53
|
-
"claudeAppOAuth.issue": { idempotent: false, fn: (args: Put & { refreshKey?: string; clientId: string }) => {
|
|
53
|
+
"claudeAppOAuth.issue": { offLoop: true, idempotent: false, fn: (args: Put & { refreshKey?: string; clientId: string }) => {
|
|
54
54
|
// Consume and replace in the same writer transaction; concurrent refreshes cannot resurrect a revoked family.
|
|
55
55
|
let old: { clientId: string; family: string; type: string; used?: boolean } | undefined;
|
|
56
56
|
if (args.refreshKey) {
|
|
@@ -65,7 +65,7 @@ export const CLAUDE_APP_OAUTH_WRITE_OPS: Readonly<Record<string, WriterOpSpec>>
|
|
|
65
65
|
.run(JSON.stringify({ ...old, used: true }), args.resource, args.kind, args.refreshKey!);
|
|
66
66
|
return "ok";
|
|
67
67
|
} },
|
|
68
|
-
"claudeAppOAuth.revoke": { idempotent: true, fn: (args: Key & { clientId: string }) => {
|
|
68
|
+
"claudeAppOAuth.revoke": { offLoop: true, idempotent: true, fn: (args: Key & { clientId: string }) => {
|
|
69
69
|
const value = get(args);
|
|
70
70
|
const credential = value ? JSON.parse(value) as { clientId: string; family: string } : null;
|
|
71
71
|
if (credential?.clientId === args.clientId) removeFamily(args.resource, credential.family);
|
|
@@ -3,16 +3,19 @@ import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
|
|
|
3
3
|
|
|
4
4
|
export const CODEX_RESET_CONSUMES_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
5
5
|
"codexResetConsumes.begin": {
|
|
6
|
+
offLoop: true,
|
|
6
7
|
idempotent: true,
|
|
7
8
|
fn: (args: { input: Parameters<typeof beginCodexResetConsume>[0] }, ctx: WriterOpContext) =>
|
|
8
9
|
beginCodexResetConsume({ ...args.input, now: args.input.now ?? ctx.now }),
|
|
9
10
|
},
|
|
10
11
|
"codexResetConsumes.complete": {
|
|
12
|
+
offLoop: true,
|
|
11
13
|
idempotent: true,
|
|
12
14
|
fn: (args: { input: Parameters<typeof completeCodexResetConsume>[0] }, ctx: WriterOpContext) =>
|
|
13
15
|
completeCodexResetConsume({ ...args.input, now: args.input.now ?? ctx.now }),
|
|
14
16
|
},
|
|
15
17
|
"codexResetConsumes.prune": {
|
|
18
|
+
offLoop: true,
|
|
16
19
|
idempotent: true,
|
|
17
20
|
fn: (args: { olderThan?: number }, ctx: WriterOpContext) => pruneCodexResetConsumes(args.olderThan ?? ctx.now),
|
|
18
21
|
},
|
package/src/db/command-row.ts
CHANGED
|
@@ -41,13 +41,15 @@ export interface CommandRow {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
/** `slim` (#3391): listings omit `params.agentProfile` (~0.5 MB per spawn row) instead of hydrating it;
|
|
45
|
+
* `GET /api/commands/:id` returns the full row. */
|
|
46
|
+
export function rowToCommand(row: CommandRow, options: { slim?: boolean } = {}): Command {
|
|
45
47
|
return {
|
|
46
48
|
id: row.id,
|
|
47
49
|
type: row.type,
|
|
48
50
|
source: row.source,
|
|
49
51
|
target: row.target,
|
|
50
|
-
params: hydrateCommandAgentProfile(parseObject(row.params), row.agent_profile_hash),
|
|
52
|
+
params: options.slim ? withoutAgentProfile(parseObject(row.params)) : hydrateCommandAgentProfile(parseObject(row.params), row.agent_profile_hash),
|
|
51
53
|
status: row.status,
|
|
52
54
|
result: row.result ? parseObject(row.result) : undefined,
|
|
53
55
|
error: row.error ?? undefined,
|
|
@@ -78,6 +80,12 @@ export function rowToCommand(row: CommandRow): Command {
|
|
|
78
80
|
};
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
function withoutAgentProfile(params: Record<string, unknown>): Record<string, unknown> {
|
|
84
|
+
if (!("agentProfile" in params)) return params;
|
|
85
|
+
const { agentProfile: _omitted, ...rest } = params;
|
|
86
|
+
return rest;
|
|
87
|
+
}
|
|
88
|
+
|
|
81
89
|
function parseObject(raw: string): Record<string, unknown> {
|
|
82
90
|
try {
|
|
83
91
|
const parsed = JSON.parse(raw);
|
|
@@ -9,6 +9,8 @@ export interface CommandFilters {
|
|
|
9
9
|
dispatchableOnly?: boolean;
|
|
10
10
|
/** #2663 — oldest-first for the executor DISPATCH feed, whose window is capped. See `getCommands`. */
|
|
11
11
|
oldestFirst?: boolean;
|
|
12
|
+
/** #3391 — omit `params.agentProfile` from rows (listing views; fetch the row by id for the profile). */
|
|
13
|
+
slim?: boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export function buildListCommandsQuery(filters: CommandFilters = {}): { sql: string; params: unknown[] } {
|
|
@@ -29,5 +29,5 @@ export const IN_FLIGHT_SPAWNS_BY_PARENT_SQL = `SELECT * FROM commands INDEXED BY
|
|
|
29
29
|
/** One parent's agent.spawn commands still in flight, newest first. */
|
|
30
30
|
export function listInFlightSpawnCommands(parentId: string, limit = 500): Command[] {
|
|
31
31
|
const rows = getDb().query(IN_FLIGHT_SPAWNS_BY_PARENT_SQL).all(...SPAWN_IN_FLIGHT_STATUSES, parentId, limit) as CommandRow[];
|
|
32
|
-
return rows.map(rowToCommand);
|
|
32
|
+
return rows.map((row) => rowToCommand(row));
|
|
33
33
|
}
|