@sema-agent/server 7.150.0 → 7.152.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 +451 -0
- package/README.md +15 -3
- package/README.zh-CN.md +10 -2
- package/USAGE.md +144 -87
- package/deploy/sema-up/README.md +11 -4
- 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 +7 -6
- package/deploy/sema-up/kube-up.sh +6 -6
- package/deploy/sema-up/lib/flagshape.sh +36 -8
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/deploy/sema-up/machines.example.yaml +3 -1
- package/deploy/sema-up/sema-up.sh +22 -16
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-audit-store.d.ts +1 -1
- package/dist/approval-ask-machine.d.ts +4 -10
- package/dist/approval-ask-retention.d.ts +1 -1
- package/dist/approval-card.d.ts +12 -14
- package/dist/approval-gate-currency.d.ts +9 -9
- package/dist/approval-gate-currency.js +3 -4
- package/dist/approval-hmac.d.ts +17 -1
- package/dist/approval-hmac.js +7 -1
- package/dist/approval-queue-kind.d.ts +1 -1
- package/dist/approval.d.ts +2 -2
- package/dist/approval.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 +1 -1
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +3 -6
- package/dist/bind-host.js +4 -7
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/coordinators.d.ts +1 -1
- package/dist/boot/coordinators.js +9 -10
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +9 -14
- package/dist/boot/execution-env.js +85 -22
- 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/leader.d.ts +31 -30
- package/dist/boot/leader.js +38 -28
- package/dist/boot/leg-path-adjudication.d.ts +40 -0
- package/dist/boot/leg-path-adjudication.js +18 -0
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.js +3 -15
- package/dist/boot/reapers.d.ts +6 -1
- package/dist/boot/reapers.js +13 -2
- package/dist/boot/resolve-spec.d.ts +3 -3
- package/dist/boot/resolve-spec.js +43 -48
- package/dist/boot/runner-deps.d.ts +46 -35
- package/dist/boot/runner-deps.js +94 -91
- 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 +9 -5
- package/dist/boot/shutdown.d.ts +6 -0
- package/dist/boot/shutdown.js +10 -4
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-02-web-admin-pull.js +4 -5
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +3 -2
- package/dist/boot/stage-06-runners.d.ts +9 -4
- package/dist/boot/stage-06-runners.js +24 -9
- package/dist/boot/stage-07-capability-layer.d.ts +8 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +8 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +12 -5
- package/dist/boot/stage-09-leader.js +14 -5
- package/dist/boot/stage-10-http-server.d.ts +19 -5
- package/dist/boot/stage-10-http-server.js +14 -21
- package/dist/boot/stores.js +7 -4
- package/dist/boot/web-admin.js +5 -8
- 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/capabilities/approvals-push.d.ts +3 -3
- package/dist/capabilities/scenarios.d.ts +28 -13
- package/dist/capabilities/scenarios.js +2 -2
- package/dist/capability-facts.d.ts +43 -32
- package/dist/capability-facts.js +45 -51
- package/dist/card-rule-offers.d.ts +32 -0
- package/dist/card-rule-offers.js +130 -0
- 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 +26 -22
- package/dist/config-dir-trust.js +4 -2
- package/dist/config-invariants.d.ts +20 -8
- package/dist/config-invariants.js +55 -12
- package/dist/config-lkg.d.ts +5 -19
- package/dist/config-lkg.js +8 -62
- package/dist/config-provider.d.ts +1 -1
- package/dist/config-root-migration.d.ts +2 -2
- package/dist/config-types.d.ts +38 -42
- package/dist/config.d.ts +58 -7
- package/dist/config.js +90 -40
- package/dist/control-socket.d.ts +51 -0
- package/dist/control-socket.js +115 -0
- package/dist/deployment-governance.d.ts +2 -1
- 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 +7 -0
- package/dist/device-ws-hub.js +10 -3
- package/dist/device-ws-protocol.d.ts +63 -10
- package/dist/device-ws-protocol.js +56 -25
- package/dist/elicitation.js +2 -2
- package/dist/engine-identity.d.ts +19 -7
- package/dist/engine-identity.js +10 -2
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/entry-problems.d.ts +40 -3
- package/dist/entry-problems.js +3 -1
- package/dist/execution-env-refusal.d.ts +29 -0
- package/dist/execution-env-refusal.js +8 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +1 -1
- 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 +12 -29
- package/dist/fleet/engine-signal.js +1 -7
- package/dist/fleet-client.js +2 -5
- package/dist/gate-settlement.d.ts +1 -8
- package/dist/gate-settlement.js +0 -4
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +2 -3
- package/dist/hitl-delivery.js +0 -2
- package/dist/hooks/hook-llm.js +4 -2
- package/dist/hooks/hook-runner.d.ts +3 -2
- package/dist/hooks/hook-runner.js +18 -3
- package/dist/host-decision.d.ts +11 -11
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +35 -2
- package/dist/http/active-run-conflict.js +48 -19
- package/dist/http/admission.js +17 -2
- package/dist/http/approval-sweeps.d.ts +1 -1
- package/dist/http/approval-sweeps.js +10 -7
- package/dist/http/checkpoint-ctx.d.ts +4 -0
- package/dist/http/checkpoint-ctx.js +2 -0
- package/dist/http/dispatch.d.ts +8 -3
- package/dist/http/dispatch.js +59 -32
- package/dist/http/durable-run-leg.js +16 -17
- package/dist/http/health-reader.d.ts +16 -9
- package/dist/http/health-reader.js +2 -1
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +3 -1
- package/dist/http/owner-access.d.ts +33 -14
- package/dist/http/owner-access.js +40 -10
- package/dist/http/principal-gate.d.ts +49 -21
- package/dist/http/principal-gate.js +61 -11
- package/dist/http/request-channel.d.ts +23 -0
- package/dist/http/request-channel.js +9 -0
- package/dist/http/request-guards.js +17 -2
- package/dist/http/resume-ctx-read.js +42 -3
- package/dist/http/resume-legs.d.ts +4 -3
- package/dist/http/resume-legs.js +367 -117
- package/dist/http/route-ctx.d.ts +91 -15
- package/dist/http/route-ctx.js +17 -0
- package/dist/http/route-table.d.ts +5 -1
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/admin-config-refresh.js +3 -3
- package/dist/http/routes/admin-drain.d.ts +3 -0
- package/dist/http/routes/admin-drain.js +7 -7
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/admin-memory-optout.js +3 -3
- package/dist/http/routes/adoption.js +3 -5
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +2 -1
- package/dist/http/routes/approvals-assistant.js +99 -51
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.d.ts +4 -0
- package/dist/http/routes/capabilities.js +38 -10
- package/dist/http/routes/config-catalog.js +2 -2
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +19 -7
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/images.js +10 -10
- package/dist/http/routes/memory-bundle.js +3 -3
- package/dist/http/routes/memory-compliance.js +3 -3
- package/dist/http/routes/memory-consolidation.js +2 -2
- package/dist/http/routes/memory-origin.js +3 -3
- package/dist/http/routes/memory-policy.js +2 -2
- package/dist/http/routes/observability.js +3 -3
- package/dist/http/routes/projects.d.ts +3 -2
- package/dist/http/routes/projects.js +4 -5
- package/dist/http/routes/retention-ops.js +3 -3
- package/dist/http/routes/rules.js +5 -5
- package/dist/http/routes/run-permission-mode.d.ts +2 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +4 -9
- package/dist/http/routes/runs.js +171 -65
- package/dist/http/routes/session-sync.d.ts +22 -9
- package/dist/http/routes/session-sync.js +204 -107
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.js +30 -15
- package/dist/http/routes/tasks.js +46 -41
- package/dist/http/routes/trace-usage.js +2 -2
- package/dist/http/routes/workflows.js +1 -1
- package/dist/http/server.d.ts +30 -30
- package/dist/http/server.js +16 -4
- package/dist/http/submit-ctx.d.ts +1 -1
- package/dist/http/submit-ctx.js +7 -4
- package/dist/http/wire-types.d.ts +14 -4
- package/dist/human-facing-args.d.ts +33 -0
- package/dist/human-facing-args.js +33 -0
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +5 -1
- package/dist/k8s-api-credentials.d.ts +29 -0
- package/dist/k8s-api-credentials.js +25 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +2 -2
- package/dist/leader/diffup.d.ts +19 -0
- package/dist/leader/diffup.js +7 -0
- package/dist/leader/leader.d.ts +116 -11
- package/dist/leader/leader.js +69 -5
- package/dist/leader/repair-wire.js +2 -2
- package/dist/leader/run-entry.d.ts +2 -1
- package/dist/leader/run-entry.js +1 -1
- package/dist/leader/wire.d.ts +42 -132
- package/dist/leader/wire.js +81 -67
- package/dist/leg-facts.d.ts +13 -5
- package/dist/leg-facts.js +2 -1
- package/dist/memory-scope.d.ts +23 -11
- package/dist/memory-scope.js +18 -6
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/model-entry-headers.d.ts +9 -10
- package/dist/model-entry-headers.js +0 -4
- package/dist/model-entry-refusal.d.ts +7 -4
- package/dist/model-entry-refusal.js +11 -5
- package/dist/model-plane-face.d.ts +1 -1
- package/dist/model-plane-face.js +3 -1
- package/dist/model-route-endpoint.d.ts +13 -7
- package/dist/model-route-endpoint.js +14 -11
- package/dist/model-select.d.ts +22 -0
- package/dist/model-select.js +9 -0
- package/dist/model-unreachable-notice.d.ts +11 -0
- package/dist/model-unreachable-notice.js +4 -4
- package/dist/object-store-buckets.d.ts +640 -6
- package/dist/object-store-buckets.js +166 -0
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +25 -17
- package/dist/observability/fail-open.js +25 -17
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/operator-roster.d.ts +68 -0
- package/dist/operator-roster.js +32 -0
- 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/outbound-dispatcher.d.ts +71 -8
- package/dist/outbound-dispatcher.js +48 -7
- package/dist/owner-faces.d.ts +2 -2
- package/dist/parked-decide.d.ts +106 -55
- 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/permission-mode-admission.d.ts +74 -5
- package/dist/permission-mode-admission.js +56 -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 +14 -2
- package/dist/plugins/approval-ask-store-file.js +11 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +10 -1
- package/dist/plugins/approval-ask-store-memory.js +35 -10
- package/dist/plugins/approval-ask-store-sql.d.ts +69 -4
- package/dist/plugins/approval-ask-store-sql.js +45 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/blob-backend.d.ts +83 -7
- package/dist/plugins/blob-backend.js +57 -6
- 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/checkpoint-index-columns.d.ts +20 -16
- package/dist/plugins/checkpoint-index-columns.js +3 -6
- package/dist/plugins/checkpoint-store-face.d.ts +119 -61
- package/dist/plugins/checkpoint-store-face.js +134 -55
- 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/execution-placement-sql.js +6 -6
- 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 +13 -3
- package/dist/plugins/local-checkpoint-store.js +38 -49
- 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-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +104 -80
- package/dist/plugins/one-time-migrations.js +226 -132
- 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 +35 -10
- 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 +4 -1
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +41 -15
- 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 +106 -8
- package/dist/plugins/remote-env-e2b.d.ts +15 -6
- package/dist/plugins/remote-env-e2b.js +42 -32
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +46 -10
- package/dist/plugins/remote-env-host.js +124 -52
- package/dist/plugins/remote-env-k8s.d.ts +109 -41
- package/dist/plugins/remote-env-k8s.js +160 -54
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +34 -41
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +60 -59
- package/dist/plugins/remote-shell.d.ts +98 -1
- package/dist/plugins/remote-shell.js +218 -0
- package/dist/plugins/replica-registration.d.ts +1 -1
- package/dist/plugins/replica-registration.js +1 -1
- 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.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 +21 -2
- package/dist/plugins/run-store-sql.js +31 -7
- package/dist/plugins/s3-presign.d.ts +23 -0
- package/dist/plugins/s3-presign.js +37 -3
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +1 -1
- package/dist/plugins/scenario-prefix-switch-m42.js +2 -2
- package/dist/plugins/scheduler-support.d.ts +2 -2
- package/dist/plugins/scheduler-support.js +0 -3
- package/dist/plugins/schema-consistency.d.ts +4 -2
- package/dist/plugins/schema-consistency.js +19 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-file-ledger.d.ts +2 -2
- package/dist/plugins/send-file-ledger.js +5 -2
- package/dist/plugins/send-user-file.d.ts +3 -4
- package/dist/plugins/send-user-file.js +56 -52
- package/dist/plugins/serving-requirement.d.ts +26 -7
- package/dist/plugins/serving-requirement.js +11 -4
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-blob-claim-token.d.ts +15 -0
- package/dist/plugins/session-blob-claim-token.js +20 -0
- package/dist/plugins/session-blob-namespace.d.ts +46 -0
- package/dist/plugins/session-blob-namespace.js +116 -0
- 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/snapshot-bucket-presence.d.ts +25 -2
- package/dist/plugins/snapshot-bucket-presence.js +8 -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/sql-json-column.d.ts +1 -1
- package/dist/plugins/stop-then-start-sentence.d.ts +10 -4
- package/dist/plugins/stop-then-start-sentence.js +14 -10
- 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 +84 -15
- package/dist/plugins/store-backend.js +236 -72
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +17 -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.d.ts +2 -1
- package/dist/plugins/task-attachment-store.js +14 -1
- 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 +21 -25
- 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-custody.d.ts +4 -3
- 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/project-context.d.ts +0 -2
- package/dist/project-context.js +4 -8
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +2 -1
- package/dist/question.js +5 -13
- package/dist/request-form.d.ts +6 -1
- package/dist/request-form.js +4 -1
- 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/rule-issue-reading.d.ts +1 -1
- package/dist/rules-consent.d.ts +1 -1
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-local.js +9 -9
- package/dist/runs.d.ts +54 -16
- package/dist/runs.js +67 -13
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +30 -32
- package/dist/security.js +41 -7
- package/dist/sema-config-dir.d.ts +2 -1
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- 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 +10 -0
- package/dist/session-incarnation.js +10 -1
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +25 -103
- package/dist/session-sync.js +14 -76
- 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/blob-index-sql.d.ts +30 -9
- package/dist/stores-sql/blob-index-sql.js +40 -21
- package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
- package/dist/stores-sql/checkpoint-store-sql.js +70 -146
- package/dist/stores-sql/file-history-store-sql.d.ts +113 -15
- package/dist/stores-sql/file-history-store-sql.js +205 -95
- 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 +1 -9
- package/dist/stores-sql/retention-store-sql.js +5 -19
- 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 +2 -2
- package/dist/task-settings.d.ts +7 -5
- package/dist/task-settings.js +3 -3
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +465 -507
- package/dist/tool-approval.js +606 -1222
- package/dist/trace/core-keyset-guard.d.ts +1 -1
- package/dist/trace/ledger-events.d.ts +3 -3
- package/dist/trace/project.d.ts +2 -3
- package/dist/trace/redact.js +3 -2
- package/dist/trace/self-minted-wire.d.ts +571 -178
- package/dist/trace/self-minted-wire.js +189 -56
- package/dist/web-admin-client/apply-effective.js +2 -2
- package/dist/web-admin-client/read-warnings.d.ts +2 -2
- package/dist/web-admin-client/read-warnings.js +1 -1
- package/dist/web-admin-client/types.d.ts +1 -1
- package/dist/workspace-space.d.ts +10 -4
- package/dist/workspace-space.js +4 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +79 -28
- package/package.json +7 -3
- package/scripts/embed-minimal.mjs +3 -3
- package/wire-changes/server@7.151.0.json +762 -0
- package/wire-changes/server@7.152.0.json +900 -0
- package/dist/config-d-migration.d.ts +0 -37
- package/dist/config-d-migration.js +0 -60
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { captureFileBackupViaEnv, applyFileRestoreViaEnv, fileHistoryModeProvenDifferent, worldStillMatchesMint, annulProofFailure, boundaryPublishVerdict, fileHistoryDescribeTrackKey, fileHistoryTrackKeyOf, fileHistoryResolveTrackKey, fileHistoryExportDigest, validateFileHistoryExport, resolveFileHistoryRetention, fileHistoryBoundariesToKeep, } from "@sema-agent/core";
|
|
3
|
-
import { BlobTooLargeError, SqlBlobIndex } from "./blob-index-sql.js";
|
|
3
|
+
import { BlobTooLargeError, SqlBlobIndex, blobGcCutoffAt, hashBatches } from "./blob-index-sql.js";
|
|
4
4
|
import { mysqlDriver, pgDriver } from "../plugins/sql-driver.js";
|
|
5
|
-
import { isMissingColumnError, retryOnDeadlock } from "../plugins/sql-errors.js";
|
|
5
|
+
import { isMissingColumnError, retryOnDeadlock, SqlArbitrationLostError } from "../plugins/sql-errors.js";
|
|
6
6
|
import { probedMissingColumnRefusal } from "../plugins/schema-drift-sentence.js";
|
|
7
7
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
8
8
|
import { foldCaughtFailure } from "../file-history-disclosure.js";
|
|
9
9
|
export const FILE_HISTORY_BLOB_TABLE = "file_history_blob";
|
|
10
|
-
export const
|
|
10
|
+
export const FILE_HISTORY_BLOB_GRANT_TABLE = "file_history_blob_grant";
|
|
11
|
+
export const FILE_HISTORY_SCOPED_TABLES = [
|
|
12
|
+
"file_history_boundary_file",
|
|
13
|
+
"file_history_boundary",
|
|
14
|
+
"file_history_reaped_entry",
|
|
15
|
+
"file_history_version",
|
|
16
|
+
"file_history_tracked",
|
|
17
|
+
FILE_HISTORY_BLOB_GRANT_TABLE,
|
|
18
|
+
"file_history_scope",
|
|
19
|
+
];
|
|
11
20
|
const sha256hex = (s) => createHash("sha256").update(s).digest("hex");
|
|
12
21
|
const truthy = (v) => v === true || v === 1 || v === "1";
|
|
13
22
|
class StagedRefGoneError extends Error {
|
|
14
23
|
}
|
|
15
|
-
class ScopeSentinelVanishedError extends
|
|
24
|
+
class ScopeSentinelVanishedError extends SqlArbitrationLostError {
|
|
16
25
|
}
|
|
17
26
|
function reapedEntryRefusal(entryId) {
|
|
18
27
|
return {
|
|
@@ -23,14 +32,89 @@ function reapedEntryRefusal(entryId) {
|
|
|
23
32
|
},
|
|
24
33
|
};
|
|
25
34
|
}
|
|
35
|
+
export class SqlBlobExchange {
|
|
36
|
+
blobs;
|
|
37
|
+
constructor(blobs) {
|
|
38
|
+
this.blobs = blobs;
|
|
39
|
+
}
|
|
40
|
+
async put(hash, bytes) {
|
|
41
|
+
if (sha256hex(bytes) !== hash) {
|
|
42
|
+
return { ok: false, error: { code: "adopt_failed", message: `blob ${hash}: the bytes do not hash to this address — nothing stored`, permanence: "terminal" } };
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
await this.blobs.put(hash, bytes);
|
|
46
|
+
return { ok: true };
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (err instanceof BlobTooLargeError)
|
|
50
|
+
return { ok: false, error: { code: "adopt_failed", message: err.message, permanence: "terminal", blobCap: { wallSource: err.cap.source } } };
|
|
51
|
+
const f = foldCaughtFailure(err, "sql-blob-exchange.put");
|
|
52
|
+
return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} write/upload failed: ${f.text}`, ...f.fault } };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
get(hash) {
|
|
56
|
+
return this.blobs.get(hash);
|
|
57
|
+
}
|
|
58
|
+
has(hashes) {
|
|
59
|
+
return this.blobs.has([...hashes]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export class SqlBlobLanding {
|
|
63
|
+
db;
|
|
64
|
+
exchange;
|
|
65
|
+
constructor(db, exchange) {
|
|
66
|
+
this.db = db;
|
|
67
|
+
this.exchange = exchange;
|
|
68
|
+
}
|
|
69
|
+
q(mysql, pg) {
|
|
70
|
+
return this.db.dialect === "mysql" ? mysql : pg;
|
|
71
|
+
}
|
|
72
|
+
static ownerKey(landing) {
|
|
73
|
+
return landing.owner ?? "";
|
|
74
|
+
}
|
|
75
|
+
async putAt(landing, hash, bytes) {
|
|
76
|
+
const stored = await this.exchange.put(hash, bytes);
|
|
77
|
+
if (!stored.ok)
|
|
78
|
+
return stored;
|
|
79
|
+
try {
|
|
80
|
+
await this.db.query(this.q(`INSERT INTO ${FILE_HISTORY_BLOB_GRANT_TABLE} (scope, landing_owner, blob_hash, granted_at) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE granted_at = GREATEST(granted_at, VALUES(granted_at))`, `INSERT INTO ${FILE_HISTORY_BLOB_GRANT_TABLE} (scope, landing_owner, blob_hash, granted_at) VALUES ($1,$2,$3,$4) ON CONFLICT (scope, landing_owner, blob_hash) DO UPDATE SET granted_at = GREATEST(${FILE_HISTORY_BLOB_GRANT_TABLE}.granted_at, EXCLUDED.granted_at)`), [landing.sessionId, SqlBlobLanding.ownerKey(landing), hash, new Date()]);
|
|
81
|
+
return { ok: true };
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const f = foldCaughtFailure(err, "sql-blob-landing.putAt");
|
|
85
|
+
return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} was stored but its upload grant could not be recorded: ${f.text}`, ...f.fault } };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async visibleAt(landing, hashes) {
|
|
89
|
+
const wanted = new Set(hashes);
|
|
90
|
+
if (wanted.size === 0)
|
|
91
|
+
return new Set();
|
|
92
|
+
const candidates = new Set();
|
|
93
|
+
if (landing.occupied) {
|
|
94
|
+
const graph = await this.db.query(this.q("SELECT DISTINCT blob_hash FROM file_history_version WHERE scope = ? AND blob_hash IS NOT NULL", "SELECT DISTINCT blob_hash FROM file_history_version WHERE scope = $1 AND blob_hash IS NOT NULL"), [landing.sessionId]);
|
|
95
|
+
for (const r of graph.rows) {
|
|
96
|
+
const h = String(r.blob_hash);
|
|
97
|
+
if (wanted.has(h))
|
|
98
|
+
candidates.add(h);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const ungranted = [...wanted].filter((h) => !candidates.has(h));
|
|
102
|
+
for (const batch of hashBatches(ungranted)) {
|
|
103
|
+
const ph = batch.map((_, i) => (this.db.dialect === "mysql" ? "?" : `$${i + 3}`)).join(",");
|
|
104
|
+
const granted = await this.db.query(this.q(`SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE scope = ? AND landing_owner = ? AND blob_hash IN (${ph})`, `SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE scope = $1 AND landing_owner = $2 AND blob_hash IN (${ph})`), [landing.sessionId, SqlBlobLanding.ownerKey(landing), ...batch]);
|
|
105
|
+
for (const r of granted.rows)
|
|
106
|
+
candidates.add(String(r.blob_hash));
|
|
107
|
+
}
|
|
108
|
+
if (candidates.size === 0)
|
|
109
|
+
return new Set();
|
|
110
|
+
return this.exchange.has([...candidates]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
26
113
|
export class SqlFileHistoryStore {
|
|
27
114
|
db;
|
|
28
115
|
pool;
|
|
29
|
-
blobExchange
|
|
30
|
-
|
|
31
|
-
get: (hash) => this.blobs.get(hash),
|
|
32
|
-
has: (hashes) => this.blobs.has([...hashes]),
|
|
33
|
-
};
|
|
116
|
+
blobExchange;
|
|
117
|
+
blobLanding;
|
|
34
118
|
blobs;
|
|
35
119
|
spentAttempts = new Set();
|
|
36
120
|
activeAttempts = new Set();
|
|
@@ -44,6 +128,8 @@ export class SqlFileHistoryStore {
|
|
|
44
128
|
...(opts?.blobSqlMaxBytes !== undefined ? { maxBytes: opts.blobSqlMaxBytes } : {}),
|
|
45
129
|
...(opts?.log !== undefined ? { log: opts.log } : {}),
|
|
46
130
|
});
|
|
131
|
+
this.blobExchange = new SqlBlobExchange(this.blobs);
|
|
132
|
+
this.blobLanding = new SqlBlobLanding(this.db, this.blobExchange);
|
|
47
133
|
this.boundaryKeep = resolveFileHistoryRetention(this.db.dialect === "mysql" ? "TiDBFileHistoryStore" : "PgFileHistoryStore", opts?.retention);
|
|
48
134
|
}
|
|
49
135
|
q(mysql, pg) {
|
|
@@ -67,14 +153,17 @@ export class SqlFileHistoryStore {
|
|
|
67
153
|
await conn.begin();
|
|
68
154
|
}
|
|
69
155
|
restart = true;
|
|
70
|
-
|
|
71
|
-
await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
|
|
72
|
-
const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
73
|
-
if (!r.rows[0])
|
|
74
|
-
throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
|
|
75
|
-
}
|
|
156
|
+
await this.lockScopeOn(conn, ordered);
|
|
76
157
|
}, (err) => err instanceof ScopeSentinelVanishedError);
|
|
77
158
|
}
|
|
159
|
+
async lockScopeOn(conn, scopes) {
|
|
160
|
+
for (const scope of [...new Set(scopes)].sort()) {
|
|
161
|
+
await conn.query(this.q("INSERT INTO file_history_scope (scope, created_at_ms) VALUES (?,?) ON DUPLICATE KEY UPDATE scope = scope", "INSERT INTO file_history_scope (scope, created_at_ms) VALUES ($1,$2) ON CONFLICT (scope) DO NOTHING"), [scope, Date.now()]);
|
|
162
|
+
const r = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
163
|
+
if (!r.rows[0])
|
|
164
|
+
throw new ScopeSentinelVanishedError(`could not acquire the scope write lock for "${scope}" (sentinel row kept vanishing)`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
78
167
|
async markObserved(scope, keyHash) {
|
|
79
168
|
const r = await this.db.query(this.q("UPDATE file_history_tracked SET observed_later = 1 WHERE scope = ? AND key_hash = ? AND observed_later = 0", "UPDATE file_history_tracked SET observed_later = TRUE WHERE scope = $1 AND key_hash = $2 AND observed_later = FALSE"), [scope, keyHash]);
|
|
80
169
|
return r.affected;
|
|
@@ -134,7 +223,7 @@ export class SqlFileHistoryStore {
|
|
|
134
223
|
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} kept racing a concurrent retraction — retry` } };
|
|
135
224
|
}
|
|
136
225
|
catch (err) {
|
|
137
|
-
const f = foldCaughtFailure(err);
|
|
226
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.trackEdit");
|
|
138
227
|
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${f.text}`, ...f.fault } };
|
|
139
228
|
}
|
|
140
229
|
}
|
|
@@ -201,7 +290,7 @@ export class SqlFileHistoryStore {
|
|
|
201
290
|
return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} was replaced while this retraction was being proven` } };
|
|
202
291
|
}
|
|
203
292
|
catch (err) {
|
|
204
|
-
const f = foldCaughtFailure(err);
|
|
293
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.annulTrack");
|
|
205
294
|
return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${f.text}`, ...f.fault } };
|
|
206
295
|
}
|
|
207
296
|
}
|
|
@@ -309,7 +398,7 @@ export class SqlFileHistoryStore {
|
|
|
309
398
|
}
|
|
310
399
|
}
|
|
311
400
|
catch (err) {
|
|
312
|
-
const f = foldCaughtFailure(err);
|
|
401
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
313
402
|
return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
|
|
314
403
|
}
|
|
315
404
|
this.activeAttempts.add(lease);
|
|
@@ -412,7 +501,7 @@ export class SqlFileHistoryStore {
|
|
|
412
501
|
catch (err) {
|
|
413
502
|
await conn.rollback().catch(() => undefined);
|
|
414
503
|
this.spentAttempts.add(lease);
|
|
415
|
-
const f = foldCaughtFailure(err);
|
|
504
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
416
505
|
return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${f.text}`, ...f.fault } };
|
|
417
506
|
}
|
|
418
507
|
finally {
|
|
@@ -423,7 +512,7 @@ export class SqlFileHistoryStore {
|
|
|
423
512
|
}
|
|
424
513
|
catch (err) {
|
|
425
514
|
this.spentAttempts.add(lease);
|
|
426
|
-
const f = foldCaughtFailure(err);
|
|
515
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.snapshot");
|
|
427
516
|
return { ok: false, error: { code: "snapshot_failed", message: f.text, ...f.fault } };
|
|
428
517
|
}
|
|
429
518
|
finally {
|
|
@@ -491,7 +580,7 @@ export class SqlFileHistoryStore {
|
|
|
491
580
|
});
|
|
492
581
|
}
|
|
493
582
|
catch (err) {
|
|
494
|
-
applied = { outcome: "failed", reason: foldCaughtFailure(err).text };
|
|
583
|
+
applied = { outcome: "failed", reason: foldCaughtFailure(err, "sql-file-history-store.restore").text };
|
|
495
584
|
}
|
|
496
585
|
if (applied.outcome === "applied")
|
|
497
586
|
ledger.filesChanged.push(t.trackKey);
|
|
@@ -508,7 +597,7 @@ export class SqlFileHistoryStore {
|
|
|
508
597
|
}
|
|
509
598
|
catch (err) {
|
|
510
599
|
const touched = empty.filesChanged.length > 0 || empty.identicalSkipped.length > 0 || empty.refused.length > 0 || empty.failed.length > 0;
|
|
511
|
-
const f = foldCaughtFailure(err);
|
|
600
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.restore");
|
|
512
601
|
return { outcome: touched ? "partial" : "failed", ...empty, error: { code: "restore_failed", message: f.text, ...f.fault } };
|
|
513
602
|
}
|
|
514
603
|
}
|
|
@@ -578,11 +667,7 @@ export class SqlFileHistoryStore {
|
|
|
578
667
|
try {
|
|
579
668
|
await conn.begin();
|
|
580
669
|
await this.lockScope(conn, scope);
|
|
581
|
-
|
|
582
|
-
for (const table of ["file_history_boundary_file", "file_history_boundary", "file_history_reaped_entry", "file_history_version", "file_history_tracked", "file_history_scope"]) {
|
|
583
|
-
const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
|
|
584
|
-
total += r.affected;
|
|
585
|
-
}
|
|
670
|
+
const total = await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
|
|
586
671
|
await conn.commit();
|
|
587
672
|
return total;
|
|
588
673
|
}
|
|
@@ -594,27 +679,25 @@ export class SqlFileHistoryStore {
|
|
|
594
679
|
conn.release();
|
|
595
680
|
}
|
|
596
681
|
}
|
|
597
|
-
async
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
if (orphans.length === 0)
|
|
601
|
-
return 0;
|
|
602
|
-
return this.blobs.sweep(orphans);
|
|
682
|
+
async deleteScopeOn(conn, scope) {
|
|
683
|
+
await this.lockScopeOn(conn, [scope]);
|
|
684
|
+
return this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES);
|
|
603
685
|
}
|
|
604
|
-
async
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
await this.blobs.put(hash, bytes);
|
|
610
|
-
return { ok: true };
|
|
611
|
-
}
|
|
612
|
-
catch (err) {
|
|
613
|
-
if (err instanceof BlobTooLargeError)
|
|
614
|
-
return { ok: false, error: { code: "adopt_failed", message: err.message, permanence: "terminal", blobCap: { wallSource: err.cap.source } } };
|
|
615
|
-
const f = foldCaughtFailure(err);
|
|
616
|
-
return { ok: false, error: { code: "snapshot_failed", message: `blob ${hash} write/upload failed: ${f.text}`, ...f.fault } };
|
|
686
|
+
async deleteScopeRowsOn(conn, scope, tables) {
|
|
687
|
+
let total = 0;
|
|
688
|
+
for (const table of tables) {
|
|
689
|
+
const r = await conn.query(this.q(`DELETE FROM ${table} WHERE scope = ?`, `DELETE FROM ${table} WHERE scope = $1`), [scope]);
|
|
690
|
+
total += r.affected;
|
|
617
691
|
}
|
|
692
|
+
return total;
|
|
693
|
+
}
|
|
694
|
+
async sweepOrphanBlobs() {
|
|
695
|
+
const cutoff = blobGcCutoffAt(Date.now());
|
|
696
|
+
return this.blobs.sweep(async () => {
|
|
697
|
+
await this.db.query(this.q(`DELETE FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE granted_at < ?`, `DELETE FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE granted_at < $1`), [cutoff]);
|
|
698
|
+
const { rows } = await this.db.query(`SELECT blob_hash FROM ${FILE_HISTORY_BLOB_TABLE} WHERE blob_hash NOT IN (SELECT blob_hash FROM file_history_version WHERE blob_hash IS NOT NULL) AND blob_hash NOT IN (SELECT blob_hash FROM ${FILE_HISTORY_BLOB_GRANT_TABLE})`);
|
|
699
|
+
return rows.map((r) => String(r.blob_hash));
|
|
700
|
+
}, cutoff);
|
|
618
701
|
}
|
|
619
702
|
async adoptScope(fromScope, toScope) {
|
|
620
703
|
try {
|
|
@@ -650,7 +733,7 @@ export class SqlFileHistoryStore {
|
|
|
650
733
|
}
|
|
651
734
|
}
|
|
652
735
|
catch (err) {
|
|
653
|
-
const f = foldCaughtFailure(err);
|
|
736
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.adoptScope");
|
|
654
737
|
return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${f.text}`, ...f.fault } };
|
|
655
738
|
}
|
|
656
739
|
}
|
|
@@ -707,10 +790,10 @@ export class SqlFileHistoryStore {
|
|
|
707
790
|
const conn = await this.db.connect();
|
|
708
791
|
try {
|
|
709
792
|
await conn.begin();
|
|
710
|
-
await this.
|
|
711
|
-
const
|
|
793
|
+
const held = await conn.query(this.q("SELECT scope FROM file_history_scope WHERE scope = ? FOR UPDATE", "SELECT scope FROM file_history_scope WHERE scope = $1 FOR UPDATE"), [scope]);
|
|
794
|
+
const history = held.rows[0] === undefined ? null : await this.exportOf(conn, scope, true);
|
|
712
795
|
await conn.commit();
|
|
713
|
-
return { ok: true, history
|
|
796
|
+
return { ok: true, history };
|
|
714
797
|
}
|
|
715
798
|
catch (err) {
|
|
716
799
|
await conn.rollback().catch(() => undefined);
|
|
@@ -732,7 +815,7 @@ export class SqlFileHistoryStore {
|
|
|
732
815
|
bytes = await srcGetBlob(hash);
|
|
733
816
|
}
|
|
734
817
|
catch (err) {
|
|
735
|
-
const f = foldCaughtFailure(err);
|
|
818
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.verifySourceBlobs");
|
|
736
819
|
return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${f.text}`, ...f.fault } };
|
|
737
820
|
}
|
|
738
821
|
if (bytes === undefined)
|
|
@@ -745,6 +828,40 @@ export class SqlFileHistoryStore {
|
|
|
745
828
|
return { ok: true };
|
|
746
829
|
}
|
|
747
830
|
async importHistory(scope, data, srcGetBlob) {
|
|
831
|
+
const plan = await this.prepareImport(scope, data, srcGetBlob, { replace: false });
|
|
832
|
+
if (!plan.ok)
|
|
833
|
+
return plan;
|
|
834
|
+
if (plan.mode === "same")
|
|
835
|
+
return { ok: true };
|
|
836
|
+
try {
|
|
837
|
+
const conn = await this.db.connect();
|
|
838
|
+
try {
|
|
839
|
+
await conn.begin();
|
|
840
|
+
await this.lockScope(conn, scope);
|
|
841
|
+
const out = await this.publishImportLockedOn(conn, scope, data, { replace: false });
|
|
842
|
+
if (out.ok)
|
|
843
|
+
await conn.commit();
|
|
844
|
+
else
|
|
845
|
+
await conn.rollback();
|
|
846
|
+
return out;
|
|
847
|
+
}
|
|
848
|
+
catch (err) {
|
|
849
|
+
await conn.rollback().catch(() => undefined);
|
|
850
|
+
throw err;
|
|
851
|
+
}
|
|
852
|
+
finally {
|
|
853
|
+
conn.release();
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
catch (err) {
|
|
857
|
+
return { ok: false, error: this.importFailureOf(err) };
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
importFailureOf(err) {
|
|
861
|
+
const f = foldCaughtFailure(err, "sql-file-history-store.importHistory");
|
|
862
|
+
return { code: "adopt_failed", message: `importHistory failed: ${f.text}`, ...f.fault };
|
|
863
|
+
}
|
|
864
|
+
async prepareImport(scope, data, srcGetBlob, opts) {
|
|
748
865
|
try {
|
|
749
866
|
const shaped = validateFileHistoryExport(data);
|
|
750
867
|
if (!shaped.ok)
|
|
@@ -762,59 +879,51 @@ export class SqlFileHistoryStore {
|
|
|
762
879
|
return exported;
|
|
763
880
|
const existing = exported.history;
|
|
764
881
|
const sameGraph = existing !== null && fileHistoryExportDigest(existing) === fileHistoryExportDigest(data);
|
|
765
|
-
if (existing !== null && !sameGraph) {
|
|
882
|
+
if (existing !== null && !sameGraph && !opts.replace) {
|
|
766
883
|
return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" already holds a DIFFERENT history — a first import requires an empty target and a retry is legal only for the identical envelope (atomic visibility prevents half-graphs; this law prevents publishing the wrong complete graph over locally-grown history)` } };
|
|
767
884
|
}
|
|
768
885
|
const verified = await this.verifySourceBlobs(data, srcGetBlob, sameGraph ? undefined : (hash, bytes) => this.blobs.put(hash, bytes));
|
|
769
886
|
if (!verified.ok)
|
|
770
887
|
return verified;
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
for (const t of data.tracked) {
|
|
788
|
-
const keyHash = sha256hex(t.relOrAbsPath);
|
|
789
|
-
await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
|
|
790
|
-
for (const v of t.versions) {
|
|
791
|
-
await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
|
|
795
|
-
let publishSeq = Number(seqBase.rows[0].s);
|
|
796
|
-
for (const b of data.boundaries) {
|
|
797
|
-
publishSeq += 1;
|
|
798
|
-
await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
|
|
799
|
-
for (const f of b.files) {
|
|
800
|
-
await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
await conn.commit();
|
|
888
|
+
return { ok: true, mode: sameGraph ? "same" : "publish" };
|
|
889
|
+
}
|
|
890
|
+
catch (err) {
|
|
891
|
+
return { ok: false, error: this.importFailureOf(err) };
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
async publishImportOn(conn, scope, data, plan, opts) {
|
|
895
|
+
if (plan.mode === "same")
|
|
896
|
+
return { ok: true };
|
|
897
|
+
await this.lockScopeOn(conn, [scope]);
|
|
898
|
+
return this.publishImportLockedOn(conn, scope, data, opts);
|
|
899
|
+
}
|
|
900
|
+
async publishImportLockedOn(conn, scope, data, opts) {
|
|
901
|
+
if (!(await this.scopeEmpty(conn, scope, true))) {
|
|
902
|
+
const held = await this.exportOf(conn, scope, true);
|
|
903
|
+
if (held !== null && fileHistoryExportDigest(held) === fileHistoryExportDigest(data))
|
|
804
904
|
return { ok: true };
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
905
|
+
if (!opts.replace)
|
|
906
|
+
return { ok: false, error: { code: "conflict", message: `importHistory target "${scope}" gained a DIFFERENT history while this import was fetching blobs — nothing was published` } };
|
|
907
|
+
await this.deleteScopeRowsOn(conn, scope, FILE_HISTORY_SCOPED_TABLES.filter((t) => t !== "file_history_scope"));
|
|
908
|
+
}
|
|
909
|
+
const now = Date.now();
|
|
910
|
+
for (const t of data.tracked) {
|
|
911
|
+
const keyHash = sha256hex(t.relOrAbsPath);
|
|
912
|
+
await conn.query(this.q("INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES (?,?,?,?,?,?,0,?)", "INSERT INTO file_history_tracked (scope, key_hash, track_key, key_kind, key_family, base_available, observed_later, created_at_ms) VALUES ($1,$2,$3,$4,$5,$6,FALSE,$7)"), [scope, keyHash, t.relOrAbsPath, t.keyKind, t.keyFamily, this.bool(t.baseAvailable), now]);
|
|
913
|
+
for (const v of t.versions) {
|
|
914
|
+
await conn.query(this.q("INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES (?,?,?,?,?,?,?)", "INSERT INTO file_history_version (scope, key_hash, version, blob_hash, mode, parent_ident, backup_time) VALUES ($1,$2,$3,$4,$5,$6,$7)"), [scope, keyHash, v.version, v.blobHash, v.mode ?? null, v.parentIdent ?? null, v.backupTime]);
|
|
812
915
|
}
|
|
813
916
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
917
|
+
const seqBase = await conn.query(this.q("SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = ?", "SELECT COALESCE(MAX(publish_seq), 0) AS s FROM file_history_boundary WHERE scope = $1"), [scope]);
|
|
918
|
+
let publishSeq = Number(seqBase.rows[0].s);
|
|
919
|
+
for (const b of data.boundaries) {
|
|
920
|
+
publishSeq += 1;
|
|
921
|
+
await conn.query(this.q("INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary (scope, entry_id, published_at_ms, publish_seq) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, now, publishSeq]);
|
|
922
|
+
for (const f of b.files) {
|
|
923
|
+
await conn.query(this.q("INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES (?,?,?,?)", "INSERT INTO file_history_boundary_file (scope, entry_id, key_hash, version) VALUES ($1,$2,$3,$4)"), [scope, b.entryId, sha256hex(f.relOrAbsPath), f.version]);
|
|
924
|
+
}
|
|
817
925
|
}
|
|
926
|
+
return { ok: true };
|
|
818
927
|
}
|
|
819
928
|
}
|
|
820
929
|
export class TiDBFileHistoryStore extends SqlFileHistoryStore {
|
|
@@ -836,6 +945,7 @@ export async function assertFileHistorySchema(query, dialect) {
|
|
|
836
945
|
["file_history_scope", "SELECT scope, created_at_ms FROM file_history_scope WHERE 1=0"],
|
|
837
946
|
["file_history_reaped_entry", "SELECT scope, entry_id, reaped_at_ms FROM file_history_reaped_entry WHERE 1=0"],
|
|
838
947
|
[FILE_HISTORY_BLOB_TABLE, `SELECT blob_hash, byte_len, bytes, created_at FROM ${FILE_HISTORY_BLOB_TABLE} WHERE 1=0`],
|
|
948
|
+
[FILE_HISTORY_BLOB_GRANT_TABLE, `SELECT scope, landing_owner, blob_hash, granted_at FROM ${FILE_HISTORY_BLOB_GRANT_TABLE} WHERE 1=0`],
|
|
839
949
|
];
|
|
840
950
|
for (const [table, sql] of probes) {
|
|
841
951
|
try {
|
|
@@ -2,9 +2,9 @@ import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type Ses
|
|
|
2
2
|
import type { Pool, PoolClient } from "pg";
|
|
3
3
|
import { WindowedSessionStorage } from "./windowed-session-storage.js";
|
|
4
4
|
import { type PlacementAcquireOpts } from "../plugins/session-placement.js";
|
|
5
|
-
import { type StagingHandle } from "../session-sync-kernel.js";
|
|
5
|
+
import { type EntriesStreamOptions, type StagedCommitOptions, type StagingHandle, type SyncRelation } from "../session-sync-kernel.js";
|
|
6
6
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
7
|
-
import { type RegisterReceipt, type WithdrawOutcome } from "../session-incarnation.js";
|
|
7
|
+
import { type RegisterReceipt, type SessionFace, type WithdrawOutcome } from "../session-incarnation.js";
|
|
8
8
|
import type { SessionWriteHooks } from "./session-write-hooks.js";
|
|
9
9
|
import { type IndexSpec } from "../plugins/ensure-index.js";
|
|
10
10
|
import { type SessionDeleteCondition } from "./tidb-session-store.js";
|
|
@@ -78,7 +78,7 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
78
78
|
/** Idempotently create a session_meta row with an owner (core `SessionStore.register`). Existing owner is never overwritten. */
|
|
79
79
|
register(sessionId: string, owner: string | null): Promise<void>;
|
|
80
80
|
/** 出生回执面(TiDB 孪生 {@link TiDBSessionStore.registerWithReceipt} 同义:候选 = 这一次 INSERT 入参里铸的化身)。 */
|
|
81
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
81
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: string): Promise<RegisterReceipt>;
|
|
82
82
|
/** 条件删除(TiDB 孪生 {@link TiDBSessionStore.deleteSessionIf} 同义)。 */
|
|
83
83
|
deleteSessionIf(sessionId: string, cond: SessionDeleteCondition): Promise<WithdrawOutcome>;
|
|
84
84
|
/** acquire 的建行(唯一一处;placed 会话的属主 = `placement.owner` 原样,core 7.62.0 [ref] 盒义务 7 —— TiDB 孪生同名方法同注)。 */
|
|
@@ -86,6 +86,8 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
86
86
|
/** The one session_meta INSERT. Existing owner is never overwritten.
|
|
87
87
|
* [ref]:`placement` 与行同一条 INSERT;`DO NOTHING` 臂 ⇒ 已存在行的元组永不被重写(first-write 不可变)。 */
|
|
88
88
|
private insertMeta;
|
|
89
|
+
/** {@link insertMeta} 那一句,发在给定的连接上(带种类的登记在自己的事务连接上发)。 */
|
|
90
|
+
private insertMetaOn;
|
|
89
91
|
/** [ref] 义务 6 的廉价探针(TiDB 孪生 {@link TiDBSessionStore.placementOf} 同义)。 */
|
|
90
92
|
placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
|
|
91
93
|
/** [ref] 义务 5 —— placed 分区枚举(年龄锚/上界/tupleIncomplete 三条读法与 TiDB 孪生逐字同义,
|
|
@@ -128,10 +130,7 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
128
130
|
* held connection across the stream → a slow consumer can't pin one). Start cursor = afterSeq ?? -1 (0-based dense).
|
|
129
131
|
* Resolves to null (NOT an empty iterable) for a missing session — eager `session_meta` probe (BIGINT seq comes
|
|
130
132
|
* back as a STRING in node-pg → always Number(...) the cursor advance). */
|
|
131
|
-
exportEntriesStream(sessionId: string, opts
|
|
132
|
-
afterSeq?: number;
|
|
133
|
-
batchSize?: number;
|
|
134
|
-
}): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
133
|
+
exportEntriesStream(sessionId: string, opts: EntriesStreamOptions): Promise<AsyncIterable<SessionTreeEntry> | null>;
|
|
135
134
|
/** @see TiDBSessionStore.importEntries — 2c session-sync IMPORT: core `validateEntriesForImport` gate FIRST (fail-closed),
|
|
136
135
|
* then persist its verbatim output (re-seq dense from 0, ids/parents/payload/ts unchanged) in ONE txn, **lock-or-create, meta first**
|
|
137
136
|
* (占行 → 锁行判是不是本次占下的 → 部署的事务内钩 `import` → 事件);owner = the RE-STAMPED authenticated principal (never the bundle's). */
|
|
@@ -160,4 +159,32 @@ export declare class PgSessionStore implements SessionStore {
|
|
|
160
159
|
get size(): number;
|
|
161
160
|
dispose(): void;
|
|
162
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* 2c session-sync P1d-β — the PG twin of {@link TiDBStagingHandle} (behaviourally identical; only the SQL dialect
|
|
164
|
+
* differs: `$n` placeholders, `$n::jsonb`, `ON CONFLICT (session_id, entry_id) DO NOTHING`, rowCount, FOR UPDATE,
|
|
165
|
+
* BEGIN/COMMIT handle). Streams entry batches into a shadow session_event partition, then atomically RENAMEs them
|
|
166
|
+
* onto the real session id in ONE txn; session_meta is locked (or claimed, for a fresh push) first and settled last, COMMIT = the commit point.
|
|
167
|
+
*/
|
|
168
|
+
/** 暂存句柄(会话同步的推送腿逐批写、提交、撤销;由本店的 `stageImport` 交出)。导出只为组合座给它封口(店边界)。 */
|
|
169
|
+
export declare class PgStagingHandle implements StagingHandle {
|
|
170
|
+
private readonly pool;
|
|
171
|
+
private readonly hooks;
|
|
172
|
+
readonly realSessionId: string;
|
|
173
|
+
readonly stagingId: string;
|
|
174
|
+
private nextSeq;
|
|
175
|
+
private readonly seen;
|
|
176
|
+
constructor(pool: Pool, hooks: SessionWriteHooks, realSessionId: string, stagingId: string);
|
|
177
|
+
/** @see TiDBStagingHandle.appendBatch — DENSE re-seq (skip already-staged ids), idempotent ON CONFLICT (session_id,
|
|
178
|
+
* entry_id) DO NOTHING, one txn/batch. */
|
|
179
|
+
appendBatch(entries: SessionTreeEntry[]): Promise<void>;
|
|
180
|
+
/** @see TiDBStagingHandle.commit — the atomic swap: owner CAS first (lock / claim the session_meta row) → in-commit re-classify (FOR UPDATE)
|
|
181
|
+
* → purge dst → rename staging→real → settle session_meta. Throws StagedCommitOccupantChangedError when the owner cell is not the judged one,
|
|
182
|
+
* SyncConflictError on an unconsented fork/stale flip. */
|
|
183
|
+
commit(owner: string | null, opts: StagedCommitOptions): Promise<{
|
|
184
|
+
relation: SyncRelation["relation"];
|
|
185
|
+
face: SessionFace;
|
|
186
|
+
}>;
|
|
187
|
+
/** @see TiDBStagingHandle.abort — DELETE the staging rows. Idempotent. */
|
|
188
|
+
abort(): Promise<void>;
|
|
189
|
+
}
|
|
163
190
|
//# sourceMappingURL=pg-session-storage.d.ts.map
|