@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
|
@@ -22,7 +22,10 @@ const PRODUCT_COLUMNS = [
|
|
|
22
22
|
export const CLIENT_WRITES_COLUMN = { name: "client_writes", mysql: "client_writes BIGINT NOT NULL DEFAULT 0", pg: "client_writes BIGINT NOT NULL DEFAULT 0" };
|
|
23
23
|
export const BUMP_CLIENT_WRITES = "client_writes = client_writes + 1";
|
|
24
24
|
export const DELETING_TOKEN_COLUMN = { name: "deleting_token", mysql: "deleting_token VARCHAR(36) NULL", pg: `deleting_token VARCHAR(36) COLLATE "C"` };
|
|
25
|
-
export const
|
|
25
|
+
export const SESSION_KIND_COLUMN = { name: "session_kind", mysql: "session_kind VARCHAR(32) NULL", pg: `session_kind VARCHAR(32) COLLATE "C"` };
|
|
26
|
+
export const SESSION_EXT_COLUMNS = [...PRODUCT_COLUMNS, ...EXECUTION_PLACEMENT_COLUMNS, CLIENT_WRITES_COLUMN, DELETING_TOKEN_COLUMN, SESSION_KIND_COLUMN];
|
|
27
|
+
export const SESSION_EXT_KIND_INDEX = "idx_session_ext_kind";
|
|
28
|
+
export const SESSION_EXT_INDEXES = [{ table: SESSION_EXT_TABLE, name: SESSION_EXT_KIND_INDEX, columns: [SESSION_KIND_COLUMN.name] }];
|
|
26
29
|
export const SESSION_EXT_MOVED_COLUMNS = [...PRODUCT_COLUMNS, ...EXECUTION_PLACEMENT_COLUMNS];
|
|
27
30
|
export const SESSION_EXT_FOREIGN_KEY = "fk_session_ext_session";
|
|
28
31
|
export const SESSION_META_KEY_COLLATION_PROBE = "SELECT CHARACTER_SET_NAME AS cs, COLLATION_NAME AS coll FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'session_meta' AND COLUMN_NAME = 'session_id'";
|
|
@@ -43,6 +46,7 @@ export function sessionExtDdl(dialect, referenced) {
|
|
|
43
46
|
` ${key},\n` +
|
|
44
47
|
SESSION_EXT_COLUMNS.map((c) => ` ${c[dialect]},\n`).join("") +
|
|
45
48
|
" PRIMARY KEY (session_id),\n" +
|
|
49
|
+
(dialect === "mysql" ? SESSION_EXT_INDEXES.map((i) => ` KEY ${i.name} (${i.columns.join(", ")}),\n`).join("") : "") +
|
|
46
50
|
` CONSTRAINT ${SESSION_EXT_FOREIGN_KEY} FOREIGN KEY (session_id) REFERENCES session_meta (session_id) ON DELETE CASCADE\n` +
|
|
47
51
|
(dialect === "pg" ? " )" : " ) COLLATE utf8mb4_bin"));
|
|
48
52
|
}
|
|
@@ -23,9 +23,56 @@
|
|
|
23
23
|
* 之后这一行连同标题换了主 —— 是行的历史,不是越权写。
|
|
24
24
|
* 应答不在事务内读(理由见上),所以③这一窗在;不取「事务内应答」。
|
|
25
25
|
* 全局锁序:根 `session_meta` 一行 → 它的旁表行(→ 读日志 mark 时它的末条事件),不碰 `task_*`(与旁表的每个写者同序:根行先)。
|
|
26
|
+
*
|
|
27
|
+
* ## 「锁根行读住客」只有一句({@link lockSessionRootOn})
|
|
28
|
+
* 部署侧(本目录之外的 `src/stores-sql/**` 不在射程)每一个先锁根 `session_meta` 行再判 / 写的写事务都经它:行格写原语与落定段({@link lockSessionRowOn})、
|
|
29
|
+
* 执行席的写序律 ①(`execution-placement-sql.ts`)、旁表格写(`session-store-sql.ts` 的 `withLockedSessionExt`)。选择列是它们要的并集(属主 · 化身 · 委派判别位 · 叶序 · 最后活动 —— 最后一格是删除围栏的老化重判读的),
|
|
30
|
+
* 各读者按自己的读法解码同一行。
|
|
31
|
+
*
|
|
32
|
+
* ## 落定段({@link withLandedRow};律在 `landed-attendants.ts` 头注)
|
|
33
|
+
* 一只事务:{@link lockSessionRowOn}(锁根行 → 补旁表行 → 锁读格与在删令牌)→ 判官 `judgeLandedRow`(就是 `judgeSessionRowWrite` 的 `replay` 写者:行在 ∧ 非在删 ∧
|
|
34
|
+
* 非委派分区 ∧ 属主与化身整对同)→ 是 ⇒ 段体在**同一连接、同一事务**里跑各店的语句源 → 提交;不是 ⇒ 回滚、一个字节不写。死锁受害 / 仲裁输了
|
|
35
|
+
* (`SqlArbitrationLostError`:文件历史哨兵消失等)⇒ 从**段首**重来(含锁根行与判,经仓里唯一的 `retryOnDeadlock`)—— 段内不许有自己回滚重开事务的语句源。
|
|
36
|
+
*/
|
|
37
|
+
import type { SqlDialect, SqlDriver, SqlTxConn } from "./sql-driver.js";
|
|
38
|
+
import type { SessionLogMark } from "@sema-agent/core";
|
|
39
|
+
import { type SessionFace } from "../session-incarnation.js";
|
|
40
|
+
import { type LockedSessionRow, type SessionRowAnswer, type SessionRowPatch, type SessionRowWrite, type SessionRowWriteOutcome, type LandedOutcome } from "../session-row.js";
|
|
41
|
+
/** 一条连接上的行读口(本事务的语句面:SQL 文本 + 参数 → 行)—— `SqlTxConn` / mysql2 连接 / node-pg 客户端各包一行即得。 */
|
|
42
|
+
export type SessionRootRowsOn = (text: string, values: readonly unknown[]) => Promise<ReadonlyArray<Readonly<Record<string, unknown>>>>;
|
|
43
|
+
/** `SqlTxConn` 的行读口。 */
|
|
44
|
+
export declare function rootRowsOnTx(conn: Pick<SqlTxConn, "query">): SessionRootRowsOn;
|
|
45
|
+
/**
|
|
46
|
+
* **锁根行读住客 —— 唯一一句**(头注):同一连接上 `SELECT owner, incarnation, placement_kind, leaf_seq, updated_at FROM session_meta WHERE session_id = ? FOR UPDATE`。
|
|
47
|
+
* 行不在 ⇒ `undefined`(InnoDB 可重复读下锁一只不在的键取间隙锁 —— 挡住同 id 的并发登记到本事务结束,调用方随即回滚)。读者各自解码五格。
|
|
48
|
+
*/
|
|
49
|
+
export declare function lockSessionRootOn(conn: SessionRootRowsOn, dialect: SqlDialect, sessionId: string): Promise<Readonly<Record<string, unknown>> | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* 会话根行的部署格(SQL 会话规则店的构造参数,组合座 `store-backend.ts` 交入;店目录不认识根行与旁表,R8):`lockRoot` = 上面那一句(行在不在),
|
|
52
|
+
* `countClientWrite` = 客户端写计数的唯一一处(`session-withdraw-sql.ts`)。形由规则店的 `SessionRootSeat` 型在组合座上结构核对。
|
|
53
|
+
*/
|
|
54
|
+
export declare const SQL_SESSION_ROOT_SEAT: {
|
|
55
|
+
readonly lockRoot: (conn: Pick<SqlTxConn, "query">, dialect: SqlDialect, sessionId: string) => Promise<boolean>;
|
|
56
|
+
readonly countClientWrite: (conn: SqlTxConn, dialect: SqlDialect, sessionId: string) => Promise<void>;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* 写原语与落定段的**同一前缀**(头注 ①):锁根行({@link lockSessionRootOn})→ 行在 ⇒ 写序律:先补旁表行、再锁定读它的格与在删令牌(锁定读永远落在一行在的记录上 ——
|
|
60
|
+
* InnoDB 间隙锁死锁,见 `execution-placement-sql.ts` 的 readCellOn;锁定读 = 最新已提交)→ 判官吃的形;`logMark` ⇒ 同锁下读日志的 mark。行不在 ⇒ `locked: undefined`。
|
|
61
|
+
*/
|
|
62
|
+
export declare function lockSessionRowOn(conn: SqlTxConn, dialect: SqlDialect, sessionId: string, opts: {
|
|
63
|
+
readonly logMark: boolean;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
readonly locked: LockedSessionRow | undefined;
|
|
66
|
+
readonly mark?: SessionLogMark;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* **落定段**(头注「落定段」):一只事务里锁根行判住客(`landed` = 提交回执交回的那一位 / identical 臂门读的那一位 / 运行腿受理时见证的那一位 / 路由门读的那一位)→
|
|
70
|
+
* 是那一位 ⇒ `body(本事务连接)` → 提交 ⇒ `{ landed: true, value }`;不是 ⇒ 回滚 ⇒ `{ landed: false }`(一个字节没写)。`body` 抛 ⇒ 回滚、原样上抛(段体自己的拒,
|
|
71
|
+
* 例:规则收紧门)。死锁受害 / 仲裁输了 / `alsoRetry` 认的错 ⇒ 从段首整段重来(重来同样重锁、重判)。
|
|
26
72
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
73
|
+
export declare function withLandedRow<T>(db: Pick<SqlDriver, "dialect" | "connect">, sessionId: string, landed: SessionFace, body: (tx: SqlTxConn) => Promise<T>, opts?: {
|
|
74
|
+
readonly alsoRetry?: (err: unknown) => boolean;
|
|
75
|
+
}): Promise<LandedOutcome<T>>;
|
|
29
76
|
/**
|
|
30
77
|
* 写原语(头注):一只事务里锁根行 → 判官 → 写 / 不写;提交 / 回滚之后经 `readAnswer`(调用方店的列表行读 + 行上的住客)另读应答行。
|
|
31
78
|
* `db` = 店自己的池包成的 SqlDriver(连接经它的初始化);`readAnswer` 只在判官答 `write` / `changed` 时被调。
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { BUMP_CLIENT_WRITES, SESSION_EXT_TABLE, ensureSessionExtRowStatement } from "./session-ext-table.js";
|
|
1
|
+
import { BUMP_CLIENT_WRITES, DELETING_TOKEN_COLUMN, SESSION_EXT_TABLE, ensureSessionExtRowStatement } from "./session-ext-table.js";
|
|
2
2
|
import { incarnationFromCell } from "../session-incarnation.js";
|
|
3
|
-
import {
|
|
3
|
+
import { retryOnDeadlock } from "./sql-errors.js";
|
|
4
|
+
import { countClientWriteOn } from "./session-withdraw-sql.js";
|
|
5
|
+
import { judgeLandedRow, judgeSessionRowWrite, settleSessionRowWrite, } from "../session-row.js";
|
|
4
6
|
function binder(dialect) {
|
|
5
7
|
const values = [];
|
|
6
8
|
return {
|
|
@@ -11,11 +13,27 @@ function binder(dialect) {
|
|
|
11
13
|
},
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
export function rootRowsOnTx(conn) {
|
|
17
|
+
return async (text, values) => (await conn.query(text, [...values])).rows;
|
|
18
|
+
}
|
|
19
|
+
export async function lockSessionRootOn(conn, dialect, sessionId) {
|
|
20
|
+
return (await conn(`SELECT owner, incarnation, placement_kind, leaf_seq, updated_at FROM session_meta WHERE session_id = ${dialect === "pg" ? "$1" : "?"} FOR UPDATE`, [sessionId]))[0];
|
|
21
|
+
}
|
|
22
|
+
export const SQL_SESSION_ROOT_SEAT = {
|
|
23
|
+
async lockRoot(conn, dialect, sessionId) {
|
|
24
|
+
return (await lockSessionRootOn(rootRowsOnTx(conn), dialect, sessionId)) !== undefined;
|
|
25
|
+
},
|
|
26
|
+
async countClientWrite(conn, dialect, sessionId) {
|
|
27
|
+
await countClientWriteOn(conn, dialect, sessionId);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
14
30
|
function lockedRowFrom(dialect, sessionId, row, ext) {
|
|
31
|
+
const token = ext?.[DELETING_TOKEN_COLUMN.name];
|
|
15
32
|
return {
|
|
16
33
|
owner: row.owner === null || row.owner === undefined ? null : String(row.owner),
|
|
17
34
|
incarnation: incarnationFromCell(sessionId, row.incarnation, "absent"),
|
|
18
35
|
placed: row.placement_kind !== null && row.placement_kind !== undefined,
|
|
36
|
+
deleting: token !== null && token !== undefined,
|
|
19
37
|
mirror: ext?.execution_role === "mirror",
|
|
20
38
|
cells: {
|
|
21
39
|
title: ext?.title === null || ext?.title === undefined ? null : String(ext.title),
|
|
@@ -23,6 +41,40 @@ function lockedRowFrom(dialect, sessionId, row, ext) {
|
|
|
23
41
|
},
|
|
24
42
|
};
|
|
25
43
|
}
|
|
44
|
+
export async function lockSessionRowOn(conn, dialect, sessionId, opts) {
|
|
45
|
+
const root = await lockSessionRootOn(rootRowsOnTx(conn), dialect, sessionId);
|
|
46
|
+
if (root === undefined)
|
|
47
|
+
return { locked: undefined };
|
|
48
|
+
const ensure = ensureSessionExtRowStatement(dialect, sessionId);
|
|
49
|
+
await conn.query(ensure.text, [...ensure.values]);
|
|
50
|
+
const extRead = binder(dialect);
|
|
51
|
+
const ext = (await conn.query(`SELECT execution_role, title, pinned, ${DELETING_TOKEN_COLUMN.name} FROM ${SESSION_EXT_TABLE} WHERE session_id = ${extRead.p(sessionId)} FOR UPDATE`, extRead.values)).rows[0];
|
|
52
|
+
const locked = lockedRowFrom(dialect, sessionId, root, ext);
|
|
53
|
+
return opts.logMark ? { locked, mark: await lockedLogMark(conn, dialect, sessionId, root.leaf_seq) } : { locked };
|
|
54
|
+
}
|
|
55
|
+
export async function withLandedRow(db, sessionId, landed, body, opts) {
|
|
56
|
+
return retryOnDeadlock(db.dialect, async () => {
|
|
57
|
+
const conn = await db.connect();
|
|
58
|
+
try {
|
|
59
|
+
await conn.begin();
|
|
60
|
+
const { locked } = await lockSessionRowOn(conn, db.dialect, sessionId, { logMark: false });
|
|
61
|
+
if (!judgeLandedRow(sessionId, landed, locked)) {
|
|
62
|
+
await conn.rollback();
|
|
63
|
+
return { landed: false };
|
|
64
|
+
}
|
|
65
|
+
const value = await body(conn);
|
|
66
|
+
await conn.commit();
|
|
67
|
+
return { landed: true, value };
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
await conn.rollback().catch(() => undefined);
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
conn.release();
|
|
75
|
+
}
|
|
76
|
+
}, opts?.alsoRetry);
|
|
77
|
+
}
|
|
26
78
|
async function lockedLogMark(conn, dialect, sessionId, leafSeq) {
|
|
27
79
|
const b = binder(dialect);
|
|
28
80
|
const last = await conn.query(`SELECT entry_id FROM session_event WHERE session_id = ${b.p(sessionId)} ORDER BY seq DESC LIMIT 1 FOR UPDATE`, b.values);
|
|
@@ -35,17 +87,8 @@ export async function writeSessionRowCellsSql(db, sessionId, cells, how, readAns
|
|
|
35
87
|
const conn = await db.connect();
|
|
36
88
|
try {
|
|
37
89
|
await conn.begin();
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const extRead = binder(dialect);
|
|
41
|
-
let ext;
|
|
42
|
-
if (locked !== undefined) {
|
|
43
|
-
const ensure = ensureSessionExtRowStatement(dialect, sessionId);
|
|
44
|
-
await conn.query(ensure.text, [...ensure.values]);
|
|
45
|
-
ext = (await conn.query(`SELECT execution_role, title, pinned FROM ${SESSION_EXT_TABLE} WHERE session_id = ${extRead.p(sessionId)} FOR UPDATE`, extRead.values)).rows[0];
|
|
46
|
-
}
|
|
47
|
-
const mark = how.row.log === undefined || locked === undefined ? undefined : await lockedLogMark(conn, dialect, sessionId, locked.leaf_seq);
|
|
48
|
-
verdict = judgeSessionRowWrite(sessionId, how, locked === undefined ? undefined : lockedRowFrom(dialect, sessionId, locked, ext), () => {
|
|
90
|
+
const { locked, mark } = await lockSessionRowOn(conn, dialect, sessionId, { logMark: how.row.log !== undefined });
|
|
91
|
+
verdict = judgeSessionRowWrite(sessionId, how, locked, () => {
|
|
49
92
|
if (mark === undefined)
|
|
50
93
|
throw new Error(`writeSessionRowCellsSql: the judge asked session ${sessionId}'s log mark, but the expectation carries none`);
|
|
51
94
|
return mark;
|
|
@@ -21,26 +21,18 @@ import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type Ses
|
|
|
21
21
|
import type { TiDBSessionStore } from "../stores-sql/tidb-session-store.js";
|
|
22
22
|
import type { SessionWriteHooks } from "../stores-sql/session-write-hooks.js";
|
|
23
23
|
import type { SqlDriver } from "./sql-driver.js";
|
|
24
|
+
import { type IdleSession, type IdleSessionCursor, type SessionKind, type SessionKindReading } from "../session-kind.js";
|
|
24
25
|
import { type ExecutionPlacementSeat } from "../execution-placement.js";
|
|
25
26
|
import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
|
|
26
|
-
import { type RegisterReceipt, type SessionBirth, type WithdrawOutcome } from "../session-incarnation.js";
|
|
27
|
+
import { type RegisterReceipt, type SessionBirth, type SessionFace, type WithdrawOutcome } from "../session-incarnation.js";
|
|
27
28
|
import { type SessionDeletionFace } from "../session-deletion.js";
|
|
28
29
|
import { type ClientSessionRowWrite, type ReplaySessionRowWrite, type ReplaySessionRowWriteOutcome, type SessionRowAnswer, type SessionRowPatch, type SessionRowWriteOutcome } from "../session-row.js";
|
|
29
|
-
import type { SessionSummary } from "./store-contracts.js";
|
|
30
|
+
import type { SessionListQuery, SessionSummary } from "./store-contracts.js";
|
|
30
31
|
import type { SessionWorkspace } from "../session-workspace.js";
|
|
31
32
|
/** 座的面:座的公开成员(两方言同形 —— PG 孪生按结构赋给它,组合座里 tsc 判)。 */
|
|
32
33
|
export type SessionSeat = Pick<TiDBSessionStore, "retention" | "placements" | "durability" | "acquire" | "register" | "registerWithReceipt" | "deleteSessionIf" | "placementOf" | "listPlaced" | "headOf" | "touch" | "release" | "forget" | "fork" | "forkTo" | "exportEntries" | "listEntryIds" | "exportEntriesStream" | "importEntries" | "replaceEntries" | "beginImportStaging" | "readStagedEntries" | "sweepStagingSessions" | "size" | "dispose">;
|
|
33
|
-
/** 列表面的查询(`OwnerAwareSessionStore.listSessions`
|
|
34
|
-
export
|
|
35
|
-
owner?: string;
|
|
36
|
-
includeUnowned?: boolean;
|
|
37
|
-
cursor?: {
|
|
38
|
-
lastActivityAt: string;
|
|
39
|
-
sessionId: string;
|
|
40
|
-
};
|
|
41
|
-
limit: number;
|
|
42
|
-
q?: string;
|
|
43
|
-
}
|
|
34
|
+
/** 列表面的查询(`OwnerAwareSessionStore.listSessions` 的入参形;三店同一形)。 */
|
|
35
|
+
export type SessionListOptions = SessionListQuery;
|
|
44
36
|
/**
|
|
45
37
|
* 会话店的事务内钩(座锁住根行之后、写之前调;同一事务、同一连接):
|
|
46
38
|
* · 四个词同一只判官 {@link judgeSessionWrite}(local 店的写锁内同调这一只):`erase` 只判这一行的在删令牌(不是 ⇒ 拒 `SessionDeletionSupersededError`);其余认领在 ⇒ 拒 `SessionActiveRunError`;
|
|
@@ -49,6 +41,11 @@ export interface SessionListOptions {
|
|
|
49
41
|
* · 键控 fork(服务扩展)—— `record`:新行的 fork 键落旁表(新行是本事务刚插下的,本事务持着它的锁);`targetOf`:撞上已在的目标时的一次池读(属主 + fork 键)。
|
|
50
42
|
*/
|
|
51
43
|
export declare function createSqlSessionWriteHooks(db: Pick<SqlDriver, "dialect" | "query">): SessionWriteHooks;
|
|
44
|
+
/**
|
|
45
|
+
* 🔴 **视图谓词的 SQL 一句**(两方言同一函数;列表 lister 与老化候选面同调 —— local 店的同一判是 `session-kind.ts` 的 `sessionKindListed`):
|
|
46
|
+
* 缺省视图(`view` 缺席)⇒ 只有无种类的行;`view` 在场 ⇒ 恰那一种。`se` = 旁表 `session_ext` 的别名(LEFT JOIN:旁表行不在 = 无种类)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function sessionKindSql(view: SessionKind | undefined, p: (v: unknown) => string): string;
|
|
52
49
|
export declare class SqlSessionStore implements SessionStore {
|
|
53
50
|
private readonly db;
|
|
54
51
|
/** 座(引擎座表的唯一写者)。 */
|
|
@@ -63,8 +60,10 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
63
60
|
constructor(db: SqlDriver, seatOn: (hooks: SessionWriteHooks) => SessionSeat);
|
|
64
61
|
acquire(...a: Parameters<SessionSeat["acquire"]>): Promise<AcquiredSession>;
|
|
65
62
|
register(sessionId: string, owner: string | null): Promise<void>;
|
|
66
|
-
/** 出生回执面(
|
|
67
|
-
registerWithReceipt(sessionId: string, owner: string | null): Promise<RegisterReceipt>;
|
|
63
|
+
/** 出生回执面(座逐字转发,种类一并转 —— 漏一层 = 种类在 SQL 上静默丢;`plugins/session-birth.ts`)。 */
|
|
64
|
+
registerWithReceipt(sessionId: string, owner: string | null, kind?: SessionKind): Promise<RegisterReceipt>;
|
|
65
|
+
/** 按 id 的种类读(`session-kind.ts` 的 `SessionKindFace`):一条 PK SELECT —— 根行的化身 + 旁表的种类(同一次读;旁表行不在 = 无种类)。不在 ⇒ `undefined`。 */
|
|
66
|
+
sessionKindOf(sessionId: string): Promise<SessionKindReading | undefined>;
|
|
68
67
|
/** 条件撤回面:座的条件删除 + 本部署的判据(启用标记 / 客户端写计数 / 别的 run / 本次 run 的部署行;同一事务)。 */
|
|
69
68
|
withdrawBirth(birth: SessionBirth, ownTaskId: string | undefined): Promise<WithdrawOutcome>;
|
|
70
69
|
placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
|
|
@@ -99,6 +98,22 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
99
98
|
* 写序与旁表的其余格写者同一条(根行 → 旁表;根行先 ⇒ 与认领事务、座的删除 / 导入同一锁序)。
|
|
100
99
|
*/
|
|
101
100
|
private fenceDeletion;
|
|
101
|
+
/**
|
|
102
|
+
* 老化条件的锁内判({@link SessionAgeOutExpectation};调用方持根行锁、旁表行已补并锁定 —— `readDeletingTokenOn` 之后):住客仍是候选那一位 ∧ 最后活动仍早于视界
|
|
103
|
+
* ∧ 种类仍是它 ∧ 当下无活引用(与托管留存同一只谓词;认领那一腿随后由围栏自己的判官再判一次,结局 `active`)。
|
|
104
|
+
* **全部是当前读**:住客与最后活动来自根行的锁定读;种类与活引用两读也带 `FOR UPDATE` —— MySQL 协议的可重复读下普通 SELECT 读的是一份快照(TiDB:事务起点的快照),
|
|
105
|
+
* 等根行锁期间别的事务提交的待决检查点 / 子代 / workflow 行会被它漏掉;锁定读读最新提交(与托管留存执行器的候选锁读同一形)。
|
|
106
|
+
*/
|
|
107
|
+
private ageOutHoldsOn;
|
|
108
|
+
/**
|
|
109
|
+
* 老化候选面(`OwnerAwareSessionStore.listIdleOfKind`;律 `src/session-kind.ts`):`session_meta` JOIN 旁表 —— 视图谓词同一只片段({@link sessionKindSql})∧ 最后活动早于视界
|
|
110
|
+
* ∧ 当下无活引用(与托管留存同一只谓词),**在删的行也交**(一次失败的自动删除撂下的在删行,两只 lister 都读不到它 —— 交给围栏:持有者已死 ⇒ 接管收完)。
|
|
111
|
+
* 最老先出,`(updated_at, session_id)` 升序 keyset 续页;走 `idx_session_ext_kind`。每读带语句期限(过期 ⇒ 这一句自己拒,调用方本拍停、下拍再来)。
|
|
112
|
+
*/
|
|
113
|
+
listIdleOfKind(kind: SessionKind, idleBefore: Date, page: {
|
|
114
|
+
readonly after?: IdleSessionCursor;
|
|
115
|
+
readonly limit: number;
|
|
116
|
+
}): Promise<IdleSession[]>;
|
|
102
117
|
get size(): number;
|
|
103
118
|
dispose(): void;
|
|
104
119
|
/**
|
|
@@ -135,9 +150,10 @@ export declare class SqlSessionStore implements SessionStore {
|
|
|
135
150
|
/** Cheap pre-LLM probe: "none" = session_meta row not yet REGISTERED (createRun fires before the Runner's session acquire — the titler retries),
|
|
136
151
|
* "untitled" / "titled" as read (no side-table row = untitled). */
|
|
137
152
|
probeTitle(sessionId: string): Promise<"none" | "untitled" | "titled">;
|
|
138
|
-
/** The auto-titler's write: lands ONLY when title IS NULL (a concurrent/prior title — the user's included — wins; writer order: `src/session-row.ts`)
|
|
139
|
-
*
|
|
140
|
-
|
|
153
|
+
/** The auto-titler's write: lands ONLY when title IS NULL (a concurrent/prior title — the user's included — wins; writer order: `src/session-row.ts`)
|
|
154
|
+
* AND the session row is still `landed` (the occupant the titler read at acceptance) — judged in the landed section (`withLandedRow`: lock the root row,
|
|
155
|
+
* the row-write judge). Returns whether this call set it. No session row / another occupant / being deleted ⇒ `false`, zero bytes. */
|
|
156
|
+
setTitleIfNull(sessionId: string, title: string, landed: SessionFace): Promise<boolean>;
|
|
141
157
|
/** 换源通告的基线读(一行 PK 读;列的三态读法见 `instruction-source-notice.ts`)。旁表行不在 ⇒ 读作「没记过」。语句期限 {@link BASELINE_IO_DEADLINE_MS}(过期 ⇒ 查询自己拒、连接销毁)。 */
|
|
142
158
|
readInstructionSource(sessionId: string): Promise<InstructionSourceBaseline>;
|
|
143
159
|
/**
|
|
@@ -2,7 +2,10 @@ import { uuidv7 } from "@sema-agent/core";
|
|
|
2
2
|
import { escapeLike } from "./sql-escape.js";
|
|
3
3
|
import { jsonColumnText } from "./sql-json-column.js";
|
|
4
4
|
import { pgSafeJsonStringify } from "./pg-safe-json.js";
|
|
5
|
-
import { DELETING_TOKEN_COLUMN, SESSION_EXT_TABLE, ensureSessionExtRowStatement, readDeletingTokenOn } from "./session-ext-table.js";
|
|
5
|
+
import { DELETING_TOKEN_COLUMN, SESSION_EXT_TABLE, SESSION_KIND_COLUMN, ensureSessionExtRowStatement, readDeletingTokenOn } from "./session-ext-table.js";
|
|
6
|
+
import { sessionKindFromCell } from "../session-kind.js";
|
|
7
|
+
import { sessionLiveReferenceSql } from "./retention-sql.js";
|
|
8
|
+
import { lockHoldSentinel } from "./retention-lane-store-sql.js";
|
|
6
9
|
import { decodeSessionWorkspaceCell, encodeSessionWorkspaceCell } from "./session-workspace-cell.js";
|
|
7
10
|
import { createSqlExecutionPlacementSeat, markMirrorStatement, readCellOn, readClaimOn, writeCellOn } from "./execution-placement-sql.js";
|
|
8
11
|
import { judgeSessionWrite, sessionWriteTouchesCell } from "../execution-placement.js";
|
|
@@ -10,9 +13,10 @@ import { BASELINE_IO_DEADLINE_MS, decodeInstructionSource, encodeInstructionSour
|
|
|
10
13
|
import { forkLineageOfRow, headFromRow, incarnationFromCell } from "../session-incarnation.js";
|
|
11
14
|
import { CROSS_PROCESS_TAKEOVER_AFTER_MS, deletionTokenMintedAt } from "../session-deletion.js";
|
|
12
15
|
import { sessionRowTagKey } from "../session-row.js";
|
|
13
|
-
import { writeSessionRowCellsSql } from "./session-row-sql.js";
|
|
16
|
+
import { lockSessionRootOn, withLandedRow, writeSessionRowCellsSql } from "./session-row-sql.js";
|
|
14
17
|
import { bumpClientWritesOn, createSqlWithdrawJudge } from "./session-withdraw-sql.js";
|
|
15
18
|
import { WITHDRAWABLE_ENTRY_TYPES } from "./session-birth.js";
|
|
19
|
+
import { sealStoreClass, sealStoreObject } from "./store-boundary.js";
|
|
16
20
|
const RUN_PREVIEW_PRESENT = "CHAR_LENGTH(objective_preview) > 0";
|
|
17
21
|
function binder(dialect) {
|
|
18
22
|
const values = [];
|
|
@@ -57,17 +61,30 @@ export function createSqlSessionWriteHooks(db) {
|
|
|
57
61
|
return { owner: row.owner === null || row.owner === undefined ? null : String(row.owner), forkKey: row.fork_key === null || row.fork_key === undefined ? null : String(row.fork_key) };
|
|
58
62
|
},
|
|
59
63
|
},
|
|
64
|
+
birth: {
|
|
65
|
+
async record(txn, born) {
|
|
66
|
+
const ensure = ensureSessionExtRowStatement(dialect, born.rootSessionId);
|
|
67
|
+
await txn.query(ensure.text, [...ensure.values]);
|
|
68
|
+
const b = binder(dialect);
|
|
69
|
+
const res = await txn.query(`UPDATE ${SESSION_EXT_TABLE} SET ${SESSION_KIND_COLUMN.name} = ${b.p(born.kind)} WHERE session_id = ${b.p(born.rootSessionId)}`, b.values);
|
|
70
|
+
if (res.affected !== 1)
|
|
71
|
+
throw new Error(`registration of session ${born.rootSessionId}: the session kind write matched ${res.affected} row(s) of a row this transaction just created — engine/driver anomaly, refusing to guess`);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
60
74
|
};
|
|
61
75
|
}
|
|
76
|
+
export function sessionKindSql(view, p) {
|
|
77
|
+
return view === undefined ? `se.${SESSION_KIND_COLUMN.name} IS NULL` : `se.${SESSION_KIND_COLUMN.name} = ${p(view)}`;
|
|
78
|
+
}
|
|
79
|
+
const IDLE_SESSION_READ = { deadlineMs: 2_000 };
|
|
62
80
|
const BASELINE_STATEMENT = { deadlineMs: BASELINE_IO_DEADLINE_MS };
|
|
63
81
|
async function withLockedSessionExt(db, sessionId, lock, write) {
|
|
64
82
|
const conn = await db.connect();
|
|
65
83
|
const query = (sql, params) => conn.query(sql, params, lock.statement);
|
|
66
84
|
try {
|
|
67
85
|
await conn.begin();
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
if (locked.rows.length === 0) {
|
|
86
|
+
const root = await lockSessionRootOn(async (text, values) => (await query(text, [...values])).rows, db.dialect, sessionId);
|
|
87
|
+
if (root === undefined || (lock.incarnation !== undefined && root.incarnation !== lock.incarnation)) {
|
|
71
88
|
await conn.rollback();
|
|
72
89
|
return false;
|
|
73
90
|
}
|
|
@@ -90,6 +107,10 @@ const listedLineageOf = (sessionId, forkedFrom) => {
|
|
|
90
107
|
const lineage = forkLineageOfRow(sessionId, forkedFrom, undefined);
|
|
91
108
|
return lineage.forkedFrom !== undefined ? { forkedFrom: lineage.forkedFrom } : {};
|
|
92
109
|
};
|
|
110
|
+
const listedKindOf = (sessionId, cell) => {
|
|
111
|
+
const kind = sessionKindFromCell(sessionId, cell);
|
|
112
|
+
return kind !== undefined ? { sessionKind: kind } : {};
|
|
113
|
+
};
|
|
93
114
|
function holderMayBeAlive(holder, token) {
|
|
94
115
|
switch (holder) {
|
|
95
116
|
case "running":
|
|
@@ -123,8 +144,15 @@ export class SqlSessionStore {
|
|
|
123
144
|
register(sessionId, owner) {
|
|
124
145
|
return this.seat.register(sessionId, owner);
|
|
125
146
|
}
|
|
126
|
-
registerWithReceipt(sessionId, owner) {
|
|
127
|
-
return this.seat.registerWithReceipt(sessionId, owner);
|
|
147
|
+
registerWithReceipt(sessionId, owner, kind) {
|
|
148
|
+
return this.seat.registerWithReceipt(sessionId, owner, kind);
|
|
149
|
+
}
|
|
150
|
+
async sessionKindOf(sessionId) {
|
|
151
|
+
const b = binder(this.db.dialect);
|
|
152
|
+
const row = (await this.db.query(`SELECT sm.incarnation, se.${SESSION_KIND_COLUMN.name} AS session_kind FROM session_meta sm LEFT JOIN ${SESSION_EXT_TABLE} se ON se.session_id = sm.session_id WHERE sm.session_id = ${b.p(sessionId)}`, b.values)).rows[0];
|
|
153
|
+
if (row === undefined)
|
|
154
|
+
return undefined;
|
|
155
|
+
return { incarnation: incarnationFromCell(sessionId, row.incarnation, "absent"), kind: sessionKindFromCell(sessionId, row.session_kind) };
|
|
128
156
|
}
|
|
129
157
|
withdrawBirth(birth, ownTaskId) {
|
|
130
158
|
const cond = {
|
|
@@ -190,7 +218,7 @@ export class SqlSessionStore {
|
|
|
190
218
|
sweepStagingSessions() {
|
|
191
219
|
return this.seat.sweepStagingSessions();
|
|
192
220
|
}
|
|
193
|
-
sessionDeletion = {
|
|
221
|
+
sessionDeletion = sealStoreObject({
|
|
194
222
|
fence: (sessionId, owner, opts) => this.fenceDeletion(sessionId, owner, opts),
|
|
195
223
|
holds: async (sessionId, token) => {
|
|
196
224
|
const b = binder(this.db.dialect);
|
|
@@ -201,21 +229,25 @@ export class SqlSessionStore {
|
|
|
201
229
|
const rows = (await this.db.query(`SELECT sm.session_id, sm.owner, se.${DELETING_TOKEN_COLUMN.name} AS token FROM session_meta sm JOIN ${SESSION_EXT_TABLE} se ON se.session_id = sm.session_id WHERE se.${DELETING_TOKEN_COLUMN.name} IS NOT NULL ORDER BY sm.session_id`, [])).rows;
|
|
202
230
|
return rows.map((r) => ({ sessionId: String(r.session_id), owner: r.owner ?? null, token: String(r.token) }));
|
|
203
231
|
},
|
|
204
|
-
};
|
|
232
|
+
}, "sql-session-deletion", { fence: "exit", holds: "exit", pending: "exit" });
|
|
205
233
|
async fenceDeletion(sessionId, owner, opts) {
|
|
206
234
|
const dialect = this.db.dialect;
|
|
207
235
|
const conn = await this.db.connect();
|
|
208
236
|
try {
|
|
209
237
|
await conn.begin();
|
|
210
238
|
const rows = async (sql, values) => (await conn.query(sql, [...values])).rows;
|
|
211
|
-
|
|
239
|
+
if (opts.ageOut !== undefined && (await lockHoldSentinel(conn, dialect, owner ?? ""))) {
|
|
240
|
+
await conn.rollback();
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
const root = await lockSessionRootOn(rows, dialect, sessionId);
|
|
212
244
|
if (root === undefined || (root.owner ?? null) !== owner) {
|
|
213
245
|
await conn.rollback();
|
|
214
246
|
return undefined;
|
|
215
247
|
}
|
|
216
248
|
const held = await readDeletingTokenOn(rows, dialect, sessionId);
|
|
217
249
|
if (held === null) {
|
|
218
|
-
if (opts.expect !== undefined) {
|
|
250
|
+
if (opts.expect !== undefined || (opts.ageOut !== undefined && !(await this.ageOutHoldsOn(rows, sessionId, root, opts.ageOut)))) {
|
|
219
251
|
await conn.rollback();
|
|
220
252
|
return undefined;
|
|
221
253
|
}
|
|
@@ -251,6 +283,45 @@ export class SqlSessionStore {
|
|
|
251
283
|
conn.release();
|
|
252
284
|
}
|
|
253
285
|
}
|
|
286
|
+
async ageOutHoldsOn(rows, sessionId, root, ageOut) {
|
|
287
|
+
if (incarnationFromCell(sessionId, root.incarnation, "absent") !== ageOut.incarnation)
|
|
288
|
+
return false;
|
|
289
|
+
const lastActivity = root.updated_at instanceof Date ? root.updated_at : new Date(String(root.updated_at));
|
|
290
|
+
if (!(lastActivity.getTime() < ageOut.idleBefore.getTime()))
|
|
291
|
+
return false;
|
|
292
|
+
const b = binder(this.db.dialect);
|
|
293
|
+
const cell = (await rows(`SELECT ${SESSION_KIND_COLUMN.name} AS session_kind FROM ${SESSION_EXT_TABLE} WHERE session_id = ${b.p(sessionId)} FOR UPDATE`, b.values))[0];
|
|
294
|
+
if (sessionKindFromCell(sessionId, cell?.session_kind) !== ageOut.kind)
|
|
295
|
+
return false;
|
|
296
|
+
const live = binder(this.db.dialect);
|
|
297
|
+
return (await rows(`SELECT 1 AS live FROM session_meta sm WHERE sm.session_id = ${live.p(sessionId)} AND ${sessionLiveReferenceSql(this.db.dialect)} FOR UPDATE`, live.values)).length === 0;
|
|
298
|
+
}
|
|
299
|
+
async listIdleOfKind(kind, idleBefore, page) {
|
|
300
|
+
const b = binder(this.db.dialect);
|
|
301
|
+
const where = [sessionKindSql(kind, b.p), `sm.updated_at < ${b.p(idleBefore)}`, `NOT ${sessionLiveReferenceSql(this.db.dialect)}`];
|
|
302
|
+
if (page.after !== undefined) {
|
|
303
|
+
const at = new Date(page.after.lastActivityAt);
|
|
304
|
+
where.push(`(sm.updated_at > ${b.p(at)} OR (sm.updated_at = ${b.p(at)} AND sm.session_id > ${b.p(page.after.sessionId)}))`);
|
|
305
|
+
}
|
|
306
|
+
const sql = `SELECT sm.session_id, sm.owner, sm.incarnation, sm.updated_at FROM session_meta sm JOIN ${SESSION_EXT_TABLE} se ON se.session_id = sm.session_id ` +
|
|
307
|
+
`WHERE ${where.join(" AND ")} ORDER BY sm.updated_at ASC, sm.session_id ASC LIMIT ${b.p(page.limit)}`;
|
|
308
|
+
const conn = await this.db.connect();
|
|
309
|
+
try {
|
|
310
|
+
const rows = (await conn.query(sql, b.values, IDLE_SESSION_READ)).rows;
|
|
311
|
+
return rows.map((r) => {
|
|
312
|
+
const sessionId = String(r.session_id);
|
|
313
|
+
return {
|
|
314
|
+
sessionId,
|
|
315
|
+
owner: r.owner ?? null,
|
|
316
|
+
incarnation: incarnationFromCell(sessionId, r.incarnation, "absent"),
|
|
317
|
+
lastActivityAt: r.updated_at instanceof Date ? r.updated_at.toISOString() : new Date(String(r.updated_at)).toISOString(),
|
|
318
|
+
};
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
finally {
|
|
322
|
+
conn.release();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
254
325
|
get size() {
|
|
255
326
|
return this.seat.size;
|
|
256
327
|
}
|
|
@@ -265,7 +336,7 @@ export class SqlSessionStore {
|
|
|
265
336
|
return this.selectListRows({
|
|
266
337
|
limit: opts.limit,
|
|
267
338
|
where: (p) => {
|
|
268
|
-
const where = ["sm.placement_kind IS NULL"];
|
|
339
|
+
const where = ["sm.placement_kind IS NULL", sessionKindSql(opts.sessionKind, p)];
|
|
269
340
|
if (opts.owner !== undefined)
|
|
270
341
|
where.push(opts.includeUnowned ? `(sm.owner = ${p(opts.owner)} OR sm.owner IS NULL)` : `sm.owner = ${p(opts.owner)}`);
|
|
271
342
|
if (opts.q) {
|
|
@@ -311,7 +382,7 @@ export class SqlSessionStore {
|
|
|
311
382
|
runAnd() +
|
|
312
383
|
" ) pr WHERE rn = 1) pv ON pv.session_id = sm.session_id ";
|
|
313
384
|
const where = [...q.where(b.p), `se.${DELETING_TOKEN_COLUMN.name} IS NULL`];
|
|
314
|
-
const sql =
|
|
385
|
+
const sql = `SELECT sm.session_id, sm.owner, sm.incarnation, sm.updated_at AS last_activity, sm.created_at AS first_activity, sm.forked_from, se.title, se.pinned, se.${SESSION_KIND_COLUMN.name} AS session_kind, ` +
|
|
315
386
|
" COALESCE(r.run_count, 0) AS run_count, pv.objective_preview, latest.status, latest.task_id AS last_run_id, latest.last_task_run_id " +
|
|
316
387
|
"FROM session_meta sm " +
|
|
317
388
|
`LEFT JOIN ${SESSION_EXT_TABLE} se ON se.session_id = sm.session_id ` +
|
|
@@ -342,6 +413,7 @@ export class SqlSessionStore {
|
|
|
342
413
|
pinned,
|
|
343
414
|
...sessionRowTagKey({ sessionId, owner, incarnation, cells: { title, pinned } }),
|
|
344
415
|
...listedLineageOf(sessionId, r.forked_from),
|
|
416
|
+
...listedKindOf(sessionId, r.session_kind),
|
|
345
417
|
};
|
|
346
418
|
return { row, occupant: { owner, incarnation } };
|
|
347
419
|
});
|
|
@@ -356,11 +428,12 @@ export class SqlSessionStore {
|
|
|
356
428
|
return "none";
|
|
357
429
|
return row.title === null || row.title === undefined ? "untitled" : "titled";
|
|
358
430
|
}
|
|
359
|
-
async setTitleIfNull(sessionId, title) {
|
|
360
|
-
|
|
431
|
+
async setTitleIfNull(sessionId, title, landed) {
|
|
432
|
+
const out = await withLandedRow(this.db, sessionId, landed, async (tx) => {
|
|
361
433
|
const b = binder(this.db.dialect);
|
|
362
|
-
return (await query(`UPDATE ${SESSION_EXT_TABLE} SET title = ${b.p(title)} WHERE session_id = ${b.p(sessionId)} AND title IS NULL`, b.values)).affected > 0;
|
|
434
|
+
return (await tx.query(`UPDATE ${SESSION_EXT_TABLE} SET title = ${b.p(title)} WHERE session_id = ${b.p(sessionId)} AND title IS NULL`, b.values)).affected > 0;
|
|
363
435
|
});
|
|
436
|
+
return out.landed && out.value;
|
|
364
437
|
}
|
|
365
438
|
async readInstructionSource(sessionId) {
|
|
366
439
|
const b = binder(this.db.dialect);
|
|
@@ -389,10 +462,18 @@ export class SqlSessionStore {
|
|
|
389
462
|
async recordSessionWorkspace(sessionId, incarnation, workspace) {
|
|
390
463
|
const dialect = this.db.dialect;
|
|
391
464
|
const cell = encodeSessionWorkspaceCell(workspace, dialect === "pg" ? pgSafeJsonStringify : JSON.stringify, sessionId);
|
|
392
|
-
await withLockedSessionExt(this.db, sessionId, {
|
|
465
|
+
await withLockedSessionExt(this.db, sessionId, { incarnation }, async (query) => {
|
|
393
466
|
const b = binder(dialect);
|
|
394
467
|
return (await query(`UPDATE ${SESSION_EXT_TABLE} SET workspace = ${b.p(cell)}${dialect === "pg" ? "::jsonb" : ""} WHERE session_id = ${b.p(sessionId)}`, b.values)).affected > 0;
|
|
395
468
|
});
|
|
396
469
|
}
|
|
397
470
|
}
|
|
471
|
+
sealStoreClass(SqlSessionStore, "sql-session-store", {
|
|
472
|
+
acquire: "exit", register: "exit", registerWithReceipt: "exit", withdrawBirth: "exit", placementOf: "exit", listPlaced: "exit", headOf: "exit",
|
|
473
|
+
deletionHeadOf: "exit", touch: "exit", release: "exit", forget: "exit", fork: "exit", forkTo: "exit", exportEntries: "exit", listEntryIds: "exit",
|
|
474
|
+
exportEntriesStream: "exit", importEntries: "exit", replaceEntries: "exit", beginImportStaging: "exit", readStagedEntries: "exit",
|
|
475
|
+
sweepStagingSessions: "exit", dispose: "exit", listSessions: "exit", listSessionRows: "exit", sessionSummaryOf: "exit", writeSessionRowCells: "exit",
|
|
476
|
+
probeTitle: "exit", setTitleIfNull: "exit", readInstructionSource: "exit", recordInstructionSource: "exit", readSessionWorkspace: "exit",
|
|
477
|
+
recordSessionWorkspace: "exit", sessionKindOf: "exit", listIdleOfKind: "exit",
|
|
478
|
+
});
|
|
398
479
|
//# sourceMappingURL=session-store-sql.js.map
|
|
@@ -118,6 +118,7 @@ export declare class SqlSharedMemoryStore implements SharedMemoryStoreProvider {
|
|
|
118
118
|
* 并发读被写者串起来,而这是会话附着的热路径)。规则少了一条:全店从此只有写方法开事务。
|
|
119
119
|
*/
|
|
120
120
|
private readBinding;
|
|
121
|
+
/** 交给引擎的读器(快照兑现之后才拨库)—— 出店口,造对象处封(读器上的库错同样只带原码 + 稳定句)。 */
|
|
121
122
|
private readerFor;
|
|
122
123
|
/** One keyset window. Always the PAGED shape — a large library must never be materialized per call. */
|
|
123
124
|
private listDocuments;
|
|
@@ -2,6 +2,7 @@ import { writeLogText } from "../observability/logger.js";
|
|
|
2
2
|
import { isOrgScopeKey, isSharedMemoryDocumentPath, isSharedMemoryStoreId, SHARED_MEMORY_READ_CAP_BYTES, SharedMemoryStoreError, } from "@sema-agent/core";
|
|
3
3
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
4
|
import { isDupKeyError } from "./sql-errors.js";
|
|
5
|
+
import { sealStoreClass, sealStoreObject } from "./store-boundary.js";
|
|
5
6
|
const isDupKey = isDupKeyError;
|
|
6
7
|
export const SHARED_MEMORY_SCOPE_TABLE = "shared_memory_scope";
|
|
7
8
|
export const SHARED_MEMORY_STORE_TABLE = "shared_memory_store";
|
|
@@ -159,10 +160,10 @@ export class SqlSharedMemoryStore {
|
|
|
159
160
|
};
|
|
160
161
|
}
|
|
161
162
|
readerFor(storeId, scopeKey) {
|
|
162
|
-
return {
|
|
163
|
+
return sealStoreObject({
|
|
163
164
|
list: (prefix, opts) => this.listDocuments(storeId, scopeKey, prefix, opts),
|
|
164
165
|
read: (path, opts) => this.readDocument(storeId, scopeKey, path, opts),
|
|
165
|
-
};
|
|
166
|
+
}, "sql-shared-memory-reader", { list: "exit", read: "exit" });
|
|
166
167
|
}
|
|
167
168
|
async listDocuments(storeId, scopeKey, prefix, opts) {
|
|
168
169
|
throwIfAborted(opts.signal);
|
|
@@ -363,6 +364,9 @@ export class SqlSharedMemoryStore {
|
|
|
363
364
|
}
|
|
364
365
|
}
|
|
365
366
|
}
|
|
367
|
+
sealStoreClass(SqlSharedMemoryStore, "sql-shared-memory-store", {
|
|
368
|
+
snapshot: "exit", putScopeState: "exit", putStore: "exit", putDocument: "exit", deleteDocument: "exit", deleteStore: "exit",
|
|
369
|
+
});
|
|
366
370
|
export class TiDBSharedMemoryStore extends SqlSharedMemoryStore {
|
|
367
371
|
constructor(pool, authorizer, opts) {
|
|
368
372
|
super(mysqlDriver(pool), authorizer, opts);
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
* 被读成「这个空间头一回」,从空目录起;run 末的保存虽失败,报的却是一条不点名桶的 curl 404,没有一行说「桶没建」。
|
|
10
10
|
*
|
|
11
11
|
* ## 形(一条规则,不加特例)
|
|
12
|
-
* · 核的是 {@link MinioBlobBackend.probeBucket}(presigned 列举 `max-keys=1
|
|
12
|
+
* · 核的是 {@link MinioBlobBackend.probeBucket}(presigned 列举 `max-keys=1`,列举前缀 = 角色行的 `probePrefix`:会话桶 = 退役快照纪元的根 `{legacyBlobRoot}`,
|
|
13
|
+
* 工作区桶 = 适配器写入的那只前缀 `<WORKSPACE_SNAPSHOT_PREFIX>/`,与适配器同一读 `workspaceSnapshotPrefixOf` —— 按前缀授列举的最小权限凭据对探针与对适配器同答;
|
|
14
|
+
* 两行各是对象存储动作表的一行 `boot-probe/*:LIST`);**只有** 404 + `NoSuchBucket` 是「缺」,其余证明不了的形(连不上 / 403 / 5xx / 没有
|
|
13
15
|
* NoSuchBucket 的 404)⇒ **不拒**、照常起服,走登记过的 F 类兜底口 `recordFailOpen("server.snapshot-bucket.presence-unproven")`(计数 + 探针行 + 记录器的一次性 warn;
|
|
14
16
|
* 三问写在该 tag 的 note 里)—— 拒启要有证据,没有证据只留痕;
|
|
15
17
|
* · 缺 = 配置好的店资源还没就绪,与「库连不上」同一类处境:在 `STORE_LOCK_WAIT_MS` 窗内重试({@link openWithinWait},同一只窗、同一只节拍、同一条窗尾规则 —— 编排里
|
|
@@ -36,6 +38,16 @@ export declare const SNAPSHOT_BUCKET_ROLES: {
|
|
|
36
38
|
readonly defaultName: "session-snapshots";
|
|
37
39
|
readonly consequence: "every snapshot-offload write and SendUserFile private-track request would answer 404 NoSuchBucket (and the orphan sweep would log one every minute, forever)";
|
|
38
40
|
readonly createHint: "; this version's sema-up scripts create it — re-run them on an existing sema-up deployment";
|
|
41
|
+
readonly probeOp: "boot-probe/session:LIST";
|
|
42
|
+
readonly probePrefix: (store: {
|
|
43
|
+
endpoint: string;
|
|
44
|
+
bucket: string;
|
|
45
|
+
accessKey: string;
|
|
46
|
+
secretKey: string;
|
|
47
|
+
region?: string;
|
|
48
|
+
keyPrefix?: string;
|
|
49
|
+
presignTtlSec?: number;
|
|
50
|
+
}) => string;
|
|
39
51
|
};
|
|
40
52
|
readonly workspace: {
|
|
41
53
|
readonly noun: "workspace snapshot bucket";
|
|
@@ -43,9 +55,20 @@ export declare const SNAPSHOT_BUCKET_ROLES: {
|
|
|
43
55
|
readonly defaultName: "workspaces";
|
|
44
56
|
readonly consequence: "no workspace snapshot could be saved or restored (every run would start from an empty /workspace and every run-end save would fail on a bare 404), and no line would say the bucket is missing";
|
|
45
57
|
readonly createHint: "";
|
|
58
|
+
readonly probeOp: "boot-probe/workspace:LIST";
|
|
59
|
+
readonly probePrefix: (store: {
|
|
60
|
+
endpoint: string;
|
|
61
|
+
bucket: string;
|
|
62
|
+
accessKey: string;
|
|
63
|
+
secretKey: string;
|
|
64
|
+
region?: string;
|
|
65
|
+
keyPrefix?: string;
|
|
66
|
+
presignTtlSec?: number;
|
|
67
|
+
}) => string;
|
|
46
68
|
};
|
|
47
69
|
};
|
|
48
|
-
/** boot 期单次探针的上界(ms):黑洞端点(丢包不拒连)不许把起服拖到对象存储 IO 的 120s;到点 ⇒ `unknown`(证明不了缺桶 ⇒ 不拒、报一次)。
|
|
70
|
+
/** boot 期单次探针的上界(ms):黑洞端点(丢包不拒连)不许把起服拖到对象存储 IO 的 120s;到点 ⇒ `unknown`(证明不了缺桶 ⇒ 不拒、报一次)。
|
|
71
|
+
* 会话 blob 命名空间的认领请求(`session-blob-namespace.ts`,起服的那一次与每次删除前的重读)读同一只数:起服对快照桶的探针只有这一个上界。 */
|
|
49
72
|
export declare const SNAPSHOT_BUCKET_PROBE_TIMEOUT_MS = 10000;
|
|
50
73
|
/** 缺桶的拒启句(唯一铸点)。 */
|
|
51
74
|
/** @param endpoint `MINIO_ENDPOINT` 的**显示安全形**(调用方过 {@link buildDisplaySafeUrl};本函数不碰原串)。 */
|