@sema-agent/server 7.133.0 → 7.135.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 +221 -0
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/USAGE.md +222 -36
- package/deploy/sema-up/README.md +16 -0
- 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 +14 -0
- package/deploy/sema-up/chart/templates/server.yaml +14 -0
- package/deploy/sema-up/chart/values-full-single.yaml +5 -1
- package/deploy/sema-up/chart/values.yaml +34 -0
- package/dist/adoption/plan.d.ts +1 -1
- package/dist/approval-ask-audit-store.d.ts +25 -25
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +66 -154
- package/dist/approval-card.js +33 -52
- package/dist/approval-content-kind.d.ts +26 -6
- package/dist/approval-content-kind.js +23 -3
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +91 -0
- package/dist/approval-gate-currency.js +120 -0
- package/dist/approval-hmac.d.ts +7 -7
- package/dist/approval-policy-settlement.d.ts +2 -2
- package/dist/approval-reconciler.d.ts +3 -3
- package/dist/approval.d.ts +14 -8
- package/dist/approval.js +35 -16
- package/dist/auth-bridge.d.ts +1 -1
- package/dist/auto-mode-face.d.ts +4 -4
- package/dist/background-session-reap.d.ts +2 -2
- package/dist/bake-runner/main.d.ts +2 -2
- package/dist/bake-runner/runner.d.ts +4 -4
- package/dist/bench/s1/live-deps.d.ts +1 -1
- package/dist/bench/s1/run-firm.d.ts +1 -1
- package/dist/boot/coordinators.d.ts +7 -2
- package/dist/boot/coordinators.js +8 -5
- package/dist/boot/deferred-sandbox-path-env.d.ts +0 -6
- package/dist/boot/deferred-sandbox-path-env.js +0 -5
- package/dist/boot/engine-lease.d.ts +5 -5
- package/dist/boot/execution-env.d.ts +16 -15
- package/dist/boot/execution-env.js +19 -21
- package/dist/boot/fatal-exit.d.ts +2 -2
- package/dist/boot/late-binds.d.ts +1 -1
- package/dist/boot/leader.d.ts +2 -0
- package/dist/boot/leader.js +2 -1
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/memory-consolidation.d.ts +15 -15
- package/dist/boot/parked-revive-gate.d.ts +3 -3
- package/dist/boot/parked-revive-gate.js +3 -2
- package/dist/boot/read-deny-anchor-audit.js +2 -2
- package/dist/boot/reapers.d.ts +4 -4
- package/dist/boot/resolve-spec.d.ts +1 -1
- package/dist/boot/resolve-spec.js +28 -24
- package/dist/boot/runner-deps.d.ts +29 -16
- package/dist/boot/runner-deps.js +12 -2
- package/dist/boot/session-faces.d.ts +3 -3
- package/dist/boot/session-faces.js +11 -30
- package/dist/boot/shutdown.d.ts +5 -5
- package/dist/boot/side-query-lane.d.ts +2 -2
- package/dist/boot/stage-05-execution-env.js +4 -4
- package/dist/boot/stage-06-runners.d.ts +4 -3
- package/dist/boot/stage-06-runners.js +15 -4
- package/dist/boot/stage-07-capability-layer.d.ts +2 -1
- package/dist/boot/stage-08-reapers.d.ts +2 -1
- package/dist/boot/stage-09-leader.d.ts +2 -1
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +2 -1
- package/dist/boot/stage-10-http-server.js +2 -1
- package/dist/boot/stores.d.ts +8 -0
- package/dist/boot/stores.js +10 -13
- package/dist/boot/web-admin.d.ts +21 -15
- package/dist/boot/web-admin.js +16 -12
- package/dist/boot/workflow-orchestration.js +2 -9
- package/dist/brain.d.ts +11 -11
- package/dist/budget.d.ts +4 -4
- package/dist/budget.js +5 -1
- package/dist/caller-text-echo.d.ts +2 -0
- package/dist/caller-text-echo.js +2 -1
- package/dist/canonical-json.d.ts +2 -41
- package/dist/canonical-json.js +2 -13
- package/dist/capabilities/approvals-push.d.ts +4 -4
- package/dist/capabilities/builtin-tools.d.ts +5 -5
- package/dist/capabilities/center-plugins.d.ts +5 -5
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +1 -1
- package/dist/capabilities/center-wiring.d.ts +1 -1
- package/dist/capabilities/composite-members.d.ts +2 -2
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/execution-lane.d.ts +5 -5
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +5 -5
- package/dist/capabilities/mcp-probe.d.ts +10 -7
- package/dist/capabilities/mcp-probe.js +2 -2
- package/dist/capabilities/sandbox-file-send.d.ts +1 -18
- package/dist/capabilities/sandbox-file-send.js +0 -7
- package/dist/capabilities/scenarios.d.ts +28 -10
- package/dist/capabilities/scenarios.js +15 -5
- package/dist/capabilities/send-user-file-tool.d.ts +1 -1
- package/dist/capabilities/skills.d.ts +31 -12
- package/dist/capabilities/skills.js +23 -17
- package/dist/capabilities/tool-defer.d.ts +1 -1
- package/dist/capability-facts.d.ts +27 -24
- package/dist/capability-facts.js +18 -20
- package/dist/center-config-tier.d.ts +1 -1
- package/dist/center-credential.d.ts +4 -4
- 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 +5 -0
- package/dist/checkpoint-identity.js +14 -0
- package/dist/config-catalog.d.ts +12 -12
- package/dist/config-invariants.d.ts +4 -4
- package/dist/config-invariants.js +3 -2
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-provider.d.ts +13 -13
- package/dist/config-provider.js +2 -1
- package/dist/config-types.d.ts +83 -83
- package/dist/config.d.ts +26 -24
- package/dist/config.js +12 -10
- package/dist/cross-session-settings.d.ts +1 -1
- package/dist/delegated-session-owner.d.ts +16 -13
- package/dist/delegated-session-owner.js +9 -10
- package/dist/deployment-governance.d.ts +16 -16
- package/dist/deployment-shape.d.ts +127 -0
- package/dist/deployment-shape.js +72 -0
- package/dist/device-store.d.ts +1 -1
- package/dist/device-ws-hub.d.ts +1 -1
- package/dist/egress-redirect.d.ts +1 -1
- package/dist/entry-mode-clamp-notice.d.ts +2 -2
- package/dist/env-facts.d.ts +10 -9
- package/dist/env-facts.js +1 -1
- package/dist/env-name-allowlist-knobs.d.ts +5 -5
- package/dist/exec-bounds.d.ts +2 -2
- package/dist/execution-lane-caps.d.ts +31 -43
- package/dist/execution-lane-caps.js +0 -13
- package/dist/field-conflict.d.ts +2 -1
- package/dist/field-conflict.js +1 -0
- package/dist/file-history-capture.d.ts +9 -9
- package/dist/file-history-disclosure.d.ts +50 -9
- package/dist/file-history-disclosure.js +8 -13
- package/dist/fleet/drain-entry.d.ts +2 -2
- package/dist/fleet/fleet-bus.d.ts +26 -14
- package/dist/fleet/fleet-bus.js +6 -5
- package/dist/fleet/fleet-reconciler.d.ts +9 -9
- package/dist/fleet/subagent-tail-bus.d.ts +4 -4
- package/dist/fleet-client.d.ts +13 -13
- package/dist/fleet-lease.d.ts +16 -16
- package/dist/governance-http-status.d.ts +2 -2
- package/dist/hooks/hook-llm.d.ts +7 -7
- package/dist/hooks/hook-runner.d.ts +57 -30
- package/dist/hooks/hook-runner.js +38 -20
- package/dist/host-decision.d.ts +5 -5
- package/dist/host-lsp-manager.d.ts +5 -5
- package/dist/hosted-posture.d.ts +23 -13
- package/dist/hosted-posture.js +4 -9
- package/dist/http/admission.d.ts +2 -2
- package/dist/http/admission.js +28 -5
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +5 -2
- package/dist/http/checkpoint-ctx.d.ts +183 -2
- package/dist/http/checkpoint-ctx.js +197 -2
- package/dist/http/dispatch.d.ts +3 -3
- package/dist/http/dispatch.js +3 -3
- package/dist/http/durable-run-leg.js +7 -5
- package/dist/http/idempotency.d.ts +4 -4
- package/dist/http/idempotency.js +2 -2
- package/dist/http/mcp-dial-deadline.d.ts +7 -5
- package/dist/http/memory-compliance-failure-reply.d.ts +4 -4
- package/dist/http/owner-access.d.ts +4 -6
- package/dist/http/owner-access.js +1 -1
- package/dist/http/principal-gate.d.ts +39 -13
- package/dist/http/principal-gate.js +30 -6
- package/dist/http/readiness.d.ts +1 -1
- package/dist/http/refusal-body.d.ts +12 -0
- package/dist/http/refusal-body.js +11 -0
- package/dist/http/request-guards.d.ts +4 -13
- package/dist/http/request-guards.js +4 -17
- package/dist/http/resume-ctx-read.d.ts +53 -6
- package/dist/http/resume-ctx-read.js +26 -3
- package/dist/http/resume-legs.d.ts +5 -4
- package/dist/http/resume-legs.js +47 -29
- package/dist/http/route-ctx.d.ts +29 -38
- package/dist/http/route-table.d.ts +9 -9
- package/dist/http/routes/agents-roster.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +5 -5
- package/dist/http/routes/approvals-assistant.js +91 -17
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/background.js +2 -2
- package/dist/http/routes/capabilities.d.ts +1 -1
- package/dist/http/routes/capabilities.js +16 -8
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/devices.d.ts +1 -1
- package/dist/http/routes/diagnostics.d.ts +6 -6
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/fleet.d.ts +1 -1
- package/dist/http/routes/fleet.js +5 -4
- package/dist/http/routes/mcp-reconnect.d.ts +4 -4
- package/dist/http/routes/mcp-reconnect.js +3 -3
- package/dist/http/routes/memory-consolidation.d.ts +1 -1
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -2
- package/dist/http/routes/rules.d.ts +1 -1
- package/dist/http/routes/rules.js +4 -4
- package/dist/http/routes/runs.js +44 -11
- package/dist/http/routes/session-sync.d.ts +3 -2
- package/dist/http/routes/session-sync.js +109 -62
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions-list.js +4 -5
- package/dist/http/routes/sessions.js +34 -48
- package/dist/http/routes/tasks.d.ts +1 -1
- package/dist/http/routes/tasks.js +21 -16
- package/dist/http/routes/trace-usage.d.ts +1 -1
- package/dist/http/routes/trace-usage.js +7 -9
- package/dist/http/routes/workflows.d.ts +3 -0
- package/dist/http/routes/workflows.js +31 -28
- package/dist/http/send.d.ts +5 -5
- package/dist/http/server.d.ts +39 -33
- package/dist/http/server.js +5 -2
- package/dist/http/session-inherit-env.d.ts +3 -3
- package/dist/http/sse-lifecycle.d.ts +1 -1
- package/dist/http/sse-log.d.ts +2 -2
- package/dist/http/submit-ctx.d.ts +4 -3
- package/dist/http/submit-ctx.js +19 -3
- package/dist/http/sync-submit-body.d.ts +1 -1
- package/dist/http/verify-rounds.d.ts +1 -1
- package/dist/http/wire-types.d.ts +35 -24
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/instruction-source-notice.d.ts +2 -2
- package/dist/key-resolver.d.ts +3 -3
- package/dist/lane-home-probe.d.ts +1 -1
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/leader/diffup.d.ts +2 -2
- package/dist/leader/endpoint.d.ts +1 -1
- package/dist/leader/fanout.d.ts +1 -1
- package/dist/leader/leader.d.ts +4 -4
- package/dist/leader/merge.d.ts +3 -3
- package/dist/leader/repair-wire.d.ts +1 -1
- package/dist/leader/wire.d.ts +9 -5
- package/dist/leader/wire.js +8 -7
- package/dist/list-entry-display.d.ts +1 -1
- package/dist/lsp-evict.d.ts +1 -1
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +1 -1
- package/dist/memory-layer-legacy-lock.d.ts +1 -1
- package/dist/memory-operator-faces.d.ts +1 -1
- package/dist/memory-origin-fence.js +2 -2
- package/dist/memory-posture.js +4 -2
- package/dist/memory-project-layer.d.ts +1 -1
- package/dist/memory-scope.d.ts +19 -19
- package/dist/memory-store-refusal.d.ts +4 -4
- package/dist/model-compat.d.ts +1 -1
- package/dist/model-entry-headers.d.ts +2 -2
- package/dist/model-entry-refusal.d.ts +17 -17
- package/dist/model-provider.d.ts +10 -10
- package/dist/model-reach-scope.d.ts +1 -1
- package/dist/model-route-endpoint.d.ts +6 -6
- package/dist/model-route-url.d.ts +5 -5
- package/dist/model-select.d.ts +15 -6
- package/dist/model-select.js +5 -0
- package/dist/model-unreachable-notice.d.ts +3 -3
- package/dist/namespaced-rule-name.d.ts +15 -5
- package/dist/namespaced-rule-name.js +3 -2
- package/dist/observability/corrupt-read-seat.d.ts +9 -9
- package/dist/observability/cost-taxonomy.d.ts +1 -1
- package/dist/observability/err-text.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +12 -8
- package/dist/observability/fail-open.js +12 -8
- package/dist/observability/metrics.d.ts +3 -3
- package/dist/observability/prompt-manifest.d.ts +19 -8
- package/dist/observability/prompt-manifest.js +9 -8
- package/dist/observability/run-terminal.d.ts +36 -36
- package/dist/observability/secret-env-scrub.d.ts +3 -3
- package/dist/observability/tool-trace.d.ts +1 -1
- package/dist/observability/tool-trace.js +8 -9
- package/dist/operator-ask.d.ts +4 -4
- package/dist/orchestration/workflow-agent-session-index.d.ts +3 -3
- package/dist/orchestration/workflow-completion-inbox.d.ts +20 -5
- package/dist/orchestration/workflow-completion-inbox.js +29 -7
- package/dist/orchestration/workflow-notify-journal.d.ts +43 -19
- package/dist/orchestration/workflow-notify-journal.js +17 -0
- package/dist/orchestration/workflow-park-decision.d.ts +1 -1
- package/dist/orchestration/workflow-park-decision.js +1 -0
- package/dist/outbound-dispatcher.d.ts +4 -4
- package/dist/parent-watch.d.ts +4 -4
- package/dist/parked-decide.d.ts +20 -20
- package/dist/parked-decide.js +8 -5
- package/dist/parked-revive-surface.d.ts +7 -7
- package/dist/parked-revive-surface.js +2 -3
- package/dist/peer-directory.d.ts +3 -3
- package/dist/peer-directory.js +1 -1
- package/dist/permission-rule-list.d.ts +10 -1
- package/dist/permission-rule-list.js +7 -5
- package/dist/permission-rule-vocab.d.ts +3 -25
- package/dist/permission-rule-vocab.js +0 -13
- package/dist/plugins/adoption-log-sql.d.ts +1 -1
- package/dist/plugins/approval-ask-store-file.d.ts +8 -1
- package/dist/plugins/approval-ask-store-file.js +6 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +11 -7
- package/dist/plugins/approval-ask-store-memory.js +11 -7
- package/dist/plugins/approval-ask-store-sql.d.ts +34 -15
- package/dist/plugins/approval-ask-store-sql.js +18 -5
- package/dist/plugins/approval-exemption-store.d.ts +3 -3
- package/dist/plugins/approval-nonce-store.d.ts +3 -3
- package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
- package/dist/plugins/approval-payload-fingerprint.js +1 -1
- package/dist/plugins/background-agent-store-sql.d.ts +1 -1
- package/dist/plugins/background-shell-support.d.ts +2 -2
- package/dist/plugins/blob-backend.d.ts +1 -1
- package/dist/plugins/caching-session-store.d.ts +24 -33
- package/dist/plugins/caching-session-store.js +8 -19
- package/dist/plugins/checkpoint-index-columns.d.ts +81 -0
- package/dist/plugins/checkpoint-index-columns.js +62 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +66 -67
- package/dist/plugins/checkpoint-store-sql.js +100 -103
- package/dist/plugins/device-store-sql.d.ts +7 -6
- package/dist/plugins/e2b-orphan-reclaim.d.ts +1 -1
- package/dist/plugins/ensure-schema-lock-policy.d.ts +1 -1
- package/dist/plugins/file-history-store-sql.d.ts +9 -7
- package/dist/plugins/file-history-store-sql.js +27 -15
- package/dist/plugins/file-run-store.d.ts +8 -8
- package/dist/plugins/fork-routing-session-store.d.ts +2 -2
- package/dist/plugins/fork-routing-session-store.js +1 -1
- package/dist/plugins/host-platform.d.ts +10 -10
- package/dist/plugins/image-bake-store-sql.d.ts +1 -1
- package/dist/plugins/image-index-sql.d.ts +1 -1
- package/dist/plugins/leader-run-store-sql.d.ts +1 -1
- package/dist/plugins/local-checkpoint-store.d.ts +23 -12
- package/dist/plugins/local-checkpoint-store.js +29 -4
- package/dist/plugins/local-session-store.d.ts +44 -45
- package/dist/plugins/local-session-store.js +42 -52
- package/dist/plugins/local-session-window.d.ts +12 -6
- package/dist/plugins/local-session-window.js +1 -17
- package/dist/plugins/mailbox-store-sql.d.ts +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +1 -1
- package/dist/plugins/memory-run-store.d.ts +4 -4
- package/dist/plugins/memory-sync-store-pg.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +76 -39
- package/dist/plugins/one-time-migrations.js +127 -34
- package/dist/plugins/outcome-ledger-sql.d.ts +1 -1
- package/dist/plugins/park-commit-watch.d.ts +3 -3
- package/dist/plugins/permission-rule-store-file.d.ts +5 -5
- package/dist/plugins/permission-rule-store-file.js +16 -19
- package/dist/plugins/permission-rule-store-sql.d.ts +38 -4
- package/dist/plugins/permission-rule-store-sql.js +74 -31
- package/dist/plugins/pg-cost-quota.d.ts +1 -1
- package/dist/plugins/pg-pool.d.ts +2 -2
- package/dist/plugins/pg-pool.js +5 -2
- package/dist/plugins/pg-rate-limiter.d.ts +1 -1
- package/dist/plugins/pg-session-storage.d.ts +9 -21
- package/dist/plugins/pg-session-storage.js +51 -42
- package/dist/plugins/remote-env-adb.d.ts +10 -10
- package/dist/plugins/remote-env-device.d.ts +22 -14
- package/dist/plugins/remote-env-device.js +28 -16
- package/dist/plugins/remote-env-e2b.d.ts +3 -3
- package/dist/plugins/remote-env-host.d.ts +16 -16
- package/dist/plugins/remote-env-k8s.d.ts +8 -8
- package/dist/plugins/remote-env-local-docker.d.ts +2 -2
- package/dist/plugins/remote-env-ssh.d.ts +4 -4
- package/dist/plugins/remote-scratchpad.d.ts +2 -3
- package/dist/plugins/remote-scratchpad.js +0 -4
- package/dist/plugins/remote-shell.d.ts +6 -6
- package/dist/plugins/retention-lane-store-sql.d.ts +4 -4
- package/dist/plugins/retention-store-sql.d.ts +4 -4
- package/dist/plugins/roster-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +8 -8
- package/dist/plugins/schema-consistency.d.ts +2 -2
- package/dist/plugins/schema-ensure-legs.d.ts +3 -3
- package/dist/plugins/schema-indexes.d.ts +1 -1
- package/dist/plugins/schema-live-columns.d.ts +1 -1
- package/dist/plugins/session-event-payload.d.ts +4 -4
- package/dist/plugins/session-fork.d.ts +34 -0
- package/dist/plugins/session-fork.js +29 -0
- 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-policy-store-sql.d.ts +12 -12
- package/dist/plugins/session-store.d.ts +2 -2
- package/dist/plugins/session-store.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +2 -2
- package/dist/plugins/sql-driver.d.ts +8 -8
- package/dist/plugins/sql-errors.d.ts +1 -1
- package/dist/plugins/sql-json-column.d.ts +21 -21
- package/dist/plugins/sql-row-helpers.d.ts +2 -2
- package/dist/plugins/store-backend.d.ts +17 -16
- package/dist/plugins/store-backend.js +3 -3
- package/dist/plugins/store-contracts.d.ts +21 -21
- package/dist/plugins/task-attachment-store.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/tidb-pool.d.ts +2 -2
- package/dist/plugins/tidb-pool.js +9 -2
- package/dist/plugins/tidb-session-store.d.ts +17 -27
- package/dist/plugins/tidb-session-store.js +52 -42
- package/dist/plugins/tool-result-store-sql.d.ts +1 -1
- package/dist/plugins/usage-window-store-sql.d.ts +3 -3
- package/dist/plugins/user-input-ledger-file.d.ts +1 -1
- package/dist/plugins/user-input-ledger-sql.d.ts +3 -3
- package/dist/plugins/web-search.d.ts +19 -5
- package/dist/plugins/web-search.js +19 -4
- package/dist/{orchestration/workflow-journal-entry.d.ts → plugins/workflow-journal-payload.d.ts} +23 -32
- package/dist/plugins/workflow-journal-payload.js +32 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +28 -14
- package/dist/plugins/workflow-journal-store-sql.js +34 -15
- package/dist/plugins/workflow-run-store-sql.d.ts +4 -4
- package/dist/posture-source.d.ts +11 -11
- package/dist/principal-jwt.d.ts +6 -6
- package/dist/project-identity.d.ts +3 -3
- package/dist/project-memory.d.ts +4 -4
- package/dist/read-face-posture.d.ts +7 -7
- package/dist/request-key-closure.d.ts +1 -1
- package/dist/request-key-closure.js +1 -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 +15 -8
- package/dist/request-value-closure.js +2 -0
- package/dist/router/route-orchestration.d.ts +11 -16
- package/dist/router/route-orchestration.js +2 -12
- package/dist/rule-entry-list.d.ts +8 -7
- package/dist/rule-entry-list.js +2 -9
- package/dist/rules-consent.d.ts +6 -6
- package/dist/rules-consent.js +2 -0
- package/dist/run-cancel-context.d.ts +5 -5
- package/dist/run-local.d.ts +10 -10
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +15 -12
- package/dist/runs.js +19 -4
- package/dist/runtime-caps-resolver.d.ts +6 -6
- package/dist/runtime-governance.d.ts +9 -9
- package/dist/sandbox-pkg-source.d.ts +9 -31
- package/dist/sandbox-pkg-source.js +14 -8
- package/dist/sealed-key.d.ts +34 -2
- package/dist/sealed-key.js +55 -1
- package/dist/security.d.ts +31 -32
- package/dist/security.js +12 -9
- package/dist/server-secret-env.d.ts +10 -10
- package/dist/session-children-retire.d.ts +1 -1
- package/dist/session-error-wire.d.ts +19 -12
- package/dist/session-error-wire.js +4 -1
- package/dist/session-incarnation.d.ts +52 -35
- package/dist/session-incarnation.js +23 -8
- package/dist/session-policy-wire.d.ts +27 -5
- package/dist/session-policy-wire.js +15 -1
- package/dist/session-records-skipped-notice.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +38 -11
- package/dist/session-sync-kernel.js +10 -0
- package/dist/session-sync.d.ts +49 -6
- package/dist/session-sync.js +52 -10
- package/dist/session-titler.d.ts +7 -6
- package/dist/session-titler.js +8 -13
- package/dist/session-watch.d.ts +3 -3
- package/dist/session-watch.js +4 -4
- package/dist/sighup-idle.d.ts +2 -2
- package/dist/spec-fields.d.ts +4 -4
- package/dist/sql-engine-posture.d.ts +3 -3
- package/dist/store-posture.d.ts +2 -2
- package/dist/stored-request-tool-axes-m19.d.ts +1 -1
- package/dist/task-a2a.d.ts +3 -1
- package/dist/task-a2a.js +38 -5
- package/dist/task-cwd.d.ts +7 -88
- package/dist/task-cwd.js +2 -15
- package/dist/task-mcp.d.ts +14 -10
- package/dist/task-mcp.js +39 -12
- package/dist/task-settings.d.ts +34 -18
- package/dist/task-settings.js +34 -4
- package/dist/task-workflow.d.ts +0 -24
- package/dist/task-workflow.js +2 -1
- package/dist/terminal.d.ts +5 -5
- package/dist/tighten-only-seats.d.ts +7 -6
- package/dist/tighten-only-seats.js +1 -1
- package/dist/tool-approval.d.ts +273 -228
- package/dist/tool-approval.js +125 -47
- package/dist/tool-rule-names.d.ts +7 -1
- package/dist/trace/core-keyset-guard.d.ts +15 -9
- package/dist/trace/engine-notice-wire.d.ts +5 -5
- package/dist/trace/engine-notice-wire.js +1 -0
- package/dist/trace/exit-seat.d.ts +40 -1
- package/dist/trace/exit-seat.js +46 -14
- package/dist/trace/ledger-events.d.ts +6 -4
- package/dist/trace/ledger-sink.d.ts +1 -1
- package/dist/trace/model-segment.d.ts +3 -3
- package/dist/trace/project.d.ts +65 -46
- package/dist/trace/project.js +49 -5
- package/dist/trace/redact.d.ts +44 -27
- package/dist/trace/redact.js +343 -73
- package/dist/trace/self-minted-wire.d.ts +39 -14
- package/dist/trace/self-minted-wire.js +9 -0
- package/dist/trace/sema-provenance.d.ts +1 -1
- package/dist/trace/task-notification-facets.d.ts +4 -4
- package/dist/trace/wire-projection-faces.d.ts +9 -3
- package/dist/trace/wire-projection-faces.js +7 -1
- package/dist/unattended-permission-mode.d.ts +5 -5
- package/dist/url-credential.d.ts +52 -0
- package/dist/url-credential.js +49 -0
- package/dist/url-refusal.d.ts +6 -2
- package/dist/url-refusal.js +8 -1
- package/dist/usage-analytics.d.ts +2 -2
- package/dist/user-input-ledger.d.ts +23 -23
- package/dist/web-admin-client/apply-effective.d.ts +5 -5
- package/dist/web-admin-client/apply-effective.js +2 -1
- package/dist/web-admin-client/apply-ledger.d.ts +2 -2
- package/dist/web-admin-client/center-request.d.ts +2 -2
- package/dist/web-admin-client/facade.d.ts +5 -5
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/hot-keys-registry.d.ts +2 -2
- package/dist/web-admin-client/http-client.d.ts +4 -4
- package/dist/web-admin-client/mcp-revocation.d.ts +1 -1
- package/dist/web-admin-client/pull-state.d.ts +1 -1
- package/dist/web-admin-client/read-face.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +5 -5
- package/dist/web-admin-client/restart-signal.d.ts +6 -6
- package/dist/web-admin-client/skills-mcp.d.ts +29 -4
- package/dist/web-admin-client/skills-mcp.js +31 -4
- package/dist/web-admin-client/types.d.ts +17 -10
- package/dist/workspace-space.d.ts +5 -3
- package/dist/write-protection.d.ts +2 -2
- package/package.json +4 -3
- package/scripts/drain-check-local.mjs +35 -2
- package/scripts/drain-check.mysql.sql +22 -2
- package/scripts/drain-check.pg.sql +22 -2
- package/skills/loop.md +1 -1
- package/dist/mcp-tool-faces.d.ts +0 -69
- package/dist/mcp-tool-faces.js +0 -104
- package/dist/orchestration/workflow-journal-entry.js +0 -27
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 因此**导入两口**只认已验明的 principal,连 `explicitOperatorOk` 的旁路都不给:一个 operator 想给
|
|
13
13
|
* 自己导规则,用他自己的 principal 走同一条路即可(那时他就是租户)。
|
|
14
14
|
*
|
|
15
|
-
* 🔴 **`POST /v1/rules` 是撤销口的对偶,不是导入口的简写**(
|
|
15
|
+
* 🔴 **`POST /v1/rules` 是撤销口的对偶,不是导入口的简写**([ref]):它写的只有**收紧**方向
|
|
16
16
|
* (deny/ask),而收紧不需要同意仪式 —— 与撤销为什么不需要是同一条理由(core `removePersistedRule`
|
|
17
17
|
* 头注逐字:「a host may narrow on a user's behalf, it may not widen」)。放宽(allow)仍然只有两条路:
|
|
18
18
|
* 一张卡上的人点头,或一次显式的 settings 导入。方向表在 `permission-rule-vocab.ts`,不在本文件。
|
|
@@ -6,8 +6,8 @@ import * as facts from "../../capability-facts.js";
|
|
|
6
6
|
import { createLogger } from "../../observability/logger.js";
|
|
7
7
|
import { RULE_IMPORT_RETRY_AFTER_SEC, RULE_SCOPE_REFUSAL_SENTENCE, MAX_RULE_SCOPE_CHARS, buildCcImportLayerRootRefusal, parseRuleScope, serializeRuleScope } from "../../rules-consent.js";
|
|
8
8
|
import { hasControlOrBidi } from "@sema-agent/settings-schema";
|
|
9
|
-
import { MAX_RULE_TEXT_CHARS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
|
|
10
|
-
import {
|
|
9
|
+
import { IMPORTED_SETTINGS_LAYERS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, RULE_ADD_ORIGINS, RULE_BEHAVIORS, isValidDurableScope } from "@sema-agent/core";
|
|
10
|
+
import { isPersistedRuleTool, isDirectWritableRuleBehavior } from "../../permission-rule-vocab.js";
|
|
11
11
|
const logger = createLogger();
|
|
12
12
|
export const RULES_CC_IMPORT_PREPARE_PATH = "/v1/rules/cc-import/prepare";
|
|
13
13
|
export const RULES_CC_IMPORT_REDEEM_PATH = "/v1/rules/cc-import/redeem";
|
|
@@ -23,7 +23,7 @@ const CcImportPrepareBodySchema = z
|
|
|
23
23
|
layers: z
|
|
24
24
|
.array(z
|
|
25
25
|
.object({
|
|
26
|
-
layer: z.enum(
|
|
26
|
+
layer: z.enum(IMPORTED_SETTINGS_LAYERS),
|
|
27
27
|
path: z.string().min(1).max(1024),
|
|
28
28
|
root: z.string().max(1024),
|
|
29
29
|
content: z.string().max(MAX_LAYER_CONTENT_CHARS),
|
|
@@ -41,7 +41,7 @@ const CcImportRedeemBodySchema = z.object({ ticket: TicketStringSchema }).strict
|
|
|
41
41
|
const LocalImportAddSchema = z
|
|
42
42
|
.object({
|
|
43
43
|
dot: z.object({ actor: z.string().min(1).max(190), counter: z.number().int().nonnegative().safe() }).strict(),
|
|
44
|
-
origin: z.enum(
|
|
44
|
+
origin: z.enum(RULE_ADD_ORIGINS),
|
|
45
45
|
createdAt: z.string().min(1).max(64),
|
|
46
46
|
})
|
|
47
47
|
.strict();
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -3,6 +3,7 @@ import { redactHead, redactLedgerEventForRead } from "../../observability/run-te
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { uuidv7, mintCheckpointToken, CheckpointError, policyCannotAnswer, validatePendingSteer, TASK_OUTPUT_REPLAY_KINDS, isSystemInjectionPriority } from "@sema-agent/core";
|
|
5
5
|
import { isTerminalRunStatus, isParkedRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
|
|
6
|
+
import { askRowCarriesOwner } from "../../plugins/approval-ask-store-sql.js";
|
|
6
7
|
import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-sql.js";
|
|
7
8
|
import { redactSecrets } from "../../trace/redact.js";
|
|
8
9
|
import { isUuidV7, encodeCheckpointScope } from "../../security.js";
|
|
@@ -13,7 +14,7 @@ import { streamSseLog } from "../sse-log.js";
|
|
|
13
14
|
import { bindSseLifecycle } from "../sse-lifecycle.js";
|
|
14
15
|
import { buildApprovalPreamble, buildApprovalPreambleSseFrames, readClosedWordSeat, storedCardDemandsAPerson } from "../../approval-card.js";
|
|
15
16
|
import { heldAskOf, liveSettledBy, readDecidedBy, retiredDecisionKeyFacts, DECIDED_BY_NOT_IN_PROOF, DECIDED_BY_OUTSIDE_CLOSED_SET, POLICY_CANNOT_ALLOW_PERSON_ASK } from "../../host-decision.js";
|
|
16
|
-
import { ASK_DECISION_CONSUMER_ABSENT, outcomeOfDecidedRow, resolveStreamApprovalGate } from "../../tool-approval.js";
|
|
17
|
+
import { ASK_DECISION_CONSUMER_ABSENT, approvalPreambleReplays, outcomeOfDecidedRow, presentedApprovalFrameFamily, resolveStreamApprovalGate } from "../../tool-approval.js";
|
|
17
18
|
import { MAX_DECISION_NOTE_CHARS, noteLandedOnRow, noteRecordedReceipt } from "../../approval-ask-machine.js";
|
|
18
19
|
import { causeOfAskRow } from "../../approval-deny-reasons.js";
|
|
19
20
|
import { normalizeRunEventType, screenedStoredEventData } from "../../trace/project.js";
|
|
@@ -32,6 +33,7 @@ import { RUN_NOT_FOUND_MESSAGE, runNotFoundMessage } from "../route-ctx.js";
|
|
|
32
33
|
import { withPrincipal } from "../../observability/principal-context.js";
|
|
33
34
|
import { readResumeCtx } from "../resume-ctx-read.js";
|
|
34
35
|
import { storedBodyReplayAnswer, storedBodyReplayLogFields } from "../checkpoint-ctx.js";
|
|
36
|
+
import { headReadOf } from "../../session-incarnation.js";
|
|
35
37
|
import { serviceVersion } from "../../service-version.js";
|
|
36
38
|
import { storedBodyReplayRefusal } from "../stored-body-replay.js";
|
|
37
39
|
import { steerBodyKeyIssue } from "../../request-key-closure.js";
|
|
@@ -116,10 +118,18 @@ async function streamRunEvents(req, res, deps, runStore, taskId, staleMs) {
|
|
|
116
118
|
toolApprovalEnabled: Boolean(deps.toolApproval),
|
|
117
119
|
streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
|
|
118
120
|
backend: deps.backend,
|
|
119
|
-
|
|
121
|
+
checkpointStore: deps.checkpointStore,
|
|
120
122
|
});
|
|
121
123
|
if (!gate.active)
|
|
122
124
|
return [];
|
|
125
|
+
if (!approvalPreambleReplays({
|
|
126
|
+
streamApprovalOn: gate.active,
|
|
127
|
+
windowMs: deps.config.streamApproval?.windowMs,
|
|
128
|
+
windowMarginMs: deps.config.streamAskWindowMarginMs,
|
|
129
|
+
declaredFamilies: new Set([presentedApprovalFrameFamily(gate.active)]),
|
|
130
|
+
})) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
123
133
|
const store = gate.askStore;
|
|
124
134
|
const rows = await store.listPendingByTask(taskId, signal);
|
|
125
135
|
const { frames, skipped, dropped } = buildApprovalPreamble(rows, Date.now(), deps.config.streamApproval.replayMax);
|
|
@@ -560,7 +570,8 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
560
570
|
}
|
|
561
571
|
return;
|
|
562
572
|
}
|
|
563
|
-
|
|
573
|
+
const sessionHeadOf = headReadOf(deps.sessionStorage);
|
|
574
|
+
if (deps.checkpointStore && sessionHeadOf) {
|
|
564
575
|
const activeTaskId = await runStore.getActiveTaskId?.(run.sessionId).catch(() => undefined);
|
|
565
576
|
if (activeTaskId !== undefined && activeTaskId !== null && activeTaskId !== taskId) {
|
|
566
577
|
sendNotRunning(`run is ${run.status} and its session has an ACTIVE run (${activeTaskId}) — steer that run instead`);
|
|
@@ -610,14 +621,18 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
610
621
|
mintResult.duplicateKey = true;
|
|
611
622
|
return;
|
|
612
623
|
}
|
|
613
|
-
const leafId = await
|
|
624
|
+
const leafId = await sessionHeadOf(run.sessionId).then((h) => h?.leafId).catch(() => undefined);
|
|
614
625
|
if (leafId === undefined || leafId === null)
|
|
615
626
|
return;
|
|
616
|
-
const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId));
|
|
627
|
+
const resumeRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
|
|
617
628
|
if (resumeRead.kind === "corrupt") {
|
|
618
629
|
mintResult.corruptCtxWhere = resumeRead.where;
|
|
619
630
|
return;
|
|
620
631
|
}
|
|
632
|
+
if (resumeRead.kind === "unsealable") {
|
|
633
|
+
mintResult.unsealableCtx = resumeRead;
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
621
636
|
if (resumeRead.kind === "absent") {
|
|
622
637
|
mintResult.noResumeCtx = true;
|
|
623
638
|
return;
|
|
@@ -641,10 +656,13 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
641
656
|
createdAt: Date.now(),
|
|
642
657
|
sourceTaskId: taskId,
|
|
643
658
|
});
|
|
644
|
-
const stillRead = await readResumeCtx(cs.getCtx(run.sessionId));
|
|
645
|
-
if (stillRead.kind === "corrupt") {
|
|
646
|
-
await withdrawWakeCard(wakeToken, cpScope, "resume_context_corrupt");
|
|
647
|
-
|
|
659
|
+
const stillRead = await readResumeCtx(cs.getCtx(run.sessionId), { sessionId: run.sessionId, opener: deps.checkpointCtxSealing });
|
|
660
|
+
if (stillRead.kind === "corrupt" || stillRead.kind === "unsealable") {
|
|
661
|
+
await withdrawWakeCard(wakeToken, cpScope, stillRead.kind === "corrupt" ? "resume_context_corrupt" : "resume_context_unsealable");
|
|
662
|
+
if (stillRead.kind === "corrupt")
|
|
663
|
+
mintResult.corruptCtxWhere = stillRead.where;
|
|
664
|
+
else
|
|
665
|
+
mintResult.unsealableCtx = stillRead;
|
|
648
666
|
return;
|
|
649
667
|
}
|
|
650
668
|
if (stillRead.kind !== "ok") {
|
|
@@ -681,6 +699,10 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
681
699
|
sendError(res, 500, "corrupt", "run already ended and this session's stored resume context cannot be read — nothing was queued. Ask whoever operates this deployment to repair or remove the row named in `where` before steering this session again.", { where: mintResult.corruptCtxWhere });
|
|
682
700
|
return;
|
|
683
701
|
}
|
|
702
|
+
if (mintResult.unsealableCtx !== undefined) {
|
|
703
|
+
sendError(res, 409, "conflict.checkpoint_ctx_unsealable", "run already ended and this session's stored resume context holds credentials this server cannot unseal (reason says why) — nothing was queued, because POST /v1/sessions/:id/wake could not resume it; restore the sealed-key directory that sealed them, restart this server (it reads its keys only at startup) and steer again, or submit a new task instead", { field: mintResult.unsealableCtx.field, reason: mintResult.unsealableCtx.reason });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
684
706
|
if (mintResult.unservable !== undefined) {
|
|
685
707
|
deps.logger?.warn?.("steer_wake_park_refused_stored_body", { taskId, sessionId: run.sessionId, ...storedBodyReplayLogFields(mintResult.unservable) });
|
|
686
708
|
const { status, body: { error, errorCode, ...rest } } = storedBodyReplayAnswer(mintResult.unservable, serviceVersion(), false);
|
|
@@ -1432,6 +1454,10 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1432
1454
|
});
|
|
1433
1455
|
return;
|
|
1434
1456
|
}
|
|
1457
|
+
if (hit && !askRowCarriesOwner(hit, row0.owner)) {
|
|
1458
|
+
askNotFound();
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1435
1461
|
if (hit && hit.state === "DECIDED") {
|
|
1436
1462
|
if (!syncLiveFromDecidedRow(hit))
|
|
1437
1463
|
return;
|
|
@@ -1450,7 +1476,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1450
1476
|
let outcome;
|
|
1451
1477
|
const releaseEditMark = body.decision === "approve" && hasUpdatedInput ? deps.toolApproval?.markEditedDecisionInFlight(askId) : undefined;
|
|
1452
1478
|
try {
|
|
1453
|
-
outcome = await askStore.decideAsk(askId, row0.batchId, {
|
|
1479
|
+
outcome = await askStore.decideAsk(askId, row0.batchId, row0.owner, {
|
|
1454
1480
|
decision: body.decision,
|
|
1455
1481
|
decisionActor: actor,
|
|
1456
1482
|
decisionNote: body.note ?? null,
|
|
@@ -1466,13 +1492,16 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1466
1492
|
hadIdempotencyKey: body.idempotencyKey !== undefined,
|
|
1467
1493
|
error: err instanceof Error ? err.message : String(err ?? ""),
|
|
1468
1494
|
});
|
|
1495
|
+
let confirmedOutOfScope = false;
|
|
1469
1496
|
if (releaseEditMark !== undefined &&
|
|
1470
1497
|
body.idempotencyKey !== undefined &&
|
|
1471
1498
|
deps.toolApproval &&
|
|
1472
1499
|
deps.toolApproval.editedDecisionInFlightCount(askId) === 1) {
|
|
1473
1500
|
try {
|
|
1474
1501
|
const confirmed = await withDeadline(askStore.getAsk(askId), ASK_DECISION_CONFIRM_TIMEOUT_MS, "getAsk(ambiguous-commit-confirm)");
|
|
1475
|
-
if (confirmed !== null &&
|
|
1502
|
+
if (confirmed !== null && !askRowCarriesOwner(confirmed, row0.owner))
|
|
1503
|
+
confirmedOutOfScope = true;
|
|
1504
|
+
else if (confirmed !== null &&
|
|
1476
1505
|
confirmed.state === "DECIDED" &&
|
|
1477
1506
|
confirmed.decision === body.decision &&
|
|
1478
1507
|
confirmed.idempotencyKey === body.idempotencyKey &&
|
|
@@ -1485,6 +1514,10 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1485
1514
|
deps.logger?.warn?.("ask_decision_edit_confirm_failed", { taskId, askId, error: confirmErr instanceof Error ? confirmErr.message : String(confirmErr ?? "") });
|
|
1486
1515
|
}
|
|
1487
1516
|
}
|
|
1517
|
+
if (confirmedOutOfScope) {
|
|
1518
|
+
askNotFound();
|
|
1519
|
+
return;
|
|
1520
|
+
}
|
|
1488
1521
|
if (body.idempotencyKey !== undefined) {
|
|
1489
1522
|
sendError(res, 500, "internal.error", "the ask decision store failed around commit — the decision MAY already be persisted; retry with the same idempotencyKey to replay it instead of colliding with it");
|
|
1490
1523
|
}
|
|
@@ -34,8 +34,9 @@ export type PendingStaging = {
|
|
|
34
34
|
declaredEntryIds: string[];
|
|
35
35
|
/** The principal that opened this staging — a different caller may not drive it (404, no oracle). */
|
|
36
36
|
openedBy: string | null;
|
|
37
|
-
/**
|
|
38
|
-
|
|
37
|
+
/** The owner cell the gate judged when it opened this staging (head-read reading `headOf(id)?.owner`: `undefined` = no such session) — the commit lands only on
|
|
38
|
+
* this same cell (`StagedCommitOptions.expectedOwner`, `session-sync-kernel.ts`); `owner` above (the re-stamped importing principal) is derived from it for a fleet caller. */
|
|
39
|
+
expectedOwner: string | null | undefined;
|
|
39
40
|
};
|
|
40
41
|
/** 单域独占状态 + 它的两个操作。每个 server 实例一份。 */
|
|
41
42
|
export interface SessionSyncLocal {
|
|
@@ -2,13 +2,13 @@ import { once } from "node:events";
|
|
|
2
2
|
import { randomBytes, createHash } from "node:crypto";
|
|
3
3
|
import { sessionLogDigest, sessionLogDigestsComparable, StreamingImportValidator, validateFileHistoryExport } from "@sema-agent/core";
|
|
4
4
|
import { StringDecoder } from "node:string_decoder";
|
|
5
|
-
import { exportSessionManifest, fileHistoryImportFace, replayFileHistory, replayPolicyRecords, wipeSessionAttendants } from "../../session-sync.js";
|
|
5
|
+
import { FileHistoryUnreadableError, blobGetterOf, exportSessionManifest, exportedFileHistory, fileHistoryImportFace, replayFileHistory, replayPolicyRecords, wipeSessionAttendants } from "../../session-sync.js";
|
|
6
6
|
import * as facts from "../../capability-facts.js";
|
|
7
7
|
import { classifySyncRelationshipByIds, SyncConflictError } from "../../session-sync-kernel.js";
|
|
8
|
-
import { isUuidShape } from "../../security.js";
|
|
8
|
+
import { isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
|
|
9
9
|
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
|
|
10
10
|
import { buildDisplaySafeUrl } from "../../trace/redact.js";
|
|
11
|
-
import { gatedPrincipal, explicitOperatorOk, sendUnauthorized } from "../principal-gate.js";
|
|
11
|
+
import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sendUnauthorized, sessionCallerOf } from "../principal-gate.js";
|
|
12
12
|
const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
|
|
13
13
|
const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
|
|
14
14
|
const SYNC_IMPORT_BATCH = 500;
|
|
@@ -16,6 +16,7 @@ import { SHA256_HEX_RE } from "../../digest-form.js";
|
|
|
16
16
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
17
17
|
import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
|
|
18
18
|
import { readSessionPinned, readSessionTitle } from "../../session-row.js";
|
|
19
|
+
import { sessionFaceOfHead } from "../../session-incarnation.js";
|
|
19
20
|
export function createSessionSyncLocal() {
|
|
20
21
|
const pendingStagings = new Map();
|
|
21
22
|
const importLeases = new Map();
|
|
@@ -34,7 +35,7 @@ export function createSessionSyncLocal() {
|
|
|
34
35
|
}
|
|
35
36
|
export async function handleSessionSync(req, res, match, ctx) {
|
|
36
37
|
const { deps } = ctx;
|
|
37
|
-
const { readJson, readRawBody, safeDecode,
|
|
38
|
+
const { readJson, readRawBody, safeDecode, rateLimited } = ctx.helpers;
|
|
38
39
|
const { pendingStagings, importLeases, touchImportLease, cleanupStaging } = ctx.local.sessionSync;
|
|
39
40
|
{
|
|
40
41
|
{
|
|
@@ -44,7 +45,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
47
|
const { backend, sessionStorage, historyStore } = sync;
|
|
47
|
-
const scope =
|
|
48
|
+
const scope = fleetViewOf(req, deps, "write");
|
|
48
49
|
if (!scope.fleetWide && scope.gateOwner === null) {
|
|
49
50
|
sendUnauthorized(res, "identity");
|
|
50
51
|
return;
|
|
@@ -54,23 +55,25 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
54
55
|
sendError(res, 400, "request.id_invalid", "invalid session id (must be a canonical uuid)");
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
|
-
const
|
|
58
|
+
const judgeSessionGate = async () => {
|
|
59
|
+
const face = sessionFaceOfHead(sessionId, await sessionStorage.headOf(sessionId));
|
|
60
|
+
const mayTouch = face !== undefined && (scope.fleetWide || face.owner === scope.gateOwner || legacyUnownedSessionOk(deps.config, sessionCallerOf(req, deps), await sessionOwnerCellOf(sessionStorage, sessionId, face.owner)));
|
|
61
|
+
return { face, mayPull: mayTouch, mayPush: face === undefined || mayTouch };
|
|
62
|
+
};
|
|
63
|
+
const gate = await judgeSessionGate();
|
|
64
|
+
const gateFace = gate.face;
|
|
58
65
|
const owner = gateFace === undefined ? undefined : gateFace.owner;
|
|
59
|
-
const
|
|
66
|
+
const sendSessionAbsent = () => sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
60
67
|
const pullGateOk = () => {
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
if (!ownsOrFleet(owner)) {
|
|
66
|
-
sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
|
|
68
|
+
if (!gate.mayPull) {
|
|
69
|
+
sendSessionAbsent();
|
|
67
70
|
return false;
|
|
68
71
|
}
|
|
69
72
|
return true;
|
|
70
73
|
};
|
|
71
74
|
const pushGateOk = () => {
|
|
72
|
-
if (
|
|
73
|
-
|
|
75
|
+
if (!gate.mayPush) {
|
|
76
|
+
sendSessionAbsent();
|
|
74
77
|
return false;
|
|
75
78
|
}
|
|
76
79
|
return true;
|
|
@@ -80,6 +83,11 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
80
83
|
return true;
|
|
81
84
|
return face !== undefined && (await sessionStorage.patchSessionMeta(sessionId, row, face)) !== undefined;
|
|
82
85
|
};
|
|
86
|
+
const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
|
|
87
|
+
const replayHistory = async (envelope, allowReplace) => {
|
|
88
|
+
const r = await replayFileHistory(historyStore, sessionId, envelope, blobGetterOf(historyStore), { allowReplace });
|
|
89
|
+
return r.ok ? undefined : r;
|
|
90
|
+
};
|
|
83
91
|
if (match.decl.id === "session-sync-manifest") {
|
|
84
92
|
if (!pullGateOk())
|
|
85
93
|
return;
|
|
@@ -88,12 +96,12 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
88
96
|
out = await exportSessionManifest(sessionId, backend, historyStore);
|
|
89
97
|
}
|
|
90
98
|
catch (e) {
|
|
91
|
-
if (sendSessionPolicyError(res, e))
|
|
99
|
+
if (sendSessionPolicyError(res, e) || sendFileHistoryUnreadable(res, e))
|
|
92
100
|
return;
|
|
93
101
|
throw e;
|
|
94
102
|
}
|
|
95
103
|
if (out === null) {
|
|
96
|
-
|
|
104
|
+
sendSessionAbsent();
|
|
97
105
|
return;
|
|
98
106
|
}
|
|
99
107
|
sendJson(res, 200, { manifest: out.manifest });
|
|
@@ -114,7 +122,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
114
122
|
}
|
|
115
123
|
const it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ? undefined : { afterSeq });
|
|
116
124
|
if (it === null) {
|
|
117
|
-
|
|
125
|
+
sendSessionAbsent();
|
|
118
126
|
return;
|
|
119
127
|
}
|
|
120
128
|
res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
|
|
@@ -154,8 +162,16 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
154
162
|
return;
|
|
155
163
|
}
|
|
156
164
|
const fs = blobs.historyStore;
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
let envelope;
|
|
166
|
+
try {
|
|
167
|
+
envelope = await exportedFileHistory(fs, sessionId);
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
if (sendFileHistoryUnreadable(res, e))
|
|
171
|
+
return;
|
|
172
|
+
throw e;
|
|
173
|
+
}
|
|
174
|
+
const referenced = envelope !== null && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
|
|
159
175
|
if (!referenced) {
|
|
160
176
|
sendError(res, 404, "not_found.blob", "blob not found");
|
|
161
177
|
return;
|
|
@@ -273,6 +289,17 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
273
289
|
sendError(res, 409, "conflict", "sync conflict", { relation: relA });
|
|
274
290
|
return;
|
|
275
291
|
}
|
|
292
|
+
if (fileHistory !== null) {
|
|
293
|
+
const distinct = new Set();
|
|
294
|
+
for (const t of fileHistory.tracked)
|
|
295
|
+
for (const v of t.versions)
|
|
296
|
+
if (v.blobHash !== null)
|
|
297
|
+
distinct.add(v.blobHash);
|
|
298
|
+
if (await firstMissingBlob(facts.sessionSyncFileHistory(deps), [...distinct]) !== undefined) {
|
|
299
|
+
sendMissingBlob(res);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
276
303
|
let payloadVerified = false;
|
|
277
304
|
let digestSaysDiffer = false;
|
|
278
305
|
if (relA.relation === "identical" && srcLogDigest !== undefined) {
|
|
@@ -288,8 +315,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
288
315
|
digestSaysDiffer = true;
|
|
289
316
|
}
|
|
290
317
|
if (relA.relation === "identical" && !digestSaysDiffer) {
|
|
291
|
-
|
|
292
|
-
if (fileHistory !== null && blobFaces.available && fileHistoryImportFace(blobFaces.historyStore)) {
|
|
318
|
+
if (fileHistory !== null && canReplayHistory) {
|
|
293
319
|
if (resolution === "overwrite-dst") {
|
|
294
320
|
const activeNow = await deps.runStore?.getActiveTaskId(sessionId);
|
|
295
321
|
if (activeNow) {
|
|
@@ -297,11 +323,9 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
297
323
|
return;
|
|
298
324
|
}
|
|
299
325
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (!r.ok) {
|
|
304
|
-
sendError(res, 422, failCode, `file history import failed (${r.error.code})`);
|
|
326
|
+
const failed = await replayHistory(fileHistory, resolution === "overwrite-dst");
|
|
327
|
+
if (failed !== undefined) {
|
|
328
|
+
sendFileHistoryReplayFailure(res, failed);
|
|
305
329
|
return;
|
|
306
330
|
}
|
|
307
331
|
}
|
|
@@ -354,31 +378,6 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
354
378
|
return;
|
|
355
379
|
}
|
|
356
380
|
}
|
|
357
|
-
const fss = historyStore;
|
|
358
|
-
if (fileHistory !== null && fileHistoryImportFace(fss) !== undefined) {
|
|
359
|
-
const distinct = new Set();
|
|
360
|
-
for (const t of fileHistory.tracked)
|
|
361
|
-
for (const v of t.versions)
|
|
362
|
-
if (v.blobHash !== null)
|
|
363
|
-
distinct.add(v.blobHash);
|
|
364
|
-
const all = [...distinct];
|
|
365
|
-
if (typeof fss.hasBlobs === "function") {
|
|
366
|
-
const present = await fss.hasBlobs(all);
|
|
367
|
-
const missing = all.find((h) => !present.has(h));
|
|
368
|
-
if (missing !== undefined) {
|
|
369
|
-
sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
else if (typeof fss.getBlob === "function") {
|
|
374
|
-
for (const hash of all) {
|
|
375
|
-
if (!(await fss.getBlob(hash))) {
|
|
376
|
-
sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
381
|
const importingPrincipal = scope.fleetWide ? (owner ?? null) : scope.gateOwner;
|
|
383
382
|
const operatorOk = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
|
|
384
383
|
const token = randomBytes(8).toString("hex");
|
|
@@ -387,7 +386,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
387
386
|
importLeases.set(sessionId, { at: Date.now(), stagingId });
|
|
388
387
|
pendingStagings.set(stagingId, {
|
|
389
388
|
handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
|
|
390
|
-
fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner,
|
|
389
|
+
fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: scope.gateOwner, expectedOwner: owner,
|
|
391
390
|
});
|
|
392
391
|
sendJson(res, 200, { stagingId, relation: relA.relation });
|
|
393
392
|
return;
|
|
@@ -403,11 +402,10 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
403
402
|
sendError(res, 404, "not_found.staging", "staging not found");
|
|
404
403
|
return;
|
|
405
404
|
}
|
|
406
|
-
if (!
|
|
405
|
+
if (!scope.fleetWide && pending.openedBy !== scope.gateOwner) {
|
|
407
406
|
sendError(res, 404, "not_found.staging", "staging not found");
|
|
408
407
|
return;
|
|
409
408
|
}
|
|
410
|
-
const getBlob = (h) => historyStore.getBlob ? historyStore.getBlob(h) : Promise.resolve(undefined);
|
|
411
409
|
const validator = new StreamingImportValidator();
|
|
412
410
|
let lineBuf = "";
|
|
413
411
|
let pendingBatch = [];
|
|
@@ -485,7 +483,23 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
485
483
|
return;
|
|
486
484
|
throw e;
|
|
487
485
|
}
|
|
488
|
-
|
|
486
|
+
let mayPushAtCommit;
|
|
487
|
+
let activeAtCommit;
|
|
488
|
+
try {
|
|
489
|
+
mayPushAtCommit = (await judgeSessionGate()).mayPush;
|
|
490
|
+
activeAtCommit = mayPushAtCommit ? await deps.runStore?.getActiveTaskId(sessionId) : undefined;
|
|
491
|
+
}
|
|
492
|
+
catch (e) {
|
|
493
|
+
await pending.handle.abort().catch(() => undefined);
|
|
494
|
+
cleanupStaging(stagingId);
|
|
495
|
+
throw e;
|
|
496
|
+
}
|
|
497
|
+
if (!mayPushAtCommit) {
|
|
498
|
+
await pending.handle.abort().catch(() => undefined);
|
|
499
|
+
cleanupStaging(stagingId);
|
|
500
|
+
sendSessionAbsent();
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
489
503
|
if (activeAtCommit) {
|
|
490
504
|
await pending.handle.abort().catch(() => undefined);
|
|
491
505
|
cleanupStaging(stagingId);
|
|
@@ -493,15 +507,14 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
493
507
|
return;
|
|
494
508
|
}
|
|
495
509
|
try {
|
|
496
|
-
const committed = await pending.handle.commit(pending.owner, pending.resolution ? { resolution: pending.resolution } :
|
|
510
|
+
const committed = await pending.handle.commit(pending.owner, { expectedOwner: pending.expectedOwner, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
|
|
497
511
|
if (pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale")) {
|
|
498
512
|
await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
|
|
499
513
|
}
|
|
500
|
-
if (pending.fileHistory !== null &&
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
sendError(res, 422, failCode, `file history import failed (${r.error.code})`);
|
|
514
|
+
if (pending.fileHistory !== null && canReplayHistory) {
|
|
515
|
+
const failed = await replayHistory(pending.fileHistory, pending.resolution === "overwrite-dst");
|
|
516
|
+
if (failed !== undefined) {
|
|
517
|
+
sendFileHistoryReplayFailure(res, failed);
|
|
505
518
|
cleanupStaging(stagingId);
|
|
506
519
|
return;
|
|
507
520
|
}
|
|
@@ -556,6 +569,40 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
556
569
|
}
|
|
557
570
|
}
|
|
558
571
|
}
|
|
572
|
+
function sendFileHistoryUnreadable(res, e) {
|
|
573
|
+
if (!(e instanceof FileHistoryUnreadableError))
|
|
574
|
+
return false;
|
|
575
|
+
const permanence = e.failure.permanence;
|
|
576
|
+
const advice = permanence === "transient" ? "the history store judged the fault transient: retry later" : permanence === "terminal" ? "the history store judged the fault permanent: retrying will not help until the store is repaired" : "the history store did not judge whether retrying can help";
|
|
577
|
+
sendError(res, 503, "state.file_history_unreadable", `this session's file history cannot be read whole (${e.failure.code}), so nothing was exported — ${advice}`, permanence === undefined ? undefined : { permanence });
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
function sendMissingBlob(res) {
|
|
581
|
+
sendError(res, 422, "missing_blob", "missing blob; PUT all referenced blobs before import");
|
|
582
|
+
}
|
|
583
|
+
function sendFileHistoryReplayFailure(res, failure) {
|
|
584
|
+
if (failure.missingBlob !== undefined) {
|
|
585
|
+
sendMissingBlob(res);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const { code, permanence } = failure.error;
|
|
589
|
+
sendError(res, 422, code, `file history import failed (${code})`, permanence === undefined ? undefined : { permanence });
|
|
590
|
+
}
|
|
591
|
+
async function firstMissingBlob(blobFaces, referenced) {
|
|
592
|
+
if (referenced.length === 0)
|
|
593
|
+
return undefined;
|
|
594
|
+
if (!blobFaces.available)
|
|
595
|
+
return referenced[0];
|
|
596
|
+
const store = blobFaces.historyStore;
|
|
597
|
+
if (typeof store.hasBlobs === "function") {
|
|
598
|
+
const present = await store.hasBlobs([...referenced]);
|
|
599
|
+
return referenced.find((h) => !present.has(h));
|
|
600
|
+
}
|
|
601
|
+
for (const hash of referenced)
|
|
602
|
+
if (!(await store.getBlob(hash)))
|
|
603
|
+
return hash;
|
|
604
|
+
return undefined;
|
|
605
|
+
}
|
|
559
606
|
function sendSessionSyncUnavailable(res, why) {
|
|
560
607
|
switch (why) {
|
|
561
608
|
case "store_backend_absent":
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* [ref] A9 域模块 —— 会话列表 / 发件链接列表。
|
|
3
3
|
*
|
|
4
4
|
* 路由:`GET /v1/sessions`(CC /resume picker,keyset 分页)、`GET /v1/sendfile-links`。
|
|
5
|
-
* owner-scope 与 trace 列表同一权威模型(
|
|
5
|
+
* owner-scope 与 trace 列表同一权威模型(`fleetViewOf` 读档:service 凭据不报主体 / 只读 trace 凭据 / dev-open = fleet-wide;带验过的主体 = 钉住那位主体)。本域零可变状态。
|
|
6
6
|
*/
|
|
7
7
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
8
8
|
import { type SessionListItem } from "../../security.js";
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { isUuidV7, legacyUnownedAmnestyOpen } from "../../security.js";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
|
-
import { sendUnauthorized } from "../principal-gate.js";
|
|
3
|
+
import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
|
|
4
4
|
import { filterFingerprint } from "../cursor-fingerprint.js";
|
|
5
5
|
import { sessionTempoOfRunStatus } from "../../plugins/store-contracts.js";
|
|
6
6
|
import { assertNever } from "../route-ctx.js";
|
|
7
7
|
import * as facts from "../../capability-facts.js";
|
|
8
8
|
export async function handleSessionsList(req, res, match, ctx) {
|
|
9
9
|
const { deps } = ctx;
|
|
10
|
-
const { isFleetWide, sessionOwnerScope } = ctx.helpers;
|
|
11
10
|
switch (match.decl.id) {
|
|
12
11
|
case "sessions-list": {
|
|
13
|
-
const { fleetWide, gateOwner } =
|
|
12
|
+
const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
|
|
14
13
|
if (!fleetWide && gateOwner === null) {
|
|
15
14
|
sendUnauthorized(res, "identity");
|
|
16
15
|
return;
|
|
@@ -21,12 +20,12 @@ export async function handleSessionsList(req, res, match, ctx) {
|
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
23
22
|
const lister = listing.lister;
|
|
24
|
-
const includeUnowned = !fleetWide && legacyUnownedAmnestyOpen(deps.config
|
|
23
|
+
const includeUnowned = !fleetWide && legacyUnownedAmnestyOpen(deps.config, gateOwner);
|
|
25
24
|
await handleSessionList(res, lister, new URLSearchParams(match.search), gateOwner, includeUnowned);
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
28
27
|
case "sendfile-links": {
|
|
29
|
-
const { fleetWide, gateOwner } =
|
|
28
|
+
const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
|
|
30
29
|
if (!fleetWide && gateOwner === null) {
|
|
31
30
|
sendUnauthorized(res, "identity");
|
|
32
31
|
return;
|