@humwick/server 0.130.1 → 0.130.2
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/docs/guides/tools-administration.md +4 -0
- package/docs/guides/tools-coordination.md +1 -0
- package/docs/guides/tools-tasks.md +8 -0
- package/docs/guides/workflows.md +58 -0
- package/docs/openapi.json +414 -1
- package/package.json +8 -17
- package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-BWLqMGKG.js} +2 -2
- package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-3TlIQpjk.js} +2 -2
- package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-Wimm0Czv.js} +2 -2
- package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-Bau_vNax.js} +2 -2
- package/public/assets/{activity-yLztXEBt.js → activity-CrSurn-r.js} +2 -2
- package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-CknAJKcb.js} +2 -2
- package/public/assets/agent-liveness-CaNwK0Zf.js +2 -0
- package/public/assets/{agent-name-CTZBrSD9.js → agent-name-DKbiIhBo.js} +2 -2
- package/public/assets/agent-profiles-DwF6EQ4R.js +2 -0
- package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-Diz4Sjjb.js} +2 -2
- package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-CRhpRQza.js} +2 -2
- package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-LrUEU3lB.js} +2 -2
- package/public/assets/{agents-BYDslkJc.js → agents-B-v66C-4.js} +2 -2
- package/public/assets/{analytics-B-XSbEMC.js → analytics-BqCb-LKi.js} +2 -2
- package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-kf4pGuAR.js} +2 -2
- package/public/assets/{artifacts-oBOqks-2.js → artifacts-D32zyw4Y.js} +2 -2
- package/public/assets/{artifacts-DPN1q4pA.js → artifacts-DJevXcvg.js} +2 -2
- package/public/assets/{automation-4KcRFXEu.js → automation-BpRajx_5.js} +2 -2
- package/public/assets/{backlog-Cw9xPTCF.js → backlog-D_UjTdzX.js} +2 -2
- package/public/assets/{busy-health-CTu32MZt.js → busy-health-N3VEh4ao.js} +2 -2
- package/public/assets/{channels-BiXzg1G9.js → channels-9jopungq.js} +2 -2
- package/public/assets/{chat-Ctk2qwvA.js → chat-CSXrTB3C.js} +2 -2
- package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-p1NnmqK0.js} +2 -2
- package/public/assets/{connectors-C36ax4Vw.js → connectors-CZdqlDNL.js} +2 -2
- package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BgdsE4dG.js} +2 -2
- package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-30aXTKva.js} +2 -2
- package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-B_jvw2GE.js} +2 -2
- package/public/assets/{deploys-Bwfq146q.js → deploys-DoN6bAb5.js} +2 -2
- package/public/assets/{display-CfO7rTuF.js → display-BrKWFGJz.js} +2 -2
- package/public/assets/{files-DhhZI2Ih.js → files-D6XEu8Ng.js} +2 -2
- package/public/assets/{fleet-B_rFEbnL.js → fleet-C7jQWbw2.js} +2 -2
- package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BiDs3MLx.js} +2 -2
- package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-CQBwc1fb.js} +3 -3
- package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-DyG0WsQS.js} +2 -2
- package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-DKaW31dN.js} +2 -2
- package/public/assets/index-CRHep3M9.js +15 -0
- package/public/assets/index-MYAIwYTX.css +2 -0
- package/public/assets/{insights-fH1EL-qZ.js → insights-CzrtkpOE.js} +2 -2
- package/public/assets/{integrations-C5Oix6ng.js → integrations-aVsUmigt.js} +2 -2
- package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-BnSlM_95.js} +2 -2
- package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-qe7Ee47Z.js} +2 -2
- package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-NfjqFZAk.js} +2 -2
- package/public/assets/{managed-agents-egllbpij.js → managed-agents-BiH0HgaE.js} +2 -2
- package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-BixaT3Xr.js} +3 -3
- package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-DNGlWIS3.js} +2 -2
- package/public/assets/{memory-C8WmXsyr.js → memory-DNsCl6UX.js} +2 -2
- package/public/assets/{messages-BzQdqlO6.js → messages-DopU1L1X.js} +2 -2
- package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Cq7ckLQT.js} +2 -2
- package/public/assets/{overview-DCUnI4Z7.js → overview-C1DCTzzV.js} +2 -2
- package/public/assets/{pairs-ftCd2XcD.js → pairs-DE_m6rrE.js} +2 -2
- package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-B3rfh77F.js} +2 -2
- package/public/assets/project-profile-instructions-DQWZE0kA.js +2 -0
- package/public/assets/projects-Br2Bd2h1.js +2 -0
- package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-BKvFsvGD.js} +2 -2
- package/public/assets/provider-display-DsuWMvVL.js +2 -0
- package/public/assets/{registry-DWCU5c8q.js → registry-Cw38_6gW.js} +2 -2
- package/public/assets/run-card-CpKqRbhg.js +2 -0
- package/public/assets/scroll-text-BKXS1ahr.js +2 -0
- package/public/assets/{secrets-C7GIUATz.js → secrets-DxI-vzSq.js} +2 -2
- package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-D9s_VJbd.js} +2 -2
- package/public/assets/{settings-C6sZ9eBa.js → settings-CKZTVGIx.js} +2 -2
- package/public/assets/{shipping-Bu8p1gEw.js → shipping-B9YtnwtG.js} +2 -2
- package/public/assets/{stats-V9Z-GxUd.js → stats-DyUBKyWI.js} +2 -2
- package/public/assets/{status-dot-CVv0iGHL.js → status-dot-DYqlEUhJ.js} +2 -2
- package/public/assets/{store-BvtFdlGX.js → store-DcClXLH0.js} +3 -3
- package/public/assets/{tasks-CXU75HRF.js → tasks-Bh7Chr4-.js} +2 -2
- package/public/assets/{teams-BPf976zb.js → teams-bowI7qVY.js} +2 -2
- package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-BgVLHdsU.js} +3 -3
- package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-Dz22UPy6.js} +2 -2
- package/public/assets/token-estimate-Co-Jdphh.js +2 -0
- package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-DSQQ-iY7.js} +2 -2
- package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-samMQhQf.js} +2 -2
- package/public/assets/use-project-list-59LheVP7.js +2 -0
- package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BZa25xEB.js} +2 -2
- package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-DHxlvUvV.js} +2 -2
- package/public/assets/versioned-prompt-editor-BmED5DnJ.js +8 -0
- package/public/assets/{work-queue-TCjJxeT-.js → work-queue-CSvpuNLz.js} +2 -2
- package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-DAZcj5qt.js} +2 -2
- package/public/assets/{workflows-CXQX20Qj.js → workflows-DdmxRSyg.js} +2 -2
- package/public/assets/{workspaces-qSYzKYMA.js → workspaces-BxeKfVuF.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/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/agent-runner/credentials.ts +42 -12
- package/runner/src/agent-runner/inbox.ts +27 -0
- package/runner/src/agent-runner/lifecycle-milestones.ts +0 -2
- 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/index.ts +5 -2
- package/runner/src/provider-setup.ts +34 -0
- package/runner/src/providers.ts +2 -1
- package/runner/src/runner-core.ts +18 -23
- package/runner/src/spawn-input.ts +2 -1
- package/runner/src/test-run-dedup.ts +59 -56
- package/scripts/cd-config.ts +8 -0
- package/scripts/gate-run-lease.ts +10 -7
- package/scripts/gate.sh +5 -1
- package/src/branch-land-notice.ts +93 -0
- package/src/branch-landed.ts +7 -76
- package/src/bus.ts +19 -20
- package/src/cd-deploy-notify.ts +30 -2
- 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/root-missing.ts +2 -7
- package/src/ci/transition-notify.ts +7 -39
- 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 +8 -2
- package/src/commands-db.ts +3 -3
- package/src/config-store-write.ts +13 -1
- package/src/config-store.ts +25 -14
- 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-search.ts +1 -15
- package/src/db/agents-async.ts +52 -5
- package/src/db/agents-write-ops.ts +12 -3
- package/src/db/agents.ts +81 -54
- package/src/db/ci-incidents-async.ts +5 -5
- package/src/db/ci-incidents-write-ops.ts +2 -2
- package/src/db/command-row.ts +10 -2
- package/src/db/commands-list-query.ts +2 -0
- package/src/db/commands-spawn-read.ts +1 -1
- package/src/db/config-store-write-ops.ts +7 -2
- package/src/db/continuation-archives-async.ts +5 -0
- package/src/db/continuation-archives-write-ops.ts +7 -0
- package/src/db/continuations.ts +2 -2
- 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/hosts-registration.ts +10 -2
- package/src/db/hosts.ts +9 -6
- package/src/db/inbox.ts +0 -14
- 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-lifecycle.ts +3 -4
- package/src/db/issue-refs-async.ts +20 -0
- package/src/db/issue-refs-write-ops.ts +29 -0
- package/src/db/issue-refs.ts +7 -8
- package/src/db/long-running-work.ts +2 -2
- package/src/db/main-connection-writes.ts +23 -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/mappers.ts +2 -14
- package/src/db/merge-lease.ts +1 -15
- package/src/db/migrations.ts +7 -15
- package/src/db/orchestrators.ts +4 -72
- package/src/db/pairs.ts +1 -13
- package/src/db/project-profile-instructions.ts +50 -0
- 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 +5 -0
- package/src/db/read-ops.ts +4 -0
- package/src/db/routing-policy.ts +2 -3
- package/src/db/schema.ts +9 -3
- package/src/db/spawn-delegation-state.ts +11 -4
- package/src/db/stats-async.ts +4 -3
- package/src/db/task-entity.ts +23 -2
- package/src/db/task-list.ts +3 -1
- package/src/db/tasks.ts +1 -17
- package/src/db/timer-ingress.ts +7 -1
- package/src/db/token-db-write-ops.ts +17 -0
- package/src/db/token-standing.ts +15 -11
- package/src/db/workflow-contact.ts +1 -1
- package/src/db/workflow-task-read-ops.ts +30 -0
- package/src/db/write-ops.ts +6 -0
- package/src/db/writer-gateway.ts +17 -11
- 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/host/disk-alert.ts +121 -0
- package/src/lifecycle-manager.ts +3 -2
- package/src/maintenance/cd-watcher.ts +3 -3
- package/src/maintenance/critical-job-watchdog.ts +16 -17
- package/src/maintenance/index.ts +1 -0
- package/src/maintenance/jobs.ts +3 -2
- package/src/maintenance/scheduler.ts +84 -128
- package/src/maintenance/stalled-delivery-pager.ts +6 -5
- package/src/maintenance/workspaces.ts +1 -1
- package/src/managed-policy.ts +31 -27
- package/src/mcp/index.ts +5 -2
- package/src/mcp/output-descriptions.ts +8 -8
- package/src/mcp/presentation.ts +4 -4
- package/src/mcp/project-profile-instructions.ts +32 -0
- package/src/mcp/tool-groups.ts +1 -1
- package/src/mcp/tools-spawn.ts +4 -3
- package/src/mcp-agent-action.ts +1 -2
- package/src/mcp-issue-ref-tools.ts +12 -11
- package/src/mcp-maintenance-tools.ts +2 -2
- package/src/mcp-profile-trust-tools.ts +4 -4
- package/src/mcp-provider-catalog.ts +2 -2
- package/src/mcp-task-tools.ts +11 -5
- package/src/mcp-team-template-tools.ts +3 -3
- package/src/mcp-workflow-tools.ts +10 -3
- package/src/notification-types.ts +2 -1
- package/src/operator-alarm.ts +26 -11
- package/src/project-instructions.ts +4 -0
- package/src/project-profile-instruction-text.ts +6 -0
- package/src/project-profile-instructions.ts +20 -0
- 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-config-store.ts +5 -4
- package/src/provider-secrets.test-fixture.ts +3 -3
- package/src/recipe-runner.ts +2 -2
- package/src/repo-config-source.ts +10 -4
- package/src/routes/agent-profiles.ts +6 -6
- package/src/routes/agents-spawn.ts +1 -1
- package/src/routes/agents.ts +6 -6
- package/src/routes/commands-listing.ts +4 -0
- package/src/routes/commands.ts +2 -2
- package/src/routes/continuation-archives.ts +2 -2
- package/src/routes/index.ts +10 -1
- package/src/routes/integrations.ts +24 -50
- package/src/routes/issue-refs.ts +7 -7
- package/src/routes/orchestrator-bootstrap.ts +1 -1
- package/src/routes/orchestrator-host-registration.ts +2 -2
- package/src/routes/orchestrator-host-utilization.ts +3 -1
- package/src/routes/orchestrator-proxy.ts +2 -2
- package/src/routes/orchestrator.ts +2 -2
- package/src/routes/project-profile-instructions.ts +27 -0
- package/src/routes/project-trust.ts +2 -2
- package/src/routes/provider-config.ts +6 -6
- package/src/routes/provider-quota-config.ts +2 -2
- package/src/routes/settings.ts +5 -5
- 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 +5 -5
- package/src/routes/teams-config.ts +2 -2
- package/src/routes/tokens.ts +12 -5
- package/src/routes/workflows.ts +20 -5
- package/src/routing-policy-normalize.ts +1 -2
- package/src/routing-step-defaults.ts +0 -2
- package/src/runner-token-mint-limit.ts +63 -0
- package/src/runtime-grant.ts +4 -2
- package/src/runtime-tokens.ts +39 -7
- package/src/security.ts +13 -20
- package/src/server-background.ts +1 -1
- package/src/server.ts +5 -2
- package/src/services/host-utilization.ts +23 -0
- package/src/services/idle-epics.ts +5 -6
- package/src/services/issue-lifecycle.ts +57 -61
- package/src/services/issue-refs.ts +9 -13
- package/src/services/kernel-timers-cutover-chaos-worker.ts +10 -7
- package/src/services/kernel-timers-ingress.ts +1 -1
- package/src/services/landed-ancestry.ts +19 -3
- package/src/services/memory-areas.ts +15 -51
- package/src/services/plan-ci-notice.ts +57 -0
- package/src/services/plan-ci-recovery.ts +2 -55
- package/src/services/plan-wake-digest.ts +1 -0
- package/src/services/profile-trust.ts +4 -3
- package/src/services/project-config-read.ts +70 -0
- package/src/services/project-profile-instructions.ts +54 -0
- package/src/services/provisioning-harness/budget-baseline.json +4 -4
- package/src/services/restart-spawn.ts +61 -49
- package/src/services/self-care-state.ts +2 -1
- package/src/services/self-effort.ts +5 -5
- package/src/services/send-message.ts +5 -1
- package/src/services/spawn-agent.ts +13 -2
- package/src/services/spawn-chain-inspector.ts +6 -13
- package/src/services/spawn-policy.ts +68 -0
- package/src/services/spawn-tree-cleanup.ts +2 -2
- package/src/services/task-dispatch.ts +3 -0
- package/src/services/task-state-reconcile.ts +6 -14
- package/src/services/team-templates.ts +9 -8
- package/src/services/transient-agent-reaper.ts +3 -1
- package/src/services/workflow-auto-start.ts +25 -13
- package/src/services/workflow-ci-main.ts +1 -1
- package/src/services/workflow-deferred-cleanup.ts +4 -2
- package/src/services/workflow-effect-driver.ts +2 -0
- package/src/services/workflow-effects.ts +18 -11
- package/src/services/workflow-land-notice.ts +10 -0
- package/src/services/workflow-pause-text.ts +43 -0
- package/src/services/workflow-reconcile.ts +13 -11
- package/src/services/workflow-run-view.ts +2 -0
- package/src/services/workflow-runs.ts +29 -13
- package/src/services/workflow-supervisor-state.ts +5 -0
- package/src/services/workflow-supervisor.ts +7 -3
- package/src/settings/registry.ts +1 -2
- package/src/spawn-command.ts +4 -4
- package/src/spawn-models.ts +10 -12
- package/src/spawn-placement.ts +1 -1
- package/src/spawn-targets.ts +1 -1
- package/src/startup-context-injection.ts +1 -0
- 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.ts +7 -6
- package/src/task-dispatch-live.ts +1 -1
- package/src/task-dispatcher.ts +1 -1
- package/src/teams-config-store.ts +4 -3
- package/src/token-db-write.ts +10 -0
- package/src/workspace-command-settle.ts +2 -1
- package/src/workspace-steward-wake.ts +2 -2
- 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/use-project-list-B-T2Bnnn.js +0 -2
- package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
- package/runner/src/gate-run-lease-probe.ts +0 -38
- package/src/db/claude-catalog-reconcile.ts +0 -27
- package/src/routing-model-aliases.ts +0 -21
|
@@ -70,6 +70,7 @@ export function renderPlanWakeDigest(agentId: string, now = Date.now()): string
|
|
|
70
70
|
do {
|
|
71
71
|
const page = listPlansByTeam(teamId, { limit: 8, cursor });
|
|
72
72
|
for (const summary of page.plans) {
|
|
73
|
+
if (!summary.nodeCount) continue;
|
|
73
74
|
const plan = getPlan(summary.id);
|
|
74
75
|
if (!plan) continue;
|
|
75
76
|
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,9 +39,9 @@ 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
|
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { hasScope, isRecord } from "@humwick/sdk";
|
|
3
|
+
import type { ProjectProfileInstructions } from "../types";
|
|
4
|
+
import { listAgentProfiles, resolveAgentProfileKey } from "../config-store";
|
|
5
|
+
import { getGateway } from "../db/gateway";
|
|
6
|
+
import { ValidationError } from "../db/connection";
|
|
7
|
+
import { promptActorFromContext, promptVersionNumber } from "./prompt-version-writer";
|
|
8
|
+
import type { AuthContext } from "./auth-context";
|
|
9
|
+
import { cleanString } from "../validation";
|
|
10
|
+
import { emitConfigChanged } from "../sse";
|
|
11
|
+
|
|
12
|
+
export async function projectProfileInstructionKey(projectId: string, profile: string) {
|
|
13
|
+
const canonical = resolveAgentProfileKey(profile);
|
|
14
|
+
if (!canonical) throw new ValidationError("profile not found");
|
|
15
|
+
if (!await getGateway().read("projects.get", { id: projectId })) throw new ValidationError("project not found");
|
|
16
|
+
return { projectId, profile: canonical };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function readProjectProfileInstructions(projectId: string, profile: string) {
|
|
20
|
+
return getGateway().read("projectProfileInstructions.get", await projectProfileInstructionKey(projectId, profile));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function projectProfileInstructionHistory(projectId: string, profile: string) {
|
|
24
|
+
return { versions: await getGateway().read("projectProfileInstructions.history", await projectProfileInstructionKey(projectId, profile)) };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function listProjectProfileInstructions(filter: { projectId?: string; profile?: string }) {
|
|
28
|
+
const gateway = getGateway();
|
|
29
|
+
const profile = filter.profile ? resolveAgentProfileKey(filter.profile) : undefined;
|
|
30
|
+
if (filter.profile && !profile) throw new ValidationError("profile not found");
|
|
31
|
+
if (filter.projectId && !await gateway.read("projects.get", { id: filter.projectId })) throw new ValidationError("project not found");
|
|
32
|
+
if (!filter.projectId && !profile) throw new ValidationError("projectId or profile required");
|
|
33
|
+
const stored = await gateway.read("projectProfileInstructions.list", { projectId: filter.projectId, profile });
|
|
34
|
+
const byKey = new Map(stored.map(entry => [JSON.stringify([entry.projectId, entry.profile]), entry]));
|
|
35
|
+
const entry = (projectId: string, profile: string): ProjectProfileInstructions => byKey.get(JSON.stringify([projectId, profile])) ?? { projectId, profile, template: "", version: 0, updatedAt: 0 };
|
|
36
|
+
return { instructions: filter.projectId
|
|
37
|
+
? listAgentProfiles().filter(item => !profile || item.key === profile).map(item => entry(filter.projectId!, item.key))
|
|
38
|
+
: (await gateway.read("projects.list", { includeArchived: true })).map(project => ({ ...entry(project.id, profile!), projectTitle: project.title, projectSlug: project.slug })) };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function mutateProjectProfileInstructions(ctx: AuthContext, projectId: string, profile: string, input: unknown, restore = false) {
|
|
42
|
+
if (ctx.actor.kind !== "system" && !hasScope(ctx.scopes, "agent:write")) throw new ValidationError("agent:write scope required");
|
|
43
|
+
const key = await projectProfileInstructionKey(projectId, profile);
|
|
44
|
+
if (!isRecord(input)) throw new ValidationError("JSON object body required");
|
|
45
|
+
if (!Number.isSafeInteger(input.expectedVersion) || (input.expectedVersion as number) < 0) throw new ValidationError("expectedVersion must be a non-negative integer");
|
|
46
|
+
const result = await getGateway().write("projectProfileInstructions.write", {
|
|
47
|
+
...key, expectedVersion: input.expectedVersion as number,
|
|
48
|
+
template: restore ? undefined : input.template as string,
|
|
49
|
+
restoreVersion: restore ? promptVersionNumber(input.version, "version") : undefined,
|
|
50
|
+
actor: promptActorFromContext(ctx), reason: cleanString(input.reason, "reason", { max: 2000 }),
|
|
51
|
+
}, { idempotencyKey: randomUUID() }) as unknown as ProjectProfileInstructions;
|
|
52
|
+
emitConfigChanged("project-profile-instructions", `${key.projectId}:${key.profile}`, result.version);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"unknown": 0
|
|
20
20
|
},
|
|
21
21
|
"mcp:relay-schemas": {
|
|
22
|
-
"residentKnown":
|
|
22
|
+
"residentKnown": 24574,
|
|
23
23
|
"onDemandAvailable": 0,
|
|
24
24
|
"unknown": 0
|
|
25
25
|
},
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"unknown": 0
|
|
115
115
|
},
|
|
116
116
|
"mcp:relay-schemas": {
|
|
117
|
-
"residentKnown":
|
|
117
|
+
"residentKnown": 24574,
|
|
118
118
|
"onDemandAvailable": 0,
|
|
119
119
|
"unknown": 0
|
|
120
120
|
},
|
|
@@ -364,11 +364,11 @@
|
|
|
364
364
|
"reviewer:codex": 11221,
|
|
365
365
|
"sec-ops:claude": 11610,
|
|
366
366
|
"sec-ops:codex": 10644,
|
|
367
|
-
"ops-assistant:claude":
|
|
367
|
+
"ops-assistant:claude": 25390,
|
|
368
368
|
"ops-assistant:codex": 25562,
|
|
369
369
|
"sub-coordinator:claude": 20137,
|
|
370
370
|
"sub-coordinator:codex": 20392,
|
|
371
|
-
"coordinator:claude":
|
|
371
|
+
"coordinator:claude": 26584,
|
|
372
372
|
"coordinator:codex": 26622,
|
|
373
373
|
"isolated-research:claude": 2852,
|
|
374
374
|
"isolated-research:codex": 2790,
|
|
@@ -16,7 +16,7 @@ import { resolveWhoamiRole } from "../mcp/identity-projection";
|
|
|
16
16
|
import { listManagedOrchestratorsForAgent } from "../orchestrator-lookup";
|
|
17
17
|
import { applyDefaultSharedMcp } from "../shared-mcp";
|
|
18
18
|
import { buildSpawnCommand, generateSpawnRequestId, resolveSpawnModelParams, resolveSpawnModelParamsAsync } from "../spawn-command";
|
|
19
|
-
import { SUCCESSOR_LAUNCH, runnerRuntimeTokenEnv } from "../runtime-tokens";
|
|
19
|
+
import { SUCCESSOR_LAUNCH, runnerRuntimeTokenEnv, runnerRuntimeTokenEnvAsync, type RunnerRuntimeTokenInput } from "../runtime-tokens";
|
|
20
20
|
import { restartEffortState } from "./self-effort";
|
|
21
21
|
// #2033 — from isolated-workspace-placement.ts, NOT ./spawn-identity: that module also exports
|
|
22
22
|
// buildProspectiveSpawnIdentity, which imports mcp/identity.ts → self-resume.ts → restart-spawn.ts,
|
|
@@ -27,7 +27,7 @@ import { restartInstructionParamsForAgent, restartInstructionParamsForAgentAsync
|
|
|
27
27
|
import { launchedProjectRole, projectRoleRestartError, refuseSyncProjectRoleRestart, restartProjectRole } from "./restart-project-role";
|
|
28
28
|
import { authContextFromSystem } from "./auth-context";
|
|
29
29
|
import { markManagedAgentRunning } from "./managed-running";
|
|
30
|
-
import type { AgentCard, AgentProfile, Command, Orchestrator, SpawnApprovalMode } from "../types";
|
|
30
|
+
import type { AgentCard, AgentProfile, SpawnPolicy, Command, Orchestrator, SpawnApprovalMode } from "../types";
|
|
31
31
|
|
|
32
32
|
export type SelfRestartReason = "upgrade" | "token-remint" | "manual" | "reset-unconfirmed";
|
|
33
33
|
type RestartOptions = { resumeId?: string; continuation?: string; generation?: number; reason?: string };
|
|
@@ -116,30 +116,9 @@ function buildRestartSpawnParamsForAgent(
|
|
|
116
116
|
requestedBy,
|
|
117
117
|
// Override the policy builder's normal mint so stable team/project bindings are also
|
|
118
118
|
// carried by the fresh token, not merely preserved incidentally on the agent row.
|
|
119
|
-
env: runnerRuntimeTokenEnv(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
cwd: policy.value.cwd,
|
|
123
|
-
provider: policy.value.provider,
|
|
124
|
-
label: policy.value.label,
|
|
125
|
-
policyName: policy.value.name,
|
|
126
|
-
spawnRequestId: requestId,
|
|
127
|
-
createdBy: requestedBy,
|
|
128
|
-
profile: policy.value.profile || undefined,
|
|
129
|
-
// #2245 — the successor's posture comes from the POLICY (server config, unforgeable), the
|
|
130
|
-
// same value `buildManagedSpawnParams` launches it with; stamp it into the signed constraints.
|
|
131
|
-
approvalMode: policy.value.permissionMode,
|
|
132
|
-
...(agent.teamId ? { teamId: agent.teamId } : {}),
|
|
133
|
-
...(projectId ? { projectId } : {}),
|
|
134
|
-
...([...stewardExtraCwdPrefixes, ...isolatedExtraCwdPrefixes].length
|
|
135
|
-
? { extraCwdPrefixes: [...stewardExtraCwdPrefixes, ...isolatedExtraCwdPrefixes] }
|
|
136
|
-
: {}),
|
|
137
|
-
}),
|
|
138
|
-
...(opts.continuation ? { prompt: opts.continuation } : {}),
|
|
139
|
-
...(restartResumeWorkspace ? { resumeWorkspace: restartResumeWorkspace } : {}),
|
|
140
|
-
// F5 — carry the self-restart generation marker on BOTH successor spawns (policy and
|
|
141
|
-
// dashboard/non-policy), so the audit lineage is symmetric regardless of branch.
|
|
142
|
-
...(opts.generation ? { extra: { selfRestart: { generation: opts.generation, reason: opts.reason } } } : {}),
|
|
119
|
+
env: runnerRuntimeTokenEnv(managedRestartTokenInput(agent, policy.value, requestId, requestedBy, projectId,
|
|
120
|
+
[...stewardExtraCwdPrefixes, ...isolatedExtraCwdPrefixes])),
|
|
121
|
+
...managedRestartOptions(opts, restartResumeWorkspace),
|
|
143
122
|
};
|
|
144
123
|
return opts.resumeId ? withResumeParams(params, opts.resumeId, agent.id) : params;
|
|
145
124
|
}
|
|
@@ -160,7 +139,7 @@ function buildRestartSpawnParamsForAgent(
|
|
|
160
139
|
const resolvedProfile = withResolvedProvisioning(profileName ? getAgentProfile(profileName)?.value : undefined, provider);
|
|
161
140
|
const agentProfile = resolvedProfile ? applyDefaultSharedMcp(resolvedProfile) : undefined;
|
|
162
141
|
const workspaceMode = stringValue(agent.meta?.workspaceMode) ?? "inherit";
|
|
163
|
-
const resolvedModel = resolveSpawnModelParams(provider, model, effort, { modelSource: "runtime"
|
|
142
|
+
const resolvedModel = resolveSpawnModelParams(provider, model, effort, { modelSource: "runtime" });
|
|
164
143
|
const projectedInstructions = restartInstructionParamsForAgent(agent, { spawnRequestId: predecessorSpawnRequestId, cwd }) ?? {};
|
|
165
144
|
// #1598 — canonicalize so a worktree/subdir cwd binds to its owning checkout's project.
|
|
166
145
|
const projectId = resolveProjectForCanonicalCwd(cwd).project?.id;
|
|
@@ -175,7 +154,7 @@ function buildRestartSpawnParamsForAgent(
|
|
|
175
154
|
cwd,
|
|
176
155
|
orchestrator.baseDir,
|
|
177
156
|
);
|
|
178
|
-
|
|
157
|
+
const options = {
|
|
179
158
|
provider,
|
|
180
159
|
modelParams: resolvedModel,
|
|
181
160
|
cwd,
|
|
@@ -185,7 +164,10 @@ function buildRestartSpawnParamsForAgent(
|
|
|
185
164
|
policyName: policyName || undefined,
|
|
186
165
|
spawnRequestId: requestId,
|
|
187
166
|
requestedBy,
|
|
188
|
-
}
|
|
167
|
+
};
|
|
168
|
+
const tokenContext = { orchestratorId: orchestrator.id, projectId, extraCwdPrefixes: stewardExtraCwdPrefixes };
|
|
169
|
+
return buildRestartSpawnCommand(agent, predecessorSpawnRequestId, agentProfile, projectedInstructions, opts, options, tokenContext,
|
|
170
|
+
runnerRuntimeTokenEnv(restartTokenInput(agent, options, tokenContext)));
|
|
189
171
|
}
|
|
190
172
|
|
|
191
173
|
/** Worker-safe restart command construction used by HTTP/orchestrator/self-restart flows. */
|
|
@@ -233,14 +215,8 @@ async function buildRestartSpawnParamsForAgentAsync(
|
|
|
233
215
|
const params = {
|
|
234
216
|
...await buildManagedSpawnParamsAsync(relaunchPolicy(policy.value, relaunch.effort), requestId, { createdBy: requestedBy, authority: SUCCESSOR_LAUNCH, identityAgentId: agent.id, gitRepoRoot }),
|
|
235
217
|
...relaunch.carried, agentId: agent.id, requestedBy,
|
|
236
|
-
env:
|
|
237
|
-
|
|
238
|
-
createdBy: requestedBy, profile: policy.value.profile || undefined, ...(agent.teamId ? { teamId: agent.teamId } : {}),
|
|
239
|
-
approvalMode: policy.value.permissionMode,
|
|
240
|
-
...(projectId ? { projectId } : {}), ...(combinedExtraCwdPrefixes.length ? { extraCwdPrefixes: combinedExtraCwdPrefixes } : {}), }),
|
|
241
|
-
...(opts.continuation ? { prompt: opts.continuation } : {}),
|
|
242
|
-
...(restartResumeWorkspace ? { resumeWorkspace: restartResumeWorkspace } : {}),
|
|
243
|
-
...(opts.generation ? { extra: { selfRestart: { generation: opts.generation, reason: opts.reason } } } : {}),
|
|
218
|
+
env: await runnerRuntimeTokenEnvAsync(managedRestartTokenInput(agent, policy.value, requestId, requestedBy, projectId, combinedExtraCwdPrefixes)),
|
|
219
|
+
...managedRestartOptions(opts, restartResumeWorkspace),
|
|
244
220
|
};
|
|
245
221
|
return opts.resumeId ? withResumeParams(params, opts.resumeId, agent.id) : params;
|
|
246
222
|
}
|
|
@@ -257,15 +233,55 @@ async function buildRestartSpawnParamsForAgentAsync(
|
|
|
257
233
|
const profileName = role ? role.profileName : stringValue(agent.meta?.profile);
|
|
258
234
|
const resolvedProfile = role ? undefined : await withResolvedProvisioningAsync(profileName ? getAgentProfile(profileName)?.value : undefined, provider);
|
|
259
235
|
const agentProfile = role?.agentProfile ?? (resolvedProfile ? applyDefaultSharedMcp(resolvedProfile) : undefined);
|
|
260
|
-
const resolvedModel = await resolveSpawnModelParamsAsync(provider, model, effort, { modelSource: "runtime"
|
|
236
|
+
const resolvedModel = await resolveSpawnModelParamsAsync(provider, model, effort, { modelSource: "runtime" });
|
|
261
237
|
const projectedInstructions = await restartInstructionParamsForAgentAsync(agent, { spawnRequestId: predecessorSpawnRequestId, cwd, ...(role ? { profile: role.agentProfile } : {}) }) ?? {};
|
|
262
238
|
const projectId = resolveProjectForCanonicalCwd(cwd).project?.id;
|
|
263
239
|
const stewardExtraCwdPrefixes = stewardWorktreeCwdPrefixes(isProvenStewardAgent(agent.id, policyName), cwd, orchestrator.baseDir);
|
|
264
|
-
|
|
240
|
+
const options = {
|
|
265
241
|
provider, modelParams: resolvedModel, cwd, workspaceMode, profile: profileName || undefined,
|
|
266
242
|
...relaunch.carried, ...role?.spawn, policyName: policyName || undefined, spawnRequestId: requestId,
|
|
267
243
|
requestedBy,
|
|
268
|
-
}
|
|
244
|
+
};
|
|
245
|
+
const tokenContext = { orchestratorId: orchestrator.id, projectId, extraCwdPrefixes: stewardExtraCwdPrefixes };
|
|
246
|
+
return buildRestartSpawnCommand(agent, predecessorSpawnRequestId, agentProfile, projectedInstructions, opts, options, tokenContext,
|
|
247
|
+
await runnerRuntimeTokenEnvAsync(restartTokenInput(agent, options, tokenContext)));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function managedRestartOptions(opts: RestartOptions, restartResumeWorkspace: ReturnType<typeof resumeWorkspaceForRestart>) {
|
|
251
|
+
return {
|
|
252
|
+
...(opts.continuation ? { prompt: opts.continuation } : {}),
|
|
253
|
+
...(restartResumeWorkspace ? { resumeWorkspace: restartResumeWorkspace } : {}),
|
|
254
|
+
// F5 — carry the self-restart generation marker on BOTH successor spawns (policy and
|
|
255
|
+
// dashboard/non-policy), so the audit lineage is symmetric regardless of branch.
|
|
256
|
+
...(opts.generation ? { extra: { selfRestart: { generation: opts.generation, reason: opts.reason } } } : {}),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function managedRestartTokenInput(agent: AgentCard, policy: SpawnPolicy, requestId: string, requestedBy: string, projectId: string | undefined, extraCwdPrefixes: string[]): RunnerRuntimeTokenInput {
|
|
261
|
+
return {
|
|
262
|
+
authority: SUCCESSOR_LAUNCH, agentId: agent.id, orchestratorId: policy.orchestratorId,
|
|
263
|
+
cwd: policy.cwd, provider: policy.provider, label: policy.label, policyName: policy.name,
|
|
264
|
+
spawnRequestId: requestId, createdBy: requestedBy, profile: policy.profile || undefined,
|
|
265
|
+
// #2245: both successor paths stamp the policy's current posture into signed constraints.
|
|
266
|
+
approvalMode: policy.permissionMode,
|
|
267
|
+
...(agent.teamId ? { teamId: agent.teamId } : {}),
|
|
268
|
+
...(projectId ? { projectId } : {}),
|
|
269
|
+
...(extraCwdPrefixes.length ? { extraCwdPrefixes } : {}),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
type RestartTokenContext = Pick<RunnerRuntimeTokenInput, "orchestratorId" | "projectId" | "extraCwdPrefixes">;
|
|
274
|
+
const restartApprovalMode = (agent: AgentCard): SpawnApprovalMode => (stringValue(agent.meta?.approvalMode) as SpawnApprovalMode | undefined) ?? "guarded";
|
|
275
|
+
const restartLabel = (agent: AgentCard): string | undefined => (stringValue(agent.meta?.label) ?? agent.label) || undefined;
|
|
276
|
+
|
|
277
|
+
/** The successor token a non-policy restart carries; the sync twin and the writer-op path mint the same input. */
|
|
278
|
+
function restartTokenInput(agent: AgentCard, options: Omit<Parameters<typeof buildSpawnCommand>[0], "env">, tokenContext: RestartTokenContext): RunnerRuntimeTokenInput {
|
|
279
|
+
return { ...tokenContext, authority: SUCCESSOR_LAUNCH,
|
|
280
|
+
agentId: agent.id, cwd: options.cwd, provider: options.provider, label: restartLabel(agent),
|
|
281
|
+
policyName: options.policyName, spawnRequestId: options.spawnRequestId,
|
|
282
|
+
createdBy: options.requestedBy, profile: options.profile, approvalMode: restartApprovalMode(agent),
|
|
283
|
+
...(agent.teamId ? { teamId: agent.teamId } : {}),
|
|
284
|
+
};
|
|
269
285
|
}
|
|
270
286
|
|
|
271
287
|
function buildRestartSpawnCommand(
|
|
@@ -275,25 +291,21 @@ function buildRestartSpawnCommand(
|
|
|
275
291
|
projectedInstructions: Record<string, unknown>,
|
|
276
292
|
opts: RestartOptions,
|
|
277
293
|
options: Omit<Parameters<typeof buildSpawnCommand>[0], "env">,
|
|
278
|
-
tokenContext:
|
|
294
|
+
tokenContext: RestartTokenContext,
|
|
295
|
+
env: Record<string, string>,
|
|
279
296
|
): Record<string, unknown> {
|
|
280
297
|
const memorySeam = parseMemorySeam(projectedInstructions.memorySeam);
|
|
281
298
|
const resumeWorkspace = resumeWorkspaceForRestart(agent);
|
|
282
299
|
const providerArgs = metaStringArray(agent.meta, "providerArgs");
|
|
283
|
-
const approvalMode = (
|
|
284
|
-
const label = (
|
|
300
|
+
const approvalMode = restartApprovalMode(agent);
|
|
301
|
+
const label = restartLabel(agent);
|
|
285
302
|
const params = buildSpawnCommand({
|
|
286
303
|
...options,
|
|
287
304
|
orchestratorId: tokenContext.orchestratorId,
|
|
288
305
|
headless: true, requestedAt: Date.now(),
|
|
289
306
|
...(opts.continuation ? { prompt: opts.continuation } : {}),
|
|
290
307
|
...(opts.generation ? { extra: { selfRestart: { generation: opts.generation, reason: opts.reason } } } : {}),
|
|
291
|
-
env
|
|
292
|
-
agentId: agent.id, cwd: options.cwd, provider: options.provider, label,
|
|
293
|
-
policyName: options.policyName, spawnRequestId: options.spawnRequestId,
|
|
294
|
-
createdBy: options.requestedBy, profile: options.profile, approvalMode,
|
|
295
|
-
...(agent.teamId ? { teamId: agent.teamId } : {}),
|
|
296
|
-
}),
|
|
308
|
+
env,
|
|
297
309
|
agentId: agent.id, tags: agent.tags, systemTags: agent.systemTags, capabilities: agent.capabilities,
|
|
298
310
|
label,
|
|
299
311
|
approvalMode, permissionMode: approvalMode,
|
|
@@ -2,9 +2,10 @@ import { renderLiveRunsSection } from "../live-runs-section";
|
|
|
2
2
|
import { renderOpenDecisionsSection } from "../operator-decisions-section";
|
|
3
3
|
import { renderIdleEpicsSection } from "./idle-epics";
|
|
4
4
|
import { renderPlanWakeDigest } from "./plan-wake-digest";
|
|
5
|
+
import { renderPausedRunsSection } from "./workflow-pause-text";
|
|
5
6
|
|
|
6
7
|
/** Stored live state survives every self-care boundary; tracker refresh must never block a wake. */
|
|
7
8
|
export function renderSelfCareState(agentId: string): string {
|
|
8
9
|
return [renderLiveRunsSection(agentId), renderOpenDecisionsSection(agentId),
|
|
9
|
-
renderIdleEpicsSection(agentId, [], false), renderPlanWakeDigest(agentId)].filter(Boolean).join("\n\n");
|
|
10
|
+
renderIdleEpicsSection(agentId, [], false), renderPlanWakeDigest(agentId), renderPausedRunsSection(agentId)].filter(Boolean).join("\n\n");
|
|
10
11
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { stringValue, type SpawnProvider } from "@humwick/sdk";
|
|
2
|
-
import {
|
|
2
|
+
import { findProviderCatalog, findProviderCatalogModel, type ProviderCatalogEntry } from "@humwick/sdk/provider-catalog";
|
|
3
3
|
import { findConfirmedEffortSwitch, findLaunchEffort, type LaunchEffort } from "../db/commands-effort-read";
|
|
4
4
|
import { getAgentEffortState } from "../db/agent-effort-state";
|
|
5
5
|
import { SELF_EFFORT_BAND, getSelfEffortCeiling, type SelfEffortIdentity } from "../db/self-effort-permissions";
|
|
@@ -44,7 +44,7 @@ export function resolveSpawnSelfEffort(
|
|
|
44
44
|
if (!(base ?? known?.defaultEffort)) throw new ValidationError("selfEffort without selfEffortCeiling needs a base effort: set effort, or pass selfEffortCeiling");
|
|
45
45
|
return { band: true };
|
|
46
46
|
}
|
|
47
|
-
const levels = known?.efforts ??
|
|
47
|
+
const levels = known?.efforts ?? [];
|
|
48
48
|
if (!levels.includes(ceiling)) {
|
|
49
49
|
throw new ValidationError(`selfEffortCeiling ${ceiling} is not an effort ${known ? `${known.provider} model ${known.alias}` : provider} offers (${levels.join(", ")})`);
|
|
50
50
|
}
|
|
@@ -90,7 +90,7 @@ export function selfEffortBase(agent: AgentCard): string | undefined {
|
|
|
90
90
|
|
|
91
91
|
/** One step down and one step up from `base` on `ladder`, clamped at both ends. */
|
|
92
92
|
export function selfEffortBand(base: string, ladder: readonly string[]): { floor: string; ceiling: string } {
|
|
93
|
-
const levels = ladder.includes(base) ? ladder :
|
|
93
|
+
const levels = ladder.includes(base) ? ladder : [base];
|
|
94
94
|
const at = levels.indexOf(base);
|
|
95
95
|
return { floor: levels[Math.max(0, at - 1)]!, ceiling: levels[Math.min(levels.length - 1, at + 1)]! };
|
|
96
96
|
}
|
|
@@ -119,7 +119,7 @@ export function selfEffortPolicyFor(agent: AgentCard, grant: SelfEffortGrant, mo
|
|
|
119
119
|
if ("ceiling" in grant) return { ceiling: grant.ceiling };
|
|
120
120
|
const base = selfEffortBase(agent);
|
|
121
121
|
if (!base) throw new ValidationError("your self-change band has no base effort; ask your coordinator to set your effort");
|
|
122
|
-
return { band: true, base, ...selfEffortBand(base, modelEfforts ?? agentCatalogModel(agent)?.efforts ??
|
|
122
|
+
return { band: true, base, ...selfEffortBand(base, modelEfforts ?? agentCatalogModel(agent)?.efforts ?? [base]) };
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/** #2950 H3 — a restart successor launches at the agent's desired effort (#2984: applied or still pending),
|
|
@@ -138,7 +138,7 @@ export function restartEffortState(agent: AgentCard): { effort?: string; carried
|
|
|
138
138
|
export function assertSelfEffortAllowed(agent: AgentCard, level: string, modelEfforts: readonly string[] | undefined): SelfEffortPolicy {
|
|
139
139
|
const policy = spawnSelfEffortPolicy(agent, modelEfforts);
|
|
140
140
|
if (!policy) throw new ValidationError("selfEffort is not enabled for you, so you cannot change your own effort; ask your coordinator");
|
|
141
|
-
const ladder = modelEfforts
|
|
141
|
+
const ladder = modelEfforts ?? agentCatalogModel(agent)?.efforts ?? [];
|
|
142
142
|
const at = ladder.indexOf(level);
|
|
143
143
|
if (at < 0 || at > ladder.indexOf(policy.ceiling)) {
|
|
144
144
|
throw new ValidationError(policy.band
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
import { recentFinalResponseCaptureIds } from "../db/lineage-startup-captures";
|
|
46
46
|
import { yieldToEventLoop } from "../event-loop-yield";
|
|
47
47
|
import { markAgentWorkFinal } from "./work-finality";
|
|
48
|
+
import { agentProviderState } from "../provider-state";
|
|
48
49
|
import { planSend, type DeliveryReceipt } from "../agent-ref";
|
|
49
50
|
import { receiptWithChannelSuppression } from "./channel-suppression-receipt";
|
|
50
51
|
import { emitMessageDeliveryUpdated, emitMessageQueued, emitNewMessages } from "../sse";
|
|
@@ -203,7 +204,8 @@ function resolveSendTarget(input: SendMessageInput, from: string): DeliveryRecei
|
|
|
203
204
|
}
|
|
204
205
|
// excludeId: a bare ref must never resolve back to its own author — that self-loop silently
|
|
205
206
|
// swallows the message (the reddit-briefing → telegram bridge break, #290).
|
|
206
|
-
const
|
|
207
|
+
const agents = listAgents();
|
|
208
|
+
const plan = planSend(input.to, agents, { excludeId: from });
|
|
207
209
|
// Ambiguous is a real "can't decide" → reject on every transport (categorically unlike
|
|
208
210
|
// not_found, which stores). HTTP → 409, MCP → invalid-params.
|
|
209
211
|
if (plan.kind === "ambiguous") throw new AmbiguousTargetError(plan.message);
|
|
@@ -215,6 +217,8 @@ function resolveSendTarget(input: SendMessageInput, from: string): DeliveryRecei
|
|
|
215
217
|
// direct (incl. a single OFFLINE match — receipt already carries reason "recipient offline")
|
|
216
218
|
// / fanout / passthrough: adopt the canonical (possibly rewritten) id + the receipt.
|
|
217
219
|
input.to = plan.to;
|
|
220
|
+
const providerState = agentProviderState(agents.find(agent => agent.id === plan.to));
|
|
221
|
+
if (providerState?.reason === "providerSetupRequired") throw new ValidationError(providerState.message ?? providerState.recommendedAction ?? "Provider setup required; restart the runner after completing setup.");
|
|
218
222
|
return plan.receipt;
|
|
219
223
|
}
|
|
220
224
|
|
|
@@ -44,7 +44,7 @@ import { emitCommandEvent } from "../command-events";
|
|
|
44
44
|
import { redactCommandSecrets } from "../command-secrets";
|
|
45
45
|
import { buildSpawnCommand, generateSpawnRequestId } from "../spawn-command"; import { systemTagsForSpawn } from "../agent-system-tags";
|
|
46
46
|
import { resolveSpawnLandBlocked } from "../land-block";
|
|
47
|
-
import {
|
|
47
|
+
import { runnerRuntimeTokenEnvAsync } from "../runtime-tokens";
|
|
48
48
|
import { liveSpawnQuota } from "../spawn-quota";
|
|
49
49
|
import { resolveCanonicalHost } from "../host-identity";
|
|
50
50
|
import { resolveSpawnHostAnchor } from "../spawn-targets";
|
|
@@ -59,6 +59,7 @@ import { isolatedSpawnGitRepoError, resolveSpawnRepoRoot } from "./spawn-repo-pr
|
|
|
59
59
|
import { autoSeedProjectForCwdAsync } from "./project"; import { applyProjectCapabilityGates } from "../project-trust";
|
|
60
60
|
import { assertProjectRoleMcpCwd, assertProjectRoleMcpTrusted, projectRoleProfile, projectRoleProvenance, projectRoleSpawnDefaults, withRoleProfile } from "../project-roles";
|
|
61
61
|
import { spawnWarnings } from "./spawn-warnings";
|
|
62
|
+
import { enforceSpawnPolicy, spawnerKind, spawnPolicyTask, type AppliedSpawnPolicy } from "./spawn-policy";
|
|
62
63
|
import { resolveSpawnProjectRole } from "./spawn-project-role";
|
|
63
64
|
import { profileProviderPin, resolveSpawnLaunch } from "./spawn-launch";
|
|
64
65
|
import { hydrateTaskContext, projectTaskHydration } from "./task-context-hydration";
|
|
@@ -210,6 +211,8 @@ export interface SpawnAgentInput extends SelfEffortSpawnInput {
|
|
|
210
211
|
roleSnapshot?: import("../project-roles").ProjectRole;
|
|
211
212
|
workflowCaller?: WorkflowSpawnQuota;
|
|
212
213
|
roleSha?: string; workflowRunId?: string; roleProfile?: string; taskRepoCwd?: string; roleHost?: string;
|
|
214
|
+
/** #3736 — the workflows of the run tree spawning this step, for a spawn-policy `require.workflow`. Service-only. */
|
|
215
|
+
workflowNames?: string[];
|
|
213
216
|
prompt?: string;
|
|
214
217
|
systemPromptAppend?: string;
|
|
215
218
|
/**
|
|
@@ -324,6 +327,8 @@ export interface SpawnAgentResult {
|
|
|
324
327
|
dispatchDecision?: Awaited<ReturnType<typeof dispatchTaskAsync>>;
|
|
325
328
|
/** #3043 — the spawn went ahead, but the caller should know (a role read from a stale default branch). */
|
|
326
329
|
warnings?: string[];
|
|
330
|
+
/** #3736 — the project spawn-policy rules that applied to this spawn. */
|
|
331
|
+
spawnPolicy?: AppliedSpawnPolicy;
|
|
327
332
|
}
|
|
328
333
|
|
|
329
334
|
/** Reject when a component token's signed resource constraints disallow the target (#323). */
|
|
@@ -428,6 +433,11 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
428
433
|
});
|
|
429
434
|
|
|
430
435
|
assertOrchestratorSupportsLaunchMode(orchestrator, launchMode, input.providerArgs);
|
|
436
|
+
// #3736 — the project's spawn policy, before any side effect: a refusal names the rule, the allowed set and the hint.
|
|
437
|
+
const spawnPolicy = await enforceSpawnPolicy(
|
|
438
|
+
{ projectId: lazyRoot?.projectId ?? resolveProjectForCwd(resolvedCwd)?.id, ...(lazyRoot ? {} : { checkout: { cwd: resolvedCwd, orchestratorId: orchestrator.id } }) },
|
|
439
|
+
{ spawner: spawnerKind(ctx, input, caller), task: spawnPolicyTask(linkedTask), subject: { role: projectRole?.name, profile: profileName, workflows: input.workflowNames } },
|
|
440
|
+
);
|
|
431
441
|
|
|
432
442
|
// Resolve + validate the named agent profile server-side (was HTTP-only; the MCP path passed
|
|
433
443
|
// the name through unvalidated). Omitted profile uses Relay's spawn default so coordinator
|
|
@@ -703,7 +713,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
703
713
|
// Child runner token. `agentInitiated` (set whenever an agent is the caller) forces a
|
|
704
714
|
// non-spawn-capable child (no grandchildren); `spawnedBy` stamps authoritative lineage the
|
|
705
715
|
// child can't forge (it registers with spawnedBy = caller, read from the signed token).
|
|
706
|
-
const env = { ...callerEnv, ...
|
|
716
|
+
const env = { ...callerEnv, ...await runnerRuntimeTokenEnvAsync({
|
|
707
717
|
agentId: targetAgentId,
|
|
708
718
|
orchestratorId: orchestrator.id,
|
|
709
719
|
cwd: resolvedCwd,
|
|
@@ -900,6 +910,7 @@ export async function spawnAgent(input: SpawnAgentInput, ctx: AuthContext): Prom
|
|
|
900
910
|
...(autoScaffoldedTask ? { task: autoScaffoldedTask } : {}),
|
|
901
911
|
...(taskDispatchDecision ? { dispatchDecision: taskDispatchDecision } : {}),
|
|
902
912
|
...(warnings.length ? { warnings } : {}),
|
|
913
|
+
...(spawnPolicy ? { spawnPolicy } : {}),
|
|
903
914
|
};
|
|
904
915
|
}
|
|
905
916
|
|
|
@@ -24,7 +24,7 @@ import { join } from "node:path";
|
|
|
24
24
|
import type { LaunchMode, SpawnProvider } from "@humwick/sdk";
|
|
25
25
|
import { withResolvedProvisioning } from "../db";
|
|
26
26
|
import { getAgentProfile } from "../config-store";
|
|
27
|
-
import { buildSpawnCommand } from "../spawn-command";
|
|
27
|
+
import { buildSpawnCommand, resolveSpawnModelParams } from "../spawn-command";
|
|
28
28
|
import { spawnOptionsFromControl } from "../../orchestrator/src/control";
|
|
29
29
|
import type { SpawnOptions } from "../../orchestrator/src/spawn/types";
|
|
30
30
|
import { buildEnv, buildRunnerCommand } from "../../orchestrator/src/spawn/command";
|
|
@@ -139,18 +139,10 @@ export function prepareSpawnChain(opts: SpawnChainRequest, observe?: SpawnChainP
|
|
|
139
139
|
prompt: opts.spawn?.prompt,
|
|
140
140
|
systemPromptAppend: opts.spawn?.systemPromptAppend,
|
|
141
141
|
headless: opts.spawn?.headless ?? true,
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
...(opts.spawn.effort ? { effort: opts.spawn.effort } : {}),
|
|
147
|
-
// #2595 — window passes through the same payload field production threads.
|
|
148
|
-
...(typeof opts.spawn.contextWindowTokens === "number" && Number.isSafeInteger(opts.spawn.contextWindowTokens) && opts.spawn.contextWindowTokens > 0
|
|
149
|
-
? { contextWindowTokens: opts.spawn.contextWindowTokens }
|
|
150
|
-
: {}),
|
|
151
|
-
},
|
|
152
|
-
}
|
|
153
|
-
: {}),
|
|
142
|
+
modelParams: {
|
|
143
|
+
...resolveSpawnModelParams(provider, opts.spawn?.model, opts.spawn?.effort),
|
|
144
|
+
...(opts.spawn?.contextWindowTokens !== undefined ? { contextWindowTokens: opts.spawn.contextWindowTokens } : {}),
|
|
145
|
+
},
|
|
154
146
|
} as Parameters<typeof buildSpawnCommand>[0]);
|
|
155
147
|
|
|
156
148
|
return prepareCommandChain(cmdParams, opts, observe);
|
|
@@ -216,6 +208,7 @@ export function prepareCommandChain(
|
|
|
216
208
|
provider: cli.provider,
|
|
217
209
|
...(cli.model ? { model: cli.model } : {}),
|
|
218
210
|
...(cli.effort ? { effort: cli.effort } : {}),
|
|
211
|
+
...(cli.modelRecord ? { modelRecord: cli.modelRecord } : {}),
|
|
219
212
|
// #2595 — the real runner CLI carries the window as a flag; carry it through the same seam.
|
|
220
213
|
...(cli.contextWindowTokens !== undefined ? { contextWindowTokens: cli.contextWindowTokens } : {}),
|
|
221
214
|
runnerId: "inspector",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// #3736 — the one spawn-policy check. spawnAgent runs it for every spawn (relay_spawn_agent,
|
|
2
|
+
// relay_task_dispatch, POST /api/agents/spawn, workflow steps, sub-coordinators); the workflow
|
|
3
|
+
// auto-start asks it which workflow a Task's work runs through. A project without the file, or with
|
|
4
|
+
// an invalid or unreadable one, is not restricted: stored config never fails a spawn.
|
|
5
|
+
import { stringValue, type AgentCard } from "@humwick/sdk";
|
|
6
|
+
import {
|
|
7
|
+
matchSpawnPolicy, SPAWN_POLICY_FILE, spawnPolicyAtCommit, spawnPolicyRefusal, spawnPolicyWorkflow,
|
|
8
|
+
type SpawnerKind, type SpawnPolicy, type SpawnPolicySubject, type SpawnPolicyTask,
|
|
9
|
+
} from "@humwick/sdk/spawn-policy";
|
|
10
|
+
import { ValidationError } from "../db";
|
|
11
|
+
import type { AuthContext } from "./auth-context";
|
|
12
|
+
import { readProjectConfigFirst, type ProjectCheckout } from "./project-config-read";
|
|
13
|
+
|
|
14
|
+
/** Where the policy is read: the spawn's own checkout first, then the project's registered roots. */
|
|
15
|
+
export interface SpawnPolicyWhere {
|
|
16
|
+
projectId?: string;
|
|
17
|
+
checkout?: ProjectCheckout;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** The rules that applied, for the caller's receipt. */
|
|
21
|
+
export interface AppliedSpawnPolicy {
|
|
22
|
+
file: string;
|
|
23
|
+
ref: string;
|
|
24
|
+
sha: string;
|
|
25
|
+
rules: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface LoadedSpawnPolicy {
|
|
29
|
+
policy: SpawnPolicy;
|
|
30
|
+
ref: string;
|
|
31
|
+
sha: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function loadSpawnPolicy(where: SpawnPolicyWhere): Promise<LoadedSpawnPolicy | undefined> {
|
|
35
|
+
if (!where.projectId) return undefined;
|
|
36
|
+
const { lookup } = await readProjectConfigFirst(where.projectId, where.checkout ? [where.checkout] : [], SPAWN_POLICY_FILE, spawnPolicyAtCommit, "spawns are not restricted until it is fixed");
|
|
37
|
+
return lookup?.status === "found" ? { policy: lookup.config, ref: lookup.ref, sha: lookup.sha } : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A workflow run's step, a sub-coordinator, any other agent, or a caller with no agent (dashboard, operator). */
|
|
41
|
+
export function spawnerKind(ctx: AuthContext, input: { workflowRunId?: string }, caller: AgentCard | undefined): SpawnerKind {
|
|
42
|
+
if (ctx.actor.kind === "system" && input.workflowRunId) return "workflow";
|
|
43
|
+
if (!caller) return "operator";
|
|
44
|
+
return stringValue(caller.meta?.profile) === "sub-coordinator" ? "sub-coordinator" : "coordinator";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function spawnPolicyTask(task: { id: number; tags?: readonly string[]; paths?: readonly string[] } | undefined): SpawnPolicyTask | undefined {
|
|
48
|
+
return task ? { id: task.id, ...(task.tags ? { tags: task.tags } : {}), ...(task.paths ? { paths: task.paths } : {}) } : undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Refuses a spawn the project's policy does not allow (a `ValidationError` naming the rule, the
|
|
52
|
+
* allowed set and the hint); otherwise the rules that applied, if any. */
|
|
53
|
+
export async function enforceSpawnPolicy(where: SpawnPolicyWhere, facts: { spawner: SpawnerKind; task?: SpawnPolicyTask; subject: SpawnPolicySubject }): Promise<AppliedSpawnPolicy | undefined> {
|
|
54
|
+
const loaded = await loadSpawnPolicy(where);
|
|
55
|
+
if (!loaded) return undefined;
|
|
56
|
+
const rules = matchSpawnPolicy(loaded.policy, facts);
|
|
57
|
+
if (!rules.length) return undefined;
|
|
58
|
+
const refusal = spawnPolicyRefusal(rules, facts.subject, facts.task);
|
|
59
|
+
if (refusal) throw new ValidationError(refusal);
|
|
60
|
+
return { file: SPAWN_POLICY_FILE, ref: loaded.ref, sha: loaded.sha, rules: rules.map((rule) => rule.name) };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The workflow the project's policy routes this Task's work through, and the rule that says so. */
|
|
64
|
+
export async function spawnPolicyWorkflowFor(where: SpawnPolicyWhere, facts: { spawner: SpawnerKind; task: SpawnPolicyTask }): Promise<{ workflow: string; rule: string } | undefined> {
|
|
65
|
+
const loaded = await loadSpawnPolicy(where);
|
|
66
|
+
const chosen = loaded && spawnPolicyWorkflow(matchSpawnPolicy(loaded.policy, facts));
|
|
67
|
+
return chosen ? { workflow: chosen.workflow, rule: chosen.rule.name } : undefined;
|
|
68
|
+
}
|