@sema-agent/server 7.149.0 → 7.151.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 +307 -9
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +92 -40
- package/deploy/sema-up/README.md +7 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +3 -3
- package/dist/approval-gate-currency.d.ts +2 -2
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +2 -2
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +7 -8
- package/dist/boot/resolve-spec.js +80 -35
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +28 -24
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +16 -8
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +44 -6
- package/dist/boot/stage-10-http-server.js +12 -10
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/boot/web-admin.js +3 -1
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capability-facts.d.ts +84 -66
- package/dist/capability-facts.js +58 -41
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +15 -12
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +22 -15
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +66 -29
- package/dist/device-ws-protocol.d.ts +79 -12
- package/dist/device-ws-protocol.js +64 -26
- package/dist/engine-identity.d.ts +23 -5
- package/dist/engine-identity.js +13 -0
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +3 -3
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +19 -4
- package/dist/http/approval-sweeps.js +7 -6
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +20 -63
- package/dist/http/checkpoint-ctx.js +2 -24
- package/dist/http/claim-heartbeat.d.ts +4 -4
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +36 -29
- package/dist/http/durable-run-leg.js +17 -17
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +264 -20
- package/dist/http/owner-access.js +215 -5
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.js +38 -1
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +273 -89
- package/dist/http/route-ctx.d.ts +41 -19
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/a2a-serve.js +15 -14
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +12 -12
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +10 -6
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/projects.d.ts +4 -2
- package/dist/http/routes/projects.js +7 -6
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +125 -66
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +174 -83
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +26 -48
- package/dist/http/routes/tasks.js +38 -23
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +28 -30
- package/dist/http/server.js +7 -3
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +1 -2
- package/dist/http/submit-ctx.js +8 -6
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +19 -6
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/endpoint.js +9 -8
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +19 -5
- package/dist/leg-facts.js +3 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +12 -8
- package/dist/observability/fail-open.js +12 -8
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/owner-faces.d.ts +28 -4
- package/dist/owner-faces.js +2 -0
- package/dist/parked-decide.d.ts +104 -53
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/permission-mode-admission.d.ts +41 -5
- package/dist/permission-mode-admission.js +29 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -1
- package/dist/plugins/local-checkpoint-store.js +3 -0
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +80 -61
- package/dist/plugins/one-time-migrations.js +241 -104
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +28 -1
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +8 -3
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +44 -17
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +114 -14
- package/dist/plugins/remote-env-e2b.d.ts +18 -7
- package/dist/plugins/remote-env-e2b.js +53 -40
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +18 -1
- package/dist/plugins/remote-env-host.js +48 -47
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +56 -32
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +37 -43
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +64 -62
- package/dist/plugins/remote-shell.d.ts +101 -2
- package/dist/plugins/remote-shell.js +221 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +22 -3
- package/dist/plugins/run-store-sql.js +33 -9
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
- package/dist/plugins/schema-consistency.d.ts +9 -5
- package/dist/plugins/schema-consistency.js +48 -18
- package/dist/plugins/schema-drift-sentence.js +1 -1
- package/dist/plugins/send-file-ledger.js +3 -0
- package/dist/plugins/serving-requirement.d.ts +68 -0
- package/dist/plugins/serving-requirement.js +60 -0
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/stop-then-start-sentence.d.ts +48 -3
- package/dist/plugins/stop-then-start-sentence.js +48 -0
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +40 -13
- package/dist/plugins/store-backend.js +169 -27
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +29 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.js +9 -0
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +6 -1
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +64 -0
- package/dist/project-context.js +66 -0
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-cancel-card.d.ts +1 -1
- package/dist/run-cancel-card.js +2 -1
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +31 -33
- package/dist/security.js +41 -7
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-agent.d.ts +1 -10
- package/dist/session-agent.js +0 -6
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +28 -4
- package/dist/session-incarnation.js +14 -2
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +4 -98
- package/dist/session-sync.js +4 -74
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
- package/dist/stores-sql/checkpoint-store-sql.js +106 -18
- package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +2 -10
- package/dist/stores-sql/retention-store-sql.js +2 -10
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +6 -5
- package/dist/task-settings.d.ts +19 -5
- package/dist/task-settings.js +13 -7
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +147 -12
- package/dist/tool-approval.js +206 -109
- package/dist/trace/engine-notice-wire.d.ts +14 -0
- package/dist/trace/engine-notice-wire.js +18 -1
- package/dist/trace/project.d.ts +4 -3
- package/dist/trace/project.js +3 -2
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/self-minted-wire.d.ts +422 -26
- package/dist/trace/self-minted-wire.js +149 -23
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +120 -41
- package/package.json +3 -3
- package/wire-changes/server@7.150.0.json +335 -0
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { once } from "node:events";
|
|
2
2
|
import { sessionLogDigest, sessionLogDigestsComparable, validateFileHistoryExport } from "@sema-agent/core";
|
|
3
3
|
import { StringDecoder } from "node:string_decoder";
|
|
4
|
-
import { FileHistoryUnreadableError, blobGetterOf, exportSessionManifest, exportedFileHistory
|
|
4
|
+
import { FileHistoryUnreadableError, blobGetterOf, exportSessionManifest, exportedFileHistory } from "../../session-sync.js";
|
|
5
|
+
import { fileHistoryImportFace } from "../../plugins/landed-attendants.js";
|
|
5
6
|
import * as facts from "../../capability-facts.js";
|
|
6
7
|
import { classifySyncRelationshipByIds, createStagedLogFeed, MalformedImportEntryError, newStagingToken, readImportAnchors, SyncConflictError } from "../../session-sync-kernel.js";
|
|
7
8
|
import { isUuidShape } from "../../security.js";
|
|
8
9
|
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
|
|
9
10
|
import { StampedSessionArchiveError } from "../../session-error-wire.js";
|
|
10
|
-
import { readSessionAgent } from "../../session-agent.js";
|
|
11
11
|
import { buildDisplaySafeUrl } from "../../trace/redact.js";
|
|
12
12
|
import { storeFaultClassOf } from "../../plugins/store-fault.js";
|
|
13
|
-
import { enter,
|
|
13
|
+
import { enter, readSessionAgent, readSyncGate, recheckSyncGate, refuse } from "../owner-access.js";
|
|
14
14
|
import { listFilterOf, ownerKeyOf, sameKey } from "../../owner-faces.js";
|
|
15
15
|
const SYNC_BLOB_MAX_BYTES = 64 * 1024 * 1024;
|
|
16
16
|
const SYNC_NDJSON_LINE_MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -18,7 +18,7 @@ import { SHA256_HEX_RE } from "../../digest-form.js";
|
|
|
18
18
|
import { assertNever } from "../route-ctx.js";
|
|
19
19
|
import { readSessionRulesRecords, describeSessionRulesRecordProblem } from "../../session-policy-wire.js";
|
|
20
20
|
import { readSessionPinned, readSessionTitle } from "../../session-row.js";
|
|
21
|
-
import {
|
|
21
|
+
import { incarnationLogPrefix, SessionOccupantChangedError } from "../../session-incarnation.js";
|
|
22
22
|
import { defaultTaskRegistry } from "@sema-agent/core";
|
|
23
23
|
import { SessionActiveRunError, SessionForkInProgressError, SessionWriterPresentError } from "../../execution-placement.js";
|
|
24
24
|
import { probeSessionChildren, sessionTenantScope } from "../../session-children-retire.js";
|
|
@@ -94,10 +94,8 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
96
|
const judgeSessionGate = async () => {
|
|
97
|
-
const face =
|
|
98
|
-
|
|
99
|
-
const mayTouch = held !== undefined && (await judgeSession(syncEntry, sessionStorage, sessionId, held)) !== undefined;
|
|
100
|
-
return { face, occupant: held, mayPull: face !== undefined && mayTouch, mayPush: held === undefined || mayTouch };
|
|
97
|
+
const { face, occupant, mayTouch } = await readSyncGate(syncEntry, sessionStorage, sessionId);
|
|
98
|
+
return { face, occupant, mayPull: face !== undefined && mayTouch, mayPush: occupant === undefined || mayTouch };
|
|
101
99
|
};
|
|
102
100
|
let gate;
|
|
103
101
|
try {
|
|
@@ -125,6 +123,33 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
125
123
|
}
|
|
126
124
|
return true;
|
|
127
125
|
};
|
|
126
|
+
const stillAdmitted = async (port) => {
|
|
127
|
+
const admitted = port === "pull" ? gate.face : gate.occupant;
|
|
128
|
+
return admitted === undefined || (await recheckSyncGate(sessionStorage, sessionId, admitted, port));
|
|
129
|
+
};
|
|
130
|
+
const pullAnswer = async (send) => {
|
|
131
|
+
let same;
|
|
132
|
+
try {
|
|
133
|
+
same = await stillAdmitted("pull");
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
if (sendPullUnreadable(req, res, deps.logger, e))
|
|
137
|
+
return;
|
|
138
|
+
throw e;
|
|
139
|
+
}
|
|
140
|
+
if (!same) {
|
|
141
|
+
sendSessionAbsent("missing");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
send();
|
|
145
|
+
};
|
|
146
|
+
const pushAnswer = async (send) => {
|
|
147
|
+
if (!(await stillAdmitted("push"))) {
|
|
148
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
send();
|
|
152
|
+
};
|
|
128
153
|
const replaySessionRow = async (row, face) => {
|
|
129
154
|
if (Object.keys(row).length === 0)
|
|
130
155
|
return true;
|
|
@@ -170,9 +195,28 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
170
195
|
}
|
|
171
196
|
};
|
|
172
197
|
const canReplayHistory = fileHistoryImportFace(historyStore) !== undefined;
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
198
|
+
const landAttendants = async (attendants, landed, plan) => {
|
|
199
|
+
if (plan.wipe && !(await attendants.wipe(sessionId, landed)).landed)
|
|
200
|
+
return { kind: "gone", leg: "wipe" };
|
|
201
|
+
if (plan.fileHistory !== null && canReplayHistory) {
|
|
202
|
+
const h = await attendants.replayHistory(sessionId, landed, plan.fileHistory, blobGetterOf(historyStore), { allowReplace: plan.allowReplace });
|
|
203
|
+
if (!h.landed)
|
|
204
|
+
return { kind: "gone", leg: "file_history" };
|
|
205
|
+
if (!h.value.ok)
|
|
206
|
+
return { kind: "history_failed", failure: h.value };
|
|
207
|
+
}
|
|
208
|
+
if (plan.policy.length > 0 && !(await attendants.replayPolicy(sessionId, landed, plan.policy, plan.operator)).landed)
|
|
209
|
+
return { kind: "gone", leg: "policy" };
|
|
210
|
+
if (plan.anchors.length > 0 && !(await attendants.putAnchors(sessionId, landed, plan.anchors, plan.owner)).landed)
|
|
211
|
+
return { kind: "gone", leg: "anchors" };
|
|
212
|
+
if (!(await replaySessionRow(plan.row, landed)))
|
|
213
|
+
return { kind: "gone", leg: "row" };
|
|
214
|
+
return { kind: "landed" };
|
|
215
|
+
};
|
|
216
|
+
const sendLandedOccupantGone = (arm, leg, landed) => {
|
|
217
|
+
deps.logger?.warn?.("session_sync_landed_occupant_gone", { sessionId, arm, leg, landed: incarnationLogPrefix(landed.incarnation) });
|
|
218
|
+
deps.metrics?.inc("session_sync_landed_occupant_gone_total", { arm, leg }, 1);
|
|
219
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
176
220
|
};
|
|
177
221
|
if (match.decl.id === "session-sync-manifest") {
|
|
178
222
|
if (!pullGateOk())
|
|
@@ -190,7 +234,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
190
234
|
sendSessionAbsent("missing");
|
|
191
235
|
return;
|
|
192
236
|
}
|
|
193
|
-
sendJson(res, 200, { manifest: out.manifest });
|
|
237
|
+
await pullAnswer(() => sendJson(res, 200, { manifest: out.manifest }));
|
|
194
238
|
return;
|
|
195
239
|
}
|
|
196
240
|
if (match.decl.id === "session-sync-entries") {
|
|
@@ -206,9 +250,11 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
206
250
|
}
|
|
207
251
|
afterSeq = n;
|
|
208
252
|
}
|
|
253
|
+
const recheck = async () => { if (!(await stillAdmitted("pull")))
|
|
254
|
+
throw new SessionOccupantChangedError(sessionId); };
|
|
209
255
|
let it;
|
|
210
256
|
try {
|
|
211
|
-
it = await sessionStorage.exportEntriesStream(sessionId, afterSeq === undefined ?
|
|
257
|
+
it = await sessionStorage.exportEntriesStream(sessionId, { ...(afterSeq === undefined ? {} : { afterSeq }), recheck });
|
|
212
258
|
}
|
|
213
259
|
catch (e) {
|
|
214
260
|
if (sendPullUnreadable(req, res, deps.logger, e))
|
|
@@ -219,6 +265,19 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
219
265
|
sendSessionAbsent("missing");
|
|
220
266
|
return;
|
|
221
267
|
}
|
|
268
|
+
let openSame;
|
|
269
|
+
try {
|
|
270
|
+
openSame = await stillAdmitted("pull");
|
|
271
|
+
}
|
|
272
|
+
catch (e) {
|
|
273
|
+
if (sendPullUnreadable(req, res, deps.logger, e))
|
|
274
|
+
return;
|
|
275
|
+
throw e;
|
|
276
|
+
}
|
|
277
|
+
if (!openSame) {
|
|
278
|
+
sendSessionAbsent("missing");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
222
281
|
res.writeHead(200, { "content-type": "application/x-ndjson", "transfer-encoding": "chunked" });
|
|
223
282
|
const write = async (line) => { if (!res.write(line))
|
|
224
283
|
await once(res, "drain"); };
|
|
@@ -233,7 +292,10 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
233
292
|
res.end();
|
|
234
293
|
}
|
|
235
294
|
catch (e) {
|
|
236
|
-
|
|
295
|
+
if (e instanceof SessionOccupantChangedError)
|
|
296
|
+
deps.logger?.info?.("session_sync_pull_occupant_changed", { sessionId, count });
|
|
297
|
+
else
|
|
298
|
+
deps.logger?.error?.("sync entries stream failed", { sessionId, count, error: msg(e) });
|
|
237
299
|
res.end();
|
|
238
300
|
}
|
|
239
301
|
return;
|
|
@@ -268,7 +330,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
268
330
|
}
|
|
269
331
|
const referenced = envelope !== null && envelope.tracked.some((t) => t.versions.some((v) => v.blobHash === hash));
|
|
270
332
|
if (!referenced) {
|
|
271
|
-
sendError(res, 404, "not_found.blob", "blob not found");
|
|
333
|
+
await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
|
|
272
334
|
return;
|
|
273
335
|
}
|
|
274
336
|
let bytes;
|
|
@@ -280,12 +342,15 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
280
342
|
return;
|
|
281
343
|
throw e;
|
|
282
344
|
}
|
|
283
|
-
|
|
284
|
-
|
|
345
|
+
const found = bytes;
|
|
346
|
+
if (!found) {
|
|
347
|
+
await pullAnswer(() => sendError(res, 404, "not_found.blob", "blob not found"));
|
|
285
348
|
return;
|
|
286
349
|
}
|
|
287
|
-
|
|
288
|
-
|
|
350
|
+
await pullAnswer(() => {
|
|
351
|
+
res.writeHead(200, { "content-type": "application/octet-stream" });
|
|
352
|
+
res.end(Buffer.from(found));
|
|
353
|
+
});
|
|
289
354
|
return;
|
|
290
355
|
}
|
|
291
356
|
if (match.decl.id === "session-sync-blob-put") {
|
|
@@ -390,10 +455,14 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
390
455
|
const entryIds = body.entryIds;
|
|
391
456
|
const policy = policyRead.records;
|
|
392
457
|
const anchors = anchorsRead.anchors;
|
|
393
|
-
const dstIds = (await sessionStorage.listEntryIds?.(sessionId)) ?? null;
|
|
458
|
+
const dstIds = gate.occupant === undefined ? null : ((await sessionStorage.listEntryIds?.(sessionId)) ?? null);
|
|
394
459
|
const relA = classifySyncRelationshipByIds(entryIds, dstIds);
|
|
395
460
|
const refusalA = await firstPhaseRefusal(sessionStorage, sessionId, relA.relation, resolution === "overwrite-dst");
|
|
396
461
|
if (refusalA !== undefined) {
|
|
462
|
+
if (!(await stillAdmitted("push"))) {
|
|
463
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
397
466
|
if (refusalA.kind === "stamped") {
|
|
398
467
|
if (sendSessionError(res, refusalA.error, "import"))
|
|
399
468
|
return;
|
|
@@ -409,7 +478,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
409
478
|
if (v.blobHash !== null)
|
|
410
479
|
distinct.add(v.blobHash);
|
|
411
480
|
if (await firstMissingBlob(facts.sessionSyncFileHistory(deps), [...distinct]) !== undefined) {
|
|
412
|
-
sendMissingBlob(res);
|
|
481
|
+
await pushAnswer(() => sendMissingBlob(res));
|
|
413
482
|
return;
|
|
414
483
|
}
|
|
415
484
|
}
|
|
@@ -436,10 +505,10 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
436
505
|
case "mirror":
|
|
437
506
|
break;
|
|
438
507
|
case "writer":
|
|
439
|
-
sendSessionWriter(res);
|
|
508
|
+
await pushAnswer(() => sendSessionWriter(res));
|
|
440
509
|
return;
|
|
441
510
|
case "forking":
|
|
442
|
-
sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message);
|
|
511
|
+
await pushAnswer(() => sendError(res, 409, "conflict.fork_in_progress", new SessionForkInProgressError(sessionId).message));
|
|
443
512
|
return;
|
|
444
513
|
default: {
|
|
445
514
|
const unknownRole = placed.cell;
|
|
@@ -447,12 +516,13 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
447
516
|
}
|
|
448
517
|
}
|
|
449
518
|
}
|
|
450
|
-
const activeNow = await activityOf(gateFace);
|
|
519
|
+
const activeNow = gate.occupant === undefined ? undefined : await activityOf(gateFace);
|
|
451
520
|
if (activeNow !== undefined) {
|
|
452
|
-
sendActivity(activeNow, "open");
|
|
521
|
+
await pushAnswer(() => sendActivity(activeNow, "open"));
|
|
453
522
|
return;
|
|
454
523
|
}
|
|
455
524
|
if (relA.relation === "identical" && !digestSaysDiffer) {
|
|
525
|
+
const attendantsA = backend.landedAttendants();
|
|
456
526
|
const seat = sessionStorage.executionPlacement;
|
|
457
527
|
if (seat !== undefined) {
|
|
458
528
|
if (gateFace === undefined) {
|
|
@@ -478,35 +548,38 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
478
548
|
}
|
|
479
549
|
}
|
|
480
550
|
}
|
|
481
|
-
if (
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
551
|
+
if (gateFace === undefined) {
|
|
552
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
let landedA;
|
|
556
|
+
try {
|
|
557
|
+
landedA = await landAttendants(attendantsA, gateFace, { wipe: false, fileHistory, allowReplace: resolution === "overwrite-dst", policy, operator: operatorOk, anchors, owner: importingPrincipal, row });
|
|
558
|
+
}
|
|
559
|
+
catch (e) {
|
|
560
|
+
if (sendSessionPolicyError(res, e))
|
|
485
561
|
return;
|
|
486
|
-
|
|
562
|
+
throw e;
|
|
487
563
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
564
|
+
switch (landedA.kind) {
|
|
565
|
+
case "landed":
|
|
566
|
+
break;
|
|
567
|
+
case "gone":
|
|
568
|
+
sendLandedOccupantGone("identical", landedA.leg, gateFace);
|
|
569
|
+
return;
|
|
570
|
+
case "history_failed":
|
|
571
|
+
sendFileHistoryReplayFailure(res, landedA.failure);
|
|
572
|
+
return;
|
|
573
|
+
default: {
|
|
574
|
+
const unhandled = landedA;
|
|
575
|
+
throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
|
|
496
576
|
}
|
|
497
577
|
}
|
|
498
|
-
|
|
499
|
-
for (const a of anchors)
|
|
500
|
-
await deps.resumeAnchorStore.put(sessionId, a.eventId, a.entryId, importingPrincipal);
|
|
501
|
-
if (!(await replaySessionRow(row, gateFace))) {
|
|
502
|
-
sendError(res, 409, "conflict", "sync conflict");
|
|
503
|
-
return;
|
|
504
|
-
}
|
|
505
|
-
sendJson(res, 200, {
|
|
578
|
+
await pushAnswer(() => sendJson(res, 200, {
|
|
506
579
|
relation: "identical",
|
|
507
580
|
basis: payloadVerified ? "entry-ids+digest" : "entry-ids",
|
|
508
581
|
payloadVerified,
|
|
509
|
-
});
|
|
582
|
+
}));
|
|
510
583
|
return;
|
|
511
584
|
}
|
|
512
585
|
const leaseKey = importLeaseKey(gate.occupant !== undefined ? gate.occupant.owner : importingPrincipal, sessionId);
|
|
@@ -518,8 +591,12 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
518
591
|
const heldLease = importLeases.get(leaseKey);
|
|
519
592
|
if (heldLease) {
|
|
520
593
|
const retryAfterSec = staleMs > 0 ? Math.max(1, Math.ceil((staleMs - (Date.now() - heldLease.at)) / 1000)) : undefined;
|
|
521
|
-
sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
|
|
522
|
-
+ (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined);
|
|
594
|
+
await pushAnswer(() => sendError(res, 409, "import_in_flight", "an import is already in flight for this session"
|
|
595
|
+
+ (retryAfterSec !== undefined ? ` (a stalled holder is taken over after ${staleSec}s of inactivity; retry in ~${retryAfterSec}s)` : ""), retryAfterSec !== undefined ? { retryAfterSec } : undefined));
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (!(await stillAdmitted("push"))) {
|
|
599
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
523
600
|
return;
|
|
524
601
|
}
|
|
525
602
|
const token = newStagingToken();
|
|
@@ -528,7 +605,7 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
528
605
|
importLeases.set(leaseKey, { at: Date.now(), stagingId, sessionId });
|
|
529
606
|
pendingStagings.set(stagingId, {
|
|
530
607
|
handle, realSessionId: sessionId, owner: importingPrincipal, ...(resolution ? { resolution } : {}), operatorOk,
|
|
531
|
-
fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner),
|
|
608
|
+
fileHistory, policy, anchors, row, declaredEntryIds: entryIds, openedBy: ownerKeyOf(scope.gateOwner), expectedOccupant: gateFace, leaseKey,
|
|
532
609
|
});
|
|
533
610
|
sendJson(res, 200, { stagingId, relation: relA.relation });
|
|
534
611
|
return;
|
|
@@ -614,19 +691,22 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
614
691
|
return;
|
|
615
692
|
throw e;
|
|
616
693
|
}
|
|
617
|
-
let
|
|
694
|
+
let gateAtCommit;
|
|
618
695
|
let activeAtCommit;
|
|
696
|
+
let activeStillAdmitted = true;
|
|
619
697
|
try {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
activeAtCommit =
|
|
698
|
+
gateAtCommit = await judgeSessionGate();
|
|
699
|
+
const atCommit = gateAtCommit.occupant;
|
|
700
|
+
activeAtCommit = gateAtCommit.mayPush && atCommit !== undefined ? await activityOf(gateAtCommit.face) : undefined;
|
|
701
|
+
if (activeAtCommit !== undefined && atCommit !== undefined)
|
|
702
|
+
activeStillAdmitted = await recheckSyncGate(sessionStorage, sessionId, atCommit, "push");
|
|
623
703
|
}
|
|
624
704
|
catch (e) {
|
|
625
705
|
await pending.handle.abort().catch(() => undefined);
|
|
626
706
|
cleanupStaging(stagingId);
|
|
627
707
|
throw e;
|
|
628
708
|
}
|
|
629
|
-
if (!
|
|
709
|
+
if (!gateAtCommit.mayPush) {
|
|
630
710
|
await pending.handle.abort().catch(() => undefined);
|
|
631
711
|
cleanupStaging(stagingId);
|
|
632
712
|
sendSessionAbsent("not_visible");
|
|
@@ -635,37 +715,43 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
635
715
|
if (activeAtCommit !== undefined) {
|
|
636
716
|
await pending.handle.abort().catch(() => undefined);
|
|
637
717
|
cleanupStaging(stagingId);
|
|
718
|
+
if (!activeStillAdmitted) {
|
|
719
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
638
722
|
sendActivity(activeAtCommit, "streamed");
|
|
639
723
|
return;
|
|
640
724
|
}
|
|
641
725
|
try {
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
await wipeSessionAttendants({ fileHistoryStore: historyStore, sessionPolicyStore: deps.sessionPolicyStore, resumeAnchorStore: deps.resumeAnchorStore }, sessionId);
|
|
645
|
-
}
|
|
646
|
-
if (pending.fileHistory !== null && canReplayHistory) {
|
|
647
|
-
const failed = await replayHistory(pending.fileHistory, pending.resolution === "overwrite-dst");
|
|
648
|
-
if (failed !== undefined) {
|
|
649
|
-
sendFileHistoryReplayFailure(res, failed);
|
|
650
|
-
cleanupStaging(stagingId);
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
const policyStore = deps.sessionPolicyStore;
|
|
655
|
-
if (policyStore)
|
|
656
|
-
await replayPolicyRecords(policyStore, sessionId, pending.policy, pending.operatorOk);
|
|
657
|
-
const anchorStore = deps.resumeAnchorStore;
|
|
658
|
-
if (anchorStore)
|
|
659
|
-
for (const a of pending.anchors)
|
|
660
|
-
await anchorStore.put(sessionId, a.eventId, a.entryId, pending.owner);
|
|
661
|
-
const rowLanded = await replaySessionRow(pending.row, committed.face);
|
|
726
|
+
const attendantsB = backend.landedAttendants();
|
|
727
|
+
const committed = await pending.handle.commit(pending.owner, { expectedOccupant: pending.expectedOccupant, ...(pending.resolution ? { resolution: pending.resolution } : {}) });
|
|
662
728
|
sessionStorage.evict?.(sessionId);
|
|
729
|
+
const landedB = await landAttendants(attendantsB, committed.face, {
|
|
730
|
+
wipe: pending.resolution === "overwrite-dst" && (committed.relation === "fork" || committed.relation === "stale"),
|
|
731
|
+
fileHistory: pending.fileHistory,
|
|
732
|
+
allowReplace: pending.resolution === "overwrite-dst",
|
|
733
|
+
policy: pending.policy,
|
|
734
|
+
operator: pending.operatorOk,
|
|
735
|
+
anchors: pending.anchors,
|
|
736
|
+
owner: pending.owner,
|
|
737
|
+
row: pending.row,
|
|
738
|
+
});
|
|
663
739
|
cleanupStaging(stagingId);
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
740
|
+
switch (landedB.kind) {
|
|
741
|
+
case "landed":
|
|
742
|
+
sendJson(res, 200, { relation: committed.relation });
|
|
743
|
+
return;
|
|
744
|
+
case "gone":
|
|
745
|
+
sendLandedOccupantGone("commit", landedB.leg, committed.face);
|
|
746
|
+
return;
|
|
747
|
+
case "history_failed":
|
|
748
|
+
sendFileHistoryReplayFailure(res, landedB.failure);
|
|
749
|
+
return;
|
|
750
|
+
default: {
|
|
751
|
+
const unhandled = landedB;
|
|
752
|
+
throw new Error(`session sync: unknown landing answer ${JSON.stringify(unhandled)}`);
|
|
753
|
+
}
|
|
667
754
|
}
|
|
668
|
-
sendJson(res, 200, { relation: committed.relation });
|
|
669
755
|
}
|
|
670
756
|
catch (e) {
|
|
671
757
|
await pending.handle.abort().catch(() => undefined);
|
|
@@ -704,9 +790,17 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
704
790
|
sendError(res, 400, "request.field_invalid", "entryIds must be an array of strings");
|
|
705
791
|
return;
|
|
706
792
|
}
|
|
707
|
-
const dst = await sessionStorage.exportEntries(sessionId);
|
|
793
|
+
const dst = gate.occupant === undefined ? null : await sessionStorage.exportEntries(sessionId);
|
|
708
794
|
const relation = classifySyncRelationshipByIds(body.entryIds, dst ? dst.map((e) => e.id) : null);
|
|
795
|
+
if (gate.occupant === undefined) {
|
|
796
|
+
sendJson(res, 200, relation);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
709
799
|
const refusal = await firstPhaseRefusal(sessionStorage, sessionId, relation.relation, false);
|
|
800
|
+
if (!(await stillAdmitted("push"))) {
|
|
801
|
+
sendError(res, 409, "conflict", "sync conflict");
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
710
804
|
if (refusal?.kind === "stamped") {
|
|
711
805
|
if (sendSessionError(res, refusal.error, "import"))
|
|
712
806
|
return;
|
|
@@ -795,9 +889,6 @@ function sendSessionSyncUnavailable(res, why) {
|
|
|
795
889
|
case "session_import_staging_absent":
|
|
796
890
|
sendError(res, 501, "capability.session_store_required", "staged session import requires a durable session store");
|
|
797
891
|
return;
|
|
798
|
-
case "file_history_store_absent":
|
|
799
|
-
sendError(res, 501, "capability.snapshot_store_required", "session sync is not available on this deployment: no file-history store is wired, so there is no file history to export or import");
|
|
800
|
-
return;
|
|
801
892
|
case "policy_purge_absent":
|
|
802
893
|
sendError(res, 501, "capability.policy_purge_required", "session sync is not available on this deployment: the session-policy store has no deleteBySession purge verb, so an overwrite-dst import could not wipe the destination's stale policy rows. Every in-tree policy store carries it since core 1.423 — upgrade the policy store");
|
|
803
894
|
return;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { isUuidV7 } from "../../security.js";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
3
|
import { sendUnauthorized } from "../principal-gate.js";
|
|
4
|
-
import { routeListFilter } from "../owner-access.js";
|
|
4
|
+
import { listOwnerOf, listVisibleSessions, routeListFilter } from "../owner-access.js";
|
|
5
5
|
import { filterFingerprint } from "../cursor-fingerprint.js";
|
|
6
|
+
import { SESSION_KINDS, isSessionKind } from "../../session-kind.js";
|
|
6
7
|
import { sessionTempoOfRunStatus } from "../../plugins/store-contracts.js";
|
|
7
8
|
import { assertNever } from "../route-ctx.js";
|
|
8
9
|
import { PRINCIPAL_MAX_BYTES } from "../../principal-shape.js";
|
|
@@ -21,8 +22,7 @@ export async function handleSessionsList(req, res, match, ctx) {
|
|
|
21
22
|
sendError(res, 501, "capability.session_store_required", "session list requires a durable session store (DB_BACKEND=mysql|pg|local)");
|
|
22
23
|
return;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
await handleSessionList(res, lister, new URLSearchParams(match.search), gateOwner, includeUnowned);
|
|
25
|
+
await handleSessionList(res, listing.lister, new URLSearchParams(match.search), { fleetWide, gateOwner, includeUnowned });
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
28
|
case "sendfile-links": {
|
|
@@ -109,18 +109,24 @@ function decodeSessionCursor(s, expectF) {
|
|
|
109
109
|
return undefined;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
async function handleSessionList(res, lister, query,
|
|
113
|
-
const
|
|
112
|
+
async function handleSessionList(res, lister, query, filter) {
|
|
113
|
+
const kindRaw = query.get("sessionKind");
|
|
114
|
+
if (kindRaw !== null && !isSessionKind(kindRaw)) {
|
|
115
|
+
sendError(res, 400, "request.query_invalid", `sessionKind must be one of ${SESSION_KINDS.map((w) => JSON.stringify(w)).join(" | ")} when present (absent = the default view: top-level sessions only)`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const sessionKind = kindRaw ?? undefined;
|
|
119
|
+
const owner = listOwnerOf(filter, query.get("owner") ?? undefined);
|
|
114
120
|
const limit = Math.min(100, Math.max(1, Number(query.get("limit") ?? 50) || 50));
|
|
115
121
|
const qRaw = (query.get("q") ?? "").trim();
|
|
116
122
|
const q = qRaw ? qRaw.slice(0, 256) : undefined;
|
|
117
|
-
const f = filterFingerprint([owner, includeUnowned, q]);
|
|
123
|
+
const f = filterFingerprint(sessionKind === undefined ? [owner, filter.includeUnowned, q] : [owner, filter.includeUnowned, q, sessionKind]);
|
|
118
124
|
const cursor = decodeSessionCursor(query.get("cursor"), f);
|
|
119
125
|
if (cursor === "mismatch") {
|
|
120
126
|
sendError(res, 400, "request.cursor_filter_mismatch", "cursor was issued under a different filter (owner/q) — restart from the first page without a cursor");
|
|
121
127
|
return;
|
|
122
128
|
}
|
|
123
|
-
const rows = await lister
|
|
129
|
+
const rows = await listVisibleSessions(lister, filter, query.get("owner") ?? undefined, { ...(cursor ? { cursor } : {}), limit: limit + 1, ...(q ? { q } : {}), ...(sessionKind !== undefined ? { sessionKind } : {}) });
|
|
124
130
|
const hasMore = rows.length > limit;
|
|
125
131
|
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
126
132
|
const last = page[page.length - 1];
|
|
@@ -26,7 +26,7 @@ export interface SessionsLocal {
|
|
|
26
26
|
degraded?: boolean;
|
|
27
27
|
}>;
|
|
28
28
|
}>;
|
|
29
|
-
/**
|
|
29
|
+
/** [ref] 件4:`/a2a` 面板的短 TTL single-flight 缓存。与 `mcpStatusCache` **分开一张表**而不是
|
|
30
30
|
* 共用带前缀的键:两张面板的体不同形(`peers` vs `servers`),塞进一张表就得靠 unknown 兜住两形,
|
|
31
31
|
* 于是「取到的是哪一形」变成运行期约定 —— 两张表让它回到类型上。 */
|
|
32
32
|
a2aStatusCache: Map<string, {
|