@humwick/server 0.130.2 → 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/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/workflows.md +16 -0
- package/docs/openapi.json +73 -4
- package/package.json +8 -7
- package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
- package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
- package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
- package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
- package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
- package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
- package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +28 -28
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +2 -1
- package/runner/src/runner-core.ts +14 -15
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +3 -3
- package/src/branch-landed.ts +25 -23
- package/src/bus.ts +21 -19
- package/src/cd-deploy-notify.ts +2 -2
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +3 -3
- package/src/ci/transition-notify.ts +5 -5
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/workflow.ts +12 -3
- package/src/commands-db.ts +4 -4
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +2 -2
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agents-async.ts +8 -5
- package/src/db/agents.ts +15 -12
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuations.ts +4 -4
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -3
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-refs-async.ts +4 -1
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs.ts +8 -8
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +20 -2
- package/src/db/maintenance-job-runs-async.ts +2 -2
- package/src/db/maintenance-job-write-ops.ts +1 -1
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +18 -1
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +10 -4
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +41 -48
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/read-op-marshaling-fixtures.ts +18 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +4 -1
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +5 -3
- package/src/db/task-entity.ts +5 -4
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/token-db-write-ops.ts +2 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +6 -9
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +31 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +42 -46
- package/src/dev.ts +8 -3
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/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 +104 -98
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +3 -3
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/jobs.ts +29 -67
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +18 -13
- package/src/maintenance/stalled-delivery-pager.ts +4 -4
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +17 -27
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +3 -3
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +8 -8
- package/src/mcp/output-descriptions.ts +1 -1
- package/src/mcp/presentation.ts +2 -1
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +3 -2
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +3 -3
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +1 -1
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +5 -3
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +2 -5
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +8 -1
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +4 -3
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +17 -119
- package/src/routes/auth.ts +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 +1 -1
- package/src/routes/commands.ts +29 -27
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +2 -1
- package/src/routes/integrations.ts +9 -7
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +3 -3
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +1 -1
- package/src/routes/orchestrator-host-registration.ts +2 -0
- package/src/routes/orchestrator-host-utilization.ts +2 -2
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +27 -18
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +1 -1
- package/src/routes/project-trust.ts +1 -1
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +1 -1
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/team-templates.ts +7 -7
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +18 -17
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +2 -2
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-push.ts +6 -6
- package/src/runtime-grant.ts +17 -11
- package/src/runtime-tokens.ts +20 -28
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +3 -1
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +1 -1
- package/src/server.ts +21 -22
- 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 +9 -9
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +4 -4
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +14 -13
- package/src/services/issue-refs.ts +4 -5
- package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +3 -3
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +6 -5
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +3 -3
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +1 -1
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +8 -3
- package/src/services/profile-trust.ts +2 -2
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +17 -16
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/send-message.ts +16 -33
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +12 -41
- package/src/services/spawn-chain-inspector.ts +1 -1
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +7 -8
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +3 -4
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +5 -5
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +22 -19
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +2 -1
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +1 -1
- package/src/services/workflow-effect-driver.ts +42 -19
- package/src/services/workflow-effects.ts +41 -27
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +1 -0
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +4 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +34 -22
- package/src/services/workflow-supervisor-state.ts +21 -1
- package/src/services/workflow-supervisor.ts +4 -3
- package/src/services/workspace-recovery.ts +4 -3
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-placement.ts +27 -9
- package/src/spawn-targets.ts +8 -8
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +61 -57
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +2 -2
- package/src/task-dispatch-live.ts +5 -2
- package/src/task-dispatcher.ts +2 -2
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +24 -16
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
- package/public/assets/provider-display-DsuWMvVL.js +0 -2
- package/public/assets/run-card-CpKqRbhg.js +0 -2
- package/public/assets/shipping-B9YtnwtG.js +0 -2
- package/public/assets/store-DcClXLH0.js +0 -9
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/src/db/on-loop-write-transaction.ts +0 -34
package/src/mcp/index.ts
CHANGED
|
@@ -239,7 +239,7 @@ async function callTool(auth: VerifiedMcpAuthContext, params: unknown, signal?:
|
|
|
239
239
|
else if (name === "relay_workspace_merge_resume") result = await relayWorkspaceMutation(auth, "resume-merge", args);
|
|
240
240
|
else if (name === "relay_red_main_recover") result = await relayRedMainRecover(auth, args);
|
|
241
241
|
else if (name === "relay_workspace_release") result = await relayWorkspaceMutation(auth, "release-claim", args);
|
|
242
|
-
else if (name.startsWith("relay_merge_")) result = relayMergeTool(auth, name, args); else if (name.startsWith("relay_maintenance_")) result = await relayMaintenanceTool(auth, name, args); else if (name.startsWith("relay_team_")) result = await relayTeamTool(auth, name, args); else if (name === "relay_decision") result = relayDecisionTool(auth, args);
|
|
242
|
+
else if (name.startsWith("relay_merge_")) result = (await relayMergeTool(auth, name, args)); else if (name.startsWith("relay_maintenance_")) result = await relayMaintenanceTool(auth, name, args); else if (name.startsWith("relay_team_")) result = await relayTeamTool(auth, name, args); else if (name === "relay_decision") result = (await relayDecisionTool(auth, args));
|
|
243
243
|
else if (name.startsWith("relay_plan_")) result = await relayPlanTool(auth, name, args);
|
|
244
244
|
else if (name === "relay_task_deliver") result = await relayTaskDeliverTool(auth, name, args);
|
|
245
245
|
else if (TASK_VALIDATION_TOOLS.some((tool) => tool.name === name)) result = await relayTaskValidationTool(auth, name, args);
|
|
@@ -252,16 +252,16 @@ async function callTool(auth: VerifiedMcpAuthContext, params: unknown, signal?:
|
|
|
252
252
|
else if (name === "relay_task_comment" || name === "relay_task_close_bridge") result = await relayTaskWeaveTool(auth, name, args);
|
|
253
253
|
else if (name === "relay_release_readiness") result = await relayReleaseTool(name, args);
|
|
254
254
|
else if (name.startsWith("relay_task_")) result = await relayTaskTool(auth, name, args);
|
|
255
|
-
else if (name.startsWith("relay_blackboard_")) result = relayBlackboardTool(auth, name, args);
|
|
255
|
+
else if (name.startsWith("relay_blackboard_")) result = (await relayBlackboardTool(auth, name, args));
|
|
256
256
|
// #2591 — the journal tools must claim their prefix BEFORE the generic relay_project_
|
|
257
257
|
// dispatcher, or they would fall through to relayProjectTool as "unknown tool".
|
|
258
|
-
else if (name.startsWith("relay_project_journal_")) result = relayProjectJournalTool(auth, name, args);
|
|
259
|
-
else if (name === "relay_project_ingest_claudemd") result = await relayProjectIngestClaudeMd(auth, args); else if (name.startsWith("relay_project_")) result = await relayProjectTool(auth, name, args); else if (name.startsWith("relay_issue_ref_")) result = await relayIssueRefTool(auth, name, args); else if (name.startsWith("relay_issue_association_")) result = relayIssueAssociationTool(auth, name, args); else if (name.startsWith("relay_issue_activity_")) result = await relayIssueActivityTool(auth, name, args); else if (name.startsWith("relay_issue_lifecycle_")) result = await relayIssueLifecycleTool(auth, name, args);
|
|
258
|
+
else if (name.startsWith("relay_project_journal_")) result = (await relayProjectJournalTool(auth, name, args));
|
|
259
|
+
else if (name === "relay_project_ingest_claudemd") result = await relayProjectIngestClaudeMd(auth, args); else if (name.startsWith("relay_project_")) result = await relayProjectTool(auth, name, args); else if (name.startsWith("relay_issue_ref_")) result = await relayIssueRefTool(auth, name, args); else if (name.startsWith("relay_issue_association_")) result = (await relayIssueAssociationTool(auth, name, args)); else if (name.startsWith("relay_issue_activity_")) result = await relayIssueActivityTool(auth, name, args); else if (name.startsWith("relay_issue_lifecycle_")) result = await relayIssueLifecycleTool(auth, name, args);
|
|
260
260
|
else if (name === "relay_subscribe" || name === "relay_unsubscribe" || name === "relay_list_subscriptions" || name === "relay_why_notified" || name === "relay_notification_preview") result = await relayNotificationSubscriptionTool(auth, name, args);
|
|
261
|
-
else if (name === "relay_notify_ntfy") result = relayNotifyNtfy(args);
|
|
261
|
+
else if (name === "relay_notify_ntfy") result = (await relayNotifyNtfy(args));
|
|
262
262
|
else if (name === "relay_delete_channel_binding") result = await relayDeleteChannelBinding(args, auth);
|
|
263
263
|
else if (name === "relay_channel_output") result = await relayChannelOutput(args, auth);
|
|
264
|
-
else if (name === "relay_send_to_channel") result = relayEgressToChannel(args, auth);
|
|
264
|
+
else if (name === "relay_send_to_channel") result = (await relayEgressToChannel(args, auth));
|
|
265
265
|
else throw new ValidationError(`unknown tool: ${wireName}`);
|
|
266
266
|
|
|
267
267
|
return toolResult(presentToolOutput(name, result, verbosity, args));
|
|
@@ -295,9 +295,9 @@ async function visibleTools(auth: McpAuthContext, generation: ToolGeneration): P
|
|
|
295
295
|
alwaysOn: auth.component?.role === "provider" && Boolean(constraints.profile || auth.component.sub.startsWith("runner:")),
|
|
296
296
|
allowUnknownGroups: true,
|
|
297
297
|
})
|
|
298
|
-
: null;
|
|
298
|
+
: auth.component?.role === "provider" ? resolveRelayTools({}, { alwaysOn: false }) : null;
|
|
299
299
|
if (auth.component?.role === "provider") {
|
|
300
|
-
for (const name of
|
|
300
|
+
for (const name of resolveRelayTools({ groups: [SELF_CARE_TOOL_GROUP] }, { alwaysOn: false })) allowedNames?.add(name);
|
|
301
301
|
}
|
|
302
302
|
// #1570 — an explicit per-tool allowlist narrows the surface further (still ∩ scopes ∩ groups). This
|
|
303
303
|
// is the Codex-worker provider-split: it trims the always-loaded MCP set the client eager-loads every
|
|
@@ -63,7 +63,7 @@ export const OUTPUT_DESCRIPTIONS: Record<string, string> = {
|
|
|
63
63
|
relay_why_notified: "Explain delivery.",
|
|
64
64
|
relay_workflow_cancel: "Cancel run; reap agents.",
|
|
65
65
|
relay_workflow_get: "Read run status; history opt-in.",
|
|
66
|
-
relay_workflow_resume: "Resume, pause/unpause, or answer
|
|
66
|
+
relay_workflow_resume: "Resume, pause/unpause, re-pin, or answer decisions.",
|
|
67
67
|
relay_workflow_start: "Start Task workflow.",
|
|
68
68
|
relay_workspace_deps: "Check or refresh workspace dependencies.",
|
|
69
69
|
relay_workspace_list: "List workspaces.",
|
package/src/mcp/presentation.ts
CHANGED
|
@@ -228,6 +228,7 @@ export function projectSpawnTargets(
|
|
|
228
228
|
},
|
|
229
229
|
baseline: matrix.baseline,
|
|
230
230
|
orchestrators: matrix.orchestrators,
|
|
231
|
+
...(matrix.apiBudgets ? { apiBudgets: matrix.apiBudgets } : {}),
|
|
231
232
|
// #2656 — operator-disabled providers are absent from the matrix; name them so callers know why.
|
|
232
233
|
...(Array.isArray(full.disabledProviders) ? { disabledProviders: full.disabledProviders } : {}),
|
|
233
234
|
// Profile prose stays in verbose; daily discovery needs only the spawnable names (#3594).
|
|
@@ -238,7 +239,7 @@ export function projectSpawnTargets(
|
|
|
238
239
|
target: routingTargetLabel(asRecord(rule.target)),
|
|
239
240
|
})),
|
|
240
241
|
},
|
|
241
|
-
guidance: "
|
|
242
|
+
guidance: "Default to isSelf; use named profiles and spawnRequestId for idempotency.",
|
|
242
243
|
};
|
|
243
244
|
}
|
|
244
245
|
|
|
@@ -27,7 +27,7 @@ export const RUNTIME_OUTPUT: Record<string, OutputProjection> = {
|
|
|
27
27
|
relay_spawn_targets: [],
|
|
28
28
|
relay_channel_output: [],
|
|
29
29
|
relay_claude_api_budget: [],
|
|
30
|
-
relay_routing_policy_get: [],
|
|
30
|
+
relay_routing_policy_get: [{ path: "diagnostics", brief: null, lean: null }],
|
|
31
31
|
relay_service_access: [],
|
|
32
32
|
relay_list_timers: ["body", "command.stdoutTail", "command.stderrTail"].map(path => ({ path: `timers.*.${path}`, brief: 160 })),
|
|
33
33
|
relay_list_artifacts: [{ path: "artifacts.*.links.*.title", brief: null }],
|
|
@@ -74,6 +74,11 @@ function jobSummary(job: MaintenanceJob, verbosity: OutputVerbosity): Record<str
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
export function projectRuntimeOutput(name: string, result: unknown, verbosity: OutputVerbosity): unknown {
|
|
77
|
+
// Migration provenance is already exposed by diagnostics; never send the notes twice (#3828).
|
|
78
|
+
if (name === "relay_routing_policy_get" && isRecord(result) && isRecord(result.policy)) {
|
|
79
|
+
const { migration, ...policy } = result.policy;
|
|
80
|
+
return { ...result, policy };
|
|
81
|
+
}
|
|
77
82
|
if (name !== "relay_maintenance_jobs" || verbosity === "verbose" || !isRecord(result)) return result;
|
|
78
83
|
if (verbosity === "brief" && isRecord(result.job)) return { job: jobSummary(result.job as unknown as MaintenanceJob, verbosity) };
|
|
79
84
|
if (!Array.isArray(result.jobs)) return result;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isRecord } from "@humwick/sdk";
|
|
2
2
|
import type { AgentCard, ComponentToken } from "../types";
|
|
3
3
|
import { hasComponentScope } from "../security";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveRelayTools, SELF_CARE_TOOL_GROUP } from "./tool-groups";
|
|
5
5
|
|
|
6
6
|
export function supportsSelfResume(agent: AgentCard | null): boolean {
|
|
7
7
|
const context = agent?.providerCapabilities?.context;
|
|
@@ -17,7 +17,7 @@ export function canDiscoverSelfResume(agent: AgentCard | null, token: ComponentT
|
|
|
17
17
|
const constraints = token.constraints;
|
|
18
18
|
const selection = { groups: constraints?.toolGroups, include: constraints?.toolInclude, exclude: constraints?.toolExclude };
|
|
19
19
|
const tools = resolveRelayTools(selection, { alwaysOn: token.role === "provider" && Boolean(constraints?.profile || token.sub.startsWith("runner:")), allowUnknownGroups: true });
|
|
20
|
-
if (token.role === "provider") for (const name of
|
|
20
|
+
if (token.role === "provider") for (const name of resolveRelayTools({ groups: [SELF_CARE_TOOL_GROUP] }, { alwaysOn: false })) tools.add(name);
|
|
21
21
|
if (!tools.has("relay_compact_and_resume")) return false;
|
|
22
22
|
return !constraints?.toolAllowlist || constraints.toolAllowlist.includes("relay_compact_and_resume");
|
|
23
23
|
}
|
|
@@ -31,7 +31,16 @@ export function projectSpawnTargetMatrix(full: Record<string, unknown>, enrich?:
|
|
|
31
31
|
const baseline = choices.map(({ value }) => value);
|
|
32
32
|
return {
|
|
33
33
|
self: { orchestratorId: stringOrNull(self.orchestratorId), host: stringOrNull(self.host) },
|
|
34
|
-
...(Array.isArray(full.apiBudgets) ? { apiBudgets: full.apiBudgets
|
|
34
|
+
...(Array.isArray(full.apiBudgets) ? { apiBudgets: asRecords(full.apiBudgets).map((budget) => ({
|
|
35
|
+
budgetId: budget.budgetId, source: budget.source, month: budget.month,
|
|
36
|
+
headroomMicroUsd: budget.headroomMicroUsd,
|
|
37
|
+
...(budget.baselineKnown ? {
|
|
38
|
+
startsAt: budget.startsAt, endsAt: budget.endsAt,
|
|
39
|
+
ceilingMicroUsd: budget.ceilingMicroUsd, estimatedSpentMicroUsd: budget.estimatedSpentMicroUsd,
|
|
40
|
+
enabled: budget.enabled,
|
|
41
|
+
...(budget.refusalReason ? { refusalReason: budget.refusalReason } : {}),
|
|
42
|
+
} : {}),
|
|
43
|
+
})) } : {}),
|
|
35
44
|
...(Array.isArray(full.disabledProviders) ? { disabledProviders: full.disabledProviders } : {}),
|
|
36
45
|
baseline: choices.map(({ value, original }) => ({ ...value, ...enrich?.(original) })),
|
|
37
46
|
orchestrators: hosts.map(({ host, providers }) => {
|
package/src/mcp/tool-groups.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { memoryRetirementMessage } from "../memory-retirement";
|
|
2
2
|
import { registryToolName, type AgentProfile } from "@humwick/sdk";
|
|
3
|
+
import { ASSIGNED_RELAY_TOOLS } from "./tool-roles";
|
|
3
4
|
|
|
4
5
|
// Tool group membership (#551). Each tool belongs to exactly one group; toolGroups in the token
|
|
5
6
|
// constraints lists which groups are enabled (absent = all). This is the surface/eager layer on
|
|
@@ -93,11 +94,11 @@ export function resolveRelayTools(selection: AgentProfile["relay"]["tools"] = {}
|
|
|
93
94
|
if (!RELAY_TOOL_NAMES.has(registryToolName(name))) throw new Error(memoryRetirementMessage(registryToolName(name)) ?? `${field}: unknown Relay tool "${name}"`);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
|
-
const tools = new Set((selection.groups ?? Object.keys(RELAY_TOOL_GROUPS)).flatMap((group) => (RELAY_TOOL_GROUPS[group] ?? [])));
|
|
97
|
+
const tools = new Set((selection.groups ?? Object.keys(RELAY_TOOL_GROUPS)).flatMap((group) => (RELAY_TOOL_GROUPS[group] ?? [])).filter(name => ASSIGNED_RELAY_TOOLS.has(name)));
|
|
97
98
|
for (const name of selection.include ?? []) tools.add(registryToolName(name));
|
|
98
99
|
for (const name of selection.exclude ?? []) tools.delete(registryToolName(name));
|
|
99
100
|
for (const group of options.alwaysOn !== false ? ["core", SELF_CARE_TOOL_GROUP] : []) {
|
|
100
|
-
for (const name of RELAY_TOOL_GROUPS[group]!) tools.add(name);
|
|
101
|
+
for (const name of RELAY_TOOL_GROUPS[group]!) if (ASSIGNED_RELAY_TOOLS.has(name)) tools.add(name);
|
|
101
102
|
}
|
|
102
103
|
return tools;
|
|
103
104
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { AgentProfile } from "@humwick/sdk";
|
|
2
|
+
|
|
3
|
+
// Explicit names, never registry/group expansion: adding a tool must not grow a role (#3817).
|
|
4
|
+
const COMMON_READ = ["relay_guide", "relay_whoami", "relay_get_message", "relay_get_thread", "relay_find_agents", "relay_task_get", "relay_recall", "web_search"];
|
|
5
|
+
const COMMON_WRITE = ["relay_secret_request", "relay_send_message", "relay_reply", "relay_task_deliver", "relay_compact_and_resume", "relay_run", "relay_schedule_timer"];
|
|
6
|
+
const MEMORY_READ = ["relay_project_read", "relay_project_search"];
|
|
7
|
+
const MEMORY_WRITE = ["relay_project_write_entry", "relay_project_retract"];
|
|
8
|
+
const ARTIFACT_READ = ["relay_list_artifacts", "relay_read_artifact"];
|
|
9
|
+
const ARTIFACT_WRITE = ["relay_upload_artifact", "relay_attach_artifact", "relay_pin_artifact"];
|
|
10
|
+
const TEAM_READ = ["relay_blackboard_get", "relay_blackboard_read", "relay_blackboard_search"];
|
|
11
|
+
const TEAM_WRITE = ["relay_blackboard_write", "relay_blackboard_retract"];
|
|
12
|
+
const TASK_READ = ["relay_task_list", "relay_task_history", "relay_task_memory_read"];
|
|
13
|
+
const PLAN_READ = ["relay_plan_get", "relay_plan_list", "relay_plan_conformance"];
|
|
14
|
+
const WORKSPACE_READ = ["relay_workspace_status", "relay_workspace_deps"];
|
|
15
|
+
const TIMER_READ = ["relay_list_timers"];
|
|
16
|
+
const TIMER_WRITE = ["relay_schedule_timer", "relay_cancel_timer"];
|
|
17
|
+
const WORK_READ = [...MEMORY_READ, ...ARTIFACT_READ, ...TEAM_READ, ...WORKSPACE_READ, ...TASK_READ, ...PLAN_READ, "relay_workflow_get"];
|
|
18
|
+
const WORK_WRITE = [...MEMORY_WRITE, ...ARTIFACT_WRITE, ...TEAM_WRITE];
|
|
19
|
+
const PLAN_WRITE = ["relay_plan_import", "relay_plan_create", "relay_plan_add_node", "relay_plan_update_node", "relay_plan_add_edge", "relay_plan_remove_node", "relay_plan_remove_edge", "relay_plan_archive", "relay_plan_delete", "relay_plan_bind_node", "relay_plan_start"];
|
|
20
|
+
const TASK_WRITE = ["relay_task_set_validation", "relay_task_needs_validation", "relay_task_create", "relay_task_update", "relay_task_set_status", "relay_task_set_stage", "relay_task_set_review_hold", "relay_task_withdraw_land", "relay_task_confirm_carry", "relay_task_record_gate", "relay_task_add_dependency", "relay_task_remove_dependency", "relay_task_add_ref", "relay_task_remove_ref", "relay_task_assign_agent", "relay_task_memory_replace_working_state", "relay_task_memory_append_ruled_out", "relay_task_memory_append_decision", "relay_task_dispatch", "relay_backlog_promote", "relay_task_comment", "relay_task_close_bridge"];
|
|
21
|
+
const SPAWN_READ = ["relay_spawn_targets", "relay_my_agents", "relay_agent_status", "relay_agent_crash_report", "relay_team_get"];
|
|
22
|
+
const SPAWN_WRITE = ["relay_spawn_agent", "relay_shutdown_agent", "relay_interrupt_agent", "relay_agent_keep", "relay_agent_action", "relay_permission_decision", "relay_team_set_spawn_delegation", "relay_team_set_brief", "relay_team_claim", "relay_team_dissolve"];
|
|
23
|
+
const WORKFLOW_WRITE = ["relay_workflow_start", "relay_workflow_resume", "relay_workflow_cancel"];
|
|
24
|
+
|
|
25
|
+
function role(why: string, read: readonly string[] = [], write: readonly string[] = []) {
|
|
26
|
+
return { why, read: [...new Set([...COMMON_READ, ...read])].sort(), write: [...new Set([...COMMON_WRITE, ...write])].sort() };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const implementer = role("Implement and deliver the hydrated bound Task. Bounded waits use relay_run.", [...MEMORY_READ, ...ARTIFACT_READ, ...TEAM_READ, ...WORKSPACE_READ], [...WORK_WRITE, "relay_set_effort"]);
|
|
30
|
+
const quality = role("Read Tasks and plans, execute checks and deliver findings; report through the bound Task.", WORK_READ, [...WORK_WRITE, ...TIMER_WRITE]);
|
|
31
|
+
const research = role("Research and report; keep findings and artifacts without workspace or orchestration administration.", [...MEMORY_READ, ...TEAM_READ, ...ARTIFACT_READ, "relay_web_tool_calls"], [...MEMORY_WRITE, ...TEAM_WRITE, ...ARTIFACT_WRITE]);
|
|
32
|
+
|
|
33
|
+
export const RELAY_TOOL_ROLES: Readonly<Record<string, ReturnType<typeof role>>> = {
|
|
34
|
+
coordinator: role("Own plan, Task, workflow and team lifecycle; request service access and delegate broker setup and operational work to specialists.",
|
|
35
|
+
[...WORK_READ, ...SPAWN_READ, ...TIMER_READ, "relay_backlog", "relay_release_readiness", "relay_hosts", "relay_merge_pauses", "relay_routing_policy_get", "relay_project_list", "relay_project_get", "relay_project_journal_get", "relay_team_template_list", "relay_team_template_get"],
|
|
36
|
+
[...WORK_WRITE, ...PLAN_WRITE, ...TASK_WRITE, ...SPAWN_WRITE, ...WORKFLOW_WRITE, ...TIMER_WRITE, "relay_decision", "relay_set_effort", "relay_service_access", "relay_red_main_recover", "relay_merge_pause", "relay_merge_renew", "relay_merge_resume", "relay_workspace_merge_hold", "relay_workspace_merge_resume", "relay_host_gate_budget", "relay_routing_policy_set", "relay_project_profile_instructions", "relay_prompt", "relay_project_onboard", "relay_project_checkout", "relay_project_add_root", "relay_project_add_edge", "relay_project_remove_edge", "relay_project_archive", "relay_project_promote_entry", "relay_project_ingest_claudemd", "relay_project_journal_update", "relay_team_template_save", "relay_team_template_delete", "relay_team_spawn_from_template"]),
|
|
37
|
+
"sub-coordinator": role("Coordinate a delegated project and its plan/workflow; parent owns fleet routing and project administration.",
|
|
38
|
+
[...WORK_READ, ...SPAWN_READ, ...TIMER_READ],
|
|
39
|
+
[...WORK_WRITE, ...PLAN_WRITE, ...WORKFLOW_WRITE, ...TIMER_WRITE, "relay_decision", "relay_set_effort", "relay_spawn_agent", "relay_shutdown_agent", "relay_interrupt_agent", "relay_agent_keep", "relay_agent_action", "relay_permission_decision", "relay_team_set_brief", "relay_team_dissolve", "relay_task_create", "relay_task_update", "relay_task_set_status", "relay_task_set_review_hold", "relay_task_withdraw_land", "relay_task_record_gate", "relay_task_add_dependency", "relay_task_remove_dependency", "relay_task_add_ref", "relay_task_remove_ref", "relay_task_assign_agent", "relay_task_memory_replace_working_state", "relay_task_memory_append_ruled_out", "relay_task_memory_append_decision", "relay_task_dispatch", "relay_task_comment"]),
|
|
40
|
+
worker: implementer,
|
|
41
|
+
"worker-gui": role("Implement GUI work from the hydrated Task and return artifacts; inspect its workspace.", [...MEMORY_READ, ...ARTIFACT_READ, ...WORKSPACE_READ], [...MEMORY_WRITE, ...ARTIFACT_WRITE, "relay_set_effort"]),
|
|
42
|
+
debugger: implementer,
|
|
43
|
+
reviewer: quality,
|
|
44
|
+
QA: quality,
|
|
45
|
+
"device-qa": quality,
|
|
46
|
+
"slice-qa": quality,
|
|
47
|
+
"plan-auditor": quality,
|
|
48
|
+
probe: role("Run a bounded proof and return its result; no project or workspace administration."),
|
|
49
|
+
"image-gen": role("Generate and deliver image artifacts for a bound Task.", [...MEMORY_READ, ...ARTIFACT_READ, ...WORKSPACE_READ], [...MEMORY_WRITE, ...ARTIFACT_WRITE]),
|
|
50
|
+
"software-design": role("Inspect architecture, Tasks and plans and deliver a design; coordinator authors orchestration.", WORK_READ, WORK_WRITE),
|
|
51
|
+
brainstorm: research,
|
|
52
|
+
explorer: research,
|
|
53
|
+
"isolated-research": research,
|
|
54
|
+
"social-media": role("Research and prepare channel output; no team or Task administration.", [...MEMORY_READ, ...ARTIFACT_READ, "relay_web_tool_calls"], [...MEMORY_WRITE, ...ARTIFACT_WRITE, "relay_channel_output", "relay_send_to_channel"]),
|
|
55
|
+
"ops-assistant": role("Operate gates, maintenance and delivery; inspect agent health without spawning or planning.",
|
|
56
|
+
[...MEMORY_READ, ...ARTIFACT_READ, ...WORKSPACE_READ, ...TIMER_READ, "relay_hosts", "relay_agent_status", "relay_agent_crash_report", "relay_maintenance_jobs", "relay_maintenance_pauses", "relay_merge_pauses", "relay_workspace_list", "relay_release_readiness"],
|
|
57
|
+
[...MEMORY_WRITE, ...ARTIFACT_WRITE, ...TIMER_WRITE, "relay_maintenance_pause", "relay_maintenance_resume", "relay_merge_pause", "relay_merge_renew", "relay_merge_resume", "relay_workspace_claim", "relay_workspace_release", "relay_workspace_merge_hold", "relay_workspace_merge_resume", "relay_red_main_recover", "relay_set_effort"]),
|
|
58
|
+
"sec-ops": role("Audit security and manage broker access; no orchestration or fleet mutation.",
|
|
59
|
+
[...MEMORY_READ, ...ARTIFACT_READ, ...WORKSPACE_READ, "relay_hosts", "relay_web_tool_calls"], [...MEMORY_WRITE, ...ARTIFACT_WRITE, "relay_service_access", "relay_secret_reader_create", "relay_secret_project_create", "relay_secret_set", "relay_notify_ntfy"]),
|
|
60
|
+
// These require admin/control tokens, not provider-agent grants. No hub agent profile is created.
|
|
61
|
+
operator: role("Operator/control-client tools that cannot be conferred by an agent profile.",
|
|
62
|
+
["relay_kernel_listInstances", "relay_kernel_getInstance", "relay_kernel_getJournal", "relay_kernel_listEvents", "relay_kernel_listEntities", "relay_kernel_getEntity", "relay_issue_ref_get", "relay_issue_ref_list", "relay_issue_association_list_issues_for_entity", "relay_issue_association_list_entities_for_issue", "relay_issue_activity_by_issue", "relay_issue_activity_by_agent", "relay_list_subscriptions", "relay_why_notified", "relay_notification_preview"],
|
|
63
|
+
["relay_kernel_cancel", "relay_kernel_pause", "relay_kernel_resume", "relay_kernel_retry", "relay_profile_trust", "relay_codex_reset_consume", "relay_claude_api_budget", "relay_delete_channel_binding", "relay_issue_ref_upsert", "relay_issue_ref_resolve", "relay_issue_ref_update", "relay_issue_ref_delete", "relay_issue_association_associate", "relay_issue_association_remove", "relay_issue_activity_record", "relay_issue_lifecycle_reopen", "relay_subscribe", "relay_unsubscribe", "relay_notify_ntfy", "relay_reevaluate_channel_delivery"]),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const ASSIGNED_RELAY_TOOLS: ReadonlySet<string> = new Set(Object.values(RELAY_TOOL_ROLES).flatMap(role => [...role.read, ...role.write]));
|
|
67
|
+
|
|
68
|
+
/** Exact includes keep later group additions out of already-curated profiles. */
|
|
69
|
+
export function relayRoleSelection(name: string): NonNullable<AgentProfile["relay"]["tools"]> {
|
|
70
|
+
const assignment = RELAY_TOOL_ROLES[name];
|
|
71
|
+
if (!assignment) throw new Error(`No Relay tool role for profile ${name}`);
|
|
72
|
+
return { groups: [], include: [...new Set([...assignment.read, ...assignment.write])].sort(), exclude: [] };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function relayToolRoleErrors(registered: readonly string[]): string[] {
|
|
76
|
+
const names = new Set(registered);
|
|
77
|
+
return [
|
|
78
|
+
...registered.filter(name => !ASSIGNED_RELAY_TOOLS.has(name)).map(name => `${name}: assign this Relay tool to at least one role in src/mcp/tool-roles.ts`),
|
|
79
|
+
...[...ASSIGNED_RELAY_TOOLS].filter(name => !names.has(name)).map(name => `${name}: role assignment names an unregistered Relay tool`),
|
|
80
|
+
];
|
|
81
|
+
}
|
|
@@ -238,7 +238,7 @@ export async function relayWorkspaceMutation(auth: McpAuthContext, action: Works
|
|
|
238
238
|
payload.guidance = describeWorkspacePhase(result.workspace);
|
|
239
239
|
// Legacy workspace-ready route/CLI path is an explicit, platform-owned completion signal: the caller
|
|
240
240
|
// is declaring its work window closed. Close it, forwarding only the held final group.
|
|
241
|
-
markAgentWorkFinal(result.workspace.ownerAgentId ?? callerAgentId(auth), "workspace-ready");
|
|
241
|
+
(await markAgentWorkFinal(result.workspace.ownerAgentId ?? callerAgentId(auth), "workspace-ready"));
|
|
242
242
|
}
|
|
243
243
|
return payload;
|
|
244
244
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { writeEntryAsync, retractEntryAsync } from "./db/runtime-tail-async";
|
|
2
|
+
import { getAgent, getEntry, getEntryChain, listEntries, searchEntries, ValidationError } from "./db";
|
|
2
3
|
import { McpNotFoundError } from "./mcp-errors";
|
|
3
4
|
import { authContextFromMcp } from "./services/auth-context";
|
|
4
5
|
import { cleanString, cleanStringArray, optionalEnum } from "./validation";
|
|
@@ -92,14 +93,14 @@ function ensureSameTeam(entryId: string, teamId: string): void {
|
|
|
92
93
|
if (entry.teamId !== teamId) throw new McpNotFoundError("blackboard entry not found");
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
export function relayBlackboardTool(auth: McpAuthLike, name: string, args: Record<string, unknown>): Record<string, unknown
|
|
96
|
+
export async function relayBlackboardTool(auth: McpAuthLike, name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
96
97
|
const { agentId, teamId } = callerTeam(auth);
|
|
97
98
|
if (name === "relay_blackboard_write") {
|
|
98
99
|
const supersedes = cleanString(args.supersedes, "supersedes", { max: 120 });
|
|
99
100
|
const kind = cleanKind(args.kind);
|
|
100
101
|
if (!kind) throw new ValidationError("kind required");
|
|
101
102
|
if (supersedes) ensureSameTeam(supersedes, teamId);
|
|
102
|
-
return
|
|
103
|
+
return (await writeEntryAsync({
|
|
103
104
|
teamId,
|
|
104
105
|
authorId: agentId,
|
|
105
106
|
kind,
|
|
@@ -107,7 +108,7 @@ export function relayBlackboardTool(auth: McpAuthLike, name: string, args: Recor
|
|
|
107
108
|
body: cleanString(args.body, "body", { max: 16_000 }),
|
|
108
109
|
tags: cleanStringArray(args.tags, "tags", { itemMax: 80, maxItems: 32 }),
|
|
109
110
|
supersedes,
|
|
110
|
-
}) as unknown as Record<string, unknown>;
|
|
111
|
+
})) as unknown as Record<string, unknown>;
|
|
111
112
|
}
|
|
112
113
|
if (name === "relay_blackboard_get") {
|
|
113
114
|
const id = cleanString(args.id, "id", { required: true, max: 120 })!;
|
|
@@ -123,7 +124,7 @@ export function relayBlackboardTool(auth: McpAuthLike, name: string, args: Recor
|
|
|
123
124
|
if (name === "relay_blackboard_retract") {
|
|
124
125
|
const id = cleanString(args.id, "id", { required: true, max: 120 })!;
|
|
125
126
|
ensureSameTeam(id, teamId);
|
|
126
|
-
const entry =
|
|
127
|
+
const entry = (await retractEntryAsync(id));
|
|
127
128
|
if (!entry) throw new McpNotFoundError("blackboard entry not found");
|
|
128
129
|
return entry as unknown as Record<string, unknown>;
|
|
129
130
|
}
|
|
@@ -66,16 +66,16 @@ function requiredId(args: Record<string, unknown>): number {
|
|
|
66
66
|
return id;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function run(auth: McpAuthLike, args: Record<string, unknown>): Record<string, unknown
|
|
69
|
+
async function run(auth: McpAuthLike, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
70
70
|
const ctx = authContextFromMcp(auth);
|
|
71
71
|
const action = cleanEnum(args.action, "action", ACTIONS);
|
|
72
72
|
if (action === "file") {
|
|
73
|
-
const decision = fileDecision(ctx, args, callerProjectId(ctx));
|
|
73
|
+
const decision = (await fileDecision(ctx, args, callerProjectId(ctx)));
|
|
74
74
|
return { id: decision.id, kind: decision.kind, status: decision.status, teamId: decision.teamId };
|
|
75
75
|
}
|
|
76
|
-
if (action === "update") return { id: updateDecision(ctx, requiredId(args), args).id, status: "open" };
|
|
77
|
-
if (action === "withdraw") return { id: withdrawDecision(ctx, requiredId(args)).id, status: "withdrawn" };
|
|
78
|
-
const teamId = callerDecisionTeam(ctx, false);
|
|
76
|
+
if (action === "update") return { id: (await updateDecision(ctx, requiredId(args), args)).id, status: "open" };
|
|
77
|
+
if (action === "withdraw") return { id: (await withdrawDecision(ctx, requiredId(args))).id, status: "withdrawn" };
|
|
78
|
+
const teamId = (await callerDecisionTeam(ctx, false));
|
|
79
79
|
const id = optionalPositiveInt(args.id, "id");
|
|
80
80
|
if (id !== undefined) return { decision: teamDecision(teamId, id) };
|
|
81
81
|
const status = optionalEnum(args.status, "status", [...OPERATOR_DECISION_STATUSES, "all"] as const, "open");
|
|
@@ -84,9 +84,9 @@ function run(auth: McpAuthLike, args: Record<string, unknown>): Record<string, u
|
|
|
84
84
|
return { lines: decisions.map((decision) => renderDecisionLine(decision)) };
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
export function relayDecisionTool(auth: McpAuthLike, args: Record<string, unknown>): Record<string, unknown
|
|
87
|
+
export async function relayDecisionTool(auth: McpAuthLike, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
88
88
|
try {
|
|
89
|
-
return run(auth, args);
|
|
89
|
+
return (await run(auth, args));
|
|
90
90
|
} catch (error) {
|
|
91
91
|
if (error instanceof ServiceAuthError) throw new McpAuthError(error.message);
|
|
92
92
|
if (error instanceof DecisionNotFoundError) throw new McpNotFoundError(error.message);
|
package/src/mcp-egress-tools.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sendMessageWithResultAsync } from "./db/message-send";
|
|
1
2
|
// Generic egress MCP tool + relay_notify_ntfy shim (#777).
|
|
2
3
|
//
|
|
3
4
|
// relay_send_to_channel — resolves a registered channel agent by ID, builds a
|
|
@@ -15,7 +16,7 @@ import { channelOutputControl, changeChannelOutput } from "./channel-output-cont
|
|
|
15
16
|
import { McpAuthError } from "./mcp-errors";
|
|
16
17
|
import { isComponentAuthorizedFor, isIntegrationAllowed } from "./security";
|
|
17
18
|
import { MAX_BODY_BYTES } from "./config";
|
|
18
|
-
import { channelObligationAnsweredBy, getChannel,
|
|
19
|
+
import { channelObligationAnsweredBy, getChannel, ValidationError } from "./db";
|
|
19
20
|
import { validateChannelEnvelope } from "./routes/integrations";
|
|
20
21
|
import { emitNewMessage } from "./sse";
|
|
21
22
|
import { optionalEnum } from "./validation";
|
|
@@ -91,12 +92,12 @@ function egressBodyForEvent(event: Record<string, unknown>): string {
|
|
|
91
92
|
return serialized;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
function emitChannelEgress(
|
|
95
|
+
async function emitChannelEgress(
|
|
95
96
|
channelId: string,
|
|
96
97
|
event: Record<string, unknown>,
|
|
97
98
|
callerId?: string,
|
|
98
99
|
idempotencyKey?: string,
|
|
99
|
-
): { accepted: boolean; channelId: string; to: string } {
|
|
100
|
+
): Promise<{ accepted: boolean; channelId: string; to: string }> {
|
|
100
101
|
const channel = getChannel(channelId);
|
|
101
102
|
if (!channel) throw new ValidationError(`channel ${channelId} not registered`);
|
|
102
103
|
if (channel.direction === "inbound") {
|
|
@@ -123,7 +124,7 @@ function emitChannelEgress(
|
|
|
123
124
|
// We DON'T route this through sendMessageService: that gate authorizes on message:send, but egress carries only channel:egress, so a component
|
|
124
125
|
// token would 403; the raw path preserves the channel:egress scope model.
|
|
125
126
|
const answeredObligation = callerId ? channelObligationAnsweredBy(callerId, channel.agentId) : null;
|
|
126
|
-
const { message, created } =
|
|
127
|
+
const { message, created } = (await sendMessageWithResultAsync({
|
|
127
128
|
from: callerId ?? "system",
|
|
128
129
|
to: channel.agentId,
|
|
129
130
|
kind: "channel.event",
|
|
@@ -132,19 +133,19 @@ function emitChannelEgress(
|
|
|
132
133
|
replyExpected: false,
|
|
133
134
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
134
135
|
...(answeredObligation !== null ? { replyTo: answeredObligation } : {}),
|
|
135
|
-
});
|
|
136
|
+
}));
|
|
136
137
|
if (created) emitNewMessage(message);
|
|
137
138
|
return { accepted: true, channelId, to: channel.agentId };
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
export function relayEgressToChannel(args: Record<string, unknown>, auth?: McpAuthContext, idempotencyKey?: string): { accepted: boolean; channelId: string; to: string } {
|
|
141
|
+
export async function relayEgressToChannel(args: Record<string, unknown>, auth?: McpAuthContext, idempotencyKey?: string): Promise<{ accepted: boolean; channelId: string; to: string }> {
|
|
141
142
|
const channelId = stringField(args.channelId, "channelId", { required: true, max: 200 });
|
|
142
143
|
const event = recordField(args.event, "event");
|
|
143
144
|
const callerId = auth ? callerAgentId(auth) : undefined;
|
|
144
|
-
return emitChannelEgress(channelId, event, callerId, idempotencyKey);
|
|
145
|
+
return (await emitChannelEgress(channelId, event, callerId, idempotencyKey));
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
export function relayNotifyNtfy(args: Record<string, unknown>, idempotencyKey?: string): { accepted: boolean; channelId: string } {
|
|
148
|
+
export async function relayNotifyNtfy(args: Record<string, unknown>, idempotencyKey?: string): Promise<{ accepted: boolean; channelId: string }> {
|
|
148
149
|
const title = stringField(args.title, "title", { required: true, max: 200 });
|
|
149
150
|
const body = stringField(args.body, "body", { required: true, maxBytes: MAX_BODY_BYTES });
|
|
150
151
|
const priority = optionalEnum(args.priority, "priority", NTFY_PRIORITIES) as NtfyPriority | undefined;
|
|
@@ -154,7 +155,7 @@ export function relayNotifyNtfy(args: Record<string, unknown>, idempotencyKey?:
|
|
|
154
155
|
if (priority !== undefined) event.priority = priority;
|
|
155
156
|
if (tags?.length) event.tags = tags;
|
|
156
157
|
if (click !== undefined) event.click = click;
|
|
157
|
-
const result = emitChannelEgress(NTFY_CHANNEL_ID, event, undefined, idempotencyKey);
|
|
158
|
+
const result = (await emitChannelEgress(NTFY_CHANNEL_ID, event, undefined, idempotencyKey));
|
|
158
159
|
return { accepted: result.accepted, channelId: result.channelId };
|
|
159
160
|
}
|
|
160
161
|
|
|
@@ -86,7 +86,7 @@ function limitArg(value: unknown): number | undefined {
|
|
|
86
86
|
|
|
87
87
|
export async function relayIssueActivityTool(_auth: IssueActivityToolAuth, name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
88
88
|
if (name === "relay_issue_activity_record") {
|
|
89
|
-
const event = recordAndEmitIssueActivity({
|
|
89
|
+
const event = (await recordAndEmitIssueActivity({
|
|
90
90
|
agentId: cleanString(args.agentId, "agentId", { required: true, max: 200 })!,
|
|
91
91
|
action: actionArg(args.action),
|
|
92
92
|
issueRefId: cleanString(args.issueRefId, "issueRefId", { max: 120 }),
|
|
@@ -97,7 +97,7 @@ export async function relayIssueActivityTool(_auth: IssueActivityToolAuth, name:
|
|
|
97
97
|
title: cleanString(args.title, "title", { max: 200 }),
|
|
98
98
|
body: cleanString(args.body, "body", { max: 1000 }),
|
|
99
99
|
metadata: cleanMeta(args.metadata),
|
|
100
|
-
});
|
|
100
|
+
}));
|
|
101
101
|
return { event };
|
|
102
102
|
}
|
|
103
103
|
if (name === "relay_issue_activity_by_issue") {
|
|
@@ -83,9 +83,9 @@ function associationInput(args: Record<string, unknown>) {
|
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
export function relayIssueAssociationTool(_auth: IssueAssociationToolAuth, name: string, args: Record<string, unknown>): Record<string, unknown
|
|
86
|
+
export async function relayIssueAssociationTool(_auth: IssueAssociationToolAuth, name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
87
87
|
if (!isRecord(args)) throw new ValidationError("arguments must be an object");
|
|
88
|
-
if (name === "relay_issue_association_associate") return associateIssueRef(associationInput(args)) as unknown as Record<string, unknown>;
|
|
88
|
+
if (name === "relay_issue_association_associate") return (await associateIssueRef(associationInput(args))) as unknown as Record<string, unknown>;
|
|
89
89
|
if (name === "relay_issue_association_list_issues_for_entity") {
|
|
90
90
|
return {
|
|
91
91
|
issues: listIssueRefsForEntity(
|
|
@@ -95,9 +95,9 @@ export function relayIssueAssociationTool(_auth: IssueAssociationToolAuth, name:
|
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
if (name === "relay_issue_association_list_entities_for_issue") {
|
|
98
|
-
const issueRef = resolveAssociationIssueRef(issueInput(args));
|
|
98
|
+
const issueRef = (await resolveAssociationIssueRef(issueInput(args)));
|
|
99
99
|
return { issueRef, entities: listIssueEntities(issueRef.id) };
|
|
100
100
|
}
|
|
101
|
-
if (name === "relay_issue_association_remove") return removeIssueAssociation(associationInput(args));
|
|
101
|
+
if (name === "relay_issue_association_remove") return (await removeIssueAssociation(associationInput(args)));
|
|
102
102
|
throw new ValidationError(`unknown tool: ${name}`);
|
|
103
103
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getIssueRef, getIssueRefByExternalKey, issueRefClosedCompleted, issueRefForRefString
|
|
2
|
-
import { deleteIssueRefAsync, resolveIssueRefByExternalKeyAsync, resolveIssueRefFromStringAsync, updateIssueRefAsync, upsertIssueRefAsync } from "./db/issue-refs-async";
|
|
1
|
+
import { getIssueRef, getIssueRefByExternalKey, issueRefClosedCompleted, issueRefForRefString } from "./db/issue-refs";
|
|
2
|
+
import { deleteIssueRefAsync, listIssueRefsAsync, resolveIssueRefByExternalKeyAsync, resolveIssueRefFromStringAsync, updateIssueRefAsync, upsertIssueRefAsync } from "./db/issue-refs-async";
|
|
3
3
|
import { McpNotFoundError } from "./mcp-errors";
|
|
4
4
|
import { cleanEnum, cleanString, optionalEnum } from "./validation";
|
|
5
5
|
import { ISSUE_REF_CLOSE_REASONS, ISSUE_PROVIDERS, ISSUE_REF_STATUSES, isRecord, type IssueProvider, type IssueRef, type IssueRefCloseReason, type IssueRefStatus } from "./types";
|
|
@@ -183,7 +183,7 @@ export async function relayIssueRefTool(_auth: IssueRefToolAuth, name: string, a
|
|
|
183
183
|
}
|
|
184
184
|
if (name === "relay_issue_ref_list") {
|
|
185
185
|
return {
|
|
186
|
-
issueRefs:
|
|
186
|
+
issueRefs: await listIssueRefsAsync({
|
|
187
187
|
provider: optionalEnum(args.provider, "provider", ISSUE_PROVIDERS) as IssueProvider | undefined,
|
|
188
188
|
repo: cleanString(args.repo, "repo", { max: 500 }),
|
|
189
189
|
status: statusArg(args.status),
|
package/src/mcp-merge-tools.ts
CHANGED
|
@@ -29,24 +29,24 @@ export const MERGE_TOOLS = [
|
|
|
29
29
|
|
|
30
30
|
type McpAuthLike = Parameters<typeof authContextFromMcp>[0];
|
|
31
31
|
|
|
32
|
-
export function relayMergeTool(auth: McpAuthLike, name: string, args: Record<string, unknown>): Record<string, unknown
|
|
32
|
+
export async function relayMergeTool(auth: McpAuthLike, name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {
|
|
33
33
|
const ctx = authContextFromMcp(auth);
|
|
34
34
|
if (name === "relay_merge_pauses") {
|
|
35
35
|
const pauses = listAutoMergePauses();
|
|
36
36
|
return { pauses, count: pauses.length };
|
|
37
37
|
}
|
|
38
38
|
if (name === "relay_merge_pause") {
|
|
39
|
-
const result = pauseAutoMerge({
|
|
39
|
+
const result = (await pauseAutoMerge({
|
|
40
40
|
repoRoot: cleanString(args.repoRoot, "repoRoot", { required: true, max: 1024 })!,
|
|
41
41
|
baseRef: cleanString(args.baseRef, "baseRef", { max: 240 }),
|
|
42
42
|
holder: cleanString(args.holder, "holder", { max: 240 }) ?? ctx.callerAgentId ?? ctx.actor.id,
|
|
43
43
|
reason: cleanString(args.reason, "reason", { max: 1000 }),
|
|
44
44
|
ttlMs: optionalPositiveInt(args.ttlMs, "ttlMs"),
|
|
45
|
-
});
|
|
45
|
+
}));
|
|
46
46
|
return result.ok ? { ok: true, pause: result.pause } : { ok: false, error: "merge target already paused", pause: result.pause };
|
|
47
47
|
}
|
|
48
48
|
if (name === "relay_merge_renew") {
|
|
49
|
-
const pause = renewAutoMergePause(cleanString(args.id, "id", { required: true, max: 120 })!, optionalPositiveInt(args.ttlMs, "ttlMs"));
|
|
49
|
+
const pause = (await renewAutoMergePause(cleanString(args.id, "id", { required: true, max: 120 })!, optionalPositiveInt(args.ttlMs, "ttlMs")));
|
|
50
50
|
if (!pause) throw new McpNotFoundError("merge pause not found or expired");
|
|
51
51
|
return { pause };
|
|
52
52
|
}
|
|
@@ -54,7 +54,7 @@ export function relayMergeTool(auth: McpAuthLike, name: string, args: Record<str
|
|
|
54
54
|
const id = cleanString(args.id, "id", { max: 120 });
|
|
55
55
|
const repoRoot = cleanString(args.repoRoot, "repoRoot", { max: 1024 });
|
|
56
56
|
if (!id && !repoRoot) throw new ValidationError("id or repoRoot required");
|
|
57
|
-
return { released: resumeAutoMerge({ id, repoRoot, baseRef: cleanString(args.baseRef, "baseRef", { max: 240 }) }) };
|
|
57
|
+
return { released: (await resumeAutoMerge({ id, repoRoot, baseRef: cleanString(args.baseRef, "baseRef", { max: 240 }) })) };
|
|
58
58
|
}
|
|
59
59
|
throw new ValidationError(`unknown tool: ${name}`);
|
|
60
60
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { addSubscriptionAsync, addSubscriptionsAsync, removeSubscriptionAsync } from "./db/lifecycle-tail-async";
|
|
1
2
|
import {
|
|
2
|
-
addSubscription,
|
|
3
3
|
childStreamFromSubscriptionType,
|
|
4
4
|
childStreamSubscriptionType,
|
|
5
5
|
cleanChildStream,
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
listSubscriptions,
|
|
10
10
|
NOTIFICATION_SUBSCRIPTION_MODES,
|
|
11
11
|
NOTIFICATION_SUBSCRIPTION_TYPES,
|
|
12
|
-
removeSubscription,
|
|
13
12
|
type ConfigurableChildStream,
|
|
14
13
|
type ChildStream,
|
|
15
14
|
type NotificationSubscriptionMode,
|
|
@@ -112,14 +111,14 @@ export async function relayNotificationSubscriptionTool(
|
|
|
112
111
|
if (Object.prototype.hasOwnProperty.call(args, "streams")) {
|
|
113
112
|
const scope = cleanChildStreamScope(args, agentId);
|
|
114
113
|
const streams = cleanChildStreams(args.streams);
|
|
115
|
-
const subscriptions = streams
|
|
114
|
+
const subscriptions = await addSubscriptionsAsync(streams
|
|
116
115
|
.filter((stream): stream is ConfigurableChildStream => stream !== "responses")
|
|
117
|
-
.map((stream) =>
|
|
116
|
+
.map((stream) => ({
|
|
118
117
|
agentId,
|
|
119
118
|
type: childStreamSubscriptionType(stream),
|
|
120
119
|
mode: cleanModeOrDefault(args.mode),
|
|
121
120
|
scopeMatch: scope,
|
|
122
|
-
}));
|
|
121
|
+
})));
|
|
123
122
|
return {
|
|
124
123
|
subscriptions,
|
|
125
124
|
childStreamFilter: {
|
|
@@ -132,21 +131,21 @@ export async function relayNotificationSubscriptionTool(
|
|
|
132
131
|
if (Object.prototype.hasOwnProperty.call(args, "taskId")) {
|
|
133
132
|
const scope = await taskScope(ctx, args.taskId, args.scope);
|
|
134
133
|
const mode = cleanModeOrDefault(args.mode);
|
|
135
|
-
const subscriptions = TASK_NOTIFICATION_TYPES.map((type) =>
|
|
134
|
+
const subscriptions = await addSubscriptionsAsync(TASK_NOTIFICATION_TYPES.map((type) => ({
|
|
136
135
|
agentId,
|
|
137
136
|
type,
|
|
138
137
|
mode,
|
|
139
138
|
scopeMatch: scope,
|
|
140
|
-
}));
|
|
139
|
+
})));
|
|
141
140
|
return { subscriptions, taskFilter: scope };
|
|
142
141
|
}
|
|
143
142
|
if (args.type === undefined || args.type === null) throw new ValidationError("type or streams required");
|
|
144
|
-
const subscription =
|
|
143
|
+
const subscription = (await addSubscriptionAsync({
|
|
145
144
|
agentId,
|
|
146
145
|
type: cleanSubscriptionType(args.type),
|
|
147
146
|
mode: cleanModeOrDefault(args.mode),
|
|
148
147
|
scopeMatch: cleanScope(args.scope),
|
|
149
|
-
});
|
|
148
|
+
}));
|
|
150
149
|
return { subscription };
|
|
151
150
|
}
|
|
152
151
|
if (name === "relay_unsubscribe") {
|
|
@@ -157,12 +156,12 @@ export async function relayNotificationSubscriptionTool(
|
|
|
157
156
|
let removed = 0;
|
|
158
157
|
for (const stream of streams) {
|
|
159
158
|
if (stream === "responses") continue;
|
|
160
|
-
removed +=
|
|
159
|
+
removed += (await removeSubscriptionAsync({
|
|
161
160
|
agentId,
|
|
162
161
|
type: childStreamSubscriptionType(stream),
|
|
163
162
|
mode: args.mode === undefined || args.mode === null ? undefined : cleanSubscriptionMode(args.mode),
|
|
164
163
|
scopeMatch: scope,
|
|
165
|
-
});
|
|
164
|
+
}));
|
|
166
165
|
}
|
|
167
166
|
return { removed, responsesAlwaysOn: true };
|
|
168
167
|
}
|
|
@@ -173,24 +172,24 @@ export async function relayNotificationSubscriptionTool(
|
|
|
173
172
|
: [cleanSubscriptionType(args.type)];
|
|
174
173
|
let removed = 0;
|
|
175
174
|
for (const type of types) {
|
|
176
|
-
removed +=
|
|
175
|
+
removed += (await removeSubscriptionAsync({
|
|
177
176
|
agentId,
|
|
178
177
|
type,
|
|
179
178
|
mode: args.mode === undefined || args.mode === null ? undefined : cleanSubscriptionMode(args.mode),
|
|
180
179
|
scopeMatch: scope,
|
|
181
|
-
});
|
|
180
|
+
}));
|
|
182
181
|
}
|
|
183
182
|
return { removed };
|
|
184
183
|
}
|
|
185
184
|
const type = args.type === undefined || args.type === null ? undefined : cleanSubscriptionType(args.type);
|
|
186
185
|
if (!id && !type) throw new ValidationError("id or type required");
|
|
187
|
-
const removed =
|
|
186
|
+
const removed = (await removeSubscriptionAsync({
|
|
188
187
|
agentId,
|
|
189
188
|
id,
|
|
190
189
|
type,
|
|
191
190
|
mode: args.mode === undefined || args.mode === null ? undefined : cleanSubscriptionMode(args.mode),
|
|
192
191
|
...(Object.prototype.hasOwnProperty.call(args, "scope") ? { scopeMatch: cleanScope(args.scope) } : {}),
|
|
193
|
-
});
|
|
192
|
+
}));
|
|
194
193
|
return { removed };
|
|
195
194
|
}
|
|
196
195
|
if (name === "relay_list_subscriptions") {
|
|
@@ -58,7 +58,7 @@ export async function seedOutputFixture(database: ReturnType<typeof db.getDb>) {
|
|
|
58
58
|
await call("relay_decision", { action: "file", title: "Choose output convention", context: OUTPUT_BODY, questions: [{ prompt: "Adopt canonical verbosity?", kind: "text" }] });
|
|
59
59
|
db.upsertWorkspace({ id: "output-ws", repoRoot: process.cwd(), sourceCwd: process.cwd(), worktreePath: process.cwd(), branch: "agent/output", orchestratorId: "output-host", ownerAgentId: caller, mode: "isolated", status: "active", metadata: {} });
|
|
60
60
|
db.recordCrashReport({ agentId: "output-worker-0", parentId: caller, reason: "Provider exited", diagnosis: { cause: "provider-crash", confidence: "high", summary: "Provider exited with nonzero status", evidence: [OUTPUT_BODY], detectedAt: 1000 }, createdAt: 1000 });
|
|
61
|
-
const notification = routeNotification({ type: "agent.ready", scope: { agentId: "output-worker-0", parent: caller }, recipients: [caller], message: { body: "Worker ready" } })[0]!;
|
|
61
|
+
const notification = (await routeNotification({ type: "agent.ready", scope: { agentId: "output-worker-0", parent: caller }, recipients: [caller], message: { body: "Worker ready" } }))[0]!;
|
|
62
62
|
const host = createSqliteModuleHost({ db: database, clock: createControllableClock(1000) });
|
|
63
63
|
host.register(timers);
|
|
64
64
|
const timer = await host.invoke(timers, "create", { actor: `runner:${caller}`, grants: ["timers:write"] }, { fireAt: 2000 }) as Timer;
|