@sema-agent/server 1.323.0 → 2.0.0
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/dist/approval-hmac.d.ts +40 -0
- package/dist/approval-hmac.js +67 -0
- package/dist/approval.d.ts +31 -0
- package/dist/approval.js +72 -4
- package/dist/audit.d.ts +26 -0
- package/dist/audit.js +40 -1
- package/dist/auth-bridge.d.ts +10 -0
- package/dist/auth-bridge.js +47 -4
- package/dist/auth-keys.d.ts +19 -0
- package/dist/auth-keys.js +13 -0
- package/dist/bake-runner/main.d.ts +5 -0
- package/dist/bake-runner/main.js +43 -4
- package/dist/bake-runner/protocol.d.ts +57 -0
- package/dist/bake-runner/protocol.js +58 -3
- package/dist/bake-runner/runner.d.ts +54 -0
- package/dist/bake-runner/runner.js +87 -5
- package/dist/bench/l8/artifact.d.ts +63 -0
- package/dist/bench/l8/artifact.js +61 -2
- package/dist/bench/l8/escape.d.ts +36 -0
- package/dist/bench/l8/escape.js +25 -0
- package/dist/bench/l8/index.d.ts +14 -0
- package/dist/bench/l8/index.js +14 -0
- package/dist/bench/l8/probes.d.ts +74 -0
- package/dist/bench/l8/probes.js +60 -0
- package/dist/bench/l8/run-probes.d.ts +43 -0
- package/dist/bench/l8/run-probes.js +45 -2
- package/dist/bench/s1/arms.d.ts +126 -0
- package/dist/bench/s1/arms.js +188 -13
- package/dist/bench/s1/live-deps.d.ts +66 -0
- package/dist/bench/s1/live-deps.js +249 -11
- package/dist/bench/s1/oracle.d.ts +49 -0
- package/dist/bench/s1/oracle.js +36 -1
- package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
- package/dist/bench/s1/repair-oracle-adapter.js +30 -0
- package/dist/bench/s1/reviewer.d.ts +38 -0
- package/dist/bench/s1/reviewer.js +34 -0
- package/dist/bench/s1/row.d.ts +77 -0
- package/dist/bench/s1/row.js +62 -0
- package/dist/bench/s1/run-firm.d.ts +47 -0
- package/dist/bench/s1/run-firm.js +70 -4
- package/dist/bench/s1/runner-ctx.d.ts +71 -0
- package/dist/bench/s1/runner-ctx.js +36 -0
- package/dist/bench/s1/tasks.d.ts +108 -0
- package/dist/bench/s1/tasks.js +115 -0
- package/dist/boot-reclaim.d.ts +19 -0
- package/dist/boot-reclaim.js +20 -0
- package/dist/brain.d.ts +25 -0
- package/dist/brain.js +61 -1
- package/dist/budget.d.ts +66 -0
- package/dist/budget.js +128 -4
- package/dist/capabilities/builtin-tools.d.ts +3 -0
- package/dist/capabilities/builtin-tools.js +3 -0
- package/dist/capabilities/center-plugins.d.ts +17 -1
- package/dist/capabilities/center-plugins.js +45 -4
- package/dist/capabilities/center-prompts.d.ts +46 -0
- package/dist/capabilities/center-prompts.js +57 -3
- package/dist/capabilities/code-review-council.d.ts +28 -0
- package/dist/capabilities/code-review-council.js +40 -7
- package/dist/capabilities/collab-wire.d.ts +2 -0
- package/dist/capabilities/collab-workflows.d.ts +7 -0
- package/dist/capabilities/collab-workflows.js +44 -1
- package/dist/capabilities/oa-tools.d.ts +6 -0
- package/dist/capabilities/oa-tools.js +10 -0
- package/dist/capabilities/prompt.d.ts +14 -0
- package/dist/capabilities/prompt.js +14 -0
- package/dist/capabilities/prompts/code-review.d.ts +14 -0
- package/dist/capabilities/prompts/code-review.js +14 -0
- package/dist/capabilities/prompts/identity.d.ts +6 -0
- package/dist/capabilities/prompts/identity.js +6 -0
- package/dist/capabilities/prompts/team.d.ts +4 -0
- package/dist/capabilities/prompts/team.js +4 -0
- package/dist/capabilities/repo-tools.d.ts +11 -0
- package/dist/capabilities/repo-tools.js +8 -0
- package/dist/capabilities/sandbox-file-send.d.ts +95 -0
- package/dist/capabilities/sandbox-file-send.js +91 -3
- package/dist/capabilities/scenarios.d.ts +130 -0
- package/dist/capabilities/scenarios.js +180 -7
- package/dist/capabilities/select-environment-tool.d.ts +7 -0
- package/dist/capabilities/select-environment-tool.js +30 -0
- package/dist/capabilities/send-user-file-tool.d.ts +33 -0
- package/dist/capabilities/send-user-file-tool.js +65 -1
- package/dist/capabilities/skills.d.ts +29 -0
- package/dist/capabilities/skills.js +13 -2
- package/dist/capabilities/team.d.ts +22 -0
- package/dist/capabilities/team.js +22 -2
- package/dist/capabilities/tool-defer.d.ts +26 -0
- package/dist/capabilities/tool-defer.js +3 -0
- package/dist/config-center/apply-effective.d.ts +65 -0
- package/dist/config-center/apply-effective.js +204 -12
- package/dist/config-center/http-client.d.ts +34 -0
- package/dist/config-center/http-client.js +68 -0
- package/dist/config-center/restart-signal.d.ts +22 -0
- package/dist/config-center/restart-signal.js +39 -0
- package/dist/config-center/skills-mcp.d.ts +20 -1
- package/dist/config-center/skills-mcp.js +42 -7
- package/dist/config-center/types.d.ts +92 -1
- package/dist/config-lkg.d.ts +12 -0
- package/dist/config-lkg.js +41 -0
- package/dist/config-provider.d.ts +78 -0
- package/dist/config-provider.js +165 -2
- package/dist/config-types.d.ts +546 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.js +455 -60
- package/dist/degenerate-instrument.d.ts +38 -0
- package/dist/degenerate-instrument.js +55 -3
- package/dist/elicitation.d.ts +39 -0
- package/dist/elicitation.js +87 -3
- package/dist/env-facts.d.ts +61 -0
- package/dist/env-facts.js +73 -7
- package/dist/fleet/fleet-bus.d.ts +185 -0
- package/dist/fleet/fleet-bus.js +333 -27
- package/dist/fleet/subagent-tail-bus.d.ts +11 -0
- package/dist/fleet/subagent-tail-bus.js +33 -2
- package/dist/fleet-client.d.ts +38 -0
- package/dist/fleet-client.js +44 -9
- package/dist/fleet-lease.d.ts +46 -0
- package/dist/fleet-lease.js +73 -5
- package/dist/hooks/branch-transcript.d.ts +8 -0
- package/dist/hooks/branch-transcript.js +33 -0
- package/dist/hooks/cc-stop-prompt.d.ts +42 -0
- package/dist/hooks/cc-stop-prompt.js +43 -1
- package/dist/hooks/hook-llm.d.ts +15 -0
- package/dist/hooks/hook-llm.js +47 -0
- package/dist/hooks/hook-runner.d.ts +89 -0
- package/dist/hooks/hook-runner.js +327 -18
- package/dist/http/idempotency.d.ts +31 -0
- package/dist/http/idempotency.js +34 -0
- package/dist/http/principal-gate.d.ts +17 -0
- package/dist/http/principal-gate.js +35 -3
- package/dist/http/route-ctx.d.ts +36 -0
- package/dist/http/routes/approvals-assistant.d.ts +25 -0
- package/dist/http/routes/approvals-assistant.js +253 -23
- package/dist/http/routes/attachments.js +22 -4
- package/dist/http/routes/capabilities.d.ts +7 -0
- package/dist/http/routes/capabilities.js +202 -1
- package/dist/http/routes/fleet.d.ts +6 -0
- package/dist/http/routes/fleet.js +94 -5
- package/dist/http/routes/images.d.ts +17 -0
- package/dist/http/routes/images.js +222 -14
- package/dist/http/routes/leader.d.ts +7 -0
- package/dist/http/routes/leader.js +10 -0
- package/dist/http/routes/memory-policy.d.ts +6 -0
- package/dist/http/routes/memory-policy.js +38 -6
- package/dist/http/routes/notify-wake.d.ts +10 -0
- package/dist/http/routes/notify-wake.js +19 -3
- package/dist/http/routes/observability.d.ts +6 -0
- package/dist/http/routes/observability.js +19 -2
- package/dist/http/routes/runs.d.ts +15 -0
- package/dist/http/routes/runs.js +464 -41
- package/dist/http/routes/session-sync.d.ts +15 -0
- package/dist/http/routes/session-sync.js +229 -19
- package/dist/http/routes/sessions-list.d.ts +6 -0
- package/dist/http/routes/sessions-list.js +35 -4
- package/dist/http/routes/sessions.d.ts +14 -0
- package/dist/http/routes/sessions.js +176 -31
- package/dist/http/routes/side-query.d.ts +8 -0
- package/dist/http/routes/side-query.js +26 -1
- package/dist/http/routes/tasks.d.ts +18 -0
- package/dist/http/routes/tasks.js +501 -38
- package/dist/http/routes/trace-usage.d.ts +10 -0
- package/dist/http/routes/trace-usage.js +66 -14
- package/dist/http/routes/workflows.d.ts +12 -0
- package/dist/http/routes/workflows.js +180 -19
- package/dist/http/run-meta.d.ts +11 -0
- package/dist/http/run-meta.js +6 -0
- package/dist/http/send.d.ts +19 -0
- package/dist/http/send.js +11 -0
- package/dist/http/server.d.ts +255 -0
- package/dist/http/server.js +921 -75
- package/dist/http/sse-log.d.ts +15 -0
- package/dist/http/sse-log.js +16 -0
- package/dist/http/tar.d.ts +9 -0
- package/dist/http/tar.js +21 -5
- package/dist/http/wire-gate.d.ts +9 -0
- package/dist/http/wire-gate.js +9 -0
- package/dist/http/wire-types.d.ts +187 -0
- package/dist/http/workspace-content.d.ts +8 -0
- package/dist/http/workspace-content.js +10 -0
- package/dist/images/bake-validate.d.ts +63 -0
- package/dist/images/bake-validate.js +71 -1
- package/dist/images/manifest.d.ts +19 -0
- package/dist/images/manifest.js +6 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +10 -5
- package/dist/key-resolver.d.ts +23 -0
- package/dist/key-resolver.js +27 -2
- package/dist/leader/diffout.d.ts +23 -0
- package/dist/leader/diffout.js +8 -1
- package/dist/leader/diffup.d.ts +32 -0
- package/dist/leader/diffup.js +43 -0
- package/dist/leader/endpoint.d.ts +20 -0
- package/dist/leader/endpoint.js +25 -2
- package/dist/leader/fanout.d.ts +60 -0
- package/dist/leader/fanout.js +29 -3
- package/dist/leader/grader-env-factory.d.ts +74 -0
- package/dist/leader/grader-env-factory.js +62 -3
- package/dist/leader/leader.d.ts +97 -0
- package/dist/leader/leader.js +151 -4
- package/dist/leader/merge.d.ts +94 -0
- package/dist/leader/merge.js +112 -9
- package/dist/leader/planner.d.ts +52 -0
- package/dist/leader/planner.js +47 -3
- package/dist/leader/repair-oracle.d.ts +61 -0
- package/dist/leader/repair-oracle.js +59 -1
- package/dist/leader/repair-wire.d.ts +78 -0
- package/dist/leader/repair-wire.js +79 -2
- package/dist/leader/wire.d.ts +79 -0
- package/dist/leader/wire.js +255 -8
- package/dist/lsp/e2b-bridge.d.ts +16 -0
- package/dist/lsp/e2b-bridge.js +32 -4
- package/dist/lsp/e2b-manager.d.ts +10 -0
- package/dist/lsp/e2b-manager.js +18 -2
- package/dist/lsp/lsp-frames.d.ts +12 -0
- package/dist/lsp/lsp-frames.js +12 -0
- package/dist/lsp/manager.d.ts +12 -0
- package/dist/lsp/manager.js +35 -2
- package/dist/lsp/types.d.ts +10 -0
- package/dist/lsp/ws-transport.d.ts +12 -0
- package/dist/lsp/ws-transport.js +53 -5
- package/dist/lsp-evict.d.ts +14 -0
- package/dist/lsp-evict.js +15 -1
- package/dist/main.js +2132 -96
- package/dist/memory-export.d.ts +1 -0
- package/dist/memory-export.js +4 -0
- package/dist/memory-scope.d.ts +49 -0
- package/dist/memory-scope.js +87 -4
- package/dist/memory-sync-client.d.ts +24 -0
- package/dist/memory-sync-client.js +41 -2
- package/dist/memory-sync.d.ts +23 -0
- package/dist/memory-sync.js +70 -1
- package/dist/model-select.d.ts +39 -0
- package/dist/model-select.js +42 -1
- package/dist/observability/cost-quota.d.ts +20 -0
- package/dist/observability/cost-quota.js +4 -0
- package/dist/observability/cost-taxonomy.d.ts +45 -0
- package/dist/observability/cost-taxonomy.js +34 -0
- package/dist/observability/logger.d.ts +1 -0
- package/dist/observability/logger.js +6 -0
- package/dist/observability/metrics.d.ts +13 -0
- package/dist/observability/metrics.js +63 -0
- package/dist/observability/otel-exporter.d.ts +9 -0
- package/dist/observability/otel-exporter.js +11 -3
- package/dist/observability/principal-context.d.ts +9 -0
- package/dist/observability/principal-context.js +9 -0
- package/dist/observability/prompt-manifest.d.ts +37 -0
- package/dist/observability/prompt-manifest.js +35 -1
- package/dist/observability/rate-limit.d.ts +10 -0
- package/dist/observability/rate-limit.js +1 -0
- package/dist/observability/tool-trace.d.ts +24 -0
- package/dist/observability/tool-trace.js +41 -1
- package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
- package/dist/orchestration/hardened-vm-runner.js +119 -4
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
- package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
- package/dist/orchestration/hardened-vm-worker.js +27 -0
- package/dist/orchestration/subagent-steer.d.ts +44 -0
- package/dist/orchestration/subagent-steer.js +45 -1
- package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
- package/dist/orchestration/workflow-agent-steer.js +80 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
- package/dist/orchestration/workflow-completion-inbox.js +283 -32
- package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
- package/dist/orchestration/workflow-notify-journal.js +187 -13
- package/dist/parked-decide.d.ts +61 -0
- package/dist/parked-decide.js +58 -1
- package/dist/per-task-image.d.ts +54 -0
- package/dist/per-task-image.js +41 -0
- package/dist/plan-cache-probe.d.ts +35 -0
- package/dist/plan-cache-probe.js +18 -3
- package/dist/plugins/approval-exemption-store.d.ts +7 -0
- package/dist/plugins/approval-exemption-store.js +28 -2
- package/dist/plugins/approval-store-sql.d.ts +64 -0
- package/dist/plugins/approval-store-sql.js +32 -0
- package/dist/plugins/background-agent-store-sql.d.ts +55 -0
- package/dist/plugins/background-agent-store-sql.js +91 -4
- package/dist/plugins/background-shell-support.d.ts +98 -0
- package/dist/plugins/background-shell-support.js +117 -13
- package/dist/plugins/blob-backend.d.ts +104 -0
- package/dist/plugins/blob-backend.js +163 -6
- package/dist/plugins/breaker-state-sql.d.ts +65 -1
- package/dist/plugins/breaker-state-sql.js +46 -8
- package/dist/plugins/caching-session-store.d.ts +42 -0
- package/dist/plugins/caching-session-store.js +63 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
- package/dist/plugins/checkpoint-store-sql.js +239 -11
- package/dist/plugins/file-outcome-sink.d.ts +4 -0
- package/dist/plugins/file-outcome-sink.js +9 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
- package/dist/plugins/file-resume-anchor-store.js +43 -4
- package/dist/plugins/file-run-store.d.ts +90 -0
- package/dist/plugins/file-run-store.js +145 -13
- package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
- package/dist/plugins/file-snapshot-store-sql.js +178 -10
- package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
- package/dist/plugins/file-workflow-journal-store.js +10 -0
- package/dist/plugins/fork-routing-session-store.d.ts +47 -0
- package/dist/plugins/fork-routing-session-store.js +51 -3
- package/dist/plugins/host-platform.d.ts +69 -0
- package/dist/plugins/host-platform.js +81 -2
- package/dist/plugins/image-bake-store-sql.d.ts +136 -1
- package/dist/plugins/image-bake-store-sql.js +241 -7
- package/dist/plugins/image-index-sql.d.ts +46 -0
- package/dist/plugins/image-index-sql.js +113 -4
- package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
- package/dist/plugins/k8s-bg-scripts.js +88 -4
- package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
- package/dist/plugins/k8s-exec-protocol.js +41 -0
- package/dist/plugins/local-checkpoint-store.d.ts +40 -0
- package/dist/plugins/local-checkpoint-store.js +86 -7
- package/dist/plugins/local-session-store.d.ts +157 -0
- package/dist/plugins/local-session-store.js +289 -34
- package/dist/plugins/local-task-attachment-store.js +14 -2
- package/dist/plugins/mailbox-store-sql.d.ts +38 -0
- package/dist/plugins/mailbox-store-sql.js +39 -6
- package/dist/plugins/memory-engine-pg.d.ts +30 -0
- package/dist/plugins/memory-engine-pg.js +122 -4
- package/dist/plugins/memory-engine-tidb.d.ts +26 -0
- package/dist/plugins/memory-engine-tidb.js +115 -5
- package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
- package/dist/plugins/memory-engine-vector-util.js +5 -0
- package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
- package/dist/plugins/memory-resume-anchor-store.js +17 -0
- package/dist/plugins/memory-run-store.d.ts +63 -0
- package/dist/plugins/memory-run-store.js +73 -8
- package/dist/plugins/memory-session-policy-store.d.ts +17 -0
- package/dist/plugins/memory-session-policy-store.js +17 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
- package/dist/plugins/memory-sync-store-pg.js +45 -2
- package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
- package/dist/plugins/memory-sync-store-tidb.js +31 -1
- package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
- package/dist/plugins/outcome-ledger-sql.js +97 -3
- package/dist/plugins/pg-approval-store.d.ts +7 -0
- package/dist/plugins/pg-approval-store.js +7 -0
- package/dist/plugins/pg-breaker-state.d.ts +6 -0
- package/dist/plugins/pg-breaker-state.js +6 -0
- package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
- package/dist/plugins/pg-checkpoint-store.js +8 -0
- package/dist/plugins/pg-cost-quota.d.ts +17 -0
- package/dist/plugins/pg-cost-quota.js +6 -0
- package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/pg-file-snapshot-store.js +6 -0
- package/dist/plugins/pg-image-bake.d.ts +9 -0
- package/dist/plugins/pg-image-bake.js +9 -0
- package/dist/plugins/pg-image-index.d.ts +9 -0
- package/dist/plugins/pg-image-index.js +9 -0
- package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
- package/dist/plugins/pg-outcome-ledger.js +9 -0
- package/dist/plugins/pg-pool.d.ts +50 -0
- package/dist/plugins/pg-pool.js +78 -0
- package/dist/plugins/pg-query.d.ts +11 -0
- package/dist/plugins/pg-rate-limiter.d.ts +23 -0
- package/dist/plugins/pg-rate-limiter.js +12 -2
- package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/pg-resume-anchor-store.js +5 -0
- package/dist/plugins/pg-run-store.d.ts +7 -0
- package/dist/plugins/pg-run-store.js +7 -0
- package/dist/plugins/pg-safe-json.d.ts +13 -0
- package/dist/plugins/pg-safe-json.js +40 -4
- package/dist/plugins/pg-session-policy-store.d.ts +5 -0
- package/dist/plugins/pg-session-policy-store.js +5 -0
- package/dist/plugins/pg-session-storage.d.ts +72 -0
- package/dist/plugins/pg-session-storage.js +152 -20
- package/dist/plugins/pg-session-store.d.ts +10 -0
- package/dist/plugins/pg-session-store.js +10 -0
- package/dist/plugins/pg-tool-result-store.d.ts +7 -0
- package/dist/plugins/pg-tool-result-store.js +7 -0
- package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-journal-store.js +7 -0
- package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-run-store.js +7 -0
- package/dist/plugins/posix-shell-fs.d.ts +3 -0
- package/dist/plugins/posix-shell-fs.js +31 -1
- package/dist/plugins/remote-env-adb.d.ts +25 -0
- package/dist/plugins/remote-env-adb.js +95 -12
- package/dist/plugins/remote-env-e2b.d.ts +146 -0
- package/dist/plugins/remote-env-e2b.js +371 -40
- package/dist/plugins/remote-env-file-error.d.ts +34 -0
- package/dist/plugins/remote-env-file-error.js +37 -0
- package/dist/plugins/remote-env-host.d.ts +151 -0
- package/dist/plugins/remote-env-host.js +468 -70
- package/dist/plugins/remote-env-k8s.d.ts +135 -0
- package/dist/plugins/remote-env-k8s.js +318 -32
- package/dist/plugins/remote-env-local-docker.d.ts +65 -0
- package/dist/plugins/remote-env-local-docker.js +149 -24
- package/dist/plugins/remote-env-ssh.d.ts +35 -0
- package/dist/plugins/remote-env-ssh.js +117 -20
- package/dist/plugins/remote-scratchpad.d.ts +38 -0
- package/dist/plugins/remote-scratchpad.js +32 -2
- package/dist/plugins/remote-shell.d.ts +22 -0
- package/dist/plugins/remote-shell.js +27 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
- package/dist/plugins/resume-anchor-store-sql.js +11 -0
- package/dist/plugins/roster-store-sql.d.ts +27 -0
- package/dist/plugins/roster-store-sql.js +54 -0
- package/dist/plugins/run-store-sql.d.ts +194 -0
- package/dist/plugins/run-store-sql.js +210 -9
- package/dist/plugins/s3-presign.d.ts +20 -0
- package/dist/plugins/s3-presign.js +49 -2
- package/dist/plugins/scheduler-support.d.ts +12 -0
- package/dist/plugins/scheduler-support.js +75 -3
- package/dist/plugins/send-file-ledger.d.ts +15 -0
- package/dist/plugins/send-file-ledger.js +53 -4
- package/dist/plugins/send-user-file.d.ts +77 -0
- package/dist/plugins/send-user-file.js +92 -4
- package/dist/plugins/session-policy-store-sql.d.ts +15 -0
- package/dist/plugins/session-policy-store-sql.js +75 -3
- package/dist/plugins/session-store.d.ts +45 -0
- package/dist/plugins/session-store.js +51 -0
- package/dist/plugins/sql-driver.d.ts +77 -0
- package/dist/plugins/sql-driver.js +4 -0
- package/dist/plugins/sql-escape.d.ts +8 -0
- package/dist/plugins/sql-escape.js +8 -0
- package/dist/plugins/sql-row-helpers.d.ts +25 -0
- package/dist/plugins/sql-row-helpers.js +25 -0
- package/dist/plugins/store-backend.d.ts +103 -0
- package/dist/plugins/store-backend.js +120 -27
- package/dist/plugins/store-contracts.d.ts +62 -0
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +60 -0
- package/dist/plugins/task-attachment-store.js +49 -3
- package/dist/plugins/task-list-store-sql.d.ts +25 -0
- package/dist/plugins/task-list-store-sql.js +21 -0
- package/dist/plugins/tidb-approval-store.d.ts +6 -0
- package/dist/plugins/tidb-approval-store.js +6 -0
- package/dist/plugins/tidb-breaker-state.d.ts +5 -0
- package/dist/plugins/tidb-breaker-state.js +5 -0
- package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
- package/dist/plugins/tidb-checkpoint-store.js +7 -0
- package/dist/plugins/tidb-cost-quota.d.ts +6 -0
- package/dist/plugins/tidb-cost-quota.js +1 -0
- package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/tidb-file-snapshot-store.js +6 -0
- package/dist/plugins/tidb-image-bake.d.ts +8 -0
- package/dist/plugins/tidb-image-bake.js +8 -0
- package/dist/plugins/tidb-image-index.d.ts +8 -0
- package/dist/plugins/tidb-image-index.js +8 -0
- package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
- package/dist/plugins/tidb-outcome-ledger.js +10 -0
- package/dist/plugins/tidb-pool.d.ts +56 -0
- package/dist/plugins/tidb-pool.js +181 -1
- package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
- package/dist/plugins/tidb-rate-limiter.js +5 -2
- package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/tidb-resume-anchor-store.js +5 -0
- package/dist/plugins/tidb-run-store.d.ts +7 -0
- package/dist/plugins/tidb-run-store.js +7 -0
- package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
- package/dist/plugins/tidb-session-policy-store.js +5 -0
- package/dist/plugins/tidb-session-storage.d.ts +43 -0
- package/dist/plugins/tidb-session-storage.js +62 -3
- package/dist/plugins/tidb-session-store.d.ts +142 -0
- package/dist/plugins/tidb-session-store.js +264 -16
- package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
- package/dist/plugins/tidb-tool-result-store.js +7 -0
- package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/tidb-workflow-journal-store.js +7 -0
- package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
- package/dist/plugins/tidb-workflow-run-store.js +8 -0
- package/dist/plugins/tool-result-store-sql.d.ts +58 -0
- package/dist/plugins/tool-result-store-sql.js +38 -2
- package/dist/plugins/web-search.d.ts +35 -0
- package/dist/plugins/web-search.js +45 -9
- package/dist/plugins/workflow-journal-limits.d.ts +10 -0
- package/dist/plugins/workflow-journal-limits.js +10 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
- package/dist/plugins/workflow-journal-store-sql.js +58 -2
- package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
- package/dist/plugins/workflow-run-store-sql.js +84 -6
- package/dist/plugins/worktree-isolation.d.ts +45 -0
- package/dist/plugins/worktree-isolation.js +105 -6
- package/dist/plugins/write-behind-counter.d.ts +56 -1
- package/dist/plugins/write-behind-counter.js +53 -14
- package/dist/principal-jwt.d.ts +24 -0
- package/dist/principal-jwt.js +60 -5
- package/dist/project-memory.d.ts +22 -0
- package/dist/project-memory.js +144 -15
- package/dist/prompts-domain-validate.d.ts +28 -0
- package/dist/prompts-domain-validate.js +42 -1
- package/dist/question.d.ts +33 -0
- package/dist/question.js +69 -2
- package/dist/resource-suspend.d.ts +21 -0
- package/dist/resource-suspend.js +16 -0
- package/dist/router/route-orchestration.d.ts +78 -0
- package/dist/router/route-orchestration.js +77 -0
- package/dist/run-local.d.ts +32 -0
- package/dist/run-local.js +172 -8
- package/dist/runs.d.ts +189 -4
- package/dist/runs.js +465 -24
- package/dist/runtime-caps-resolver.d.ts +106 -0
- package/dist/runtime-caps-resolver.js +89 -4
- package/dist/runtime-governance.d.ts +84 -0
- package/dist/runtime-governance.js +127 -1
- package/dist/sandbox-pkg-source.d.ts +23 -0
- package/dist/sandbox-pkg-source.js +37 -0
- package/dist/sealed-key.d.ts +54 -0
- package/dist/sealed-key.js +68 -3
- package/dist/security.d.ts +108 -0
- package/dist/security.js +145 -6
- package/dist/sema-registry.d.ts +21 -0
- package/dist/sema-registry.js +21 -0
- package/dist/session-leaf-bus.d.ts +31 -0
- package/dist/session-leaf-bus.js +32 -0
- package/dist/session-sync-content.d.ts +46 -0
- package/dist/session-sync-content.js +47 -1
- package/dist/session-sync-kernel.d.ts +89 -0
- package/dist/session-sync-kernel.js +48 -3
- package/dist/session-sync.d.ts +125 -0
- package/dist/session-sync.js +181 -8
- package/dist/session-titler.d.ts +26 -0
- package/dist/session-titler.js +41 -7
- package/dist/session-watch.d.ts +53 -1
- package/dist/session-watch.js +73 -9
- package/dist/sighup-idle.d.ts +30 -0
- package/dist/sighup-idle.js +12 -1
- package/dist/spec-fields.d.ts +91 -3
- package/dist/spec-fields.js +116 -4
- package/dist/task-cwd.d.ts +50 -0
- package/dist/task-cwd.js +68 -1
- package/dist/task-mcp.d.ts +47 -0
- package/dist/task-mcp.js +29 -0
- package/dist/task-settings.d.ts +175 -0
- package/dist/task-settings.js +226 -11
- package/dist/task-workflow.d.ts +67 -0
- package/dist/task-workflow.js +75 -8
- package/dist/tool-approval.d.ts +91 -0
- package/dist/tool-approval.js +215 -0
- package/dist/trace/artifacts.d.ts +9 -0
- package/dist/trace/artifacts.js +30 -5
- package/dist/trace/core-keyset-guard.d.ts +18 -0
- package/dist/trace/ledger-sink.d.ts +43 -0
- package/dist/trace/ledger-sink.js +64 -5
- package/dist/trace/project.d.ts +133 -0
- package/dist/trace/project.js +189 -2
- package/dist/trace/redact.d.ts +19 -0
- package/dist/trace/redact.js +66 -9
- package/dist/usage-analytics.d.ts +26 -0
- package/dist/usage-analytics.js +26 -3
- package/package.json +1 -1
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entitlements resolver — the SERVICE-side wiring of core 1.157's `RunnerDeps.runtimeCapsResolver` (design/99 §K).
|
|
3
|
+
* (design/158 N11: this module's own exports were renamed `*Caps*` → `*Entitlements*` to stop sharing a word
|
|
4
|
+
* root with the UNRELATED `capabilities` face (deployment route discovery, `src/capabilities/`) and
|
|
5
|
+
* `ScenarioBundle` assembly — "caps" meant three different things across those three faces. `RuntimeCaps` /
|
|
6
|
+
* `EntitlementRuntimeCaps` themselves stay as-is below: they are core's / registry-core's own contract type
|
|
7
|
+
* names, not ours to rename.)
|
|
8
|
+
* It is the ENFORCE last-link of the three-stage workflows gate
|
|
9
|
+
* (engine-can ∧ center-may ∧ shell-show): core calls it ONCE per task at prepare time with `spec.principal`,
|
|
10
|
+
* and the engine enforces the two caps it CAN enforce — `allowWorkflows` (deny self-orchestration) and
|
|
11
|
+
* `forceDurableGate` (force a policy `ask` onto the durable-approval wire).
|
|
12
|
+
*
|
|
13
|
+
* It pulls the PER-PRINCIPAL entitlement from center's `GET /api/config/effective?principal=` (via
|
|
14
|
+
* {@link fetchPrincipalCaps}). center has ALREADY pre-resolved the tighten-only intersection (fleet defaults ∩
|
|
15
|
+
* tier ⊕ roles + time-bounded overrides); the service passes the resolved value through VERBATIM (per center
|
|
16
|
+
* ruling: "service 只透传 resolved 值、无需再 tighten"). The resolver adds only the data-plane concerns center can't:
|
|
17
|
+
* a per-principal TTL+ETag CACHE (so per-task prepare-time lookups don't hammer center) and FAIL-CLOSED degrade.
|
|
18
|
+
*
|
|
19
|
+
* 🔐 FAIL-CLOSED (core security mandate, prepare-task.ts): an entitlement-resolver outage must NEVER silently
|
|
20
|
+
* GRANT a capability center may have denied. On a hard fetch error we return `{ allowWorkflows: false }` (deny the
|
|
21
|
+
* OPTIONAL workflows privilege) and do NOT force the durable gate (that could strand an autonomous run on an
|
|
22
|
+
* absent operator — the same minimal degrade core applies when the resolver throws). We never serve a STALE
|
|
23
|
+
* cached GRANT past its TTL on a fresh-fetch failure (a revoked cap must not linger because center blipped).
|
|
24
|
+
*
|
|
25
|
+
* The resolver maps center's `EntitlementRuntimeCaps` → the SUBSET core enforces ({@link RuntimeCaps}): center
|
|
26
|
+
* also carries `allowUltracode` (a shell/UX reasoning-tier cap the engine has no primitive for), which we DROP —
|
|
27
|
+
* this seam feeds the ENGINE, and `allowUltracode` is enforced at the service settings-resolution layer, not here.
|
|
28
|
+
*/
|
|
1
29
|
import type { RuntimeCaps } from "@sema-agent/core";
|
|
2
30
|
import type { EntitlementRuntimeCaps } from "@sema-agent/registry-core";
|
|
3
31
|
import { fetchPrincipalCaps, type ExecutionRuling } from "./sema-registry.js";
|
|
@@ -5,25 +33,103 @@ import type { ScenarioRuling } from "./capabilities/scenarios.js";
|
|
|
5
33
|
export interface EntitlementsResolverOpts {
|
|
6
34
|
baseUrl: string;
|
|
7
35
|
token: string;
|
|
36
|
+
/** This worker's name (`SEMA_REGISTRY_WORKER`), passed as `?worker=` so a worker-scoped `wpt_<self>` token can
|
|
37
|
+
* resolve its OWN worker's principal caps (caps-only); harmless on a full token (the caps value
|
|
38
|
+
* is worker-independent). Omitted ⇒ no `?worker=` (a full-token, non-fleet deployment). */
|
|
8
39
|
worker?: string;
|
|
40
|
+
/** Per-principal cache TTL (ms). A resolved entitlement is reused for this long before an ETag-conditional
|
|
41
|
+
* re-pull, collapsing per-task prepare-time lookups to ~1 center call/principal/TTL. Default 60s. */
|
|
9
42
|
ttlMs?: number;
|
|
43
|
+
/** Short window (ms) a FAIL-CLOSED deny is cached to avoid hammering center (8s timeout each) on a sustained
|
|
44
|
+
* outage, without pinning a deny long past a transient blip. Default min(ttlMs, 10s). */
|
|
10
45
|
denyTtlMs?: number;
|
|
46
|
+
/** Injected for tests. */
|
|
11
47
|
fetchImpl?: typeof fetch;
|
|
12
48
|
fetchCaps?: typeof fetchPrincipalCaps;
|
|
13
49
|
now?: () => number;
|
|
50
|
+
/** Observability hook for a resolve failure (defaults to a `runtime_caps_resolve_failed` warn). */
|
|
14
51
|
onError?: (err: Error, principal: string) => void;
|
|
15
52
|
}
|
|
53
|
+
/** Map center's `EntitlementRuntimeCaps` → the subset core's engine enforces. `allowUltracode` (shell/UX) is
|
|
54
|
+
* dropped on purpose (not a core primitive); `allowWorkflows` / `forceDurableGate` / `allowFork` are the three the
|
|
55
|
+
* engine enforces. Returns undefined when no enforceable cap is set (= no restriction). FAIL-CLOSED defense-in-depth:
|
|
56
|
+
* do NOT trust the wire to be boolean. center serializes these as zod-validated booleans, but a schema drift / proxy
|
|
57
|
+
* mangling that sent a TRUTHY non-boolean (e.g. the STRING "false") would slip past core's strict `=== false` deny
|
|
58
|
+
* check and silently GRANT. So a cap that is PRESENT but not a real boolean is a contract breach → THROW (the
|
|
59
|
+
* resolver's catch then fail-closes to deny). `allowFork` (registry-core 0.1.47): the per-principal Fork
|
|
60
|
+
* ceiling — core mounts Fork only when `runtimeCaps.allowFork !== false` (prepare-task), tighten-only like allowWorkflows.
|
|
61
|
+
*
|
|
62
|
+
* `allowObservers`(observer 开闸线,core 1.270.0/1.273.0):**极性与 allow* 相反** —
|
|
63
|
+
* core 是 `=== true` 显式 opt-in(默认 OFF,undefined ships dark)。registry-core 0.10.3 起该键已收编进
|
|
64
|
+
* `EntitlementRuntimeCaps` 类型(此前 0.10.2 走 unknown 宽读透传,现为类型直读,行为零变)。
|
|
65
|
+
* **缺键=不写键**(绝不把缺键补成显式 false —— core 是唯一默认源,补 false 语义上等价但会伪造「center
|
|
66
|
+
* 说过话」的显式判决,污染 env-baseline 合成序,见 applyObserverEnvOptIn)。非 boolean 虽然骗不过 core
|
|
67
|
+
* 的 `=== true`(不会误 GRANT),但 PRESENT-非-boolean 与 allow* 同属同一 body 的契约破损信号 → 同款 THROW。
|
|
68
|
+
*
|
|
69
|
+
* `autoMode`(core 1.276.0 `RuntimeCaps.autoMode`):auto-mode 分类器 per-principal
|
|
70
|
+
* 开闸线,极性同 allowObservers(`=== true` 显式 opt-in,默认 OFF;真执行还要 deployment 装配
|
|
71
|
+
* `RunnerDeps.autoMode` 分类器面=信任门,center 键只是 entitlement 半场)。registry-core 类型未收编
|
|
72
|
+
* → unknown 宽读透传(allowObservers 0.10.2 期同款先例);center 发键即活。 */
|
|
16
73
|
export declare function toCoreRuntimeCaps(ent: EntitlementRuntimeCaps | null | undefined): RuntimeCaps | undefined;
|
|
74
|
+
/** A MISCONFIG diagnostic (review MEDIUM): a worker-scoped `wpt_<self>` pull token REQUIRES `?worker=<self>` to
|
|
75
|
+
* resolve per-principal caps — so a `wpt_` token with NO `SEMA_REGISTRY_WORKER` set will 403
|
|
76
|
+
* on every caps fetch → fail-closed DENY ALL workflows for ALL principals (correct degrade, but otherwise silent
|
|
77
|
+
* bar per-task warns). True ⇒ the caller should log a one-shot BOOT warning so the misconfig is diagnosable.
|
|
78
|
+
* (The orchestrator normally injects SEMA_REGISTRY_WORKER alongside a wpt_ token, so this is a hand-misconfig.) */
|
|
17
79
|
export declare function scopedTokenNeedsWorker(token: string, worker: string | undefined): boolean;
|
|
80
|
+
/** The two per-principal faces served off ONE caps fetch + cache. */
|
|
18
81
|
export interface PrincipalEntitlementsClient {
|
|
82
|
+
/** core's `RunnerDeps.runtimeCapsResolver` seam — FAIL-CLOSED on error (deny workflows/fork). */
|
|
19
83
|
resolveRuntimeCaps: (principal: string | undefined) => Promise<RuntimeCaps | undefined>;
|
|
84
|
+
/** The resolved per-principal scenario ruling for resolveSpec's gateScenarioRequest —
|
|
85
|
+
* FAIL-OPEN on error / older center without scenario keys / no principal (undefined = no governance, legacy passthrough).
|
|
86
|
+
* Scenario switching is not a privilege-amplifying face; a center blip must not pin users to `default`. */
|
|
20
87
|
scenarioRuling: (principal: string | undefined) => Promise<ScenarioRuling | undefined>;
|
|
88
|
+
/** (stage7 P5) The resolved per-principal execution-lane ruling for resolveSpec's
|
|
89
|
+
* gateExecutionLane. FAIL-OPEN + audit on error (this phase is "honest-but-bypassable";
|
|
90
|
+
* tightening to fail-closed is a future, separate decision) / older center without the execution key / no principal. */
|
|
21
91
|
executionRuling: (principal: string | undefined) => Promise<ExecutionRuling | undefined>;
|
|
22
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Task-admission enforcement of the per-principal execution policy(stage7 P5 的「真强制」
|
|
95
|
+
* service 半场——壳侧锁定是易用性强制可绕,这里是引擎闸)。The lane is a WORKER-PROCESS identity
|
|
96
|
+
* (REMOTE_EXEC is boot wiring; there is no per-task lane switch), so the gate is "this worker's lane is not
|
|
97
|
+
* permitted for this principal ⇒ reject the task": typed 403 `execution_lane_not_allowed` carrying the
|
|
98
|
+
* allowlist + this worker's lane (machine code on the wire, prose stays with the shell/web).
|
|
99
|
+
* No ruling / required=false / caps blip ⇒ pass (fail-open + audit). `allowedLanes` is an
|
|
100
|
+
* OPEN domain — unknown names simply never match this worker's lane.
|
|
101
|
+
*/
|
|
23
102
|
export declare function gateExecutionLane(ruling: ExecutionRuling | undefined, ownLane: string): void;
|
|
103
|
+
/**
|
|
104
|
+
* Build the per-principal caps client: `resolveRuntimeCaps` matches core's seam signature
|
|
105
|
+
* `(principal) => Promise<RuntimeCaps | undefined>`; `scenarioRuling` rides the SAME fetch/cache/in-flight
|
|
106
|
+
* (zero extra center RTT — center attaches the ruling to the caps body). Wire ONLY when a center is
|
|
107
|
+
* configured (and not in dry-run) — absent ⇒ core sees `undefined` ⇒ NO per-principal restriction, and the
|
|
108
|
+
* scenario gate sees `undefined` ⇒ legacy body-or-default chain.
|
|
109
|
+
*/
|
|
24
110
|
export declare function createPrincipalEntitlementsClient(opts: EntitlementsResolverOpts): PrincipalEntitlementsClient;
|
|
111
|
+
/** Back-compat face for core's seam-only consumers: the caps half of {@link createPrincipalEntitlementsClient}. */
|
|
25
112
|
export declare function createEntitlementsResolver(opts: EntitlementsResolverOpts): (principal: string | undefined) => Promise<RuntimeCaps | undefined>;
|
|
113
|
+
/** core's `RunnerDeps.runtimeCapsResolver` seam signature (types.d.ts): sync or async, undefined = no caps. */
|
|
26
114
|
export type EntitlementsResolverFn = (principal: string | undefined) => RuntimeCaps | undefined | Promise<RuntimeCaps | undefined>;
|
|
115
|
+
/**
|
|
116
|
+
* observer 开闸线的 env 半场:`EXPERIMENTAL_OBSERVER_AGENTS=true` 时把
|
|
117
|
+
* `RuntimeCaps.allowObservers: true` 作为**部署基线**合成进 caps resolver(core 1.270.0/1.273.0 的
|
|
118
|
+
* observer 面是 `=== true` 显式 opt-in、默认 OFF —— 命名先例=CC 的 `CLAUDE_CODE_EXPERIMENTAL_OBSERVER_AGENTS`
|
|
119
|
+
* env 对儿)。租户姿势(与 FORK_ENABLED/SELF_ORCHESTRATION 同款判别):
|
|
120
|
+
* - **单用户部署**(`requirePrincipal !== true`,operator 即用户):env=true 直开 —— 无 center 时静态
|
|
121
|
+
* `{allowObservers:true}`;有 center 时作 BASELINE,**center caps 带键则 center 赢**(含显式 false;
|
|
122
|
+
* 缺键=center 没说话 → env 基线生效。这依赖 toCoreRuntimeCaps 缺键不补 false 的纪律 —— core 是唯一
|
|
123
|
+
* 默认源,center 只有真说了话才覆盖)。fail-closed 错误 entry(deny)不带 allowObservers 键 → 单用户
|
|
124
|
+
* env 基线在 center blip 期间维持(operator 在自己盒子上显式 opt-in 过;observers 非 workflows/fork
|
|
125
|
+
* 级的放大面,且 deny entry 的两把闸不受影响)。
|
|
126
|
+
* - **多租户**(`requirePrincipal === true`):env **不认**,只认 center caps(半配置 fail-loud:置了
|
|
127
|
+
* env 却多租户 → 一次 boot warn,行为零变——与 MEMORY_ENGINE_BACKEND 半配置同款姿势)。
|
|
128
|
+
* 返回合成后的 resolver;两边都无源(无 center、env 无效)⇒ undefined(RunnerDeps 不接线,零行为差)。
|
|
129
|
+
* ⚠️ 调用方注意:`Boolean(centerResolver)` 才是「entitlement resolver wired」语义(enableForkFromBody /
|
|
130
|
+
* selfOrchestrationFromBody 的多租户 fail-close 判别),不要改用本函数的返回值判 —— env-only lane 不是
|
|
131
|
+
* center 背书的 entitlement 源。
|
|
132
|
+
*/
|
|
27
133
|
export declare function applyObserverEnvOptIn(centerResolver: EntitlementsResolverFn | undefined, opts: {
|
|
28
134
|
experimentalObserverAgents: boolean;
|
|
29
135
|
requirePrincipal: boolean;
|
|
@@ -2,9 +2,30 @@ import { fetchPrincipalCaps } from "./sema-registry.js";
|
|
|
2
2
|
import { HttpError } from "./security.js";
|
|
3
3
|
import { createLogger } from "./observability/logger.js";
|
|
4
4
|
const defaultLogger = createLogger();
|
|
5
|
+
/** Map center's `EntitlementRuntimeCaps` → the subset core's engine enforces. `allowUltracode` (shell/UX) is
|
|
6
|
+
* dropped on purpose (not a core primitive); `allowWorkflows` / `forceDurableGate` / `allowFork` are the three the
|
|
7
|
+
* engine enforces. Returns undefined when no enforceable cap is set (= no restriction). FAIL-CLOSED defense-in-depth:
|
|
8
|
+
* do NOT trust the wire to be boolean. center serializes these as zod-validated booleans, but a schema drift / proxy
|
|
9
|
+
* mangling that sent a TRUTHY non-boolean (e.g. the STRING "false") would slip past core's strict `=== false` deny
|
|
10
|
+
* check and silently GRANT. So a cap that is PRESENT but not a real boolean is a contract breach → THROW (the
|
|
11
|
+
* resolver's catch then fail-closes to deny). `allowFork` (registry-core 0.1.47): the per-principal Fork
|
|
12
|
+
* ceiling — core mounts Fork only when `runtimeCaps.allowFork !== false` (prepare-task), tighten-only like allowWorkflows.
|
|
13
|
+
*
|
|
14
|
+
* `allowObservers`(observer 开闸线,core 1.270.0/1.273.0):**极性与 allow* 相反** —
|
|
15
|
+
* core 是 `=== true` 显式 opt-in(默认 OFF,undefined ships dark)。registry-core 0.10.3 起该键已收编进
|
|
16
|
+
* `EntitlementRuntimeCaps` 类型(此前 0.10.2 走 unknown 宽读透传,现为类型直读,行为零变)。
|
|
17
|
+
* **缺键=不写键**(绝不把缺键补成显式 false —— core 是唯一默认源,补 false 语义上等价但会伪造「center
|
|
18
|
+
* 说过话」的显式判决,污染 env-baseline 合成序,见 applyObserverEnvOptIn)。非 boolean 虽然骗不过 core
|
|
19
|
+
* 的 `=== true`(不会误 GRANT),但 PRESENT-非-boolean 与 allow* 同属同一 body 的契约破损信号 → 同款 THROW。
|
|
20
|
+
*
|
|
21
|
+
* `autoMode`(core 1.276.0 `RuntimeCaps.autoMode`):auto-mode 分类器 per-principal
|
|
22
|
+
* 开闸线,极性同 allowObservers(`=== true` 显式 opt-in,默认 OFF;真执行还要 deployment 装配
|
|
23
|
+
* `RunnerDeps.autoMode` 分类器面=信任门,center 键只是 entitlement 半场)。registry-core 类型未收编
|
|
24
|
+
* → unknown 宽读透传(allowObservers 0.10.2 期同款先例);center 发键即活。 */
|
|
5
25
|
export function toCoreRuntimeCaps(ent) {
|
|
6
26
|
if (!ent)
|
|
7
27
|
return undefined;
|
|
28
|
+
// 宽读(additive wide-read):registry-core 0.10.3 类型未含 autoMode,center 下发先行时走 unknown 读。
|
|
8
29
|
const autoMode = ent.autoMode;
|
|
9
30
|
const badCap = (v) => v !== undefined && typeof v !== "boolean";
|
|
10
31
|
if (badCap(ent.allowWorkflows) || badCap(ent.forceDurableGate) || badCap(ent.allowFork) || badCap(ent.allowObservers) || badCap(autoMode)) {
|
|
@@ -23,9 +44,23 @@ export function toCoreRuntimeCaps(ent) {
|
|
|
23
44
|
caps.autoMode = autoMode;
|
|
24
45
|
return Object.keys(caps).length ? caps : undefined;
|
|
25
46
|
}
|
|
47
|
+
/** A MISCONFIG diagnostic (review MEDIUM): a worker-scoped `wpt_<self>` pull token REQUIRES `?worker=<self>` to
|
|
48
|
+
* resolve per-principal caps — so a `wpt_` token with NO `SEMA_REGISTRY_WORKER` set will 403
|
|
49
|
+
* on every caps fetch → fail-closed DENY ALL workflows for ALL principals (correct degrade, but otherwise silent
|
|
50
|
+
* bar per-task warns). True ⇒ the caller should log a one-shot BOOT warning so the misconfig is diagnosable.
|
|
51
|
+
* (The orchestrator normally injects SEMA_REGISTRY_WORKER alongside a wpt_ token, so this is a hand-misconfig.) */
|
|
26
52
|
export function scopedTokenNeedsWorker(token, worker) {
|
|
27
53
|
return token.startsWith("wpt_") && !worker;
|
|
28
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Task-admission enforcement of the per-principal execution policy(stage7 P5 的「真强制」
|
|
57
|
+
* service 半场——壳侧锁定是易用性强制可绕,这里是引擎闸)。The lane is a WORKER-PROCESS identity
|
|
58
|
+
* (REMOTE_EXEC is boot wiring; there is no per-task lane switch), so the gate is "this worker's lane is not
|
|
59
|
+
* permitted for this principal ⇒ reject the task": typed 403 `execution_lane_not_allowed` carrying the
|
|
60
|
+
* allowlist + this worker's lane (machine code on the wire, prose stays with the shell/web).
|
|
61
|
+
* No ruling / required=false / caps blip ⇒ pass (fail-open + audit). `allowedLanes` is an
|
|
62
|
+
* OPEN domain — unknown names simply never match this worker's lane.
|
|
63
|
+
*/
|
|
29
64
|
export function gateExecutionLane(ruling, ownLane) {
|
|
30
65
|
if (!ruling?.required)
|
|
31
66
|
return;
|
|
@@ -36,6 +71,13 @@ export function gateExecutionLane(ruling, ownLane) {
|
|
|
36
71
|
});
|
|
37
72
|
}
|
|
38
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Build the per-principal caps client: `resolveRuntimeCaps` matches core's seam signature
|
|
76
|
+
* `(principal) => Promise<RuntimeCaps | undefined>`; `scenarioRuling` rides the SAME fetch/cache/in-flight
|
|
77
|
+
* (zero extra center RTT — center attaches the ruling to the caps body). Wire ONLY when a center is
|
|
78
|
+
* configured (and not in dry-run) — absent ⇒ core sees `undefined` ⇒ NO per-principal restriction, and the
|
|
79
|
+
* scenario gate sees `undefined` ⇒ legacy body-or-default chain.
|
|
80
|
+
*/
|
|
39
81
|
export function createPrincipalEntitlementsClient(opts) {
|
|
40
82
|
const ttlMs = opts.ttlMs ?? 60_000;
|
|
41
83
|
const denyTtlMs = opts.denyTtlMs ?? Math.min(ttlMs, 10_000);
|
|
@@ -45,6 +87,9 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
45
87
|
const onError = opts.onError ?? ((err, principal) => defaultLogger.warn("runtime_caps_resolve_failed", { principal, err: String(err) }));
|
|
46
88
|
const cache = new Map();
|
|
47
89
|
const inflight = new Map();
|
|
90
|
+
// Bound cache growth (review L1-1): `principal` is a per-user identity, so a long-lived worker — or a direct-door
|
|
91
|
+
// caller spoofing many principals — would accumulate one entry forever. On write, when the map crosses a soft cap,
|
|
92
|
+
// sweep logically-expired entries (TTL is a freshness gate, not eviction). Caps retention to ~the active set.
|
|
48
93
|
const MAX_CACHE = 10_000;
|
|
49
94
|
const putCache = (key, entry) => {
|
|
50
95
|
if (cache.size >= MAX_CACHE) {
|
|
@@ -55,17 +100,25 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
55
100
|
}
|
|
56
101
|
cache.set(key, entry);
|
|
57
102
|
};
|
|
103
|
+
// ONE loader behind both faces: fresh-cached entry → as-is; else fetch (in-flight-deduped) → cache → entry.
|
|
58
104
|
async function load(principal) {
|
|
59
105
|
const cached = cache.get(principal);
|
|
60
106
|
if (cached && cached.expiresAt > now())
|
|
61
107
|
return cached;
|
|
108
|
+
// Collapse concurrent prepare-time lookups for the SAME principal onto one in-flight fetch.
|
|
62
109
|
const dup = inflight.get(principal);
|
|
63
110
|
if (dup)
|
|
64
111
|
return dup;
|
|
65
112
|
const p = (async () => {
|
|
66
113
|
try {
|
|
114
|
+
// `cached?.etag` is set only on a real prior entry (an error entry clears it) → an `if-none-match` here can
|
|
115
|
+
// only 304-confirm a REAL value, never resurrect a stale deny. Pass `opts.worker` as `?worker=<self>` so a
|
|
116
|
+
// worker-scoped `wpt_<self>` token can resolve its OWN worker's principal caps; harmless
|
|
117
|
+
// on a full token (caps are worker-independent — the worker only scopes the config view we ignore).
|
|
67
118
|
const r = await fetchCaps(opts.baseUrl, opts.token, principal, cached?.etag, fetchImpl, opts.worker);
|
|
68
119
|
if (r === null) {
|
|
120
|
+
// 304 — unchanged. We only sent if-none-match because `cached` was a real entry → reuse caps AND the
|
|
121
|
+
// rulings (same body, same generation), refresh TTL.
|
|
69
122
|
const entry = {
|
|
70
123
|
caps: cached?.caps,
|
|
71
124
|
...(cached?.scenario ? { scenario: cached.scenario } : {}),
|
|
@@ -76,11 +129,14 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
76
129
|
putCache(principal, entry);
|
|
77
130
|
return entry;
|
|
78
131
|
}
|
|
132
|
+
// execution ruling shape drift = ruling dropped (fail-open) + THIS audit
|
|
133
|
+
// line — the "fail-open + audit" posture now covers the wire-drift direction too (previously a
|
|
134
|
+
// drifted allowedLanes coerced to [] = silent fleet-wide deny-all). Routed through onError (never throws).
|
|
79
135
|
if (r.executionDrift) {
|
|
80
136
|
try {
|
|
81
137
|
onError(new Error(`execution ruling wire drift: ${r.executionDrift}`), principal);
|
|
82
138
|
}
|
|
83
|
-
catch { }
|
|
139
|
+
catch { /* observability never breaks the resolver */ }
|
|
84
140
|
}
|
|
85
141
|
const entry = {
|
|
86
142
|
caps: toCoreRuntimeCaps(r.runtimeCaps),
|
|
@@ -94,12 +150,18 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
94
150
|
}
|
|
95
151
|
catch (err) {
|
|
96
152
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
153
|
+
// Caps face FAIL CLOSED: deny the OPTIONAL amplification caps (workflows + fork); never force the durable
|
|
154
|
+
// gate on error. Scenario face FAIL OPEN: `scenario` stays undefined (no governance — never pin users to
|
|
155
|
+
// the default scenario on a center blip; deliberate posture split, see PrincipalEntitlementsClient). Cache the
|
|
156
|
+
// deny for a SHORT window (bound center hammering on a sustained outage) WITHOUT an etag — so the next
|
|
157
|
+
// fetch is a full 200 pull that re-reads the real caps the moment center recovers (a 304 can't resurrect
|
|
158
|
+
// this deny). Write the deny BEFORE onError so a throwing observability hook can't escape before recording.
|
|
97
159
|
const entry = { caps: { allowWorkflows: false, allowFork: false }, expiresAt: now() + denyTtlMs };
|
|
98
160
|
putCache(principal, entry);
|
|
99
161
|
try {
|
|
100
162
|
onError(e, principal);
|
|
101
163
|
}
|
|
102
|
-
catch { }
|
|
164
|
+
catch { /* an observability hook must never break the resolver */ }
|
|
103
165
|
return entry;
|
|
104
166
|
}
|
|
105
167
|
finally {
|
|
@@ -110,25 +172,48 @@ export function createPrincipalEntitlementsClient(opts) {
|
|
|
110
172
|
return p;
|
|
111
173
|
}
|
|
112
174
|
return {
|
|
175
|
+
// No principal = an anonymous/system run with no per-principal identity → no per-principal restriction
|
|
176
|
+
// (tighten-only: absence falls back to the deployment-level default; core treats undefined as "no caps").
|
|
113
177
|
resolveRuntimeCaps: async (principal) => (principal ? (await load(principal)).caps : undefined),
|
|
114
178
|
scenarioRuling: async (principal) => (principal ? (await load(principal)).scenario : undefined),
|
|
115
179
|
executionRuling: async (principal) => (principal ? (await load(principal)).execution : undefined),
|
|
116
180
|
};
|
|
117
181
|
}
|
|
182
|
+
/** Back-compat face for core's seam-only consumers: the caps half of {@link createPrincipalEntitlementsClient}. */
|
|
118
183
|
export function createEntitlementsResolver(opts) {
|
|
119
184
|
return createPrincipalEntitlementsClient(opts).resolveRuntimeCaps;
|
|
120
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* observer 开闸线的 env 半场:`EXPERIMENTAL_OBSERVER_AGENTS=true` 时把
|
|
188
|
+
* `RuntimeCaps.allowObservers: true` 作为**部署基线**合成进 caps resolver(core 1.270.0/1.273.0 的
|
|
189
|
+
* observer 面是 `=== true` 显式 opt-in、默认 OFF —— 命名先例=CC 的 `CLAUDE_CODE_EXPERIMENTAL_OBSERVER_AGENTS`
|
|
190
|
+
* env 对儿)。租户姿势(与 FORK_ENABLED/SELF_ORCHESTRATION 同款判别):
|
|
191
|
+
* - **单用户部署**(`requirePrincipal !== true`,operator 即用户):env=true 直开 —— 无 center 时静态
|
|
192
|
+
* `{allowObservers:true}`;有 center 时作 BASELINE,**center caps 带键则 center 赢**(含显式 false;
|
|
193
|
+
* 缺键=center 没说话 → env 基线生效。这依赖 toCoreRuntimeCaps 缺键不补 false 的纪律 —— core 是唯一
|
|
194
|
+
* 默认源,center 只有真说了话才覆盖)。fail-closed 错误 entry(deny)不带 allowObservers 键 → 单用户
|
|
195
|
+
* env 基线在 center blip 期间维持(operator 在自己盒子上显式 opt-in 过;observers 非 workflows/fork
|
|
196
|
+
* 级的放大面,且 deny entry 的两把闸不受影响)。
|
|
197
|
+
* - **多租户**(`requirePrincipal === true`):env **不认**,只认 center caps(半配置 fail-loud:置了
|
|
198
|
+
* env 却多租户 → 一次 boot warn,行为零变——与 MEMORY_ENGINE_BACKEND 半配置同款姿势)。
|
|
199
|
+
* 返回合成后的 resolver;两边都无源(无 center、env 无效)⇒ undefined(RunnerDeps 不接线,零行为差)。
|
|
200
|
+
* ⚠️ 调用方注意:`Boolean(centerResolver)` 才是「entitlement resolver wired」语义(enableForkFromBody /
|
|
201
|
+
* selfOrchestrationFromBody 的多租户 fail-close 判别),不要改用本函数的返回值判 —— env-only lane 不是
|
|
202
|
+
* center 背书的 entitlement 源。
|
|
203
|
+
*/
|
|
121
204
|
export function applyObserverEnvOptIn(centerResolver, opts) {
|
|
122
205
|
if (!opts.experimentalObserverAgents)
|
|
123
|
-
return centerResolver;
|
|
206
|
+
return centerResolver; // env 未置 = 纯透传(多数部署路径,零成本)
|
|
124
207
|
if (opts.requirePrincipal) {
|
|
208
|
+
// 多租户不认 env(observer 是 per-principal 治理面,只认 center caps)——半配置 fail-loud 一次。
|
|
125
209
|
opts.warn?.("observer_env_opt_in_ignored", {
|
|
126
210
|
reason: "EXPERIMENTAL_OBSERVER_AGENTS=true is single-user only; a multi-tenant deployment (REQUIRE_PRINCIPAL=true) honors ONLY center caps allowObservers — env ignored, behavior unchanged",
|
|
127
211
|
});
|
|
128
212
|
return centerResolver;
|
|
129
213
|
}
|
|
130
214
|
if (!centerResolver)
|
|
131
|
-
return () => ({ allowObservers: true });
|
|
215
|
+
return () => ({ allowObservers: true }); // 单用户无 center:env 即静态开闸
|
|
216
|
+
// 单用户 + center:env 作 baseline,center 带键(true/false 皆)覆盖;缺键 → baseline 生效。
|
|
132
217
|
return async (principal) => ({ allowObservers: true, ...(await centerResolver(principal)) });
|
|
133
218
|
}
|
|
134
219
|
//# sourceMappingURL=runtime-caps-resolver.js.map
|
|
@@ -1,17 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime governance compiler — the "second baton" (center §10, core 1.114.0): turn the
|
|
3
|
+
* operator's declarative `runtime.autonomy` + `runtime.commandPolicy` (`@sema-agent/registry-core`,
|
|
4
|
+
* carried to the service via sema-registry `EffectiveConfig.runtime`) into TIGHTEN-ONLY overrides on the
|
|
5
|
+
* per-task `TaskSpec`. Pure so it is unit-testable in isolation (the spec is otherwise assembled inside
|
|
6
|
+
* main.ts's `resolveSpec`).
|
|
7
|
+
*
|
|
8
|
+
* 🪤 TWO TRAPS this module exists to NOT fall into (see core
|
|
9
|
+
* `tool-policy.ts` / `tighten-task-spec.ts` JSDoc):
|
|
10
|
+
*
|
|
11
|
+
* TRAP #1 — `TaskSpec.toolPolicy` OVERRIDES (not merges) `RunnerDeps.toolPolicy` (the runner does
|
|
12
|
+
* `spec.toolPolicy ?? deps.toolPolicy`). A bare `spec.toolPolicy = createCoarseCommandNamePolicy(…)` would
|
|
13
|
+
* SILENTLY DISCARD the deployment's approval/durable baseline. We compose via {@link tightenTaskSpec}, whose
|
|
14
|
+
* toolPolicy rule is `combinePolicies(base, override)` (deny-wins) — the command gate can only ADD denies/asks
|
|
15
|
+
* on top of the baseline, never clear it.
|
|
16
|
+
*
|
|
17
|
+
* TRAP #2 — `autonomy` must EXPAND INTO the three core primitives (`handsReadOnly` / `shellGate` / a
|
|
18
|
+
* `toolPolicy`), NOT become a parallel enum on the spec (design-research §10: a parallel `autonomy` field +
|
|
19
|
+
* `handsReadOnly:true` would conflict). The expansion is tighten-only and routed through `tightenTaskSpec`, so
|
|
20
|
+
* `auto` (the loosest mode) can never LOOSEN a stricter base — `tightenTaskSpec` THROWS instead.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ `commandPolicy` is a COARSE name-level filter, NOT a sandbox. `sh -c …` / `$(…)` / pipes / `env X=…` /
|
|
23
|
+
* path-prefixed commands all bypass the argv[0] match (they route to `ask`, fail-closed, but are not blocked by
|
|
24
|
+
* name). Real isolation is the `executionEnv` sandbox. Same caveat core documents on `createCoarseCommandNamePolicy`.
|
|
25
|
+
*/
|
|
1
26
|
import { type TaskSpec, type ToolPolicy } from "@sema-agent/core";
|
|
27
|
+
/** A per-command governance rule (registry `runtime.commandPolicy[]`). */
|
|
2
28
|
export type CommandRule = {
|
|
3
29
|
command: string;
|
|
4
30
|
decision: "allow" | "ask" | "deny";
|
|
5
31
|
};
|
|
32
|
+
/** True when `name` names a DELEGATION tool — the subagent tool (CC-187 canonical `"Agent"`, core 1.202
|
|
33
|
+
* `DEFAULT_SUBAGENT_TOOL_NAME`; legacy alias `"Task"`). CANONICAL-space compare (`canonicalToolName`) so both
|
|
34
|
+
* spellings match — the pre-1.202 raw `!== "Task"` compare in the read-only strip (main.ts) silently stopped
|
|
35
|
+
* matching when core renamed the tool (fail-open: a plan-mode / hands-read-only parent could delegate to a
|
|
36
|
+
* WRITABLE-hands child, because core does not propagate handsReadOnly to a delegated child).
|
|
37
|
+
* core 1.257 (design/136 BREAKING): the standalone `Fork` tool is retired — a fork is now
|
|
38
|
+
* `Agent(subagent_type:"fork")`, i.e. an Agent call, already matched by DEFAULT_SUBAGENT_TOOL_NAME. */
|
|
6
39
|
export declare function isDelegationToolName(name: string): boolean;
|
|
40
|
+
/** The hands-read-only DELEGATION STRIP (the main.ts governed-spec site, extracted here so the actual filter —
|
|
41
|
+
* not just the name predicate — is pinned by tests): core does not propagate `handsReadOnly` to a delegated
|
|
42
|
+
* child, so a read-only (plan-mode) run must not mount a delegation tool at all — the child would get WRITABLE
|
|
43
|
+
* hands, defeating the read-only contract. Identity (the same array) when nothing matches, so the caller's
|
|
44
|
+
* spec-object churn stays minimal. */
|
|
7
45
|
export declare function stripDelegationTools<T extends {
|
|
8
46
|
name: string;
|
|
9
47
|
}>(tools: readonly T[]): T[];
|
|
48
|
+
/** The operator autonomy mode (registry `runtime.autonomy`). */
|
|
10
49
|
export type Autonomy = "read-only" | "ask" | "plan" | "auto";
|
|
50
|
+
/** 导出给 的枚举式行为钉用(见那里的顶注:从 core 行为反推再比对)。 */
|
|
11
51
|
export declare const COARSE_SHELL_TOOLS_MIRROR: readonly string[];
|
|
52
|
+
/** Validate `commandPolicy` rules — the shape (array of {command, decision}), the `command` (a bare argv[0] name,
|
|
53
|
+
* see {@link VALID_COMMAND_NAME}), AND the `decision` enum. Returns the list of human-readable errors (empty =
|
|
54
|
+
* OK). Called at config-apply (sema-registry.ts `applyRuntimeHot`) so a malformed rule that BYPASSED the
|
|
55
|
+
* registry schema (a hand-edited config.d / a non-conformant publish) is rejected LOUDLY rather than
|
|
56
|
+
* silently mis-compiling — review MEDIUM: an out-of-enum `decision` (e.g. "DENY") would otherwise fall through
|
|
57
|
+
* {@link compileCommandPolicy}'s `decision==="deny"?…:"ask"` to ASK, silently WEAKENING an intended deny. */
|
|
12
58
|
export declare function validateCommandRules(rules: CommandRule[]): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Compile `runtime.commandPolicy` (per-command 3-way rules) into a single ToolPolicy, or `undefined` when there
|
|
61
|
+
* is nothing to govern. The registry model (per-command `allow`/`ask`/`deny`) and core's helper model
|
|
62
|
+
* (`allow[]` + `deny[]` + `defaultAction`) don't map 1:1, so the compilation picks a mode by the rules present:
|
|
63
|
+
*
|
|
64
|
+
* - **Allowlist mode** — triggered when ANY rule resolves to `allow`. Only `allow` commands pass; `deny` wins;
|
|
65
|
+
* EVERY other command — `ask`-decision AND unlisted — falls to `defaultAction:"ask"`.
|
|
66
|
+
* 🔴 OPERATOR FOOTGUN (documented contract): adding even one `allow` rule flips the whole policy to a strict
|
|
67
|
+
* allowlist — previously-passing unlisted commands now ASK.
|
|
68
|
+
* - **Blocklist mode** — no `allow` rules. Only `deny` commands are blocked; the rest pass THROUGH to the
|
|
69
|
+
* deployment baseline. Per-command `ask` is carried by {@link createCommandAskListPolicy} (the coarse helper
|
|
70
|
+
* can't express it). Un-parseable bypass commands fail toward `ask` in both the deny gate and the ask-list.
|
|
71
|
+
*
|
|
72
|
+
* Duplicate rules for the SAME command collapse to the STRICTEST decision (`deny > ask > allow`) BEFORE the mode
|
|
73
|
+
* split, so e.g. a command listed both `allow` and `ask` resolves to `ask` — honoring `combinePolicies`'
|
|
74
|
+
* strictest-wins (without this, the `allow` rule would shadow the `ask` for that command in allowlist mode).
|
|
75
|
+
*
|
|
76
|
+
* Either way the result only ever ADDS asks/denies — composed onto the baseline via `combinePolicies`
|
|
77
|
+
* (deny-wins) by {@link applyRuntimeGovernance}, so it is tighten-only. (Assumes commands are pre-validated by
|
|
78
|
+
* {@link validateCommandRules}; an un-matchable command here is simply inert, never a parse error.)
|
|
79
|
+
*/
|
|
13
80
|
export declare function compileCommandPolicy(rules: CommandRule[] | undefined): ToolPolicy | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Expand an autonomy mode into TIGHTEN-ONLY `TaskSpec` safety overrides (the three primitives — TRAP #2):
|
|
83
|
+
* - `read-only` / `plan` → `handsReadOnly: true` (read + propose, never mutate; the §6 verifier read-only
|
|
84
|
+
* boundary). `plan` shares the SAME safety boundary as `read-only`; the "present a plan for approval" intent
|
|
85
|
+
* is higher up (UX), not a distinct TaskSpec safety field, so both map to read-only hands.
|
|
86
|
+
* - `ask` → `shellGate: "always"` (every `Bash` command tightens to an `irreversible_ask` durable suspend —
|
|
87
|
+
* the fail-closed default for an unattended deployment with no parsed classifier).
|
|
88
|
+
* - `auto` / `undefined` → `{}` (no extra tightening; still subject to the deployment baseline + commandPolicy).
|
|
89
|
+
*/
|
|
14
90
|
export declare function autonomyOverrides(autonomy: Autonomy | undefined): Partial<TaskSpec>;
|
|
91
|
+
/**
|
|
92
|
+
* Apply the operator's runtime governance (autonomy + commandPolicy) onto a base `TaskSpec`, TIGHTEN-ONLY, in a
|
|
93
|
+
* SINGLE {@link tightenTaskSpec} call: commandPolicy compiles to a `toolPolicy` override (combined onto the
|
|
94
|
+
* baseline by `tightenTaskSpec` — TRAP #1), and autonomy expands to `handsReadOnly` / `shellGate` overrides
|
|
95
|
+
* (TRAP #2). `tightenTaskSpec` THROWS `TaskSpecTightenError` if any override would LOOSEN a stricter base safety
|
|
96
|
+
* field — surfacing a misconfiguration loudly instead of silently weakening the gate. Returns `base` untouched
|
|
97
|
+
* when there is nothing to apply (no autonomy override and no commandPolicy).
|
|
98
|
+
*/
|
|
15
99
|
export declare function applyRuntimeGovernance(base: TaskSpec, governance: {
|
|
16
100
|
autonomy?: Autonomy;
|
|
17
101
|
commandPolicy?: CommandRule[];
|
|
@@ -1,34 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime governance compiler — the "second baton" (center §10, core 1.114.0): turn the
|
|
3
|
+
* operator's declarative `runtime.autonomy` + `runtime.commandPolicy` (`@sema-agent/registry-core`,
|
|
4
|
+
* carried to the service via sema-registry `EffectiveConfig.runtime`) into TIGHTEN-ONLY overrides on the
|
|
5
|
+
* per-task `TaskSpec`. Pure so it is unit-testable in isolation (the spec is otherwise assembled inside
|
|
6
|
+
* main.ts's `resolveSpec`).
|
|
7
|
+
*
|
|
8
|
+
* 🪤 TWO TRAPS this module exists to NOT fall into (see core
|
|
9
|
+
* `tool-policy.ts` / `tighten-task-spec.ts` JSDoc):
|
|
10
|
+
*
|
|
11
|
+
* TRAP #1 — `TaskSpec.toolPolicy` OVERRIDES (not merges) `RunnerDeps.toolPolicy` (the runner does
|
|
12
|
+
* `spec.toolPolicy ?? deps.toolPolicy`). A bare `spec.toolPolicy = createCoarseCommandNamePolicy(…)` would
|
|
13
|
+
* SILENTLY DISCARD the deployment's approval/durable baseline. We compose via {@link tightenTaskSpec}, whose
|
|
14
|
+
* toolPolicy rule is `combinePolicies(base, override)` (deny-wins) — the command gate can only ADD denies/asks
|
|
15
|
+
* on top of the baseline, never clear it.
|
|
16
|
+
*
|
|
17
|
+
* TRAP #2 — `autonomy` must EXPAND INTO the three core primitives (`handsReadOnly` / `shellGate` / a
|
|
18
|
+
* `toolPolicy`), NOT become a parallel enum on the spec (design-research §10: a parallel `autonomy` field +
|
|
19
|
+
* `handsReadOnly:true` would conflict). The expansion is tighten-only and routed through `tightenTaskSpec`, so
|
|
20
|
+
* `auto` (the loosest mode) can never LOOSEN a stricter base — `tightenTaskSpec` THROWS instead.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ `commandPolicy` is a COARSE name-level filter, NOT a sandbox. `sh -c …` / `$(…)` / pipes / `env X=…` /
|
|
23
|
+
* path-prefixed commands all bypass the argv[0] match (they route to `ask`, fail-closed, but are not blocked by
|
|
24
|
+
* name). Real isolation is the `executionEnv` sandbox. Same caveat core documents on `createCoarseCommandNamePolicy`.
|
|
25
|
+
*/
|
|
1
26
|
import { canonicalToolName, combinePolicies, createCoarseCommandNamePolicy, DEFAULT_SUBAGENT_TOOL_NAME, parseLeadingCommandName, tightenTaskSpec, } from "@sema-agent/core";
|
|
27
|
+
/** True when `name` names a DELEGATION tool — the subagent tool (CC-187 canonical `"Agent"`, core 1.202
|
|
28
|
+
* `DEFAULT_SUBAGENT_TOOL_NAME`; legacy alias `"Task"`). CANONICAL-space compare (`canonicalToolName`) so both
|
|
29
|
+
* spellings match — the pre-1.202 raw `!== "Task"` compare in the read-only strip (main.ts) silently stopped
|
|
30
|
+
* matching when core renamed the tool (fail-open: a plan-mode / hands-read-only parent could delegate to a
|
|
31
|
+
* WRITABLE-hands child, because core does not propagate handsReadOnly to a delegated child).
|
|
32
|
+
* core 1.257 (design/136 BREAKING): the standalone `Fork` tool is retired — a fork is now
|
|
33
|
+
* `Agent(subagent_type:"fork")`, i.e. an Agent call, already matched by DEFAULT_SUBAGENT_TOOL_NAME. */
|
|
2
34
|
export function isDelegationToolName(name) {
|
|
3
35
|
const c = canonicalToolName(name);
|
|
4
36
|
return c === DEFAULT_SUBAGENT_TOOL_NAME;
|
|
5
37
|
}
|
|
38
|
+
/** The hands-read-only DELEGATION STRIP (the main.ts governed-spec site, extracted here so the actual filter —
|
|
39
|
+
* not just the name predicate — is pinned by tests): core does not propagate `handsReadOnly` to a delegated
|
|
40
|
+
* child, so a read-only (plan-mode) run must not mount a delegation tool at all — the child would get WRITABLE
|
|
41
|
+
* hands, defeating the read-only contract. Identity (the same array) when nothing matches, so the caller's
|
|
42
|
+
* spec-object churn stays minimal. */
|
|
6
43
|
export function stripDelegationTools(tools) {
|
|
7
44
|
const kept = tools.filter((t) => !isDelegationToolName(t.name));
|
|
8
45
|
return kept.length === tools.length ? tools : kept;
|
|
9
46
|
}
|
|
47
|
+
/** The shell tool names a command-name gate parses. Mirrors core's (un-exported) `COARSE_SHELL_TOOLS` default so
|
|
48
|
+
* the ask-list policy below gates the SAME tools `createCoarseCommandNamePolicy` does. A unit test pins behavior
|
|
49
|
+
* (a `Bash` ask-command asks) so a core rename surfaces as a red test, not silent drift.
|
|
50
|
+
* Q6 (core 1.161): tool names align to CC — `bash`→`Bash`; the old `bash_readonly` MERGED into `Bash` (read-only is
|
|
51
|
+
* now a toolEffect, not a separate tool).
|
|
52
|
+
*
|
|
53
|
+
* 🔴 2026-07-26:core 1.414 把默认从 `["Bash"]` 改成 `["Bash","Monitor"]`(Monitor 走同一条执行 seam,此前是
|
|
54
|
+
* 两条 always-on 门的旁门;core 的端到端实证:同一条 `rm -rf $(cat targets)`,Bash 被拒、**Monitor 零门执行**)。
|
|
55
|
+
* 我这份镜像因此漂了,后果是 **blocklist 模式下我的 ask-list 不覆盖 Monitor 而 core 的 deny 覆盖**。
|
|
56
|
+
* ⚠️ 更要紧的是**旧的钉抓不到这次加名** —— 它只钉了「一条 Bash 的 ask-command 会 ask」,加一个新名字它照样绿
|
|
57
|
+
* (core [1707]③ 明确点了这条)。现在的钉改成**枚举式且从 core 的行为反推**:
|
|
58
|
+
* `test/coarse-shell-tools-mirror.test.ts` 拿 core 导出的 `createCoarseCommandNamePolicy()`(默认参)去逐个探
|
|
59
|
+
* 候选工具名,把「core 真的门了哪些」测出来,再断言本常量**等于**那个集合。
|
|
60
|
+
* 这样做的理由:core 的 `COARSE_SHELL_TOOLS` **未导出**,而扫它的 dist 源码只能挡写法不挡行为
|
|
61
|
+
* (core RB-149 的教训:一个变异靠换写法就穿过了源码扫描)。 */
|
|
10
62
|
const COARSE_SHELL_TOOLS = ["Bash", "Monitor"];
|
|
63
|
+
/** 导出给 的枚举式行为钉用(见那里的顶注:从 core 行为反推再比对)。 */
|
|
11
64
|
export const COARSE_SHELL_TOOLS_MIRROR = COARSE_SHELL_TOOLS;
|
|
65
|
+
/**
|
|
66
|
+
* A per-command ask-list ToolPolicy: a parsed shell command whose `argv[0]` is in `askCommands` tightens to
|
|
67
|
+
* `ask`; everything else passes (`allow`). core's `createCoarseCommandNamePolicy` has NO per-command ask list
|
|
68
|
+
* (only `allow[]` / `deny[]` / `defaultAction`), so blocklist-mode "ask before THIS command, pass the rest"
|
|
69
|
+
* cannot be expressed by it — this thin policy carries the `ask` decisions. It reuses core's
|
|
70
|
+
* `parseLeadingCommandName` (the SINGLE source-of-truth simple-command parser used by the `Bash` tool and
|
|
71
|
+
* `createCoarseCommandNamePolicy`), so the argv[0]-bypass surface (operators / pipes / `env=` / path-prefix)
|
|
72
|
+
* routes to `ask` (fail toward the gate), never silent-allow.
|
|
73
|
+
*/
|
|
12
74
|
function createCommandAskListPolicy(askCommands, tools = COARSE_SHELL_TOOLS) {
|
|
13
75
|
const askSet = new Set(askCommands);
|
|
14
76
|
const shellTools = new Set(tools);
|
|
15
77
|
const ask = (message) => ({ action: "ask", message, decisionReason: "rule" });
|
|
16
78
|
return {
|
|
17
79
|
check(req) {
|
|
80
|
+
// Out of scope for non-shell tools: this gate only speaks about shell command names. Canonical-space
|
|
81
|
+
// lookup ("Bash" has no alias today — identity; uniform with every other service policy face, so a
|
|
82
|
+
// future core alias or a pre-rename durable replay can't slip the gate).
|
|
18
83
|
if (!shellTools.has(canonicalToolName(req.toolName)))
|
|
19
84
|
return { action: "allow" };
|
|
20
85
|
const command = req.args?.command;
|
|
21
86
|
if (typeof command !== "string")
|
|
22
87
|
return ask(`tool "${req.toolName}" call has no parseable command string`);
|
|
23
88
|
const parsed = parseLeadingCommandName(command);
|
|
89
|
+
// Un-parseable (operators / path-prefix / env-assignment) = exactly the argv[0]-bypass surface → gate it.
|
|
24
90
|
if ("reject" in parsed)
|
|
25
91
|
return ask(`command is not a single simple command (${parsed.reject})`);
|
|
26
92
|
return askSet.has(parsed.name) ? ask(`command "${parsed.name}" requires approval by policy`) : { action: "allow" };
|
|
27
93
|
},
|
|
28
94
|
};
|
|
29
95
|
}
|
|
96
|
+
/** A valid `commandPolicy` rule targets a bare argv[0] command NAME. core's `createCoarseCommandNamePolicy` does
|
|
97
|
+
* EXACT `Set` matching (NOT glob, NOT last-match-wins — the §10 verdict deliberately downgraded the original
|
|
98
|
+
* `createCommandGlobPolicy` idea), so a glob like `git*` or a path `/usr/bin/rm` or `npm i`
|
|
99
|
+
* would SILENTLY never match a parsed argv[0] → the command would slip the gate. We accept only bare-name tokens
|
|
100
|
+
* (letters/digits and `. _ - +`, covering `python3.11`/`docker-compose`/`g++`) and reject the rest FAIL-LOUD at
|
|
101
|
+
* config-apply. 🔴 Kept ALIGNED with the `@sema-agent/registry-core` contract-layer regex (center fixed the
|
|
102
|
+
* glob→exact contract bug in 0.1.26 + publish-validates with this SAME pattern) so the contract gate and this
|
|
103
|
+
* defense-in-depth gate agree. The dep is
|
|
104
|
+
* `^0.1.26` (additive-compatible), so an additive contract bump stays aligned; a contract regex CHANGE would
|
|
105
|
+
* need this updated in lockstep (the two layers are coupled by design, not by a frozen byte-equality guarantee). */
|
|
30
106
|
const VALID_COMMAND_NAME = /^[A-Za-z0-9._+-]+$/;
|
|
107
|
+
/** The three legal per-command decisions (mirrors the registry `runtime.commandPolicy[].decision` enum). */
|
|
31
108
|
const VALID_DECISIONS = new Set(["allow", "ask", "deny"]);
|
|
109
|
+
/** Validate `commandPolicy` rules — the shape (array of {command, decision}), the `command` (a bare argv[0] name,
|
|
110
|
+
* see {@link VALID_COMMAND_NAME}), AND the `decision` enum. Returns the list of human-readable errors (empty =
|
|
111
|
+
* OK). Called at config-apply (sema-registry.ts `applyRuntimeHot`) so a malformed rule that BYPASSED the
|
|
112
|
+
* registry schema (a hand-edited config.d / a non-conformant publish) is rejected LOUDLY rather than
|
|
113
|
+
* silently mis-compiling — review MEDIUM: an out-of-enum `decision` (e.g. "DENY") would otherwise fall through
|
|
114
|
+
* {@link compileCommandPolicy}'s `decision==="deny"?…:"ask"` to ASK, silently WEAKENING an intended deny. */
|
|
32
115
|
export function validateCommandRules(rules) {
|
|
33
116
|
const errors = [];
|
|
34
117
|
if (!Array.isArray(rules))
|
|
@@ -49,9 +132,31 @@ export function validateCommandRules(rules) {
|
|
|
49
132
|
}
|
|
50
133
|
return errors;
|
|
51
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Compile `runtime.commandPolicy` (per-command 3-way rules) into a single ToolPolicy, or `undefined` when there
|
|
137
|
+
* is nothing to govern. The registry model (per-command `allow`/`ask`/`deny`) and core's helper model
|
|
138
|
+
* (`allow[]` + `deny[]` + `defaultAction`) don't map 1:1, so the compilation picks a mode by the rules present:
|
|
139
|
+
*
|
|
140
|
+
* - **Allowlist mode** — triggered when ANY rule resolves to `allow`. Only `allow` commands pass; `deny` wins;
|
|
141
|
+
* EVERY other command — `ask`-decision AND unlisted — falls to `defaultAction:"ask"`.
|
|
142
|
+
* 🔴 OPERATOR FOOTGUN (documented contract): adding even one `allow` rule flips the whole policy to a strict
|
|
143
|
+
* allowlist — previously-passing unlisted commands now ASK.
|
|
144
|
+
* - **Blocklist mode** — no `allow` rules. Only `deny` commands are blocked; the rest pass THROUGH to the
|
|
145
|
+
* deployment baseline. Per-command `ask` is carried by {@link createCommandAskListPolicy} (the coarse helper
|
|
146
|
+
* can't express it). Un-parseable bypass commands fail toward `ask` in both the deny gate and the ask-list.
|
|
147
|
+
*
|
|
148
|
+
* Duplicate rules for the SAME command collapse to the STRICTEST decision (`deny > ask > allow`) BEFORE the mode
|
|
149
|
+
* split, so e.g. a command listed both `allow` and `ask` resolves to `ask` — honoring `combinePolicies`'
|
|
150
|
+
* strictest-wins (without this, the `allow` rule would shadow the `ask` for that command in allowlist mode).
|
|
151
|
+
*
|
|
152
|
+
* Either way the result only ever ADDS asks/denies — composed onto the baseline via `combinePolicies`
|
|
153
|
+
* (deny-wins) by {@link applyRuntimeGovernance}, so it is tighten-only. (Assumes commands are pre-validated by
|
|
154
|
+
* {@link validateCommandRules}; an un-matchable command here is simply inert, never a parse error.)
|
|
155
|
+
*/
|
|
52
156
|
export function compileCommandPolicy(rules) {
|
|
53
157
|
if (!rules || rules.length === 0)
|
|
54
158
|
return undefined;
|
|
159
|
+
// Collapse per command to the strictest decision (deny > ask > allow) so a duplicate can't shadow a stricter one.
|
|
55
160
|
const RANK = { deny: 3, ask: 2, allow: 1 };
|
|
56
161
|
const strictest = new Map();
|
|
57
162
|
for (const r of rules) {
|
|
@@ -67,9 +172,13 @@ export function compileCommandPolicy(rules) {
|
|
|
67
172
|
}
|
|
68
173
|
const policies = [];
|
|
69
174
|
if (allow.length > 0) {
|
|
175
|
+
// Allowlist mode: `allow` passes, `deny` wins, `ask`-decision + unlisted fall to defaultAction "ask".
|
|
70
176
|
policies.push(createCoarseCommandNamePolicy({ allow, deny, defaultAction: "ask" }));
|
|
71
177
|
}
|
|
72
178
|
else {
|
|
179
|
+
// Blocklist mode: only `deny` blocks; per-command `ask` via the ask-list; unlisted pass through.
|
|
180
|
+
// (NOTE: never pass `allow: []` to the coarse helper — an empty array is truthy there and would turn it
|
|
181
|
+
// into an allowlist that asks on EVERYTHING. Omit allow entirely instead.)
|
|
73
182
|
if (deny.length > 0)
|
|
74
183
|
policies.push(createCoarseCommandNamePolicy({ deny }));
|
|
75
184
|
if (ask.length > 0)
|
|
@@ -79,6 +188,15 @@ export function compileCommandPolicy(rules) {
|
|
|
79
188
|
return undefined;
|
|
80
189
|
return policies.length === 1 ? policies[0] : combinePolicies(...policies);
|
|
81
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Expand an autonomy mode into TIGHTEN-ONLY `TaskSpec` safety overrides (the three primitives — TRAP #2):
|
|
193
|
+
* - `read-only` / `plan` → `handsReadOnly: true` (read + propose, never mutate; the §6 verifier read-only
|
|
194
|
+
* boundary). `plan` shares the SAME safety boundary as `read-only`; the "present a plan for approval" intent
|
|
195
|
+
* is higher up (UX), not a distinct TaskSpec safety field, so both map to read-only hands.
|
|
196
|
+
* - `ask` → `shellGate: "always"` (every `Bash` command tightens to an `irreversible_ask` durable suspend —
|
|
197
|
+
* the fail-closed default for an unattended deployment with no parsed classifier).
|
|
198
|
+
* - `auto` / `undefined` → `{}` (no extra tightening; still subject to the deployment baseline + commandPolicy).
|
|
199
|
+
*/
|
|
82
200
|
export function autonomyOverrides(autonomy) {
|
|
83
201
|
switch (autonomy) {
|
|
84
202
|
case "read-only":
|
|
@@ -91,13 +209,21 @@ export function autonomyOverrides(autonomy) {
|
|
|
91
209
|
return {};
|
|
92
210
|
}
|
|
93
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Apply the operator's runtime governance (autonomy + commandPolicy) onto a base `TaskSpec`, TIGHTEN-ONLY, in a
|
|
214
|
+
* SINGLE {@link tightenTaskSpec} call: commandPolicy compiles to a `toolPolicy` override (combined onto the
|
|
215
|
+
* baseline by `tightenTaskSpec` — TRAP #1), and autonomy expands to `handsReadOnly` / `shellGate` overrides
|
|
216
|
+
* (TRAP #2). `tightenTaskSpec` THROWS `TaskSpecTightenError` if any override would LOOSEN a stricter base safety
|
|
217
|
+
* field — surfacing a misconfiguration loudly instead of silently weakening the gate. Returns `base` untouched
|
|
218
|
+
* when there is nothing to apply (no autonomy override and no commandPolicy).
|
|
219
|
+
*/
|
|
94
220
|
export function applyRuntimeGovernance(base, governance) {
|
|
95
221
|
const overrides = { ...autonomyOverrides(governance.autonomy) };
|
|
96
222
|
const coarse = compileCommandPolicy(governance.commandPolicy);
|
|
97
223
|
if (coarse)
|
|
98
224
|
overrides.toolPolicy = coarse;
|
|
99
225
|
if (overrides.toolPolicy === undefined && overrides.handsReadOnly === undefined && overrides.shellGate === undefined) {
|
|
100
|
-
return base;
|
|
226
|
+
return base; // nothing to govern → avoid a needless tightenTaskSpec pass
|
|
101
227
|
}
|
|
102
228
|
return tightenTaskSpec(base, overrides);
|
|
103
229
|
}
|