@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,388 @@
|
|
|
1
|
+
import { lstat, readFile, readdir, readlink, realpath, stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { LOCAL_READER_DOCUMENTS } from "./config-d-migration.js";
|
|
4
|
+
import { recordFailOpen } from "./observability/fail-open.js";
|
|
5
|
+
import { HOST_PLATFORM } from "./plugins/host-platform.js";
|
|
6
|
+
export const CONFIG_DIR_UNTRUSTED_CODE = "config.dir_untrusted";
|
|
7
|
+
export const CONFIG_LOCAL_OWNER_UID_ENV = "CONFIG_LOCAL_OWNER_UID";
|
|
8
|
+
export const CONFIG_DOCUMENT_MAX_BYTES = 16 * 1024 * 1024;
|
|
9
|
+
export const CONFIG_DIR_LINK_HOPS_MAX = 40;
|
|
10
|
+
const UID_MAX = 4294967294;
|
|
11
|
+
const WIN32_UNVERIFIED_TAG = "server.config-dir-trust.win32-owner-mode-unverifiable";
|
|
12
|
+
const errnoOf = (e) => (e instanceof Error && "code" in e && typeof e.code === "string" ? e.code : undefined);
|
|
13
|
+
const KUBELET_VOLUME_ROOT = /\/pods\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\/volumes\/kubernetes\.io~configmap\/[^/]+$/;
|
|
14
|
+
const coversPath = (ancestor, p) => ancestor === p || ancestor === "/" || p.startsWith(`${ancestor}/`);
|
|
15
|
+
const unescapeMountinfoPath = (field) => field.replace(/\\([0-7]{3})/g, (_m, oct) => String.fromCharCode(Number.parseInt(oct, 8)));
|
|
16
|
+
function visibleMountOf(rows, dir) {
|
|
17
|
+
const ids = new Set(rows.map((r) => r.id));
|
|
18
|
+
let level = rows.filter((r) => !ids.has(r.parent) || r.parent === r.id);
|
|
19
|
+
let visible;
|
|
20
|
+
for (let depth = 0; depth <= rows.length; depth++) {
|
|
21
|
+
const covering = level.filter((r) => coversPath(r.mountPoint, dir));
|
|
22
|
+
if (covering.length === 0)
|
|
23
|
+
break;
|
|
24
|
+
const shortest = Math.min(...covering.map((r) => r.mountPoint.length));
|
|
25
|
+
const first = covering.filter((r) => r.mountPoint.length === shortest);
|
|
26
|
+
if (first.length !== 1)
|
|
27
|
+
return "ambiguous";
|
|
28
|
+
const next = first[0];
|
|
29
|
+
visible = next;
|
|
30
|
+
level = rows.filter((r) => r.parent === next.id && r.id !== next.id);
|
|
31
|
+
}
|
|
32
|
+
return visible;
|
|
33
|
+
}
|
|
34
|
+
export function kubeletVolumeIn(mountinfo, dir) {
|
|
35
|
+
const rows = [];
|
|
36
|
+
for (const line of mountinfo.split("\n")) {
|
|
37
|
+
const f = line.split(" ");
|
|
38
|
+
const [id, parent, dev, root, mountPoint, options] = f;
|
|
39
|
+
if (f.indexOf("-", 6) === -1 || id === undefined || parent === undefined || dev === undefined || root === undefined || mountPoint === undefined || options === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
rows.push({ id, parent, dev, root: unescapeMountinfoPath(root), mountPoint: unescapeMountinfoPath(mountPoint), options: options.split(",") });
|
|
42
|
+
}
|
|
43
|
+
const visible = visibleMountOf(rows, dir);
|
|
44
|
+
if (typeof visible !== "object" || visible.mountPoint !== dir || !visible.options.includes("ro") || !KUBELET_VOLUME_ROOT.test(visible.root))
|
|
45
|
+
return undefined;
|
|
46
|
+
const source = visible.root;
|
|
47
|
+
const writableExposures = [];
|
|
48
|
+
for (const r of rows) {
|
|
49
|
+
if (r.dev !== visible.dev || r.options.includes("ro") || !coversPath(r.root, source))
|
|
50
|
+
continue;
|
|
51
|
+
const exposed = path.posix.join(r.mountPoint, r.root === "/" ? source : source.slice(r.root.length));
|
|
52
|
+
const seen = visibleMountOf(rows, exposed);
|
|
53
|
+
if (typeof seen === "object" && seen !== r)
|
|
54
|
+
continue;
|
|
55
|
+
if (!writableExposures.some((e) => e.path === exposed))
|
|
56
|
+
writableExposures.push({ path: exposed, mountPoint: r.mountPoint });
|
|
57
|
+
}
|
|
58
|
+
return { source, writableExposures };
|
|
59
|
+
}
|
|
60
|
+
async function processMountinfo() {
|
|
61
|
+
return HOST_PLATFORM === "linux" ? readFile("/proc/self/mountinfo", "utf8") : "";
|
|
62
|
+
}
|
|
63
|
+
const processHost = () => ({ platform: HOST_PLATFORM, euid: process.geteuid?.(), mountinfo: processMountinfo });
|
|
64
|
+
const UNREACHABLE = new Set(["ENOENT", "ENOTDIR"]);
|
|
65
|
+
const NOT_REACHED = { reached: false };
|
|
66
|
+
function typeOf(st) {
|
|
67
|
+
if (st.isDirectory())
|
|
68
|
+
return "directory";
|
|
69
|
+
if (st.isFIFO())
|
|
70
|
+
return "fifo";
|
|
71
|
+
if (st.isSocket())
|
|
72
|
+
return "socket";
|
|
73
|
+
if (st.isCharacterDevice())
|
|
74
|
+
return "character device";
|
|
75
|
+
if (st.isBlockDevice())
|
|
76
|
+
return "block device";
|
|
77
|
+
return "non-regular file";
|
|
78
|
+
}
|
|
79
|
+
function componentVerdict(p, st, owners) {
|
|
80
|
+
if (!owners.has(st.uid))
|
|
81
|
+
return { kind: "owner", path: p, uid: st.uid };
|
|
82
|
+
if (st.isSymbolicLink() || (st.mode & 0o022) === 0)
|
|
83
|
+
return "closed";
|
|
84
|
+
if (st.isDirectory() && (st.mode & 0o1000) !== 0)
|
|
85
|
+
return "open";
|
|
86
|
+
return { kind: "writable", path: p, mode: st.mode & 0o7777 };
|
|
87
|
+
}
|
|
88
|
+
const KUBELET_NODE_SIDE_TAG = "server.config-dir-trust.kubelet-volume-node-side-unverifiable";
|
|
89
|
+
const KUBELET_TIMESTAMP_DIR = /^\.\.\d{4}_\d{2}_\d{2}_\d{2}_\d{2}_\d{2}\.\d+$/;
|
|
90
|
+
const KUBELET_DATA_LINKS = new Set(["..data", "..data_tmp"]);
|
|
91
|
+
async function projectedVolumeRoot(dir, mode, ctx) {
|
|
92
|
+
const listing = await readdir(dir).then((names) => ({ names }), (error) => ({ error }));
|
|
93
|
+
if ("error" in listing)
|
|
94
|
+
return false;
|
|
95
|
+
const names = listing.names;
|
|
96
|
+
if (!names.includes("..data"))
|
|
97
|
+
return false;
|
|
98
|
+
let at = dir;
|
|
99
|
+
let volume;
|
|
100
|
+
try {
|
|
101
|
+
const stampDirs = new Set();
|
|
102
|
+
const linkTargets = [];
|
|
103
|
+
for (const name of names) {
|
|
104
|
+
at = path.posix.join(dir, name);
|
|
105
|
+
const st = await lstat(at);
|
|
106
|
+
if (!ctx.owners.has(st.uid))
|
|
107
|
+
return false;
|
|
108
|
+
if (KUBELET_DATA_LINKS.has(name)) {
|
|
109
|
+
if (!st.isSymbolicLink())
|
|
110
|
+
return false;
|
|
111
|
+
linkTargets.push(await readlink(at));
|
|
112
|
+
}
|
|
113
|
+
else if (KUBELET_TIMESTAMP_DIR.test(name)) {
|
|
114
|
+
if (!st.isDirectory() || componentVerdict(at, st, ctx.owners) !== "closed")
|
|
115
|
+
return false;
|
|
116
|
+
stampDirs.add(name);
|
|
117
|
+
}
|
|
118
|
+
else if (name.startsWith("..") || !st.isSymbolicLink() || (await readlink(at)) !== `..data/${name}`) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!linkTargets.every((target) => stampDirs.has(target)))
|
|
123
|
+
return false;
|
|
124
|
+
at = "/proc/self/mountinfo";
|
|
125
|
+
volume = kubeletVolumeIn(await ctx.mountinfo(), dir);
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
return { kind: "unreadable", path: at, errno: errnoOf(e) ?? String(e) };
|
|
129
|
+
}
|
|
130
|
+
if (volume === undefined)
|
|
131
|
+
return false;
|
|
132
|
+
const exposure = volume.writableExposures[0];
|
|
133
|
+
if (exposure !== undefined)
|
|
134
|
+
return { kind: "exposed", path: exposure.path, mountPoint: exposure.mountPoint, volume: dir, mode };
|
|
135
|
+
recordFailOpen(KUBELET_NODE_SIDE_TAG, `volume=${dir} source=${volume.source}`);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
async function judgeComponent(p, st, ctx) {
|
|
139
|
+
const v = componentVerdict(p, st, ctx.owners);
|
|
140
|
+
if (typeof v === "string" || v.kind !== "writable" || !st.isDirectory())
|
|
141
|
+
return v;
|
|
142
|
+
const projected = await projectedVolumeRoot(p, v.mode, ctx);
|
|
143
|
+
if (projected === true)
|
|
144
|
+
return "closed";
|
|
145
|
+
return projected === false ? v : projected;
|
|
146
|
+
}
|
|
147
|
+
const isStats = (x) => "isDirectory" in x;
|
|
148
|
+
async function lstatStep(p) {
|
|
149
|
+
try {
|
|
150
|
+
return await lstat(p);
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
const code = errnoOf(e);
|
|
154
|
+
if (code !== undefined && UNREACHABLE.has(code))
|
|
155
|
+
return NOT_REACHED;
|
|
156
|
+
return { finding: { kind: "unreadable", path: p, errno: code ?? String(e) } };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
async function walk(from, pending, want, ctx) {
|
|
160
|
+
let cur = from.start;
|
|
161
|
+
let st = from.stats;
|
|
162
|
+
let open = from.open;
|
|
163
|
+
let hops = from.hops;
|
|
164
|
+
const queue = [...pending];
|
|
165
|
+
const enter = async (p) => {
|
|
166
|
+
const got = await lstatStep(p);
|
|
167
|
+
if (!isStats(got))
|
|
168
|
+
return got;
|
|
169
|
+
const v = await judgeComponent(p, got, ctx);
|
|
170
|
+
if (typeof v !== "string")
|
|
171
|
+
return { finding: v };
|
|
172
|
+
cur = p;
|
|
173
|
+
st = got;
|
|
174
|
+
open = v === "open";
|
|
175
|
+
return undefined;
|
|
176
|
+
};
|
|
177
|
+
while (queue.length > 0) {
|
|
178
|
+
const name = queue.shift();
|
|
179
|
+
if (name === "" || name === ".")
|
|
180
|
+
continue;
|
|
181
|
+
if (name === "..") {
|
|
182
|
+
const stop = await enter(path.posix.dirname(cur));
|
|
183
|
+
if (stop !== undefined)
|
|
184
|
+
return stop;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const next = path.posix.join(cur, name);
|
|
188
|
+
const got = await lstatStep(next);
|
|
189
|
+
if (!isStats(got)) {
|
|
190
|
+
if (!("reached" in got) || !open)
|
|
191
|
+
return got;
|
|
192
|
+
return { finding: { kind: "creatable", path: next, parent: cur, mode: st.mode & 0o7777 } };
|
|
193
|
+
}
|
|
194
|
+
const v = await judgeComponent(next, got, ctx);
|
|
195
|
+
if (typeof v !== "string")
|
|
196
|
+
return { finding: v };
|
|
197
|
+
if (got.isSymbolicLink()) {
|
|
198
|
+
if (++hops > CONFIG_DIR_LINK_HOPS_MAX)
|
|
199
|
+
return { finding: { kind: "link-loop", path: next } };
|
|
200
|
+
let target;
|
|
201
|
+
try {
|
|
202
|
+
target = await readlink(next);
|
|
203
|
+
}
|
|
204
|
+
catch (e) {
|
|
205
|
+
const code = errnoOf(e);
|
|
206
|
+
if (code !== undefined && UNREACHABLE.has(code))
|
|
207
|
+
return NOT_REACHED;
|
|
208
|
+
return { finding: { kind: "unreadable", path: next, errno: code ?? String(e) } };
|
|
209
|
+
}
|
|
210
|
+
queue.unshift(...target.split("/"));
|
|
211
|
+
if (target.startsWith("/")) {
|
|
212
|
+
const stop = await enter("/");
|
|
213
|
+
if (stop !== undefined)
|
|
214
|
+
return stop;
|
|
215
|
+
}
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (queue.some((n) => n !== "" && n !== ".") && !got.isDirectory())
|
|
219
|
+
return NOT_REACHED;
|
|
220
|
+
cur = next;
|
|
221
|
+
st = got;
|
|
222
|
+
open = v === "open";
|
|
223
|
+
}
|
|
224
|
+
if (want === "dir")
|
|
225
|
+
return st.isDirectory() ? { reached: true, physical: cur, stats: st, open, hops } : NOT_REACHED;
|
|
226
|
+
if (!st.isFile())
|
|
227
|
+
return { finding: { kind: "not-regular", path: cur, type: typeOf(st) } };
|
|
228
|
+
if (st.size > CONFIG_DOCUMENT_MAX_BYTES)
|
|
229
|
+
return { finding: { kind: "too-large", path: cur, bytes: st.size } };
|
|
230
|
+
return { reached: true, physical: cur, stats: st, open, hops };
|
|
231
|
+
}
|
|
232
|
+
async function confirmUnreached(lexical) {
|
|
233
|
+
try {
|
|
234
|
+
await stat(lexical);
|
|
235
|
+
}
|
|
236
|
+
catch (e) {
|
|
237
|
+
const code = errnoOf(e);
|
|
238
|
+
if (code !== undefined && UNREACHABLE.has(code))
|
|
239
|
+
return undefined;
|
|
240
|
+
if (code === "ELOOP")
|
|
241
|
+
return { kind: "link-loop", path: lexical };
|
|
242
|
+
return { kind: "unreadable", path: lexical, errno: code ?? String(e) };
|
|
243
|
+
}
|
|
244
|
+
return { kind: "unresolvable", path: lexical };
|
|
245
|
+
}
|
|
246
|
+
const documentFiles = () => LOCAL_READER_DOCUMENTS.map((d) => `${d}.json`);
|
|
247
|
+
async function reachDir(lexical, ctx) {
|
|
248
|
+
const top = await lstatStep("/");
|
|
249
|
+
if (!isStats(top))
|
|
250
|
+
return "finding" in top ? top.finding : undefined;
|
|
251
|
+
const rootVerdict = await judgeComponent("/", top, ctx);
|
|
252
|
+
if (typeof rootVerdict !== "string")
|
|
253
|
+
return rootVerdict;
|
|
254
|
+
const step = await walk({ start: "/", stats: top, open: rootVerdict === "open", hops: 0 }, lexical.split("/"), "dir", ctx);
|
|
255
|
+
if ("finding" in step)
|
|
256
|
+
return step.finding;
|
|
257
|
+
return step.reached ? step : confirmUnreached(lexical);
|
|
258
|
+
}
|
|
259
|
+
async function judgePosix(configDir, ctx) {
|
|
260
|
+
const dir = await reachDir(configDir, ctx);
|
|
261
|
+
if (dir === undefined || "kind" in dir)
|
|
262
|
+
return dir;
|
|
263
|
+
for (const file of documentFiles()) {
|
|
264
|
+
const doc = await walk({ start: dir.physical, stats: dir.stats, open: dir.open, hops: dir.hops }, [file], "file", ctx);
|
|
265
|
+
if ("finding" in doc)
|
|
266
|
+
return doc.finding;
|
|
267
|
+
if (!doc.reached) {
|
|
268
|
+
const unseen = await confirmUnreached(path.join(configDir, file));
|
|
269
|
+
if (unseen !== undefined)
|
|
270
|
+
return unseen;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
async function judgeWin32(configDir) {
|
|
276
|
+
const resolveStep = async (p) => {
|
|
277
|
+
try {
|
|
278
|
+
return await realpath(p);
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
const code = errnoOf(e);
|
|
282
|
+
if (code !== undefined && UNREACHABLE.has(code))
|
|
283
|
+
return undefined;
|
|
284
|
+
if (code === "ELOOP")
|
|
285
|
+
return { kind: "link-loop", path: p };
|
|
286
|
+
return { kind: "unreadable", path: p, errno: code ?? String(e) };
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const dir = await resolveStep(configDir);
|
|
290
|
+
if (dir === undefined)
|
|
291
|
+
return undefined;
|
|
292
|
+
if (typeof dir !== "string")
|
|
293
|
+
return dir;
|
|
294
|
+
if (!(await stat(dir)).isDirectory())
|
|
295
|
+
return undefined;
|
|
296
|
+
for (const file of documentFiles()) {
|
|
297
|
+
const doc = await resolveStep(path.join(dir, file));
|
|
298
|
+
if (doc === undefined)
|
|
299
|
+
continue;
|
|
300
|
+
if (typeof doc !== "string")
|
|
301
|
+
return doc;
|
|
302
|
+
const st = await stat(doc);
|
|
303
|
+
if (!st.isFile())
|
|
304
|
+
return { kind: "not-regular", path: doc, type: typeOf(st) };
|
|
305
|
+
if (st.size > CONFIG_DOCUMENT_MAX_BYTES)
|
|
306
|
+
return { kind: "too-large", path: doc, bytes: st.size };
|
|
307
|
+
}
|
|
308
|
+
recordFailOpen(WIN32_UNVERIFIED_TAG, `config.d=${dir}`);
|
|
309
|
+
return undefined;
|
|
310
|
+
}
|
|
311
|
+
export function localConfigDirOf(root) {
|
|
312
|
+
return path.join(path.resolve(root), "config.d");
|
|
313
|
+
}
|
|
314
|
+
export async function judgeLocalConfigDir(input) {
|
|
315
|
+
const host = input.host ?? processHost();
|
|
316
|
+
const configDir = localConfigDirOf(input.root);
|
|
317
|
+
if (host.platform === "win32")
|
|
318
|
+
return judgeWin32(configDir);
|
|
319
|
+
const owners = new Set([0]);
|
|
320
|
+
if (host.euid !== undefined)
|
|
321
|
+
owners.add(host.euid);
|
|
322
|
+
if (input.declaredOwnerUid !== undefined)
|
|
323
|
+
owners.add(input.declaredOwnerUid);
|
|
324
|
+
return judgePosix(configDir, { owners, mountinfo: host.mountinfo ?? processMountinfo });
|
|
325
|
+
}
|
|
326
|
+
const octal = (mode) => `0${(mode & 0o7777).toString(8).padStart(3, "0")}`;
|
|
327
|
+
export function buildConfigDirUntrustedSentence(f, ctx) {
|
|
328
|
+
const self = ctx.euid === undefined ? "this server's user" : `this server's user (uid ${ctx.euid})`;
|
|
329
|
+
const declared = ctx.declaredOwnerUid === undefined ? "" : ` or the declared owner ${CONFIG_LOCAL_OWNER_UID_ENV}=${ctx.declaredOwnerUid}`;
|
|
330
|
+
const head = `${CONFIG_DIR_UNTRUSTED_CODE}: refusing to read the local config source ${ctx.configDir} — its documents decide which commands this server starts (mcp.json) ` +
|
|
331
|
+
`and where it sends credentials (models.json), so only ${self}, root${declared} may be able to change them, but`;
|
|
332
|
+
switch (f.kind) {
|
|
333
|
+
case "owner":
|
|
334
|
+
return (`${head} ${f.path} is owned by uid ${f.uid}${ctx.declaredOwnerUid === undefined ? ` (${CONFIG_LOCAL_OWNER_UID_ENV} is not set)` : ""}. ` +
|
|
335
|
+
`Fix: chown ${ctx.euid ?? "<this server's uid>"} ${f.path}, or declare that owner with ${CONFIG_LOCAL_OWNER_UID_ENV}=${f.uid}.`);
|
|
336
|
+
case "writable": {
|
|
337
|
+
const who = (f.mode & 0o020) !== 0 && (f.mode & 0o002) !== 0 ? "group- and other" : (f.mode & 0o020) !== 0 ? "group" : "other";
|
|
338
|
+
return `${head} ${f.path} is ${who}-writable (mode ${octal(f.mode)}). Fix: chmod go-w ${f.path}.`;
|
|
339
|
+
}
|
|
340
|
+
case "not-regular":
|
|
341
|
+
return `${head} ${f.path} is a ${f.type}, not a regular file. Fix: replace it with a regular file, or remove it.`;
|
|
342
|
+
case "too-large":
|
|
343
|
+
return `${head} ${f.path} is ${f.bytes} bytes, over the ${CONFIG_DOCUMENT_MAX_BYTES}-byte cap for one config document. Fix: shrink it.`;
|
|
344
|
+
case "link-loop":
|
|
345
|
+
return `${head} ${f.path} leads through more than ${CONFIG_DIR_LINK_HOPS_MAX} symbolic links. Fix: point the link at the file directly.`;
|
|
346
|
+
case "unreadable":
|
|
347
|
+
return `${head} ${f.path} cannot be inspected (${f.errno}), so its owner and mode cannot be checked. Fix: give this server's user search access to every directory on the path.`;
|
|
348
|
+
case "creatable":
|
|
349
|
+
return (`${head} ${f.path} does not exist and ${f.parent} (mode ${octal(f.mode)}) lets other users create it between this check and the read. ` +
|
|
350
|
+
`Fix: create ${f.path} as this server's user, or move the config root (CONFIG_LOCAL_DIR) under a directory only this server's user or root can write.`);
|
|
351
|
+
case "unresolvable":
|
|
352
|
+
return `${head} ${f.path} is a symbolic link that does not resolve to a path (it points at a kernel object such as a /proc descriptor), so its owner and mode cannot be checked. Fix: point it at a regular file.`;
|
|
353
|
+
case "exposed":
|
|
354
|
+
return (`${head} ${f.volume} is a read-only Kubernetes ConfigMap volume whose source is also reachable through the writable mount at ${f.mountPoint}, as ${f.path} ` +
|
|
355
|
+
`(mode ${octal(f.mode)}), so whoever can reach that path can replace these documents between this check and the read. ` +
|
|
356
|
+
`Fix: remove the writable mount at ${f.mountPoint} — do not mount the node's root, its kubelet directory or any other ancestor of that directory writable into this pod; mount the config with subPath, or do not mount that ancestor at all. Do not relax permissions on the node.`);
|
|
357
|
+
default: {
|
|
358
|
+
const unhandled = f;
|
|
359
|
+
throw new Error(`buildConfigDirUntrustedSentence: unhandled finding ${JSON.stringify(unhandled)}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
export class ConfigDirUntrustedError extends Error {
|
|
364
|
+
code = CONFIG_DIR_UNTRUSTED_CODE;
|
|
365
|
+
finding;
|
|
366
|
+
constructor(sentence, finding) {
|
|
367
|
+
super(sentence);
|
|
368
|
+
this.name = "ConfigDirUntrustedError";
|
|
369
|
+
this.finding = finding;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
export async function assertLocalConfigDirTrusted(input) {
|
|
373
|
+
const host = input.host ?? processHost();
|
|
374
|
+
const finding = await judgeLocalConfigDir({ ...input, host });
|
|
375
|
+
if (finding === undefined)
|
|
376
|
+
return;
|
|
377
|
+
throw new ConfigDirUntrustedError(buildConfigDirUntrustedSentence(finding, { configDir: localConfigDirOf(input.root), euid: host.euid, declaredOwnerUid: input.declaredOwnerUid }), finding);
|
|
378
|
+
}
|
|
379
|
+
export function parseConfigLocalOwnerUid(raw) {
|
|
380
|
+
if (raw === undefined)
|
|
381
|
+
return undefined;
|
|
382
|
+
const n = /^(0|[1-9][0-9]{0,9})$/.test(raw) ? Number(raw) : Number.NaN;
|
|
383
|
+
if (Number.isInteger(n) && n <= UID_MAX)
|
|
384
|
+
return n;
|
|
385
|
+
throw new Error(`env ${CONFIG_LOCAL_OWNER_UID_ENV}=${JSON.stringify(raw)} must be a uid — a decimal integer in [0, ${UID_MAX}]: the one extra owner (besides this server's user and root) ` +
|
|
386
|
+
`the local config source's directories and documents may have (a userns-remapped bind mount, an operator-owned config). Unset it to trust only this server's user and root.`);
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=config-dir-trust.js.map
|
|
@@ -34,9 +34,9 @@ import type { ServiceConfigFlat } from "./config-types.js";
|
|
|
34
34
|
*/
|
|
35
35
|
export declare const LIVENESS_HEARTBEAT_MS = 30000;
|
|
36
36
|
/** 闭集:新增一条不变量必须在这里加词(拼错 = 编译红,而不是运行期悄悄不判)。 */
|
|
37
|
-
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "multi-tenant-shared-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "model-route-endpoint" | "default-model-resolvable" | "refused-names-not-minted" | "require-execution-lane" | "center-one-identity";
|
|
37
|
+
export type CrossInvariantId = "run-stale-heartbeat" | "bind-posture" | "bake-runner-credential" | "direct-door-anchors" | "operator-principals-required" | "operator-single-user" | "bake-operator-principals" | "sensitive-write-patterns" | "leader-host-lane" | "multi-tenant-shared-lane" | "leader-durable-store" | "device-durable-store" | "device-durable-approval" | "model-provider-word" | "gateway-url-userinfo" | "model-route-endpoint" | "default-model-resolvable" | "refused-names-not-minted" | "require-execution-lane" | "center-one-identity" | "workflow-park-decision-domain";
|
|
38
38
|
/** 表读的键集(取自平铺配置型 ⇒ 键名/类型永不与真配置漂)。 */
|
|
39
|
-
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "sensitiveWritePatterns" | "leaderEnabled" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models" | "modelRefusals" | "tiers" | "authBridgeIssuer" | "webAdmin">>;
|
|
39
|
+
export type CrossInvariantView = Readonly<Pick<ServiceConfigFlat, "runStaleSec" | "authToken" | "authTokens" | "allowUnauthedWrites" | "imageBakes" | "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals" | "operatorSingleUser" | "sensitiveWritePatterns" | "leaderEnabled" | "selfOrchestrationEnabled" | "workflowRunStoreBackend" | "remoteExec" | "requireExecutionLane" | "dbBackend" | "tidb" | "pg" | "envModel" | "gatewayBaseUrl" | "gatewayFallbackUrls" | "anthropic" | "models" | "modelRefusals" | "tiers" | "authBridgeIssuer" | "webAdmin">>;
|
|
40
40
|
export interface CrossInvariantInput {
|
|
41
41
|
/** 现役配置(boot 期 = 候选自身)。 */
|
|
42
42
|
readonly live: CrossInvariantView;
|
|
@@ -68,11 +68,17 @@ export interface CrossInvariant {
|
|
|
68
68
|
/** `direct-door-anchors` 的状态臂:半开的直连门(开着却缺锚点)。转换臂(门姿态翻转)只活在热路径,留在条目里。 */
|
|
69
69
|
export declare function halfOpenDirectDoorRefusal(v: Pick<CrossInvariantView, "directApprovalDoor" | "durableApproval" | "approvalHmacKeys" | "principalJwtPubkeys" | "principalJwtIss" | "principalJwtAud" | "requirePrincipal" | "operatorPrincipals">): string | undefined;
|
|
70
70
|
/**
|
|
71
|
-
* `operator-principals-required`([ref]-① 普查候选 1/2):BFF 多租户 durable 形(DURABLE_APPROVAL ∧ REQUIRE_PRINCIPAL,直连门关)的空 operator
|
|
72
|
-
*
|
|
71
|
+
* `operator-principals-required`([ref]-① 普查候选 1/2):BFF 多租户 durable 形(DURABLE_APPROVAL ∧ REQUIRE_PRINCIPAL,直连门关)的空 operator 名单。
|
|
72
|
+
* 这条不变量生于审批四读面读「空名单 = 人人是」那条读法的年代(那时它防的是跨租户读待批队列);S-1050 删了那条读法 —— 空名单在每一面都是「没人是」,
|
|
73
|
+
* 不再外泄任何东西 —— 剩下的事实是「这台多租 worker 的审批队列没有人能当运维」。本版只把句子改真、不改拒启集;删不删这一条是另一次表态。
|
|
73
74
|
*/
|
|
74
75
|
export declare function operatorPrincipalsRequiredRefusal(v: Pick<CrossInvariantView, "durableApproval" | "requirePrincipal" | "operatorPrincipals">): string | undefined;
|
|
75
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* `operator-single-user`(S-1050,[ref] ① 裁 A):「谁是 operator」一个事实一个来源。`OPERATOR_SINGLE_USER=true`(单用户形的每个调用方都是运维)
|
|
78
|
+
* 只在单用户形、名单为空时成立:多租形没有「单一用户」(声明会把每个租户都变成运维);名单非空时两个来源答同一个问题。两形都拒,句子点名两根旋钮与出路。
|
|
79
|
+
*/
|
|
80
|
+
export declare function operatorSingleUserRefusal(v: Pick<CrossInvariantView, "operatorSingleUser" | "requirePrincipal" | "operatorPrincipals">): string | undefined;
|
|
81
|
+
/** `bake-operator-principals`(IMAGE-API-DESIGN §P2.4a):bake 门是 build-host 无限制执行面,要**具名**运维 —— 空名单下要么没人用得了,要么(单用户声明)人人用得了。 */
|
|
76
82
|
export declare function bakeOperatorPrincipalsRefusal(v: Pick<CrossInvariantView, "imageBakes" | "operatorPrincipals">): string | undefined;
|
|
77
83
|
/**
|
|
78
84
|
* `bake-runner-credential`(IMAGE-API-DESIGN §P2.12 / H1):bake-runner 的身份由它的 bearer 凭据**派生**(token-derived `source`),不是自称的头 ——
|
|
@@ -84,6 +90,13 @@ export declare function bakeRunnerCredentialRefusal(v: Pick<CrossInvariantView,
|
|
|
84
90
|
* 「多副本」在 config 层判不了(副本数不是本进程的知识),可判的**代理**就是 durable 前提本身。
|
|
85
91
|
*/
|
|
86
92
|
export declare function leaderDurableStoreRefusal(v: Pick<CrossInvariantView, "leaderEnabled" | "dbBackend">): string | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* `workflow-park-decision-domain`(7.133.0)—— workflow 子代审批决定行的店必须与会话认领同域。决定行在 run 店的会话认领栅栏里写(SQL 后端一个事务、同一只池),
|
|
95
|
+
* 而库里的决定行随库里的 workflow 记录收割 ⇒ SQL 后端上 workflow 记录也必须在库里(`WORKFLOW_RUN_STORE=auto`)。`file` / `memory` 把记录放在库外,没有一只决定店两头都满足。
|
|
96
|
+
* 判的是**这份配置会不会装出 SQL 店**(坐标铸出来了没有,与 `device-durable-store` 同读法),不是 `dbBackend` 标签。**配置组合的拒启** —— 判在第 1 段(loadConfig),
|
|
97
|
+
* 先于第 3 段的一次性迁移:拒的那一次起服没有动过库。`createHttpServer` 里的 `parkDecisionStoreRefusal` 判的是另一件事(嵌入方递进来的决定店绑没绑在这只 run 店上,按身份比)。
|
|
98
|
+
*/
|
|
99
|
+
export declare function workflowParkDecisionDomainRefusal(v: Pick<CrossInvariantView, "selfOrchestrationEnabled" | "workflowRunStoreBackend" | "dbBackend" | "tidb" | "pg">): string | undefined;
|
|
87
100
|
/**
|
|
88
101
|
* `center-one-identity`(7.124.0)—— **中心只有一个身份**。引擎接的 web-admin 由三只旋钮描述:基址(`WEB_ADMIN_ENV.url`,传输地址)、
|
|
89
102
|
* 鉴权桥 issuer(`AUTH_BRIDGE_ISSUER`,缺席 = 基址 —— {@link authBridgeIssuerOf} 一只取值口)、web 基址(`WEB_ADMIN_ENV.webUrl`,上
|
|
@@ -34,19 +34,28 @@ export function halfOpenDirectDoorRefusal(v) {
|
|
|
34
34
|
if (!v.principalJwtAud)
|
|
35
35
|
missing.push("PRINCIPAL_JWT_AUD");
|
|
36
36
|
if (v.operatorPrincipals.length === 0)
|
|
37
|
-
missing.push("OPERATOR_PRINCIPALS (
|
|
37
|
+
missing.push("OPERATOR_PRINCIPALS (an empty list means no operator, and the direct door's operator faces need named operators)");
|
|
38
38
|
if (!v.requirePrincipal)
|
|
39
39
|
missing.push("REQUIRE_PRINCIPAL=true (a direct door is multi-tenant; without it an absent principal is anonymous and the self-asserted header governs owner/quota checks)");
|
|
40
40
|
return missing.length > 0 ? `DIRECT_APPROVAL_DOOR=true but D-G anchors are missing: ${missing.join(", ")} — refusing to start a half-open direct door (design/80 D-G boot invariant)` : undefined;
|
|
41
41
|
}
|
|
42
42
|
export function operatorPrincipalsRequiredRefusal(v) {
|
|
43
43
|
return v.durableApproval === true && v.requirePrincipal && v.operatorPrincipals.length === 0
|
|
44
|
-
? "DURABLE_APPROVAL=true + REQUIRE_PRINCIPAL=true but OPERATOR_PRINCIPALS is empty —
|
|
44
|
+
? "DURABLE_APPROVAL=true + REQUIRE_PRINCIPAL=true but OPERATOR_PRINCIPALS is empty — an empty operator list means no operator, so nobody could operate this multi-tenant worker's approval queue (list any owner's pending via GET /v1/approvals & siblings, decide any approval). Set OPERATOR_PRINCIPALS, or unset REQUIRE_PRINCIPAL if this is a single-tenant deployment (#157-① boot invariant)"
|
|
45
45
|
: undefined;
|
|
46
46
|
}
|
|
47
|
+
export function operatorSingleUserRefusal(v) {
|
|
48
|
+
if (v.operatorSingleUser !== true)
|
|
49
|
+
return undefined;
|
|
50
|
+
if (v.requirePrincipal)
|
|
51
|
+
return "OPERATOR_SINGLE_USER=true but REQUIRE_PRINCIPAL=true — the declaration makes every caller an operator, which only fits a single-user deployment; a multi-tenant worker names its operators in OPERATOR_PRINCIPALS. Unset OPERATOR_SINGLE_USER, or unset REQUIRE_PRINCIPAL if this is a single-user deployment";
|
|
52
|
+
if (v.operatorPrincipals.length > 0)
|
|
53
|
+
return "OPERATOR_SINGLE_USER=true but OPERATOR_PRINCIPALS is also set — the two answer the same question (who is an operator) in two ways. Keep one: OPERATOR_SINGLE_USER=true (every caller of this single-user deployment) or OPERATOR_PRINCIPALS (only the named principals)";
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
47
56
|
export function bakeOperatorPrincipalsRefusal(v) {
|
|
48
57
|
return v.imageBakes.enabled && v.operatorPrincipals.length === 0
|
|
49
|
-
? "IMAGE_BAKES_ENABLED=true but OPERATOR_PRINCIPALS is empty — the bake door runs build.sh on the privileged build host
|
|
58
|
+
? "IMAGE_BAKES_ENABLED=true but OPERATOR_PRINCIPALS is empty — the bake door runs build.sh on the privileged build host and needs named operators: with an empty list nobody can use it, and the single-user operator declaration would open it to every caller (world-writable RCE). Set OPERATOR_PRINCIPALS or disable bakes (IMAGE-API-DESIGN.md §P2.4a boot invariant)"
|
|
50
59
|
: undefined;
|
|
51
60
|
}
|
|
52
61
|
export function bakeRunnerCredentialRefusal(v) {
|
|
@@ -64,6 +73,15 @@ export function leaderDurableStoreRefusal(v) {
|
|
|
64
73
|
"(#193 车4 件2 / staleness ledger P1-9+P1-10 boot invariant)"
|
|
65
74
|
: undefined;
|
|
66
75
|
}
|
|
76
|
+
export function workflowParkDecisionDomainRefusal(v) {
|
|
77
|
+
const sqlStore = (v.dbBackend === "mysql" && v.tidb !== undefined) || (v.dbBackend === "pg" && v.pg !== undefined);
|
|
78
|
+
return sqlStore && v.selfOrchestrationEnabled && v.workflowRunStoreBackend !== "auto"
|
|
79
|
+
? `DB_BACKEND=${v.dbBackend} with self-orchestration on and WORKFLOW_RUN_STORE=${v.workflowRunStoreBackend} is refused before any schema migration runs (the database was not touched) ` +
|
|
80
|
+
"[workflow-park-decision-domain]: a workflow approval decision is written in the same atomic step that checks the delivering run still holds the host session, so on a SQL backend it lives in the database " +
|
|
81
|
+
"with the session claims and is reaped with the workflow records — which this setting keeps off the database. " +
|
|
82
|
+
"Leave WORKFLOW_RUN_STORE=auto (unset it: the workflow records go to the same database), or turn self-orchestration off (SELF_ORCHESTRATION_ENABLED=false)"
|
|
83
|
+
: undefined;
|
|
84
|
+
}
|
|
67
85
|
export function centerIdentityRefusal(v) {
|
|
68
86
|
const webBaseUrl = v.webAdmin?.webBaseUrl;
|
|
69
87
|
if (webBaseUrl === undefined)
|
|
@@ -125,6 +143,13 @@ export const CONFIG_CROSS_INVARIANTS = [
|
|
|
125
143
|
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:operator-principals-required" },
|
|
126
144
|
check: ({ next }) => operatorPrincipalsRequiredRefusal(next),
|
|
127
145
|
},
|
|
146
|
+
{
|
|
147
|
+
id: "operator-single-user",
|
|
148
|
+
keys: ["operatorSingleUser", "requirePrincipal", "operatorPrincipals"],
|
|
149
|
+
restartReason: "operator-principals",
|
|
150
|
+
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:operator-single-user" },
|
|
151
|
+
check: ({ next }) => operatorSingleUserRefusal(next),
|
|
152
|
+
},
|
|
128
153
|
{
|
|
129
154
|
id: "bake-operator-principals",
|
|
130
155
|
keys: ["imageBakes", "operatorPrincipals"],
|
|
@@ -183,6 +208,13 @@ export const CONFIG_CROSS_INVARIANTS = [
|
|
|
183
208
|
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:leader-durable-store" },
|
|
184
209
|
check: ({ next }) => leaderDurableStoreRefusal(next),
|
|
185
210
|
},
|
|
211
|
+
{
|
|
212
|
+
id: "workflow-park-decision-domain",
|
|
213
|
+
keys: ["selfOrchestrationEnabled", "workflowRunStoreBackend", "dbBackend", "tidb", "pg"],
|
|
214
|
+
restartReason: "workflow-orchestration",
|
|
215
|
+
bootAnchor: { file: "src/config.ts", marker: "CROSS-INVARIANT:workflow-park-decision-domain" },
|
|
216
|
+
check: ({ next }) => workflowParkDecisionDomainRefusal(next),
|
|
217
|
+
},
|
|
186
218
|
{
|
|
187
219
|
id: "device-durable-store",
|
|
188
220
|
keys: ["remoteExec", "dbBackend", "tidb", "pg"],
|
|
@@ -127,6 +127,9 @@ export interface ConfigProviderInput {
|
|
|
127
127
|
* `process.cwd()`,而工厂只在 `CONFIG_PROVIDER === "local"` 字面上递它 ⇒ 另一条走到 local 的路上配置源读 cwd、
|
|
128
128
|
* 合成步读 localRoot,两个根分家。一个远程源也收它:`remote` 而无中心 URL 的形照样落回 local。 */
|
|
129
129
|
localDir: string;
|
|
130
|
+
/** S-163:本地配置源的属主声明(`CONFIG_LOCAL_OWNER_UID`,配置席 `configLocalOwnerUid`)—— 每拍读 `config.d` 之前的目录信任判官与起服那一次判同一个值。
|
|
131
|
+
* **必填**(值可以是 `undefined` = 没声明):两个生产构造点都必须递,漏递 = 起服判过、每拍却按「没声明」判 ⇒ 每一拍都拒(tsc 在这里挡)。 */
|
|
132
|
+
localOwnerUid: number | undefined;
|
|
130
133
|
/** S-1556:远程配置源的技能正文盘缓存目录(见 {@link ConfigProvider.skillBodyCacheDir});本地配置源不认它(正文本就在盘上)。缺席 = 不落盘。 */
|
|
131
134
|
skillBodyCacheDir?: string;
|
|
132
135
|
}
|
|
@@ -165,7 +168,9 @@ export declare class LocalConfigProvider implements ConfigProvider {
|
|
|
165
168
|
/** [ref]b 可观测性:config_loaded 日志要能回答「到底读的哪个目录」——复验实录:只设 LOCAL_DATA_ROOT 时
|
|
166
169
|
* config.d 静默读不到且 0 模型无告警(CONFIG_LOCAL_DIR 才是本 lane 的选目录旋钮)。 */
|
|
167
170
|
readonly root: string;
|
|
168
|
-
constructor(root: string, store?: FileConfigStore
|
|
171
|
+
constructor(root: string, store?: FileConfigStore, trust?: {
|
|
172
|
+
readonly declaredOwnerUid: number | undefined;
|
|
173
|
+
});
|
|
169
174
|
fetchEffective(etag: string | undefined): Promise<FetchEffectiveResult>;
|
|
170
175
|
fetchSkillContent(contentHash: string): Promise<string | undefined>;
|
|
171
176
|
}
|
package/dist/config-provider.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readMcpSourceLabel } from "./mcp-source-label.js";
|
|
|
2
2
|
import { createHmac, randomBytes } from "node:crypto";
|
|
3
3
|
import { retiredDomainFindingOf, splitFoldedReadWarnings, withDroppedCatalogEntries } from "./web-admin-client/read-warnings.js";
|
|
4
4
|
import { FileConfigStore } from "@sema-agent/settings-schema/node";
|
|
5
|
+
import { assertLocalConfigDirTrusted } from "./config-dir-trust.js";
|
|
5
6
|
import { danglingRefs, emptyEffective, findSkillContent, promptArtifactFor, renderRefIssue, skillContentHash, } from "@sema-agent/settings-schema";
|
|
6
7
|
import { redactSecrets } from "./trace/redact.js";
|
|
7
8
|
import { fetchEffective as remoteFetchEffective, fetchSkillContent as remoteFetchSkillContent, WebAdminHttpError, } from "./web-admin-client/facade.js";
|
|
@@ -75,12 +76,15 @@ export class LocalConfigProvider {
|
|
|
75
76
|
store;
|
|
76
77
|
root;
|
|
77
78
|
#injectedStore;
|
|
78
|
-
|
|
79
|
+
#declaredOwnerUid;
|
|
80
|
+
constructor(root, store, trust = { declaredOwnerUid: undefined }) {
|
|
79
81
|
this.root = root;
|
|
80
82
|
this.#injectedStore = store;
|
|
81
83
|
this.store = store ?? new FileConfigStore(root);
|
|
84
|
+
this.#declaredOwnerUid = trust.declaredOwnerUid;
|
|
82
85
|
}
|
|
83
86
|
async fetchEffective(etag) {
|
|
87
|
+
await assertLocalConfigDirTrusted({ root: this.root, declaredOwnerUid: this.#declaredOwnerUid });
|
|
84
88
|
const readWarnings = [];
|
|
85
89
|
const store = this.#injectedStore ??
|
|
86
90
|
new FileConfigStore(this.root, {
|
|
@@ -245,7 +249,7 @@ export function mapToServiceEffective(eff, version) {
|
|
|
245
249
|
export function createConfigProvider(input) {
|
|
246
250
|
return configProviderKind(input) === "remote" && input.webAdmin !== undefined
|
|
247
251
|
? new RemoteConfigProvider(input.webAdmin, {}, input.skillBodyCacheDir)
|
|
248
|
-
: new LocalConfigProvider(input.localDir);
|
|
252
|
+
: new LocalConfigProvider(input.localDir, undefined, { declaredOwnerUid: input.localOwnerUid });
|
|
249
253
|
}
|
|
250
254
|
export function configLocalRoot(config) {
|
|
251
255
|
return config.configLocalDir ?? process.env.AGENT_DATA_DIR ?? join(homedir(), ".ai-agent");
|