@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/routes/messages.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { sendMessageWithResultAsync, sendMessageAsync } from "../db/message-send";
|
|
1
2
|
import { authorityDenied } from "../authority-audit";
|
|
2
3
|
// Auto-split from routes.ts (#299). Domain: messages.
|
|
3
4
|
import { MAX_BODY_BYTES } from "../config";
|
|
4
|
-
import { ValidationError, applyMessageDeliveryActionAsync, claimMessageAsync, deleteMessageAsync, getAgent, getLatestMessageIdAsync, getMessage, getMessageAsync, getMessageDeliveryStatusAsync, getThreadAsync, listQueuedMessagesAsync, listRecentMessagesAsync, markReadAsync, pollMessagesAsync, recordMessageDeliveryAttemptAsync, renewMessageClaimAsync,
|
|
5
|
+
import { ValidationError, applyMessageDeliveryActionAsync, claimMessageAsync, deleteMessageAsync, getAgent, getLatestMessageIdAsync, getMessage, getMessageAsync, getMessageDeliveryStatusAsync, getThreadAsync, listQueuedMessagesAsync, listRecentMessagesAsync, markReadAsync, pollMessagesAsync, recordMessageDeliveryAttemptAsync, renewMessageClaimAsync, setMessageReactionAsync, isChannelEgressTarget } from "../db";
|
|
5
6
|
import { requestUserAddress, resolveActingUser, auditEvent, cleanAttachmentRefs, dispatchTaskCallbacksInBackground, emitCommand, error, json, normalizeAgentSessionGuard, parseBody, parseId, parseQueryInt, reactionEmoji, sendReactionNotificationToAuthor, withPayloadAttachments, type Handler } from "./_shared";
|
|
6
7
|
import { cleanMeta, cleanParams, cleanPositiveId, cleanString, optionalEnum } from "../validation";
|
|
7
8
|
import { emitMessageClaimed, emitMessageDeleted, emitMessageDeliveryUpdated, emitMessageQueued, emitMessageReactionUpdated, emitNewMessage, emitTaskChanged } from "../sse";
|
|
@@ -12,12 +13,11 @@ import { authContextFromRequest } from "../services/auth-context";
|
|
|
12
13
|
import { sendMessagesBatchService, sendMessageServiceAsync } from "../services/send-message";
|
|
13
14
|
import { recordFanoutSuppression } from "../services/channel-suppression-receipt";
|
|
14
15
|
import { fanOutToAgent } from "../services/agent-message-fanout";
|
|
15
|
-
import { isChannelEgressTarget } from "../db";
|
|
16
16
|
import { CHANNEL_SUPPRESSION_REASON, isDisallowedChannelContent } from "../db/channel-egress-allowlist.ts";
|
|
17
17
|
import { settleParkedSelfResumeContinuation } from "../self-resume";
|
|
18
18
|
import { AmbiguousTargetError, ServiceAuthError } from "../services/errors";
|
|
19
19
|
import { reEvaluateChannelDelivery } from "../services/message-delivery-actions";
|
|
20
|
-
import { isOtherHumanSink, messageVisibleTo } from "../message-visibility";
|
|
20
|
+
import { isOtherHumanSink, messageVisibleTo, type MessageViewer } from "../message-visibility";
|
|
21
21
|
import { messageViewerForRequest, visibleMessages } from "./message-viewer";
|
|
22
22
|
import { type AgentSessionGuard, type Message, type PollQuery, type SendMessageInput } from "../types";
|
|
23
23
|
|
|
@@ -136,7 +136,7 @@ export const postMessageDeliveryAttempt: Handler = async (req, params) => {
|
|
|
136
136
|
}, idempotencyKey);
|
|
137
137
|
if (!result.ok) return error(result.error ?? "message not found", result.error === "message not found" ? 404 : 409);
|
|
138
138
|
emitMessageDeliveryUpdated(result.message!);
|
|
139
|
-
if (status === "delivered") settleParkedSelfResumeContinuation(result.message!);
|
|
139
|
+
if (status === "delivered") (await settleParkedSelfResumeContinuation(result.message!));
|
|
140
140
|
return json(await getMessageDeliveryStatusAsync(id), 201);
|
|
141
141
|
} catch (e) {
|
|
142
142
|
if (e instanceof ValidationError) return error(e.message, 400);
|
|
@@ -222,13 +222,13 @@ export const postSystemBroadcast: Handler = async (req) => {
|
|
|
222
222
|
const body = parsed.body;
|
|
223
223
|
if (!body?.body) return error("body required");
|
|
224
224
|
try {
|
|
225
|
-
const msg =
|
|
225
|
+
const msg = (await sendMessageAsync({
|
|
226
226
|
from: "system",
|
|
227
227
|
to: "broadcast",
|
|
228
228
|
kind: "system",
|
|
229
229
|
subject: body.subject ?? undefined,
|
|
230
230
|
body: body.body,
|
|
231
|
-
});
|
|
231
|
+
}));
|
|
232
232
|
emitNewMessage(msg);
|
|
233
233
|
return json(msg, 201);
|
|
234
234
|
} catch (e) {
|
|
@@ -351,7 +351,7 @@ export const getMessages: Handler = async (req) => {
|
|
|
351
351
|
const channel = url.searchParams.get("channel") ?? undefined;
|
|
352
352
|
// #3567 D6 — a non-admin reads only their own human sink; another human's inbox is a 403.
|
|
353
353
|
const viewer = messageViewerForRequest(req);
|
|
354
|
-
if (forAgent && isOtherHumanSink(viewer, forAgent)) return authorityDenied(req, "you can only read your own messages", 403, forAgent, "read sink");
|
|
354
|
+
if (forAgent && isOtherHumanSink(viewer, forAgent)) return (await authorityDenied(req, "you can only read your own messages", 403, forAgent, "read sink"));
|
|
355
355
|
|
|
356
356
|
// No agent filter — return all recent messages
|
|
357
357
|
if (!forAgent) {
|
|
@@ -367,6 +367,12 @@ export const getMessages: Handler = async (req) => {
|
|
|
367
367
|
channel,
|
|
368
368
|
limit,
|
|
369
369
|
};
|
|
370
|
+
return json(await pollAgentMessages(viewer, pollQuery));
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
/** Shared display/turn-delivery polling for GET messages and the liveness exchange (#3608). */
|
|
374
|
+
export async function pollAgentMessages(viewer: MessageViewer | null, pollQuery: PollQuery): Promise<Message[]> {
|
|
375
|
+
const forAgent = pollQuery.for;
|
|
370
376
|
//
|
|
371
377
|
// #2335 (P1 privacy) — a poll whose `for` resolves to a channel-egress bridge is a DELIVERY poll by
|
|
372
378
|
// construction: the only thing on the other end is a bridge about to forward what it receives into a
|
|
@@ -394,18 +400,18 @@ export const getMessages: Handler = async (req) => {
|
|
|
394
400
|
// gets the COMPLETE set: `history` is still dashboard/thread-visible by definition, and this endpoint is
|
|
395
401
|
// where the dashboard reads it. Suppressing there would evict it from the view (dashboard merge REPLACEs),
|
|
396
402
|
// breaking the "no data loss" invariant — so the seam gates delivery, never display.
|
|
397
|
-
if (
|
|
403
|
+
if (!pollQuery.turnDelivery) return polled;
|
|
398
404
|
const delivered: Message[] = [];
|
|
399
405
|
for (const msg of polled) fanOutToAgent(forAgent, msg, () => delivered.push(msg));
|
|
400
|
-
return
|
|
401
|
-
}
|
|
406
|
+
return delivered;
|
|
407
|
+
}
|
|
402
408
|
|
|
403
409
|
export const getMessageById: Handler = async (req, params) => {
|
|
404
410
|
const id = parseId(params.id);
|
|
405
411
|
if (id === null) return error("invalid message id");
|
|
406
412
|
const msg = await getMessageAsync(id);
|
|
407
413
|
if (!msg) return error("message not found", 404);
|
|
408
|
-
return messageVisibleTo(messageViewerForRequest(req), msg) ? json(msg) : authorityDenied(req, "you can only read your own messages", 403, String(id), "read message");
|
|
414
|
+
return messageVisibleTo(messageViewerForRequest(req), msg) ? json(msg) : (await authorityDenied(req, "you can only read your own messages", 403, String(id), "read message"));
|
|
409
415
|
};
|
|
410
416
|
|
|
411
417
|
export const getMessageThread: Handler = async (req, params) => {
|
|
@@ -415,7 +421,7 @@ export const getMessageThread: Handler = async (req, params) => {
|
|
|
415
421
|
if (!thread.length) return error("message not found", 404);
|
|
416
422
|
const viewer = messageViewerForRequest(req);
|
|
417
423
|
const root = thread.find((message) => message.id === id);
|
|
418
|
-
if (root && !messageVisibleTo(viewer, root)) return authorityDenied(req, "you can only read your own messages", 403, String(id), "read thread");
|
|
424
|
+
if (root && !messageVisibleTo(viewer, root)) return (await authorityDenied(req, "you can only read your own messages", 403, String(id), "read thread"));
|
|
419
425
|
return json(visibleMessages(viewer, thread));
|
|
420
426
|
};
|
|
421
427
|
|
|
@@ -537,7 +543,7 @@ function channelReactionActor(actorId: string): Record<string, unknown> {
|
|
|
537
543
|
};
|
|
538
544
|
}
|
|
539
545
|
|
|
540
|
-
function sendOutboundChannelReaction(parent: Message, actorId: string, emoji: string): void {
|
|
546
|
+
async function sendOutboundChannelReaction(parent: Message, actorId: string, emoji: string): Promise<void> {
|
|
541
547
|
if (!parent.channel) return;
|
|
542
548
|
const target = telegramTargetFromMessage(parent);
|
|
543
549
|
if (!target) return;
|
|
@@ -545,7 +551,7 @@ function sendOutboundChannelReaction(parent: Message, actorId: string, emoji: st
|
|
|
545
551
|
const accountId = target.accountId ?? cleanString(payloadChannel.accountId, "payload.channel.accountId", { max: 200 }) ?? "default";
|
|
546
552
|
const conversation = isRecord(parent.payload?.conversation) ? parent.payload.conversation : undefined;
|
|
547
553
|
const now = Date.now();
|
|
548
|
-
const result =
|
|
554
|
+
const result = (await sendMessageWithResultAsync({
|
|
549
555
|
from: actorId,
|
|
550
556
|
to: parent.channel,
|
|
551
557
|
kind: "channel.event",
|
|
@@ -580,7 +586,7 @@ function sendOutboundChannelReaction(parent: Message, actorId: string, emoji: st
|
|
|
580
586
|
},
|
|
581
587
|
},
|
|
582
588
|
},
|
|
583
|
-
});
|
|
589
|
+
}));
|
|
584
590
|
if (result.created) {
|
|
585
591
|
if (result.message.deliveryStatus === "queued") emitMessageQueued(result.message);
|
|
586
592
|
else emitNewMessage(result.message);
|
|
@@ -601,8 +607,8 @@ export const postMessageReaction: Handler = async (req, params) => {
|
|
|
601
607
|
const result = await setMessageReactionAsync({ messageId: id, actorId, emoji, action });
|
|
602
608
|
if (!result.ok) return error(result.error, result.error === "message not found" ? 404 : 400);
|
|
603
609
|
emitMessageReactionUpdated(result.message);
|
|
604
|
-
if (action === "add") sendOutboundChannelReaction(result.message, actorId, emoji);
|
|
605
|
-
sendReactionNotificationToAuthor(result.message, actorId, emoji, action);
|
|
610
|
+
if (action === "add") (await sendOutboundChannelReaction(result.message, actorId, emoji));
|
|
611
|
+
(await sendReactionNotificationToAuthor(result.message, actorId, emoji, action));
|
|
606
612
|
return json(result.message);
|
|
607
613
|
} catch (e) {
|
|
608
614
|
if (e instanceof ValidationError) return error(e.message, 400);
|
|
@@ -76,7 +76,7 @@ export const postOrchestratorBootstrapExchange: Handler = async (req) => {
|
|
|
76
76
|
if (!isRecord(parsed.body)) return error("body required");
|
|
77
77
|
const id = cleanString(parsed.body.id, "id", { required: true, max: 120 })!;
|
|
78
78
|
const baseDir = cleanString(parsed.body.baseDir, "baseDir", { required: true, max: 500 })!;
|
|
79
|
-
const denied = authorizeRoute(req, { scope: "token:write", resource: { orchestratorId: id } });
|
|
79
|
+
const denied = (await authorizeRoute(req, { scope: "token:write", resource: { orchestratorId: id } }));
|
|
80
80
|
if (denied) return denied;
|
|
81
81
|
const auth = getComponentAuth(req);
|
|
82
82
|
if (!auth || auth.role !== "orchestrator-bootstrap") return error("bootstrap token required", 403);
|
|
@@ -8,6 +8,7 @@ import { conflictingHardwareFields, upsertHostFromRegistrationAsync, type HostRe
|
|
|
8
8
|
import { auditEvent, cleanSafeNumber } from "./_shared";
|
|
9
9
|
import { recordOrchestratorUtilization } from "./orchestrator-host-utilization";
|
|
10
10
|
import { cleanString } from "../validation";
|
|
11
|
+
import { reportRuntimeDependencyFailure } from "../services/runtime-dependency-alert";
|
|
11
12
|
|
|
12
13
|
// The machine fingerprint an orchestrator reports at registration (§3.5). Lenient/observability-grade
|
|
13
14
|
// like `cleanQueuedSpawns`: a malformed blob yields `undefined` (treated as "no fingerprint", never a
|
|
@@ -118,6 +119,7 @@ export async function linkOrchestratorHost(orchestratorId: string, hostname: str
|
|
|
118
119
|
const result = await upsertHostFromRegistrationAsync({ orchestratorId, hostname, hardware });
|
|
119
120
|
await emitHostRegistrationEvents(result.events);
|
|
120
121
|
await recordOrchestratorUtilization(orchestratorId, result.host.id, body);
|
|
122
|
+
await reportRuntimeDependencyFailure(result.host.id, hostname, body);
|
|
121
123
|
} catch (err) {
|
|
122
124
|
// Additive over the orchestrator row; log so it is visible, then let the heartbeat path retry.
|
|
123
125
|
console.warn(`[relay] host registration for orchestrator ${orchestratorId} (${hostname}) failed; will self-heal on next heartbeat:`, err);
|
|
@@ -247,11 +247,11 @@ export async function recordOrchestratorUtilization(
|
|
|
247
247
|
const sample = cleanHostUtilizationSample(raw, now);
|
|
248
248
|
if (!sample) return false;
|
|
249
249
|
const gateArming = cleanGateArming(isRecord(body) ? body.gateArming : undefined, now);
|
|
250
|
-
return recordHostUtilization({
|
|
250
|
+
return (await recordHostUtilization({
|
|
251
251
|
hostId,
|
|
252
252
|
orchestratorId,
|
|
253
253
|
machine: { ...toMachineSample(sample), ...(gateArming ? { gateArming } : {}) },
|
|
254
254
|
daemon: toDaemonSample(sample),
|
|
255
255
|
now,
|
|
256
|
-
});
|
|
256
|
+
}));
|
|
257
257
|
}
|
|
@@ -153,8 +153,8 @@ export const getOrchestratorSessions: Handler = (req, params) => proxyOrchestrat
|
|
|
153
153
|
|
|
154
154
|
export const getOrchestratorVersion: Handler = (req, params) => proxyOrchestratorGet(req, params.id!, "/api/version");
|
|
155
155
|
|
|
156
|
-
export const getOrchestratorLogs: Handler = (req, params) => {
|
|
157
|
-
const denied = authorizeRoute(req, { scope: "logs:read", resource: { orchestratorId: params.id!, logsRead: true } });
|
|
156
|
+
export const getOrchestratorLogs: Handler = async (req, params) => {
|
|
157
|
+
const denied = (await authorizeRoute(req, { scope: "logs:read", resource: { orchestratorId: params.id!, logsRead: true } }));
|
|
158
158
|
return denied ?? proxyOrchestratorGet(req, params.id!, `/api/logs/${encodeURIComponent(params.session!)}`);
|
|
159
159
|
};
|
|
160
160
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { deleteOrchestratorAsync } from "../db/runtime-tail-async";
|
|
1
2
|
import { cleanBrowserInventory, reconcileBrowserInventory } from "../services/browser-inventory";
|
|
2
3
|
// Auto-split from routes.ts (#299). Domain: orchestrator.
|
|
3
4
|
import { APPROVAL_MODES, SPAWN_PROVIDERS, VALID_WORKSPACE_MODES, fireAndForget, isRecord } from "@humwick/sdk";
|
|
@@ -6,7 +7,7 @@ import { CONTRACT_VERSIONS, parseRuntimeCapabilities, parseRuntimeContracts, par
|
|
|
6
7
|
import { notifyAgentOffline, notifyAgentSpawnQueued } from "../agent-lifecycle-events";
|
|
7
8
|
import { diagnoseReportedExit } from "../services/reported-exit-death";
|
|
8
9
|
import { VERSION } from "../config";
|
|
9
|
-
import { ValidationError,
|
|
10
|
+
import { ValidationError, effectiveProviderCatalogListAsync, getAgent, getOrchestrator, getOrchestratorAsync, listOrchestrators, listOrchestratorsAsync, orchestratorHeartbeatAsync, recordAgentExitDiagnosticsAsync, reportOrchestratorRosterAsync, setOrchestratorUpgradeStateAsync, upsertOrchestratorAsync } from "../db";
|
|
10
11
|
import { reconcileOrchestratorSchedulerCommands } from "../services/scheduler-recovery.ts";
|
|
11
12
|
import { recoverRegisteredOrchestrator } from "../services/orchestrator-registration-recovery";
|
|
12
13
|
import { recoverOrchestratorLegacyLandings } from "../services/orchestrator-landing-recovery";
|
|
@@ -24,10 +25,9 @@ import { serializeCommandForRead } from "../services/dispatch-command";
|
|
|
24
25
|
import { isOrchestratorRegistrationAuthorized } from "../security";
|
|
25
26
|
import { isOrchestratorSelfReportAuthorized } from "../orchestrator-self-report-authz";
|
|
26
27
|
import { getHostProviderSetting } from "../host-provider-store";
|
|
27
|
-
import { hostDisabledFromValue } from "../host-provider-enablement";
|
|
28
|
+
import { hostDisabledFromValue, isHostSwitchableProvider } from "../host-provider-enablement";
|
|
28
29
|
import { seedHostProviders } from "../services/host-providers";
|
|
29
|
-
import {
|
|
30
|
-
import { type ManagedAgent, type ManagedSessionExitDiagnostics, type OrchestratorRuntimeInput, type QueuedSpawn, type RegisterOrchestratorInput, type SpawnApprovalMode, type SpawnProvider } from "../types";
|
|
30
|
+
import { type ManagedAgent, type ManagedSessionExitDiagnostics, type Orchestrator, type OrchestratorRuntimeInput, type QueuedSpawn, type RegisterOrchestratorInput, type SpawnApprovalMode, type SpawnProvider } from "../types";
|
|
31
31
|
import { restartSpawnParamsForAgentAsync } from "../services/restart-spawn";
|
|
32
32
|
import { cleanProjectToolchain } from "../project-toolchain";
|
|
33
33
|
import { cleanHostTools } from "../host-tools";
|
|
@@ -215,8 +215,17 @@ function orchestratorSelfReportDenied(req: Request, orchestratorId: string): Res
|
|
|
215
215
|
return error("forbidden: only the orchestrator itself may report its host state", 403);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
+
// #2410 — the list is polled by every open dashboard and the per-host `providerCatalog` (a
|
|
219
|
+
// deprecated host snapshot, stored in the row and again in `meta`) was ~85% of a 515 KB response
|
|
220
|
+
// nothing reads: the hub owns the model catalog. It stays on the row (`GET /:id`) and in the DB.
|
|
221
|
+
function withoutHostCatalog(orch: Orchestrator): Orchestrator {
|
|
222
|
+
const { providerCatalog: _snapshot, ...row } = orch;
|
|
223
|
+
const { providerCatalog: _metaSnapshot, ...meta } = orch.meta;
|
|
224
|
+
return { ...row, meta };
|
|
225
|
+
}
|
|
226
|
+
|
|
218
227
|
export const getOrchestrators: Handler = async () => {
|
|
219
|
-
return json(await listOrchestratorsAsync());
|
|
228
|
+
return json((await listOrchestratorsAsync()).map(withoutHostCatalog));
|
|
220
229
|
};
|
|
221
230
|
|
|
222
231
|
export const getOrchestratorById: Handler = async (_req, params) => {
|
|
@@ -239,7 +248,7 @@ export const postOrchestratorHeartbeat: Handler = async (req, params) => {
|
|
|
239
248
|
const parsed = await parseBody<unknown>(req);
|
|
240
249
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
241
250
|
try {
|
|
242
|
-
const denied = authorizeRoute(req, { scope: "command:write", resource: { orchestratorId: params.id! } });
|
|
251
|
+
const denied = (await authorizeRoute(req, { scope: "command:write", resource: { orchestratorId: params.id! } }));
|
|
243
252
|
if (denied) return denied;
|
|
244
253
|
// #1797 round 2 (F1) — same self-report claim as the roster PATCH: this writes the host's
|
|
245
254
|
// reported version/providers/capabilities, which the upgrade reconcile then acts on.
|
|
@@ -292,7 +301,7 @@ export const patchOrchestratorAgents: Handler = async (req, params) => {
|
|
|
292
301
|
try {
|
|
293
302
|
const orch = getOrchestrator(params.id!);
|
|
294
303
|
if (!orch) return error("orchestrator not found", 404);
|
|
295
|
-
const denied = authorizeRoute(req, { scope: "command:write", resource: { orchestratorId: orch.id } });
|
|
304
|
+
const denied = (await authorizeRoute(req, { scope: "command:write", resource: { orchestratorId: orch.id } }));
|
|
296
305
|
if (denied) return denied;
|
|
297
306
|
// #1797 round 2 (F1) — this roster IS the input to the managed-state reconcile; the scope +
|
|
298
307
|
// resource check above cannot establish that the caller IS this orchestrator. See the helper.
|
|
@@ -344,7 +353,7 @@ export const patchOrchestratorAgents: Handler = async (req, params) => {
|
|
|
344
353
|
if (queuedSpawns) {
|
|
345
354
|
for (const queued of queuedSpawns) {
|
|
346
355
|
if (!queued.spawnedBy) continue;
|
|
347
|
-
notifyAgentSpawnQueued({
|
|
356
|
+
await notifyAgentSpawnQueued({
|
|
348
357
|
parent: queued.spawnedBy,
|
|
349
358
|
spawnRequestId: queued.spawnRequestId,
|
|
350
359
|
provider: queued.provider,
|
|
@@ -357,7 +366,7 @@ export const patchOrchestratorAgents: Handler = async (req, params) => {
|
|
|
357
366
|
// between the ack and this call, so reconciles still run in request order. Running it after
|
|
358
367
|
// the exit-audit loop below (which awaits the async gateway per exited agent) let a stale,
|
|
359
368
|
// superseded roster from a slow request land AFTER a newer report's reconcile and overwrite it.
|
|
360
|
-
getLifecycleManager().onOrchestratorManagedAgentsReported(params.id!, cleaned, exitedAgents);
|
|
369
|
+
(await getLifecycleManager().onOrchestratorManagedAgentsReported(params.id!, cleaned, exitedAgents));
|
|
361
370
|
for (const exited of exitedAgents) {
|
|
362
371
|
const agent = await recordAgentExitDiagnosticsAsync(exited.agentId, exited);
|
|
363
372
|
if (agent) {
|
|
@@ -370,7 +379,7 @@ export const patchOrchestratorAgents: Handler = async (req, params) => {
|
|
|
370
379
|
// #636 — classify the death from the captured exit diagnostics + agent state and ride the
|
|
371
380
|
// verdict on the terminal event (also persisted as a crash report inside notifyAgentOffline).
|
|
372
381
|
// Exit diagnostics remain on replay; the shared generation ledger dedups the parent notice.
|
|
373
|
-
notifyAgentOffline(exited.agentId, exitReason(exited), diagnoseReportedExit(agent, exitReason(exited), exited));
|
|
382
|
+
(await notifyAgentOffline(exited.agentId, exitReason(exited), diagnoseReportedExit(agent, exitReason(exited), exited)));
|
|
374
383
|
}
|
|
375
384
|
await auditEvent({
|
|
376
385
|
clientId: [
|
|
@@ -550,9 +559,9 @@ export const postOrchestratorAction: Handler = async (req, params) => {
|
|
|
550
559
|
if (action === "migrate-provider-config") {
|
|
551
560
|
// #1259 — fleet-wide host action: a command:fleet-scoped token may cross its own
|
|
552
561
|
// cwd/orchestrator sandbox pin for this action only.
|
|
553
|
-
const denied = authorizeFleetRoute(req, { orchestratorId: orch.id });
|
|
562
|
+
const denied = (await authorizeFleetRoute(req, { orchestratorId: orch.id }));
|
|
554
563
|
if (denied) return denied;
|
|
555
|
-
const command = dispatchProviderConfigMigration(orch, "dashboard");
|
|
564
|
+
const command = (await dispatchProviderConfigMigration(orch, "dashboard"));
|
|
556
565
|
if (!command) return error(`orchestrator ${orch.id} does not support provider-config migration; upgrade it first`, 409);
|
|
557
566
|
await auditEvent({
|
|
558
567
|
clientId: `server-orchestrator-migrate-provider-config-${orch.id}-${command.id}`,
|
|
@@ -570,7 +579,7 @@ export const postOrchestratorAction: Handler = async (req, params) => {
|
|
|
570
579
|
if (action === "upgrade") {
|
|
571
580
|
// #1259 — fleet-wide host action: a command:fleet-scoped token may cross its own
|
|
572
581
|
// cwd/orchestrator sandbox pin for this action only.
|
|
573
|
-
const denied = authorizeFleetRoute(req, { orchestratorId: orch.id });
|
|
582
|
+
const denied = (await authorizeFleetRoute(req, { orchestratorId: orch.id }));
|
|
574
583
|
if (denied) return denied;
|
|
575
584
|
const targetVersion = cleanString(parsed.body.targetVersion, "targetVersion", { max: 80 }) ?? VERSION;
|
|
576
585
|
if (!ORCH_UPGRADE_SEMVER_RE.test(targetVersion)) return error("targetVersion must be a semver like 0.10.20");
|
|
@@ -657,8 +666,8 @@ export const postOrchestratorAction: Handler = async (req, params) => {
|
|
|
657
666
|
// command:fleet; "shutdown" is NOT in that enumeration and stays on the constrained path.
|
|
658
667
|
const resource = { orchestratorId: orch.id, agentId, policyName, spawnRequestId };
|
|
659
668
|
const denied = action === "restart"
|
|
660
|
-
? authorizeFleetRoute(req, resource)
|
|
661
|
-
: authorizeRoute(req, { scope: "command:write", resource });
|
|
669
|
+
? (await authorizeFleetRoute(req, resource))
|
|
670
|
+
: (await authorizeRoute(req, { scope: "command:write", resource }));
|
|
662
671
|
if (denied) return denied;
|
|
663
672
|
const agent = action === "restart" && agentId ? getAgent(agentId) : undefined;
|
|
664
673
|
const restartSpawn = agent ? await restartSpawnParamsForAgentAsync(agent, orch, policyName, spawnRequestId) : undefined;
|
|
@@ -690,10 +699,10 @@ export const postOrchestratorAction: Handler = async (req, params) => {
|
|
|
690
699
|
}
|
|
691
700
|
};
|
|
692
701
|
|
|
693
|
-
export const deleteOrchestratorById: Handler = (req, params) => {
|
|
694
|
-
const denied = authorizeRoute(req, { scope: "system:admin", resource: { orchestratorId: params.id! } });
|
|
702
|
+
export const deleteOrchestratorById: Handler = async (req, params) => {
|
|
703
|
+
const denied = (await authorizeRoute(req, { scope: "system:admin", resource: { orchestratorId: params.id! } }));
|
|
695
704
|
if (denied) return denied;
|
|
696
|
-
const deleted =
|
|
705
|
+
const deleted = (await deleteOrchestratorAsync(params.id!));
|
|
697
706
|
if (!deleted) return error("orchestrator not found", 404);
|
|
698
707
|
return json({ ok: true });
|
|
699
708
|
};
|
package/src/routes/pairs.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { sendPairMessageAsync, rejectPairAsync, endPairAsync, createPairAsync, acceptPairAsync, getPairAsync, listPairsAsync } from "../db/pairs-async";
|
|
1
2
|
// Auto-split from routes.ts (#299). Domain: pairs.
|
|
2
3
|
import { MAX_BODY_BYTES } from "../config";
|
|
3
|
-
import { ValidationError,
|
|
4
|
+
import { ValidationError, getPair, listAgents, listPairs } from "../db";
|
|
4
5
|
import { resolveCallerAgentId } from "../agent-ref";
|
|
5
6
|
import { getComponentAuth, hasComponentScope } from "../security";
|
|
6
7
|
import { auditEvent, authorizeRoute, error, json, parseBody, type Handler } from "./_shared";
|
|
@@ -59,7 +60,7 @@ export const postPair: Handler = async (req) => {
|
|
|
59
60
|
const parsed = await parseBody<unknown>(req);
|
|
60
61
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
61
62
|
try {
|
|
62
|
-
const result =
|
|
63
|
+
const result = (await createPairAsync(normalizeCreatePairInput(parsed.body)));
|
|
63
64
|
if (!result.ok) return pairError(result);
|
|
64
65
|
emitNewMessage(result.invite);
|
|
65
66
|
await auditEvent({
|
|
@@ -96,7 +97,7 @@ export const getPairs: Handler = async (req) => {
|
|
|
96
97
|
? resolveCallerAgentId(component.constraints, listAgents)
|
|
97
98
|
: undefined;
|
|
98
99
|
if (!(agentId && callerAgentId === agentId && component && hasComponentScope(component, "agent:read"))) {
|
|
99
|
-
const denied = authorizeRoute(req, { scope: "pairs:read" });
|
|
100
|
+
const denied = (await authorizeRoute(req, { scope: "pairs:read" }));
|
|
100
101
|
if (denied) return denied;
|
|
101
102
|
}
|
|
102
103
|
|
|
@@ -115,7 +116,7 @@ export const postAcceptPair: Handler = async (req, params) => {
|
|
|
115
116
|
const parsed = await parseBody<unknown>(req);
|
|
116
117
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
117
118
|
try {
|
|
118
|
-
const result =
|
|
119
|
+
const result = (await acceptPairAsync(params.id!, normalizePairActionInput(parsed.body)));
|
|
119
120
|
if (!result.ok) return pairError(result);
|
|
120
121
|
for (const notice of result.notices) emitNewMessage(notice);
|
|
121
122
|
await auditEvent({
|
|
@@ -140,7 +141,7 @@ export const postRejectPair: Handler = async (req, params) => {
|
|
|
140
141
|
const parsed = await parseBody<unknown>(req);
|
|
141
142
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
142
143
|
try {
|
|
143
|
-
const result =
|
|
144
|
+
const result = (await rejectPairAsync(params.id!, normalizePairActionInput(parsed.body)));
|
|
144
145
|
if (!result.ok) return pairError(result);
|
|
145
146
|
emitNewMessage(result.notice);
|
|
146
147
|
await auditEvent({
|
|
@@ -165,7 +166,7 @@ export const postHangupPair: Handler = async (req, params) => {
|
|
|
165
166
|
const parsed = await parseBody<unknown>(req);
|
|
166
167
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
167
168
|
try {
|
|
168
|
-
const result =
|
|
169
|
+
const result = (await endPairAsync(params.id!, normalizePairActionInput(parsed.body)));
|
|
169
170
|
if (!result.ok) return pairError(result);
|
|
170
171
|
if (result.notice) emitNewMessage(result.notice);
|
|
171
172
|
await auditEvent({
|
|
@@ -190,7 +191,7 @@ export const postPairMessage: Handler = async (req, params) => {
|
|
|
190
191
|
const parsed = await parseBody<unknown>(req);
|
|
191
192
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
192
193
|
try {
|
|
193
|
-
const result =
|
|
194
|
+
const result = (await sendPairMessageAsync(params.id!, normalizePairMessageInput(parsed.body)));
|
|
194
195
|
if (!result.ok) return pairError(result);
|
|
195
196
|
emitNewMessage(result.message);
|
|
196
197
|
await auditEvent({
|
|
@@ -211,4 +212,3 @@ export const postPairMessage: Handler = async (req, params) => {
|
|
|
211
212
|
throw e;
|
|
212
213
|
}
|
|
213
214
|
};
|
|
214
|
-
import { getPairAsync, listPairsAsync } from "../db/pairs-async";
|
|
@@ -6,7 +6,7 @@ import { PromptVersionConflictError } from "../prompt-version-errors";
|
|
|
6
6
|
import { listProjectProfileInstructions, mutateProjectProfileInstructions, projectProfileInstructionHistory, readProjectProfileInstructions } from "../services/project-profile-instructions";
|
|
7
7
|
|
|
8
8
|
export const projectProfileInstructionsRoute: Handler = async (req, params) => {
|
|
9
|
-
const denied = authorizeRoute(req, { scope: req.method === "GET" ? "agent:read" : "agent:write" });
|
|
9
|
+
const denied = (await authorizeRoute(req, { scope: req.method === "GET" ? "agent:read" : "agent:write" }));
|
|
10
10
|
if (denied) return denied;
|
|
11
11
|
try {
|
|
12
12
|
const projectId = cleanString(params.id, "projectId", { max: 200 });
|
|
@@ -32,7 +32,7 @@ export const postProjectTrustApproveRoute: Handler = async (req, params) => {
|
|
|
32
32
|
const mode = optionalEnum(body.mode, "mode", ["fingerprint", "commit"] as const);
|
|
33
33
|
if (mode && !approvedValue.startsWith(mode === "commit" ? "commit:" : "sha256:")) return error(`approved value must be prefixed "${mode === "commit" ? "commit:" : "sha256:"}" for ${mode} review`, 400);
|
|
34
34
|
|
|
35
|
-
const approval = approveProfileProjectTrust({ name, capability, repoKey, value: approvedValue, by: requestUserAddress(req) });
|
|
35
|
+
const approval = (await approveProfileProjectTrust({ name, capability, repoKey, value: approvedValue, by: requestUserAddress(req) }));
|
|
36
36
|
await auditEvent({
|
|
37
37
|
kind: "state",
|
|
38
38
|
title: `Project trust approved: ${name} / ${capability}`,
|
package/src/routes/projects.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getProjectEntryAsync, getProjectEntryChainAsync, listProjectsAsync, resolveProjectAsync, resolveProjectEntriesAsync, retractProjectEntryAsync, rootsForProjectAsync, searchProjectEntriesAsync, writeProjectEntryAsync, ValidationError } from "../db";
|
|
2
2
|
import { resolveProjectForCanonicalCwdAsync } from "../services/project";
|
|
3
3
|
import { authContextFromRequest } from "../services/auth-context";
|
|
4
4
|
import { callerProfile, resolveAgentWriteInject } from "../services/memory-identity";
|
|
@@ -14,7 +14,7 @@ import { PROJECT_ENTRY_INJECT_TIERS, PROJECT_ENTRY_KINDS, type ProjectEntry, typ
|
|
|
14
14
|
//
|
|
15
15
|
// #1940 Part 2 — manual/promoted entry CRUD from the dashboard. Mutations are thin wrappers
|
|
16
16
|
// around the SAME db functions the audited `relay_project_write_entry`/`relay_project_retract`
|
|
17
|
-
// MCP tools call (
|
|
17
|
+
// MCP tools call (writeProjectEntryAsync/retractProjectEntryAsync, src/db/project-entries.ts) — one
|
|
18
18
|
// write path for both surfaces, never a direct/duplicated DB write here. `ingested` entries
|
|
19
19
|
// are refused because the CLAUDE.md ingest pipeline owns them. `steward` entries remain
|
|
20
20
|
// operator-curatable: an edit adopts the replacement as `manual` input for a later sweep.
|
|
@@ -103,12 +103,12 @@ export const getProjectResolveRoute: Handler = async (req) => {
|
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
-
export const getProjectEntryRoute: Handler = (req, params) => {
|
|
106
|
+
export const getProjectEntryRoute: Handler = async (req, params) => {
|
|
107
107
|
try {
|
|
108
108
|
const id = cleanString(params.entryId, "entryId", { required: true, max: 120 })!;
|
|
109
|
-
const entry =
|
|
109
|
+
const entry = await getProjectEntryAsync(id);
|
|
110
110
|
if (!entry) return error("project entry not found", 404);
|
|
111
|
-
return json({ entry, chain:
|
|
111
|
+
return json({ entry, chain: await getProjectEntryChainAsync(id) });
|
|
112
112
|
} catch (err) {
|
|
113
113
|
return error(err instanceof Error ? err.message : "projects route failed");
|
|
114
114
|
}
|
|
@@ -130,8 +130,8 @@ function cleanAudience(value: unknown): ProjectEntryAudience | undefined {
|
|
|
130
130
|
|
|
131
131
|
// Historical steward entries retain the same curation rights as manual entries (#3456).
|
|
132
132
|
// Only the current active version is editable, preserving supersession and retraction.
|
|
133
|
-
function loadEditableEntry(projectId: string, entryId: string): { entry: ProjectEntry } | { errorResponse: Response } {
|
|
134
|
-
const entry =
|
|
133
|
+
async function loadEditableEntry(projectId: string, entryId: string): Promise<{ entry: ProjectEntry } | { errorResponse: Response }> {
|
|
134
|
+
const entry = await getProjectEntryAsync(entryId);
|
|
135
135
|
if (!entry || entry.projectId !== projectId) return { errorResponse: error("project entry not found", 404) };
|
|
136
136
|
if (!isEditableSource(entry.source)) {
|
|
137
137
|
return { errorResponse: error(`${entry.source} entries are owned by the ingest pipeline and cannot be edited or removed here`, 409) };
|
|
@@ -170,7 +170,7 @@ export const postProjectEntryRoute: Handler = async (req, params) => {
|
|
|
170
170
|
// Use the same caller placement as MCP writes; dashboard callers fall back to project roots.
|
|
171
171
|
// Areas stay optional because the dashboard has no areas input yet.
|
|
172
172
|
const areas = await resolveWriteAreas(project, areaCallerFromCtx(authContextFromRequest(req)), parsed.body.areas, { requireDeclared: false });
|
|
173
|
-
const entry =
|
|
173
|
+
const entry = await writeProjectEntryAsync({
|
|
174
174
|
projectId: project.id,
|
|
175
175
|
authorId: requestUserAddress(req),
|
|
176
176
|
kind,
|
|
@@ -188,7 +188,7 @@ export const postProjectEntryRoute: Handler = async (req, params) => {
|
|
|
188
188
|
agentId: entry.authorId,
|
|
189
189
|
metadata: projectEntryAuditMetadata(req, "relay_project_write_entry", project.id, entry.id),
|
|
190
190
|
});
|
|
191
|
-
return json({ entry, ...(tier.note ? { injectNote: tier.note } : {}), ...areaDeliveryReport(entry) }, 201);
|
|
191
|
+
return json({ entry, ...(tier.note ? { injectNote: tier.note } : {}), ...await areaDeliveryReport(entry) }, 201);
|
|
192
192
|
} catch (err) {
|
|
193
193
|
if (err instanceof ValidationError) return error(err.message, 400);
|
|
194
194
|
return error(err instanceof Error ? err.message : "projects route failed");
|
|
@@ -196,7 +196,7 @@ export const postProjectEntryRoute: Handler = async (req, params) => {
|
|
|
196
196
|
};
|
|
197
197
|
|
|
198
198
|
// PATCH /api/projects/:id/entries/:entryId — Edit (#1940 Part 2). There is no in-place UPDATE
|
|
199
|
-
// in the ledger (
|
|
199
|
+
// in the ledger (writeProjectEntryAsync only inserts); an edit is a new entry that `supersedes` the
|
|
200
200
|
// old one — the exact mechanism relay_project_write_entry's `supersedes` param already gives
|
|
201
201
|
// agents. Omitted fields fall back to the current entry's value (a partial patch, not a
|
|
202
202
|
// full-replace); an explicit `null` for `body` clears it.
|
|
@@ -206,7 +206,7 @@ export const patchProjectEntryRoute: Handler = async (req, params) => {
|
|
|
206
206
|
const project = await resolveProjectAsync(ref);
|
|
207
207
|
if (!project) return error("project not found", 404);
|
|
208
208
|
const entryId = cleanString(params.entryId, "entryId", { required: true, max: 120 })!;
|
|
209
|
-
const loaded = loadEditableEntry(project.id, entryId);
|
|
209
|
+
const loaded = await loadEditableEntry(project.id, entryId);
|
|
210
210
|
if ("errorResponse" in loaded) return loaded.errorResponse;
|
|
211
211
|
const { entry } = loaded;
|
|
212
212
|
|
|
@@ -234,7 +234,7 @@ export const patchProjectEntryRoute: Handler = async (req, params) => {
|
|
|
234
234
|
);
|
|
235
235
|
const areas = await resolveWriteAreas(project, areaCallerFromCtx(authContextFromRequest(req)), body.areas, { prior: entry.areas, requireDeclared: false });
|
|
236
236
|
|
|
237
|
-
const updated =
|
|
237
|
+
const updated = await writeProjectEntryAsync({
|
|
238
238
|
projectId: project.id,
|
|
239
239
|
authorId: requestUserAddress(req),
|
|
240
240
|
kind,
|
|
@@ -250,7 +250,7 @@ export const patchProjectEntryRoute: Handler = async (req, params) => {
|
|
|
250
250
|
source: entry.source === "steward" ? "manual" : entry.source,
|
|
251
251
|
originRef: entry.originRef,
|
|
252
252
|
sensitivity: entry.sensitivity,
|
|
253
|
-
// Carry a POSITIVE prior TTL only:
|
|
253
|
+
// Carry a POSITIVE prior TTL only: writeProjectEntryAsync rejects invalid epochs, so a corrupt
|
|
254
254
|
// legacy value cannot turn a partial dashboard edit into a failed adoption.
|
|
255
255
|
...(entry.expiresAt !== undefined && entry.expiresAt > 0 ? { expiresAt: entry.expiresAt } : {}),
|
|
256
256
|
});
|
|
@@ -261,7 +261,7 @@ export const patchProjectEntryRoute: Handler = async (req, params) => {
|
|
|
261
261
|
agentId: updated.authorId,
|
|
262
262
|
metadata: projectEntryAuditMetadata(req, "relay_project_write_entry", project.id, updated.id, { supersedes: entry.id }),
|
|
263
263
|
});
|
|
264
|
-
return json({ entry: updated, ...(tier.note ? { injectNote: tier.note } : {}), ...areaDeliveryReport(updated) });
|
|
264
|
+
return json({ entry: updated, ...(tier.note ? { injectNote: tier.note } : {}), ...await areaDeliveryReport(updated) });
|
|
265
265
|
} catch (err) {
|
|
266
266
|
if (err instanceof ValidationError) return error(err.message, 400);
|
|
267
267
|
return error(err instanceof Error ? err.message : "projects route failed");
|
|
@@ -276,10 +276,10 @@ export const deleteProjectEntryRoute: Handler = async (req, params) => {
|
|
|
276
276
|
const project = await resolveProjectAsync(ref);
|
|
277
277
|
if (!project) return error("project not found", 404);
|
|
278
278
|
const entryId = cleanString(params.entryId, "entryId", { required: true, max: 120 })!;
|
|
279
|
-
const loaded = loadEditableEntry(project.id, entryId);
|
|
279
|
+
const loaded = await loadEditableEntry(project.id, entryId);
|
|
280
280
|
if ("errorResponse" in loaded) return loaded.errorResponse;
|
|
281
281
|
|
|
282
|
-
const retracted =
|
|
282
|
+
const retracted = await retractProjectEntryAsync(entryId);
|
|
283
283
|
if (!retracted) return error("project entry not found", 404);
|
|
284
284
|
await auditEvent({
|
|
285
285
|
kind: "state",
|
|
@@ -21,21 +21,21 @@ function routeError(err: unknown): Response {
|
|
|
21
21
|
return error(err instanceof Error ? err.message : "prompt template route failed");
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function authorizePromptRead(req: Request): Response | null {
|
|
24
|
+
async function authorizePromptRead(req: Request): Promise<Response | null> {
|
|
25
25
|
const auth = getComponentAuth(req);
|
|
26
26
|
if (auth && (hasComponentScope(auth, "system:admin") || hasComponentScope(auth, "agent:read"))) return null;
|
|
27
|
-
return authorizeRoute(req, { scope: "system:admin" });
|
|
27
|
+
return (await authorizeRoute(req, { scope: "system:admin" }));
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export const getPromptTemplatesRoute: Handler = async (req) => {
|
|
31
|
-
const denied = authorizePromptRead(req);
|
|
31
|
+
const denied = (await authorizePromptRead(req));
|
|
32
32
|
if (denied) return denied;
|
|
33
33
|
const category = cleanString(new URL(req.url).searchParams.get("category"), "category", { max: 120 }) ?? undefined;
|
|
34
34
|
return json({ templates: (await readPromptTemplates(category)).filter(entry => !memoryRetirementMessage(entry.slug)) });
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export const getPromptTemplateRoute: Handler = async (req, params) => {
|
|
38
|
-
const denied = authorizePromptRead(req);
|
|
38
|
+
const denied = (await authorizePromptRead(req));
|
|
39
39
|
if (denied) return denied;
|
|
40
40
|
const slug = slugParam(params);
|
|
41
41
|
const retirement = memoryRetirementMessage(slug);
|
|
@@ -45,7 +45,7 @@ export const getPromptTemplateRoute: Handler = async (req, params) => {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
export const putPromptTemplateRoute: Handler = async (req, params) => {
|
|
48
|
-
const denied = authorizeRoute(req, { scope: versionedPromptsEnabled() ? "agent:write" : "system:admin" });
|
|
48
|
+
const denied = (await authorizeRoute(req, { scope: versionedPromptsEnabled() ? "agent:write" : "system:admin" }));
|
|
49
49
|
if (denied) return denied;
|
|
50
50
|
const parsed = await parseBody<Record<string, unknown>>(req);
|
|
51
51
|
if (!parsed.ok) return error(parsed.error, parsed.status);
|
|
@@ -55,31 +55,31 @@ export const putPromptTemplateRoute: Handler = async (req, params) => {
|
|
|
55
55
|
await mutatePrompt(authContextFromRequest(req), slug, parsed.body);
|
|
56
56
|
return json(await readPromptTemplate(slug));
|
|
57
57
|
}
|
|
58
|
-
const legacyDenied = authorizeRoute(req, { scope: "system:admin" });
|
|
58
|
+
const legacyDenied = (await authorizeRoute(req, { scope: "system:admin" }));
|
|
59
59
|
if (legacyDenied) return legacyDenied;
|
|
60
60
|
const template = cleanString(parsed.body?.template, "template", { required: true, max: 200_000 })!;
|
|
61
|
-
return json(updatePromptTemplate(slug, template));
|
|
61
|
+
return json((await updatePromptTemplate(slug, template)));
|
|
62
62
|
} catch (err) {
|
|
63
63
|
return routeError(err);
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
export const postPromptTemplateResetRoute: Handler = async (req, params) => {
|
|
68
|
-
const denied = authorizeRoute(req, { scope: versionedPromptsEnabled() ? "agent:write" : "system:admin" });
|
|
68
|
+
const denied = (await authorizeRoute(req, { scope: versionedPromptsEnabled() ? "agent:write" : "system:admin" }));
|
|
69
69
|
if (denied) return denied;
|
|
70
70
|
try {
|
|
71
71
|
const slug = slugParam(params);
|
|
72
72
|
if (versionedPromptsEnabled() && (await readPromptTemplate(slug))?.version !== undefined) return mutateRevision(req, slug, "adopt");
|
|
73
|
-
const legacyDenied = authorizeRoute(req, { scope: "system:admin" });
|
|
73
|
+
const legacyDenied = (await authorizeRoute(req, { scope: "system:admin" }));
|
|
74
74
|
if (legacyDenied) return legacyDenied;
|
|
75
|
-
return json(resetPromptTemplate(slug));
|
|
75
|
+
return json((await resetPromptTemplate(slug)));
|
|
76
76
|
} catch (err) {
|
|
77
77
|
return routeError(err);
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
export const getPromptHistoryRoute: Handler = async (req, params) => {
|
|
82
|
-
const denied = authorizePromptRead(req);
|
|
82
|
+
const denied = (await authorizePromptRead(req));
|
|
83
83
|
if (denied) return denied;
|
|
84
84
|
const slug = slugParam(params);
|
|
85
85
|
if (!versionedPromptsEnabled() || (await readPromptTemplate(slug))?.version === undefined) return error("versioned prompt not found", 404);
|
|
@@ -100,7 +100,7 @@ async function mutateRevision(req: Request, slug: string, action: "adopt" | "res
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
export const postPromptRevisionRoute: Handler = async (req, params) => {
|
|
103
|
-
const denied = authorizeRoute(req, { scope: "agent:write" });
|
|
103
|
+
const denied = (await authorizeRoute(req, { scope: "agent:write" }));
|
|
104
104
|
if (denied) return denied;
|
|
105
105
|
return mutateRevision(req, slugParam(params), new URL(req.url).pathname.endsWith("/restore") ? "restore" : "adopt");
|
|
106
106
|
};
|