@humwick/server 0.130.2 → 0.130.4
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 +175 -4
- package/package.json +8 -7
- package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-BOkmEvgZ.js} +2 -2
- package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-BkaDJp0r.js} +2 -2
- package/public/assets/{TraceView-Wimm0Czv.js → TraceView-B99Uu2yT.js} +2 -2
- package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DUIfTTFF.js} +2 -2
- package/public/assets/{activity-CrSurn-r.js → activity-ZIX0N1El.js} +2 -2
- package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-kq9TPYFw.js} +2 -2
- package/public/assets/agent-liveness-DSQY1Aa_.js +2 -0
- package/public/assets/{agent-name-DKbiIhBo.js → agent-name-C_7F4DFR.js} +2 -2
- package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-BNOcrGcY.js} +2 -2
- package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-B6yAh70a.js} +2 -2
- package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-CcrhmOzF.js} +2 -2
- package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CXSLrKiq.js} +2 -2
- package/public/assets/{agents-B-v66C-4.js → agents-DIZG97_X.js} +2 -2
- package/public/assets/{analytics-BqCb-LKi.js → analytics-rasmoPjR.js} +2 -2
- package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-tBpTrEPb.js} +2 -2
- package/public/assets/{artifacts-DJevXcvg.js → artifacts-BNkrynP1.js} +2 -2
- package/public/assets/{artifacts-D32zyw4Y.js → artifacts-Bjq-ZyBA.js} +2 -2
- package/public/assets/{automation-BpRajx_5.js → automation-Cx422L3L.js} +2 -2
- package/public/assets/{backlog-D_UjTdzX.js → backlog-RuFQ8PUu.js} +2 -2
- package/public/assets/{busy-health-N3VEh4ao.js → busy-health-BvNQ9g5x.js} +2 -2
- package/public/assets/{channels-9jopungq.js → channels-DNbKAS0I.js} +2 -2
- package/public/assets/{chat-CSXrTB3C.js → chat-Bp3Fx73h.js} +3 -3
- package/public/assets/{code-preview-p1NnmqK0.js → code-preview-KIRZA6cz.js} +2 -2
- package/public/assets/{connectors-CZdqlDNL.js → connectors-k7vO4vvc.js} +2 -2
- package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BuVoq1aw.js} +2 -2
- package/public/assets/{crate-agent-30aXTKva.js → crate-agent-irqlt4NH.js} +2 -2
- package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-D_rurNBz.js} +2 -2
- package/public/assets/{deploys-DoN6bAb5.js → deploys-yzZqIpxE.js} +2 -2
- package/public/assets/{display-BrKWFGJz.js → display-BemJG1f_.js} +2 -2
- package/public/assets/{files-D6XEu8Ng.js → files-DXWcrxOz.js} +2 -2
- package/public/assets/{fleet-C7jQWbw2.js → fleet-TEuOCZXE.js} +2 -2
- package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BGoDAFI-.js} +2 -2
- package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-BB9eq9nN.js} +2 -2
- package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-qy2nTD_1.js} +3 -3
- package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-BGPHxuwT.js} +2 -2
- package/public/assets/{index-CRHep3M9.js → index-BC5XZc0z.js} +5 -5
- package/public/assets/{index-MYAIwYTX.css → index-D8Rp9pz2.css} +1 -1
- package/public/assets/{insights-CzrtkpOE.js → insights-C-KQG0h-.js} +2 -2
- package/public/assets/{integrations-aVsUmigt.js → integrations-ClPRPyKU.js} +2 -2
- package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-DbH8J9Ak.js} +2 -2
- package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-PH4zVn24.js} +2 -2
- package/public/assets/{maintenance-NfjqFZAk.js → maintenance-5lV43uTL.js} +2 -2
- package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-BdgU35aX.js} +2 -2
- package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-DNT4OUwQ.js} +3 -3
- package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CnCcPy0A.js} +2 -2
- package/public/assets/{memory-DNsCl6UX.js → memory--GgWH1gH.js} +2 -2
- package/public/assets/{messages-DopU1L1X.js → messages-CzFl_97O.js} +2 -2
- package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-CVvJVkzv.js} +2 -2
- package/public/assets/overview-DsrZvE86.js +2 -0
- package/public/assets/{pairs-DE_m6rrE.js → pairs-D2d0d2py.js} +2 -2
- package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-_SMuSbYF.js} +2 -2
- package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-Apn15y43.js} +2 -2
- package/public/assets/{projects-Br2Bd2h1.js → projects-D3B6kto5.js} +2 -2
- package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-DnPB6Ez6.js} +2 -2
- package/public/assets/provider-display-bWwiuedV.js +2 -0
- package/public/assets/{registry-Cw38_6gW.js → registry-D790cIhN.js} +2 -2
- package/public/assets/run-card-BCro-Odj.js +2 -0
- package/public/assets/{secrets-DxI-vzSq.js → secrets-CVXvfvbU.js} +2 -2
- package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-D3Xxqb9w.js} +2 -2
- package/public/assets/{settings-CKZTVGIx.js → settings-CoUC7Jci.js} +2 -2
- package/public/assets/shipping-D_Lp9n_J.js +2 -0
- package/public/assets/{stats-DyUBKyWI.js → stats-CXiNjB9S.js} +2 -2
- package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-C703YIy1.js} +2 -2
- package/public/assets/store-BgDALGIX.js +9 -0
- package/public/assets/{tasks-Bh7Chr4-.js → tasks-DO0WpJCx.js} +2 -2
- package/public/assets/{teams-bowI7qVY.js → teams-FGkdi_tL.js} +2 -2
- package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-Dh8dSC7e.js} +3 -3
- package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-B5Zriip3.js} +2 -2
- package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-CRUVDvLC.js} +2 -2
- package/public/assets/{use-decisions-samMQhQf.js → use-decisions-CoaqRh4l.js} +2 -2
- package/public/assets/{use-project-list-59LheVP7.js → use-project-list-X-BgT53X.js} +2 -2
- package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-0X_UZkk-.js} +2 -2
- package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-CkLhVBGu.js} +2 -2
- package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-BkTi7eim.js} +2 -2
- package/public/assets/{work-queue-CSvpuNLz.js → work-queue-DDOLEyKo.js} +2 -2
- package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-CzOsB8BM.js} +2 -2
- package/public/assets/{workflows-DdmxRSyg.js → workflows-DJilvmRM.js} +2 -2
- package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CHcfbLR3.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +29 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/src/adapters/claude-api.ts +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 +3 -2
- 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/login-link.ts +35 -0
- 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/index.ts +7 -1
- package/src/cli/init.ts +53 -0
- package/src/cli/orchestrator.ts +1 -7
- package/src/cli/setup.ts +6 -4
- 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 +3 -12
- 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/workflow-execution.ts +3 -3
- 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 +12 -16
- 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/init.ts +299 -0
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/invite-link.ts +16 -9
- 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 +44 -17
- 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-providers.ts +18 -0
- 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 +7 -3
- 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 +3 -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 +4 -5
- package/src/routes/secrets-import.ts +3 -4
- package/src/routes/secrets-vault.ts +12 -14
- 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-install.ts +30 -0
- 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 +25 -26
- 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/auth-context.ts +6 -0
- 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-api-key.ts +73 -0
- 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/setup.ts +47 -8
- 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/utils.ts +7 -0
- 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/overview-C1DCTzzV.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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { isRecord } from "@humwick/sdk";
|
|
3
|
+
import { createActivityEventByClientIdAsync } from "../db/activity-async";
|
|
4
|
+
import { notifyWorkspaceHumanEscalation } from "../workspace-human-escalation";
|
|
5
|
+
import { stewardFallbackTarget } from "../config";
|
|
6
|
+
import { notifyTarget } from "../maintenance/events";
|
|
7
|
+
|
|
8
|
+
/** Heartbeats already persist provider failures for Fleet; page once per broken checkout (#3791). */
|
|
9
|
+
export async function reportRuntimeDependencyFailure(hostId: string, hostname: string, body: unknown): Promise<void> {
|
|
10
|
+
if (!isRecord(body) || !Array.isArray(body.providerStatus)) return;
|
|
11
|
+
const failure = body.providerStatus.find((status) => isRecord(status) && status.available === false
|
|
12
|
+
&& typeof status.reason === "string" && status.reason.startsWith("Runtime dependencies unavailable in "));
|
|
13
|
+
if (!failure) return;
|
|
14
|
+
const reason = failure.reason as string;
|
|
15
|
+
const checkout = reason.split(": ")[0]!;
|
|
16
|
+
const key = `runtime-dependencies:${hostId}:${createHash("sha256").update(checkout).digest("hex")}`;
|
|
17
|
+
const subject = `Runtime dependencies broken on ${hostname}`;
|
|
18
|
+
const message = `${hostname}: ${reason}. Providers are unavailable until this checkout is repaired.`;
|
|
19
|
+
const event = await createActivityEventByClientIdAsync({ clientId: key, kind: "state", title: subject, body: message,
|
|
20
|
+
meta: hostId, icon: "ti-alert-triangle", view: "orchestrators", metadata: { hostId, reason } });
|
|
21
|
+
if (!event.created) return;
|
|
22
|
+
const payload = { hostId, reason, kind: "runtime-dependencies.failed" };
|
|
23
|
+
const human = await notifyWorkspaceHumanEscalation({ subject, body: message, priority: "urgent", source: "runtime-dependencies", payload, idempotencyKey: key });
|
|
24
|
+
const target = stewardFallbackTarget();
|
|
25
|
+
const routed = target ? await notifyTarget("maintenance.degraded", {}, target, subject, message, payload, key) : null;
|
|
26
|
+
console.warn(`[relay] ${subject}: ${reason}${human.accepted || routed ? "" : " — no notification target configured"}`);
|
|
27
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { updateCommandAsync } from "../commands-write";
|
|
1
2
|
import { writeChildEnv } from "@humwick/sdk/env";
|
|
2
3
|
import { basename } from "node:path";
|
|
3
4
|
import { SCHEDULER_RETRY_MS } from "../config";
|
|
4
5
|
import { errMessage, stringValue } from "@humwick/sdk";
|
|
5
6
|
import { hasScope } from "@humwick/sdk/types";
|
|
6
|
-
import {
|
|
7
|
+
import { getCommand } from "../commands-db";
|
|
8
|
+
import { findLatestCommandByCorrelationAsync } from "../commands-write";
|
|
7
9
|
import { RELAY_RUN_DEADLINE_GRACE_MS } from "../relay-run-lease";
|
|
8
10
|
import { storeTextArtifact } from "../artifact-text";
|
|
9
11
|
import { gateRunIdentity, recordAgentGateRun } from "../gate-run-capture";
|
|
@@ -119,7 +121,7 @@ export async function dispatchScheduledCommand(timer: ScheduledTimer, ctx = pers
|
|
|
119
121
|
// Freeze the agent generation that owns this command. Managed restarts reuse the
|
|
120
122
|
// durable agent id, so agentId alone would let predecessor teardown kill a successor's command.
|
|
121
123
|
const executionOwnerSpawnRequestId = spawnRequestIds?.length === 1 ? spawnRequestIds[0] : undefined;
|
|
122
|
-
const command =
|
|
124
|
+
const command = await findLatestCommandByCorrelationAsync("scheduler.command", timer.correlationId) ?? await dispatchCommandAsync({
|
|
123
125
|
type: "scheduler.command",
|
|
124
126
|
source: timer.createdBy,
|
|
125
127
|
target: `orchestrator-${timer.command.orchestratorId}`,
|
|
@@ -186,7 +188,7 @@ export async function fireScheduledCommandTimeout(timer: ScheduledTimer, now: nu
|
|
|
186
188
|
return { status: "deferred" };
|
|
187
189
|
}
|
|
188
190
|
const neverStarted = !!command && (command.status === "pending" || command.status === "accepted") && commandResult(command).phase !== "running";
|
|
189
|
-
if (command)
|
|
191
|
+
if (command) (await updateCommandAsync(command.id, { status: "timed_out", error: "background command timed out" }));
|
|
190
192
|
const result = command ? commandResult(command) : {};
|
|
191
193
|
const admittedAt = numberValue(result.admittedAt) ?? timer.command.admittedAt;
|
|
192
194
|
const durationMs = admittedAt === undefined ? 0 : Math.max(0, now - admittedAt);
|
|
@@ -202,7 +204,7 @@ export async function fireScheduledCommandTimeout(timer: ScheduledTimer, now: nu
|
|
|
202
204
|
stdoutTail: stringValue(result.stdoutTail) ?? timer.command.stdoutTail ?? "",
|
|
203
205
|
stderrTail: stringValue(result.stderrTail) ?? timer.command.stderrTail ?? (neverStarted ? queuedTimeoutReason(timer.command.orchestratorId) : "background command timed out"),
|
|
204
206
|
};
|
|
205
|
-
return fireScheduledCommandWake(timer, {
|
|
207
|
+
return (await fireScheduledCommandWake(timer, {
|
|
206
208
|
status: "timed_out",
|
|
207
209
|
finishedAt: timer.command.finishedAt ?? now,
|
|
208
210
|
durationMs,
|
|
@@ -213,7 +215,7 @@ export async function fireScheduledCommandTimeout(timer: ScheduledTimer, now: nu
|
|
|
213
215
|
exitCode: null,
|
|
214
216
|
stdoutTail: timeoutResult.stdoutTail,
|
|
215
217
|
stderrTail: timeoutResult.stderrTail,
|
|
216
|
-
}, timeoutResult, now, inlineWakeSuppressed(timer.command, now));
|
|
218
|
+
}, timeoutResult, now, inlineWakeSuppressed(timer.command, now)));
|
|
217
219
|
}
|
|
218
220
|
|
|
219
221
|
/** #2776 — admission report: the fallback timer now guards the RUN (end + grace), not the queue ceiling. */
|
|
@@ -243,7 +245,7 @@ export async function settleScheduledCommandTimer(command: Command, now = Date.n
|
|
|
243
245
|
: "failed";
|
|
244
246
|
const stdout = clipTail(stringValue(result.stdoutTail) ?? stringValue(result.stdout) ?? "");
|
|
245
247
|
const stderr = clipTail(stringValue(result.stderrTail) ?? stringValue(result.stderr) ?? command.error ?? "");
|
|
246
|
-
return fireScheduledCommandWake(timer, {
|
|
248
|
+
return (await fireScheduledCommandWake(timer, {
|
|
247
249
|
status,
|
|
248
250
|
finishedAt: timer.command.finishedAt ?? now,
|
|
249
251
|
startedAt: numberValue(result.startedAt),
|
|
@@ -262,7 +264,7 @@ export async function settleScheduledCommandTimer(command: Command, now = Date.n
|
|
|
262
264
|
// Strictly stronger than truncation: the command was KILLED for flooding, it did not finish.
|
|
263
265
|
outputLimitExceeded: result.outputLimitExceeded === true,
|
|
264
266
|
logArtifactId: stringValue(result.logArtifactId),
|
|
265
|
-
}, result, now, inlineWakeSuppressed(timer.command, now));
|
|
267
|
+
}, result, now, inlineWakeSuppressed(timer.command, now)));
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
/**
|
|
@@ -358,7 +360,7 @@ async function fireScheduledCommandWake(
|
|
|
358
360
|
try {
|
|
359
361
|
const runNumber = timerForSend.runCount + 1;
|
|
360
362
|
const payloadResult = commandPayload(timerForSend.command!, rawResult, logArtifactId);
|
|
361
|
-
const send = sendMessageService({
|
|
363
|
+
const send = (await sendMessageService({
|
|
362
364
|
from: timerForSend.deliveryFrom,
|
|
363
365
|
to: timerForSend.target,
|
|
364
366
|
kind: timerForSend.messageKind as SendMessageInput["kind"] | undefined,
|
|
@@ -387,7 +389,7 @@ async function fireScheduledCommandWake(
|
|
|
387
389
|
},
|
|
388
390
|
// One stable key per command completion (not per run count): overlapping settlements dedupe.
|
|
389
391
|
idempotencyKey: `${timerForSend.idempotencyKey ?? `scheduler:${timerForSend.id}`}:completion`,
|
|
390
|
-
}, persistedCommandAuthContext(timerForSend));
|
|
392
|
+
}, persistedCommandAuthContext(timerForSend)));
|
|
391
393
|
await completeTimerRunAsync(timerForSend, send.message.id, now);
|
|
392
394
|
return { status: "fired", messageId: send.message.id };
|
|
393
395
|
} catch (error) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { framed } from "../hub-metrics";
|
|
1
2
|
import { createScheduledTimer } from "./scheduler-create";
|
|
2
3
|
import { planScheduledTimerCreate, cleanOptionalString, canAdministerTimers, type ScheduleTimerInput } from "./scheduler-plan";
|
|
3
4
|
export { type ScheduleTimerInput } from "./scheduler-plan";
|
|
@@ -84,9 +85,8 @@ export function startRelayScheduler(): void {
|
|
|
84
85
|
if (isEphemeralMode()) return;
|
|
85
86
|
if (schedulerTimer) return;
|
|
86
87
|
void timePostBindPhase("runDueScheduledTimers", runDueScheduledTimers).catch((error) => console.warn(`relay scheduler tick failed: ${errMessage(error)}`));
|
|
87
|
-
schedulerTimer = setInterval(() =>
|
|
88
|
-
|
|
89
|
-
}, SCHEDULER_TICK_MS);
|
|
88
|
+
schedulerTimer = setInterval(framed("timer scheduled-timers", () =>
|
|
89
|
+
timePostBindPhase("runDueScheduledTimers", runDueScheduledTimers).catch((error) => console.warn(`relay scheduler tick failed: ${errMessage(error)}`))), SCHEDULER_TICK_MS);
|
|
90
90
|
// #1408 K7 Phase-2: additively light up the kernel-served timers supervisor iff the reversible
|
|
91
91
|
// switch is on (default OFF ⇒ pure no-op). Legacy above stays authoritative; the kernel path is
|
|
92
92
|
// not yet a functional replacement for message/command dispatch (see kernel-timers.ts).
|
|
@@ -292,7 +292,7 @@ async function fireClaimedTimer(
|
|
|
292
292
|
await disableTimerAsync(timer.id, "timer expired before delivery");
|
|
293
293
|
return { status: "disabled" };
|
|
294
294
|
}
|
|
295
|
-
return fireScheduledCommandTimeout(timer, now);
|
|
295
|
+
return (await fireScheduledCommandTimeout(timer, now));
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
try {
|
|
@@ -323,7 +323,7 @@ async function fireClaimedTimer(
|
|
|
323
323
|
await disableTimerAsync(timer.id, "timer expired before delivery");
|
|
324
324
|
return { status: "disabled" };
|
|
325
325
|
}
|
|
326
|
-
const result = sendMessageService(sendInput, persistedAuthContext(timer));
|
|
326
|
+
const result = (await sendMessageService(sendInput, persistedAuthContext(timer)));
|
|
327
327
|
await completeTimerRunAsync(timer, result.message.id, now);
|
|
328
328
|
return { status: "fired", messageId: result.message.id };
|
|
329
329
|
} catch (error) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { grantSelfEffortAsync } from "../db/agent-control-async";
|
|
2
|
+
export { SELF_EFFORT_GRANT_COMMAND } from "../db/agent-control-write";
|
|
1
3
|
import { randomUUID } from "node:crypto";
|
|
2
4
|
import { stringValue } from "@humwick/sdk";
|
|
3
5
|
import { createCommandInternal, updateCommandInternal } from "../commands-db";
|
|
@@ -14,7 +16,7 @@ import type { Command } from "../types";
|
|
|
14
16
|
|
|
15
17
|
// #2966 — the operator turns selfEffort on or off for a running agent. The permission row is the
|
|
16
18
|
// state; the settled command written beside it is the audit record.
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
|
|
19
21
|
interface SelfEffortGrantInput extends SelfEffortSpawnInput {
|
|
20
22
|
agentId: string;
|
|
@@ -27,7 +29,7 @@ interface SelfEffortGrantInput extends SelfEffortSpawnInput {
|
|
|
27
29
|
export async function grantSelfEffort(input: SelfEffortGrantInput, ctx: AuthContext): Promise<{ selfEffort: SelfEffortPolicy | null; command: Command }> {
|
|
28
30
|
const agent = getAgent(input.agentId);
|
|
29
31
|
if (!agent) throw new AgentActionTargetError(`agent ${input.agentId} not found`);
|
|
30
|
-
authorizeShutdown(ctx, { agentId: agent.id, requestedVia: input.requestedVia });
|
|
32
|
+
(await authorizeShutdown(ctx, { agentId: agent.id, requestedVia: input.requestedVia }));
|
|
31
33
|
const spawnRequestId = stringValue(agent.meta?.spawnRequestId);
|
|
32
34
|
if (typeof input.selfEffort !== "boolean") throw new ValidationError("selfEffort must be true or false");
|
|
33
35
|
const model = agent.providerCapabilities?.model;
|
|
@@ -64,29 +66,7 @@ export async function grantSelfEffort(input: SelfEffortGrantInput, ctx: AuthCont
|
|
|
64
66
|
revalidateAgentInstance(agent);
|
|
65
67
|
// Nothing executes a grant: it is written settled with the permission in one transaction. The
|
|
66
68
|
// identity is resolved inside it, so a stale writer cannot restore a deleted policy's row.
|
|
67
|
-
const command =
|
|
68
|
-
const now = Date.now();
|
|
69
|
-
const identity = selfEffortIdentity(agent);
|
|
70
|
-
setSelfEffortCeilingInternal(identity, !grant ? null : "band" in grant ? SELF_EFFORT_BAND : grant.ceiling, requestedBy, now);
|
|
71
|
-
createCommandInternal({ id: commandId, input: {
|
|
72
|
-
type: SELF_EFFORT_GRANT_COMMAND,
|
|
73
|
-
source: "system",
|
|
74
|
-
target: agent.id,
|
|
75
|
-
...(spawnRequestId ? { correlationId: spawnRequestId } : {}),
|
|
76
|
-
params: {
|
|
77
|
-
agentId: agent.id,
|
|
78
|
-
...(spawnRequestId ? { spawnRequestId } : {}),
|
|
79
|
-
permission: identity,
|
|
80
|
-
selfEffort,
|
|
81
|
-
previousSelfEffort: previous,
|
|
82
|
-
requestedBy,
|
|
83
|
-
...(input.requestedByUser ? { requestedByUser: input.requestedByUser } : {}),
|
|
84
|
-
requestedVia: input.requestedVia,
|
|
85
|
-
requestedAt: now,
|
|
86
|
-
},
|
|
87
|
-
} }, now);
|
|
88
|
-
return updateCommandInternal(commandId, { status: "succeeded", result: { selfEffort } }, {}, now).command!;
|
|
89
|
-
});
|
|
69
|
+
const command = await grantSelfEffortAsync({ agent, grant, requestedBy, commandId, spawnRequestId, input, selfEffort, previous });
|
|
90
70
|
emitCommandEvent(command, "command.succeeded");
|
|
91
71
|
emitActivityEvent(event);
|
|
92
72
|
return { selfEffort, command };
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { promoteLineageCapturedResponseAsync } from "../db/runtime-tail-async";
|
|
2
|
+
import { sendMessageWithResultAsync } from "../db/message-send";
|
|
1
3
|
import { refusedResponseReport } from "./response-report-admission";
|
|
2
4
|
import { suppressResultsOnlyAck, isResultsOnlyAckCandidate } from "../db/message-send-suppression";
|
|
3
5
|
import { getGateway } from "../db/gateway";
|
|
4
|
-
import { getMessageAsync, channelObligationAnsweredByAsync } from "../db";
|
|
6
|
+
import { getMessageAsync, channelObligationAnsweredByAsync, ValidationError, getAgent, getMessage, isChannelAgentId, listAgents, sendMessagesBatchWithResultAsync, channelObligationAnsweredBy, agentPrincipalUserId, isMultiUserWorld, type SendMessageResult as DbSendMessageResult } from "../db";
|
|
5
7
|
import { agentPrincipalSink } from "../db/agent-ownership";
|
|
6
8
|
// Transport convergence (epic #342, slice #346) — the message-send service.
|
|
7
9
|
//
|
|
@@ -27,21 +29,6 @@ import { agentPrincipalSink } from "../db/agent-ownership";
|
|
|
27
29
|
// OUT OF SCOPE (transport-edge, excluded from the parity facet): automatic memory injection
|
|
28
30
|
// (needs request-derived context) and per-transport audit (HTTP domain row vs MCP tool-call row).
|
|
29
31
|
import { LEGACY_HUMAN_AGENT_ID, USER_NAMESPACE_PREFIX, userSinkId, canonicalHumanAgentId, heldForSender, isHumanAgentId, isMechanicalMessageKind, isRecord, isReservedAgentId, isTurnFinalSession } from "@humwick/sdk";
|
|
30
|
-
import {
|
|
31
|
-
ValidationError,
|
|
32
|
-
getAgent,
|
|
33
|
-
getMessage,
|
|
34
|
-
isChannelAgentId,
|
|
35
|
-
listAgents,
|
|
36
|
-
promoteLineageCapturedResponse,
|
|
37
|
-
sendMessagesBatchWithResultAsync,
|
|
38
|
-
sendMessageWithResult,
|
|
39
|
-
sendMessageWithResultAsync,
|
|
40
|
-
channelObligationAnsweredBy,
|
|
41
|
-
agentPrincipalUserId,
|
|
42
|
-
isMultiUserWorld,
|
|
43
|
-
type SendMessageResult as DbSendMessageResult,
|
|
44
|
-
} from "../db";
|
|
45
32
|
import { recentFinalResponseCaptureIds } from "../db/lineage-startup-captures";
|
|
46
33
|
import { yieldToEventLoop } from "../event-loop-yield";
|
|
47
34
|
import { markAgentWorkFinal } from "./work-finality";
|
|
@@ -367,18 +354,12 @@ function agentSendAllowed(input: SendMessageInput, ctx: AuthContext, sender: Mes
|
|
|
367
354
|
return inSameMessagingRun(sender, getAgent(input.to));
|
|
368
355
|
}
|
|
369
356
|
|
|
370
|
-
export function sendMessageService(
|
|
357
|
+
export async function sendMessageService(
|
|
371
358
|
input: SendMessageInput,
|
|
372
359
|
ctx: AuthContext,
|
|
373
360
|
opts: SendMessageOptions = {},
|
|
374
|
-
): SendMessageResult {
|
|
375
|
-
|
|
376
|
-
if (suppressedParent) return { message: suppressedParent, created: false, receipt };
|
|
377
|
-
const result = sendMessageWithResult(input, { allowUnregisteredSender: opts.allowUnregisteredSender });
|
|
378
|
-
const sent = { message: result.message, created: result.created, receipt: finalizeReceipt(result.message, receipt) };
|
|
379
|
-
if (opts.deferLiveEffects) return { ...sent, publish: () => emitSendResults([result]) };
|
|
380
|
-
emitSendResults([result]);
|
|
381
|
-
return sent;
|
|
361
|
+
): Promise<SendMessageResult> {
|
|
362
|
+
return sendMessageServiceAsync(input, ctx, opts);
|
|
382
363
|
}
|
|
383
364
|
|
|
384
365
|
/** Async persistence and message-history reads; live target authorization and emits stay on main.
|
|
@@ -391,8 +372,10 @@ export async function sendMessageServiceAsync(
|
|
|
391
372
|
const { receipt, suppressedParent } = await prepareSendMessageAsync(input, ctx, opts);
|
|
392
373
|
if (suppressedParent) return { message: suppressedParent, created: false, receipt };
|
|
393
374
|
const result = await sendMessageWithResultAsync(input, { allowUnregisteredSender: opts.allowUnregisteredSender });
|
|
394
|
-
|
|
395
|
-
return {
|
|
375
|
+
const sent = { message: result.message, created: result.created, receipt: finalizeReceipt(result.message, receipt) };
|
|
376
|
+
if (opts.deferLiveEffects) return { ...sent, publish: async () => (await emitSendResults([result])) };
|
|
377
|
+
(await emitSendResults([result]));
|
|
378
|
+
return sent;
|
|
396
379
|
}
|
|
397
380
|
|
|
398
381
|
export async function sendMessagesBatchService(
|
|
@@ -426,7 +409,7 @@ export async function sendMessagesBatchService(
|
|
|
426
409
|
receipt: finalizeReceipt(result.message, prepared[outputIndex]!.receipt),
|
|
427
410
|
};
|
|
428
411
|
}
|
|
429
|
-
emitSendResults(stored);
|
|
412
|
+
(await emitSendResults(stored));
|
|
430
413
|
return results;
|
|
431
414
|
}
|
|
432
415
|
|
|
@@ -504,11 +487,11 @@ export async function sweepDeferredLineageReportsOnStartup(now: number = Date.no
|
|
|
504
487
|
// A tagged capture was already flushed before boot (or by an earlier sweep). Skipping it avoids
|
|
505
488
|
// re-arming the held ring, minting a second finality window, and re-emitting `message.finalized`.
|
|
506
489
|
if (isRecord(capture.payload?.finality)) continue;
|
|
507
|
-
const promoted =
|
|
490
|
+
const promoted = (await promoteLineageCapturedResponseAsync(capture));
|
|
508
491
|
if (promoted?.created) emitted.push(promoted.message);
|
|
509
492
|
// The ordinary 10-minute cutoff protects live coalescing. Recovery is already bounded by the
|
|
510
493
|
// 24-hour query, and persistence proves this capture's source turn completed before boot.
|
|
511
|
-
const recovered = markAgentWorkFinal(capture.from, "edge-fallback", { includeStaleCompletedFinals: true });
|
|
494
|
+
const recovered = (await markAgentWorkFinal(capture.from, "edge-fallback", { includeStaleCompletedFinals: true }));
|
|
512
495
|
recoveredCount += recovered.forwarded.filter((entry) => entry.created).length;
|
|
513
496
|
}
|
|
514
497
|
if (emitted.length > 0) emitNewMessages(emitted);
|
|
@@ -517,7 +500,7 @@ export async function sweepDeferredLineageReportsOnStartup(now: number = Date.no
|
|
|
517
500
|
return { promoted: emitted.length + recoveredCount, scanned, ...(signal?.aborted ? { aborted: true as const } : {}) };
|
|
518
501
|
}
|
|
519
502
|
|
|
520
|
-
function emitSendResults(results: DbSendMessageResult[]): void {
|
|
503
|
+
export async function emitSendResults(results: DbSendMessageResult[]): Promise<void> {
|
|
521
504
|
const liveMessages: Message[] = [];
|
|
522
505
|
for (const result of results) {
|
|
523
506
|
if (result.created) {
|
|
@@ -538,13 +521,13 @@ function emitSendResults(results: DbSendMessageResult[]): void {
|
|
|
538
521
|
emitMessageDeliveryUpdated(result.message);
|
|
539
522
|
}
|
|
540
523
|
}
|
|
541
|
-
const promoted =
|
|
524
|
+
const promoted = (await promoteLineageCapturedResponseAsync(result.message));
|
|
542
525
|
if (promoted?.created) liveMessages.push(promoted.message);
|
|
543
526
|
} else if (result.updated) {
|
|
544
527
|
// Session-step upsert (#parity): the row changed in place (same DB id). Re-emit so the
|
|
545
528
|
// dashboard's id-keyed merge replaces the existing step live — no duplicate row.
|
|
546
529
|
liveMessages.push(result.message);
|
|
547
|
-
const promoted =
|
|
530
|
+
const promoted = (await promoteLineageCapturedResponseAsync(result.message));
|
|
548
531
|
if (promoted?.created) liveMessages.push(promoted.message);
|
|
549
532
|
}
|
|
550
533
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createAgentControlAsync } from "../db/agent-control-async";
|
|
2
|
+
import type { SafeCandidate } from "./idle-agent-digest";
|
|
1
3
|
import { spawnTreeContains } from "../db/spawn-tree";
|
|
2
4
|
import { spawnDelegationState } from "../db/spawn-delegation-state";
|
|
3
5
|
// Transport convergence (epic #342, slice #347) — the agent-shutdown service.
|
|
@@ -37,7 +39,6 @@ import { spawnDelegationState } from "../db/spawn-delegation-state";
|
|
|
37
39
|
// system auth" — the steward-reaper's forceful escalation does; its graceful first attempt does not.
|
|
38
40
|
import {
|
|
39
41
|
ValidationError,
|
|
40
|
-
inWriteTransaction,
|
|
41
42
|
createActivityEventAsync,
|
|
42
43
|
getAgent,
|
|
43
44
|
getOrchestrator,
|
|
@@ -46,7 +47,7 @@ import {
|
|
|
46
47
|
mergeAgentMetaAsync,
|
|
47
48
|
} from "../db";
|
|
48
49
|
import { randomUUID } from "node:crypto";
|
|
49
|
-
import {
|
|
50
|
+
import { findSpawnCommandByRequestId, getCommand } from "../commands-db";
|
|
50
51
|
import { SPAWN_CANCELABLE_STATUSES } from "../spawn-intent";
|
|
51
52
|
import { isRestartSensitiveCommand } from "../db/restart-sensitive";
|
|
52
53
|
import { cancelCommandIfStatusAsync } from "../commands-write";
|
|
@@ -112,6 +113,7 @@ interface ShutdownAgentInput {
|
|
|
112
113
|
/** #3428 — automatic disposal only: re-checked on the fresh card at command admission, after
|
|
113
114
|
* every await; a returned reason refuses the shutdown. */
|
|
114
115
|
admit?: (agent: AgentCard) => string | undefined;
|
|
116
|
+
idleCandidate?: SafeCandidate;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
interface ShutdownAgentResult {
|
|
@@ -173,7 +175,7 @@ export interface ShutdownAuthorization {
|
|
|
173
175
|
|
|
174
176
|
/** The #221 parent→child gate — the single home for shutdown authorization across all
|
|
175
177
|
* three transports. Throws `ShutdownAuthError` on denial; full-reach callers bypass ownership. */
|
|
176
|
-
export function authorizeShutdown(ctx: AuthContext, input: ShutdownAgentInput, action = "shutdown"): ShutdownAuthorization {
|
|
178
|
+
export async function authorizeShutdown(ctx: AuthContext, input: ShutdownAgentInput, action = "shutdown"): Promise<ShutdownAuthorization> {
|
|
177
179
|
const callerId = ctx.callerAgentId;
|
|
178
180
|
// A scoped agent caller may target only its OWN live spawned children — or (#2618) live members
|
|
179
181
|
// of a team it currently coordinates, e.g. after claiming a dead coordinator's team. Two PRECISE
|
|
@@ -211,7 +213,7 @@ export function authorizeShutdown(ctx: AuthContext, input: ShutdownAgentInput, a
|
|
|
211
213
|
}
|
|
212
214
|
}
|
|
213
215
|
// #3567 — the one lifecycle-control check (principal, role, coordinator authority).
|
|
214
|
-
const denied = authorizeAgentControl(ctx, target, action);
|
|
216
|
+
const denied = (await authorizeAgentControl(ctx, target, action));
|
|
215
217
|
if (denied) {
|
|
216
218
|
throw new ShutdownAuthError(denied.reason === "coordinator" && !input.agentId
|
|
217
219
|
? `no spawned child of yours matches spawnRequestId ${input.spawnRequestId}` : denied.message);
|
|
@@ -315,7 +317,7 @@ async function reapInFlightSpawnCommand(
|
|
|
315
317
|
return { command: canceled ?? command, orchestratorId: (canceled ?? command).target, agent: null };
|
|
316
318
|
}
|
|
317
319
|
emitCommandEvent(canceled, "command.canceled");
|
|
318
|
-
notifyAgentSpawnFailed({
|
|
320
|
+
await notifyAgentSpawnFailed({
|
|
319
321
|
parent: stringValue(canceled.params.spawnedBy) ?? ctx.callerAgentId ?? ctx.actor.id,
|
|
320
322
|
spawnRequestId: input.spawnRequestId,
|
|
321
323
|
provider: stringValue(canceled.params.provider),
|
|
@@ -334,11 +336,11 @@ async function reapInFlightSpawnCommand(
|
|
|
334
336
|
* shutting-down (uniform across transports — MCP previously skipped this), and writes the
|
|
335
337
|
* audit row. The single fat-service entry point the three thin transports call. */
|
|
336
338
|
export function shutdownAgent(input: ShutdownAgentInput, ctx: AuthContext): Promise<ShutdownAgentResult> {
|
|
337
|
-
return withRelayEventDrain(() => shutdownAgentBody(input, ctx));
|
|
339
|
+
return withRelayEventDrain(async () => (await shutdownAgentBody(input, ctx)));
|
|
338
340
|
}
|
|
339
341
|
|
|
340
342
|
async function shutdownAgentBody(input: ShutdownAgentInput, ctx: AuthContext): Promise<ShutdownAgentResult> {
|
|
341
|
-
const authz = authorizeShutdown(ctx, input);
|
|
343
|
+
const authz = (await authorizeShutdown(ctx, input));
|
|
342
344
|
if (authz.spawnCommand) return reapInFlightSpawnCommand(authz.spawnCommand, input, ctx);
|
|
343
345
|
|
|
344
346
|
const agent = input.agentId ? getAgent(input.agentId) : null;
|
|
@@ -414,19 +416,20 @@ async function shutdownAgentBody(input: ShutdownAgentInput, ctx: AuthContext): P
|
|
|
414
416
|
const priorCommand = input.commandId ? getCommand(commandId) : null;
|
|
415
417
|
if (priorCommand) return { command: priorCommand, orchestratorId: orchestrator.id, agent: currentAgent };
|
|
416
418
|
const admit = input.admit;
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const refused = admit(getAgent(currentAgent.id) ?? currentAgent);
|
|
419
|
+
if (admit && currentAgent) {
|
|
420
|
+
const refused = admit(currentAgent);
|
|
420
421
|
if (refused) throw new AutomaticShutdownRefused(`automatic shutdown of ${currentAgent.id} refused at admission: ${refused}`);
|
|
421
|
-
|
|
422
|
-
|
|
422
|
+
}
|
|
423
|
+
const admitted = await createAgentControlAsync({ agent: currentAgent, commandId, commandInput, idleCandidate: input.idleCandidate });
|
|
424
|
+
if (!admitted.command) throw new AutomaticShutdownRefused(`automatic shutdown of ${currentAgent?.id} refused at admission: ${admitted.refused}`);
|
|
425
|
+
const command = admitted.command;
|
|
423
426
|
emitCommandEvent(command, "command.requested");
|
|
424
|
-
if (targetAgentId) reapAgentBrowserSessions(targetAgentId); // #3489 — a requested stop takes its browser with it
|
|
427
|
+
if (targetAgentId) (await reapAgentBrowserSessions(targetAgentId)); // #3489 — a requested stop takes its browser with it
|
|
425
428
|
// #1084 — an explicit shutdown is a platform-owned teardown signal: close the target's work
|
|
426
429
|
// window now rather than let a held final group die silently with the process. `edge-fallback`
|
|
427
430
|
// is the closest fit in the closed source enum — there is no cleaner workspace-ready/task-done
|
|
428
431
|
// signal backing an arbitrary teardown (which may target an agent with neither).
|
|
429
|
-
if (targetAgentId) markAgentWorkFinal(targetAgentId, "edge-fallback");
|
|
432
|
+
if (targetAgentId) (await markAgentWorkFinal(targetAgentId, "edge-fallback"));
|
|
430
433
|
|
|
431
434
|
// Lifecycle indicator — uniform across transports. The MCP path previously skipped
|
|
432
435
|
// this, so an MCP-initiated shutdown left the agent with no "shutting down" signal in
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { taskLinkedRepoCwd } from "./task-repo-cwd";
|
|
2
|
+
export { taskLinkedRepoCwd } from "./task-repo-cwd";
|
|
1
3
|
import { writeChildEnv } from "@humwick/sdk/env";
|
|
2
4
|
import { bindSpawnProjectCheckout } from "./project-checkout-binding";
|
|
3
|
-
import { REPORT_VERBOSITIES, resolveReportVerbosity } from "@humwick/sdk";
|
|
5
|
+
import { REPORT_VERBOSITIES, resolveReportVerbosity, DEFAULT_USER_ID, errMessage, isRecord, stringValue, type LaunchMode, type ReportVerbosity, type SpawnProvider, type TaskDispatch } from "@humwick/sdk";
|
|
4
6
|
import { cleanCallerSpawnEnv } from "../spawn-env";
|
|
5
|
-
import { optionalEnum } from "../validation";
|
|
6
|
-
import { optionalNonNegativeInt } from "../validation";
|
|
7
|
+
import { optionalEnum, optionalNonNegativeInt } from "../validation";
|
|
7
8
|
import { cleanSpawnBudget } from "../spawn-budget";
|
|
8
9
|
import { teamId as newTeamId } from "../db/teams";
|
|
9
10
|
import { getGateway } from "../db/gateway";
|
|
@@ -35,8 +36,7 @@ import type { WorkflowSpawnQuota } from "../db/spawn-in-flight";
|
|
|
35
36
|
// deliberately out of scope here — this slice converges the two external TRANSPORTS.
|
|
36
37
|
import { resolveSpawnApprovalMode } from "./spawn-approval";
|
|
37
38
|
import { assertOrchestratorSupportsLaunchMode, resolveSpawnLaunchMode } from "../launch-mode";
|
|
38
|
-
import {
|
|
39
|
-
import { addProjectRootAsync, countLiveSpawnedAgents, createActivityEventAsync, getAgent, getProject, getTaskDetailAsync, listAgents, listProjects, listWorkspaces, recordTaskSpawnRequestedAsync, reportedRepoRootForCwd, resolveAgentOwnershipAsync, resolveProjectForCwd, rootsForProject, ValidationError, withResolvedProvisioningAsync } from "../db";
|
|
39
|
+
import { addProjectRootAsync, countLiveSpawnedAgents, createActivityEventAsync, getAgent, getProject, listAgents, listWorkspaces, recordTaskSpawnRequestedAsync, reportedRepoRootForCwd, resolveAgentOwnershipAsync, resolveProjectForCwd, rootsForProject, ValidationError, withResolvedProvisioningAsync } from "../db";
|
|
40
40
|
import { acquireCoordinatorTeam } from "./team";
|
|
41
41
|
import { countInFlightSpawnCommands } from "../commands-db";
|
|
42
42
|
import { createSpawnCommandWithinQuotaAsync } from "../commands-write";
|
|
@@ -54,7 +54,7 @@ import { profileNotFoundMessage } from "../spawn-profile-errors";
|
|
|
54
54
|
import { composeSpawnInstructionsWithEventsAsync } from "../project-instructions";
|
|
55
55
|
import { applyDefaultSharedMcp, type SharedMcpSpawnOverride } from "../shared-mcp";
|
|
56
56
|
import { findGitRepoRoot, isInsideGitWorkTree, pathVisibleLocally } from "./canonical-root";
|
|
57
|
-
import { selectSpawnCwdPlacement } from "./spawn-cwd-placement";
|
|
57
|
+
import { selectSpawnCwdPlacement, spawnBuildWork } from "./spawn-cwd-placement";
|
|
58
58
|
import { isolatedSpawnGitRepoError, resolveSpawnRepoRoot } from "./spawn-repo-probe";
|
|
59
59
|
import { autoSeedProjectForCwdAsync } from "./project"; import { applyProjectCapabilityGates } from "../project-trust";
|
|
60
60
|
import { assertProjectRoleMcpCwd, assertProjectRoleMcpTrusted, projectRoleProfile, projectRoleProvenance, projectRoleSpawnDefaults, withRoleProfile } from "../project-roles";
|
|
@@ -152,35 +152,6 @@ export function acquisitionManifestFor(projectId: string, cwd: string): {
|
|
|
152
152
|
};
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
export async function taskLinkedRepoCwd(taskId: number, callerCwd?: string): Promise<string> {
|
|
156
|
-
const task = await getTaskDetailAsync(taskId);
|
|
157
|
-
if (!task) throw new ValidationError(`task ${taskId} not found or not a deliverable task`);
|
|
158
|
-
// #2844 — a Task created with `repo:` but no linked issue still names its project repo.
|
|
159
|
-
const repos = [...new Set([...task.issues.map((issue) => issue.repo), task.repo].filter((repo): repo is string => Boolean(repo)))];
|
|
160
|
-
if (repos.length === 0) {
|
|
161
|
-
throw new ValidationError(`task ${taskId} has no linked issue repo; pass cwd/orchestratorId explicitly`);
|
|
162
|
-
}
|
|
163
|
-
const candidates = listProjects()
|
|
164
|
-
.filter((project) => project.issueRepo && repos.includes(project.issueRepo))
|
|
165
|
-
.flatMap((project) => rootsForProject(project.id).map((root) => ({ project, root })));
|
|
166
|
-
if (candidates.length === 0) {
|
|
167
|
-
// #1627 — this refusal is real and names its own cause: with no registered root, relay has no
|
|
168
|
-
// way to turn "repo owner/name" into a checkout path on a specific host. What made it a trap
|
|
169
|
-
// was the NEXT step: following its advice (pass cwd + orchestratorId) used to hit the isolated
|
|
170
|
-
// precondition's local-filesystem probe and get told the repo was "not a git repo". That lie is
|
|
171
|
-
// fixed at assertIsolatedSpawnHasGitRepo, so the remedy below now works. Name the tool so it is
|
|
172
|
-
// mechanical rather than a step you have to know exists.
|
|
173
|
-
throw new ValidationError(`task ${taskId} links repo ${repos.join(", ")} but no Relay project root is registered for it, so relay cannot resolve a checkout path for it; pass cwd + orchestratorId explicitly, or register the checkout with relay_project_add_root`);
|
|
174
|
-
}
|
|
175
|
-
const matchingCallerRoot = callerCwd
|
|
176
|
-
? candidates
|
|
177
|
-
.filter((candidate) => isPathWithinBase(callerCwd, candidate.root.rootPath))
|
|
178
|
-
.sort((a, b) => b.root.rootPath.length - a.root.rootPath.length)[0]
|
|
179
|
-
: undefined;
|
|
180
|
-
if (matchingCallerRoot) return matchingCallerRoot.root.rootPath;
|
|
181
|
-
if (candidates.length === 1) return candidates[0]!.root.rootPath;
|
|
182
|
-
throw new ValidationError(`task ${taskId} links repo ${repos.join(", ")} with multiple registered roots; pass cwd explicitly`);
|
|
183
|
-
}
|
|
184
155
|
|
|
185
156
|
/**
|
|
186
157
|
* A normalized spawn request — every transport validates its own wire shape (enums,
|
|
@@ -390,7 +361,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
390
361
|
const lineageAgent: AgentCard | undefined = (lineageAgentId ? getAgent(lineageAgentId) : undefined) ?? undefined;
|
|
391
362
|
const callerCwd = stringValue(caller?.meta?.cwd) ?? stringValue(lineageAgent?.meta?.cwd);
|
|
392
363
|
const taskDefaultCwd = input.taskId !== undefined && (!input.orchestratorId || input.role !== undefined) && !input.cwd
|
|
393
|
-
? input.taskRepoCwd ?? await taskLinkedRepoCwd(input.taskId, callerCwd)
|
|
364
|
+
? input.taskRepoCwd ?? await taskLinkedRepoCwd(input.taskId, callerCwd, caller ?? lineageAgent)
|
|
394
365
|
: undefined;
|
|
395
366
|
const requestedCwd = input.cwd ?? taskDefaultCwd ?? (input.role !== undefined ? callerCwd : undefined);
|
|
396
367
|
const roleSpawn = input.roleSnapshot ? { role: input.roleSnapshot, warnings: [] } : input.role === undefined && input.roleSha === undefined ? undefined : await resolveSpawnProjectRole({ role: input.role, roleSha: input.roleSha, profile: input.profile, orchestratorId: input.orchestratorId, cwd: requestedCwd, preferHost: input.roleHost ?? caller?.machine ?? lineageAgent?.machine, allowedOrchestratorIds: ctx.constraints?.orchestrators, canSpawn: canSpawn(ctx) });
|
|
@@ -429,7 +400,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
429
400
|
provider: resolvedProvider, orchestratorId: input.orchestratorId, requestedCwd: repoSource ? undefined : requestedCwd, repoSource,
|
|
430
401
|
resumeWorkspace: input.resumeWorkspace, caller, lineageMachine: lineageAgent?.machine,
|
|
431
402
|
callerCwd, allowedOrchestratorIds: ctx.constraints?.orchestrators,
|
|
432
|
-
shared: workspaceMode === "shared", workspaceMode, canLand: !landBlockResolution.landBlocked, model: modelParams.model, effort: modelParams.effort,
|
|
403
|
+
shared: workspaceMode === "shared", workspaceMode, canLand: !landBlockResolution.landBlocked, buildWork: spawnBuildWork(profileName, (input.dispatch ?? linkedTask?.dispatch ?? profileSpawnDefaults.dispatch)?.type), model: modelParams.model, effort: modelParams.effort,
|
|
433
404
|
});
|
|
434
405
|
|
|
435
406
|
assertOrchestratorSupportsLaunchMode(orchestrator, launchMode, input.providerArgs);
|
|
@@ -486,7 +457,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
486
457
|
|
|
487
458
|
if (shouldAutoScaffoldTask(input, profileName)) {
|
|
488
459
|
const brief = spawnBrief(input)!;
|
|
489
|
-
linkedTask = createTaskEntity({
|
|
460
|
+
linkedTask = await createTaskEntity({
|
|
490
461
|
title: taskTitleFromBrief(brief, input.label),
|
|
491
462
|
intent: brief,
|
|
492
463
|
latestSteer: input.steer,
|
|
@@ -544,7 +515,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
544
515
|
// disk. That's only trustworthy when the spawn's target orchestrator actually shares this
|
|
545
516
|
// filesystem — a remote orchestrator's host can coincidentally have the same path with
|
|
546
517
|
// DIFFERENT content, so the gate is told explicitly rather than inferring from path existence.
|
|
547
|
-
if (agentProfile.sources?.project) agentProfile = applyProjectCapabilityGates(agentProfile, resolvedCwd, registeredProjectBeforeAutoSeed, { orchestratorLocal: isOrchestratorLocalToRelay(orchestrator), ...(projectRole ? { pinnedMcpCommit: projectRole.source.sha } : {}) });
|
|
518
|
+
if (agentProfile.sources?.project) agentProfile = (await applyProjectCapabilityGates(agentProfile, resolvedCwd, registeredProjectBeforeAutoSeed, { orchestratorLocal: isOrchestratorLocalToRelay(orchestrator), ...(projectRole ? { pinnedMcpCommit: projectRole.source.sha } : {}) }));
|
|
548
519
|
if (projectRole) assertProjectRoleMcpTrusted(projectRole, agentProfile);
|
|
549
520
|
|
|
550
521
|
// N7 — project hooks/MCP are executable code and are gated against the project
|
|
@@ -599,7 +570,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
599
570
|
}
|
|
600
571
|
|
|
601
572
|
// #3107 — the lineage coordinator's active team; a coordinator takes its project's seat, never a dissolved id.
|
|
602
|
-
const callerTeam = lineageAgentId ? acquireCoordinatorTeam(lineageAgentId) : undefined;
|
|
573
|
+
const callerTeam = lineageAgentId ? (await acquireCoordinatorTeam(lineageAgentId)) : undefined;
|
|
603
574
|
const privateTeamId = profileName === "sub-coordinator" ? newTeamId() : undefined;
|
|
604
575
|
const launchTeamId = privateTeamId ?? callerTeam?.id;
|
|
605
576
|
|
|
@@ -885,7 +856,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
885
856
|
requestedBy,
|
|
886
857
|
...(currentTask?.latestSteer ? { steer: currentTask.latestSteer } : {}),
|
|
887
858
|
});
|
|
888
|
-
autoSubscribeTaskCoordinator(requestedBy, input.taskId);
|
|
859
|
+
(await autoSubscribeTaskCoordinator(requestedBy, input.taskId));
|
|
889
860
|
} catch (err) {
|
|
890
861
|
console.warn(`task ${input.taskId} spawn attribution skipped: ${errMessage(err)}`);
|
|
891
862
|
}
|
|
@@ -50,7 +50,7 @@ export interface SpawnChainInspection {
|
|
|
50
50
|
settings: Record<string, unknown> | null;
|
|
51
51
|
/** The effective launch argv the adapter would exec. */
|
|
52
52
|
argv: string[];
|
|
53
|
-
/** The launch command (
|
|
53
|
+
/** The launch command (e.g. claude). */
|
|
54
54
|
command: string;
|
|
55
55
|
/** relay-provisioned-hooks/<ref> dir for the baseline guard. */
|
|
56
56
|
baselineHookAssetDir: string | undefined;
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { basename, join, relative } from "node:path";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
|
-
import { normalizeGitRemoteIdentity, stringValue, type AgentCard, type Orchestrator, type SpawnProvider, type WorkspaceMode, type ProjectRoot } from "@humwick/sdk";
|
|
4
|
-
import { listAgents, listOrchestrators, listWorkspaces, resolveProjectForCwd, rootsForProject, ValidationError } from "../db";
|
|
3
|
+
import { normalizeGitRemoteIdentity, stringValue, type AgentCard, type Orchestrator, type SpawnProvider, type WorkspaceMode, type ProjectRoot, type TaskDispatch } from "@humwick/sdk";
|
|
4
|
+
import { getOrchestrator, listAgents, listOrchestrators, listWorkspaces, resolveProjectForCwd, rootsForProject, ValidationError } from "../db";
|
|
5
|
+
import { listHostViews } from "../db/hosts-views";
|
|
5
6
|
import { unboundOnHost, unboundProjectRoots } from "../db/project-lifecycle";
|
|
6
7
|
import { isOrchestratorLocalToRelay, isPathWithinBase, sameHostIdentity } from "../utils";
|
|
7
8
|
import { findGitRepoRoot } from "./canonical-root";
|
|
8
9
|
import { TERMINAL_WORKSPACE_STATUSES } from "../workspace-phase";
|
|
9
|
-
import { selectSpawnPlacement, spawnPlacementCandidates, isRelayHost } from "../spawn-placement";
|
|
10
|
+
import { selectSpawnPlacement, spawnPlacementCandidates, isRelayHost, type SpawnCapOptions } from "../spawn-placement";
|
|
10
11
|
import { remoteUrlFromGitRemote } from "./git-remote";
|
|
11
12
|
import { probeHostRepo, probeLocalSourceRepo } from "./spawn-repo-probe";
|
|
12
13
|
import { hostProjectReadiness } from "./host-project-readiness";
|
|
13
14
|
|
|
15
|
+
export function spawnBuildWork(profile: string, type?: TaskDispatch["type"]): boolean {
|
|
16
|
+
return type ? !["review", "research", "ops"].includes(type) : !["reviewer", "qa", "probe", "sec-ops"].includes(profile.toLowerCase());
|
|
17
|
+
}
|
|
18
|
+
|
|
14
19
|
/** Resolve host and working directory together so capacity routing keeps the caller's repo. */
|
|
15
20
|
export async function selectSpawnCwdPlacement(input: {
|
|
16
21
|
provider: SpawnProvider;
|
|
@@ -26,15 +31,16 @@ export async function selectSpawnCwdPlacement(input: {
|
|
|
26
31
|
shared: boolean;
|
|
27
32
|
workspaceMode?: WorkspaceMode;
|
|
28
33
|
canLand?: boolean;
|
|
34
|
+
buildWork?: boolean;
|
|
29
35
|
model?: string;
|
|
30
36
|
effort?: string;
|
|
31
37
|
}): Promise<{ orchestrator: Orchestrator; placementReason: string; resolvedCwd: string; lazyRoot?: ProjectRoot }> {
|
|
32
38
|
const platformRule = input.workspaceMode === "isolated" && !input.shared && input.resumeWorkspace?.mode !== "attach"
|
|
33
39
|
? await sourcePlacementPlatforms(input) : undefined;
|
|
34
|
-
const capOpts = { ...(input.caller ? { callerAgentId: input.caller.id } : {}), attach: input.resumeWorkspace?.mode === "attach" };
|
|
40
|
+
const capOpts: SpawnCapOptions = { ...(input.caller ? { callerAgentId: input.caller.id } : {}), attach: input.resumeWorkspace?.mode === "attach", buildWork: input.buildWork };
|
|
35
41
|
const earlyPlacement = !input.orchestratorId && input.resumeWorkspace?.mode !== "attach"
|
|
36
42
|
? spawnPlacementCandidates(input.provider, input.requestedCwd, input.allowedOrchestratorIds,
|
|
37
|
-
input.shared, input.model, input.effort, input.workspaceMode, platformRule, input.canLand, capOpts)
|
|
43
|
+
input.shared, input.model, input.effort, input.buildWork === false ? undefined : input.workspaceMode, platformRule, input.canLand, capOpts)
|
|
38
44
|
: undefined;
|
|
39
45
|
const survivors = earlyPlacement?.candidates.map((host) => host.id) ?? input.allowedOrchestratorIds;
|
|
40
46
|
// Preserve selection's detailed exclusion error without probing hosts already ruled out.
|
|
@@ -43,6 +49,16 @@ export async function selectSpawnCwdPlacement(input: {
|
|
|
43
49
|
input.model, input.effort, input.workspaceMode, platformRule, input.canLand, capOpts);
|
|
44
50
|
const { attachWorkspace, hostCwds, allowedOrchestratorIds, lazyRoots, exclusions: checkoutExclusions = [] } = await omittedHostContext({ ...input, allowedOrchestratorIds: survivors });
|
|
45
51
|
const requestedCwd = input.repoSource && !hostCwds ? input.repoSource : input.requestedCwd;
|
|
52
|
+
// Review/QA setup depends on the target checkout HEAD; a caller's policy base cannot vouch for it (#3805).
|
|
53
|
+
if (input.workspaceMode === "isolated" && input.buildWork === false && !input.resumeWorkspace) {
|
|
54
|
+
const views = new Map(listHostViews(Date.now()).map((view) => [view.id, view]));
|
|
55
|
+
const hosts = input.orchestratorId ? [getOrchestrator(input.orchestratorId)].filter((host): host is Orchestrator => !!host) : earlyPlacement?.candidates ?? [];
|
|
56
|
+
const lightHosts = await Promise.all(hosts.filter((host) => isRelayHost(host, host.hostId ? views.get(host.hostId) : undefined)).map(async (host) => {
|
|
57
|
+
const probe = await probeHostRepo(host, requestedCwd ?? hostCwds?.get(host.id) ?? input.callerCwd ?? host.baseDir, undefined, true);
|
|
58
|
+
return probe.kind === "present" && probe.workspaceDepsDisabled === true ? host.id : undefined;
|
|
59
|
+
}));
|
|
60
|
+
capOpts.workspaceDepsDisabledHosts = lightHosts.filter((id): id is string => id !== undefined);
|
|
61
|
+
}
|
|
46
62
|
// #3169/#3625 — capacity ranks only hosts whose own checkout is ready for the project (refresh hook, toolchain).
|
|
47
63
|
const readiness = hostProjectReadiness();
|
|
48
64
|
const readinessExclusions: string[] = [];
|