@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { stewardFallbackTarget } from "../config.ts";
|
|
2
2
|
import { emitRelayEvent } from "../events.ts";
|
|
3
3
|
import type { WorkspaceHumanEscalationResult } from "../workspace-human-escalation.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { ingestCiObservationAsync, type CiIncidentIngestResult } from "./incidents.ts";
|
|
5
5
|
import {
|
|
6
6
|
routeCiIncidentNotification,
|
|
7
7
|
type CiFailedNotificationPayload,
|
|
@@ -41,7 +41,7 @@ import type { CiObservation, CiRunRef } from "./provider.ts";
|
|
|
41
41
|
export const CI_MAIN_WATCH_COORDINATOR = "cd-watcher";
|
|
42
42
|
|
|
43
43
|
export interface CiTransitionNotifyDeps {
|
|
44
|
-
ingest?: (observation: CiObservation, now?: number) => CiIncidentIngestResult
|
|
44
|
+
ingest?: (observation: CiObservation, now?: number) => CiIncidentIngestResult | Promise<CiIncidentIngestResult>;
|
|
45
45
|
route?: (input: Parameters<typeof routeCiIncidentNotification>[0]) => RouteCiIncidentNotificationResult;
|
|
46
46
|
/** Resolve the coordinator/owner agent the relay message addresses. Defaults to the configured
|
|
47
47
|
* steward fallback, then the system watch actor. */
|
|
@@ -65,16 +65,17 @@ export interface CiTransitionNotifyResult {
|
|
|
65
65
|
* Detect and (if a flip occurred) alert on a CI red/green transition for a single observed watch.
|
|
66
66
|
* Idempotent per transition — safe to call every poll tick.
|
|
67
67
|
*/
|
|
68
|
-
export function notifyCiTransition(
|
|
68
|
+
export async function notifyCiTransition(
|
|
69
69
|
observation: CiObservation | null | undefined,
|
|
70
70
|
deps: CiTransitionNotifyDeps = {},
|
|
71
|
-
): CiTransitionNotifyResult {
|
|
71
|
+
): Promise<CiTransitionNotifyResult> {
|
|
72
72
|
if (!observation) return { transition: "none", notified: false, messages: 0 };
|
|
73
|
-
const ingest = deps.ingest ??
|
|
73
|
+
const ingest = deps.ingest ?? ingestCiObservationAsync;
|
|
74
74
|
const route = deps.route ?? routeCiIncidentNotification;
|
|
75
75
|
const now = deps.now ?? Date.now();
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
// Notification emission follows the committed transition (one writer op, #1870), never a pre-write observation.
|
|
78
|
+
const result = await ingest(observation, deps.now);
|
|
78
79
|
emitCiStatus(result);
|
|
79
80
|
|
|
80
81
|
if (result.kind === "opened") {
|
|
@@ -155,39 +156,6 @@ export function notifyCiTransition(
|
|
|
155
156
|
return { transition: "none", ...(result.kind === "deduped" ? { incidentId: result.incident.id } : {}), notified: false, messages: 0 };
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
/** Gateway-routed companion for async maintenance polling. Notification emission follows the
|
|
159
|
-
* committed transition, never a pre-write observation. */
|
|
160
|
-
export async function notifyCiTransitionAsync(
|
|
161
|
-
observation: CiObservation | null | undefined,
|
|
162
|
-
deps: Omit<CiTransitionNotifyDeps, "ingest"> = {},
|
|
163
|
-
): Promise<CiTransitionNotifyResult> {
|
|
164
|
-
if (!observation) return { transition: "none", notified: false, messages: 0 };
|
|
165
|
-
const route = deps.route ?? routeCiIncidentNotification;
|
|
166
|
-
const now = deps.now ?? Date.now();
|
|
167
|
-
const result = await ingestCiObservationAsync(observation);
|
|
168
|
-
emitCiStatus(result);
|
|
169
|
-
if (result.kind === "opened") {
|
|
170
|
-
const coordinatorAgentId = resolveCoordinator(deps);
|
|
171
|
-
const routed = route({ type: "ci.failed", payload: { incidentId: result.incident.id, provider: observation.provider, repository: observation.repository, branch: observation.branch, workflow: observation.workflow, failingHeadSha: observation.headSha, coordinatorAgentId, observedAt: observation.observedAt, ...(observation.conclusion ? { conclusion: observation.conclusion } : {}), failingRunIds: observation.failingRuns.map((run) => run.id), failingJobNames: failingJobNames(observation) }, alertHuman: true, subject: redSubject(observation), body: redBody(observation, result.incident.id) });
|
|
172
|
-
return { transition: "went_red", incidentId: result.incident.id, notified: true, messages: routed.messages.length, ...(routed.humanFallback ? { humanFallback: routed.humanFallback } : {}) };
|
|
173
|
-
}
|
|
174
|
-
if (result.kind === "resolved") {
|
|
175
|
-
const coordinatorAgentId = resolveCoordinator(deps);
|
|
176
|
-
const routed = route({ type: "ci.recovered", payload: { incidentId: result.incident.id, provider: observation.provider, repository: observation.repository, branch: observation.branch, workflow: observation.workflow, failingHeadSha: result.incident.openedHeadSha, coordinatorAgentId, recoveredAt: now, greenHeadSha: observation.headSha, ...(result.incident.resolution ? { resolution: result.incident.resolution } : {}) }, alertHuman: true, subject: greenSubject(observation), body: greenBody(observation, result.incident.id, result.incident.openedHeadSha) });
|
|
177
|
-
return { transition: "back_green", incidentId: result.incident.id, notified: true, messages: routed.messages.length, ...(routed.humanFallback ? { humanFallback: routed.humanFallback } : {}) };
|
|
178
|
-
}
|
|
179
|
-
if (result.kind === "never_matched") {
|
|
180
|
-
const coordinatorAgentId = resolveCoordinator(deps);
|
|
181
|
-
const routed = route({ type: "ci.never_matched", payload: { provider: observation.provider, repository: observation.repository, branch: observation.branch, workflow: observation.workflow, coordinatorAgentId, firstSeenAt: result.firstSeenAt, observedAt: observation.observedAt }, alertHuman: true, subject: neverMatchedSubject(observation), body: neverMatchedBody(observation) });
|
|
182
|
-
return { transition: "never_matched", notified: true, messages: routed.messages.length, ...(routed.humanFallback ? { humanFallback: routed.humanFallback } : {}) };
|
|
183
|
-
}
|
|
184
|
-
if (result.kind === "config_mismatch") {
|
|
185
|
-
const routed = route(configMismatchRoute(observation, resolveCoordinator(deps), result.unmatchedJobs));
|
|
186
|
-
return { transition: "config_mismatch", notified: true, messages: routed.messages.length, ...(routed.humanFallback ? { humanFallback: routed.humanFallback } : {}) };
|
|
187
|
-
}
|
|
188
|
-
return { transition: "none", ...(result.kind === "deduped" ? { incidentId: result.incident.id } : {}), notified: false, messages: 0 };
|
|
189
|
-
}
|
|
190
|
-
|
|
191
159
|
/** Live CI view (#3011): one `ci.status` event per watch status transition, never per poll. */
|
|
192
160
|
function emitCiStatus(result: CiIncidentIngestResult): void {
|
|
193
161
|
if (result.statusChange) emitRelayEvent({ type: "ci.status", source: "server", subject: result.watchKey, data: { ...result.statusChange } });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CdPause, CdPauseControl } from "../state-adoption/cd-cutover";
|
|
2
|
+
import { apiRequest, ApiRequestError } from "./_shared";
|
|
3
|
+
|
|
4
|
+
/** The audited maintenance pause API (#1645) shared by local and fleet cutovers (#3470). */
|
|
5
|
+
export const cdWatcherPauses: CdPauseControl = {
|
|
6
|
+
async pause(holder, reason) {
|
|
7
|
+
try {
|
|
8
|
+
return ((await apiRequest("POST", "/api/maintenance/jobs/cd-watcher/pause", { holder, reason, indefinite: true })) as { pause: CdPause }).pause;
|
|
9
|
+
} catch (error) {
|
|
10
|
+
if (error instanceof ApiRequestError && error.status === 409) return (error.responseBody as { pause: CdPause }).pause;
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
async current() {
|
|
15
|
+
const { pauses } = (await apiRequest("GET", "/api/maintenance/pauses")) as { pauses: Array<CdPause & { jobId: string }> };
|
|
16
|
+
return pauses.find((pause) => pause.jobId === "cd-watcher") ?? null;
|
|
17
|
+
},
|
|
18
|
+
async resume() { await apiRequest("POST", "/api/maintenance/jobs/cd-watcher/resume"); },
|
|
19
|
+
};
|
package/src/cli/orchestrator.ts
CHANGED
|
@@ -118,7 +118,7 @@ export async function handleOrchestratorCommand(args: string[]): Promise<void> {
|
|
|
118
118
|
// Install the server package too so a real `humwick` bin lands in the
|
|
119
119
|
// runtime .bin dir (#1421): under bunx there is no global install, so without
|
|
120
120
|
// this the darwin shim below would point at a bin that does not exist.
|
|
121
|
-
const packageCommand = skipInstall ? [] : ["npm", "install", "--prefix", runtimePrefix,
|
|
121
|
+
const packageCommand = skipInstall ? [] : ["npm", "install", "--prefix", runtimePrefix, `@humwick/runner@${version}`, `@humwick/orchestrator@${version}`, `@humwick/server@${version}`, OPENCODE_HARNESS_PACKAGE];
|
|
122
122
|
// W1: on macOS, put `humwick` on the interactive PATH (shim + profile
|
|
123
123
|
// block). Gated to darwin — Linux global-npm installs already get the shim via
|
|
124
124
|
// the postinstall, and we avoid editing Linux user profiles unnecessarily.
|
package/src/cli/state.ts
CHANGED
|
@@ -2,8 +2,7 @@ import { readFileSync } from "node:fs";
|
|
|
2
2
|
import { adoptMacos } from "../state-adoption/macos";
|
|
3
3
|
import { adoptLinux } from "../state-adoption/linux";
|
|
4
4
|
import { adoptState } from "../state-adoption";
|
|
5
|
-
import
|
|
6
|
-
import { apiRequest, ApiRequestError } from "./_shared";
|
|
5
|
+
import { cdWatcherPauses } from "./cd-pauses";
|
|
7
6
|
|
|
8
7
|
export const STATE_USAGE = "humwick state adopt|linux-adopt|macos-adopt|cd-cutover|cd-resume --manifest PATH [--interrupt-after STEP] [--rollback] [--systemctl PATH] [--launchctl PATH]";
|
|
9
8
|
const COMMANDS = ["adopt", "linux-adopt", "macos-adopt", "cd-cutover", "cd-resume"];
|
|
@@ -43,6 +42,7 @@ export async function handleStateCommand(args: string[]): Promise<void> {
|
|
|
43
42
|
async function cdCutover(command: string, input: any, options: { rollback: boolean; systemctl?: string; launchctl?: string; interrupt: (step: string) => void }) {
|
|
44
43
|
const { runCutover, resumeCutoverCd } = await import("../state-adoption/cd-cutover");
|
|
45
44
|
if (command === "cd-resume") return resumeCutoverCd(input, cdWatcherPauses);
|
|
45
|
+
if (input?.fleet) throw new Error("Fleet activation uses bun run release --deploy-only --cutover-manifest PATH under the existing executor");
|
|
46
46
|
const [{ resolveCanonicalRelayDbPath, withDeployLedgerDb }, { resolveReleaseLocalOrchestratorId }] = await Promise.all([
|
|
47
47
|
import("../../scripts/cd-config"), import("../../scripts/release-upgrade")]);
|
|
48
48
|
const dbPath = resolveCanonicalRelayDbPath();
|
|
@@ -54,20 +54,3 @@ async function cdCutover(command: string, input: any, options: { rollback: boole
|
|
|
54
54
|
: adoptLinux(input.handoff, { rollback, systemctl: options.systemctl, interrupt: options.interrupt }),
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
/** The audited maintenance pause API (#1645) for cd-watcher; an existing pause is returned, ours or not. */
|
|
59
|
-
const cdWatcherPauses: CdPauseControl = {
|
|
60
|
-
async pause(holder, reason) {
|
|
61
|
-
try {
|
|
62
|
-
return ((await apiRequest("POST", "/api/maintenance/jobs/cd-watcher/pause", { holder, reason, indefinite: true })) as { pause: CdPause }).pause;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
if (error instanceof ApiRequestError && error.status === 409) return (error.responseBody as { pause: CdPause }).pause;
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
async current() {
|
|
69
|
-
const { pauses } = (await apiRequest("GET", "/api/maintenance/pauses")) as { pauses: Array<CdPause & { jobId: string }> };
|
|
70
|
-
return pauses.find((pause) => pause.jobId === "cd-watcher") ?? null;
|
|
71
|
-
},
|
|
72
|
-
async resume() { await apiRequest("POST", "/api/maintenance/jobs/cd-watcher/resume"); },
|
|
73
|
-
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { parseTaskIdValue } from "../validation";
|
|
2
|
+
import { apiRequest } from "./_shared";
|
|
3
|
+
|
|
4
|
+
const fields: Record<string, string> = { "--title": "title", "--intent": "intent", "--done-when": "doneWhen", "--on-deploy": "onDeploy", "--team": "teamId", "--repo": "repo" };
|
|
5
|
+
|
|
6
|
+
export async function editTaskCommand(args: string[]): Promise<void> {
|
|
7
|
+
const create = args[0] === "create";
|
|
8
|
+
const id = create ? undefined : parseTaskIdValue(args[1] ?? "");
|
|
9
|
+
if (!create && !id) throw new Error("taskId must be a positive integer (TNNNN accepted)");
|
|
10
|
+
const body: Record<string, string> = {};
|
|
11
|
+
for (let i = create ? 1 : 2; i < args.length; i++) {
|
|
12
|
+
const flag = args[i]!;
|
|
13
|
+
if (flag === "--json") continue;
|
|
14
|
+
const field = fields[flag];
|
|
15
|
+
if (!field || i + 1 >= args.length) throw new Error(`Unknown or missing task ${args[0]} option: ${flag}`);
|
|
16
|
+
body[field] = args[++i]!;
|
|
17
|
+
}
|
|
18
|
+
if (create && (!body.title || !body.intent)) throw new Error("task create requires --title and --intent");
|
|
19
|
+
if (!Object.keys(body).length) throw new Error("task update requires a field such as --on-deploy");
|
|
20
|
+
const result = await apiRequest(create ? "POST" : "PATCH", create ? "/api/tasks" : `/api/tasks/${id}`, body);
|
|
21
|
+
console.log(JSON.stringify(result, null, 2));
|
|
22
|
+
}
|
package/src/cli/task.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { editTaskCommand } from "./task-edit";
|
|
1
2
|
// Task commands — #2518 review-hold control (`humwick task review-hold …`) + #2312
|
|
2
3
|
// withdraw-land (`humwick task withdraw-land …`). Thin HTTP clients (same apiRequest seam
|
|
3
4
|
// as workspace.ts): all policy — coordinator-only authorization, the expected-HEAD CAS,
|
|
@@ -11,7 +12,7 @@ function parseTaskId(raw: string | undefined): number | null {
|
|
|
11
12
|
return raw === undefined ? null : parseTaskIdValue(raw);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export const TASK_USAGE = "Usage: humwick task get <taskId> [--verbose] [--json] | humwick task review-hold <taskId> <status|set|clear> [--expected-head SHA] [--reason TEXT] [--json] | humwick task withdraw-land <workspaceId> [--reason TEXT] [--json]";
|
|
15
|
+
export const TASK_USAGE = "Usage: humwick task create --title TEXT --intent TEXT [--on-deploy TEXT] | humwick task update <taskId> [--on-deploy TEXT] | humwick task get <taskId> [--verbose] [--json] | humwick task review-hold <taskId> <status|set|clear> [--expected-head SHA] [--reason TEXT] [--json] | humwick task withdraw-land <workspaceId> [--reason TEXT] [--json]";
|
|
15
16
|
|
|
16
17
|
interface ReviewHoldStatusView {
|
|
17
18
|
id: number;
|
|
@@ -48,6 +49,7 @@ function renderStatus(task: ReviewHoldStatusView): string {
|
|
|
48
49
|
|
|
49
50
|
export async function handleTaskCommand(args: string[]): Promise<void> {
|
|
50
51
|
const sub = args[0];
|
|
52
|
+
if (sub === "create" || sub === "update") return editTaskCommand(args);
|
|
51
53
|
if (sub === "get") {
|
|
52
54
|
const taskId = parseTaskId(args[1]);
|
|
53
55
|
if (taskId === null) throw new Error(`taskId must be a positive integer (TNNNN accepted). ${TASK_USAGE}`);
|
package/src/cli/workflow.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { apiRequest } from "./_shared";
|
|
2
2
|
import { probeWorkflowDeployment } from "../../scripts/wait-for-deploy";
|
|
3
3
|
|
|
4
|
-
export const WORKFLOW_USAGE = "Usage: humwick workflow start <workflow> <taskId> [--json] | workflow get <runId> [--verbose] [--include-held] [--results-ref <id>] [--results-cursor <cursor>] [--json] | workflow resume <runId> [--activation <id>]";
|
|
4
|
+
export const WORKFLOW_USAGE = "Usage: humwick workflow start <workflow> <taskId> [--json] | workflow get <runId> [--verbose] [--include-held] [--results-ref <id>] [--results-cursor <cursor>] [--json] | workflow resume <runId> [--activation <id>] | workflow pause <runId> --reason <text> | workflow unpause <runId>";
|
|
5
5
|
|
|
6
6
|
export async function handleWorkflowCommand(args: string[]): Promise<void> {
|
|
7
7
|
const [command, runId, ...flags] = args;
|
|
@@ -25,7 +25,13 @@ export async function handleWorkflowCommand(args: string[]): Promise<void> {
|
|
|
25
25
|
}
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
if (!["get", "resume"].includes(command ?? "") || !runId || runId.startsWith("--")) throw new Error(WORKFLOW_USAGE);
|
|
28
|
+
if (!["get", "resume", "pause", "unpause"].includes(command ?? "") || !runId || runId.startsWith("--")) throw new Error(WORKFLOW_USAGE);
|
|
29
|
+
if (command === "pause" || command === "unpause") {
|
|
30
|
+
// #3757 — a pause says why the run waits; the server refuses an empty reason.
|
|
31
|
+
if (command === "pause" ? flags.length !== 2 || flags[0] !== "--reason" || !flags[1]?.trim() : flags.length) throw new Error(WORKFLOW_USAGE);
|
|
32
|
+
console.log(JSON.stringify(await apiRequest("POST", `/api/workflows/runs/${encodeURIComponent(runId)}/${command}`, command === "pause" ? { reason: flags[1] } : {}), null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
29
35
|
if (command === "resume") {
|
|
30
36
|
if (flags.length && (flags[0] !== "--activation" || flags.length !== 2 || !flags[1])) throw new Error(WORKFLOW_USAGE);
|
|
31
37
|
console.log(JSON.stringify(await apiRequest("POST", `/api/workflows/runs/${encodeURIComponent(runId)}/resume`, { ...(flags[1] ? { activationId: flags[1] } : {}) }), null, 2));
|
package/src/commands-db.ts
CHANGED
|
@@ -305,7 +305,7 @@ export { buildListCommandsQuery } from "./db/commands-list-query";
|
|
|
305
305
|
|
|
306
306
|
export function listCommands(filters: CommandFilters = {}): Command[] {
|
|
307
307
|
const { sql, params } = buildListCommandsQuery(filters);
|
|
308
|
-
return (getDb().query(sql).all(...params as any[]) as CommandRow[]).map(rowToCommand);
|
|
308
|
+
return (getDb().query(sql).all(...params as any[]) as CommandRow[]).map((row) => rowToCommand(row, { slim: filters.slim }));
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
|
|
@@ -814,8 +814,8 @@ export function updateCommand(id: string, input: UpdateCommandInput, opts: Updat
|
|
|
814
814
|
return applyCommandUpdatePostCommit(result.previousStatus, result.command);
|
|
815
815
|
}
|
|
816
816
|
|
|
817
|
-
|
|
818
|
-
|
|
817
|
+
/** Whether the public DELETE may cancel this command. Shared by the sync and async delete paths. */
|
|
818
|
+
export function commandDeletable(existing: Command | null): existing is Command {
|
|
819
819
|
if (!existing) return false;
|
|
820
820
|
if (existing.type === "workspace.merge" && !isLegacyUnfencedWorkspaceMerge(existing)) return false;
|
|
821
821
|
if (!["pending", "accepted"].includes(existing.status)) return false;
|
|
@@ -823,7 +823,11 @@ export function deleteCommand(id: string): boolean {
|
|
|
823
823
|
// cancelable (see updateCommand's post-claim-cancel guard). Report "cannot cancel" honestly rather
|
|
824
824
|
// than a false success: without this the updateCommand guard would no-op the cancel yet we'd still
|
|
825
825
|
// return true, telling the caller a claimed push was canceled when it was not.
|
|
826
|
-
|
|
826
|
+
return !(existing.status === "accepted" && isClaimGatedReviewCommand(existing.type));
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
export function deleteCommand(id: string): boolean {
|
|
830
|
+
if (!commandDeletable(getCommand(id))) return false;
|
|
827
831
|
updateCommand(id, { status: "canceled", error: "canceled" });
|
|
828
832
|
return true;
|
|
829
833
|
}
|
|
@@ -916,7 +920,7 @@ export const ACCEPTED_BY_OWNER_SQL = `SELECT * FROM commands INDEXED BY idx_comm
|
|
|
916
920
|
export function listAcceptedCommandsByOwner(target: string, ownerToken: string): Command[] {
|
|
917
921
|
if (!target || !ownerToken) return [];
|
|
918
922
|
const rows = getDb().query(ACCEPTED_BY_OWNER_SQL).all(target, ownerToken, Date.now()) as CommandRow[];
|
|
919
|
-
return rows.map(rowToCommand);
|
|
923
|
+
return rows.map((row) => rowToCommand(row));
|
|
920
924
|
}
|
|
921
925
|
|
|
922
926
|
// #1452 round-12 HIGH#2 — RE-FENCE a claimed review-publish command IMMEDIATELY before the host's
|
|
@@ -1138,7 +1142,7 @@ export function activeRestartSensitiveCommands(now: number = Date.now()): Comman
|
|
|
1138
1142
|
AND (type != 'agent.spawn' OR coalesce(json_extract(params, '$.registrationConfirmed'), 0) != 1)
|
|
1139
1143
|
ORDER BY updated_at ASC`,
|
|
1140
1144
|
)
|
|
1141
|
-
.all(...CLAIMED_ACTIVE_STATUSES, now, now) as CommandRow[]).map(rowToCommand);
|
|
1145
|
+
.all(...CLAIMED_ACTIVE_STATUSES, now, now) as CommandRow[]).map((row) => rowToCommand(row));
|
|
1142
1146
|
}
|
|
1143
1147
|
|
|
1144
1148
|
// #1746 RC-2 / issue ask 4 — when a shutdown command settles WITHOUT a confirmed kill (the
|
package/src/commands-write.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { STALE_TTL_MS } from "./config.ts";
|
|
|
11
11
|
import { bufferedLiveAgentIds } from "./db/presence-buffer.ts";
|
|
12
12
|
import { getGateway } from "./db/gateway.ts";
|
|
13
13
|
import {
|
|
14
|
+
commandDeletable,
|
|
14
15
|
commandUpdateHasPostCommitEffects,
|
|
15
16
|
type CreateCommandOptions,
|
|
16
17
|
type CreateCommandWriteArgs,
|
|
@@ -120,6 +121,13 @@ export async function updateCommandAsync(
|
|
|
120
121
|
return result.command;
|
|
121
122
|
}
|
|
122
123
|
|
|
124
|
+
/** Public DELETE (#1870 S6a): the cancel is a normal off-loop patch, so it never writes on the main thread. */
|
|
125
|
+
export async function deleteCommandAsync(id: string): Promise<boolean> {
|
|
126
|
+
if (!commandDeletable(await getCommandAsync(id))) return false;
|
|
127
|
+
await updateCommandAsync(id, { status: "canceled", error: "canceled" });
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
123
131
|
/** Atomically cancel only if the command is still in the caller's expected live statuses. */
|
|
124
132
|
export function cancelCommandIfStatusAsync(
|
|
125
133
|
args: CancelCommandIfStatusWriteArgs,
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
import { getGateway } from "./db/gateway.ts";
|
|
9
|
-
import
|
|
9
|
+
import { agentProfileDeleteTarget, agentProfileWriteNamespace, savedAgentProfileEntry } from "./config-store.ts";
|
|
10
|
+
import type { AgentProfile, ConfigEntry } from "./types.ts";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Set a config entry off-loop (landmine #2). Routes through a single serialized `config.set` writer op
|
|
@@ -37,3 +38,14 @@ export function setConfigAsync<T = unknown>(
|
|
|
37
38
|
export function deleteConfigAsync(namespace: string, key: string, updatedBy?: string): Promise<boolean> {
|
|
38
39
|
return getGateway().write("config.delete", { namespace, key, updatedBy }) as unknown as Promise<boolean>;
|
|
39
40
|
}
|
|
41
|
+
|
|
42
|
+
/** `setAgentProfile` on the writer thread (#1870 S7). */
|
|
43
|
+
export async function setAgentProfileAsync(profile: AgentProfile, updatedBy?: string, opts: { overrideBuiltIn?: boolean } = {}): Promise<ConfigEntry<AgentProfile>> {
|
|
44
|
+
return savedAgentProfileEntry(await setConfigAsync(agentProfileWriteNamespace(profile, opts), profile.name, profile, updatedBy));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** `deleteAgentProfile` on the writer thread (#1870 S7). */
|
|
48
|
+
export function deleteAgentProfileAsync(name: string, updatedBy?: string, opts: { resetBuiltInOverride?: boolean } = {}): Promise<boolean> {
|
|
49
|
+
const target = agentProfileDeleteTarget(name, opts);
|
|
50
|
+
return deleteConfigAsync(target.namespace, target.key, updatedBy);
|
|
51
|
+
}
|
package/src/config-store.ts
CHANGED
|
@@ -1120,24 +1120,35 @@ export function listAgentProfiles(): ConfigEntry<AgentProfile>[] {
|
|
|
1120
1120
|
].sort((a, b) => Number(Boolean(b.value.builtIn)) - Number(Boolean(a.value.builtIn)) || a.key.localeCompare(b.key));
|
|
1121
1121
|
}
|
|
1122
1122
|
|
|
1123
|
+
/** Where a profile write lands: a built-in's override row, else its own row. The rollback snapshot is
|
|
1124
|
+
* dropped by setConfigInternal on an override write (#1963 N10). */
|
|
1125
|
+
export function agentProfileWriteNamespace(profile: AgentProfile, opts: { overrideBuiltIn?: boolean } = {}): string {
|
|
1126
|
+
return BUILT_IN_AGENT_PROFILE_NAMES.has(profile.name) && opts.overrideBuiltIn ? AGENT_PROFILE_OVERRIDE_NAMESPACE : AGENT_PROFILE_NAMESPACE;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
/** The stored entry a profile write returns: an override reads back merged over its built-in. */
|
|
1130
|
+
export function savedAgentProfileEntry(saved: ConfigEntry<AgentProfile>): ConfigEntry<AgentProfile> {
|
|
1131
|
+
return saved.namespace === AGENT_PROFILE_OVERRIDE_NAMESPACE ? getAgentProfile(saved.key)! : applyProfilePromptEntry(saved)!;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/** Sync twin for tests and boot; runtime callers use `setAgentProfileAsync` (#1870 S7). */
|
|
1123
1135
|
export function setAgentProfile(profile: AgentProfile, updatedBy?: string, opts: { overrideBuiltIn?: boolean } = {}): ConfigEntry<AgentProfile> {
|
|
1124
|
-
|
|
1125
|
-
// The rollback snapshot is dropped by setConfigInternal on this override write (#1963 N10).
|
|
1126
|
-
setConfig(AGENT_PROFILE_OVERRIDE_NAMESPACE, profile.name, profile, updatedBy);
|
|
1127
|
-
return getAgentProfile(profile.name)!;
|
|
1128
|
-
}
|
|
1129
|
-
return applyProfilePromptEntry(setConfig(AGENT_PROFILE_NAMESPACE, profile.name, profile, updatedBy))!;
|
|
1136
|
+
return savedAgentProfileEntry(setConfig(agentProfileWriteNamespace(profile, opts), profile.name, profile, updatedBy));
|
|
1130
1137
|
}
|
|
1131
1138
|
|
|
1132
|
-
|
|
1133
|
-
|
|
1139
|
+
/** The row a profile delete removes. #2791 — resolves case-insensitively, so DELETE /qa drops "QA". The
|
|
1140
|
+
* rollback snapshot is dropped by deleteConfigInternal on an override delete (#1963 N10). */
|
|
1141
|
+
export function agentProfileDeleteTarget(name: string, opts: { resetBuiltInOverride?: boolean } = {}): { namespace: string; key: string } {
|
|
1134
1142
|
const canonical = resolveAgentProfileKey(name) ?? name;
|
|
1135
|
-
if (BUILT_IN_AGENT_PROFILE_NAMES.has(canonical)) {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1143
|
+
if (!BUILT_IN_AGENT_PROFILE_NAMES.has(canonical)) return { namespace: AGENT_PROFILE_NAMESPACE, key: canonical };
|
|
1144
|
+
if (opts.resetBuiltInOverride) return { namespace: AGENT_PROFILE_OVERRIDE_NAMESPACE, key: canonical };
|
|
1145
|
+
throw new ValidationError("built-in agent profiles are managed by Relay");
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/** Sync twin for tests; runtime callers use `deleteAgentProfileAsync` (#1870 S7). */
|
|
1149
|
+
export function deleteAgentProfile(name: string, updatedBy?: string, opts: { resetBuiltInOverride?: boolean } = {}): boolean {
|
|
1150
|
+
const target = agentProfileDeleteTarget(name, opts);
|
|
1151
|
+
return deleteConfig(target.namespace, target.key, updatedBy);
|
|
1141
1152
|
}
|
|
1142
1153
|
|
|
1143
1154
|
export function getManagedAgentState(policyName: string): ManagedAgentState | null {
|
package/src/db/activity-async.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { activityWriteIdempotencyKey } from "./activity-write-ops.ts";
|
|
5
5
|
import { getGateway } from "./gateway.ts";
|
|
6
6
|
import type { ActivityEvent, ActivityEventInput } from "../types";
|
|
7
|
-
import type { AgentIssueActivitySummary, AgentTimelineEntry, IssueActivityAction, IssueActivityAgentSummary, RecordIssueActivityInput } from "./activity.ts";
|
|
7
|
+
import type { AgentIssueActivitySummary, CreateActivityEventResult, AgentTimelineEntry, IssueActivityAction, IssueActivityAgentSummary, RecordIssueActivityInput } from "./activity.ts";
|
|
8
8
|
|
|
9
9
|
export async function listActivityEventsAsync(input: {
|
|
10
10
|
operatorId?: string;
|
|
@@ -43,6 +43,11 @@ export async function createActivityEventAsync(input: ActivityEventInput, idempo
|
|
|
43
43
|
return (await getGateway().write("activity.create", { input }, { idempotencyKey: key })) as unknown as ActivityEvent;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/** Creates by `clientId` and reports whether this call created the row (false: the id already existed). */
|
|
47
|
+
export async function createActivityEventByClientIdAsync(input: ActivityEventInput & { clientId: string }): Promise<CreateActivityEventResult> {
|
|
48
|
+
return (await getGateway().write("activity.createByClientId", { input })) as unknown as CreateActivityEventResult;
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
/** See `createActivityEventAsync` — same `idempotent: false` / key-derivation contract. */
|
|
47
52
|
export async function recordIssueActivityAsync(input: RecordIssueActivityInput, idempotencyKey?: string): Promise<ActivityEvent> {
|
|
48
53
|
const key = activityWriteIdempotencyKey(idempotencyKey, input.clientId);
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
// "do not blindly retry").
|
|
15
15
|
|
|
16
16
|
import { randomUUID } from "node:crypto";
|
|
17
|
-
import { createActivityEvent, recordIssueActivity } from "./activity.ts";
|
|
17
|
+
import { createActivityEvent, createActivityEventWithResult, recordIssueActivity } from "./activity.ts";
|
|
18
|
+
import type { CreateActivityEventResult } from "./activity.ts";
|
|
18
19
|
import type { ActivityEvent, ActivityEventInput } from "../types";
|
|
19
20
|
import type { RecordIssueActivityInput } from "./activity.ts";
|
|
20
21
|
import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
|
|
@@ -28,7 +29,18 @@ export const ACTIVITY_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object
|
|
|
28
29
|
idempotent: false,
|
|
29
30
|
fn: (args: ActivityCreateOpArgs, ctx: WriterOpContext): ActivityEvent => createActivityEvent(args.input, ctx.now),
|
|
30
31
|
},
|
|
32
|
+
// Dedups on `clientId` inside the body, so a replay reports `created: false` truthfully; the idempotency
|
|
33
|
+
// ledger would instead replay the first `created: true` (#1870 S7, operator alarms).
|
|
34
|
+
"activity.createByClientId": {
|
|
35
|
+
offLoop: true,
|
|
36
|
+
idempotent: true,
|
|
37
|
+
fn: (args: ActivityCreateOpArgs, ctx: WriterOpContext): CreateActivityEventResult => {
|
|
38
|
+
if (!args.input.clientId) throw new Error("activity.createByClientId requires input.clientId");
|
|
39
|
+
return createActivityEventWithResult(args.input, ctx.now);
|
|
40
|
+
},
|
|
41
|
+
},
|
|
31
42
|
"activity.recordIssueActivity": {
|
|
43
|
+
offLoop: true,
|
|
32
44
|
idempotent: false,
|
|
33
45
|
fn: (args: ActivityRecordIssueOpArgs, ctx: WriterOpContext): ActivityEvent => recordIssueActivity(args.input, ctx.now),
|
|
34
46
|
},
|
package/src/db/activity.ts
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isRecord, stringValue, isMechanicalMessageKind } from "@humwick/sdk";
|
|
3
|
-
import { ORCHESTRATOR_PROTOCOL_VERSION, VERSION } from "../config.ts";
|
|
1
|
+
import { isRecord, stringValue } from "@humwick/sdk";
|
|
4
2
|
import { parseJson } from "../utils";
|
|
5
|
-
import { isLiveIsolatedWorkspace } from "../workspace-phase";
|
|
6
|
-
import {
|
|
7
|
-
CONTRACT_REQUIREMENTS,
|
|
8
|
-
contractCompatibility,
|
|
9
|
-
parseRuntimeCapabilities,
|
|
10
|
-
parseRuntimeContracts,
|
|
11
|
-
parseRuntimePackage,
|
|
12
|
-
type RuntimeContracts,
|
|
13
|
-
} from "../contracts";
|
|
14
|
-
import { STALE_TTL_MS, DAY_MS, CLAIM_LEASE_MS, POOL_CLAIM_LEASE_MS, WORKSPACE_MERGE_LEASE_MS } from "../config";
|
|
15
|
-
import { matchAgents } from "../agent-ref";
|
|
16
3
|
import { getDb, ValidationError } from "./connection.ts";
|
|
17
4
|
import { rowToActivityEvent } from "./mappers.ts";
|
|
18
5
|
import { getIssueRef, resolveIssueRefFromString } from "./issue-refs.ts";
|
|
@@ -66,6 +66,7 @@ export const AGENT_LIFECYCLE_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> =
|
|
|
66
66
|
instanceSuperseded(args.agentId, args.expectedEpoch) ? [] : releaseWorkspaceClaimsForAgent(args.agentId, args.now),
|
|
67
67
|
},
|
|
68
68
|
"agents.seedContinuationObjective": {
|
|
69
|
+
offLoop: true,
|
|
69
70
|
idempotent: true,
|
|
70
71
|
fn: (args: AgentsSeedContinuationOpArgs, ctx: WriterOpContext): null => {
|
|
71
72
|
seedContinuationObjectiveFromSpawnPrompt(args.agentId, args.spawnRequestId, ctx.now);
|
package/src/db/agent-meta.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { mainThreadRegistry } from "./main-thread-state";
|
|
2
1
|
// Agent meta has two storage temperatures: small runtime fields change on status frames, while the
|
|
3
2
|
// launch projection is fixed for the life of a runner instance. Keep the latter out of `agents.meta`
|
|
4
3
|
// so a hot status update never has to carry it through its JSON patch.
|
|
@@ -7,7 +6,8 @@ import { isRecord } from "@humwick/sdk";
|
|
|
7
6
|
|
|
8
7
|
export const AGENT_META_WARN_BYTES = 64 * 1024;
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
// Log dedupe only, so a per-thread copy is correct: the writer thread warns once itself (#1870 S6c).
|
|
10
|
+
const warnedOversizeMeta = new Set<string>();
|
|
11
11
|
|
|
12
12
|
export interface StoredAgentMeta {
|
|
13
13
|
meta: Record<string, unknown>;
|
|
@@ -23,10 +23,12 @@ export interface AgentOwnershipReassignOpArgs { fromUserId: string; toUserId: st
|
|
|
23
23
|
|
|
24
24
|
export const AGENT_OWNERSHIP_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
|
|
25
25
|
"agent-ownership.set": {
|
|
26
|
+
offLoop: true,
|
|
26
27
|
idempotent: true,
|
|
27
28
|
fn: (args: AgentOwnershipSetOpArgs, ctx: WriterOpContext): AgentOwnership => setAgentOwnership(args.input, ctx.now),
|
|
28
29
|
},
|
|
29
30
|
"agent-ownership.delete": {
|
|
31
|
+
offLoop: true,
|
|
30
32
|
idempotent: true,
|
|
31
33
|
fn: (args: AgentOwnershipDeleteOpArgs): null => {
|
|
32
34
|
deleteAgentOwnership(args.agentId);
|
|
@@ -36,6 +38,7 @@ export const AGENT_OWNERSHIP_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> =
|
|
|
36
38
|
// Back-compat migration sweep (#392) — re-running converges (`INSERT ... WHERE NOT EXISTS`), so no
|
|
37
39
|
// args and idempotent: true.
|
|
38
40
|
"agent-ownership.seedDefault": {
|
|
41
|
+
offLoop: true,
|
|
39
42
|
idempotent: true,
|
|
40
43
|
fn: (_args: unknown, ctx: WriterOpContext): null => {
|
|
41
44
|
seedDefaultAgentOwnership(ctx.now);
|
|
@@ -44,6 +47,7 @@ export const AGENT_OWNERSHIP_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> =
|
|
|
44
47
|
},
|
|
45
48
|
// #3567 H4 admin handover — re-applying finds nothing left on the old owner, so it converges.
|
|
46
49
|
"agent-ownership.reassign": {
|
|
50
|
+
offLoop: true,
|
|
47
51
|
idempotent: true,
|
|
48
52
|
fn: (args: AgentOwnershipReassignOpArgs, ctx: WriterOpContext): string[] => reassignAgentOwnership(args.fromUserId, args.toUserId, ctx.now),
|
|
49
53
|
},
|
package/src/db/agent-search.ts
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isRecord, stringValue, isMechanicalMessageKind } from "@humwick/sdk";
|
|
3
|
-
import { ORCHESTRATOR_PROTOCOL_VERSION, VERSION } from "../config.ts";
|
|
4
|
-
import { parseJson } from "../utils";
|
|
5
|
-
import { isLiveIsolatedWorkspace } from "../workspace-phase";
|
|
6
|
-
import {
|
|
7
|
-
CONTRACT_REQUIREMENTS,
|
|
8
|
-
contractCompatibility,
|
|
9
|
-
parseRuntimeCapabilities,
|
|
10
|
-
parseRuntimeContracts,
|
|
11
|
-
parseRuntimePackage,
|
|
12
|
-
type RuntimeContracts,
|
|
13
|
-
} from "../contracts";
|
|
14
|
-
import { STALE_TTL_MS, DAY_MS, CLAIM_LEASE_MS, POOL_CLAIM_LEASE_MS, WORKSPACE_MERGE_LEASE_MS } from "../config";
|
|
15
|
-
import { matchAgents } from "../agent-ref";
|
|
1
|
+
import { STALE_TTL_MS } from "../config";
|
|
16
2
|
import { ROSTER_AGENT_COLUMNS } from "./agent-card-read.ts";
|
|
17
3
|
import { getDb } from "./connection.ts";
|
|
18
4
|
import { rowToAgent } from "./mappers.ts";
|
package/src/db/agents-async.ts
CHANGED
|
@@ -11,8 +11,16 @@
|
|
|
11
11
|
|
|
12
12
|
import { agentSessionGuardResult } from "./agent-predicates.ts";
|
|
13
13
|
import {
|
|
14
|
+
agentLifecycleWriteArgs,
|
|
15
|
+
bufferOrBypassHeartbeat,
|
|
14
16
|
getAgent,
|
|
17
|
+
prepareAgentLifecycleUpdate,
|
|
15
18
|
runBeforeAgentStatusTransitionHandlers,
|
|
19
|
+
type AgentLifecycleUpdate,
|
|
20
|
+
type AgentLifecycleUpdateResult,
|
|
21
|
+
type HeartbeatInput,
|
|
22
|
+
type OrphanedTokenPage,
|
|
23
|
+
type OrphanedTokenRevocation,
|
|
16
24
|
validateAgentSession,
|
|
17
25
|
type UpsertAgentTxResult,
|
|
18
26
|
type UpsertAgentOptions,
|
|
@@ -52,8 +60,12 @@ export async function upsertAgentAsync(
|
|
|
52
60
|
): Promise<AgentCard> {
|
|
53
61
|
// #2111 — allocated before the await, per the ordinal-timing rule at the top of setStatusAsync.
|
|
54
62
|
const seq = nextLifecycleSeq();
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
return finishAgentUpsertAsync(input.id, (await getGateway().write("agents.upsert", { input, opts, seq })) as unknown as UpsertAgentTxResult);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The registration's follow-ups after its row committed. Shared with `upsertOrchestratorAsync`. */
|
|
67
|
+
export async function finishAgentUpsertAsync(inputId: string, { agent, contextState }: UpsertAgentTxResult): Promise<AgentCard> {
|
|
68
|
+
if (contextState) await recordContextSnapshotAsync(inputId, contextState);
|
|
57
69
|
evictPendingPresence(agent.id);
|
|
58
70
|
// Both effects settle on the writer. The `spawnRequestId` guard is `seedContinuationObjectiveFromSpawnPrompt`'s
|
|
59
71
|
// own first condition, hoisted here so a registration without one costs no thread hop at all.
|
|
@@ -205,6 +217,31 @@ export async function recordAgentExitDiagnosticsAsync(
|
|
|
205
217
|
return getAgentAsync(id);
|
|
206
218
|
}
|
|
207
219
|
|
|
220
|
+
/** `applyAgentLifecycleUpdate` with the write on the writer thread (#1870 S7). The guard, the `before` read
|
|
221
|
+
* and the transition handlers stay on the main thread ahead of submission; the op CAS-fences on
|
|
222
|
+
* `before.epoch`, so a takeover that lands in the hop turns this into a no-op instead of a clobber. */
|
|
223
|
+
export async function applyAgentLifecycleUpdateAsync(
|
|
224
|
+
id: string,
|
|
225
|
+
update: AgentLifecycleUpdate,
|
|
226
|
+
guard?: AgentSessionGuard,
|
|
227
|
+
now: number = Date.now(),
|
|
228
|
+
): Promise<AgentLifecycleUpdateResult> {
|
|
229
|
+
// Allocated first, per the ordinal-timing rule at the top of setStatusAsync.
|
|
230
|
+
const seq = nextLifecycleSeq();
|
|
231
|
+
const before = prepareAgentLifecycleUpdate(id, update, guard);
|
|
232
|
+
if (!before) return { ok: false, changed: false, metaWriteBytes: 0, before: null, after: null };
|
|
233
|
+
const result = (await getGateway().write("agents.applyLifecycleUpdate", agentLifecycleWriteArgs(before, update, seq, now))) as unknown as Omit<AgentLifecycleUpdateResult, "ok" | "before">;
|
|
234
|
+
return { ok: true, before, ...result };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** `recordHeartbeat` for the transports: a steady-state beat is buffered at once; a presence-critical one
|
|
238
|
+
* writes on the writer thread (#1870 S7). */
|
|
239
|
+
export async function recordHeartbeatAsync(id: string, opts: HeartbeatInput = {}): Promise<boolean> {
|
|
240
|
+
const beat = bufferOrBypassHeartbeat(id, opts);
|
|
241
|
+
if (typeof beat === "boolean") return beat;
|
|
242
|
+
return (await applyAgentLifecycleUpdateAsync(id, beat, opts.guard, opts.now ?? Date.now())).changed;
|
|
243
|
+
}
|
|
244
|
+
|
|
208
245
|
export async function heartbeatAsync(
|
|
209
246
|
id: string,
|
|
210
247
|
guard?: AgentSessionGuard,
|
|
@@ -315,14 +352,28 @@ export async function deleteAgentAsync(id: string): Promise<{ ok: boolean; error
|
|
|
315
352
|
return deleted ? { ok: true } : { ok: false, error: "agent not found" };
|
|
316
353
|
}
|
|
317
354
|
|
|
355
|
+
// #3776 — the sweep is one short writer op per page of agents (each agent's lineage revoke stays atomic), so
|
|
356
|
+
// other writes interleave between pages. It stops when aborted or past its budget; the next run starts over.
|
|
357
|
+
const ORPHAN_SWEEP_PAGE_SIZE = 8;
|
|
358
|
+
const ORPHAN_SWEEP_BUDGET_MS = 30_000;
|
|
359
|
+
|
|
318
360
|
export async function revokeOrphanedRuntimeTokensAsync(
|
|
319
361
|
graceMs: number = STALE_TTL_MS,
|
|
320
362
|
lagGraceMs = 0,
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
363
|
+
options: { signal?: AbortSignal; budgetMs?: number; pageSize?: number } = {},
|
|
364
|
+
): Promise<{ revoked: OrphanedTokenRevocation[]; complete: boolean }> {
|
|
365
|
+
const { signal, budgetMs = ORPHAN_SWEEP_BUDGET_MS, pageSize = ORPHAN_SWEEP_PAGE_SIZE } = options;
|
|
366
|
+
const deadline = Date.now() + budgetMs;
|
|
367
|
+
const revoked: OrphanedTokenRevocation[] = [];
|
|
368
|
+
let afterId: string | undefined;
|
|
369
|
+
do {
|
|
370
|
+
if (signal?.aborted) return { revoked, complete: false };
|
|
371
|
+
const page = (await getGateway().write("agents.revokeOrphanedTokens", { graceMs, lagGraceMs, afterId, limit: pageSize })) as unknown as OrphanedTokenPage;
|
|
372
|
+
revoked.push(...page.revoked);
|
|
373
|
+
if (page.nextAfterId === null) return { revoked, complete: true };
|
|
374
|
+
afterId = page.nextAfterId;
|
|
375
|
+
} while (Date.now() < deadline);
|
|
376
|
+
return { revoked, complete: false };
|
|
326
377
|
}
|
|
327
378
|
|
|
328
379
|
export async function revokeRuntimeTokensForAgentAsync(
|