@sema-agent/server 7.132.0 → 7.134.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/MIGRATION.md +353 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +301 -64
- package/deploy/sema-up/README.md +35 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
- package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
- package/deploy/sema-up/chart/templates/server.yaml +19 -2
- package/deploy/sema-up/chart/values-full-single.yaml +5 -1
- package/deploy/sema-up/chart/values.yaml +34 -0
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +32 -14
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +83 -23
- package/dist/approval-card.js +45 -15
- package/dist/approval-content-kind.d.ts +5 -2
- package/dist/approval-content-kind.js +16 -3
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +72 -0
- package/dist/approval-gate-currency.js +94 -0
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +55 -17
- package/dist/audit.d.ts +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/coordinators.d.ts +6 -1
- package/dist/boot/coordinators.js +6 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/execution-env.js +9 -7
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.d.ts +2 -0
- package/dist/boot/leader.js +4 -1
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/read-deny-anchor-audit.js +2 -2
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +60 -81
- package/dist/boot/runner-deps.d.ts +18 -5
- package/dist/boot/runner-deps.js +10 -0
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-06-runners.d.ts +6 -3
- package/dist/boot/stage-06-runners.js +20 -4
- package/dist/boot/stage-07-capability-layer.d.ts +4 -1
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +4 -1
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +5 -1
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +5 -1
- package/dist/boot/stage-10-http-server.js +6 -6
- package/dist/boot/stores.d.ts +8 -0
- package/dist/boot/stores.js +10 -14
- package/dist/boot/web-admin.d.ts +10 -0
- package/dist/boot/web-admin.js +162 -65
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +8 -3
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/budget.js +5 -1
- package/dist/caller-text-echo.d.ts +11 -6
- package/dist/caller-text-echo.js +10 -12
- package/dist/canonical-json.d.ts +2 -41
- package/dist/canonical-json.js +2 -13
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +21 -0
- package/dist/capabilities/hands-lane.js +10 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -4
- package/dist/capabilities/mcp-probe.js +29 -6
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- package/dist/capability-facts.d.ts +36 -4
- package/dist/capability-facts.js +30 -4
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
- package/dist/checkpoint-ctx-seal-m28.js +19 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +43 -28
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-provider.d.ts +6 -1
- package/dist/config-provider.js +6 -2
- package/dist/config-types.d.ts +71 -14
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +121 -59
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -23
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/execution-lane-caps.d.ts +49 -10
- package/dist/execution-lane-caps.js +43 -4
- package/dist/field-conflict.d.ts +44 -0
- package/dist/field-conflict.js +21 -0
- package/dist/file-history-disclosure.d.ts +34 -5
- package/dist/file-history-disclosure.js +2 -2
- package/dist/fleet/fleet-bus.d.ts +84 -6
- package/dist/fleet/fleet-bus.js +42 -9
- package/dist/hooks/classic-stations.d.ts +10 -5
- package/dist/hooks/classic-stations.js +4 -4
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.js +2 -2
- package/dist/hooks/hook-runner.d.ts +127 -25
- package/dist/hooks/hook-runner.js +668 -287
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.js +111 -60
- package/dist/http/approval-sweeps.js +58 -19
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +173 -18
- package/dist/http/checkpoint-ctx.js +171 -12
- package/dist/http/claimed-run.d.ts +4 -3
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +2 -1
- package/dist/http/dispatch.js +13 -7
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +37 -12
- package/dist/http/idempotency.d.ts +2 -2
- package/dist/http/idempotency.js +2 -2
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +78 -27
- package/dist/http/principal-gate.js +64 -14
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/refusal-body.d.ts +12 -0
- package/dist/http/refusal-body.js +11 -0
- package/dist/http/request-guards.d.ts +16 -32
- package/dist/http/request-guards.js +31 -30
- package/dist/http/resume-ctx-read.d.ts +50 -6
- package/dist/http/resume-ctx-read.js +33 -7
- package/dist/http/resume-legs.d.ts +5 -5
- package/dist/http/resume-legs.js +163 -91
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -37
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +91 -56
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +20 -4
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +6 -2
- package/dist/http/routes/fleet.js +4 -4
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +9 -22
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +63 -115
- package/dist/http/routes/session-sync.d.ts +3 -2
- package/dist/http/routes/session-sync.js +53 -48
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions-list.js +3 -4
- package/dist/http/routes/sessions.js +33 -43
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +71 -30
- package/dist/http/routes/trace-usage.js +7 -9
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/run-declared-families.d.ts +16 -0
- package/dist/http/run-declared-families.js +12 -0
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +23 -18
- package/dist/http/server.js +20 -15
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.d.ts +4 -3
- package/dist/http/submit-ctx.js +23 -6
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +17 -10
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/lane-home-probe.d.ts +78 -9
- package/dist/lane-home-probe.js +78 -12
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/leader/wire.d.ts +4 -0
- package/dist/leader/wire.js +8 -7
- package/dist/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/memory-origin-fence.js +2 -2
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +23 -16
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-compat.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +5 -0
- package/dist/model-provider.js +4 -2
- package/dist/model-route-endpoint.d.ts +8 -11
- package/dist/model-route-endpoint.js +4 -7
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +35 -9
- package/dist/observability/fail-open.js +35 -9
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/prompt-manifest.d.ts +22 -25
- package/dist/observability/prompt-manifest.js +54 -50
- package/dist/observability/tool-trace.js +9 -10
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +119 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +43 -11
- package/dist/parked-decide.js +100 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/permission-rule-vocab.d.ts +1 -23
- package/dist/permission-rule-vocab.js +0 -13
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
- package/dist/plugins/approval-payload-fingerprint.js +1 -1
- package/dist/plugins/blob-backend.d.ts +38 -25
- package/dist/plugins/blob-backend.js +29 -19
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +4 -1
- package/dist/plugins/caching-session-store.js +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
- package/dist/plugins/checkpoint-store-sql.js +65 -3
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/local-checkpoint-store.d.ts +15 -2
- package/dist/plugins/local-checkpoint-store.js +32 -1
- package/dist/plugins/local-session-store.d.ts +13 -10
- package/dist/plugins/local-session-store.js +23 -14
- package/dist/plugins/local-session-window.d.ts +45 -0
- package/dist/plugins/local-session-window.js +38 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +121 -5
- package/dist/plugins/one-time-migrations.js +332 -8
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/permission-rule-store-file.js +10 -6
- package/dist/plugins/permission-rule-store-sql.js +8 -8
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +18 -5
- package/dist/plugins/pg-session-storage.js +68 -23
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- package/dist/plugins/remote-env-device.d.ts +14 -7
- package/dist/plugins/remote-env-device.js +23 -15
- package/dist/plugins/remote-env-k8s.d.ts +8 -12
- package/dist/plugins/remote-env-k8s.js +23 -5
- package/dist/plugins/remote-env-local-docker.d.ts +10 -15
- package/dist/plugins/remote-env-local-docker.js +12 -9
- package/dist/plugins/remote-env-ssh.d.ts +10 -16
- package/dist/plugins/remote-env-ssh.js +17 -11
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +32 -6
- package/dist/plugins/session-epoch-anchor.js +2 -3
- package/dist/plugins/session-ownership.d.ts +11 -0
- package/dist/plugins/session-ownership.js +11 -0
- package/dist/plugins/session-placement.d.ts +12 -14
- package/dist/plugins/session-placement.js +2 -15
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/sql-driver.d.ts +74 -11
- package/dist/plugins/sql-driver.js +210 -12
- package/dist/plugins/sql-errors.d.ts +23 -0
- package/dist/plugins/sql-errors.js +21 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +40 -14
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +3 -2
- package/dist/plugins/tidb-session-storage.js +2 -2
- package/dist/plugins/tidb-session-store.d.ts +25 -5
- package/dist/plugins/tidb-session-store.js +67 -21
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +7 -0
- package/dist/request-key-closure.js +9 -1
- package/dist/request-tool-axes.d.ts +12 -0
- package/dist/request-tool-axes.js +20 -0
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +26 -2
- package/dist/rule-entry-list.js +72 -12
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +37 -6
- package/dist/runs.d.ts +12 -10
- package/dist/runs.js +25 -6
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/sealed-key.d.ts +32 -0
- package/dist/sealed-key.js +55 -1
- package/dist/security.d.ts +95 -15
- package/dist/security.js +52 -9
- package/dist/session-error-wire.d.ts +31 -7
- package/dist/session-error-wire.js +9 -2
- package/dist/session-sync-kernel.d.ts +37 -10
- package/dist/session-sync-kernel.js +10 -0
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +15 -4
- package/dist/spec-fields.js +21 -2
- package/dist/sql-engine-posture.d.ts +3 -1
- package/dist/task-a2a.js +4 -3
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +5 -5
- package/dist/task-mcp.js +27 -74
- package/dist/task-settings.d.ts +93 -88
- package/dist/task-settings.js +71 -63
- package/dist/text-bidi.d.ts +0 -4
- package/dist/text-bidi.js +1 -3
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +451 -136
- package/dist/tool-approval.js +733 -256
- package/dist/tool-rule-names.d.ts +6 -0
- package/dist/trace/core-keyset-guard.d.ts +108 -25
- package/dist/trace/exit-seat.d.ts +40 -0
- package/dist/trace/exit-seat.js +130 -0
- package/dist/trace/ledger-events.d.ts +6 -3
- package/dist/trace/project.d.ts +98 -13
- package/dist/trace/project.js +57 -32
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +57 -0
- package/dist/trace/redact.js +962 -168
- package/dist/trace/self-minted-wire.d.ts +349 -1
- package/dist/trace/self-minted-wire.js +118 -1
- package/dist/trace/wire-projection-faces.d.ts +304 -2
- package/dist/trace/wire-projection-faces.js +160 -13
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.js +6 -8
- package/dist/web-admin-client/types.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +8 -4
- package/scripts/drain-check-local.mjs +34 -2
- package/scripts/drain-check.mysql.sql +20 -2
- package/scripts/drain-check.pg.sql +20 -2
- package/dist/mcp-tool-faces.d.ts +0 -69
- package/dist/mcp-tool-faces.js +0 -106
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一张停驻审批卡的「门」此刻还是不是它 —— 应答口判 `approval_stale` 与按问读口 `state` 的**同一只判官**。
|
|
3
|
+
*
|
|
4
|
+
* ## 病灶(为什么要有这一只)
|
|
5
|
+
* 问账行 `PARKED` 是终态(`approval-ask-machine.ts`:`PARKED: []`):赎回腿的单赢者是 **checkpoint 的 CAS**,取消腿动的也是 checkpoint(先 `expire` 门、再驱 run 终局),
|
|
6
|
+
* 两条腿都不写 ask 行。于是「这张卡的门还在不在」这件事只有 checkpoint 店知道;读口若只看行,就会在卡被答过 / run 被取消之后继续说 `parked` 并指路去决定,
|
|
7
|
+
* 而应答口对同一张卡早已答 `409 approval_stale`。同一件事两个读法 —— 本模块把它收成一个:读的是同一个问题、同一个来源。
|
|
8
|
+
*
|
|
9
|
+
* ## 判官
|
|
10
|
+
* 问题:**这把 gate token 是不是该会话当前待决的审批门?**(应答口的答法:`resumeCheckpoint` 的 stale 臂 —— 回显的 token ≠ 该会话当前待决的审批门 ⇒ `409 approval_stale`。)
|
|
11
|
+
* · {@link currentApprovalGateToken} —— 该会话当前待决的审批门(审批门型优先,没有再退到任一待决行);应答口读它,读口读它,别处不再内联第二份;
|
|
12
|
+
* · {@link readGateCurrency} —— 一把 token 对着它的读数:`current` / `absent`(店里没有这一行)/ `settled`(行在,但不再是当前待决门:已结算、已过期、被取代);
|
|
13
|
+
* · {@link createParkedGateRead} —— 协调器读口的门读席:把读数译成读口要的四种读法({@link ParkedGateReading}),`state` 闭集不加字。
|
|
14
|
+
*
|
|
15
|
+
* ## `settled` 怎么译(读口只说 checkpoint 上有凭据的话;一条规矩)
|
|
16
|
+
* 落盘的行不受类型面约束(旧版 / 手改 / 坏体 / 更新版本 core 写下的行可带闭集外的词或坏形),所以已结算门只按**一条规矩**读:
|
|
17
|
+
* ① 两个闭集词(行的 `status`、结算记录的种类 `settlement.kind`)各查一张穷举表,**同一查法**({@link throughTable}:只认表自己的键,非字符串不进表):
|
|
18
|
+
* 表明说 `decided` ⇒ 往下读;明说 `void` ⇒ `void`(没有人决过它,答案无处兑现 —— 已过期〔取消 / 收割〕、仍待决却不是当前门〔被取代,应答口答 stale〕、
|
|
19
|
+
* 结算种类是引擎窗到期 / 宿主 SLA 扫 / 无人可答的失败族);**表外 ⇒ `unknown`**(读不懂的词撑不起「有人决过」,也撑不起「没有人决过它」);
|
|
20
|
+
* ② 结算赢家的门记录 `resolvedOutcome.gateOutcome` 先过 core 唯一的门记录筛 `screenGateOutcome`(**档案读法**:读回的耐久行,闭集 = 今日成员 ∪ 已退役词;
|
|
21
|
+
* 坏形记缺陷、绝不抛;本仓 `trace/project.ts` 投影同一种记录也只经这一只筛),有缺陷 ⇒ `unknown`,过了筛才读它的成员;
|
|
22
|
+
* ③ 分类之前记录要**读得全**:有结算记录、时刻(引擎写进赢家的 `settlement.when`)是有限数、赢家绑的是这一行的调用且判词是 allow / deny(与
|
|
23
|
+
* `findDecidedApprovalsForBinding` 同一只 {@link approvalDecisionOfWinner})—— 缺一个都是 `unknown`(**不编一个首决**;读口答 404,应答口对已结算的门答 409 `approval_stale`,两口不同判;
|
|
24
|
+
* `void` 也要读得全:绑在别的调用上的结算说的不是这张卡);读全了再按**结算种类**表分类:人 / 策略的四个种类 ⇒ `decided`(理由取自赢家的 `reason`),其余十个 ⇒ `void`
|
|
25
|
+
* (按种类不按当事方:跨版本稳定的是种类词,变过义的是当事方词 —— 此前版本的策略拒记 `policy_refused` + `who.party:"none"`,此后记 `"policy"`,按当事方查会把那一代合法历史记录读成 `void`);
|
|
26
|
+
* ④ 读的只是行的内容、不碰店:内容坏到读的时候抛(行上缺了必填成员)同样是坏行 ⇒ `unknown`,不冒成店故障(读口对店故障退回 `parked`)。
|
|
27
|
+
* `unknown` 的这一类(`decision_unreadable`)带上读不出的那几处(缺陷句,非空):读口答 404 `tool_approval.not_pending`,并记一行 error(首句 + 计数)。
|
|
28
|
+
* 行没了 ⇒ `unknown`(`row_absent`;应答口 PARKED 臂的 404 `not_found.approval` 同判)。
|
|
29
|
+
*
|
|
30
|
+
* ## 盲区(core 的筛不判的两处,如实写下:一处本判官手判有限数,一处本判官也不核)
|
|
31
|
+
* · 结算时刻 `settlement.when`:筛不判,本判官手判「有限数」;而本仓另一个读同一种记录的读者(trace 投影)把 `when` 原样放上 wire —— 同一个坏时刻,两个读者两种答法;
|
|
32
|
+
* · 方向与配对:赢家的方向(`resolvedOutcome.decision`)与记录自己的种类 / 处置说的方向是否一致,以及种类 × 当事方的配对 —— 筛不判,本判官也不核:读口以赢家的方向为准、读的是种类。
|
|
33
|
+
* 只有坏行 / 手改行才走得到这两处。候引擎的筛把时刻、方向与种类 × 当事方配对一并判了,两个读者同时退掉各自的手判(配对今天没有手判可退 —— 它无人判)。
|
|
34
|
+
*/
|
|
35
|
+
import { type Checkpoint, type CheckpointToken, type SettlementKind } from "@sema-agent/core";
|
|
36
|
+
import { type PendingRowBinding } from "./plugins/checkpoint-store-sql.js";
|
|
37
|
+
import { type ParkedGateRead } from "./tool-approval.js";
|
|
38
|
+
/** 判官要的两个店口(三后端同形;窄接口让测试与装配都不必拿整只店)。 */
|
|
39
|
+
export interface GateCurrencyStore {
|
|
40
|
+
get(token: CheckpointToken): Promise<Checkpoint | null>;
|
|
41
|
+
findPendingTokenBySession(sessionId: string, scope?: string, binding?: PendingRowBinding): Promise<CheckpointToken | null | undefined>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 该会话**当前待决的审批门**的 token:审批门型({@link APPROVAL_GATE_KINDS})优先 —— 同会话 `task_done` 纯 park 与新 run 的审批 park 可以并存(表无 per-session pending 唯一约束),
|
|
45
|
+
* 无序读会选中别的门型 —— 没有审批门才退到任一待决行(错门型诊断由 `/decide` 的 gate-kind 守卫点名)。应答口的 stale 臂与按问读口读这一只。
|
|
46
|
+
*/
|
|
47
|
+
export declare function currentApprovalGateToken(cs: Pick<GateCurrencyStore, "findPendingTokenBySession">, sessionId: string): Promise<CheckpointToken | null | undefined>;
|
|
48
|
+
/** 一把 gate token 对着判官的读数。 */
|
|
49
|
+
export type GateCurrency = {
|
|
50
|
+
readonly kind: "current";
|
|
51
|
+
} | {
|
|
52
|
+
readonly kind: "absent";
|
|
53
|
+
} | {
|
|
54
|
+
readonly kind: "settled";
|
|
55
|
+
readonly checkpoint: Checkpoint;
|
|
56
|
+
};
|
|
57
|
+
/** 这把 gate token 是不是它那条会话当前待决的审批门。读不出(店抛错)⇒ 原样上抛,由调用方的故障姿势处置。 */
|
|
58
|
+
export declare function readGateCurrency(cs: GateCurrencyStore, gateToken: string): Promise<GateCurrency>;
|
|
59
|
+
/** 一个闭集词对已结算门的读法类:有人 / 有策略决过(往下读决议),或没有人决过它。 */
|
|
60
|
+
type SettledClass = "decided" | "void";
|
|
61
|
+
/**
|
|
62
|
+
* 结算种类(core `SETTLEMENT_KINDS`)→ 这次结算算不算「有人 / 有策略决过」。`human_*`(人)与 `policy_*`(部署的策略)四个词是仅有的决议种类;其余十个 ——
|
|
63
|
+
* 引擎自己的窗到期 · 宿主窗 / 宿主 SLA 扫 · 无人可答的失败族 —— 没有人决过它,不读成「决议:deny」(那会让壳把一次宿主超时清算渲成「被拒绝」)。
|
|
64
|
+
* 表的键是**种类**不是当事方:种类词跨版本稳定,当事方词变过义(此前版本的策略拒记 `who.party:"none"`),按当事方查会把那一代合法历史记录读错。core 现成的两张种类表
|
|
65
|
+
* (是不是拒绝 / 有没有人评判过)答的是别的问题:`human_refused` 与 `approval_window_expired` 同是拒绝,这里一个是决议、一个不是,所以不从它们派生。
|
|
66
|
+
* 表穷举(与上面 `status` 表同形、同一查法):core 给种类闭集加词而不在此表态 ⇒ 编译红。
|
|
67
|
+
*/
|
|
68
|
+
export declare const SETTLEMENT_KIND_READING: Record<SettlementKind, SettledClass>;
|
|
69
|
+
/** 协调器读口的门读席({@link ParkedGateRead}):装配点把 checkpoint 店递进来,协调器本身不认识 checkpoint 的形。 */
|
|
70
|
+
export declare function createParkedGateRead(cs: GateCurrencyStore): ParkedGateRead;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=approval-gate-currency.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { screenGateOutcome } from "@sema-agent/core";
|
|
2
|
+
import { approvalDecisionOfWinner } from "./plugins/checkpoint-store-sql.js";
|
|
3
|
+
import { APPROVAL_GATE_KINDS } from "./tool-approval.js";
|
|
4
|
+
export async function currentApprovalGateToken(cs, sessionId) {
|
|
5
|
+
return (await cs.findPendingTokenBySession(sessionId, undefined, { gateKinds: APPROVAL_GATE_KINDS })) ?? (await cs.findPendingTokenBySession(sessionId));
|
|
6
|
+
}
|
|
7
|
+
export async function readGateCurrency(cs, gateToken) {
|
|
8
|
+
const first = await cs.get(gateToken);
|
|
9
|
+
if (first === null)
|
|
10
|
+
return { kind: "absent" };
|
|
11
|
+
if (first.status !== "pending")
|
|
12
|
+
return { kind: "settled", checkpoint: first };
|
|
13
|
+
const current = await currentApprovalGateToken(cs, first.sessionId);
|
|
14
|
+
if (current === gateToken)
|
|
15
|
+
return { kind: "current" };
|
|
16
|
+
const fresh = await cs.get(gateToken);
|
|
17
|
+
return fresh === null ? { kind: "absent" } : { kind: "settled", checkpoint: fresh };
|
|
18
|
+
}
|
|
19
|
+
const SETTLED_GATE_READING = { resolved: "decided", expired: "void", pending: "void" };
|
|
20
|
+
export const SETTLEMENT_KIND_READING = {
|
|
21
|
+
human_allowed: "decided",
|
|
22
|
+
human_refused: "decided",
|
|
23
|
+
policy_allowed: "decided",
|
|
24
|
+
policy_refused: "decided",
|
|
25
|
+
approval_window_expired: "void",
|
|
26
|
+
denial_limit_window_expired: "void",
|
|
27
|
+
park_sla_expired: "void",
|
|
28
|
+
no_approver: "void",
|
|
29
|
+
approver_unavailable: "void",
|
|
30
|
+
approver_error: "void",
|
|
31
|
+
approver_contract: "void",
|
|
32
|
+
presentation_failed: "void",
|
|
33
|
+
blanket_allow_refused: "void",
|
|
34
|
+
task_aborted: "void",
|
|
35
|
+
};
|
|
36
|
+
function unreadable(defects) {
|
|
37
|
+
return { kind: "unknown", why: "decision_unreadable", defects };
|
|
38
|
+
}
|
|
39
|
+
function throughTable(table, word, field) {
|
|
40
|
+
if (typeof word !== "string" || !Object.hasOwn(table, word))
|
|
41
|
+
return unreadable([`${field} has no reading in this server's table of its closed set`]);
|
|
42
|
+
return table[word] === "decided" ? "decided" : { kind: "void" };
|
|
43
|
+
}
|
|
44
|
+
function settledReading(checkpoint, gateBoundCallId) {
|
|
45
|
+
try {
|
|
46
|
+
return readSettledRow(checkpoint, gateBoundCallId);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return unreadable([`the settled row could not be read (${e instanceof Error ? e.name : "non-Error throw"})`]);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function readSettledRow(checkpoint, gateBoundCallId) {
|
|
53
|
+
const byStatus = throughTable(SETTLED_GATE_READING, checkpoint.status, "checkpoint status");
|
|
54
|
+
if (byStatus !== "decided")
|
|
55
|
+
return byStatus;
|
|
56
|
+
const winner = checkpoint.resolvedOutcome;
|
|
57
|
+
const recorded = winner?.gateOutcome;
|
|
58
|
+
const [defect, ...more] = screenGateOutcome(recorded, { reading: "archive" });
|
|
59
|
+
if (defect !== undefined)
|
|
60
|
+
return unreadable([defect, ...more]);
|
|
61
|
+
const settlement = recorded?.settlement;
|
|
62
|
+
if (settlement === undefined)
|
|
63
|
+
return unreadable(["the gate record carries no settlement: no decider and no time"]);
|
|
64
|
+
if (!Number.isFinite(settlement.when))
|
|
65
|
+
return unreadable(["settlement.when is not a finite epoch-ms time"]);
|
|
66
|
+
const boundCallId = gateBoundCallId ?? (checkpoint.pendingAction.kind === "tool_approval" ? checkpoint.pendingAction.toolCallId : "");
|
|
67
|
+
const direction = approvalDecisionOfWinner(winner, boundCallId);
|
|
68
|
+
if (direction === null)
|
|
69
|
+
return unreadable([`the resolved winner is not an allow / deny bound to call "${boundCallId}"`]);
|
|
70
|
+
const byKind = throughTable(SETTLEMENT_KIND_READING, settlement.kind, "settlement.kind");
|
|
71
|
+
if (byKind !== "decided")
|
|
72
|
+
return byKind;
|
|
73
|
+
const note = typeof winner?.reason === "string" && winner.reason !== "" ? winner.reason : undefined;
|
|
74
|
+
return { kind: "decided", decision: direction === "approve" ? "allow" : "deny", decidedAtMs: settlement.when, ...(note !== undefined ? { decisionNote: note } : {}) };
|
|
75
|
+
}
|
|
76
|
+
export function createParkedGateRead(cs) {
|
|
77
|
+
return async ({ gateToken, gateBoundCallId }) => {
|
|
78
|
+
const currency = await readGateCurrency(cs, gateToken);
|
|
79
|
+
switch (currency.kind) {
|
|
80
|
+
case "current":
|
|
81
|
+
return { kind: "open" };
|
|
82
|
+
case "absent":
|
|
83
|
+
return { kind: "unknown", why: "row_absent" };
|
|
84
|
+
case "settled":
|
|
85
|
+
return settledReading(currency.checkpoint, gateBoundCallId);
|
|
86
|
+
default: {
|
|
87
|
+
const unhandled = currency;
|
|
88
|
+
void unhandled;
|
|
89
|
+
return { kind: "unknown", why: "row_absent" };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=approval-gate-currency.js.map
|
package/dist/approval.d.ts
CHANGED
|
@@ -184,5 +184,20 @@ export declare function createDeploymentListExemption(store: Pick<ApprovalExempt
|
|
|
184
184
|
info(event: string, fields?: Record<string, unknown>): void;
|
|
185
185
|
warn(event: string, fields?: Record<string, unknown>): void;
|
|
186
186
|
}, leg?: "parked_revive"): DeploymentListExemption;
|
|
187
|
+
/**
|
|
188
|
+
* **每腿自动批额度的审批人名**(本仓闭词;core `AskOutcome.approver` 契约逐字「a closed word the host owns, never a person」)。
|
|
189
|
+
* 结算记录读 `policy_allowed` / `who.party: "policy"` / `who.approver` = 本词 —— 审计读者按它认出「这一次放行是部署的自动批额度答的」,
|
|
190
|
+
* 与无人值守腿的 `unattended_class_answer`(`unattended-permission-mode.ts`)同族。
|
|
191
|
+
*/
|
|
192
|
+
export declare const AUTO_APPROVE_BUDGET_APPROVER = "auto_approve_budget";
|
|
193
|
+
/**
|
|
194
|
+
* **请求叶策略:`settings.permissions.neverAuto`**(S-1351)—— 命中名单的工具恒问真人;名单外「本层没有意见」(裸 allow)。叶只管请求自己写的那张表,部署的 `APPROVAL_NEVER_AUTO`
|
|
195
|
+
* 在基线里({@link createDurableAskPolicy}),两者经 `tightenGoverned` 的 deny-wins 折叠取并:请求叶只会**多**问,删不掉基线里的任何一行。
|
|
196
|
+
*
|
|
197
|
+
* 名字读法与部署名单是**同一只**({@link createApprovalListVerdict} → 精确 ∪ covering,收紧臂读调用答得上的全部名字):一条规则只有一种读法。问的铸点是
|
|
198
|
+
* {@link requestAlwaysHumanAsk}(要真人位 + 请求出处),不是部署的 {@link operatorAlwaysHumanAsk}(那一个盖部署出身,请求里的声明冒不得)。
|
|
199
|
+
* `source` = 这张表在请求体里的坐标(出处进 `matchedAskRule`,审计 / 卡面据它说清是哪张表问的)。
|
|
200
|
+
*/
|
|
201
|
+
export declare function createRequestNeverAutoPolicy(names: readonly string[], source: string): ToolPolicy;
|
|
187
202
|
export declare function createDurableAskPolicy(opts: DurableAskOptions): ToolPolicy;
|
|
188
203
|
//# sourceMappingURL=approval.d.ts.map
|
package/dist/approval.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "@sema-agent/core";
|
|
2
|
-
import { operatorAlwaysHumanAsk, operatorAsk } from "./operator-ask.js";
|
|
1
|
+
import { createApprovalPolicy, isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "@sema-agent/core";
|
|
2
|
+
import { operatorAlwaysHumanAsk, operatorAsk, requestAlwaysHumanAsk } from "./operator-ask.js";
|
|
3
3
|
import { ASK_USER_QUESTION_TOOL_NAME } from "./approval-content-kind.js";
|
|
4
4
|
import { isExplicitPosture } from "./posture-source.js";
|
|
5
5
|
import { handsOnWorkerFilePlane } from "./execution-lane-caps.js";
|
|
@@ -37,7 +37,7 @@ export function buildNoResponderBootWarns(input) {
|
|
|
37
37
|
out.push({
|
|
38
38
|
event: "fs_write_gate_no_responder",
|
|
39
39
|
fields: {
|
|
40
|
-
hint: "host-semantics lane with no approval face: permissionMode default/auto
|
|
40
|
+
hint: "host-semantics lane with no approval face: the engine's write-gate asks (permissionMode default/auto, absent reads as default; acceptEdits outside the write roots) will auto-deny (fail-closed); wire TOOL_APPROVAL_ENABLED=true or DURABLE_APPROVAL=true to answer them",
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
}
|
|
@@ -45,7 +45,7 @@ export function buildNoResponderBootWarns(input) {
|
|
|
45
45
|
out.push({
|
|
46
46
|
event: "workflow_gate_no_responder",
|
|
47
47
|
fields: {
|
|
48
|
-
hint: "self-orchestration with no approval face:
|
|
48
|
+
hint: "self-orchestration with no approval face: run_workflow asks (every permission mode but bypassPermissions, which releases them, and dontAsk, which refuses them; absent reads as default) will auto-deny (fail-closed); wire TOOL_APPROVAL_ENABLED=true or DURABLE_APPROVAL=true to answer them",
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
51
|
}
|
|
@@ -119,8 +119,38 @@ function createNameSetMatcher(names) {
|
|
|
119
119
|
return (toolName) => exact.has(toolName);
|
|
120
120
|
return (toolName) => exact.has(toolName) || covering.some((rule) => namespacedRuleNameCovers(rule, toolName));
|
|
121
121
|
}
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
export const AUTO_APPROVE_BUDGET_APPROVER = "auto_approve_budget";
|
|
123
|
+
function budgetSeatAnswer(req, requireHit, signal) {
|
|
124
|
+
let answered = false;
|
|
125
|
+
const seat = createApprovalPolicy({
|
|
126
|
+
requireApproval: [requireHit],
|
|
127
|
+
approve: () => {
|
|
128
|
+
answered = true;
|
|
129
|
+
return { allow: true, settledBy: "policy", approver: AUTO_APPROVE_BUDGET_APPROVER };
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
return { answered: () => answered, verdict: Promise.resolve(seat.check(req, signal)) };
|
|
133
|
+
}
|
|
134
|
+
export function createRequestNeverAutoPolicy(names, source) {
|
|
135
|
+
const verdictOf = createApprovalListVerdict({ requireApproval: [], neverAuto: names });
|
|
136
|
+
return {
|
|
137
|
+
check: (req) => {
|
|
138
|
+
const verdict = verdictOf(req);
|
|
139
|
+
switch (verdict.list) {
|
|
140
|
+
case "never_auto":
|
|
141
|
+
return requestAlwaysHumanAsk(`${source}(${verdict.hit})`, `human approval required to run "${req.toolName}"`);
|
|
142
|
+
case "none":
|
|
143
|
+
return { action: "allow" };
|
|
144
|
+
case "deny":
|
|
145
|
+
case "require":
|
|
146
|
+
throw new Error(`request never-auto leaf reached a "${verdict.list}" verdict with empty deny / require lists`);
|
|
147
|
+
default: {
|
|
148
|
+
const unreachable = verdict;
|
|
149
|
+
throw new Error(`unhandled approval-list verdict: ${JSON.stringify(unreachable)}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
};
|
|
124
154
|
}
|
|
125
155
|
export function createDurableAskPolicy(opts) {
|
|
126
156
|
const verdictOf = createApprovalListVerdict(opts);
|
|
@@ -128,7 +158,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
128
158
|
let autoApproved = 0;
|
|
129
159
|
const isQuestionTool = (name) => name === ASK_USER_QUESTION_TOOL_NAME;
|
|
130
160
|
return {
|
|
131
|
-
check: (req) => {
|
|
161
|
+
check: (req, signal) => {
|
|
132
162
|
const verdict = verdictOf(req);
|
|
133
163
|
switch (verdict.list) {
|
|
134
164
|
case "deny":
|
|
@@ -136,7 +166,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
136
166
|
case "never_auto":
|
|
137
167
|
return operatorAlwaysHumanAsk(`APPROVAL_NEVER_AUTO(${verdict.hit})`, `human approval required to run "${req.toolName}"`);
|
|
138
168
|
case "require":
|
|
139
|
-
return decideRequired(req, verdict.hit);
|
|
169
|
+
return decideRequired(req, verdict.hit, signal);
|
|
140
170
|
case "none":
|
|
141
171
|
return { action: "allow" };
|
|
142
172
|
default: {
|
|
@@ -146,7 +176,7 @@ export function createDurableAskPolicy(opts) {
|
|
|
146
176
|
}
|
|
147
177
|
},
|
|
148
178
|
};
|
|
149
|
-
function decideRequired(req, requireHit) {
|
|
179
|
+
function decideRequired(req, requireHit, signal) {
|
|
150
180
|
const rem = req.budget?.resourceRemainingMicroUsd;
|
|
151
181
|
if (rem !== undefined && rem <= 0) {
|
|
152
182
|
return operatorAlwaysHumanAsk("RESOURCE_SUSPEND budget exhausted", `durable resource budget exhausted — human approval required to run "${req.toolName}"`);
|
|
@@ -159,17 +189,25 @@ export function createDurableAskPolicy(opts) {
|
|
|
159
189
|
exemption.onExempted(req.toolName);
|
|
160
190
|
return { action: "allow" };
|
|
161
191
|
}
|
|
162
|
-
return budgetOrAsk(req, ask);
|
|
192
|
+
return budgetOrAsk(req, ask, requireHit, signal);
|
|
163
193
|
})();
|
|
164
194
|
}
|
|
165
|
-
return budgetOrAsk(req, ask);
|
|
195
|
+
return budgetOrAsk(req, ask, requireHit, signal);
|
|
166
196
|
}
|
|
167
|
-
function budgetOrAsk(req, ask) {
|
|
168
|
-
if (heldRuleName(req, isQuestionTool)
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
return
|
|
197
|
+
function budgetOrAsk(req, ask, requireHit, signal) {
|
|
198
|
+
if (heldRuleName(req, isQuestionTool) !== undefined || budget <= 0 || autoApproved >= budget)
|
|
199
|
+
return ask;
|
|
200
|
+
autoApproved++;
|
|
201
|
+
const { answered, verdict } = budgetSeatAnswer(req, requireHit, signal);
|
|
202
|
+
return verdict.then((d) => {
|
|
203
|
+
if (answered() && d.action === "allow")
|
|
204
|
+
return d;
|
|
205
|
+
autoApproved--;
|
|
206
|
+
return ask;
|
|
207
|
+
}, (err) => {
|
|
208
|
+
autoApproved--;
|
|
209
|
+
throw err;
|
|
210
|
+
});
|
|
173
211
|
}
|
|
174
212
|
}
|
|
175
213
|
//# sourceMappingURL=approval.js.map
|
package/dist/audit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type StoredPromptEpoch } from "@sema-agent/core";
|
|
1
|
+
import { type SessionPlacementRecord, type StoredPromptEpoch } from "@sema-agent/core";
|
|
2
2
|
import type { Pool } from "mysql2/promise";
|
|
3
3
|
import type { Pool as PgPool } from "pg";
|
|
4
4
|
/**
|
|
@@ -29,12 +29,32 @@ export interface SessionAudit {
|
|
|
29
29
|
* the key entirely (undefined). */
|
|
30
30
|
promptEpoch?: StoredPromptEpoch;
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* 会话视图体顶层 additive 键 `agent` —— **这只会话是哪只委派子代的转录**(`GET /v1/sessions/:id`;读法:终端侧链投影方按 fleet 帧的 `transcriptId`
|
|
34
|
+
* 读同一只会话读面,从体上拿到子代身份,不必再回头翻 fleet 行 —— 行一离场就没有了)。
|
|
35
|
+
*
|
|
36
|
+
* 只投影**存下来的 placement 元组**(`session_meta` 的 `placement_*` 列,首写不可变;店的 `placementOf` 一行 PK 探针),**不另铸**:
|
|
37
|
+
* · `id` = 元组里的 `handle` —— 耐久 agent 行的 `a…` 键,与 fleet 行的 `id`、`GET /v1/agents/roster` 的 `handle` 是同一个串(core 铸元组时 `handle: taskId`);
|
|
38
|
+
* · `parentSessionId` / `rootSessionId` = 元组里的同名格(派它的会话 / 委派树的根会话);
|
|
39
|
+
* · 元组缺哪一格这里就缺哪一格(present-iff;不铸空串);元组的 `scope`(租户键)/ `placedAt` / `kind` 不上 wire。
|
|
40
|
+
* 键在场 = 这是一只委派子代的转录(哪怕元组只存了 `kind`,那时 `agent` 是 `{}`);键缺席 = 普通会话,**或这台部署的店不存 placement 元组**
|
|
41
|
+
* (local 后端:子代转录停驻前住私有短 TTL 店、停驻时拷进来的那一份是普通会话行 —— 事实没存就不报,消费方在 fleet 行 / `GET /v1/agents/roster` 上本就有 `id`)。
|
|
42
|
+
* 元组由引擎在**后台**委派子代(带耐久 agent 行、店声明了 placements)建会话时铸;同步委派的子代转录不落宿主店,没有元组。
|
|
43
|
+
*/
|
|
44
|
+
export interface SessionAgent {
|
|
45
|
+
id?: string;
|
|
46
|
+
parentSessionId?: string;
|
|
47
|
+
rootSessionId?: string;
|
|
48
|
+
}
|
|
49
|
+
/** {@link SessionAgent} 的唯一投影:店答出的 placement 元组 → 体上的 `agent` 值;`undefined`(普通会话 / 店没有这一面)⇒ 调用方不铸键。 */
|
|
50
|
+
export declare function sessionAgentOf(placement: SessionPlacementRecord | undefined): SessionAgent | undefined;
|
|
32
51
|
/**
|
|
33
52
|
* 用户消息行的**回退手柄**表:用户条目 id → 回退时交给 `resumeAt` 的那个 `event_id`(R8 用户消息锚按 run 的 taskId 键入)。
|
|
34
53
|
* 真源 = `resume_anchor`(锚店 `listBySession` 的读数),本表只是它对**一位读者**的一次投影。
|
|
35
54
|
*/
|
|
36
55
|
export type RewindHandles = ReadonlyMap<string, string>;
|
|
37
|
-
/** 会话视图读口(`ServiceDeps.sessionAudit`)的读者参数:`reader` = 读这张视图的**已验身份**(无身份 = `null`)。给了 ⇒
|
|
56
|
+
/** 会话视图读口(`ServiceDeps.sessionAudit`)的读者参数:`reader` = 读这张视图的**已验身份**(无身份 = `null`)。给了 ⇒ 这是一次**视图读**:用户消息行投回退手柄、体顶层投 `agent`({@link sessionAgentOf});
|
|
57
|
+
* 不给(只要归属的调用方:memory-status / 自助抹除)⇒ 两样投影的读都不付。 */
|
|
38
58
|
export interface SessionAuditReadOpts {
|
|
39
59
|
readonly reader: string | null;
|
|
40
60
|
}
|
|
@@ -53,15 +73,12 @@ export declare function buildRewindHandles(anchors: ReadonlyArray<{
|
|
|
53
73
|
* rewind-handle projection ({@link buildRewindHandles}); absent ⇒ no `taskId` keys. */
|
|
54
74
|
export declare function buildSessionAudit(pool: Pool, sessionId: string, handles?: RewindHandles): Promise<SessionAudit | undefined>;
|
|
55
75
|
/** The PG twin — same view over PgSessionStorage.wake. Until this, the
|
|
56
|
-
* audit face was TiDB-only and a PG/local deployment 404'd the whole web session area.
|
|
57
|
-
* (its storage seam has no wake-equivalent yet — may turn out to be a core gap). */
|
|
76
|
+
* audit face was TiDB-only and a PG/local deployment 404'd the whole web session area. */
|
|
58
77
|
export declare function buildSessionAuditPg(pool: PgPool, sessionId: string, handles?: RewindHandles): Promise<SessionAudit | undefined>;
|
|
59
|
-
/** The LOCAL (File) leg — web session area on DB_BACKEND=local.
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* `boundedTail`(纯函数切 floor)→ InMemorySessionStorage → 同一 auditFromStorage 内核。零写面、
|
|
64
|
-
* 零新 seam;createdAt 从 repo.list() 的 metadata 取(File 形态 meta 与 entries 分储)。 */
|
|
78
|
+
/** The LOCAL (File) leg — web session area on DB_BACKEND=local: the same view over `LocalSessionWindow.wake`
|
|
79
|
+
* (`plugins/local-session-window.ts`). All three legs read one way — a bounded window that carries the epoch anchor below its
|
|
80
|
+
* floor — and on every backend that is what the run reads: the SQL twins' run wakes the same window; the local run wakes the whole
|
|
81
|
+
* tree, and the local window is cut from that tree's branch, with the anchor walking the branch below the floor. */
|
|
65
82
|
export declare function buildSessionAuditLocal(root: string, sessionId: string, handles?: RewindHandles): Promise<SessionAudit | undefined>;
|
|
66
83
|
/**
|
|
67
84
|
* 🔴 **会话视图的读面口 —— `GET /v1/sessions/:id` 的全部取法(整读 / `?tail` / `?before` / `?blobCap` / `?message=N`)共用这一只**。
|
package/dist/audit.js
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { StoredSession
|
|
1
|
+
import { StoredSession } from "@sema-agent/core";
|
|
2
2
|
import { TiDBSessionStorage } from "./plugins/tidb-session-storage.js";
|
|
3
3
|
import { PgSessionStorage } from "./plugins/pg-session-storage.js";
|
|
4
|
-
import {
|
|
4
|
+
import { LocalSessionWindow } from "./plugins/local-session-window.js";
|
|
5
5
|
import { redactModelText } from "./observability/run-terminal.js";
|
|
6
6
|
import { redactDeepWith } from "./trace/redact.js";
|
|
7
7
|
import { projectToolStructured } from "./trace/tool-output-media.js";
|
|
8
8
|
import { INJECTED_BLOCK_RE, isAttachmentFrame } from "./user-authored-text.js";
|
|
9
|
+
export function sessionAgentOf(placement) {
|
|
10
|
+
if (placement === undefined)
|
|
11
|
+
return undefined;
|
|
12
|
+
return {
|
|
13
|
+
...(placement.handle !== undefined ? { id: placement.handle } : {}),
|
|
14
|
+
...(placement.parentSessionId !== undefined ? { parentSessionId: placement.parentSessionId } : {}),
|
|
15
|
+
...(placement.rootSessionId !== undefined ? { rootSessionId: placement.rootSessionId } : {}),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
9
18
|
export function buildRewindHandles(anchors, reader) {
|
|
10
19
|
const byEntry = new Map();
|
|
11
20
|
for (const a of anchors) {
|
|
@@ -26,20 +35,7 @@ export async function buildSessionAuditPg(pool, sessionId, handles) {
|
|
|
26
35
|
return auditFromStorage(await PgSessionStorage.wake(pool, sessionId), sessionId, handles);
|
|
27
36
|
}
|
|
28
37
|
export async function buildSessionAuditLocal(root, sessionId, handles) {
|
|
29
|
-
|
|
30
|
-
let entries;
|
|
31
|
-
try {
|
|
32
|
-
entries = await repo.exportEntries(sessionId);
|
|
33
|
-
}
|
|
34
|
-
catch (e) {
|
|
35
|
-
if (e.code === "not_found")
|
|
36
|
-
return undefined;
|
|
37
|
-
throw e;
|
|
38
|
-
}
|
|
39
|
-
const meta = (await repo.list()).find((m) => m.id === sessionId);
|
|
40
|
-
const { tail, floorEntryId } = boundedTail(entries);
|
|
41
|
-
const storage = new InMemorySessionStorage({ entries: tail, floorEntryId, ...(meta ? { metadata: meta } : {}) });
|
|
42
|
-
return auditFromStorage(storage, sessionId, handles);
|
|
38
|
+
return auditFromStorage(await LocalSessionWindow.wake(root, sessionId), sessionId, handles);
|
|
43
39
|
}
|
|
44
40
|
async function auditFromStorage(storage, sessionId, handles) {
|
|
45
41
|
if (!storage)
|
package/dist/bake-runner/main.js
CHANGED
|
@@ -5,6 +5,7 @@ import { logConfigDiagnostics, parseEnvNameAllowlist, parseNumOrFailNonNegative
|
|
|
5
5
|
import { installSecretEnvScrubRecorder } from "../observability/secret-env-scrub.js";
|
|
6
6
|
import { declareServerWithheldEnv, hostSubprocessEnv } from "../server-secret-env.js";
|
|
7
7
|
import { shellQuote as shellSafe } from "../plugins/remote-shell.js";
|
|
8
|
+
import { echoCallerText } from "../caller-text-echo.js";
|
|
8
9
|
import { BakeRunner, } from "./runner.js";
|
|
9
10
|
const BAKE_CLAIM_INGEST_FETCH_TIMEOUT_MS = 30_000;
|
|
10
11
|
const BAKE_HEARTBEAT_FETCH_TIMEOUT_MS = 10_000;
|
|
@@ -181,9 +182,9 @@ export async function execGroup(cmd, timeoutMs, envAllow) {
|
|
|
181
182
|
try {
|
|
182
183
|
const { code, signal } = await child.exited;
|
|
183
184
|
if (timedOut)
|
|
184
|
-
throw new Error(`host exec timed out after ${timeoutMs}ms (group killed): ${cmd
|
|
185
|
+
throw new Error(`host exec timed out after ${timeoutMs}ms (group killed): ${echoCallerText(cmd, { maxChars: 120 })}`);
|
|
185
186
|
if (code !== 0)
|
|
186
|
-
throw new Error(`host exec exited ${code ?? signal}: ${cmd
|
|
187
|
+
throw new Error(`host exec exited ${code ?? signal}: ${echoCallerText(cmd, { maxChars: 120 })}${stderr.trim() ? ` — ${stderr.trim().slice(-400)}` : ""}`);
|
|
187
188
|
return { stdout };
|
|
188
189
|
}
|
|
189
190
|
finally {
|
|
@@ -14,6 +14,7 @@ import { QuestionCoordinator } from "../question.js";
|
|
|
14
14
|
import { ToolApprovalCoordinator, type ParkedAskRedeem } from "../tool-approval.js";
|
|
15
15
|
import { FileApprovalAskAuditStore } from "../approval-ask-audit-store.js";
|
|
16
16
|
import type { ParkCommitWatch } from "../plugins/park-commit-watch.js";
|
|
17
|
+
import { type GateCurrencyStore } from "../approval-gate-currency.js";
|
|
17
18
|
import { SendUserFileEmitter } from "../capabilities/send-user-file-tool.js";
|
|
18
19
|
import { TaskEnvRegistry } from "../capabilities/sandbox-file-send.js";
|
|
19
20
|
import type { StoreBackend } from "../plugins/store-backend.js";
|
|
@@ -36,13 +37,17 @@ export interface LiveCoordinatorsCtx {
|
|
|
36
37
|
/** S-929 F1:checkpoint 店的 park 提交观察层(stage-06 与店同一处铸;在场 ⇔ 有 checkpoint 店)。协调器据它判「有序关停下的 park 路由
|
|
37
38
|
* 提交了没有」—— 审计 settle 行等 park 提交落定才写。缺席 = 没有 park 设施(core 在 ask 回调处就收场,没有提交这一步)。 */
|
|
38
39
|
parkCommits?: ParkCommitWatch;
|
|
40
|
+
/** S-1915:checkpoint 店(stage-06 的**同一只**,与 `parkCommits` 同源;在场 ⇔ 有 park 设施)。协调器的按问读口据它判一张 `PARKED` 卡的门此刻还是不是该会话当前待决的审批门
|
|
41
|
+
* (判官 = `approval-gate-currency.ts`,应答口判 `approval_stale` 读的同一只)。缺席 ⇒ 读口只能说行说的话(`parked`)。
|
|
42
|
+
* 也是流内审批协议上场门的 park 设施位:在场性与实例是一个事实 —— 门的 `active` 臂交出去的就是这一只,缺席 ⇒ 协议不上场(`no_park_facility`)。 */
|
|
43
|
+
checkpointStore?: GateCurrencyStore;
|
|
39
44
|
}
|
|
40
45
|
export declare function createLiveCoordinators(ctx: LiveCoordinatorsCtx): {
|
|
41
46
|
elicitation: ElicitationCoordinator | undefined;
|
|
42
47
|
question: QuestionCoordinator | undefined;
|
|
43
48
|
toolApproval: ToolApprovalCoordinator | undefined;
|
|
44
49
|
durableEnabled: boolean;
|
|
45
|
-
streamApprovalGate: import("../tool-approval.js").StreamApprovalGate
|
|
50
|
+
streamApprovalGate: import("../tool-approval.js").StreamApprovalGate<GateCurrencyStore>;
|
|
46
51
|
approvalAskAudit: FileApprovalAskAuditStore | undefined;
|
|
47
52
|
approvalExemptionStore: import("../plugins/approval-exemption-store.js").ApprovalExemptionStore | undefined;
|
|
48
53
|
sendUserFileEmitter: SendUserFileEmitter | undefined;
|
|
@@ -3,6 +3,7 @@ import { QuestionCoordinator } from "../question.js";
|
|
|
3
3
|
import { ToolApprovalCoordinator, resolveStreamApprovalGate } from "../tool-approval.js";
|
|
4
4
|
import { deploymentListAsks } from "../approval.js";
|
|
5
5
|
import { FileApprovalAskAuditStore } from "../approval-ask-audit-store.js";
|
|
6
|
+
import { createParkedGateRead } from "../approval-gate-currency.js";
|
|
6
7
|
import { SendUserFileEmitter, SEND_USER_FILE_MAX_BYTES, sendUserFileTool } from "../capabilities/send-user-file-tool.js";
|
|
7
8
|
import { createSandboxFileSend, TaskEnvRegistry } from "../capabilities/sandbox-file-send.js";
|
|
8
9
|
import { createSendUserFileIssuer } from "../plugins/send-user-file.js";
|
|
@@ -11,15 +12,16 @@ import { basename, resolve } from "node:path";
|
|
|
11
12
|
import { toolsRunOnThisHost } from "../task-cwd.js";
|
|
12
13
|
import { stat as fsStat, readFile as fsReadFile } from "node:fs/promises";
|
|
13
14
|
export function createLiveCoordinators(ctx) {
|
|
14
|
-
const { config, logger, backend, sendUserFileTaskEnvs, ruleConsent, ruleScopeRootFor, getParkedRedeem, parkCommits } = ctx;
|
|
15
|
+
const { config, logger, backend, sendUserFileTaskEnvs, ruleConsent, ruleScopeRootFor, getParkedRedeem, parkCommits, checkpointStore } = ctx;
|
|
15
16
|
const elicitation = config.mcpElicitation.enabled ? new ElicitationCoordinator(config.mcpElicitation.throttle) : undefined;
|
|
16
17
|
const question = config.askQuestionEnabled ? new QuestionCoordinator(config.questionThrottle) : undefined;
|
|
17
|
-
const
|
|
18
|
+
const parkStore = checkpointStore;
|
|
19
|
+
const durableEnabled = parkStore !== undefined;
|
|
18
20
|
const streamApprovalGate = resolveStreamApprovalGate({
|
|
19
21
|
toolApprovalEnabled: config.toolApprovalEnabled === true,
|
|
20
22
|
streamApprovalEnabled: config.streamApproval.enabled,
|
|
21
23
|
backend,
|
|
22
|
-
|
|
24
|
+
checkpointStore: parkStore,
|
|
23
25
|
});
|
|
24
26
|
if (config.streamApproval.enabled && !streamApprovalGate.active) {
|
|
25
27
|
logger.info("stream_approval_disabled", {
|
|
@@ -58,6 +60,7 @@ export function createLiveCoordinators(ctx) {
|
|
|
58
60
|
...(ruleScopeRootFor !== undefined ? { ruleScopeRootFor } : {}),
|
|
59
61
|
unattendedPolicy: config.unattendedApprovalPolicy,
|
|
60
62
|
...(getParkedRedeem !== undefined ? { parkedRedeem: getParkedRedeem } : {}),
|
|
63
|
+
...(checkpointStore !== undefined ? { parkedGate: createParkedGateRead(checkpointStore) } : {}),
|
|
61
64
|
...(approvalAskAudit !== undefined ? { askAudit: approvalAskAudit } : {}),
|
|
62
65
|
...(approvalExemptionStore !== undefined
|
|
63
66
|
? { sessionGrants: approvalExemptionStore, deploymentListAsks: (call) => deploymentListAsks(config, call) }
|
|
@@ -118,7 +118,7 @@ export class DeferredSandboxPathEnv extends StubExecutionEnv {
|
|
|
118
118
|
reason: found.reason,
|
|
119
119
|
face,
|
|
120
120
|
sessionId: this.sessionId ?? null,
|
|
121
|
-
note: "the sandbox
|
|
121
|
+
note: "the sandbox path adjudication has no task environment to read — the sensitive-path guard fails closed (deny) on every write target until one is bound",
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
124
|
return {
|
|
@@ -20,13 +20,14 @@ import { FileSchedulerBackend, defaultSchedulerStorePath } from "../plugins/sche
|
|
|
20
20
|
import * as facts from "../capability-facts.js";
|
|
21
21
|
import { materializeAttachmentsInto } from "../plugins/task-attachment-store.js";
|
|
22
22
|
import { reapOrphanWorktrees, withWorktreeIsolation } from "../plugins/worktree-isolation.js";
|
|
23
|
-
import {
|
|
23
|
+
import { derivePkgSourceEnv } from "../sandbox-pkg-source.js";
|
|
24
24
|
import { effectiveHostWorkspace } from "../task-cwd.js";
|
|
25
25
|
import { taskInheritEnvRefusal } from "../hosted-posture.js";
|
|
26
26
|
import { createCacheMissMemory } from "../workspace-cache.js";
|
|
27
27
|
import { workspaceSnapshotTimeoutOf } from "../workspace-space.js";
|
|
28
28
|
import { sayEgressPolicyReading } from "../sandbox-egress-policy.js";
|
|
29
29
|
import { isSandboxPathAdjudicationLane, sandboxPathEnvSlots, withSandboxPathEnvSlot } from "./deferred-sandbox-path-env.js";
|
|
30
|
+
import { LANE_HOME_UNDECLARED_EVENT, createLaneHomeAbsenceReporter } from "../lane-home-probe.js";
|
|
30
31
|
import { REMOTE_EXEC_PROVIDER_WORDS, buildUndeclaredHomeNote, executionLaneHomeDir, executionLaneOf, isSingleMachineDefaultLane, laneBindsReads, laneIsolated } from "../execution-lane-caps.js";
|
|
31
32
|
function boundedSessionSetter(map, maxEntries) {
|
|
32
33
|
return (sid, value) => {
|
|
@@ -55,7 +56,7 @@ function forwardedSandboxEnvKeys(remoteExec) {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
function buildSandboxLaneEnv(config, explicit) {
|
|
58
|
-
const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource,
|
|
59
|
+
const merged = { ...derivePkgSourceEnv(config.sandboxPkgSource, config.sandboxPkgSourceCustom), ...(explicit ?? {}) };
|
|
59
60
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
60
61
|
}
|
|
61
62
|
const MAX_CWD_SESSIONS = 4096;
|
|
@@ -197,6 +198,7 @@ export function createExecutionEnv(ctx) {
|
|
|
197
198
|
const { config, logger, metrics, taskAttachmentStore } = ctx;
|
|
198
199
|
const laneHomeDir = executionLaneHomeDir(config);
|
|
199
200
|
const homeDirSeat = laneHomeDir !== undefined ? { homeDir: laneHomeDir } : {};
|
|
201
|
+
const homeAbsentNotice = { onHomeAbsent: createLaneHomeAbsenceReporter((event, fields) => logger.warn(event, fields)) };
|
|
200
202
|
const perTaskImage = new PerTaskImageRegistry();
|
|
201
203
|
const sessionEnvSelection = new SessionEnvironmentSelection();
|
|
202
204
|
const sessionScoped = createSessionScopedRegistries();
|
|
@@ -223,7 +225,7 @@ export function createExecutionEnv(ctx) {
|
|
|
223
225
|
else if (config.remoteExec?.provider === "k8s") {
|
|
224
226
|
const k8sCfg = {
|
|
225
227
|
image: config.remoteExec.image,
|
|
226
|
-
...homeDirSeat,
|
|
228
|
+
...homeDirSeat, ...homeAbsentNotice,
|
|
227
229
|
...(config.remoteExec.apiUrl ? { apiUrl: config.remoteExec.apiUrl } : {}),
|
|
228
230
|
...(config.remoteExec.token ? { token: config.remoteExec.token } : {}),
|
|
229
231
|
...(config.remoteExec.caCert ? { caCert: config.remoteExec.caCert } : {}),
|
|
@@ -254,7 +256,7 @@ export function createExecutionEnv(ctx) {
|
|
|
254
256
|
executionEnvFactory = sshExecutionEnvFactory({
|
|
255
257
|
host: config.remoteExec.host,
|
|
256
258
|
username: config.remoteExec.username,
|
|
257
|
-
...homeDirSeat,
|
|
259
|
+
...homeDirSeat, ...homeAbsentNotice,
|
|
258
260
|
privateKey: config.remoteExec.privateKey,
|
|
259
261
|
...(config.remoteExec.port != null ? { port: config.remoteExec.port } : {}),
|
|
260
262
|
...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
|
|
@@ -278,7 +280,7 @@ export function createExecutionEnv(ctx) {
|
|
|
278
280
|
else if (config.remoteExec?.provider === "adb") {
|
|
279
281
|
executionEnvFactory = adbExecutionEnvFactory({
|
|
280
282
|
serial: config.remoteExec.serial,
|
|
281
|
-
...homeDirSeat,
|
|
283
|
+
...homeDirSeat, ...homeAbsentNotice,
|
|
282
284
|
...(config.remoteExec.adbPath ? { adbPath: config.remoteExec.adbPath } : {}),
|
|
283
285
|
...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
|
|
284
286
|
});
|
|
@@ -327,7 +329,7 @@ export function createExecutionEnv(ctx) {
|
|
|
327
329
|
executionEnvFactory = localDockerExecutionEnvFactory({
|
|
328
330
|
image: config.remoteExec.image,
|
|
329
331
|
...(config.remoteExec.mountPath ? { mountPath: config.remoteExec.mountPath } : {}),
|
|
330
|
-
...homeDirSeat,
|
|
332
|
+
...homeDirSeat, ...homeAbsentNotice,
|
|
331
333
|
...(config.remoteExec.dockerPath ? { dockerPath: config.remoteExec.dockerPath } : {}),
|
|
332
334
|
...(config.remoteExec.dockerHost ? { dockerHost: config.remoteExec.dockerHost } : {}),
|
|
333
335
|
...(config.remoteExec.memory ? { memory: config.remoteExec.memory } : {}),
|
|
@@ -416,7 +418,7 @@ export function createExecutionEnv(ctx) {
|
|
|
416
418
|
logger.warn("remote_exec_real_system", { provider: config.remoteExec.provider, note: buildRealSystemNote(config.remoteExec) });
|
|
417
419
|
const homeNote = buildUndeclaredHomeNote(config);
|
|
418
420
|
if (homeNote !== undefined)
|
|
419
|
-
logger.warn(
|
|
421
|
+
logger.warn(LANE_HOME_UNDECLARED_EVENT, { provider: config.remoteExec.provider, note: homeNote });
|
|
420
422
|
if (executionLaneOf(config.remoteExec.provider) === "host")
|
|
421
423
|
logger.info("task_inherit_env_honored", { honored: taskInheritEnvRefusal(config) === undefined });
|
|
422
424
|
}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { loadRemoteExec } from "@sema-agent/settings-schema/node";
|
|
2
|
+
import { assertLocalConfigDirTrusted } from "../config-dir-trust.js";
|
|
2
3
|
import { crossInvariant } from "../config-invariants.js";
|
|
3
4
|
import { executionLaneOf, laneIsolated } from "../execution-lane-caps.js";
|
|
5
|
+
import { buildReadFacePostureNotice, settleDerivedReadFace } from "../read-face-posture.js";
|
|
4
6
|
import { settleHostShellAtBoot } from "../plugins/host-platform.js";
|
|
5
7
|
export const FILE_SOURCED_LANES = ["host", "local-docker"];
|
|
6
8
|
export async function composeExecutionLane(config, ctx) {
|
|
7
9
|
if (ctx.configSource === "local")
|
|
8
10
|
await applyRemoteExecFile(config, ctx);
|
|
11
|
+
settleReadFaceForFinalLane(config, ctx.logger);
|
|
9
12
|
assertExecutionLaneInvariants(config);
|
|
10
13
|
}
|
|
14
|
+
function settleReadFaceForFinalLane(config, logger) {
|
|
15
|
+
if (!settleDerivedReadFace(config, config.requirePrincipal !== true))
|
|
16
|
+
return;
|
|
17
|
+
const notice = buildReadFacePostureNotice(config);
|
|
18
|
+
if (notice !== undefined)
|
|
19
|
+
logger.info(notice.event, notice.fields);
|
|
20
|
+
}
|
|
11
21
|
export async function settleHostLaneShell(config, logger) {
|
|
12
22
|
if (config.remoteExec?.provider !== "host")
|
|
13
23
|
return;
|
|
@@ -34,6 +44,7 @@ export function assertExecutionLaneInvariants(config) {
|
|
|
34
44
|
}
|
|
35
45
|
async function applyRemoteExecFile(config, ctx) {
|
|
36
46
|
const { localRoot, logger } = ctx;
|
|
47
|
+
await assertLocalConfigDirTrusted({ root: localRoot, declaredOwnerUid: config.configLocalOwnerUid });
|
|
37
48
|
let fileRx;
|
|
38
49
|
try {
|
|
39
50
|
fileRx = await loadRemoteExec(localRoot);
|