@sema-agent/server 7.132.0 → 7.133.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 +266 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +174 -55
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- 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 +31 -13
- 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 +79 -19
- package/dist/approval-card.js +44 -13
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- 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.js +2 -0
- 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/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.js +1 -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 +2 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -0
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -0
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +5 -6
- package/dist/boot/stores.js +2 -2
- package/dist/boot/web-admin.d.ts +4 -0
- package/dist/boot/web-admin.js +151 -63
- 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/caller-text-echo.d.ts +9 -6
- package/dist/caller-text-echo.js +8 -11
- 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 +27 -4
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -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 +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -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 +103 -60
- package/dist/http/approval-sweeps.js +55 -18
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +16 -16
- package/dist/http/checkpoint-ctx.js +13 -10
- 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 +10 -4
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +34 -10
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +48 -23
- package/dist/http/principal-gate.js +39 -12
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/request-guards.d.ts +16 -23
- package/dist/http/request-guards.js +30 -15
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +3 -4
- package/dist/http/resume-legs.js +126 -69
- 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 -28
- 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/approvals-assistant.js +49 -48
- 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.js +5 -1
- 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.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 +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +33 -106
- package/dist/http/routes/session-sync.js +15 -28
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +50 -14
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +17 -18
- package/dist/http/server.js +15 -13
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.js +4 -3
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +10 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -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/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/mcp-tool-faces.js +1 -3
- 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-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 +3 -17
- package/dist/observability/prompt-manifest.js +45 -42
- package/dist/observability/tool-trace.js +9 -9
- 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 +118 -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 +39 -6
- package/dist/parked-decide.js +98 -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/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/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 +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
- package/dist/plugins/checkpoint-store-sql.js +20 -2
- 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 +2 -0
- package/dist/plugins/local-checkpoint-store.js +6 -1
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -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 +110 -5
- package/dist/plugins/one-time-migrations.js +320 -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/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +29 -6
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- 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-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 +24 -4
- package/dist/plugins/tidb-session-store.js +28 -4
- 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-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 +36 -6
- package/dist/runs.d.ts +10 -9
- package/dist/runs.js +21 -3
- 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/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- 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-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +7 -66
- package/dist/task-settings.d.ts +89 -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 +303 -87
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +104 -22
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +3 -2
- package/dist/trace/project.d.ts +80 -12
- package/dist/trace/project.js +41 -28
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +298 -2
- package/dist/trace/wire-projection-faces.js +154 -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.js +4 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +7 -3
|
@@ -2,6 +2,8 @@ import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLev
|
|
|
2
2
|
import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableCatalog } from "../../model-select.js";
|
|
3
3
|
import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
|
|
4
4
|
import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
|
|
5
|
+
import { buildModelPlaneFace } from "../../model-plane-face.js";
|
|
6
|
+
import { isRosterGateArmed } from "../../config.js";
|
|
5
7
|
import { modelKeyPoisonOf, resolveModelApiKey } from "../../key-resolver.js";
|
|
6
8
|
import { projectSealedKeyCapability } from "../../sealed-key.js";
|
|
7
9
|
import { cwdHonored, deviceCwdHonored } from "../../task-cwd.js";
|
|
@@ -10,7 +12,7 @@ import { leaderEntryRefusal, leaderRunEntry } from "../../leader/run-entry.js";
|
|
|
10
12
|
import { autonomyKeepsOpenWriteFace, autonomyModeFloor } from "../../runtime-governance.js";
|
|
11
13
|
import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protocol.js";
|
|
12
14
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
13
|
-
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
15
|
+
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, McpProbeMisaligned, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
14
16
|
import { mcpForScenario } from "../../web-admin-client/facade.js";
|
|
15
17
|
import { sendScenarioNotFound } from "../scenario-read-face.js";
|
|
16
18
|
import { sendJson, sendError } from "../send.js";
|
|
@@ -21,6 +23,7 @@ import { projectWriteProtectionCapability } from "../../write-protection.js";
|
|
|
21
23
|
import { projectStoreCapability } from "../../store-posture.js";
|
|
22
24
|
import { projectWebSearchCapability } from "../../plugins/web-search.js";
|
|
23
25
|
import { projectExecutionLaneCapability } from "../../capabilities/execution-lane.js";
|
|
26
|
+
import { MCP_ASSERTION_HEADER_SENT } from "../../mcp-assertion-header.js";
|
|
24
27
|
import { gateCompositeMembers } from "../../capabilities/composite-members.js";
|
|
25
28
|
import { projectApprovalsStreamLiveCapability } from "../../capabilities/approvals-push.js";
|
|
26
29
|
import { workflowModelAllowlistFor } from "../../task-workflow.js";
|
|
@@ -29,6 +32,7 @@ import * as facts from "../../capability-facts.js";
|
|
|
29
32
|
import { judgeAutoModeArming } from "../../auto-mode-face.js";
|
|
30
33
|
import { coercePermissionModeStrict, PERMISSION_MODE_WORDS, taskHooksHonored } from "../../task-settings.js";
|
|
31
34
|
import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
|
|
35
|
+
import { callerTrust } from "../caller-trust.js";
|
|
32
36
|
function routePairingOf(deps, name, m) {
|
|
33
37
|
if (modelKeyPoisonOf(name, deps.config.modelApiKeyEnv ?? {}, process.env, deps.config.modelApiKeys ?? {}) !== undefined)
|
|
34
38
|
return "unknown";
|
|
@@ -72,12 +76,14 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
72
76
|
if (autoModeFault !== undefined)
|
|
73
77
|
deps.logger?.warn("auto_mode_face_resolver_fault", { fault: autoModeFault });
|
|
74
78
|
const rulesLaneForCaller = facts.ruleLaneForCaller(deps, gatedPrincipal(req, deps.config)).available;
|
|
79
|
+
const streamApprovalFact = facts.streamApproval(deps);
|
|
75
80
|
sendJson(res, 200, gateCompositeMembers({
|
|
76
81
|
...deps.capabilities,
|
|
77
82
|
...facts.engineCapabilityBits(),
|
|
78
83
|
asyncRuns: facts.durableRuns(deps).available,
|
|
79
84
|
artifacts: facts.durableRuns(deps).available,
|
|
80
85
|
approvals: facts.checkpointPark(deps).available,
|
|
86
|
+
approvalReadRootGrant: facts.readRootGrant(deps).available,
|
|
81
87
|
sessions: facts.sessionAuditView(deps).available,
|
|
82
88
|
deviceExecutor: facts.deviceLane(deps).available
|
|
83
89
|
? { enabled: true, protocolVersion: DEVICE_PROTOCOL_VERSION, maxInflightPerDevice: deps.config.remoteExec?.provider === "device" ? (deps.config.remoteExec.maxInflightPerDevice ?? 4) : 4, wsPath: DEVICE_WS_PATH, management: facts.deviceManagement(deps).available }
|
|
@@ -100,6 +106,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
100
106
|
mcpReconnect: facts.mcpReconnect(deps).available,
|
|
101
107
|
background: { listFace: facts.sessionOwnership(deps).available, exitFaces: facts.sessionOwnership(deps).available },
|
|
102
108
|
sharedMemory: facts.sharedMemoryRead(deps).available,
|
|
109
|
+
principalInboxDelivery: facts.principalInboxDelivery(deps).available,
|
|
103
110
|
adoption: facts.adoption(deps).available,
|
|
104
111
|
memoryBundle: facts.memoryBundle(deps).available,
|
|
105
112
|
memoryCompliance: facts.memoryCompliance(deps).available,
|
|
@@ -124,8 +131,8 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
124
131
|
scratchpadDir: true,
|
|
125
132
|
subagentSteer: facts.subagentSteer(deps).available,
|
|
126
133
|
subagentResume: facts.subagentSteer(deps).available,
|
|
127
|
-
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config) },
|
|
128
|
-
settings: { permissions: { allowGrant: true, allowLayer: true } },
|
|
134
|
+
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: cwdHonored(deps.config) || deviceCwdHonored(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), tightenOnlySeats: true },
|
|
135
|
+
settings: { permissions: { allowGrant: true, allowLayer: true, callerTrust: callerTrust(req, deps.config).trust } },
|
|
129
136
|
permissionModeAuto: {
|
|
130
137
|
accepted: true,
|
|
131
138
|
classifierSeat: deps.autoModeFace?.seatMounted === true,
|
|
@@ -160,11 +167,13 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
160
167
|
sessionInit: true,
|
|
161
168
|
mcp: true,
|
|
162
169
|
mcpProbe: true,
|
|
170
|
+
mcpAssertionHeaderSent: MCP_ASSERTION_HEADER_SENT,
|
|
163
171
|
mcpElicitation: facts.elicitation(deps).available,
|
|
164
172
|
askUserQuestion: facts.askUserQuestion(deps).available,
|
|
165
173
|
toolApproval: facts.toolApproval(deps).available,
|
|
166
174
|
approvalsStreamLive: projectApprovalsStreamLiveCapability(deps),
|
|
167
|
-
streamApproval:
|
|
175
|
+
streamApproval: streamApprovalFact.available,
|
|
176
|
+
approvalFrameFamilies: [...facts.approvalFrameFamilies(streamApprovalFact)],
|
|
168
177
|
approvalDecisionNote: true,
|
|
169
178
|
approvalDecidedBy: true,
|
|
170
179
|
permissionModes: [...PERMISSION_MODES],
|
|
@@ -273,6 +282,11 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
273
282
|
defaultModel: { id: deps.config.model.id, ...(defaultName ? { name: defaultName } : {}) },
|
|
274
283
|
droppedEntries: buildDroppedEntriesWire(deps.config.droppedCatalogEntries),
|
|
275
284
|
...(candidateRejection !== undefined ? { candidateRejected: buildCandidateRejectedWire(candidateRejection) } : {}),
|
|
285
|
+
modelPlane: buildModelPlaneFace(deps.config, {
|
|
286
|
+
envTableIsPlaceholder: isRosterGateArmed(deps.config.webAdmin),
|
|
287
|
+
candidateRejection,
|
|
288
|
+
modelRefusals: deps.modelRefusalsState?.(),
|
|
289
|
+
}),
|
|
276
290
|
});
|
|
277
291
|
return;
|
|
278
292
|
}
|
|
@@ -330,6 +344,8 @@ async function answerMcpProbe(res, ctx, answer, outcome, declaredBy) {
|
|
|
330
344
|
sendMcpProbeRefusal(res, ctx, buildMcpProbeIncompleteRefusal(err.boundMs), "failed", Math.ceil(err.boundMs / 1000));
|
|
331
345
|
return;
|
|
332
346
|
}
|
|
347
|
+
if (err instanceof McpProbeMisaligned)
|
|
348
|
+
throw err;
|
|
333
349
|
if (declaredBy === "caller") {
|
|
334
350
|
sendMcpProbeRefusal(res, ctx, buildMcpProbeDeclarationRefusal(), "failed");
|
|
335
351
|
return;
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* 门序 = operator 面口径:身份 → 能力(事实 `configCatalog`,501)→ 授权 → 应答;billable=false,
|
|
10
10
|
* 刻意不吃 drain / roster-pending 两道 503(排障读面在停机窗里恰恰要打得通)。
|
|
11
11
|
*
|
|
12
|
-
* 🔴 鉴权 = `explicitOperatorOk`(
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* 🔴 鉴权 = `explicitOperatorOk`(「谁是 operator」的唯一读法:空名单 = 谁都不是)—— 设计稿 §0.5 点名禁「空名单 = 人人都是」的 fail-open 读法
|
|
13
|
+
* (S-1050 起整只删):本面是部署事实外泄口(env 在场性 / 后端形态 / 限额值)。单用户形只在部署方显式声明 `OPERATOR_SINGLE_USER=true`
|
|
14
|
+
* (每个调用方都是运维)时对调用方开。
|
|
15
15
|
*
|
|
16
16
|
* 🔴 旋钮 `CONFIG_CATALOG_ENABLED=false` / operator 名单空 ⇒ 501(事实 `configCatalog`,与能力位同一只函数):
|
|
17
17
|
* 旋钮关 = `feature.config_catalog_disabled`(合规部署不想让部署事实上 wire 的表态;「去开旋钮」由码与句承担),
|
|
@@ -29,7 +29,7 @@ export async function handleConfigCatalog(req, res, match, ctx) {
|
|
|
29
29
|
return assertNever(fact.why);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
32
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
33
33
|
sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
@@ -47,14 +47,7 @@ function bodyKeyIssue(body, accepted) {
|
|
|
47
47
|
return `unknown key(s) in body: ${extra.join(", ")} — this endpoint accepts ${accepted.length === 0 ? "no body keys" : accepted.slice().sort().join(", ")} (a silently dropped key is a declaration that never existed)`;
|
|
48
48
|
}
|
|
49
49
|
async function readClosedBody(req, res, readJson, accepted) {
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
body = await readJson(req);
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
50
|
+
const body = await readJson(req);
|
|
58
51
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
59
52
|
sendError(res, 400, "request.body_shape", "body must be a JSON object");
|
|
60
53
|
return null;
|
|
@@ -151,7 +144,7 @@ export async function handleDevices(req, res, match, ctx) {
|
|
|
151
144
|
}
|
|
152
145
|
}
|
|
153
146
|
const { store, hub, enrollment, runStore } = lane;
|
|
154
|
-
const operator = explicitOperatorOk(principal, deps.config
|
|
147
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
155
148
|
const domain = deviceOwnerDomainOf(req, deps.config);
|
|
156
149
|
if (match.decl.id === "devices-list") {
|
|
157
150
|
if (!operator && domain === undefined) {
|
|
@@ -277,14 +270,7 @@ export async function handleDevices(req, res, match, ctx) {
|
|
|
277
270
|
sendDeviceNotFound(res);
|
|
278
271
|
return;
|
|
279
272
|
}
|
|
280
|
-
|
|
281
|
-
try {
|
|
282
|
-
body = (await readJson(req));
|
|
283
|
-
}
|
|
284
|
-
catch {
|
|
285
|
-
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
273
|
+
const body = (await readJson(req));
|
|
288
274
|
if (typeof body !== "object" || body === null || typeof body.toDeviceId !== "string" || body.expectedRev === undefined) {
|
|
289
275
|
sendError(res, 400, "request.body_shape", "body must be { toDeviceId: string, expectedRev: number } — expectedRev is the binding rev read from GET /v1/devices/sessions/{rootSessionId} (explicit prior state; two concurrent operators must not silently stomp each other)");
|
|
290
276
|
return;
|
|
@@ -15,24 +15,28 @@ export function buildServerWiringGates(input) {
|
|
|
15
15
|
parkFacility: input.checkpointStore !== undefined,
|
|
16
16
|
});
|
|
17
17
|
const noCenterArm = (knob) => `this knob has no web-admin arm on this deployment — it is set by ${knob} on this machine, or derived from the deployment posture`;
|
|
18
|
+
const noLaneArm = (knob) => `this knob has no execution-lane default — ${knob} does not depend on which execution lane this deployment runs`;
|
|
18
19
|
return {
|
|
19
20
|
streamApproval: gate.active ? "active" : gate.reason,
|
|
20
21
|
durableApproval: buildPostureKnobReading(input.durableApproval, {
|
|
21
22
|
knob: "DURABLE_APPROVAL",
|
|
22
23
|
source: input.durableApprovalSource,
|
|
23
24
|
centerMeaning: noCenterArm("DURABLE_APPROVAL"),
|
|
25
|
+
laneMeaning: noLaneArm("DURABLE_APPROVAL"),
|
|
24
26
|
postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set) composed with a durable store being present: park/resume and the /v1/approvals routes are on by default — set DURABLE_APPROVAL=false to pin them off",
|
|
25
27
|
}),
|
|
26
28
|
streamAskWindowMs: buildPostureKnobReading(input.streamAskWindowMs, {
|
|
27
29
|
knob: "STREAM_ASK_WINDOW_MS",
|
|
28
30
|
source: input.streamAskWindowMsSource,
|
|
29
31
|
centerMeaning: noCenterArm("STREAM_ASK_WINDOW_MS"),
|
|
32
|
+
laneMeaning: noLaneArm("STREAM_ASK_WINDOW_MS"),
|
|
30
33
|
postureMeaning: "derived from the single-user turnkey posture (REQUIRE_PRINCIPAL is not set): an approval card waits 24h instead of 5 minutes, so stepping away does not settle the run unattended — set STREAM_ASK_WINDOW_MS to pin your own window",
|
|
31
34
|
}),
|
|
32
35
|
sessionAutoTitle: buildPostureKnobReading(input.sessionAutoTitle, {
|
|
33
36
|
knob: "SESSION_AUTO_TITLE",
|
|
34
37
|
source: input.sessionAutoTitleSource,
|
|
35
38
|
centerMeaning: noCenterArm("SESSION_AUTO_TITLE"),
|
|
39
|
+
laneMeaning: noLaneArm("SESSION_AUTO_TITLE"),
|
|
36
40
|
postureMeaning: "this knob has no posture arm — its default is the same on every deployment shape",
|
|
37
41
|
}),
|
|
38
42
|
checkpointStore: input.checkpointStore !== undefined,
|
|
@@ -93,7 +97,7 @@ export async function handleDiagnostics(req, res, match, ctx) {
|
|
|
93
97
|
return;
|
|
94
98
|
}
|
|
95
99
|
const principal = gatedPrincipal(req, deps.config);
|
|
96
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
100
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
97
101
|
sendError(res, 403, "auth.operator_only", "wiring diagnostics are operator-only on a multi-tenant worker");
|
|
98
102
|
return;
|
|
99
103
|
}
|
|
@@ -49,8 +49,7 @@ export async function handleImages(req, res, match, ctx) {
|
|
|
49
49
|
const bakes = deps.imageBakes;
|
|
50
50
|
const idx = deps.imageIndex;
|
|
51
51
|
const principal = gatedPrincipal(req, deps.config);
|
|
52
|
-
const
|
|
53
|
-
const isExplicitOperator = explicitOperatorOk(principal, operators);
|
|
52
|
+
const isExplicitOperator = explicitOperatorOk(principal, deps.config);
|
|
54
53
|
const operatorLane = facts.operatorLane(deps);
|
|
55
54
|
const cfg = deps.config.imageBakes;
|
|
56
55
|
const isRunner = source !== undefined && source !== null && source === cfg.runnerPrincipal;
|
|
@@ -239,12 +238,12 @@ export async function handleImages(req, res, match, ctx) {
|
|
|
239
238
|
if (line.event === "heartbeat") {
|
|
240
239
|
const fresh = await bakes.getBake(bakeId);
|
|
241
240
|
if (!fresh || fresh.status !== "running") {
|
|
242
|
-
|
|
241
|
+
sendError(res, 409, "conflict.bake_not_running", "bake is not running", { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false });
|
|
243
242
|
return;
|
|
244
243
|
}
|
|
245
244
|
const ok = bake.runnerId ? await bakes.heartbeatLease(bakeId, bake.runnerId, cfg.leaseMs) : false;
|
|
246
245
|
if (!ok) {
|
|
247
|
-
|
|
246
|
+
sendError(res, 409, "conflict.bake_lease_lost", "bake lease lost", { accepted: false, leaseValid: false, cancelRequested: fresh.cancelRequested });
|
|
248
247
|
return;
|
|
249
248
|
}
|
|
250
249
|
sendJson(res, 200, { accepted: true, leaseValid: true, cancelRequested: fresh.cancelRequested });
|
|
@@ -252,7 +251,7 @@ export async function handleImages(req, res, match, ctx) {
|
|
|
252
251
|
}
|
|
253
252
|
const fresh = await bakes.getBake(bakeId);
|
|
254
253
|
if (!fresh || fresh.status !== "running") {
|
|
255
|
-
|
|
254
|
+
sendError(res, 409, "conflict.bake_not_running", "bake is not running", { accepted: false, leaseValid: false, cancelRequested: fresh?.cancelRequested ?? false });
|
|
256
255
|
return;
|
|
257
256
|
}
|
|
258
257
|
if (fresh.runnerId) {
|
|
@@ -291,7 +290,7 @@ export async function handleImages(req, res, match, ctx) {
|
|
|
291
290
|
if (pool.available && isIndexRouteId(match.decl.id)) {
|
|
292
291
|
const idx = pool.imageIndex;
|
|
293
292
|
const principal = gatedPrincipal(req, deps.config);
|
|
294
|
-
const operator = explicitOperatorOk(principal, deps.config
|
|
293
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
295
294
|
const viewer = { operator, tenantId: principal ?? null };
|
|
296
295
|
const q = new URLSearchParams(match.search);
|
|
297
296
|
if (match.decl.id === "images-index") {
|
|
@@ -345,7 +344,7 @@ export async function handleImages(req, res, match, ctx) {
|
|
|
345
344
|
sendOperatorPrincipalsRequired(res);
|
|
346
345
|
return;
|
|
347
346
|
}
|
|
348
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
347
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
349
348
|
sendError(res, 403, "auth.operator_only", "operator only");
|
|
350
349
|
return;
|
|
351
350
|
}
|
|
@@ -30,14 +30,7 @@ export async function handleLeader(req, res, match, ctx) {
|
|
|
30
30
|
if (match.decl.id === "leader-submit") {
|
|
31
31
|
if (rateLimited(req, res) || quotaExceeded(req, res) || (await leaseDenied(req, res)) || (await usageWindowDenied(req, res)))
|
|
32
32
|
return;
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
body = await readJson(req);
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
33
|
+
const body = await readJson(req);
|
|
41
34
|
const laneRefusal = leaderEntryRefusal(leaderRunEntry(deps.config.autonomy));
|
|
42
35
|
if (laneRefusal !== undefined) {
|
|
43
36
|
sendError(res, 422, "request.autonomy_lane_refused", laneRefusal);
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* 404 无 oracle,与 `POST /v1/sessions/:id/notify` 逐字同形)→ `getActiveTaskId` 取本会话的活 run →
|
|
35
35
|
* `steerableRuns` 取本副本活流。非 live 的四臂一码 409 `steering.not_running`,判据取词表属主
|
|
36
36
|
* (`isParkedRunStatus` / `isTerminalRunStatus`)与 `runProvenElsewhere`(手抄已收编成一只谓词,S-430 起同住 `plugins/store-contracts.ts`)。
|
|
37
|
-
* 显式 operator 可重拨任何租户的会话(监督动作,与 notify / steer
|
|
37
|
+
* 显式 operator 可重拨任何租户的会话(监督动作,与 notify / steer 同臂;「谁是 operator」的唯一读法 `explicitOperatorOk`)。
|
|
38
38
|
*
|
|
39
39
|
* ── 应答期限(S-431)────────────────────────────────────────────────────────────────────────────
|
|
40
40
|
* 修前这一口对 `live.reconnectMcpServer(server)` 是裸 `await`:server 侧没有期限,上界只来自 core 自己的启动期钟
|
|
@@ -7,6 +7,7 @@ import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../pri
|
|
|
7
7
|
import {} from "../route-ctx.js";
|
|
8
8
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
9
9
|
import * as facts from "../../capability-facts.js";
|
|
10
|
+
import { sessionOwnerCellOf } from "../../security.js";
|
|
10
11
|
const BodySchema = z.object({ server: z.string().min(1).max(190) }).strict();
|
|
11
12
|
const NEUTRALIZED_TEXT_MAX = 200;
|
|
12
13
|
const humanText = (s) => redactSecrets(s).slice(0, NEUTRALIZED_TEXT_MAX);
|
|
@@ -93,8 +94,8 @@ export async function handleMcpReconnect(req, res, match, ctx) {
|
|
|
93
94
|
sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
96
|
-
const
|
|
97
|
-
if (!
|
|
97
|
+
const operator = explicitOperatorOk(principal, deps.config);
|
|
98
|
+
if (!operator && !ctx.helpers.sessionOwnerOk(req, res, await sessionOwnerCellOf(sessionStorage, sessionId, owner)))
|
|
98
99
|
return;
|
|
99
100
|
const activeTaskId = await runStore.getActiveTaskId(sessionId);
|
|
100
101
|
const live = activeTaskId === undefined ? undefined : ctx.registry.steerableRuns.get(activeTaskId);
|
|
@@ -73,7 +73,7 @@ export async function handleMemoryBundle(req, res, match, ctx) {
|
|
|
73
73
|
sendOperatorPrincipalsRequired(res);
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
76
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
77
77
|
sendError(res, 403, "auth.operator_only", "memory governance bundles are an operator-only deployment action");
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
@@ -29,7 +29,7 @@ export async function handleMemoryCompliance(req, res, match, ctx) {
|
|
|
29
29
|
sendOperatorPrincipalsRequired(res);
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
32
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
33
33
|
sendError(res, 403, "auth.operator_only", "memory provenance and erasure are operator-only deployment actions");
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
@@ -92,7 +92,7 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
const faces = fact.valve;
|
|
95
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
95
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
96
96
|
sendError(res, 403, "auth.operator_only", "memory consolidation is operator-only: the caller principal is not in OPERATOR_PRINCIPALS");
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
@@ -122,7 +122,7 @@ export async function handleMemoryOrigin(req, res, match, ctx) {
|
|
|
122
122
|
sendOperatorPrincipalsRequired(res);
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
125
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
126
126
|
sendError(res, 403, "auth.operator_only", "memory origin marking and clearance are operator-only deployment actions");
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* [ref] A9 域模块 —— memory 导出/同步 + 只读策略面。
|
|
3
3
|
*
|
|
4
4
|
* 路由:`GET /v1/memory/export`、`POST /v1/memory/sync/:scope`、`GET /v1/policy`。
|
|
5
|
-
* owner 门 = 「本人 user scope / 显式 operator / `org:` 键的目录成员」(见 {@link gateMemoryScope}),
|
|
5
|
+
* owner 门 = 「本人 user scope / 本人的项目层 / 显式 operator / `org:` 键的目录成员」(见 {@link gateMemoryScope}),
|
|
6
6
|
* 越界一律 404(零存在性 oracle)。本域零可变状态。
|
|
7
7
|
*/
|
|
8
8
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
@@ -2,6 +2,7 @@ import { formatUserScope } from "@sema-agent/core";
|
|
|
2
2
|
import { parseMemorySyncRequest } from "../../memory-sync.js";
|
|
3
3
|
import { sendJson, sendError } from "../send.js";
|
|
4
4
|
import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js";
|
|
5
|
+
import { parseProjectLayerKey } from "../../project-layer-key.js";
|
|
5
6
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
|
|
6
7
|
import { assertNever } from "../route-ctx.js";
|
|
7
8
|
const ORG_PREFIX = "org:";
|
|
@@ -33,9 +34,9 @@ function directoryDecidesThisFace(mode) {
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
async function gateMemoryScope(deps, principal, scope, need) {
|
|
36
|
-
if (scope === formatUserScope(principal))
|
|
37
|
+
if (scope === formatUserScope(principal) || parseProjectLayerKey(scope)?.owner === principal)
|
|
37
38
|
return { kind: "allow" };
|
|
38
|
-
if (explicitOperatorOk(principal, deps.config
|
|
39
|
+
if (explicitOperatorOk(principal, deps.config))
|
|
39
40
|
return { kind: "allow" };
|
|
40
41
|
const directory = deps.orgMemoryDirectory;
|
|
41
42
|
if (!scope.startsWith(ORG_PREFIX) || directory === undefined || !directoryDecidesThisFace(deps.config.memoryOrgAdmissionMode)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { externalNotificationInboxEntry } from "../../orchestration/workflow-completion-inbox.js";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
|
-
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal } from "../principal-gate.js";
|
|
3
|
+
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sessionCallerOf } from "../principal-gate.js";
|
|
4
|
+
import { ownerlessRowOpen, sessionOwnerCellOf } from "../../security.js";
|
|
4
5
|
import { sendResumeOutcome } from "../route-ctx.js";
|
|
5
6
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
6
7
|
import * as facts from "../../capability-facts.js";
|
|
@@ -23,14 +24,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
|
|
|
23
24
|
sendError(res, 400, "request.path_malformed", "session id segment is not valid percent-encoding");
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
nb = (await readJson(req));
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
sendError(res, 400, "request.body_shape", "body must be JSON: { task_id, status, summary, result?, seq?, source? }");
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
27
|
+
const nb = (await readJson(req));
|
|
34
28
|
if (typeof nb.task_id !== "string" || nb.task_id.trim().length === 0 || nb.task_id.length > 190) {
|
|
35
29
|
sendError(res, 400, "request.field_invalid", "task_id must be a non-empty string of at most 190 characters");
|
|
36
30
|
return;
|
|
@@ -68,8 +62,8 @@ export async function handleNotifyWake(req, res, match, ctx) {
|
|
|
68
62
|
sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
69
63
|
return;
|
|
70
64
|
}
|
|
71
|
-
const notifyOperator = explicitOperatorOk(principal, deps.config
|
|
72
|
-
if (!notifyOperator && notifyOwner !==
|
|
65
|
+
const notifyOperator = explicitOperatorOk(principal, deps.config);
|
|
66
|
+
if (!notifyOperator && notifyOwner !== principal && !ownerlessRowOpen(await sessionOwnerCellOf(owned.sessionStorage, notifySession, notifyOwner), sessionCallerOf(req, deps))) {
|
|
73
67
|
sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
74
68
|
return;
|
|
75
69
|
}
|
|
@@ -101,7 +95,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
|
|
|
101
95
|
sendError(res, 501, "capability.workflow_store_required", "external notify requires the workflow completion inbox (WORKFLOW_RUN_STORE)");
|
|
102
96
|
return;
|
|
103
97
|
}
|
|
104
|
-
await deps.workflowCompletionInbox.enqueue(
|
|
98
|
+
await deps.workflowCompletionInbox.enqueue(externalNotificationInboxEntry(notifySession, notifyOwner ?? principal ?? null, { task_type: "external", ...payload }, Date.now()));
|
|
105
99
|
sendJson(res, 202, { sessionId: notifySession, delivery: "parked", note: "no live stream — parked in the session inbox; drained as a task_notification on the next stream open" });
|
|
106
100
|
return;
|
|
107
101
|
}
|
|
@@ -122,14 +116,7 @@ export async function handleNotifyWake(req, res, match, ctx) {
|
|
|
122
116
|
sendError(res, 400, "request.path_malformed", "session id segment is not valid percent-encoding");
|
|
123
117
|
return;
|
|
124
118
|
}
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
wakeBody = (await readJson(req));
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
sendError(res, 400, "request.body_shape", "body must be JSON: { message?: string }");
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
119
|
+
const wakeBody = (await readJson(req));
|
|
133
120
|
if (wakeBody.message !== undefined && (typeof wakeBody.message !== "string" || wakeBody.message.length === 0)) {
|
|
134
121
|
sendError(res, 400, "request.field_invalid", "message must be a non-empty string when present");
|
|
135
122
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sendJson, sendError } from "../send.js";
|
|
2
|
-
import { gatedPrincipal,
|
|
2
|
+
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
3
3
|
import { assertNever } from "../route-ctx.js";
|
|
4
4
|
import * as facts from "../../capability-facts.js";
|
|
5
5
|
import { quotaWindowResetsAt } from "../../observability/cost-quota.js";
|
|
@@ -14,7 +14,7 @@ export async function handleObservability(req, res, match, ctx) {
|
|
|
14
14
|
}
|
|
15
15
|
if (deps.config.requirePrincipal) {
|
|
16
16
|
const principal = gatedPrincipal(req, deps.config);
|
|
17
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
17
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
18
18
|
sendError(res, 403, "auth.operator_only", "outcomes view is operator-only on a multi-tenant worker");
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 跨主体投递门的**受理口**:`POST /v1/principal-inbox/messages`。
|
|
3
|
+
*
|
|
4
|
+
* 本口只做三件事,其余全归门(`src/org-delivery-gate.ts`,规则全文在它的头注):
|
|
5
|
+
* ① 取发件人 —— **只**取自验过的身份面(`gatedPrincipal`),交给门的 `authedFrom` 就是 `{ scope: <那位主体> }`;
|
|
6
|
+
* 体里没有发件人这个键(写了 = 词表外键,400)。没有验过的身份 ⇒ 401(身份面那一句),不论部署是否要求 principal ——
|
|
7
|
+
* 门要一个发件人 scope,匿名者没有。无凭证部署上 principal 头只是调用方自报 ⇒ 本口在分派器的无凭证写门内
|
|
8
|
+
* (声明行 `credentialGated`,503 `auth.service_token_required`;本地开发显式 `ALLOW_UNAUTHED_WRITES=true` 才放行);
|
|
9
|
+
* ② 判体形 —— `{ to: 非空串, content: 非空串(≤ {@link PRINCIPAL_INBOX_CONTENT_MAX_CHARS} 字), urgent?: 布尔 }`,
|
|
10
|
+
* 键闭集与提交口同一只组句器(`principalInboxBodyKeyIssue`);
|
|
11
|
+
* ③ 调门、投影门的答案 —— 回执 ⇒ 200 `{ receiptId }`;拒绝 ⇒ core 的词原样做 `errorCode`、门的那一句原样做 `error`。
|
|
12
|
+
* 本口**不碰**任何店:一个店名、一个 `.append` 都没有(`test/org-delivery-gate-single-path.test.ts` 按源码钉)。
|
|
13
|
+
*
|
|
14
|
+
* 回执**不**带门回执里的 `seq`:那是收件人箱的序号,原样交给发件人就是把「收件人这只箱收过多少封」泄给 org 里的任何人。
|
|
15
|
+
*
|
|
16
|
+
* 拒绝词 → HTTP 状态(穷举 `switch`,core 加词 ⇒ 编译红):
|
|
17
|
+
* · `not_member` → 404:「不同 org」「查无此人」「目录答不上来」同一份字节(门保证),404 与本仓反枚举的既有形一致;
|
|
18
|
+
* · `rate_limited` → 429;
|
|
19
|
+
* · `inbox_full` → 409(收件人那一侧的状态,不是发件人的速率;与 `steering.queue_full` 同档);
|
|
20
|
+
* · `recipient_tombstoned` → 410(收件人正在被删除,这条路关了)。
|
|
21
|
+
* 门缺席(本部署没声明收件箱消费方)⇒ 501 `capability.unavailable`,能力位 `principalInboxDelivery` 读同一只事实。
|
|
22
|
+
*/
|
|
23
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
24
|
+
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
25
|
+
/**
|
|
26
|
+
* 一封信正文的字符上界。全局请求体上界(8 MiB)对一只收件箱太宽:箱里最多 50 封,而读它的是收件人的助理 ——
|
|
27
|
+
* 一封信是一段话,不是一份附件(要转一份长文,发它的出处)。
|
|
28
|
+
*/
|
|
29
|
+
export declare const PRINCIPAL_INBOX_CONTENT_MAX_CHARS = 32000;
|
|
30
|
+
export declare function handlePrincipalInbox(req: IncomingMessage, res: ServerResponse, match: RouteMatch<PrincipalInboxRouteId>, ctx: RouteCtx): Promise<void>;
|
|
31
|
+
export declare const PRINCIPAL_INBOX_ROUTES: readonly [{
|
|
32
|
+
readonly id: "principal-inbox-messages";
|
|
33
|
+
readonly path: "/v1/principal-inbox/messages";
|
|
34
|
+
readonly credentialGated: readonly ["POST"];
|
|
35
|
+
readonly methods: readonly ["POST"];
|
|
36
|
+
}];
|
|
37
|
+
/** 本域可分派行的 `id` 闭集 —— handler 的 `switch` 按它判穷尽。 */
|
|
38
|
+
export type PrincipalInboxRouteId = RouteIdsOf<typeof PRINCIPAL_INBOX_ROUTES>;
|
|
39
|
+
//# sourceMappingURL=principal-inbox.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { sendJson, sendError } from "../send.js";
|
|
2
|
+
import { gatedPrincipal, sendUnauthorized } from "../principal-gate.js";
|
|
3
|
+
import { assertNever } from "../route-ctx.js";
|
|
4
|
+
import * as facts from "../../capability-facts.js";
|
|
5
|
+
import { principalInboxBodyKeyIssue } from "../../request-key-closure.js";
|
|
6
|
+
export const PRINCIPAL_INBOX_CONTENT_MAX_CHARS = 32_000;
|
|
7
|
+
function sendRefusal(res, outcome) {
|
|
8
|
+
switch (outcome.code) {
|
|
9
|
+
case "org_delivery.not_member":
|
|
10
|
+
sendError(res, 404, "org_delivery.not_member", outcome.message);
|
|
11
|
+
return;
|
|
12
|
+
case "org_delivery.rate_limited":
|
|
13
|
+
sendError(res, 429, "org_delivery.rate_limited", outcome.message);
|
|
14
|
+
return;
|
|
15
|
+
case "org_delivery.inbox_full":
|
|
16
|
+
sendError(res, 409, "org_delivery.inbox_full", outcome.message);
|
|
17
|
+
return;
|
|
18
|
+
case "org_delivery.recipient_tombstoned":
|
|
19
|
+
sendError(res, 410, "org_delivery.recipient_tombstoned", outcome.message);
|
|
20
|
+
return;
|
|
21
|
+
default:
|
|
22
|
+
return assertNever(outcome.code);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export async function handlePrincipalInbox(req, res, match, ctx) {
|
|
26
|
+
const { deps } = ctx;
|
|
27
|
+
const { readJson } = ctx.helpers;
|
|
28
|
+
switch (match.decl.id) {
|
|
29
|
+
case "principal-inbox-messages": {
|
|
30
|
+
const principal = gatedPrincipal(req, deps.config);
|
|
31
|
+
if (principal === undefined) {
|
|
32
|
+
sendUnauthorized(res, "identity");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const fact = facts.principalInboxDelivery(deps);
|
|
36
|
+
if (!fact.available) {
|
|
37
|
+
sendError(res, 501, "capability.unavailable", "cross-principal delivery is not available on this deployment (it declares no principal-inbox consumer, so no organization delivery gate is mounted)");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const raw = await readJson(req);
|
|
41
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
42
|
+
sendError(res, 400, "request.field_invalid", "body must be a JSON object { to: string, content: string, urgent?: boolean }");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const keyIssue = principalInboxBodyKeyIssue(raw);
|
|
46
|
+
if (keyIssue) {
|
|
47
|
+
sendError(res, 400, "request.body_shape", keyIssue.message, { unknownKeys: keyIssue.unknownKeys, unsupportedKeys: keyIssue.unsupportedKeys });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const body = raw;
|
|
51
|
+
if (typeof body.to !== "string" || body.to === "") {
|
|
52
|
+
sendError(res, 400, "request.field_invalid", "to must be a non-empty string naming the recipient principal");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (typeof body.content !== "string" || body.content === "" || body.content.length > PRINCIPAL_INBOX_CONTENT_MAX_CHARS) {
|
|
56
|
+
sendError(res, 400, "request.field_invalid", `content must be a non-empty string of at most ${PRINCIPAL_INBOX_CONTENT_MAX_CHARS} characters`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (body.urgent !== undefined && typeof body.urgent !== "boolean") {
|
|
60
|
+
sendError(res, 400, "request.field_invalid", "urgent must be a boolean when present");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const outcome = await fact.gate.deliverCrossPrincipal({ scope: principal }, body.to, { content: body.content, ...(body.urgent !== undefined ? { urgent: body.urgent } : {}) });
|
|
64
|
+
if (!outcome.ok) {
|
|
65
|
+
sendRefusal(res, outcome);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
sendJson(res, 200, { receiptId: outcome.receipt.receiptId });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
default:
|
|
72
|
+
return assertNever(match.decl.id);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export const PRINCIPAL_INBOX_ROUTES = [{ id: "principal-inbox-messages", path: "/v1/principal-inbox/messages", credentialGated: ["POST"], methods: ["POST"] }];
|
|
76
|
+
//# sourceMappingURL=principal-inbox.js.map
|
|
@@ -36,7 +36,7 @@ export async function handleRetention(req, res, match, ctx) {
|
|
|
36
36
|
sendOperatorPrincipalsRequired(res);
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
if (!explicitOperatorOk(principal, deps.config
|
|
39
|
+
if (!explicitOperatorOk(principal, deps.config)) {
|
|
40
40
|
sendError(res, 403, "auth.operator_only", OPERATOR_ONLY_MESSAGE);
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
@@ -71,14 +71,7 @@ async function handleHold(req, res, ctx, store, rawDomain, principal, held) {
|
|
|
71
71
|
}
|
|
72
72
|
let note;
|
|
73
73
|
if (held) {
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
raw = await ctx.helpers.readJson(req);
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
74
|
+
const raw = await ctx.helpers.readJson(req);
|
|
82
75
|
if (raw !== undefined && raw !== null && raw !== "") {
|
|
83
76
|
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
84
77
|
sendError(res, 400, "request.body_shape", "invalid retention hold body — expected an object with an optional `note` string");
|