@humwick/server 0.130.1 → 0.130.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-administration.md +4 -0
- package/docs/guides/tools-coordination.md +2 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +74 -0
- package/docs/openapi.json +486 -4
- package/package.json +10 -18
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/agent-profiles-cxtRBn6O.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-B_rFEbnL.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/index-CqqgOI5R.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/project-profile-instructions-DETKFn_E.js +2 -0
- package/public/assets/projects-M_m6AHws.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-V9Z-GxUd.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-CXU75HRF.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/use-project-list-CpWl6eHQ.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/versioned-prompt-editor-CIVg7XB1.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +31 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
- package/runner/src/adapters/claude-effort.ts +2 -4
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/codex-launch-config.ts +4 -5
- package/runner/src/adapters/codex.ts +1 -1
- package/runner/src/adapters/opencode-provider.ts +7 -22
- package/runner/src/adapters/opencode.ts +4 -4
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -4
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/bin/claude.ts +4 -0
- package/runner/src/bin/codex.ts +4 -0
- package/runner/src/bin/opencode.ts +4 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/index.ts +5 -2
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +35 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +32 -38
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/cd-config.ts +8 -0
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +31 -98
- package/src/bus.ts +40 -39
- package/src/cd-deploy-notify.ts +32 -4
- package/src/cd-host-lag-notify.ts +7 -6
- package/src/ci/incidents.ts +2 -2
- package/src/ci/monitor.ts +5 -8
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +4 -9
- package/src/ci/transition-notify.ts +12 -44
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/cd-pauses.ts +19 -0
- package/src/cli/orchestrator.ts +1 -1
- package/src/cli/state.ts +2 -19
- package/src/cli/task-edit.ts +22 -0
- package/src/cli/task.ts +3 -1
- package/src/cli/workflow.ts +19 -4
- package/src/commands-db.ts +7 -7
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/activity-async.ts +6 -1
- package/src/db/activity-write-ops.ts +12 -1
- package/src/db/activity.ts +1 -14
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agent-search.ts +1 -15
- package/src/db/agents-async.ts +59 -9
- package/src/db/agents-write-ops.ts +12 -3
- package/src/db/agents.ts +95 -65
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/config-store-write-ops.ts +7 -2
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +7 -0
- package/src/db/continuations.ts +6 -6
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/db-writer-worker.ts +8 -1
- package/src/db/deploy-events-async.ts +1 -0
- package/src/db/deploy-events-read-ops.ts +2 -1
- package/src/db/deploy-events.ts +35 -4
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/hosts-registration.ts +10 -2
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -17
- package/src/db/index.ts +2 -0
- package/src/db/integrations-async.ts +8 -0
- package/src/db/integrations-ops.ts +15 -0
- package/src/db/integrations.ts +15 -21
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +23 -0
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +15 -16
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/long-running-work.ts +2 -2
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +41 -2
- package/src/db/maintenance-job-reconcile.ts +61 -0
- package/src/db/maintenance-job-runs-async.ts +14 -0
- package/src/db/maintenance-job-write-ops.ts +9 -0
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +25 -16
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +14 -76
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +42 -61
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-profile-instructions.ts +50 -0
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/prompt-versions.ts +9 -2
- package/src/db/provider-config-history.ts +8 -3
- package/src/db/provider-model-seed.ts +34 -0
- package/src/db/read-op-marshaling-fixtures.ts +23 -0
- package/src/db/read-ops.ts +8 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/routing-policy.ts +2 -3
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +13 -4
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +9 -6
- package/src/db/task-entity.ts +28 -6
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/token-db-write-ops.ts +19 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +21 -20
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +37 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +58 -56
- package/src/dev.ts +8 -3
- package/src/dispatch-availability.ts +10 -6
- package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host/disk-alert.ts +121 -0
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/land-gate-notifications.ts +11 -10
- package/src/land-gate-queue-progress.ts +3 -3
- package/src/land-settle-dispatch.ts +52 -92
- package/src/lifecycle-context-pressure.ts +11 -10
- package/src/lifecycle-manager.ts +107 -100
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +19 -20
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +32 -69
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +98 -137
- package/src/maintenance/stalled-delivery-pager.ts +10 -9
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +18 -28
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +32 -28
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +12 -9
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +6 -5
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +4 -3
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +13 -12
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +5 -5
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +13 -4
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notification-types.ts +2 -1
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +23 -11
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +12 -1
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-catalog-store.ts +3 -49
- package/src/provider-config-store.ts +12 -11
- package/src/provider-model-seed.ts +1 -18
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-quota-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +6 -5
- package/src/repo-config-source.ts +10 -4
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +2 -2
- package/src/routes/agents.ts +19 -121
- package/src/routes/auth.ts +14 -15
- package/src/routes/authority-audit.ts +2 -2
- package/src/routes/automations.ts +6 -5
- package/src/routes/channel-binding-delete.ts +1 -1
- package/src/routes/channel-output.ts +3 -3
- package/src/routes/claude-api-budget.ts +5 -5
- package/src/routes/commands-listing.ts +5 -1
- package/src/routes/commands.ts +31 -29
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +12 -2
- package/src/routes/integrations.ts +32 -56
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +9 -9
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +2 -2
- package/src/routes/orchestrator-host-registration.ts +4 -2
- package/src/routes/orchestrator-host-utilization.ts +5 -3
- package/src/routes/orchestrator-proxy.ts +4 -4
- package/src/routes/orchestrator.ts +28 -19
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +3 -3
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-config.ts +6 -6
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +6 -6
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/stats.ts +6 -6
- package/src/routes/task-http.ts +15 -1
- package/src/routes/task-issues.ts +11 -26
- package/src/routes/tasks.ts +22 -53
- package/src/routes/team-templates.ts +12 -12
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +30 -22
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +22 -7
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-policy-push.ts +6 -6
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +21 -13
- package/src/runtime-tokens.ts +59 -35
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +16 -21
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +2 -2
- package/src/server.ts +26 -24
- package/src/services/agent-action.ts +12 -31
- package/src/services/agent-effort.ts +7 -32
- package/src/services/agent-hang-watchdog-job.ts +2 -2
- package/src/services/agent-heartbeat.ts +166 -0
- package/src/services/agent-reporting.ts +1 -1
- package/src/services/browser-inventory.ts +3 -3
- package/src/services/browser-session-state.ts +3 -2
- package/src/services/browser-session.ts +21 -27
- package/src/services/bus-command-update.ts +9 -9
- package/src/services/checkout-refresh-state.ts +1 -0
- package/src/services/checkout-refresh.test-fixture.ts +3 -2
- package/src/services/command-host.ts +7 -2
- package/src/services/coordinator-digest.ts +3 -2
- package/src/services/dispatch-command.ts +12 -13
- package/src/services/effective-launch-driver.ts +14 -9
- package/src/services/host-changed-paths.test-fixture.ts +5 -6
- package/src/services/host-project-readiness.ts +2 -2
- package/src/services/host-providers.ts +1 -1
- package/src/services/host-utilization.ts +27 -4
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +9 -10
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +69 -72
- package/src/services/issue-refs.ts +10 -15
- package/src/services/kernel-timers-cutover-chaos-worker.ts +11 -8
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +4 -4
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +25 -8
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +17 -53
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +9 -3
- package/src/services/profile-trust.ts +6 -5
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +74 -61
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +21 -34
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +25 -43
- package/src/services/spawn-chain-inspector.ts +7 -14
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +8 -9
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +8 -17
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +12 -11
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +25 -20
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +26 -13
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +5 -3
- package/src/services/workflow-effect-driver.ts +42 -17
- package/src/services/workflow-effects.ts +58 -37
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +14 -11
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +6 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +61 -33
- package/src/services/workflow-supervisor-state.ts +26 -1
- package/src/services/workflow-supervisor.ts +11 -6
- package/src/services/workspace-recovery.ts +4 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +28 -10
- package/src/spawn-targets.ts +9 -9
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +62 -57
- package/src/state-adoption/cd-cutover.ts +53 -7
- package/src/state-adoption/fleet-cutover.ts +35 -0
- package/src/state-adoption/fleet-plan.ts +36 -0
- package/src/state-adoption/index.ts +2 -2
- package/src/state-adoption/linux-plan.ts +2 -2
- package/src/state-adoption/linux.ts +2 -2
- package/src/state-adoption/macos-plan.ts +2 -2
- package/src/state-adoption/macos.ts +1 -1
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +9 -8
- package/src/task-dispatch-live.ts +6 -3
- package/src/task-dispatcher.ts +3 -3
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +26 -17
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +4 -4
- package/node_modules/@humwick/kernel/LICENSE +0 -167
- package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
- package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
- package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
- package/node_modules/@humwick/kernel/config.ts +0 -111
- package/node_modules/@humwick/kernel/contract.ts +0 -572
- package/node_modules/@humwick/kernel/control-authz.ts +0 -281
- package/node_modules/@humwick/kernel/control.ts +0 -645
- package/node_modules/@humwick/kernel/effects.ts +0 -493
- package/node_modules/@humwick/kernel/event-log.ts +0 -319
- package/node_modules/@humwick/kernel/http-transport.ts +0 -384
- package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
- package/node_modules/@humwick/kernel/identity.ts +0 -248
- package/node_modules/@humwick/kernel/index.ts +0 -28
- package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
- package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
- package/node_modules/@humwick/kernel/landing.ts +0 -953
- package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
- package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
- package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
- package/node_modules/@humwick/kernel/message-authority.ts +0 -281
- package/node_modules/@humwick/kernel/module-host.ts +0 -722
- package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
- package/node_modules/@humwick/kernel/package.json +0 -39
- package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
- package/node_modules/@humwick/kernel/persistence.ts +0 -510
- package/node_modules/@humwick/kernel/registry.ts +0 -60
- package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
- package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
- package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
- package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
- package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
- package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
- package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
- package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
- package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
- package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
- package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
- package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
- package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
- package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
- package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
- package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
- package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
- package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
- package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
- package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
- package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
- package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
- package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
- package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
- package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
- package/node_modules/@humwick/offload/LICENSE +0 -167
- package/node_modules/@humwick/offload/README.md +0 -57
- package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
- package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
- package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
- package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.js +0 -80
- package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
- package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/index.js +0 -5
- package/node_modules/@humwick/offload/dist/index.js.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
- package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
- package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/types.js +0 -176
- package/node_modules/@humwick/offload/dist/types.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
- package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
- package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.js +0 -1
- package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
- package/node_modules/@humwick/offload/package.json +0 -42
- package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
- package/node_modules/@humwick/offload/src/envelope.ts +0 -92
- package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
- package/node_modules/@humwick/offload/src/index.ts +0 -4
- package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
- package/node_modules/@humwick/offload/src/types.ts +0 -235
- package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
- package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
- package/node_modules/@humwick/offload/src/worker.ts +0 -5
- package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
- package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
- package/public/assets/index-B7ZerHLY.css +0 -2
- package/public/assets/index-BU3uWo2t.js +0 -15
- package/public/assets/projects-B_lmcqfO.js +0 -2
- package/public/assets/provider-display-DbLWpP3j.js +0 -2
- package/public/assets/run-card-CO_bguQf.js +0 -2
- package/public/assets/shipping-Bu8p1gEw.js +0 -2
- package/public/assets/store-BvtFdlGX.js +0 -9
- package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/db/on-loop-write-transaction.ts +0 -34
- package/src/routing-model-aliases.ts +0 -21
package/src/runtime-grant.ts
CHANGED
|
@@ -5,11 +5,11 @@ import { getLaunchFact } from "./db/launch-facts";
|
|
|
5
5
|
import { getTokenProfile } from "./token-db";
|
|
6
6
|
import { getAgentProfile, spawnGrantForProfile, toolGroupsForProfile } from "./config-store";
|
|
7
7
|
import { FLEET_SCOPE } from "./security";
|
|
8
|
-
import { stringValue } from "@humwick/sdk";
|
|
8
|
+
import { registryToolName, stringValue } from "@humwick/sdk";
|
|
9
9
|
import { canonicalAgentProfileName, hasScope } from "@humwick/sdk/types";
|
|
10
10
|
import { COORDINATOR_PROFILE_NAMES } from "./agent-system-tags";
|
|
11
11
|
import { SECRETS_DEFAULT_PROFILES, SECRETS_TOOL_GROUP, SECRETS_WRITE_SCOPE } from "./secrets-broker/config";
|
|
12
|
-
import { resolveRelayTools, SELF_CARE_TOOL_GROUP } from "./mcp/tool-groups";
|
|
12
|
+
import { RELAY_TOOL_GROUPS, resolveRelayTools, SELF_CARE_TOOL_GROUP } from "./mcp/tool-groups";
|
|
13
13
|
|
|
14
14
|
// Scopes that turn an agent's runtime token into a spawn-capable one (#221). Appended to the
|
|
15
15
|
// provider-agent base scope only when the resolved profile permits (maxSpawnedAgents > 0).
|
|
@@ -24,7 +24,11 @@ const SPAWN_SCOPES = ["command:spawn", "command:shutdown"] as const;
|
|
|
24
24
|
const FLEET_OPS_PROFILES = new Set(["coordinator", "ops-assistant"]);
|
|
25
25
|
// #1925 H10 — fleet visibility is coordinator-facing. Keep this a fixed trusted-profile allowlist,
|
|
26
26
|
// like command:fleet, rather than a user-editable profile setting that could widen worker tokens.
|
|
27
|
-
const
|
|
27
|
+
const HOST_WRITE_PROFILES = new Set(["coordinator"]);
|
|
28
|
+
// #3772 — the reboot runbook reads resource_control held/waiter counts from /api/hosts; ops profiles read, never write.
|
|
29
|
+
const HOST_READ_PROFILES = new Set([...HOST_WRITE_PROFILES, "ops-assistant", "sec-ops"]);
|
|
30
|
+
// #3780 — operations and QA need hub diagnostics; coordinators can delegate the read scope.
|
|
31
|
+
const STATS_READ_PROFILES = new Set(["coordinator", "ops-assistant", "qa"]);
|
|
28
32
|
// #3073 — coordinator-only groups (not in WORKER_TOOL_GROUPS) a coordinator always gets, even when its stored override predates them.
|
|
29
33
|
const COORDINATOR_ONLY_TOOL_GROUPS = ["decisions", "workflows", "project", "routing"] as const;
|
|
30
34
|
// #3327 — the coordinator edits routing preferences, like Edin in the dashboard.
|
|
@@ -43,11 +47,10 @@ function callerMayMintHostsScope(callerScopes: string[] | undefined, scope: "hos
|
|
|
43
47
|
return callerScopes === undefined || hasScope(callerScopes, scope);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
// #3110 —
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const inGroup = toolGroups ? toolGroups.includes(SECRETS_TOOL_GROUP) : Boolean(profile && SECRETS_DEFAULT_PROFILES.has(profile));
|
|
50
|
+
// #3110/#3817 — broker groups and exact includes request the same scope, capped by the caller.
|
|
51
|
+
function grantsSecretsScope(profile: string | undefined, toolGroups: string[] | undefined, explicitlySelected: boolean, callerScopes: string[] | undefined): boolean {
|
|
52
|
+
const inGroup = (toolGroups ? toolGroups.includes(SECRETS_TOOL_GROUP) : Boolean(profile && SECRETS_DEFAULT_PROFILES.has(profile)))
|
|
53
|
+
|| explicitlySelected;
|
|
51
54
|
return inGroup && (callerScopes === undefined || hasScope(callerScopes, SECRETS_WRITE_SCOPE));
|
|
52
55
|
}
|
|
53
56
|
|
|
@@ -72,6 +75,8 @@ function nonTrustedBaseline(agentInitiated: boolean): string[] {
|
|
|
72
75
|
interface RunnerGrant {
|
|
73
76
|
scope: string[];
|
|
74
77
|
canSpawn: boolean;
|
|
78
|
+
/** A sub-coordinator under its root coordinator's project delegation: it places spawns on any host its parent can (#3804). */
|
|
79
|
+
delegated: boolean;
|
|
75
80
|
maxSpawnedAgents: number;
|
|
76
81
|
toolGroups: string[] | undefined;
|
|
77
82
|
toolInclude?: string[];
|
|
@@ -93,7 +98,7 @@ export function deriveRunnerGrant(profile: string | undefined, authority: Deriva
|
|
|
93
98
|
const selection = profile ? getAgentProfile(profile)?.value.relay.tools : undefined;
|
|
94
99
|
let toolGroups = toolGroupsForProfile(profile);
|
|
95
100
|
// #2897/#3073/#3110 — stored overrides predate newer trusted-profile groups: coordinators always get the coordinator-only
|
|
96
|
-
// groups, and the
|
|
101
|
+
// groups, and the coordinator gets `secrets`. Keep explicit NONE and full-surface semantics.
|
|
97
102
|
if (toolGroups?.length) {
|
|
98
103
|
const extra: string[] = [];
|
|
99
104
|
if ((COORDINATOR_PROFILE_NAMES as readonly string[]).includes(profile ?? "")) extra.push(...COORDINATOR_ONLY_TOOL_GROUPS);
|
|
@@ -104,19 +109,21 @@ export function deriveRunnerGrant(profile: string | undefined, authority: Deriva
|
|
|
104
109
|
}
|
|
105
110
|
const fleetOps = !agentInitiated && Boolean(profile && FLEET_OPS_PROFILES.has(profile)) && callerMayMintFleetScope(callerScopes);
|
|
106
111
|
const hostsRead = !agentInitiated && Boolean(profile && HOST_READ_PROFILES.has(profile)) && callerMayMintHostsScope(callerScopes, "hosts:read");
|
|
107
|
-
resolveRelayTools({ ...selection, groups: toolGroups });
|
|
112
|
+
const selected = resolveRelayTools({ ...selection, groups: toolGroups });
|
|
113
|
+
const explicitSecrets = selection?.include?.map(registryToolName).some(name => selected.has(name) && RELAY_TOOL_GROUPS[SECRETS_TOOL_GROUP]!.includes(name)) ?? false;
|
|
108
114
|
let scope = [
|
|
109
115
|
...nonTrustedBaseline(agentInitiated),
|
|
110
116
|
...(fleetOps ? [FLEET_SCOPE] : []),
|
|
111
117
|
...(hostsRead ? ["hosts:read"] : []),
|
|
112
|
-
...(
|
|
113
|
-
...(
|
|
118
|
+
...(profile && STATS_READ_PROFILES.has(profile.toLowerCase()) && (callerScopes === undefined || hasScope(callerScopes, "stats:read")) ? ["stats:read"] : []),
|
|
119
|
+
...(!agentInitiated && Boolean(profile && HOST_WRITE_PROFILES.has(profile)) && callerMayMintHostsScope(callerScopes, "hosts:write") ? ["hosts:write"] : []),
|
|
120
|
+
...(grantsSecretsScope(profile, toolGroups, explicitSecrets, callerScopes) ? [SECRETS_WRITE_SCOPE] : []),
|
|
114
121
|
...(!agentInitiated && (COORDINATOR_PROFILE_NAMES as readonly string[]).includes(profile ?? "") && (callerScopes === undefined || hasScope(callerScopes, ROUTING_WRITE_SCOPE)) ? [ROUTING_WRITE_SCOPE] : []),
|
|
115
122
|
...(grant.canSpawn ? SPAWN_SCOPES.filter(scope => !agentInitiated || callerScopes === undefined || hasScope(callerScopes, scope)) : []),
|
|
116
123
|
...(delegated && callerScopes && hasScope(callerScopes, "teams:write") ? ["teams:write"] : []),
|
|
117
124
|
];
|
|
118
125
|
if (lineage?.participating && callerScopes) scope = scope.filter(scope => hasScope(callerScopes, scope));
|
|
119
|
-
return { scope, canSpawn: grant.canSpawn, maxSpawnedAgents: grant.maxSpawnedAgents, toolGroups,
|
|
126
|
+
return { scope, canSpawn: grant.canSpawn, delegated, maxSpawnedAgents: grant.maxSpawnedAgents, toolGroups,
|
|
120
127
|
...(selection?.include === undefined ? {} : { toolInclude: selection.include }),
|
|
121
128
|
...(selection?.exclude === undefined ? {} : { toolExclude: selection.exclude }),
|
|
122
129
|
};
|
|
@@ -149,6 +156,7 @@ export function successorGrant(agentId: string, profile: string | undefined, dep
|
|
|
149
156
|
return {
|
|
150
157
|
scope: derived.scope.filter((scope) => ceiling.scope.includes(scope)),
|
|
151
158
|
canSpawn: derived.canSpawn && ceiling.canSpawn,
|
|
159
|
+
delegated: derived.delegated && ceiling.delegated,
|
|
152
160
|
maxSpawnedAgents: Math.min(derived.maxSpawnedAgents, ceiling.maxSpawnedAgents),
|
|
153
161
|
toolGroups: derived.toolGroups,
|
|
154
162
|
toolInclude: derived.toolInclude,
|
package/src/runtime-tokens.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stringValue } from "@humwick/sdk";
|
|
2
2
|
import { writeChildEnv } from "@humwick/sdk/env";
|
|
3
3
|
import { deriveRunnerGrant, successorGrant } from "./runtime-grant";
|
|
4
4
|
export { runnerSpawnGrantForAgent } from "./runtime-grant";
|
|
5
|
-
import { TOKEN_RECOVERY_WINDOW_SECONDS, createToken, getToken, getTokenProfile, type CreateTokenInput } from "./token-db";
|
|
6
|
-
import {
|
|
5
|
+
import { TOKEN_RECOVERY_WINDOW_SECONDS, createToken, getToken, getTokenProfile, type CreateTokenInput, type HandoffTokenInput, type TokenHandoff } from "./token-db";
|
|
6
|
+
import { runnerTokenMintLimit } from "./runner-token-mint-limit";
|
|
7
|
+
import { createRunnerTokenAsync, createTokenAsync, handoffTokenAsync } from "./token-db-write";
|
|
7
8
|
import { FLEET_SCOPE, verifyComponentTokenAllowExpired } from "./security";
|
|
8
9
|
import { getAgentProfile, hostPinForProfile, spawnGrantForProfile, toolGroupsForProfile } from "./config-store";
|
|
9
10
|
import { toolAllowlistForRunner } from "./mcp-tool-allowlist";
|
|
@@ -12,11 +13,9 @@ import { getLaunchFact, recordLaunchFact, type LaunchFact } from "./db/launch-fa
|
|
|
12
13
|
import type { ComponentToken, SpawnApprovalMode, TokenConstraints, TokenRecord } from "./types";
|
|
13
14
|
import { listManagedOrchestratorsForAgent } from "./orchestrator-lookup";
|
|
14
15
|
import { sameHostIdentity } from "./utils";
|
|
15
|
-
import {
|
|
16
|
-
import { canonicalAgentProfileName, hasScope } from "@humwick/sdk/types";
|
|
16
|
+
import { canonicalAgentProfileName } from "@humwick/sdk/types";
|
|
17
17
|
import { COORDINATOR_PROFILE_NAMES } from "./agent-system-tags";
|
|
18
18
|
import { SECRETS_DEFAULT_PROFILES, SECRETS_TOOL_GROUP, SECRETS_WRITE_SCOPE } from "./secrets-broker/config";
|
|
19
|
-
import { INCLUDED_TOOL_SCOPE_NEEDS, RELAY_TOOL_GROUPS, resolveRelayTools, SELF_CARE_TOOL_GROUP } from "./mcp/tool-groups";
|
|
20
19
|
|
|
21
20
|
/**
|
|
22
21
|
* Who vouches for a runner launch's authority (#3110 review). A launch without a positively identified
|
|
@@ -38,6 +37,22 @@ interface RuntimeTokenResult {
|
|
|
38
37
|
record: TokenRecord;
|
|
39
38
|
}
|
|
40
39
|
|
|
40
|
+
/** A refused successor mint; `retryAfterSeconds` marks a per-subject rate limit (HTTP 429). */
|
|
41
|
+
export type RunnerTokenMintRefusal = { error: string; retryAfterSeconds?: number };
|
|
42
|
+
|
|
43
|
+
/** #3775 — the one way a runner token's successor is minted: within the subject's mint limit, charged per new token. */
|
|
44
|
+
export async function handoffRunnerTokenAsync(sub: string, input: HandoffTokenInput): Promise<TokenHandoff | null | { retryAfterSeconds: number }> {
|
|
45
|
+
const retryAfterSeconds = runnerTokenMintLimit.refusal(sub);
|
|
46
|
+
if (retryAfterSeconds !== undefined) return { retryAfterSeconds };
|
|
47
|
+
const handoff = await handoffTokenAsync(input);
|
|
48
|
+
if (handoff && !handoff.replayed) runnerTokenMintLimit.charge(sub);
|
|
49
|
+
return handoff;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function mintRateLimited(handoff: object | null): handoff is { retryAfterSeconds: number } {
|
|
53
|
+
return handoff !== null && "retryAfterSeconds" in handoff;
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
function runnerTokenOwnedByOrchestratorHost(
|
|
42
57
|
constraints: NonNullable<ReturnType<typeof verifyComponentTokenAllowExpired>>["constraints"],
|
|
43
58
|
orchestratorId: string,
|
|
@@ -68,7 +83,7 @@ export async function reissueRunnerRuntimeToken(input: {
|
|
|
68
83
|
expiredToken: string;
|
|
69
84
|
orchestratorId: string;
|
|
70
85
|
createdBy?: string;
|
|
71
|
-
}): Promise<RuntimeTokenResult |
|
|
86
|
+
}): Promise<RuntimeTokenResult | RunnerTokenMintRefusal> {
|
|
72
87
|
const payload = verifyComponentTokenAllowExpired(input.expiredToken, { allowStaleRevoked: true });
|
|
73
88
|
// #3133 — recovery hands off from the token's record, which holds its standing; a token without one recovers nothing.
|
|
74
89
|
if (!payload?.jti) return { error: "invalid or revoked runner token" };
|
|
@@ -95,7 +110,8 @@ export async function reissueRunnerRuntimeToken(input: {
|
|
|
95
110
|
constraints: payload.constraints,
|
|
96
111
|
createdBy: input.createdBy ?? `remint:${payload.jti}`,
|
|
97
112
|
};
|
|
98
|
-
const handoff = await
|
|
113
|
+
const handoff = await handoffRunnerTokenAsync(payload.sub, { jti: payload.jti, successor, recoverExpiredWithinSeconds: TOKEN_RECOVERY_WINDOW_SECONDS, createdBy: successor.createdBy });
|
|
114
|
+
if (mintRateLimited(handoff)) return { error: "runner token mint rate limited", retryAfterSeconds: handoff.retryAfterSeconds };
|
|
99
115
|
return handoff ?? { error: "invalid or revoked runner token" };
|
|
100
116
|
}
|
|
101
117
|
|
|
@@ -122,7 +138,7 @@ function runnerGrantKey(scope: readonly string[] | undefined, constraints: Token
|
|
|
122
138
|
* (current profile, lineage ceiling) and the presented token's launch identity. An identical grant is left
|
|
123
139
|
* alone; otherwise the token is handed off like a renewal, so a lost response is recovered by a retry.
|
|
124
140
|
*/
|
|
125
|
-
export async function remintRunnerRuntimeToken(auth: ComponentToken, createdBy: string): Promise<RunnerTokenRemint | { unchanged: true; jti: string } |
|
|
141
|
+
export async function remintRunnerRuntimeToken(auth: ComponentToken, createdBy: string): Promise<RunnerTokenRemint | { unchanged: true; jti: string } | RunnerTokenMintRefusal> {
|
|
126
142
|
const previous = auth.jti ? getToken(auth.jti) : null;
|
|
127
143
|
const c = auth.constraints ?? {};
|
|
128
144
|
const agentId = c.agents?.length === 1 ? c.agents[0] : undefined;
|
|
@@ -149,7 +165,8 @@ export async function remintRunnerRuntimeToken(auth: ComponentToken, createdBy:
|
|
|
149
165
|
});
|
|
150
166
|
if (token.constraints?.orchestrators?.includes("")) return { error: "the agent's host is unknown, so its host pin cannot be kept" };
|
|
151
167
|
if (runnerGrantKey(previous.scope, previous.constraints) === runnerGrantKey(token.scope, token.constraints)) return { unchanged: true, jti: previous.jti };
|
|
152
|
-
const handoff = await
|
|
168
|
+
const handoff = await handoffRunnerTokenAsync(auth.sub, { jti: previous.jti, allowedProfileIds: ["provider-agent"], successor: token, createdBy });
|
|
169
|
+
if (mintRateLimited(handoff)) return { error: "runner token mint rate limited", retryAfterSeconds: handoff.retryAfterSeconds };
|
|
153
170
|
if (!handoff) return { error: "the presented token was already rotated" };
|
|
154
171
|
const { record } = handoff;
|
|
155
172
|
return {
|
|
@@ -175,8 +192,8 @@ export function issueOrchestratorRuntimeToken(input: {
|
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
/** #1870 S6c — the mint on the writer thread, for the async routes. */
|
|
178
|
-
export function issueOrchestratorRuntimeTokenAsync(input: Parameters<typeof issueOrchestratorRuntimeToken>[0]): Promise<RuntimeTokenResult> {
|
|
179
|
-
return createTokenAsync(orchestratorTokenSpec(input));
|
|
195
|
+
export async function issueOrchestratorRuntimeTokenAsync(input: Parameters<typeof issueOrchestratorRuntimeToken>[0]): Promise<RuntimeTokenResult> {
|
|
196
|
+
return (await createTokenAsync(orchestratorTokenSpec(input)));
|
|
180
197
|
}
|
|
181
198
|
|
|
182
199
|
function orchestratorTokenSpec(input: Parameters<typeof issueOrchestratorRuntimeToken>[0]): CreateTokenInput {
|
|
@@ -250,21 +267,15 @@ function runnerTokenSpec(input: RunnerRuntimeTokenInput): { token: CreateTokenIn
|
|
|
250
267
|
const grant = authority.kind === "successor" ? successorGrant(input.agentId, profile)
|
|
251
268
|
: { ...deriveRunnerGrant(profile, authority.kind === "delegated" ? { agentInitiated, callerScopes: authority.callerScopes, parentAgentId: input.spawnedBy, projectId: input.projectId, maxSpawnedAgents: input.maxSpawnedAgents } : { agentInitiated }), agentInitiated };
|
|
252
269
|
const { canSpawn, maxSpawnedAgents, toolGroups, toolInclude, toolExclude } = grant;
|
|
253
|
-
|
|
254
|
-
for (const authoredName of toolInclude ?? []) {
|
|
255
|
-
const name = registryToolName(authoredName);
|
|
256
|
-
if (!selected.has(name)) continue;
|
|
257
|
-
const needs = INCLUDED_TOOL_SCOPE_NEEDS[name];
|
|
258
|
-
if (RELAY_TOOL_GROUPS.kernel!.includes(name) || (needs && !needs.some((need) => hasScope(grant.scope, need)))) {
|
|
259
|
-
throw new Error(`relay.tools.include: ${name} requires ${needs?.join(" or ") ?? "kernel control scopes"}; profile ${profile} cannot grant that scope under this launch authority`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
270
|
+
// Includes choose the surface, not launch authority. MCP scope filtering hides unavailable tools (#3817).
|
|
262
271
|
// #1570 — provider-split: a Codex worker eager-loads every listed tool schema every turn (no
|
|
263
272
|
// client-native deferral), so trim its always-loaded MCP surface to the lean worker set. Classified
|
|
264
273
|
// by explicit worker profile (not tool-group shape — reviewers share the groups but aren't workers).
|
|
265
274
|
const toolAllowlist = toolInclude !== undefined || toolExclude !== undefined
|
|
266
275
|
? undefined : toolAllowlistForRunner(input.provider, profile);
|
|
267
|
-
|
|
276
|
+
// #3804 — an agent-spawned child stays on its launch host, except a delegated sub-coordinator: its home host is
|
|
277
|
+
// often full, so it places spawns wherever its parent can unless the launch pinned it.
|
|
278
|
+
const hostPinned = grant.agentInitiated && !grant.delegated ? true : (input.hostPinned ?? hostPinForProfile(input.profile));
|
|
268
279
|
const subject = input.policyName
|
|
269
280
|
? `runner:policy:${input.policyName}`
|
|
270
281
|
: input.spawnRequestId
|
|
@@ -306,6 +317,7 @@ function runnerTokenSpec(input: RunnerRuntimeTokenInput): { token: CreateTokenIn
|
|
|
306
317
|
: { kind: "root", ...(authority.kind === "delegated" ? { launcherScopes: authority.callerScopes } : {}), ...(profile ? { profile } : {}) } };
|
|
307
318
|
}
|
|
308
319
|
|
|
320
|
+
/** Sync twin for in-process tests; every runtime launch path mints through the writer op below. */
|
|
309
321
|
export function issueRunnerRuntimeToken(input: RunnerRuntimeTokenInput): RuntimeTokenResult {
|
|
310
322
|
const spec = runnerTokenSpec(input);
|
|
311
323
|
const issued = createToken(spec.token);
|
|
@@ -314,7 +326,12 @@ export function issueRunnerRuntimeToken(input: RunnerRuntimeTokenInput): Runtime
|
|
|
314
326
|
return issued;
|
|
315
327
|
}
|
|
316
328
|
|
|
317
|
-
export function
|
|
329
|
+
export function issueRunnerRuntimeTokenAsync(input: RunnerRuntimeTokenInput): Promise<RuntimeTokenResult> {
|
|
330
|
+
const spec = runnerTokenSpec(input);
|
|
331
|
+
return createRunnerTokenAsync(spec.token, spec.launchFact ? { agentId: input.agentId, fact: spec.launchFact } : undefined);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export async function issueInteractiveRunnerRuntimeToken(input: {
|
|
318
335
|
provider: string;
|
|
319
336
|
cwd: string;
|
|
320
337
|
runnerId: string;
|
|
@@ -326,9 +343,9 @@ export function issueInteractiveRunnerRuntimeToken(input: {
|
|
|
326
343
|
* authorization, so it must ride the signature rather than the caller-writable agent card. */
|
|
327
344
|
approvalMode?: SpawnApprovalMode;
|
|
328
345
|
createdBy?: string;
|
|
329
|
-
}): RuntimeTokenResult {
|
|
346
|
+
}): Promise<RuntimeTokenResult> {
|
|
330
347
|
const agentId = input.agentId ?? input.runnerId;
|
|
331
|
-
return
|
|
348
|
+
return (await createTokenAsync({
|
|
332
349
|
profileId: "provider-interactive",
|
|
333
350
|
sub: `runner:interactive:${input.host ?? "local"}:${input.runnerId}`,
|
|
334
351
|
role: "provider",
|
|
@@ -343,22 +360,22 @@ export function issueInteractiveRunnerRuntimeToken(input: {
|
|
|
343
360
|
canDelegate: false,
|
|
344
361
|
},
|
|
345
362
|
createdBy: input.createdBy ?? "interactive-runner",
|
|
346
|
-
});
|
|
363
|
+
}));
|
|
347
364
|
}
|
|
348
365
|
|
|
349
|
-
export function issueMcpRuntimeToken(input: {
|
|
366
|
+
export async function issueMcpRuntimeToken(input: {
|
|
350
367
|
sessionId: string;
|
|
351
368
|
agentId?: string;
|
|
352
369
|
targets?: string[];
|
|
353
370
|
channels?: string[];
|
|
354
371
|
createdBy?: string;
|
|
355
|
-
}): RuntimeTokenResult {
|
|
372
|
+
}): Promise<RuntimeTokenResult> {
|
|
356
373
|
const targets = input.targets?.length
|
|
357
374
|
? input.targets
|
|
358
375
|
: input.agentId
|
|
359
376
|
? ["user", input.agentId]
|
|
360
377
|
: undefined;
|
|
361
|
-
return
|
|
378
|
+
return (await createTokenAsync({
|
|
362
379
|
profileId: "mcp-client",
|
|
363
380
|
sub: input.agentId ? `mcp:${input.agentId}:${input.sessionId}` : `mcp:session:${input.sessionId}`,
|
|
364
381
|
role: "mcp",
|
|
@@ -369,16 +386,16 @@ export function issueMcpRuntimeToken(input: {
|
|
|
369
386
|
canDelegate: false,
|
|
370
387
|
},
|
|
371
388
|
createdBy: input.createdBy ?? "runtime",
|
|
372
|
-
});
|
|
389
|
+
}));
|
|
373
390
|
}
|
|
374
391
|
|
|
375
|
-
export function issueIntegrationRuntimeToken(input: {
|
|
392
|
+
export async function issueIntegrationRuntimeToken(input: {
|
|
376
393
|
name: string;
|
|
377
394
|
targets?: string[];
|
|
378
395
|
channels?: string[];
|
|
379
396
|
createdBy?: string;
|
|
380
|
-
}): RuntimeTokenResult {
|
|
381
|
-
return
|
|
397
|
+
}): Promise<RuntimeTokenResult> {
|
|
398
|
+
return (await createTokenAsync({
|
|
382
399
|
profileId: "integration-client",
|
|
383
400
|
sub: input.name,
|
|
384
401
|
role: "integration",
|
|
@@ -389,11 +406,18 @@ export function issueIntegrationRuntimeToken(input: {
|
|
|
389
406
|
canDelegate: false,
|
|
390
407
|
},
|
|
391
408
|
createdBy: input.createdBy ?? "runtime",
|
|
392
|
-
});
|
|
409
|
+
}));
|
|
393
410
|
}
|
|
394
411
|
|
|
395
412
|
export function runnerRuntimeTokenEnv(input: RunnerRuntimeTokenInput): Record<string, string> {
|
|
396
|
-
|
|
413
|
+
return runnerTokenEnv(input, issueRunnerRuntimeToken(input));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export async function runnerRuntimeTokenEnvAsync(input: RunnerRuntimeTokenInput): Promise<Record<string, string>> {
|
|
417
|
+
return runnerTokenEnv(input, await issueRunnerRuntimeTokenAsync(input));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function runnerTokenEnv(input: RunnerRuntimeTokenInput, issued: RuntimeTokenResult): Record<string, string> {
|
|
397
421
|
return writeChildEnv({}, {
|
|
398
422
|
AGENT_RELAY_TOKEN: issued.token,
|
|
399
423
|
AGENT_RELAY_TOKEN_JTI: issued.record.jti,
|
|
@@ -9,7 +9,7 @@ import { envFilePath } from "@humwick/sdk/child-env";
|
|
|
9
9
|
export const SECRETS_TOOL_GROUP = "secrets";
|
|
10
10
|
export const SECRETS_WRITE_SCOPE = "secrets:write";
|
|
11
11
|
/** Built-in profiles whose default full surface includes the secrets group. */
|
|
12
|
-
export const SECRETS_DEFAULT_PROFILES: ReadonlySet<string> = new Set(["coordinator"
|
|
12
|
+
export const SECRETS_DEFAULT_PROFILES: ReadonlySet<string> = new Set(["coordinator"]);
|
|
13
13
|
|
|
14
14
|
export const UPLOAD_LINK_TTL_MS = 15 * 60_000;
|
|
15
15
|
export const SECRET_UPLOAD_PATH_PREFIX = "/api/secrets/upload/";
|
|
@@ -27,13 +27,13 @@ let client: InfisicalBrokerClient | undefined;
|
|
|
27
27
|
|
|
28
28
|
function brokerClient(): InfisicalBrokerClient {
|
|
29
29
|
client ??= new InfisicalBrokerClient(secretsBrokerSettings(), {
|
|
30
|
-
onLoginBlocked: (detail) => raiseOperatorAlarm({
|
|
30
|
+
onLoginBlocked: async (detail) => (await raiseOperatorAlarm({
|
|
31
31
|
clientId: "secrets-broker:login-blocked",
|
|
32
32
|
source: "secrets-broker",
|
|
33
33
|
subject: "Secrets broker login blocked",
|
|
34
34
|
detail: `${detail}. Fix the cause, then rotate or touch the credential files to re-arm.`,
|
|
35
35
|
dedupeEvent: true,
|
|
36
|
-
}),
|
|
36
|
+
})),
|
|
37
37
|
});
|
|
38
38
|
return client;
|
|
39
39
|
}
|
package/src/security.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { retireHandedOffPredecessor, tokenRetirementPending } from "./db/token-standing-async";
|
|
1
2
|
import { BRIDGED_CORS_HEADERS, relayHeader } from "@humwick/sdk";
|
|
2
3
|
import { versionedPromptsEnabled } from "./versioned-prompts";
|
|
3
4
|
import { serviceAccessRouteScope } from "./service-access/scope";
|
|
@@ -233,6 +234,8 @@ export function isOrchestratorRegistrationAuthorized(req: Request): boolean {
|
|
|
233
234
|
}
|
|
234
235
|
|
|
235
236
|
const SHARED_UI_ROUTE_SCOPES: Record<string, string> = {
|
|
237
|
+
"/api/orchestrators/bootstrap": "token:write",
|
|
238
|
+
"/api/orchestrators/bootstrap/exchange": "token:write",
|
|
236
239
|
"/api/claude-api-budget/summary": "agent:read",
|
|
237
240
|
"/api/claude-api-budget": "system:admin",
|
|
238
241
|
"/api/stats": "stats:read",
|
|
@@ -240,6 +243,7 @@ const SHARED_UI_ROUTE_SCOPES: Record<string, string> = {
|
|
|
240
243
|
"/api/metrics/hub": "stats:read",
|
|
241
244
|
"/api/shipping/board": "stats:read",
|
|
242
245
|
"/api/shipping/stats": "stats:read",
|
|
246
|
+
"/api/shipping/known-failures": "agent:read", // #3362 §11: read by builders' delivery gates
|
|
243
247
|
"/api/stats/token-usage": "stats:read",
|
|
244
248
|
// #3567 — every signed-in user reads their profile and sets their password (the handler requires a session or the admin token).
|
|
245
249
|
"/api/users/me": "agent:read",
|
|
@@ -252,6 +256,15 @@ function sharedUiRouteScope(pathname: string, method: string): string | undefine
|
|
|
252
256
|
if (/^\/api\/api-budgets\/[^/]+\/summary$/.test(pathname)) return "agent:read";
|
|
253
257
|
if (/^\/api\/api-budgets\/[^/]+$/.test(pathname)) return "system:admin";
|
|
254
258
|
if (/^\/api\/shipping\/incidents\/[^/]+\/abandon$/.test(pathname)) return "command:write";
|
|
259
|
+
if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
|
|
260
|
+
if (pathname.startsWith("/api/teams")) return method === "GET" ? "teams:read" : "teams:write";
|
|
261
|
+
if (pathname === "/api/decisions" && method === "POST") return "teams:write"; // #2914: filing = the relay_decision scope
|
|
262
|
+
if (pathname.startsWith("/api/decisions")) return method === "GET" ? "teams:read" : "message:send"; // #2885: answering = messaging the coordinator
|
|
263
|
+
if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
|
|
264
|
+
if (pathname.startsWith("/api/issue-associations")) return method === "GET" ? "issue:read" : "issue:write";
|
|
265
|
+
if (pathname.startsWith("/api/issue-activity")) return method === "GET" ? "issue:read" : "issue:write";
|
|
266
|
+
if (pathname.startsWith("/api/issue-lifecycle")) return method === "GET" ? "issue:read" : "issue:write";
|
|
267
|
+
if (pathname.startsWith("/api/issue-refs")) return method === "GET" ? "issue:read" : "issue:write";
|
|
255
268
|
return Object.hasOwn(SHARED_UI_ROUTE_SCOPES, pathname) ? SHARED_UI_ROUTE_SCOPES[pathname] : undefined;
|
|
256
269
|
}
|
|
257
270
|
|
|
@@ -266,8 +279,6 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
|
|
|
266
279
|
if (pathname === "/api/route") return "agent:read";
|
|
267
280
|
if (pathname === "/api/notifications/preview") return "notifications:read";
|
|
268
281
|
if (pathname === "/api/mcp") return "mcp:use";
|
|
269
|
-
if (pathname === "/api/orchestrators/bootstrap/exchange") return "token:write";
|
|
270
|
-
if (pathname === "/api/orchestrators/bootstrap") return "token:write";
|
|
271
282
|
if (pathname.match(/^\/api\/orchestrators\/[^/]+\/logs\//)) return "logs:read";
|
|
272
283
|
if (pathname.match(/^\/api\/orchestrators\/[^/]+\/terminal\/[^/]+\/input$/)) return "terminal:write";
|
|
273
284
|
if (pathname.match(/^\/api\/orchestrators\/[^/]+\/terminal\//)) return "terminal:read";
|
|
@@ -323,16 +334,8 @@ export function requiredScopeFor(method: string, pathname: string): string | nul
|
|
|
323
334
|
if (pathname.match(/^\/api\/provider-quotas\/[^/]+\/reset-fired$/)) return "quota:write";
|
|
324
335
|
if (pathname === "/api/provider-quotas") return method === "GET" ? "agent:read" : "quota:write";
|
|
325
336
|
if (pathname === "/api/routing-policy") return method === "GET" ? "agent:read" : "settings:write:routing";
|
|
326
|
-
if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
|
|
327
337
|
if (pathname === "/api/settings/prompts" || pathname.startsWith("/api/settings/prompts/")) return method === "GET" ? "agent:read" : "system:admin";
|
|
328
|
-
if (
|
|
329
|
-
if (pathname === "/api/decisions" && method === "POST") return "teams:write"; // #2914: filing = the relay_decision scope
|
|
330
|
-
if (pathname.startsWith("/api/decisions")) return method === "GET" ? "teams:read" : "message:send"; // #2885: answering = messaging the coordinator
|
|
331
|
-
if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
|
|
332
|
-
if (pathname.startsWith("/api/issue-associations")) return method === "GET" ? "issue:read" : "issue:write";
|
|
333
|
-
if (pathname.startsWith("/api/issue-activity")) return method === "GET" ? "issue:read" : "issue:write";
|
|
334
|
-
if (pathname.startsWith("/api/issue-lifecycle")) return method === "GET" ? "issue:read" : "issue:write";
|
|
335
|
-
if (pathname.startsWith("/api/issue-refs")) return method === "GET" ? "issue:read" : "issue:write";
|
|
338
|
+
if (/^\/api\/projects\/[^/]+\/profile-instructions(?:\/|$)/.test(pathname)) return method === "GET" ? "agent:read" : "agent:write";
|
|
336
339
|
if (pathname.startsWith("/api/projects")) return method === "GET" ? "project:read" : "project:write";
|
|
337
340
|
// Insights config (the feature toggle) stays admin-only via the default; only the
|
|
338
341
|
// mechanical observation feed is writable by lower-privilege callers.
|
|
@@ -466,7 +469,6 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
|
|
|
466
469
|
if (pathname === "/api/routing-policy") {
|
|
467
470
|
return method === "GET" ? "agent:read" : "settings:write:routing";
|
|
468
471
|
}
|
|
469
|
-
if (pathname === "/api/teams/config") return method === "GET" ? "teams:read" : "settings:write:teams";
|
|
470
472
|
if (pathname === "/api/settings/prompts" || pathname.startsWith("/api/settings/prompts/")) {
|
|
471
473
|
return method === "GET" ? "agent:read" : versionedPromptsEnabled() ? "agent:write" : "system:admin";
|
|
472
474
|
}
|
|
@@ -477,16 +479,9 @@ export function requiredComponentScopeFor(method: string, pathname: string): str
|
|
|
477
479
|
if (pathname.startsWith("/api/workflows")) return method === "GET" ? "task:read" : "task:write";
|
|
478
480
|
if (pathname.startsWith("/api/orchestrators")) return method === "GET" ? "agent:read" : "command:write";
|
|
479
481
|
if (pathname.startsWith("/api/plans")) return method === "GET" ? "plans:read" : "plans:write";
|
|
480
|
-
if (pathname.startsWith("/api/teams")) return method === "GET" ? "teams:read" : "teams:write";
|
|
481
|
-
if (pathname === "/api/decisions" && method === "POST") return "teams:write"; // #2914: filing = the relay_decision scope
|
|
482
|
-
if (pathname.startsWith("/api/decisions")) return method === "GET" ? "teams:read" : "message:send"; // #2885: answering = messaging the coordinator
|
|
483
|
-
if (pathname.startsWith("/api/blackboard")) return method === "GET" ? "blackboard:read" : "blackboard:write";
|
|
484
|
-
if (pathname.startsWith("/api/issue-associations")) return method === "GET" ? "issue:read" : "issue:write";
|
|
485
|
-
if (pathname.startsWith("/api/issue-activity")) return method === "GET" ? "issue:read" : "issue:write";
|
|
486
|
-
if (pathname.startsWith("/api/issue-lifecycle")) return method === "GET" ? "issue:read" : "issue:write";
|
|
487
|
-
if (pathname.startsWith("/api/issue-refs")) return method === "GET" ? "issue:read" : "issue:write";
|
|
488
482
|
// Fail-closed default returns system:admin, so this case is load-bearing: without it
|
|
489
483
|
// every /api/projects call from a scoped component token would 403-blackhole (#405).
|
|
484
|
+
if (/^\/api\/projects\/[^/]+\/profile-instructions(?:\/|$)/.test(pathname)) return method === "GET" ? "agent:read" : "agent:write";
|
|
490
485
|
if (pathname.startsWith("/api/projects")) return method === "GET" ? "project:read" : "project:write";
|
|
491
486
|
// The Runner posts the #184 context-gathering signal here (source:"server") via its
|
|
492
487
|
// provider token. Without this case the path fell through to the system:admin default
|
|
@@ -546,7 +541,7 @@ export function verifyComponentToken(token: string, nowSeconds = Math.floor(Date
|
|
|
546
541
|
const payload = parseBase64urlJson(payloadRaw);
|
|
547
542
|
if (!isComponentToken(payload)) return null;
|
|
548
543
|
if (payload.exp !== undefined && payload.exp <= nowSeconds) return null;
|
|
549
|
-
if (payload.jti && isTokenRevoked(payload.jti)) return null;
|
|
544
|
+
if (payload.jti && (tokenRetirementPending(payload.jti) || isTokenRevoked(payload.jti, retireHandedOffPredecessor))) return null;
|
|
550
545
|
return payload;
|
|
551
546
|
}
|
|
552
547
|
|
package/src/self-resume-carry.ts
CHANGED
|
@@ -1,69 +1,35 @@
|
|
|
1
1
|
import { errMessage, isRecord, stringValue } from "@humwick/sdk";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from "./db";
|
|
2
|
+
import { getAgent } from "./db";
|
|
3
|
+
import type { ContextResetFact } from "./db/context-reset-carry";
|
|
4
|
+
import { commandBoundary } from "./db/context-carry-write";
|
|
5
|
+
import { getGateway } from "./db/gateway";
|
|
6
|
+
import type { SendMessageResult } from "./db/messages";
|
|
6
7
|
import { emitCommandEvent } from "./command-events";
|
|
7
8
|
import { createSelfRestartCommandAsync } from "./services/restart-spawn";
|
|
8
|
-
import { isContinuationSelfResumeCommand } from "./self-resume-command";
|
|
9
9
|
import { emitNewMessage } from "./sse";
|
|
10
10
|
import type { Command, Message } from "./types";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// "Possible unread messages" list. At least once: a listed message may already be handled.
|
|
15
|
-
|
|
16
|
-
const LISTED_IDS = 200;
|
|
17
|
-
// The loss #3398 fixes is reads in the minutes before the self-care call or during it (#3523); earlier ones are in the saved state.
|
|
18
|
-
const CARRY_MARGIN_MS = 10 * 60_000;
|
|
19
|
-
// A failed or swept command proves nothing about its destructive input, so its list is only a fallback.
|
|
20
|
-
const FALLBACK_STATUSES: ReadonlySet<Command["status"]> = new Set(["failed", "canceled", "timed_out", "rejected"]);
|
|
21
|
-
|
|
22
|
-
/** Opens the obligation at accept, before the boundary command exists. */
|
|
23
|
-
export function openContextRecovery(agentId: string, generation: number, now: number): void {
|
|
24
|
-
openRecoveryObligation(agentId, generation, now);
|
|
12
|
+
export async function openContextRecovery(agentId: string, generation: number, now: number): Promise<void> {
|
|
13
|
+
await getGateway().write("contextCarry.open", { agentId, generation, now });
|
|
25
14
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
attachRecoveryCommand(agentId, generation, commandId);
|
|
15
|
+
export async function attachContextRecoveryCommand(agentId: string, generation: number, commandId: string): Promise<void> {
|
|
16
|
+
await getGateway().write("contextCarry.attach", { agentId, generation, commandId });
|
|
29
17
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
export function recordContextReset(fact: ContextResetFact): Message | null {
|
|
33
|
-
const now = Date.now();
|
|
34
|
-
return sendAndEmit(() => {
|
|
35
|
-
if (!insertContextReset(fact, now)) return null;
|
|
36
|
-
const carrying = carryingRecoveryObligations(fact.agentId);
|
|
37
|
-
if (!carrying.length) return null;
|
|
38
|
-
const result = sendCarry(fact.agentId, carrying, `${fact.resetId}:0`, { resetId: fact.resetId, kind: fact.kind });
|
|
39
|
-
closeRecoveryObligations(fact.agentId, settledBy(fact, carrying), `reset:${fact.resetId}`, now);
|
|
40
|
-
return result;
|
|
41
|
-
});
|
|
18
|
+
export async function recordContextReset(fact: ContextResetFact): Promise<Message | null> {
|
|
19
|
+
return emitCarry(await getGateway().write("contextCarry.reset", { fact }) as unknown as SendMessageResult | null);
|
|
42
20
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export function settleContextResetCarry(command: Command): Message | null {
|
|
49
|
-
const boundary = FALLBACK_STATUSES.has(command.status) ? commandBoundary(command) : null;
|
|
50
|
-
if (!boundary) return null;
|
|
51
|
-
const message = sendAndEmit(() => {
|
|
52
|
-
const carrying = carryingRecoveryObligations(boundary.agentId);
|
|
53
|
-
if (!carrying.some((obligation) => obligation.open && obligation.generation === boundary.generation)) return null;
|
|
54
|
-
const sent = sendCarry(boundary.agentId, carrying, `${command.id}:fallback`, { boundaryCommandId: command.id, status: command.status });
|
|
55
|
-
// The runner aborted before any destructive input reached the provider: no reset can follow, so nothing is owed (#3441).
|
|
56
|
-
if (isRecord(command.result) && command.result.destructiveInputSubmitted === false) {
|
|
57
|
-
closeRecoveryObligations(boundary.agentId, [boundary.generation], `submit-aborted:${command.id}`, Date.now());
|
|
58
|
-
}
|
|
59
|
-
return sent;
|
|
60
|
-
});
|
|
61
|
-
if (command.status === "failed" && isRecord(command.result) && command.result.destructiveInputUnsettled === true) {
|
|
62
|
-
void replaceUnsettledBoundary(command, boundary).catch((error) => console.error(`#3398 self-restart after unsettled ${command.type} ${command.id} failed: ${errMessage(error)}`));
|
|
21
|
+
export async function settleContextResetCarry(command: Command): Promise<Message | null> {
|
|
22
|
+
const result = emitCarry(await getGateway().write("contextCarry.settle", { command }) as unknown as SendMessageResult | null);
|
|
23
|
+
const boundary = commandBoundary(command);
|
|
24
|
+
if (boundary && command.status === "failed" && isRecord(command.result) && command.result.destructiveInputUnsettled === true) {
|
|
25
|
+
await replaceUnsettledBoundary(command, boundary);
|
|
63
26
|
}
|
|
64
|
-
return
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
function emitCarry(result: SendMessageResult | null): Message | null {
|
|
30
|
+
if (result && (result.created || result.updated)) emitNewMessage(result.message);
|
|
31
|
+
return result?.message ?? null;
|
|
65
32
|
}
|
|
66
|
-
|
|
67
33
|
/** The provider may still apply the input without any observable reset: a successor's registration is the reset instead. */
|
|
68
34
|
async function replaceUnsettledBoundary(command: Command, boundary: { agentId: string; generation: number }): Promise<void> {
|
|
69
35
|
const agent = getAgent(boundary.agentId);
|
|
@@ -74,58 +40,3 @@ async function replaceUnsettledBoundary(command: Command, boundary: { agentId: s
|
|
|
74
40
|
const restart = await createSelfRestartCommandAsync(agent, boundary.generation, continuation, fullContextMessageId, "reset-unconfirmed", Date.now());
|
|
75
41
|
emitCommandEvent(restart, "command.requested");
|
|
76
42
|
}
|
|
77
|
-
|
|
78
|
-
/** A reset settles only the boundary its provider evidence names; a replaced process settles all. */
|
|
79
|
-
function settledBy(fact: ContextResetFact, carrying: RecoveryObligation[]): number[] {
|
|
80
|
-
const open = carrying.filter((obligation) => obligation.open);
|
|
81
|
-
if (fact.kind === "restart") return open.map((obligation) => obligation.generation);
|
|
82
|
-
return open.filter((obligation) => fact.commandId !== undefined && obligation.commandId === fact.commandId).map((obligation) => obligation.generation);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function commandBoundary(command: Command): { agentId: string; generation: number } | null {
|
|
86
|
-
const selfResume = isRecord(command.params.selfResume) ? command.params.selfResume : undefined;
|
|
87
|
-
const generation = selfResume?.generation;
|
|
88
|
-
if (typeof generation !== "number") return null;
|
|
89
|
-
if (command.type === "agent.restart") {
|
|
90
|
-
const agentId = stringValue(command.params.agentId);
|
|
91
|
-
return agentId && isRecord(command.params.selfRestart) ? { agentId, generation } : null;
|
|
92
|
-
}
|
|
93
|
-
return isContinuationSelfResumeCommand(command) ? { agentId: command.target, generation } : null;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
type SendResult = ReturnType<typeof sendMessageWithResult>;
|
|
97
|
-
|
|
98
|
-
function sendAndEmit(write: () => SendResult | null): Message | null {
|
|
99
|
-
const result = writeTransaction(write);
|
|
100
|
-
if (result && (result.created || result.updated)) emitNewMessage(result.message);
|
|
101
|
-
return result?.message ?? null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Floor: the earliest capture start minus the margin. No upper bound: a read after the reset is a duplicate, never a loss, and needs no clock comparison.
|
|
105
|
-
function sendCarry(agentId: string, carrying: RecoveryObligation[], key: string, detail: Record<string, unknown>): SendResult | null {
|
|
106
|
-
const ids = readsToCarry(agentId, Math.min(...carrying.map((obligation) => obligation.openedAt)) - CARRY_MARGIN_MS);
|
|
107
|
-
if (!ids.length) return null;
|
|
108
|
-
return sendMessageWithResult({
|
|
109
|
-
from: "system",
|
|
110
|
-
to: agentId,
|
|
111
|
-
kind: "system",
|
|
112
|
-
subject: "Possible unread messages",
|
|
113
|
-
body: renderCarryBody(ids),
|
|
114
|
-
payload: { selfResumeCarry: { ...detail, generations: carrying.map((obligation) => obligation.generation), messageIds: ids } },
|
|
115
|
-
idempotencyKey: `self-resume-carry:${agentId}:${key}`,
|
|
116
|
-
replyExpected: false,
|
|
117
|
-
maxAgeSeconds: null,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function renderCarryBody(ids: number[]): string {
|
|
122
|
-
const listed = ids.slice(0, LISTED_IDS).map((id) => `#${id}`).join(" ");
|
|
123
|
-
const rest = ids.length > LISTED_IDS ? `\n…and ${ids.length - LISTED_IDS} more, up to #${ids.at(-1)}; every id is in this message's payload.` : "";
|
|
124
|
-
return [
|
|
125
|
-
`Possible unread messages: ${ids.length} message${ids.length === 1 ? "" : "s"} reached you around your context reset, after or shortly before you saved your working state, so your current context may not hold them.`,
|
|
126
|
-
"Check each one your working state does not already cover with relay_get_message <id>, and handle it. Some may be duplicates of work you have done.",
|
|
127
|
-
"Messages you already handled may appear here, including the reset instruction itself: do not repeat a reset instruction found here.",
|
|
128
|
-
"",
|
|
129
|
-
`${listed}${rest}`,
|
|
130
|
-
].join("\n");
|
|
131
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { updateCommandAsync } from "./commands-write";
|
|
1
2
|
import { getContinuationEnvelope } from "./db/continuations";
|
|
2
|
-
|
|
3
|
+
|
|
3
4
|
import type { Command } from "./types";
|
|
4
5
|
|
|
5
6
|
/** #3662 — a continuation belongs to one generation; once a newer one is captured, an older boundary is
|
|
@@ -14,6 +15,6 @@ export function supersedingGeneration(boundary: Command): number | null {
|
|
|
14
15
|
|
|
15
16
|
/** Cancel (never fail) the not-yet-started injects of a superseded boundary. Accepted/running ones are
|
|
16
17
|
* already in the provider's hands and settle on their own. */
|
|
17
|
-
export function cancelSupersededInjects(pendingAttemptIds: string[], current: number): void {
|
|
18
|
-
for (const id of pendingAttemptIds)
|
|
18
|
+
export async function cancelSupersededInjects(pendingAttemptIds: string[], current: number): Promise<void> {
|
|
19
|
+
for (const id of pendingAttemptIds) (await updateCommandAsync(id, { status: "canceled", error: `superseded by continuation generation ${current}` }));
|
|
19
20
|
}
|