@humwick/server 0.130.1 → 0.130.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/bundled/prompts/manifest.json +1 -0
- package/bundled/prompts/task.hydration.md +1 -1
- package/bundled/roles/builder.md +1 -1
- package/docs/guides/sub-coordinators.md +12 -5
- package/docs/guides/tools-administration.md +4 -0
- package/docs/guides/tools-coordination.md +2 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +74 -0
- package/docs/openapi.json +486 -4
- package/package.json +10 -18
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-Bq9kr21N.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-Dqiroy06.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-DYU962-H.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-DhPfzioE.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-DzCcQTee.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-SgDt9i3T.js} +2 -2
- package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-CcY3Aijy.js} +2 -2
- package/public/assets/agent-profiles-cxtRBn6O.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-DGYbIhaI.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-DHbftV0N.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-CY113sp-.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-BPzY7IlQ.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-DENFPv_a.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-KRvSc7sl.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-C9gSmL3s.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-DT-HkI5O.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BsmjQhKD.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-8NYH_62t.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-D3hwvYb4.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-DCJ5WL7O.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-DAIl357U.js} +3 -3
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-CzrZfr9U.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-xTxtlyou.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BpebFLK2.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-BHvI5wXC.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-DGT0o3wJ.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-hqWOHSHE.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-CDeH4I8T.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-BTeGVmTg.js} +2 -2
- package/public/assets/{fleet-B_rFEbnL.js → fleet-DgXtNgCa.js} +2 -2
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BHEt5yc_.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-MLtodyPp.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-CAe664Z8.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-mapF4Fj9.js} +2 -2
- package/public/assets/index-CqqgOI5R.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-DNyf7IzF.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-DlYOHq7T.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-CeWBNWn7.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-Cib8nqdE.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-DSn1cPm7.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-C3CkM81m.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-W4VQQPAv.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-BV17qtO4.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-Bm_1AqSA.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Dg-vfP09.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-DcYCrvlr.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-8o9nuG3V.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-BsRyBMea.js} +2 -2
- package/public/assets/project-profile-instructions-DETKFn_E.js +2 -0
- package/public/assets/projects-M_m6AHws.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-C_mNCgeL.js} +2 -2
- package/public/assets/provider-display-BEeLXC_D.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-DDHHHE5N.js} +2 -2
- package/public/assets/run-card-Dt4I4jaP.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-BkVwxI5O.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-Crq-6a-B.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CYcavMFu.js} +2 -2
- package/public/assets/shipping-H6gzEeZB.js +2 -0
- package/public/assets/{stats-V9Z-GxUd.js → stats-BJVeWkpV.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-BcHyw1Vw.js} +2 -2
- package/public/assets/store-DKPDIZBe.js +9 -0
- package/public/assets/{tasks-CXU75HRF.js → tasks-qJjlQPpx.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-Cd5Sk1uX.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-CpY5_m7W.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-0yJA_buM.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-uJXHf34W.js} +2 -2
- package/public/assets/use-project-list-CpWl6eHQ.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BdxBW8mL.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-3IndfpOc.js} +2 -2
- package/public/assets/versioned-prompt-editor-CIVg7XB1.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-B9rnLwHZ.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-X8wxyhzC.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-o5YyMFW7.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-CzEGoAng.js} +2 -2
- package/public/cosmos.html +4 -4
- package/public/index.html +31 -29
- package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
- package/runner/src/adapters/claude-effort.ts +2 -4
- package/runner/src/adapters/claude-headless.ts +1 -1
- package/runner/src/adapters/claude-launch-exit.ts +26 -0
- package/runner/src/adapters/claude-session-probe.ts +1 -1
- package/runner/src/adapters/claude-tmux.ts +38 -10
- package/runner/src/adapters/claude.ts +28 -75
- package/runner/src/adapters/codex-launch-config.ts +4 -5
- package/runner/src/adapters/codex.ts +1 -1
- package/runner/src/adapters/opencode-provider.ts +7 -22
- package/runner/src/adapters/opencode.ts +4 -4
- package/runner/src/adapters/provider-quota-harvest.ts +20 -71
- package/runner/src/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +2 -4
- package/runner/src/agent-runner/liveness-exchange.ts +104 -0
- package/runner/src/bin/claude.ts +4 -0
- package/runner/src/bin/codex.ts +4 -0
- package/runner/src/bin/opencode.ts +4 -0
- package/runner/src/claude-system-prompt.ts +49 -0
- package/runner/src/index.ts +5 -2
- package/runner/src/launch-assembly.ts +14 -10
- package/runner/src/profile-home.ts +1 -1
- package/runner/src/project-instructions.ts +2 -2
- package/runner/src/provider-command.ts +18 -0
- package/runner/src/provider-setup.ts +35 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +32 -38
- package/runner/src/runner-helpers.ts +0 -8
- package/runner/src/session-scratch.ts +6 -2
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/runner/test-support/provisioning-context.ts +4 -2
- package/runner/test-support/runner-harness.ts +2 -1
- package/scripts/cd-config.ts +8 -0
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/scripts/steward-policy-cleanup.ts +2 -2
- package/src/agent-authz.ts +2 -2
- package/src/agent-drive-arbiter.ts +3 -8
- package/src/agent-exit-cleanup-async.ts +2 -2
- package/src/agent-exit-cleanup.ts +23 -19
- package/src/agent-lifecycle-events.ts +112 -85
- package/src/agent-ref.ts +3 -2
- package/src/agent-status-events.ts +43 -14
- package/src/auth/password.ts +4 -3
- package/src/auth/session-refresh.ts +1 -1
- package/src/auth/session.test-fixture.ts +2 -2
- package/src/auth/session.ts +7 -7
- package/src/automations/crud.ts +8 -81
- package/src/automations/dispatch.ts +33 -58
- package/src/automations/index.ts +1 -1
- package/src/automations/persistence.ts +65 -0
- package/src/automations/precheck.ts +18 -16
- package/src/automations/read-async.ts +11 -0
- package/src/automations/reconcile.ts +30 -39
- package/src/automations/storage.ts +33 -10
- package/src/automations/write-async.ts +33 -0
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +31 -98
- package/src/bus.ts +40 -39
- package/src/cd-deploy-notify.ts +32 -4
- package/src/cd-host-lag-notify.ts +7 -6
- package/src/ci/incidents.ts +2 -2
- package/src/ci/monitor.ts +5 -8
- package/src/ci/notifications.ts +4 -4
- package/src/ci/root-missing.ts +4 -9
- package/src/ci/transition-notify.ts +12 -44
- package/src/claude-app/oauth-http.ts +3 -3
- package/src/cli/cd-pauses.ts +19 -0
- package/src/cli/orchestrator.ts +1 -1
- package/src/cli/state.ts +2 -19
- package/src/cli/task-edit.ts +22 -0
- package/src/cli/task.ts +3 -1
- package/src/cli/workflow.ts +19 -4
- package/src/commands-db.ts +7 -7
- package/src/commands-write.ts +8 -0
- package/src/compaction-watch.ts +10 -8
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- package/src/config.ts +4 -11
- package/src/connectors.ts +10 -8
- package/src/context-advisory.ts +22 -21
- package/src/db/activity-async.ts +6 -1
- package/src/db/activity-write-ops.ts +12 -1
- package/src/db/activity.ts +1 -14
- package/src/db/agent-action-write.ts +36 -0
- package/src/db/agent-control-async.ts +9 -0
- package/src/db/agent-control-write.ts +49 -0
- package/src/db/agent-effort-observe.ts +22 -0
- package/src/db/agent-meta.ts +14 -3
- package/src/db/agent-search.ts +1 -15
- package/src/db/agents-async.ts +59 -9
- package/src/db/agents-write-ops.ts +12 -3
- package/src/db/agents.ts +95 -65
- package/src/db/auth-identities.ts +2 -2
- package/src/db/automation-read-ops.ts +11 -0
- package/src/db/automation-write-ops.ts +46 -0
- package/src/db/blackboard.ts +2 -2
- package/src/db/browser-session-write.ts +32 -0
- package/src/db/bus-outbox-write-ops.ts +3 -1
- package/src/db/checkout-refresh-schema.ts +47 -0
- package/src/db/checkout-refresh.ts +5 -5
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/command-agent-profile-backfill.ts +39 -0
- package/src/db/command-agent-profiles.ts +5 -1
- package/src/db/command-retention.ts +126 -0
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-planner-stats.test-fixture.ts +8 -0
- package/src/db/commands-read-ops.ts +16 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/config-store-write-ops.ts +7 -2
- package/src/db/connection.ts +1 -182
- package/src/db/context-carry-write.ts +74 -0
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +7 -0
- package/src/db/continuations.ts +6 -6
- package/src/db/db-error-registry.ts +12 -0
- package/src/db/db-writer-worker.ts +8 -1
- package/src/db/deploy-events-async.ts +1 -0
- package/src/db/deploy-events-read-ops.ts +2 -1
- package/src/db/deploy-events.ts +35 -4
- package/src/db/gateway.ts +26 -133
- package/src/db/history-retention-ops.ts +13 -0
- package/src/db/hosts-registration.ts +10 -2
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox-async.ts +2 -2
- package/src/db/inbox-read-ops.ts +1 -1
- package/src/db/inbox.ts +9 -17
- package/src/db/index.ts +2 -0
- package/src/db/integrations-async.ts +8 -0
- package/src/db/integrations-ops.ts +15 -0
- package/src/db/integrations.ts +15 -21
- package/src/db/issue-associations.ts +2 -2
- package/src/db/issue-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +23 -0
- package/src/db/issue-refs-read-ops.ts +6 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +15 -16
- package/src/db/kernel-event-log-schema.ts +2 -0
- package/src/db/land-boundaries.ts +51 -5
- package/src/db/land-gate-attestations.ts +2 -2
- package/src/db/landing-receipts.ts +2 -2
- package/src/db/lifecycle-context-write.ts +5 -0
- package/src/db/lifecycle-tail-async.ts +76 -0
- package/src/db/lifecycle-tail-write-ops.ts +62 -0
- package/src/db/lifecycle-write-window.ts +2 -1
- package/src/db/lineage-pair-dedupe-sql.ts +3 -3
- package/src/db/long-running-work.ts +2 -2
- package/src/db/main-connection-mode.ts +11 -0
- package/src/db/main-connection-writes.ts +41 -2
- package/src/db/maintenance-job-reconcile.ts +61 -0
- package/src/db/maintenance-job-runs-async.ts +14 -0
- package/src/db/maintenance-job-write-ops.ts +9 -0
- package/src/db/maintenance-pauses.ts +2 -2
- package/src/db/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/message-send.ts +4 -0
- package/src/db/messages.ts +31 -25
- package/src/db/migrations.ts +25 -16
- package/src/db/notification-write-ops.ts +19 -0
- package/src/db/operator-answer-write.ts +19 -0
- package/src/db/orchestrators.ts +14 -76
- package/src/db/pairs-async.ts +22 -1
- package/src/db/pairs-write-ops.ts +8 -3
- package/src/db/pairs.ts +42 -61
- package/src/db/plan-dispatch-schema.ts +5 -1
- package/src/db/plan-ready-notices.ts +43 -0
- package/src/db/plan-tools-include-migration.ts +36 -0
- package/src/db/plans-write-ops.ts +2 -0
- package/src/db/presence-buffer.ts +5 -0
- package/src/db/presence-loop.ts +18 -23
- package/src/db/presence-write.ts +0 -6
- package/src/db/project-entries-async.ts +14 -0
- package/src/db/project-entries-read-ops.ts +5 -1
- package/src/db/project-entries-write-ops.ts +8 -0
- package/src/db/project-entries.ts +15 -12
- package/src/db/project-journal.ts +2 -2
- package/src/db/project-profile-instructions.ts +50 -0
- package/src/db/project-trust-approvals.ts +2 -2
- package/src/db/prompt-templates.ts +4 -4
- package/src/db/prompt-versions.ts +9 -2
- package/src/db/provider-config-history.ts +8 -3
- package/src/db/provider-model-seed.ts +34 -0
- package/src/db/read-op-marshaling-fixtures.ts +23 -0
- package/src/db/read-ops.ts +8 -0
- package/src/db/retention.ts +13 -2
- package/src/db/review-publish-write.ts +8 -0
- package/src/db/routing-policy.ts +2 -3
- package/src/db/runtime-admin-async.ts +19 -0
- package/src/db/runtime-admin-write-ops.ts +36 -0
- package/src/db/runtime-tail-async.ts +288 -0
- package/src/db/runtime-tail-write-ops.ts +97 -0
- package/src/db/schema.ts +13 -4
- package/src/db/spawn-budget.ts +5 -0
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/spawn-delegation.ts +1 -11
- package/src/db/sql-audit-indexes.ts +3 -0
- package/src/db/stats-async.ts +9 -6
- package/src/db/task-entity.ts +28 -6
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/team-claim-policy.ts +60 -0
- package/src/db/teams-async.ts +4 -0
- package/src/db/teams-write-ops.ts +4 -0
- package/src/db/terminal-events.ts +15 -0
- package/src/db/timer-cutover-bodies.ts +292 -0
- package/src/db/timer-cutover-core.ts +37 -278
- package/src/db/timer-cutover-state.ts +40 -0
- package/src/db/timer-cutover-write-ops.ts +1 -40
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/token-db-write-ops.ts +19 -0
- package/src/db/token-standing-async.ts +12 -0
- package/src/db/token-standing.ts +21 -20
- package/src/db/token-usage-retention.ts +33 -0
- package/src/db/token-usage-write-ops.ts +1 -1
- package/src/db/token-usage.ts +4 -1
- package/src/db/user-invites-async.ts +13 -0
- package/src/db/user-invites.ts +3 -3
- package/src/db/users.ts +14 -6
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/workspaces.ts +8 -5
- package/src/db/write-ops.ts +37 -12
- package/src/db/writer-fault-seam.ts +2 -9
- package/src/db/writer-fault-test-ops.ts +18 -0
- package/src/db/writer-gateway.ts +58 -56
- package/src/dev.ts +8 -3
- package/src/dispatch-availability.ts +10 -6
- package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
- package/src/event-loop-lag.ts +4 -2
- package/src/event-loop-yield.ts +2 -2
- package/src/events.ts +10 -8
- package/src/host/disk-alert.ts +121 -0
- package/src/host-provider-store.ts +5 -4
- package/src/hub-metrics-report.ts +5 -1
- package/src/hub-metrics.ts +38 -18
- package/src/injection-sweep-pacing.ts +6 -8
- package/src/land-gate-notifications.ts +11 -10
- package/src/land-gate-queue-progress.ts +3 -3
- package/src/land-settle-dispatch.ts +52 -92
- package/src/lifecycle-context-pressure.ts +11 -10
- package/src/lifecycle-manager.ts +107 -100
- package/src/maintenance/breaker.ts +18 -16
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/checkout-refresh.ts +18 -1
- package/src/maintenance/critical-job-watchdog.ts +19 -20
- package/src/maintenance/events.ts +3 -3
- package/src/maintenance/history-retention-job.ts +30 -0
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +32 -69
- package/src/maintenance/long-running-work.ts +3 -1
- package/src/maintenance/offline-agent-prune-job.ts +28 -0
- package/src/maintenance/orphaned-sessions.ts +5 -4
- package/src/maintenance/pauses.ts +4 -10
- package/src/maintenance/plan-ready-notice-job.ts +71 -0
- package/src/maintenance/scheduler.ts +98 -137
- package/src/maintenance/stalled-delivery-pager.ts +10 -9
- package/src/maintenance/teams.ts +19 -30
- package/src/maintenance/workspaces.ts +18 -28
- package/src/managed-policy-escalation.ts +7 -7
- package/src/managed-policy.ts +32 -28
- package/src/managed-provider-gate.ts +5 -4
- package/src/managed-spawn-reservation.ts +5 -4
- package/src/mcp/index.ts +12 -9
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +6 -5
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/runtime-output.ts +6 -1
- package/src/mcp/self-care-visibility.ts +2 -2
- package/src/mcp/spawn-targets-matrix.ts +10 -1
- package/src/mcp/tool-groups.ts +4 -3
- package/src/mcp/tool-roles.ts +81 -0
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp/tools-workspace.ts +1 -1
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-blackboard-tools.ts +6 -5
- package/src/mcp-decision-tools.ts +7 -7
- package/src/mcp-egress-tools.ts +10 -9
- package/src/mcp-issue-activity-tools.ts +2 -2
- package/src/mcp-issue-association-tools.ts +4 -4
- package/src/mcp-issue-ref-tools.ts +13 -12
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-merge-tools.ts +5 -5
- package/src/mcp-notification-subscription-tools.ts +14 -15
- package/src/mcp-output-levels.test-fixture.ts +1 -1
- package/src/mcp-profile-trust-tools.ts +5 -5
- package/src/mcp-project-journal-tools.ts +4 -12
- package/src/mcp-project-tools.ts +17 -18
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-routing-policy-tools.ts +3 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-team-tools.ts +6 -6
- package/src/mcp-workflow-tools.ts +13 -4
- package/src/memory-area-injection.ts +13 -12
- package/src/memory-boundary-capture.ts +6 -6
- package/src/memory-injection.ts +45 -43
- package/src/merge-pause-maintenance.ts +5 -4
- package/src/notification-router.ts +44 -17
- package/src/notification-types.ts +2 -1
- package/src/notify.ts +5 -5
- package/src/observed-reset-refresh.ts +4 -4
- package/src/operator-alarm.ts +23 -11
- package/src/project-ingest.ts +6 -6
- package/src/project-instructions.ts +12 -1
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- package/src/project-trust.ts +12 -11
- package/src/prompt-resolver.ts +3 -3
- package/src/provider-catalog-store.ts +3 -49
- package/src/provider-config-store.ts +12 -11
- package/src/provider-model-seed.ts +1 -18
- package/src/provider-quota-async.ts +5 -7
- package/src/provider-quota-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/provider-timeline-event.ts +4 -7
- package/src/quota-band-delivery.ts +2 -2
- package/src/recipe-runner.ts +6 -5
- package/src/repo-config-source.ts +10 -4
- package/src/retention-config-store.ts +4 -3
- package/src/reviewer-pipeline.ts +11 -10
- package/src/routes/_route.ts +4 -4
- package/src/routes/_shared.ts +13 -12
- package/src/routes/agent-effort.ts +5 -5
- package/src/routes/agent-heartbeat-quota.ts +23 -0
- package/src/routes/agent-keep.ts +1 -1
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agent-reporting.ts +1 -1
- package/src/routes/agent-self-effort.ts +5 -5
- package/src/routes/agent-sessions.ts +24 -24
- package/src/routes/agents-spawn.ts +2 -2
- package/src/routes/agents.ts +19 -121
- package/src/routes/auth.ts +14 -15
- package/src/routes/authority-audit.ts +2 -2
- package/src/routes/automations.ts +6 -5
- package/src/routes/channel-binding-delete.ts +1 -1
- package/src/routes/channel-output.ts +3 -3
- package/src/routes/claude-api-budget.ts +5 -5
- package/src/routes/commands-listing.ts +5 -1
- package/src/routes/commands.ts +31 -29
- package/src/routes/context-resets.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/coordinator-teams.ts +1 -1
- package/src/routes/decisions.ts +2 -2
- package/src/routes/host-secret-files.ts +1 -1
- package/src/routes/hosts.ts +11 -11
- package/src/routes/inbox.ts +3 -2
- package/src/routes/index.ts +12 -2
- package/src/routes/integrations.ts +32 -56
- package/src/routes/issue-activity.ts +2 -2
- package/src/routes/issue-associations.ts +4 -4
- package/src/routes/issue-refs.ts +9 -9
- package/src/routes/kernel-timers-operator.ts +1 -1
- package/src/routes/memory.ts +1 -1
- package/src/routes/merges.ts +11 -11
- package/src/routes/messages.ts +23 -17
- package/src/routes/orchestrator-bootstrap.ts +2 -2
- package/src/routes/orchestrator-host-registration.ts +4 -2
- package/src/routes/orchestrator-host-utilization.ts +5 -3
- package/src/routes/orchestrator-proxy.ts +4 -4
- package/src/routes/orchestrator.ts +28 -19
- package/src/routes/pairs.ts +8 -8
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +3 -3
- package/src/routes/projects.ts +16 -16
- package/src/routes/prompt-templates.ts +12 -12
- package/src/routes/provider-config.ts +6 -6
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/provider-quotas.ts +10 -10
- package/src/routes/run-command.ts +1 -1
- package/src/routes/secrets-backup.ts +2 -2
- package/src/routes/secrets-import.ts +1 -1
- package/src/routes/secrets-vault.ts +7 -7
- package/src/routes/settings.ts +6 -6
- package/src/routes/shipping.ts +9 -1
- package/src/routes/spawn-policy.ts +8 -7
- package/src/routes/sse.ts +2 -2
- package/src/routes/stats.ts +6 -6
- package/src/routes/task-http.ts +15 -1
- package/src/routes/task-issues.ts +11 -26
- package/src/routes/tasks.ts +22 -53
- package/src/routes/team-templates.ts +12 -12
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/teams.ts +10 -10
- package/src/routes/tokens.ts +30 -22
- package/src/routes/users.ts +24 -24
- package/src/routes/viewer-read.ts +3 -3
- package/src/routes/web-tool-calls.ts +4 -4
- package/src/routes/workflows.ts +22 -7
- package/src/routes/workspaces.ts +17 -16
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-policy-push.ts +6 -6
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +21 -13
- package/src/runtime-tokens.ts +59 -35
- package/src/secrets-broker/config.ts +1 -1
- package/src/secrets-broker/service.ts +2 -2
- package/src/security.ts +16 -21
- package/src/self-resume-carry.ts +21 -110
- package/src/self-resume-supersede.ts +4 -3
- package/src/self-resume.ts +54 -66
- package/src/server-background.ts +2 -2
- package/src/server.ts +26 -24
- package/src/services/agent-action.ts +12 -31
- package/src/services/agent-effort.ts +7 -32
- package/src/services/agent-hang-watchdog-job.ts +2 -2
- package/src/services/agent-heartbeat.ts +166 -0
- package/src/services/agent-reporting.ts +1 -1
- package/src/services/browser-inventory.ts +3 -3
- package/src/services/browser-session-state.ts +3 -2
- package/src/services/browser-session.ts +21 -27
- package/src/services/bus-command-update.ts +9 -9
- package/src/services/checkout-refresh-state.ts +1 -0
- package/src/services/checkout-refresh.test-fixture.ts +3 -2
- package/src/services/command-host.ts +7 -2
- package/src/services/coordinator-digest.ts +3 -2
- package/src/services/dispatch-command.ts +12 -13
- package/src/services/effective-launch-driver.ts +14 -9
- package/src/services/host-changed-paths.test-fixture.ts +5 -6
- package/src/services/host-project-readiness.ts +2 -2
- package/src/services/host-providers.ts +1 -1
- package/src/services/host-utilization.ts +27 -4
- package/src/services/idle-agent-digest.ts +17 -12
- package/src/services/idle-epics.ts +9 -10
- package/src/services/interrupt-agent.ts +12 -9
- package/src/services/issue-activity.ts +3 -3
- package/src/services/issue-associations.ts +15 -18
- package/src/services/issue-lifecycle-comments.ts +3 -2
- package/src/services/issue-lifecycle.ts +69 -72
- package/src/services/issue-refs.ts +10 -15
- package/src/services/kernel-timers-cutover-chaos-worker.ts +11 -8
- package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
- package/src/services/kernel-timers-ingress.ts +4 -4
- package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
- package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
- package/src/services/kernel-timers-outbox.ts +1 -1
- package/src/services/kernel-timers-stage10-operator.ts +1 -1
- package/src/services/kernel-timers.ts +4 -3
- package/src/services/land-gate-placement.ts +11 -2
- package/src/services/land-issue-relations.ts +5 -4
- package/src/services/land-restart-retry.ts +7 -6
- package/src/services/landed-ancestry.ts +25 -8
- package/src/services/legacy-landing-host.ts +4 -1
- package/src/services/legacy-landing-recovery.ts +8 -6
- package/src/services/managed-running.ts +17 -17
- package/src/services/memory-areas.ts +17 -53
- package/src/services/merge-pause.ts +9 -15
- package/src/services/operator-decisions.ts +37 -41
- package/src/services/orchestrator-registration-recovery.ts +6 -2
- package/src/services/orchestrator-upgrade.ts +14 -12
- package/src/services/permission-decision.ts +4 -3
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-conformance.ts +4 -4
- package/src/services/plan-dispatch-policy.ts +10 -3
- package/src/services/plan-dispatch.ts +35 -14
- package/src/services/plan-graph.ts +39 -261
- package/src/services/plan-import.ts +1 -1
- package/src/services/plan-live-bindings.ts +8 -37
- package/src/services/plan-task-create.ts +1 -1
- package/src/services/plan-terminal-refs.ts +2 -12
- package/src/services/plan-wake-digest.ts +9 -3
- package/src/services/profile-trust.ts +6 -5
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/project.ts +11 -10
- package/src/services/prompt-templates.ts +6 -5
- package/src/services/provider-hold-nudge.ts +9 -9
- package/src/services/provider-hold-record.ts +13 -12
- package/src/services/provider-state-audit.ts +19 -18
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/provisioning-harness/driver.ts +1 -1
- package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
- package/src/services/provisioning-harness/lifecycle.ts +24 -22
- package/src/services/provisioning-harness/prepare.ts +16 -17
- package/src/services/rate-limit-resume.ts +10 -9
- package/src/services/red-main-auto-revert.ts +7 -5
- package/src/services/red-main-controller-deps.ts +20 -3
- package/src/services/red-main-incident.ts +3 -1
- package/src/services/red-main-quarantine.ts +2 -3
- package/src/services/register-agent.ts +22 -22
- package/src/services/restart-project-role.ts +1 -1
- package/src/services/restart-spawn.ts +74 -61
- package/src/services/review-publish.ts +7 -24
- package/src/services/review-ref-reconcile.ts +29 -38
- package/src/services/runtime-dependency-alert.ts +27 -0
- package/src/services/scheduler-command.ts +11 -9
- package/src/services/scheduler.ts +5 -5
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort-grant.ts +5 -25
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +21 -34
- package/src/services/shutdown-agent.ts +17 -14
- package/src/services/spawn-agent.ts +25 -43
- package/src/services/spawn-chain-inspector.ts +7 -14
- package/src/services/spawn-cwd-placement.ts +21 -5
- package/src/services/spawn-issue-activity.ts +8 -6
- package/src/services/spawn-launch.ts +17 -1
- package/src/services/spawn-loss-escalation.ts +1 -1
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-registration-watchdog.ts +2 -2
- package/src/services/spawn-repo-probe.ts +7 -5
- package/src/services/spawn-tree-cleanup.ts +8 -9
- package/src/services/steward-reaper.ts +4 -4
- package/src/services/task-context-hydration.ts +25 -1
- package/src/services/task-delivery.ts +20 -34
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-entity.ts +40 -203
- package/src/services/task-issue-link.ts +13 -20
- package/src/services/task-issue-weave.ts +12 -11
- package/src/services/task-lifecycle.ts +27 -31
- package/src/services/task-repo-cwd.ts +37 -0
- package/src/services/task-review-hold.ts +4 -17
- package/src/services/task-semantic-events.ts +13 -11
- package/src/services/task-state-reconcile.ts +8 -17
- package/src/services/task-validation.ts +2 -2
- package/src/services/team-templates.ts +12 -11
- package/src/services/team.ts +31 -98
- package/src/services/terminal-provider-exit.ts +6 -5
- package/src/services/timer-message-fire-chaos-worker.ts +7 -3
- package/src/services/timer-message-fire-outbox.ts +1 -1
- package/src/services/transient-agent-reaper.ts +25 -20
- package/src/services/turn-reconcile-audit.ts +9 -9
- package/src/services/user-onboarding.ts +8 -6
- package/src/services/user-profile.ts +6 -9
- package/src/services/work-finality.ts +16 -4
- package/src/services/workflow-auto-start.ts +26 -13
- package/src/services/workflow-caller.ts +61 -4
- package/src/services/workflow-child-proof-worker.ts +1 -1
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-control-proof-worker.ts +1 -1
- package/src/services/workflow-coordinator.ts +8 -2
- package/src/services/workflow-decisions.ts +5 -5
- package/src/services/workflow-deferred-cleanup.ts +5 -3
- package/src/services/workflow-effect-driver.ts +42 -17
- package/src/services/workflow-effects.ts +58 -37
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-pins.ts +7 -4
- package/src/services/workflow-reconcile.ts +14 -11
- package/src/services/workflow-resume-pins.ts +3 -3
- package/src/services/workflow-routing-defaults.ts +18 -0
- package/src/services/workflow-run-view.ts +6 -3
- package/src/services/workflow-run.test-fixture.ts +1 -1
- package/src/services/workflow-runs.ts +61 -33
- package/src/services/workflow-supervisor-state.ts +26 -1
- package/src/services/workflow-supervisor.ts +11 -6
- package/src/services/workspace-recovery.ts +4 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-admission.ts +10 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +28 -10
- package/src/spawn-targets.ts +9 -9
- package/src/sse-agent-status.ts +15 -6
- package/src/sse.ts +49 -24
- package/src/startup-context-injection.ts +62 -57
- package/src/state-adoption/cd-cutover.ts +53 -7
- package/src/state-adoption/fleet-cutover.ts +35 -0
- package/src/state-adoption/fleet-plan.ts +36 -0
- package/src/state-adoption/index.ts +2 -2
- package/src/state-adoption/linux-plan.ts +2 -2
- package/src/state-adoption/linux.ts +2 -2
- package/src/state-adoption/macos-plan.ts +2 -2
- package/src/state-adoption/macos.ts +1 -1
- package/src/steward-handoff.ts +4 -3
- package/src/steward-policy-cleanup.ts +9 -8
- package/src/steward.ts +9 -8
- package/src/task-dispatch-live.ts +6 -3
- package/src/task-dispatcher.ts +3 -3
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/token-db.ts +2 -2
- package/src/token-usage-async.ts +2 -4
- package/src/user-awaiting-reply.ts +5 -5
- package/src/workspace-actions.ts +24 -29
- package/src/workspace-auto-merge.ts +14 -12
- package/src/workspace-changed-paths-client.ts +16 -5
- package/src/workspace-cleanup-stale.ts +30 -7
- package/src/workspace-command-settle.ts +26 -17
- package/src/workspace-config.ts +1 -1
- package/src/workspace-conflict-resolver.ts +9 -7
- package/src/workspace-dead-owner-recovery.ts +5 -4
- package/src/workspace-escalation.ts +12 -11
- package/src/workspace-human-escalation.ts +3 -3
- package/src/workspace-land-gate-watchdog.ts +3 -3
- package/src/workspace-land-refusal.ts +20 -0
- package/src/workspace-land-stopped.ts +1 -0
- package/src/workspace-merge.ts +10 -26
- package/src/workspace-nothing-to-land-notice.ts +2 -2
- package/src/workspace-orphans.ts +18 -37
- package/src/workspace-pr-completion.ts +10 -8
- package/src/workspace-rekey.ts +3 -3
- package/src/workspace-steward-failure.ts +2 -2
- package/src/workspace-steward-wake.ts +4 -4
- package/node_modules/@humwick/kernel/LICENSE +0 -167
- package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
- package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
- package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
- package/node_modules/@humwick/kernel/config.ts +0 -111
- package/node_modules/@humwick/kernel/contract.ts +0 -572
- package/node_modules/@humwick/kernel/control-authz.ts +0 -281
- package/node_modules/@humwick/kernel/control.ts +0 -645
- package/node_modules/@humwick/kernel/effects.ts +0 -493
- package/node_modules/@humwick/kernel/event-log.ts +0 -319
- package/node_modules/@humwick/kernel/http-transport.ts +0 -384
- package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
- package/node_modules/@humwick/kernel/identity.ts +0 -248
- package/node_modules/@humwick/kernel/index.ts +0 -28
- package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
- package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
- package/node_modules/@humwick/kernel/landing.ts +0 -953
- package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
- package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
- package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
- package/node_modules/@humwick/kernel/message-authority.ts +0 -281
- package/node_modules/@humwick/kernel/module-host.ts +0 -722
- package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
- package/node_modules/@humwick/kernel/package.json +0 -39
- package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
- package/node_modules/@humwick/kernel/persistence.ts +0 -510
- package/node_modules/@humwick/kernel/registry.ts +0 -60
- package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
- package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
- package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
- package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
- package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
- package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
- package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
- package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
- package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
- package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
- package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
- package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
- package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
- package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
- package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
- package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
- package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
- package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
- package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
- package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
- package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
- package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
- package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
- package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
- package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
- package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
- package/node_modules/@humwick/offload/LICENSE +0 -167
- package/node_modules/@humwick/offload/README.md +0 -57
- package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
- package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
- package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
- package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/envelope.js +0 -80
- package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
- package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
- package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/index.js +0 -5
- package/node_modules/@humwick/offload/dist/index.js.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
- package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
- package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
- package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
- package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/types.js +0 -176
- package/node_modules/@humwick/offload/dist/types.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
- package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
- package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
- package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
- package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
- package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
- package/node_modules/@humwick/offload/dist/worker.js +0 -1
- package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
- package/node_modules/@humwick/offload/package.json +0 -42
- package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
- package/node_modules/@humwick/offload/src/envelope.ts +0 -92
- package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
- package/node_modules/@humwick/offload/src/index.ts +0 -4
- package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
- package/node_modules/@humwick/offload/src/types.ts +0 -235
- package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
- package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
- package/node_modules/@humwick/offload/src/worker.ts +0 -5
- package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
- package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
- package/public/assets/index-B7ZerHLY.css +0 -2
- package/public/assets/index-BU3uWo2t.js +0 -15
- package/public/assets/projects-B_lmcqfO.js +0 -2
- package/public/assets/provider-display-DbLWpP3j.js +0 -2
- package/public/assets/run-card-CO_bguQf.js +0 -2
- package/public/assets/shipping-Bu8p1gEw.js +0 -2
- package/public/assets/store-BvtFdlGX.js +0 -9
- package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/agent-runner/http-liveness.ts +0 -85
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/db/on-loop-write-transaction.ts +0 -34
- package/src/routing-model-aliases.ts +0 -21
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { resolveIssueRefFromStringAsync } from "../db/issue-refs-async";
|
|
2
|
+
import { removeAssociationAsync, associateIssueAsync } from "../db/runtime-tail-async";
|
|
3
|
+
import { deletePlanAsync, createPlanRowAsync } from "../db/plans-async";
|
|
1
4
|
import { hasScope, isRecord } from "@humwick/sdk";
|
|
2
|
-
import {
|
|
5
|
+
import { sendMessageAsync, addTaskDependency, getAgent, getEntry, getPlan, getPlanAsync, getPlanByTeam, getPlanByThread, getTaskDetail, listPlansWithBoundOwner, planThreadExists, removeTaskDependency, replacePlanNodeScoped, sendMessageWithResultAsync, setPlanArchivedAsync, ValidationError } from "../db";
|
|
3
6
|
// The shared #2520 patch-time source derivation lives beside the writer op body it mirrors;
|
|
4
7
|
// plan-graph op bodies are imported directly (the barrel only re-exports plan-graph-async).
|
|
5
8
|
import { applyPatchStatusSourceDerivation, bindPlanNodeBody } from "../db/plan-graph";
|
|
6
9
|
import { writeTransaction } from "../db/connection";
|
|
7
|
-
import {
|
|
8
|
-
|
|
10
|
+
import { planNodeIssueEntityId } from "../db/issue-associations";
|
|
11
|
+
|
|
9
12
|
import { emitRelayEvent } from "../events";
|
|
10
13
|
import { cleanString, cleanStringArray, optionalEnum } from "../validation";
|
|
11
14
|
import { resolveActorIssueRepo } from "../agent-issue-repo";
|
|
@@ -84,67 +87,6 @@ function cleanOwnerRef(value: unknown): PlanOwnerRef | undefined {
|
|
|
84
87
|
return Object.keys(out).length ? out : undefined;
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
// #220: a bare `#NNN` issueId ref needs a default repo to resolve against — issue-refs.ts
|
|
88
|
-
// throws without one, contrary to its own error text advertising the bare form as accepted.
|
|
89
|
-
// Resolve it the same way #533 resolves chat `#NNN` linkify: the CALLING agent's own project
|
|
90
|
-
// (cwd → project → issueRepo), falling back to the single global env default. This scopes the
|
|
91
|
-
// default to the actor's actual repo rather than guessing from teamId — agents have no
|
|
92
|
-
// team→project FK; cwd is the only durable link (see agent-issue-repo.ts).
|
|
93
|
-
// Shared with the Task issue-link path (#2214) via resolveActorIssueRepo.
|
|
94
|
-
function cleanRefs(value: unknown, actor: string): PlanNode["refs"] | undefined {
|
|
95
|
-
if (value === undefined || value === null) return undefined;
|
|
96
|
-
const ref = cleanRecordRef(value, "refs");
|
|
97
|
-
if (!ref) return undefined;
|
|
98
|
-
const out: PlanNode["refs"] = {};
|
|
99
|
-
const issueId = cleanString(ref.issueId, "refs.issueId", { max: 1000 });
|
|
100
|
-
if (issueId) {
|
|
101
|
-
out.issueId = resolveIssueRefFromString({ ref: issueId, defaultRepo: resolveActorIssueRepo(actor) }).id;
|
|
102
|
-
}
|
|
103
|
-
// #836: refs.taskId is the live binding seam to a durable Task. Validate it resolves to a
|
|
104
|
-
// deliverable Task; store the canonical numeric id as a string. Once bound, the node's
|
|
105
|
-
// label/scopeBlurb/status PROJECT from the Task (see projectPlanOverTasks) — no double-keeping.
|
|
106
|
-
const taskIdRaw = ref.taskId;
|
|
107
|
-
const taskIdStr = typeof taskIdRaw === "number" ? String(taskIdRaw) : cleanString(taskIdRaw, "refs.taskId", { max: 240 });
|
|
108
|
-
if (taskIdStr) {
|
|
109
|
-
const taskId = parseTaskId(taskIdStr);
|
|
110
|
-
if (taskId === undefined) throw new ValidationError("refs.taskId must be a positive task id");
|
|
111
|
-
if (!getTaskDetail(taskId)) throw new ValidationError(`refs.taskId ${taskId} is not a deliverable task`);
|
|
112
|
-
out.taskId = String(taskId);
|
|
113
|
-
}
|
|
114
|
-
// agentId/landingRef remain populated by live binding in later slices (#838); reject here.
|
|
115
|
-
const unsupported = ["agentId", "landingRef"].filter((key) => cleanString(ref[key], `refs.${key}`, { max: 240 }));
|
|
116
|
-
if (unsupported.length > 0) throw new ValidationError("agentId/landingRef refs are populated by live binding in a later slice");
|
|
117
|
-
return Object.keys(out).length ? out : undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function syncPlanNodeIssueAssociation(planId: string, node: PlanNode): void {
|
|
121
|
-
if (!node.refs?.issueId) return;
|
|
122
|
-
associateIssue(node.refs.issueId, "plan-node", planNodeIssueEntityId(planId, node.id));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function removePlanNodeIssueAssociation(planId: string, node: PlanNode): void {
|
|
126
|
-
if (!node.refs?.issueId) return;
|
|
127
|
-
removeAssociation(node.refs.issueId, "plan-node", planNodeIssueEntityId(planId, node.id));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function syncChangedPlanNodeIssueAssociation(planId: string, before: PlanNode | undefined, after: PlanNode): void {
|
|
131
|
-
if (before?.refs?.issueId && before.refs.issueId !== after.refs?.issueId) {
|
|
132
|
-
removeAssociation(before.refs.issueId, "plan-node", planNodeIssueEntityId(planId, before.id));
|
|
133
|
-
}
|
|
134
|
-
if (after.refs?.issueId) syncPlanNodeIssueAssociation(planId, after);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function cleanBlackboardRefs(value: unknown, planTeamId?: string): string[] | undefined {
|
|
138
|
-
const refs = cleanStringArray(value, "node.blackboardRefs", { itemMax: 120, maxItems: 100 });
|
|
139
|
-
if (!refs?.length) return refs;
|
|
140
|
-
if (!planTeamId) throw new ValidationError("plan has no team; cannot reference blackboard entries");
|
|
141
|
-
for (const ref of refs) {
|
|
142
|
-
const entry = getEntry(ref);
|
|
143
|
-
if (!entry || entry.teamId !== planTeamId) throw new ValidationError(`blackboard entry not found for plan team: ${ref}`);
|
|
144
|
-
}
|
|
145
|
-
return refs;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
90
|
function cleanStatusSource(value: unknown): PlanNode["statusSource"] {
|
|
149
91
|
const statusSource = optionalEnum(value, "statusSource", ["manual", "bound"] as const, "manual");
|
|
150
92
|
return statusSource;
|
|
@@ -181,27 +123,6 @@ function applyBoundStatus(node: PlanNode): PlanNode {
|
|
|
181
123
|
return { ...node, status: boundStatusForAgent(getAgent(agentId)) ?? "pending" };
|
|
182
124
|
}
|
|
183
125
|
|
|
184
|
-
function cleanNode(input: PlanNodeInput, actor: string, planTeamId?: string): PlanNode {
|
|
185
|
-
if (!isRecord(input)) throw new ValidationError("node must be an object");
|
|
186
|
-
const scopeBlurb = cleanString(input.scopeBlurb, "node.scopeBlurb", { max: 2000 });
|
|
187
|
-
const ownerRef = cleanOwnerRef(input.ownerRef);
|
|
188
|
-
const lane = cleanString(input.lane, "node.lane", { max: 120 });
|
|
189
|
-
const refs = cleanRefs(input.refs, actor);
|
|
190
|
-
const blackboardRefs = cleanBlackboardRefs(input.blackboardRefs, planTeamId);
|
|
191
|
-
const statusSource = deriveStatusSource(input.statusSource, input.status, Boolean(refs?.taskId || refs?.issueId));
|
|
192
|
-
return applyBoundStatus({
|
|
193
|
-
id: cleanString(input.id, "node.id", { required: true, max: 120 })!,
|
|
194
|
-
label: cleanString(input.label, "node.label", { required: true, max: PLAN_NODE_LABEL_MAX })!,
|
|
195
|
-
...(scopeBlurb ? { scopeBlurb } : {}),
|
|
196
|
-
...(ownerRef ? { ownerRef } : {}),
|
|
197
|
-
...(lane ? { lane } : {}),
|
|
198
|
-
status: optionalEnum(input.status, "node.status", PLAN_STATUSES, "pending") as PlanStatus,
|
|
199
|
-
statusSource,
|
|
200
|
-
...(refs ? { refs } : {}),
|
|
201
|
-
...(blackboardRefs ? { blackboardRefs } : {}),
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
126
|
// The aggregate writer owns persisted validation (issue/task/blackboard existence and bound
|
|
206
127
|
// presence). This companion only validates shape, producing clone-safe command data.
|
|
207
128
|
function cleanNodeForAggregate(input: PlanNodeInput): PlanNode {
|
|
@@ -247,14 +168,6 @@ function cleanPatchForAggregate(patch: PlanNodePatch): Partial<PlanNode> {
|
|
|
247
168
|
return out;
|
|
248
169
|
}
|
|
249
170
|
|
|
250
|
-
function cleanNodes(value: unknown, actor: string, planTeamId?: string): PlanNode[] {
|
|
251
|
-
if (value === undefined || value === null) return [];
|
|
252
|
-
if (!Array.isArray(value)) throw new ValidationError("nodes must be an array");
|
|
253
|
-
const nodes = value.map((item) => cleanNode(item as PlanNodeInput, actor, planTeamId));
|
|
254
|
-
assertUnique(nodes.map((node) => node.id), "node id");
|
|
255
|
-
return nodes;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
171
|
function cleanEdge(input: unknown): PlanEdge {
|
|
259
172
|
if (!isRecord(input)) throw new ValidationError("edge must be an object");
|
|
260
173
|
return {
|
|
@@ -340,19 +253,19 @@ export function emitPlan(type: "plan.created" | "plan.changed" | "plan.deleted",
|
|
|
340
253
|
|
|
341
254
|
// #1035: a plan anchors to a messages.thread_id, but a fresh coordinator has no thread yet —
|
|
342
255
|
// forcing it to send a throwaway message just to mint one. When no threadId is supplied, mint the
|
|
343
|
-
// thread server-side by self-threading a lightweight system message (the same
|
|
256
|
+
// thread server-side by self-threading a lightweight system message (the same sendMessageAsync path the
|
|
344
257
|
// caller would have used). Sent AS the actor when that agent is registered, else the reserved
|
|
345
258
|
// `system` sink, so the mint always passes the sender-registration gate.
|
|
346
|
-
function mintPlanThread(ctx: AuthContext, channel: string | undefined): number {
|
|
259
|
+
async function mintPlanThread(ctx: AuthContext, channel: string | undefined): Promise<number> {
|
|
347
260
|
ensureCanMintThread(ctx);
|
|
348
261
|
const actor = actorId(ctx);
|
|
349
262
|
const sender = getAgent(actor) ? actor : "system";
|
|
350
|
-
const root =
|
|
263
|
+
const root = (await sendMessageAsync({
|
|
351
264
|
from: sender,
|
|
352
265
|
to: "system",
|
|
353
266
|
body: "Plan thread root",
|
|
354
267
|
...(channel ? { channel } : {}),
|
|
355
|
-
});
|
|
268
|
+
}));
|
|
356
269
|
return root.threadId ?? root.id;
|
|
357
270
|
}
|
|
358
271
|
|
|
@@ -364,7 +277,7 @@ async function mintPlanThreadAsync(ctx: AuthContext, channel: string | undefined
|
|
|
364
277
|
return root.threadId ?? root.id;
|
|
365
278
|
}
|
|
366
279
|
|
|
367
|
-
// #1043: the mint inserts a real message row through the db `
|
|
280
|
+
// #1043: the mint inserts a real message row through the db `sendMessageAsync` path, which normally
|
|
368
281
|
// lives behind the `message:send` scope. `plans:write` alone must not be a side-door around it, so
|
|
369
282
|
// gate the mint on `message:send`. Internal `system` principals (empty-scope trusted callers) and
|
|
370
283
|
// full-reach `*` tokens pass through untouched — `hasScope` short-circuits `*`.
|
|
@@ -375,78 +288,16 @@ function ensureCanMintThread(ctx: AuthContext): void {
|
|
|
375
288
|
}
|
|
376
289
|
}
|
|
377
290
|
|
|
378
|
-
export function createPlan(input: PlanCreateInput, ctx: AuthContext): Plan {
|
|
379
|
-
|
|
380
|
-
const actor = actorId(ctx);
|
|
381
|
-
const explicitTeamId = cleanString(input.teamId, "teamId", { max: 120 });
|
|
382
|
-
const teamId = explicitTeamId ?? (input.teamId === undefined || input.teamId === null ? getAgent(actor)?.teamId : undefined);
|
|
383
|
-
const nodes = cleanNodes(input.nodes, actor, teamId);
|
|
384
|
-
const edges = cleanEdges(input.edges);
|
|
385
|
-
validateEdges(nodes, edges);
|
|
386
|
-
const title = cleanString(input.title, "title", { max: 240 });
|
|
387
|
-
const objective = cleanString(input.objective, "objective", { max: 4000 });
|
|
388
|
-
const acceptance = cleanPlanAcceptance(input.acceptance);
|
|
389
|
-
// Resolve the thread only AFTER the payload validates (#1043): auto-minting first left an orphan
|
|
390
|
-
// 'Plan thread root' row behind on every rejected create.
|
|
391
|
-
const threadId = input.threadId === undefined || input.threadId === null
|
|
392
|
-
? mintPlanThread(ctx, channel)
|
|
393
|
-
: cleanThreadId(input.threadId);
|
|
394
|
-
if (!planThreadExists(threadId)) throw new ValidationError(`thread ${threadId} not found`);
|
|
395
|
-
const plan = createPlanRow({
|
|
396
|
-
threadId,
|
|
397
|
-
teamId,
|
|
398
|
-
channel,
|
|
399
|
-
title,
|
|
400
|
-
objective,
|
|
401
|
-
nodes,
|
|
402
|
-
edges,
|
|
403
|
-
acceptance,
|
|
404
|
-
createdBy: actor,
|
|
405
|
-
});
|
|
406
|
-
for (const node of plan.nodes) syncPlanNodeIssueAssociation(plan.id, node);
|
|
407
|
-
emitPlan("plan.created", plan, actor);
|
|
408
|
-
return plan;
|
|
291
|
+
export async function createPlan(input: PlanCreateInput, ctx: AuthContext): Promise<Plan> {
|
|
292
|
+
return createPlanAsync(input, ctx);
|
|
409
293
|
}
|
|
410
294
|
|
|
411
|
-
export function addPlanNode(planId: string, nodeInput: PlanNodeInput, ctx: AuthContext): Plan {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
if (plan.nodes.some((item) => item.id === node.id)) throw new ValidationError(`node ${node.id} already exists`);
|
|
418
|
-
return { ...plan, nodes: [...plan.nodes, node] };
|
|
419
|
-
}, actor);
|
|
420
|
-
syncPlanNodeIssueAssociation(updated.id, node); emitPlan("plan.changed", updated, actor);
|
|
421
|
-
return updated;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
export function updatePlanNode(planId: string, nodeId: string, patch: PlanNodePatch, ctx: AuthContext): Plan {
|
|
425
|
-
const actor = actorId(ctx);
|
|
426
|
-
// S6 #2079: re-apply the patch onto the latest node map (by nodeId); a distinct-node edit survives.
|
|
427
|
-
let existing!: PlanNode; let next!: PlanNode;
|
|
428
|
-
const updated = replacePlanNodeScoped(planId, (plan) => {
|
|
429
|
-
const current = plan.nodes.find((node) => node.id === nodeId);
|
|
430
|
-
if (!current) throw new ValidationError(`node ${nodeId} not found`); existing = current;
|
|
431
|
-
const statusSource = patch.statusSource !== undefined ? cleanStatusSource(patch.statusSource) : current.statusSource;
|
|
432
|
-
const base: PlanNode = {
|
|
433
|
-
...current,
|
|
434
|
-
...(patch.label !== undefined ? { label: cleanString(patch.label, "label", { required: true, max: PLAN_NODE_LABEL_MAX })! } : {}),
|
|
435
|
-
...(patch.scopeBlurb !== undefined ? optionalProp("scopeBlurb", cleanString(patch.scopeBlurb, "scopeBlurb", { max: 2000 })) : {}),
|
|
436
|
-
...(patch.ownerRef !== undefined ? optionalProp("ownerRef", cleanOwnerRef(patch.ownerRef)) : {}),
|
|
437
|
-
...(patch.lane !== undefined ? optionalProp("lane", cleanString(patch.lane, "lane", { max: 120 })) : {}),
|
|
438
|
-
...(patch.status !== undefined ? { status: optionalEnum(patch.status, "status", PLAN_STATUSES) as PlanStatus } : {}),
|
|
439
|
-
...(patch.refs !== undefined ? optionalProp("refs", cleanRefs(patch.refs, actor)) : {}),
|
|
440
|
-
...(patch.blackboardRefs !== undefined ? optionalProp("blackboardRefs", cleanBlackboardRefs(patch.blackboardRefs, plan.teamId)) : {}),
|
|
441
|
-
statusSource,
|
|
442
|
-
};
|
|
443
|
-
// #2520 RESOLUTION — the ONE shared patch-time source derivation (lives beside the writer op
|
|
444
|
-
// body it mirrors; see applyPatchStatusSourceDerivation in db/plan-graph.ts).
|
|
445
|
-
next = applyBoundStatus(applyPatchStatusSourceDerivation(patch, current, base));
|
|
446
|
-
return { ...plan, nodes: plan.nodes.map((node) => node.id === nodeId ? next : node) };
|
|
447
|
-
}, actor);
|
|
448
|
-
syncChangedPlanNodeIssueAssociation(updated.id, existing, next); emitPlan("plan.changed", updated, actor);
|
|
449
|
-
return updated;
|
|
295
|
+
export async function addPlanNode(planId: string, nodeInput: PlanNodeInput, ctx: AuthContext): Promise<Plan> {
|
|
296
|
+
return addPlanNodeAsync(planId, nodeInput, ctx);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export async function updatePlanNode(planId: string, nodeId: string, patch: PlanNodePatch, ctx: AuthContext): Promise<Plan> {
|
|
300
|
+
return updatePlanNodeAsync(planId, nodeId, patch, ctx);
|
|
450
301
|
}
|
|
451
302
|
|
|
452
303
|
function optionalProp<K extends keyof PlanNode>(key: K, value: PlanNode[K] | undefined): Partial<PlanNode> {
|
|
@@ -470,72 +321,20 @@ function assertEdgeKeepsAcyclic(plan: Plan, edge: PlanEdge): void {
|
|
|
470
321
|
validateEdges(projected.nodes, dedupeEdges([...projected.edges, edge]));
|
|
471
322
|
}
|
|
472
323
|
|
|
473
|
-
export function addPlanEdge(planId: string, edgeInput: unknown, ctx: AuthContext): Plan {
|
|
474
|
-
|
|
475
|
-
const edge = cleanEdge(edgeInput);
|
|
476
|
-
assertEdgeKeepsAcyclic(plan, edge);
|
|
477
|
-
// #836: when BOTH endpoints are Task-bound, the canonical edge store is task_dependencies,
|
|
478
|
-
// not the plan JSON. Plan edge {from,to} means `to` depends on `from`. The combined-graph
|
|
479
|
-
// pre-check above already rejected cross-store cycles; the edge surfaces back via projection.
|
|
480
|
-
const fromTask = boundTaskId(plan, edge.from);
|
|
481
|
-
const toTask = boundTaskId(plan, edge.to);
|
|
482
|
-
if (fromTask !== undefined && toTask !== undefined) {
|
|
483
|
-
addTaskDependency(toTask, fromTask, actorId(ctx));
|
|
484
|
-
const projected = projectPlanOverTasks(existingPlan(planId));
|
|
485
|
-
emitPlan("plan.changed", projected, actorId(ctx));
|
|
486
|
-
return projected;
|
|
487
|
-
}
|
|
488
|
-
// S6 #2079: fence behind the version-CAS; re-append + re-check acyclicity on the fresh snapshot.
|
|
489
|
-
const updated = replacePlanNodeScoped(planId, (fresh) => {
|
|
490
|
-
assertEdgeKeepsAcyclic(fresh, edge);
|
|
491
|
-
return { ...fresh, edges: dedupeEdges([...fresh.edges, edge]) };
|
|
492
|
-
}, actorId(ctx));
|
|
493
|
-
emitPlan("plan.changed", updated, actorId(ctx)); return updated;
|
|
324
|
+
export async function addPlanEdge(planId: string, edgeInput: unknown, ctx: AuthContext): Promise<Plan> {
|
|
325
|
+
return addPlanEdgeAsync(planId, edgeInput, ctx);
|
|
494
326
|
}
|
|
495
327
|
|
|
496
|
-
export function removePlanNode(planId: string, nodeId: string, ctx: AuthContext): Plan {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
edges: plan.edges.filter((edge) => edge.from !== nodeId && edge.to !== nodeId),
|
|
507
|
-
};
|
|
508
|
-
}, actor);
|
|
509
|
-
removePlanNodeIssueAssociation(updated.id, removed); emitPlan("plan.changed", updated, actor);
|
|
510
|
-
return updated;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
export function removePlanEdge(planId: string, edgeInput: unknown, ctx: AuthContext): Plan {
|
|
514
|
-
const plan = existingPlan(planId);
|
|
515
|
-
const edge = cleanEdge(edgeInput);
|
|
516
|
-
// A bound-pair edge can live in BOTH task_dependencies and the plan JSON, and projection unions
|
|
517
|
-
// them: clear both stores or the edge reappears (#2877).
|
|
518
|
-
const fromTask = boundTaskId(plan, edge.from);
|
|
519
|
-
const toTask = boundTaskId(plan, edge.to);
|
|
520
|
-
const depRemoved = fromTask !== undefined && toTask !== undefined && removeTaskDependency(toTask, fromTask, actorId(ctx));
|
|
521
|
-
// S6 #2079: fence behind the version-CAS; re-resolve the edge (and its not-found check) on fresh.
|
|
522
|
-
const updated = replacePlanNodeScoped(planId, (fresh) => {
|
|
523
|
-
const edges = fresh.edges.filter((item) => item.from !== edge.from || item.to !== edge.to);
|
|
524
|
-
if (!depRemoved && edges.length === fresh.edges.length) throw new ValidationError(`edge ${edge.from}->${edge.to} not found`);
|
|
525
|
-
return { ...fresh, edges };
|
|
526
|
-
}, actorId(ctx));
|
|
527
|
-
const projected = projectPlanOverTasks(updated);
|
|
528
|
-
emitPlan("plan.changed", projected, actorId(ctx));
|
|
529
|
-
return projected;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
export function deletePlanGraph(planId: string, ctx: AuthContext): { id: string; deleted: true } {
|
|
533
|
-
const plan = existingPlan(planId);
|
|
534
|
-
const actor = actorId(ctx);
|
|
535
|
-
deletePlan(plan.id, actor);
|
|
536
|
-
for (const node of plan.nodes) removePlanNodeIssueAssociation(plan.id, node);
|
|
537
|
-
emitPlan("plan.deleted", plan, actor);
|
|
538
|
-
return { id: plan.id, deleted: true };
|
|
328
|
+
export async function removePlanNode(planId: string, nodeId: string, ctx: AuthContext): Promise<Plan> {
|
|
329
|
+
return (await removePlanNodeAsync(planId, nodeId, ctx)).plan;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export async function removePlanEdge(planId: string, edgeInput: unknown, ctx: AuthContext): Promise<Plan> {
|
|
333
|
+
return removePlanEdgeAsync(planId, edgeInput, ctx);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export async function deletePlanGraph(planId: string, ctx: AuthContext): Promise<{ id: string; deleted: true }> {
|
|
337
|
+
return deletePlanGraphAsync(planId, ctx);
|
|
539
338
|
}
|
|
540
339
|
|
|
541
340
|
export async function archivePlanGraphAsync(planId: string, archived: boolean, ctx: AuthContext): Promise<Plan> {
|
|
@@ -547,29 +346,12 @@ export async function archivePlanGraphAsync(planId: string, archived: boolean, c
|
|
|
547
346
|
|
|
548
347
|
// In-process (legacy/unit-test) sibling of the gateway-backed applyBoundOwnersAsync path (production
|
|
549
348
|
// never takes this branch). S6 #2079: fence each write behind the version-CAS; re-derive on fresh.
|
|
550
|
-
export function updateBoundPlanNodesForAgent(agentId: string, status: PlanStatus, actor = "server"): Plan[] {
|
|
551
|
-
|
|
552
|
-
node.statusSource === "bound" && node.ownerRef?.agentId === agentId && node.status !== "landed" && node.status !== status;
|
|
553
|
-
const updated: Plan[] = [];
|
|
554
|
-
for (const plan of listPlansWithBoundOwner(agentId)) {
|
|
555
|
-
// Skip-no-op on the initial snapshot: don't even fence a write when there's nothing to flip.
|
|
556
|
-
if (!plan.nodes.some(boundFlip)) continue;
|
|
557
|
-
// Preserve that contract THROUGH a CAS-conflict retry: if a re-read snapshot no longer needs a
|
|
558
|
-
// flip (a concurrent writer already applied it), return null so no version bump / event fires.
|
|
559
|
-
let wrote = false;
|
|
560
|
-
const next = replacePlanNodeScoped(plan.id, (fresh) => {
|
|
561
|
-
wrote = fresh.nodes.some(boundFlip);
|
|
562
|
-
return wrote ? { ...fresh, nodes: fresh.nodes.map((node) => (boundFlip(node) ? { ...node, status } : node)) } : null;
|
|
563
|
-
}, actor);
|
|
564
|
-
if (!wrote) continue; // the retry resolved to a no-op — nothing was written, so don't emit/collect
|
|
565
|
-
emitPlan("plan.changed", next, actor); updated.push(next);
|
|
566
|
-
}
|
|
567
|
-
return updated;
|
|
349
|
+
export async function updateBoundPlanNodesForAgent(agentId: string, status: PlanStatus, actor = "server"): Promise<Plan[]> {
|
|
350
|
+
return updateBoundPlanNodesForAgentAsync(agentId, status, actor);
|
|
568
351
|
}
|
|
569
352
|
|
|
570
|
-
export function updateBoundPlanNodesFromAgent(agentId: string, actor = "server"): Plan[] {
|
|
571
|
-
|
|
572
|
-
return status ? updateBoundPlanNodesForAgent(agentId, status, actor) : [];
|
|
353
|
+
export async function updateBoundPlanNodesFromAgent(agentId: string, actor = "server"): Promise<Plan[]> {
|
|
354
|
+
return updateBoundPlanNodesFromAgentAsync(agentId, boundStatusForAgent(getAgent(agentId)), actor);
|
|
573
355
|
}
|
|
574
356
|
|
|
575
357
|
/** Gateway-only live-binding path. The read precheck avoids submitting a no-op writer job. */
|
|
@@ -581,7 +363,7 @@ export async function updateBoundPlanNodesForAgentAsync(agentId: string, status:
|
|
|
581
363
|
}
|
|
582
364
|
|
|
583
365
|
export async function updateBoundPlanNodesFromAgentAsync(agentId: string, status: PlanStatus | undefined, actor = "server"): Promise<Plan[]> {
|
|
584
|
-
return status ? updateBoundPlanNodesForAgentAsync(agentId, status, actor) : [];
|
|
366
|
+
return status ? (await updateBoundPlanNodesForAgentAsync(agentId, status, actor)) : [];
|
|
585
367
|
}
|
|
586
368
|
|
|
587
369
|
// #836: `view: "tasks"` returns the pure task-backed DAG synthesized from a team's deliverable
|
|
@@ -623,12 +405,8 @@ export interface BindPlanNodeInput {
|
|
|
623
405
|
taskId?: number;
|
|
624
406
|
}
|
|
625
407
|
|
|
626
|
-
export function bindPlanNodeToTask(planId: string, nodeId: string, input: BindPlanNodeInput, ctx: AuthContext): { plan: Plan; taskId: number } {
|
|
627
|
-
|
|
628
|
-
const result = writeTransaction(() => bindPlanNodeBody({ planId, nodeId, taskId: input.taskId, actor }, Date.now()));
|
|
629
|
-
emitPlan("plan.changed", result.plan, actor);
|
|
630
|
-
emitPlanTaskEvents(result.taskEvents);
|
|
631
|
-
return { plan: result.plan, taskId: result.taskId! };
|
|
408
|
+
export async function bindPlanNodeToTask(planId: string, nodeId: string, input: BindPlanNodeInput, ctx: AuthContext): Promise<{ plan: Plan; taskId: number }> {
|
|
409
|
+
return bindPlanNodeToTaskAsync(planId, nodeId, input, ctx);
|
|
632
410
|
}
|
|
633
411
|
|
|
634
412
|
// HTTP and MCP can await. Keep the synchronous entry points above for the event reducers and
|
|
@@ -698,6 +476,6 @@ export async function bindPlanNodeToTaskAsync(planId: string, nodeId: string, in
|
|
|
698
476
|
// The aggregate ack is after COMMIT. Emit every consumer-facing task intent only here,
|
|
699
477
|
// never from the worker, so failed aggregate writes are observably silent.
|
|
700
478
|
emitPlan("plan.changed", result.plan, actor);
|
|
701
|
-
emitPlanTaskEvents(result.taskEvents);
|
|
479
|
+
await emitPlanTaskEvents(result.taskEvents);
|
|
702
480
|
return { plan: result.plan, taskId: result.taskId! };
|
|
703
481
|
}
|
|
@@ -60,7 +60,7 @@ export async function importPlan(input: Record<string, unknown>, ctx: AuthContex
|
|
|
60
60
|
const { dryRun, ...args } = preparePlanImport(input, ctx);
|
|
61
61
|
if (dryRun) return await getGateway().read("planGraph.import.preview", args) as unknown as PlanImportResult;
|
|
62
62
|
const result = await getGateway().write("planGraph.import", args) as unknown as PlanImportWriteResult;
|
|
63
|
-
emitPlanTaskEvents(result.taskEvents);
|
|
63
|
+
await emitPlanTaskEvents(result.taskEvents);
|
|
64
64
|
if (result.plan) emitPlan(args.expectedVersion === 0 ? "plan.created" : "plan.changed", result.plan, args.actor);
|
|
65
65
|
return result.receipt;
|
|
66
66
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { updateBoundPlanNodesFromAgentAsync, updateBoundPlanNodesForAgentAsync } from "./plan-graph";
|
|
2
|
+
import { getTeamAsync } from "../db";
|
|
3
|
+
import { trackRelayEvent } from "../relay-event-drain";
|
|
3
4
|
import { subscribeRelayEvents, type RelayEvent } from "../events";
|
|
4
5
|
import { routeNotification } from "../notification-router";
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
|
|
7
8
|
let unsubscribe: (() => void) | undefined;
|
|
8
9
|
|
|
@@ -48,7 +49,7 @@ async function notifyBoundExit(event: RelayEvent, updatedPlans: Awaited<ReturnTy
|
|
|
48
49
|
const target = team?.coordinatorId ?? `team:${plan.teamId}`;
|
|
49
50
|
const blockedNodes = plan.nodes.filter((node) => node.statusSource === "bound" && node.ownerRef?.agentId === agentId && node.status === "blocked");
|
|
50
51
|
if (blockedNodes.length === 0) continue;
|
|
51
|
-
routeNotification({
|
|
52
|
+
await routeNotification({
|
|
52
53
|
type: "plan.bound_agent_exited",
|
|
53
54
|
scope: { agentId, planId: plan.id, teamId: plan.teamId },
|
|
54
55
|
recipients: [target],
|
|
@@ -92,39 +93,9 @@ async function handlePlanBindingEventAsync(event: RelayEvent): Promise<void> {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
function handlePlanBindingEvent(event: RelayEvent): void {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (getGateway().stats.backend === "in-process") {
|
|
99
|
-
if (event.type === "agent.status") {
|
|
100
|
-
const agentId = agentIdFromEvent(event);
|
|
101
|
-
if (agentId) updateBoundPlanNodesFromAgent(agentId, event.source || "server");
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
if (event.type === "branch.landed") {
|
|
105
|
-
const agentId = stringField(event.data.author);
|
|
106
|
-
if (agentId) updateBoundPlanNodesForAgent(agentId, "landed", event.source || "server");
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (event.type === "agent.exited") {
|
|
110
|
-
const agentId = agentIdFromEvent(event);
|
|
111
|
-
if (!agentId || isGracefulExitReason(stringField(event.data.reason))) return;
|
|
112
|
-
const updated = updateBoundPlanNodesForAgent(agentId, "blocked", event.source || "server");
|
|
113
|
-
const reason = stringField(event.data.reason);
|
|
114
|
-
for (const plan of updated) {
|
|
115
|
-
if (!plan.teamId) continue;
|
|
116
|
-
const team = getTeam(plan.teamId);
|
|
117
|
-
const nodes = plan.nodes.filter((node) => node.statusSource === "bound" && node.ownerRef?.agentId === agentId && node.status === "blocked");
|
|
118
|
-
if (nodes.length) routeNotification({ type: "plan.bound_agent_exited", scope: { agentId, planId: plan.id, teamId: plan.teamId }, recipients: [team?.coordinatorId ?? `team:${plan.teamId}`], message: { subject: "Bound plan node blocked", body: `Agent \`${agentId}\` exited${reason ? ` (${reason})` : ""}; blocked plan node(s) ${nodes.map((node) => `\`${node.id}\``).join(", ")} in \`${plan.id}\`.`, payload: { kind: "plan.bound_agent_exited", planId: plan.id, agentId, nodeIds: nodes.map((node) => node.id), reason }, replyExpected: false } });
|
|
119
|
-
}
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// Event listeners are synchronous. Serialize the asynchronous aggregate submissions so an
|
|
124
|
-
// agent's rapid status sequence reaches the FIFO writer in event order.
|
|
125
|
-
pending = pending.then(() => handlePlanBindingEventAsync(event)).catch((error) => {
|
|
126
|
-
console.error("plan live binding update failed", error);
|
|
127
|
-
});
|
|
96
|
+
const run = pending.then(() => handlePlanBindingEventAsync(event));
|
|
97
|
+
pending = run.catch(() => {});
|
|
98
|
+
trackRelayEvent(run, "plan.live-binding");
|
|
128
99
|
}
|
|
129
100
|
|
|
130
101
|
export function startPlanLiveBindings(): void {
|
|
@@ -72,7 +72,7 @@ export async function createPlanTaskAsync(input: CreateTaskEntityInput, extras:
|
|
|
72
72
|
};
|
|
73
73
|
// The caller's key makes a retry return the first result instead of a second Task or node.
|
|
74
74
|
const result = await getGateway().write("planGraph.task.create", args, { idempotencyKey: options.idempotencyKey ?? randomUUID() }) as unknown as CreatePlanTaskResult;
|
|
75
|
-
emitPlanTaskEvents(result.taskEvents);
|
|
75
|
+
await emitPlanTaskEvents(result.taskEvents);
|
|
76
76
|
if (result.plan) emitPlan("plan.changed", result.plan, createdBy);
|
|
77
77
|
// A replay returns the first write's result; the receipt reads the Task as it is now.
|
|
78
78
|
const task = await getTaskDetailAsync(result.task.id) ?? result.task;
|
|
@@ -68,16 +68,6 @@ export async function advanceTerminalPlanRefsAsync(trigger: TerminalRefTrigger):
|
|
|
68
68
|
* (replacePlanNodeScoped), and a residual failure degrades to warn-and-continue exactly like the
|
|
69
69
|
* async twin — a propagation failure must never fail the durable status/stage write.
|
|
70
70
|
*/
|
|
71
|
-
export function advanceTerminalPlanRefs(trigger: TerminalRefTrigger): Plan[] {
|
|
72
|
-
|
|
73
|
-
if (taskIds.length === 0 && issueRefIds.length === 0) return [];
|
|
74
|
-
try {
|
|
75
|
-
const results = applyTerminalPlanRefsBody({ taskIds, issueRefIds, actor }, Date.now());
|
|
76
|
-
const plans = results.map((result) => result.plan);
|
|
77
|
-
emitChanged(plans, actor);
|
|
78
|
-
return plans;
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.warn(`plan-terminal-refs propagation failed (${trigger.taskId !== undefined ? `task ${trigger.taskId}` : trigger.issueRefId !== undefined ? `issue ${trigger.issueRefId}` : "trigger"}): ${errMessage(error)}`);
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
71
|
+
export async function advanceTerminalPlanRefs(trigger: TerminalRefTrigger): Promise<Plan[]> {
|
|
72
|
+
return advanceTerminalPlanRefsAsync(trigger);
|
|
83
73
|
}
|
|
@@ -11,7 +11,7 @@ export const PLAN_WAKE_DIGEST_MAX_BYTES = 1024;
|
|
|
11
11
|
const INTRO = "Open team Plans: keep plans current and drive acceptance; relay_decision only when really blocked. In-progress age = plan update age.";
|
|
12
12
|
const MORE = "More plans/nodes: relay_plan_list; relay_plan_get mode=resume.";
|
|
13
13
|
|
|
14
|
-
function compactText(value: string, maxBytes: number): string {
|
|
14
|
+
export function compactText(value: string, maxBytes: number): string {
|
|
15
15
|
const text = value.slice(0, maxBytes).replace(/\s+/g, " ").trim();
|
|
16
16
|
if (Buffer.byteLength(value) <= maxBytes) return text;
|
|
17
17
|
let result = "";
|
|
@@ -42,9 +42,14 @@ function refsDone(node: PlanNode): boolean {
|
|
|
42
42
|
return true;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
/** The one node classification both the wake digest and the ready-node notice read (#3660). */
|
|
46
|
+
export function liveFrontier(stored: Plan) {
|
|
46
47
|
const plan = projectPlanOverTasks(stored);
|
|
47
|
-
|
|
48
|
+
return { plan, frontier: planResumeFrontier(plan) };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function planLine(stored: Plan, now: number): string {
|
|
52
|
+
const { plan, frontier } = liveFrontier(stored);
|
|
48
53
|
const parts: string[] = [];
|
|
49
54
|
if (frontier.ready.length) parts.push(`ready: ${nodeList(frontier.ready)}`);
|
|
50
55
|
if (frontier.inProgress.length) {
|
|
@@ -70,6 +75,7 @@ export function renderPlanWakeDigest(agentId: string, now = Date.now()): string
|
|
|
70
75
|
do {
|
|
71
76
|
const page = listPlansByTeam(teamId, { limit: 8, cursor });
|
|
72
77
|
for (const summary of page.plans) {
|
|
78
|
+
if (!summary.nodeCount) continue;
|
|
73
79
|
const plan = getPlan(summary.id);
|
|
74
80
|
if (!plan) continue;
|
|
75
81
|
const line = planLine(plan, now);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// #3636 — project trust edits without the dashboard: set a profile's review mode, acknowledge its
|
|
2
2
|
// project hooks/MCP, approve an observed value. One seam for the HTTP routes and the MCP tool.
|
|
3
3
|
import { ValidationError, type AgentProfile, type ProfileProjectReviewMode } from "@humwick/sdk";
|
|
4
|
-
import { getAgentProfile,
|
|
4
|
+
import { getAgentProfile, validateAgentProfile } from "../config-store";
|
|
5
|
+
import { setAgentProfileAsync } from "../config-store-write";
|
|
5
6
|
import type { ConfigEntry } from "../types";
|
|
6
7
|
import type { ProjectTrustApproval, ProjectTrustCapability } from "../db/project-trust-approvals";
|
|
7
8
|
import { approveProjectCapabilityReview, projectCellsHash } from "../project-trust";
|
|
@@ -38,17 +39,17 @@ export function withProjectTrust(profile: AgentProfile, update: ProjectTrustUpda
|
|
|
38
39
|
return validated;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export function
|
|
42
|
+
export async function updateProfileProjectTrustAsync(name: string, update: ProjectTrustUpdate, by: string): Promise<ConfigEntry<AgentProfile>> {
|
|
42
43
|
if (!update.review && !update.ack?.length) throw new ValidationError("nothing to update: pass review and/or ack");
|
|
43
|
-
const saved =
|
|
44
|
+
const saved = await setAgentProfileAsync(withProjectTrust(existingProfile(name).value, update, by), by, { overrideBuiltIn: true });
|
|
44
45
|
emitConfigChanged(saved.namespace, saved.key, saved.version);
|
|
45
46
|
return saved;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/** Approve an observed `sha256:…` (fingerprint) or `commit:…` value; the mode follows the prefix. */
|
|
49
|
-
export function approveProfileProjectTrust(input: { name: string; capability: ProjectTrustCapability; repoKey: string; value: string; by: string }): ProjectTrustApproval {
|
|
50
|
+
export async function approveProfileProjectTrust(input: { name: string; capability: ProjectTrustCapability; repoKey: string; value: string; by: string }): Promise<ProjectTrustApproval> {
|
|
50
51
|
const profileName = existingProfile(input.name).value.name;
|
|
51
52
|
const mode = input.value.startsWith("commit:") ? "commit" : input.value.startsWith("sha256:") ? "fingerprint" : undefined;
|
|
52
53
|
if (!mode) throw new ValidationError(`approved value must start with "sha256:" or "commit:", as shown in the refusal`);
|
|
53
|
-
return approveProjectCapabilityReview({ profileName, repoKey: input.repoKey, capability: input.capability, mode, approvedValue: input.value, approvedBy: input.by });
|
|
54
|
+
return (await approveProjectCapabilityReview({ profileName, repoKey: input.repoKey, capability: input.capability, mode, approvedValue: input.value, approvedBy: input.by }));
|
|
54
55
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// #3635/#3736 — one reader for `.agent-relay/*.json` project config (areas.json, spawn-policy.json): the
|
|
2
|
+
// file at the checkout's default branch (origin/<default>, fetched first), read on the checkout's host
|
|
3
|
+
// through the #3043 project-files reader. Never a working tree and never cached, so a stale checkout or
|
|
4
|
+
// an old negative answer cannot hide a file that landed.
|
|
5
|
+
import { readProjectFiles } from "@humwick/sdk";
|
|
6
|
+
import type { ConfigAtCommit } from "@humwick/sdk/repo-config-file";
|
|
7
|
+
import { errMessage } from "@humwick/sdk";
|
|
8
|
+
import { rootsForProject } from "../db";
|
|
9
|
+
import { localProjectGit, readHostProjectFiles } from "../project-roles";
|
|
10
|
+
import { hostIsRelayHost } from "../relay-host-locality";
|
|
11
|
+
import { resolveProjectFilesHost } from "./spawn-project-role";
|
|
12
|
+
|
|
13
|
+
/** A checkout to read from: a cwd on a host (a hostname or a registered orchestrator). */
|
|
14
|
+
export interface ProjectCheckout {
|
|
15
|
+
cwd: string;
|
|
16
|
+
host?: string;
|
|
17
|
+
orchestratorId?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ConfigLookup<T> = ConfigAtCommit<T> | { status: "unreadable"; error: string };
|
|
21
|
+
|
|
22
|
+
type Snapshot = { ref: string; sha: string; files: Record<string, string | null> };
|
|
23
|
+
|
|
24
|
+
const warned = new Set<string>();
|
|
25
|
+
|
|
26
|
+
/** One warning per distinct problem, so a broken file does not flood the log on every read. */
|
|
27
|
+
export function warnConfigOnce(key: string, message: string): void {
|
|
28
|
+
if (warned.has(key)) return;
|
|
29
|
+
if (warned.size >= 1000) warned.clear();
|
|
30
|
+
warned.add(key);
|
|
31
|
+
console.warn(message);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** `file` at the checkout's default branch; a read failure is `unreadable`, never a throw. Invalid and
|
|
35
|
+
* unreadable outcomes warn once, naming `file`, the checkout and why, with `consequence` appended. */
|
|
36
|
+
export async function readProjectConfig<T>(checkout: ProjectCheckout, file: string, parse: (snapshot: Snapshot) => ConfigAtCommit<T>, consequence: string): Promise<ConfigLookup<T>> {
|
|
37
|
+
const where = `${checkout.orchestratorId ?? checkout.host ?? "local"}:${checkout.cwd}`;
|
|
38
|
+
try {
|
|
39
|
+
const snapshot = !checkout.orchestratorId && hostIsRelayHost(checkout.host)
|
|
40
|
+
? await readProjectFiles({ paths: [file] }, localProjectGit(checkout.cwd))
|
|
41
|
+
: await readHostProjectFiles(
|
|
42
|
+
resolveProjectFilesHost({ subject: file, cwd: checkout.cwd, orchestratorId: checkout.orchestratorId, preferHost: checkout.host }),
|
|
43
|
+
checkout.cwd, { paths: [file] }, file,
|
|
44
|
+
);
|
|
45
|
+
const lookup = parse(snapshot);
|
|
46
|
+
if (lookup.status === "invalid") warnConfigOnce(`${file}@${where}@${lookup.sha}`, `[project-config] ${file} for ${where} at ${lookup.sha.slice(0, 12)} is invalid: ${lookup.error}; ${consequence}`);
|
|
47
|
+
return lookup;
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const error = errMessage(err);
|
|
50
|
+
warnConfigOnce(`${file}@${where}`, `[project-config] ${file} for ${where}: unreadable: ${error}; ${consequence}`);
|
|
51
|
+
return { status: "unreadable", error };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The first checkout that can be read answers: the preferred ones, then each registered root of the project. */
|
|
56
|
+
export async function readProjectConfigFirst<T>(
|
|
57
|
+
projectId: string | undefined, preferred: readonly ProjectCheckout[], file: string, parse: (snapshot: Snapshot) => ConfigAtCommit<T>, consequence: string,
|
|
58
|
+
): Promise<{ lookup?: ConfigAtCommit<T>; failures: string[] }> {
|
|
59
|
+
const checkouts: ProjectCheckout[] = [
|
|
60
|
+
...preferred,
|
|
61
|
+
...(projectId ? rootsForProject(projectId).map((root) => ({ cwd: root.rootPath, ...(root.orchestratorId ? { orchestratorId: root.orchestratorId } : {}) })) : []),
|
|
62
|
+
];
|
|
63
|
+
const failures: string[] = [];
|
|
64
|
+
for (const checkout of checkouts) {
|
|
65
|
+
const lookup = await readProjectConfig(checkout, file, parse, consequence);
|
|
66
|
+
if (lookup.status !== "unreadable") return { lookup, failures };
|
|
67
|
+
failures.push(lookup.error);
|
|
68
|
+
}
|
|
69
|
+
return { failures };
|
|
70
|
+
}
|