@sema-agent/server 7.149.0 → 7.151.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +307 -9
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +92 -40
- package/deploy/sema-up/README.md +7 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +5 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +15 -16
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -3
- package/deploy/sema-up/chart/templates/server.yaml +5 -3
- package/deploy/sema-up/chart/values-full-single.yaml +3 -1
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +1 -0
- package/deploy/sema-up/kube-up.sh +1 -1
- package/deploy/sema-up/lib/flagshape.sh +1 -1
- package/deploy/sema-up/lib/helm-values-cluster.py +2 -0
- package/deploy/sema-up/lib/helm-values-kube.py +2 -0
- package/dist/adoption/import.js +3 -3
- package/dist/approval-ask-machine.d.ts +1 -1
- package/dist/approval-card.d.ts +3 -3
- package/dist/approval-gate-currency.d.ts +2 -2
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/auth-bridge.d.ts +20 -0
- package/dist/auth-bridge.js +9 -0
- package/dist/background-session-reap.d.ts +2 -2
- package/dist/bake-runner/main.d.ts +4 -2
- package/dist/bind-host.d.ts +2 -3
- package/dist/bind-host.js +2 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/engine-lease.d.ts +5 -0
- package/dist/boot/engine-lease.js +1 -0
- package/dist/boot/execution-env.d.ts +8 -14
- package/dist/boot/execution-env.js +54 -17
- package/dist/boot/execution-lane.js +32 -5
- package/dist/boot/late-binds.d.ts +8 -4
- package/dist/boot/late-binds.js +7 -1
- package/dist/boot/memory-consolidation.d.ts +3 -2
- package/dist/boot/memory-consolidation.js +6 -6
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/reapers.d.ts +5 -0
- package/dist/boot/reapers.js +12 -1
- package/dist/boot/resolve-spec.d.ts +7 -8
- package/dist/boot/resolve-spec.js +80 -35
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/runner-deps.d.ts +9 -2
- package/dist/boot/runner-deps.js +3 -3
- package/dist/boot/session-age-out.d.ts +36 -0
- package/dist/boot/session-age-out.js +101 -0
- package/dist/boot/session-faces.d.ts +5 -14
- package/dist/boot/session-faces.js +28 -24
- package/dist/boot/stage-01-config.js +2 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-05-execution-env.d.ts +5 -3
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +7 -4
- package/dist/boot/stage-06-runners.js +16 -8
- package/dist/boot/stage-07-capability-layer.d.ts +7 -4
- package/dist/boot/stage-07-capability-layer.js +3 -2
- package/dist/boot/stage-08-reapers.d.ts +7 -4
- package/dist/boot/stage-08-reapers.js +4 -2
- package/dist/boot/stage-09-leader.d.ts +11 -5
- package/dist/boot/stage-09-leader.js +12 -3
- package/dist/boot/stage-10-http-server.d.ts +44 -6
- package/dist/boot/stage-10-http-server.js +12 -10
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/boot/web-admin.js +3 -1
- package/dist/boot/workflow-orchestration.d.ts +7 -2
- package/dist/boot/workflow-orchestration.js +24 -7
- package/dist/bounded-rotation.d.ts +29 -0
- package/dist/bounded-rotation.js +24 -0
- package/dist/capability-facts.d.ts +84 -66
- package/dist/capability-facts.js +58 -41
- package/dist/center-credential.d.ts +25 -6
- package/dist/center-credential.js +25 -5
- package/dist/config-catalog.d.ts +26 -7
- package/dist/config-catalog.js +15 -12
- package/dist/config-invariants.d.ts +2 -1
- package/dist/config-invariants.js +4 -4
- package/dist/config-types.d.ts +22 -15
- package/dist/config.d.ts +51 -2
- package/dist/config.js +35 -24
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/deployment-shape.d.ts +9 -1
- package/dist/deployment-shape.js +2 -1
- package/dist/device-protocol.d.ts +5 -4
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +66 -29
- package/dist/device-ws-protocol.d.ts +79 -12
- package/dist/device-ws-protocol.js +64 -26
- package/dist/engine-identity.d.ts +23 -5
- package/dist/engine-identity.js +13 -0
- package/dist/entry-mode-clamp-notice.d.ts +2 -1
- package/dist/execution-env-refusal.d.ts +23 -0
- package/dist/execution-env-refusal.js +5 -0
- package/dist/execution-lane-caps.d.ts +3 -1
- package/dist/field-conflict.d.ts +3 -3
- package/dist/file-history-capture.d.ts +11 -4
- package/dist/file-history-capture.js +9 -6
- package/dist/file-history-disclosure.d.ts +7 -5
- package/dist/file-history-disclosure.js +7 -5
- package/dist/fleet/drain-entry.d.ts +4 -0
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/hooks/hook-runner.js +2 -2
- package/dist/host-lsp-manager.d.ts +2 -2
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +19 -4
- package/dist/http/approval-sweeps.js +7 -6
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +20 -63
- package/dist/http/checkpoint-ctx.js +2 -24
- package/dist/http/claim-heartbeat.d.ts +4 -4
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/dispatch.d.ts +2 -1
- package/dist/http/dispatch.js +36 -29
- package/dist/http/durable-run-leg.js +17 -17
- package/dist/http/health-self-report.d.ts +9 -1
- package/dist/http/health-self-report.js +2 -0
- package/dist/http/owner-access.d.ts +264 -20
- package/dist/http/owner-access.js +215 -5
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.js +38 -1
- package/dist/http/resume-legs.d.ts +2 -1
- package/dist/http/resume-legs.js +273 -89
- package/dist/http/route-ctx.d.ts +41 -19
- package/dist/http/route-table.d.ts +1 -1
- package/dist/http/routes/a2a-serve.js +15 -14
- package/dist/http/routes/admin-memory-optout.d.ts +1 -1
- package/dist/http/routes/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +12 -12
- package/dist/http/routes/background.d.ts +3 -3
- package/dist/http/routes/capabilities.js +10 -6
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/fleet.js +10 -8
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/projects.d.ts +4 -2
- package/dist/http/routes/projects.js +7 -6
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +125 -66
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.d.ts +4 -3
- package/dist/http/routes/session-sync.js +174 -83
- package/dist/http/routes/sessions-list.js +13 -7
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +26 -48
- package/dist/http/routes/tasks.js +38 -23
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +28 -30
- package/dist/http/server.js +7 -3
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +1 -2
- package/dist/http/submit-ctx.js +8 -6
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +19 -6
- package/dist/identity-source.d.ts +20 -3
- package/dist/identity-source.js +14 -0
- package/dist/index.d.ts +4 -0
- package/dist/lane-home-probe.d.ts +3 -7
- package/dist/lane-home-probe.js +0 -1
- package/dist/leader/endpoint.js +9 -8
- package/dist/leader/leader.d.ts +2 -1
- package/dist/leg-facts.d.ts +19 -5
- package/dist/leg-facts.js +3 -1
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-scope.d.ts +5 -4
- package/dist/memory-scope.js +4 -4
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/memory-sync-client.d.ts +30 -2
- package/dist/memory-sync-client.js +16 -9
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/err-text.d.ts +7 -0
- package/dist/observability/err-text.js +5 -0
- package/dist/observability/fail-open.d.ts +12 -8
- package/dist/observability/fail-open.js +12 -8
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/orchestration/workflow-notify-journal.d.ts +18 -1
- package/dist/orchestration/workflow-notify-journal.js +12 -1
- package/dist/orchestration/workflow-park-decision.d.ts +70 -18
- package/dist/orchestration/workflow-park-decision.js +49 -10
- package/dist/orchestration/workflow-park-holder.d.ts +65 -0
- package/dist/orchestration/workflow-park-holder.js +98 -0
- package/dist/orchestration/workflow-record-fence.d.ts +36 -0
- package/dist/orchestration/workflow-record-fence.js +42 -0
- package/dist/owner-faces.d.ts +28 -4
- package/dist/owner-faces.js +2 -0
- package/dist/parked-decide.d.ts +104 -53
- package/dist/parked-decide.js +153 -117
- package/dist/peer-directory.d.ts +2 -2
- package/dist/peer-inbound-face.d.ts +2 -6
- package/dist/peer-inbound-face.js +0 -3
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/permission-mode-admission.d.ts +41 -5
- package/dist/permission-mode-admission.js +29 -3
- package/dist/plugins/adoption-log-sql.d.ts +3 -1
- package/dist/plugins/adoption-log-sql.js +7 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +8 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +6 -1
- package/dist/plugins/approval-ask-store-memory.js +28 -9
- package/dist/plugins/approval-ask-store-sql.d.ts +43 -2
- package/dist/plugins/approval-ask-store-sql.js +34 -5
- package/dist/plugins/approval-exemption-store.js +3 -0
- package/dist/plugins/approval-nonce-store.js +2 -0
- package/dist/plugins/breaker-state-sql.js +2 -0
- package/dist/plugins/caching-session-store.d.ts +9 -15
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/device-store-sql.js +6 -0
- package/dist/plugins/error-origin.d.ts +18 -0
- package/dist/plugins/error-origin.js +10 -0
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/execution-placement-sql.js +6 -6
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/image-bake-store-sql.js +6 -0
- package/dist/plugins/image-index-sql.js +4 -0
- package/dist/plugins/landed-attendants.d.ts +212 -0
- package/dist/plugins/landed-attendants.js +161 -0
- package/dist/plugins/leader-run-store-sql.js +4 -0
- package/dist/plugins/local-checkpoint-store.d.ts +4 -1
- package/dist/plugins/local-checkpoint-store.js +3 -0
- package/dist/plugins/local-session-live-reference.d.ts +40 -0
- package/dist/plugins/local-session-live-reference.js +39 -0
- package/dist/plugins/local-session-store.d.ts +71 -33
- package/dist/plugins/local-session-store.js +129 -27
- package/dist/plugins/memory-engine-pg.js +4 -0
- package/dist/plugins/memory-engine-sql-apply.js +5 -2
- package/dist/plugins/memory-engine-tidb.js +4 -0
- package/dist/plugins/memory-optout-grant-store-sql.js +4 -0
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/memory-sync-store-pg.js +5 -0
- package/dist/plugins/memory-sync-store-tidb.js +5 -0
- package/dist/plugins/one-time-migrations.d.ts +80 -61
- package/dist/plugins/one-time-migrations.js +241 -104
- package/dist/plugins/org-delivery-quota-store.js +4 -1
- package/dist/plugins/outcome-ledger-sql.js +2 -0
- package/dist/plugins/permission-rule-store-sql.js +11 -4
- package/dist/plugins/pg-cost-quota.js +4 -0
- package/dist/plugins/pg-pool.js +28 -1
- package/dist/plugins/pg-rate-limiter.js +2 -0
- package/dist/plugins/posix-shell-fs.d.ts +6 -1
- package/dist/plugins/posix-shell-fs.js +8 -3
- package/dist/plugins/remote-env-adb.d.ts +19 -15
- package/dist/plugins/remote-env-adb.js +44 -17
- package/dist/plugins/remote-env-connect-seat.d.ts +105 -0
- package/dist/plugins/remote-env-connect-seat.js +72 -0
- package/dist/plugins/remote-env-device.d.ts +22 -5
- package/dist/plugins/remote-env-device.js +114 -14
- package/dist/plugins/remote-env-e2b.d.ts +18 -7
- package/dist/plugins/remote-env-e2b.js +53 -40
- package/dist/plugins/remote-env-file-error.js +6 -2
- package/dist/plugins/remote-env-host.d.ts +18 -1
- package/dist/plugins/remote-env-host.js +48 -47
- package/dist/plugins/remote-env-k8s.d.ts +41 -39
- package/dist/plugins/remote-env-k8s.js +56 -32
- package/dist/plugins/remote-env-local-docker.d.ts +13 -8
- package/dist/plugins/remote-env-local-docker.js +37 -43
- package/dist/plugins/remote-env-ssh.d.ts +18 -12
- package/dist/plugins/remote-env-ssh.js +64 -62
- package/dist/plugins/remote-shell.d.ts +101 -2
- package/dist/plugins/remote-shell.js +221 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/resume-anchor-store-sql.d.ts +11 -2
- package/dist/plugins/resume-anchor-store-sql.js +12 -5
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/retention-lane-store-sql.js +4 -0
- package/dist/plugins/retention-sql.d.ts +20 -2
- package/dist/plugins/retention-sql.js +11 -0
- package/dist/plugins/run-store-sql.d.ts +22 -3
- package/dist/plugins/run-store-sql.js +33 -9
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
- package/dist/plugins/schema-consistency.d.ts +9 -5
- package/dist/plugins/schema-consistency.js +48 -18
- package/dist/plugins/schema-drift-sentence.js +1 -1
- package/dist/plugins/send-file-ledger.js +3 -0
- package/dist/plugins/serving-requirement.d.ts +68 -0
- package/dist/plugins/serving-requirement.js +60 -0
- package/dist/plugins/session-birth.d.ts +6 -2
- package/dist/plugins/session-capture-record-store-sql.js +2 -0
- package/dist/plugins/session-ext-table.d.ts +14 -1
- package/dist/plugins/session-ext-table.js +5 -1
- package/dist/plugins/session-row-sql.d.ts +49 -2
- package/dist/plugins/session-row-sql.js +56 -13
- package/dist/plugins/session-store-sql.d.ts +34 -18
- package/dist/plugins/session-store-sql.js +98 -17
- package/dist/plugins/shared-memory-store-sql.d.ts +1 -0
- package/dist/plugins/shared-memory-store-sql.js +6 -2
- package/dist/plugins/sql-driver.d.ts +2 -1
- package/dist/plugins/sql-driver.js +18 -3
- package/dist/plugins/sql-errors.d.ts +11 -6
- package/dist/plugins/sql-errors.js +5 -6
- package/dist/plugins/stop-then-start-sentence.d.ts +48 -3
- package/dist/plugins/stop-then-start-sentence.js +48 -0
- package/dist/plugins/stop-then-start.d.ts +109 -0
- package/dist/plugins/stop-then-start.js +104 -0
- package/dist/plugins/store-backend.d.ts +40 -13
- package/dist/plugins/store-backend.js +169 -27
- package/dist/plugins/store-boundary.d.ts +57 -0
- package/dist/plugins/store-boundary.js +139 -0
- package/dist/plugins/store-contracts.d.ts +29 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/store-fault-sentence-m53.d.ts +7 -0
- package/dist/plugins/store-fault-sentence-m53.js +25 -0
- package/dist/plugins/store-fault.d.ts +26 -7
- package/dist/plugins/store-fault.js +18 -2
- package/dist/plugins/task-attachment-store.js +9 -0
- package/dist/plugins/task-list-store-sql.d.ts +2 -2
- package/dist/plugins/task-list-store-sql.js +10 -8
- package/dist/plugins/tidb-cost-quota.js +4 -0
- package/dist/plugins/tidb-pool.js +6 -1
- package/dist/plugins/tidb-rate-limiter.js +4 -0
- package/dist/plugins/user-input-ledger-sql.js +4 -0
- package/dist/plugins/workflow-run-store-sql.d.ts +28 -10
- package/dist/plugins/workflow-run-store-sql.js +64 -4
- package/dist/plugins/workspace-fill.d.ts +4 -7
- package/dist/plugins/workspace-fill.js +2 -1
- package/dist/plugins/write-behind-counter.js +5 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +64 -0
- package/dist/project-context.js +66 -0
- package/dist/project-registry.d.ts +46 -0
- package/dist/project-registry.js +44 -0
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +4 -0
- package/dist/request-value-closure.js +10 -0
- package/dist/run-acceptance.d.ts +3 -2
- package/dist/run-acceptance.js +4 -6
- package/dist/run-cancel-card.d.ts +1 -1
- package/dist/run-cancel-card.js +2 -1
- package/dist/run-local.js +1 -0
- package/dist/runs.d.ts +37 -8
- package/dist/runs.js +53 -12
- package/dist/runtime-governance.d.ts +5 -4
- package/dist/security.d.ts +31 -33
- package/dist/security.js +41 -7
- package/dist/server-secret-env.d.ts +12 -10
- package/dist/server-secret-env.js +24 -15
- package/dist/session-agent.d.ts +1 -10
- package/dist/session-agent.js +0 -6
- package/dist/session-bindings.d.ts +82 -0
- package/dist/session-bindings.js +18 -0
- package/dist/session-children-retire.d.ts +2 -2
- package/dist/session-children-retire.js +2 -6
- package/dist/session-deletion.d.ts +16 -1
- package/dist/session-error-wire.d.ts +3 -3
- package/dist/session-error-wire.js +3 -3
- package/dist/session-incarnation.d.ts +28 -4
- package/dist/session-incarnation.js +14 -2
- package/dist/session-kind.d.ts +57 -0
- package/dist/session-kind.js +22 -0
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-row.d.ts +21 -1
- package/dist/session-row.js +7 -1
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync-kernel.d.ts +24 -14
- package/dist/session-sync-kernel.js +3 -6
- package/dist/session-sync.d.ts +4 -98
- package/dist/session-sync.js +4 -74
- package/dist/session-titler.d.ts +10 -3
- package/dist/session-titler.js +19 -6
- package/dist/ssh-host-key.d.ts +5 -0
- package/dist/ssh-host-key.js +3 -0
- package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
- package/dist/stores-sql/checkpoint-store-sql.js +106 -18
- package/dist/stores-sql/file-history-store-sql.d.ts +52 -2
- package/dist/stores-sql/file-history-store-sql.js +108 -70
- package/dist/stores-sql/pg-session-storage.d.ts +34 -7
- package/dist/stores-sql/pg-session-storage.js +37 -13
- package/dist/stores-sql/retention-store-sql.d.ts +2 -10
- package/dist/stores-sql/retention-store-sql.js +2 -10
- package/dist/stores-sql/session-policy-store-sql.d.ts +30 -7
- package/dist/stores-sql/session-policy-store-sql.js +61 -44
- package/dist/stores-sql/session-write-hooks.d.ts +11 -0
- package/dist/stores-sql/tidb-session-store.d.ts +58 -7
- package/dist/stores-sql/tidb-session-store.js +37 -13
- package/dist/submission-exit.d.ts +3 -2
- package/dist/submission-exit.js +9 -1
- package/dist/task-cwd.d.ts +6 -5
- package/dist/task-settings.d.ts +19 -5
- package/dist/task-settings.js +13 -7
- package/dist/terminal.d.ts +33 -2
- package/dist/terminal.js +139 -9
- package/dist/tool-approval.d.ts +147 -12
- package/dist/tool-approval.js +206 -109
- package/dist/trace/engine-notice-wire.d.ts +14 -0
- package/dist/trace/engine-notice-wire.js +18 -1
- package/dist/trace/project.d.ts +4 -3
- package/dist/trace/project.js +3 -2
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/self-minted-wire.d.ts +422 -26
- package/dist/trace/self-minted-wire.js +149 -23
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +120 -41
- package/package.json +3 -3
- package/wire-changes/server@7.150.0.json +335 -0
- package/wire-changes/server@7.151.0.json +762 -0
- package/dist/http/session-inherit-env.d.ts +0 -36
- package/dist/http/session-inherit-env.js +0 -6
|
@@ -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);
|
|
@@ -423,7 +423,8 @@ export declare function connectJudged<R>(db: SqlDriver, judge: (facts: SqlEngine
|
|
|
423
423
|
* (`getConnection` → 守卫租约上执行 → 归还,被守卫销毁的不归还)。语句契约不变:参数原样到连接,结果是 mysql2 的 `[rows, fields]` 元组,`{ sql, timeout }` 对象形
|
|
424
424
|
* 一并支持(原样交给连接);池的其余成员(`end` / `execute` / `on` …)原样转给底池,返回底池自身的方法(`on` 之类)返回本包装体 —— 链式调用不会逃出守卫。
|
|
425
425
|
* 生产池(`createTidbPool`)恒是它;mysql2 自己的 `pool.query` 对只读类错误(1290 / 1792 / 1836)的销毁收在同一张表里({@link isConnectionUnusableError}),不丢。
|
|
426
|
-
* 不覆盖 `pool.execute`(预备语句:今天只有任务附件店一处,语句是小定长行,碰不到语句墙)
|
|
426
|
+
* 不覆盖 `pool.execute`(预备语句:今天只有任务附件店一处,语句是小定长行,碰不到语句墙)—— 它与其余原样转给底池的成员一样,只给拒绝打驱动出身记号。
|
|
427
|
+
* **驱动出身记号**(`error-origin.ts` 的 `driver` 一词)是这只池座的第二件事:借连接、守卫租约上的语句与事务动词、原样转给底池的承诺,它们的拒绝都打记号(只记,不改对象、不记日志、不改控制流)。
|
|
427
428
|
*/
|
|
428
429
|
export declare function createCloseAwarePool(pool: MySqlPool): MySqlPool;
|
|
429
430
|
/** MySQL-protocol driver (TiDB / MySQL / MariaDB — `dialect` is the SQL TEXT axis, `facts.engine` the
|
|
@@ -3,6 +3,8 @@ import { recordFailOpen } from "../observability/fail-open.js";
|
|
|
3
3
|
import { errorKindOf } from "../observability/err-text.js";
|
|
4
4
|
import { writeLogText } from "../observability/logger.js";
|
|
5
5
|
import { isConnectionUnusableError } from "./sql-errors.js";
|
|
6
|
+
import { markErrorOrigin } from "./error-origin.js";
|
|
7
|
+
import { storeBoundaryFault } from "../terminal.js";
|
|
6
8
|
export class SqlStatementDeadlineExceeded extends Error {
|
|
7
9
|
deadlineMs;
|
|
8
10
|
constructor(deadlineMs) {
|
|
@@ -245,7 +247,8 @@ async function initMySqlSession(c) {
|
|
|
245
247
|
await c.query("SET SESSION tidb_txn_mode = 'pessimistic'");
|
|
246
248
|
}
|
|
247
249
|
catch (err) {
|
|
248
|
-
|
|
250
|
+
storeBoundaryFault(err, "sql-driver.initMySqlSession");
|
|
251
|
+
throw refuseSession(`this TiDB session is in "${txnMode}" transaction mode and SET SESSION tidb_txn_mode='pessimistic' was rejected`);
|
|
249
252
|
}
|
|
250
253
|
txnMode = await mysqlVar(c, "SELECT @@tidb_txn_mode AS v");
|
|
251
254
|
if (txnMode !== "pessimistic") {
|
|
@@ -342,6 +345,7 @@ function leaseOf(raw) {
|
|
|
342
345
|
return await run();
|
|
343
346
|
}
|
|
344
347
|
catch (err) {
|
|
348
|
+
markErrorOrigin(err, "driver");
|
|
345
349
|
if (isConnectionUnusableError(err)) {
|
|
346
350
|
destroy();
|
|
347
351
|
BROKEN_LEASES.set(lease, { error: err });
|
|
@@ -375,7 +379,9 @@ function leaseOf(raw) {
|
|
|
375
379
|
return lease;
|
|
376
380
|
}
|
|
377
381
|
export function createCloseAwarePool(pool) {
|
|
378
|
-
const lend = async () => leaseOf(await pool.getConnection())
|
|
382
|
+
const lend = async () => leaseOf(await pool.getConnection().catch((err) => {
|
|
383
|
+
throw markErrorOrigin(err, "driver");
|
|
384
|
+
}));
|
|
379
385
|
const query = async (...args) => {
|
|
380
386
|
const c = await lend();
|
|
381
387
|
try {
|
|
@@ -396,12 +402,21 @@ export function createCloseAwarePool(pool) {
|
|
|
396
402
|
return member;
|
|
397
403
|
return (...args) => {
|
|
398
404
|
const result = member.apply(target, args);
|
|
399
|
-
|
|
405
|
+
if (result === target)
|
|
406
|
+
return wrapper;
|
|
407
|
+
return isThenable(result)
|
|
408
|
+
? result.then(undefined, (err) => {
|
|
409
|
+
throw markErrorOrigin(err, "driver");
|
|
410
|
+
})
|
|
411
|
+
: result;
|
|
400
412
|
};
|
|
401
413
|
},
|
|
402
414
|
});
|
|
403
415
|
return wrapper;
|
|
404
416
|
}
|
|
417
|
+
function isThenable(v) {
|
|
418
|
+
return v !== null && (typeof v === "object" || typeof v === "function") && typeof v.then === "function";
|
|
419
|
+
}
|
|
405
420
|
export function mysqlDriver(pool) {
|
|
406
421
|
const session = poolSession(pool);
|
|
407
422
|
return {
|
|
@@ -109,7 +109,13 @@ export declare function isDeadlockError(dialect: SqlDialect, err: unknown): bool
|
|
|
109
109
|
/** 引擎仲裁之后整段重来的**唯一**上界(全仓每一条「撞死锁就重来」的腿共用这一个数)。8 = 锁形并发套的并发度:缺行首写的 N 路竞争每轮至多多走一轮([ref] 读数 1 成 7 死锁)。 */
|
|
110
110
|
export declare const DEADLOCK_RETRY_LIMIT = 8;
|
|
111
111
|
/**
|
|
112
|
-
*
|
|
112
|
+
* 语句源在一只**别人开的**事务里输了仲裁(例:文件历史的 scope 哨兵在锁读那一刻物理消失)—— 它不许自己回滚重开那只事务(段首的锁与判会随之丢掉),
|
|
113
|
+
* 只抛这一只;{@link retryOnDeadlock} 把它与死锁同读,从事务主人的段首整段重来(落定段、店自己的图事务同一条)。
|
|
114
|
+
*/
|
|
115
|
+
export declare class SqlArbitrationLostError extends Error {
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 「引擎判了死锁 ⇒ 整段重来」的**唯一**写法:有界({@link DEADLOCK_RETRY_LIMIT}),判据 {@link isDeadlockError} ∪ {@link SqlArbitrationLostError};用尽 / 其它错误原样抛。
|
|
113
119
|
* `attempt` 必须整段重做语义等价(读-判-写全在里面的一只事务,或一条幂等语句)。`alsoArbitrated`:店自己认的另一种仲裁产物(例:缺行首写撞主键 ——
|
|
114
120
|
* 并发的另一只首写赢了,重读即走更新腿),与死锁同族、同一个上界。锁等待超时不在任何一族里(延迟信号,见 {@link isDeadlockError} 的注):它照抛。
|
|
115
121
|
*/
|
|
@@ -241,17 +247,16 @@ export declare function isDeploymentFaultError(err: unknown): boolean;
|
|
|
241
247
|
*/
|
|
242
248
|
export declare function databaseAnswerCodesOf(dialect: SqlDialect, err: unknown): string | undefined;
|
|
243
249
|
/**
|
|
244
|
-
* 检查点店的两笔写(续跑输入 `putCtx` / 停驻行 `put`)被引擎以「一行装不下」拒 ⇒ **这一只**带码错误(码 `store.row_too_large`)
|
|
245
|
-
* (
|
|
246
|
-
*
|
|
247
|
-
* `
|
|
250
|
+
* 检查点店的两笔写(续跑输入 `putCtx` / 停驻行 `put`)被引擎以「一行装不下」拒 ⇒ **这一只**带码错误(码 `store.row_too_large`),不以驱动错上抛。
|
|
251
|
+
* `row` = 哪一张表的哪一格、为谁写(进句子);`wall` = 拒它的那堵墙({@link rowTooLargeWallOf} 的读数;提交腿按它选 413 的出路)。
|
|
252
|
+
* 句子是本仓的固定句,**不带**库的原句(店的出口只带原码 + 稳定句);库的那句(TiDB 的句子带上限与这一行的实际字节数)挂在 `cause` 上 ——
|
|
253
|
+
* 它出店时由店边界(`terminal.ts` 的 `storeBoundaryFault`:带词法内码的 typed 错原样过,`cause` 链上的驱动错就地换成边界形)记进 `at=store` 那一行、换成边界形。
|
|
248
254
|
* 提交腿把它答成 413 `request.payload_too_large`(`http/submit-ctx.ts`);停驻那一拍它经引擎的错误座落进运维日志。
|
|
249
255
|
*/
|
|
250
256
|
export declare class StoreRowTooLargeError extends Error {
|
|
251
257
|
readonly row: string;
|
|
252
258
|
readonly wall: RowTooLargeWall;
|
|
253
259
|
readonly code: "store.row_too_large";
|
|
254
|
-
readonly dbMessage: string;
|
|
255
260
|
constructor(row: string, cause: unknown, wall: RowTooLargeWall);
|
|
256
261
|
}
|
|
257
262
|
/** 店写口的翻译:{@link rowTooLargeWallOf} 认得出 ⇒ {@link StoreRowTooLargeError}(带那堵墙);其余原样交回(调用方 `throw` 它)。 */
|
|
@@ -55,13 +55,15 @@ export function isDeadlockError(dialect, err) {
|
|
|
55
55
|
return keyOf(err, "errno") === MYSQL_ER_LOCK_DEADLOCK_ERRNO || keyOf(err, "code") === MYSQL_ER_LOCK_DEADLOCK_CODE;
|
|
56
56
|
}
|
|
57
57
|
export const DEADLOCK_RETRY_LIMIT = 8;
|
|
58
|
+
export class SqlArbitrationLostError extends Error {
|
|
59
|
+
}
|
|
58
60
|
export async function retryOnDeadlock(dialect, attempt, alsoArbitrated) {
|
|
59
61
|
for (let tries = 0;; tries++) {
|
|
60
62
|
try {
|
|
61
63
|
return await attempt();
|
|
62
64
|
}
|
|
63
65
|
catch (err) {
|
|
64
|
-
if (tries < DEADLOCK_RETRY_LIMIT && (isDeadlockError(dialect, err) || alsoArbitrated?.(err) === true))
|
|
66
|
+
if (tries < DEADLOCK_RETRY_LIMIT && (isDeadlockError(dialect, err) || err instanceof SqlArbitrationLostError || alsoArbitrated?.(err) === true))
|
|
65
67
|
continue;
|
|
66
68
|
throw err;
|
|
67
69
|
}
|
|
@@ -214,16 +216,13 @@ export class StoreRowTooLargeError extends Error {
|
|
|
214
216
|
row;
|
|
215
217
|
wall;
|
|
216
218
|
code = "store.row_too_large";
|
|
217
|
-
dbMessage;
|
|
218
219
|
constructor(row, cause, wall) {
|
|
219
|
-
|
|
220
|
-
super(`${row} was refused by the database: the row is larger than the database stores in one row (${dbMessage}). ` +
|
|
220
|
+
super(`${row} was refused by the database: the row is larger than the database stores in one row. ` +
|
|
221
221
|
"Shrink what the request carries inline (images / userAttachments), or raise the database's single-row limit " +
|
|
222
|
-
"(TiDB: performance.txn-entry-size-limit, or the tidb_txn_entry_size_limit variable on TiDB 7.6+; MySQL / MariaDB: max_allowed_packet)");
|
|
222
|
+
"(TiDB: performance.txn-entry-size-limit, or the tidb_txn_entry_size_limit variable on TiDB 7.6+; MySQL / MariaDB: max_allowed_packet)", { cause });
|
|
223
223
|
this.row = row;
|
|
224
224
|
this.wall = wall;
|
|
225
225
|
this.name = "StoreRowTooLargeError";
|
|
226
|
-
this.dbMessage = dbMessage;
|
|
227
226
|
}
|
|
228
227
|
}
|
|
229
228
|
export function rowTooLargeOrSelf(dialect, err, row) {
|
|
@@ -2,15 +2,60 @@
|
|
|
2
2
|
* 「停-迁-起」那一段的**唯一属主**。
|
|
3
3
|
*
|
|
4
4
|
* 一次性迁移里有几条(登记表 `stopThenStart` 一格点名的)改的是更早版本的副本还会继续写的形:改完之后它再写一笔,这一笔读不出 / 丢掉。它们没有运行期开关,
|
|
5
|
-
*
|
|
5
|
+
* 起服时由守卫段判 —— 库上有「不知道这条迁移的副本还在服务」的证据 ⇒ 拒启、一字节不写。证据只有一种读法(`stop-then-start.ts` 的 `readOlderReplicaEvidence`):
|
|
6
|
+
* 判活窗内(`REAP_RUN_STALE_SEC`,收割器判 run 持有者还活着的同一个窗)心跳过的 `running` run,持有者没有登记为知道这条迁移(`replica-registration.ts`)。
|
|
6
7
|
* 四只守卫(M40 · M41 · M42 · M51)的拒句和起服列册对账的升级清单**说同一件事**:先停光更早版本的副本、等满判活窗、再起本版。
|
|
7
|
-
*
|
|
8
|
+
* 这件事的句子只在这里写一遍:证据一段({@link olderReplicaEvidenceSentence})与动作一段({@link stopThenStartAction});各守卫只讲「为什么这一条要停」。
|
|
9
|
+
* 起服准入(`serving-requirement.ts`:库上记着本构建没有的能力 ⇒ 拒启)的拒句同属这一族,也在这里({@link servingRequirementUnmetSentence});
|
|
10
|
+
* 起服拒句升级清单里「这只库要求本构建没有的能力」一步的句子同在这里({@link unmetRequirementChecklistStep})。
|
|
8
11
|
*
|
|
9
|
-
* 叶子模块:零 import(
|
|
12
|
+
* 叶子模块:零 import(守卫段、各条的拒句、M42 的拒句文件、起服准入与列册对账都静态 import 它,不成环)。
|
|
10
13
|
*/
|
|
14
|
+
/** 证据里一只登记过、却没有这条迁移能力的持有者(归因用:点名它是谁)。 */
|
|
15
|
+
export interface OlderReplicaHolder {
|
|
16
|
+
readonly instanceId: string;
|
|
17
|
+
readonly releaseLine: string;
|
|
18
|
+
readonly hostName: string;
|
|
19
|
+
readonly pid: number;
|
|
20
|
+
/** 它持有的、判活窗内心跳过的 `running` run 数。 */
|
|
21
|
+
readonly runs: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 停-迁-起守卫的证据(纯数据):判活窗内心跳过、持有者没有登记为知道 {@link migration} 的 `running` run。
|
|
25
|
+
* 登记为知道它的持有者的 run 不在这里(它们不是旧形写者);登记只作归因,不判活。
|
|
26
|
+
*/
|
|
27
|
+
export interface OlderReplicaEvidence {
|
|
28
|
+
readonly migration: string;
|
|
29
|
+
/** 算进证据的 run 总数(= {@link unregisteredRuns} + 各 {@link registeredWithout} 的 `runs`)。 */
|
|
30
|
+
readonly liveRuns: number;
|
|
31
|
+
readonly windowSec: number;
|
|
32
|
+
/** 全停之后可以再起的最早时刻(ISO;= 最新心跳 + 判活窗;读不出最新心跳 ⇒ 现在 + 窗,上界)。 */
|
|
33
|
+
readonly restartAfter: string;
|
|
34
|
+
/** 同一时刻的人读形(带「离现在还有几秒」)。 */
|
|
35
|
+
readonly after: string;
|
|
36
|
+
/** 持有者没有登记行(或没有持有者)的 run 数。 */
|
|
37
|
+
readonly unregisteredRuns: number;
|
|
38
|
+
/** 登记了而能力名单里没有这条迁移的持有者,逐只点名。 */
|
|
39
|
+
readonly registeredWithout: readonly OlderReplicaHolder[];
|
|
40
|
+
}
|
|
41
|
+
/** 证据一段(各守卫拒句与 M43 的读数共用;句子不含时刻 —— 时刻在动作段)。 */
|
|
42
|
+
export declare function olderReplicaEvidenceSentence(e: OlderReplicaEvidence): string;
|
|
11
43
|
/**
|
|
12
44
|
* 动作段:停光 → 等窗 → 再起。`after` = 全停之后可以再起的最早时刻(守卫读到的最新心跳 + 判活窗,人读形);
|
|
13
45
|
* 缺席 ⇒ 读不到具体心跳(列册对账的清单:此刻没有守卫在判),只说「等满判活窗」。
|
|
14
46
|
*/
|
|
15
47
|
export declare function stopThenStartAction(after?: string): string;
|
|
48
|
+
/** 起服准入里一行本构建没有的要求(`state` = 判读的态,词表外的词读作 `in_force`;`word` = 库里存的原词)。 */
|
|
49
|
+
export interface UnmetServingRequirement {
|
|
50
|
+
readonly migration: string;
|
|
51
|
+
readonly state: "in_force";
|
|
52
|
+
readonly word: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 起服拒句**升级清单**里的那一步(排在 `ALTER` 一步之前;多行,第一行是步骤首句):这只库要求本构建没有的能力 —— 照清单补完语句也不会让本构建能在这里服务。
|
|
56
|
+
* `unmet` 空 ⇒ 调用方不出这一步。`unreadable` 在 ⇒ 读要求表抛了:照出这一步并如实说没读到(多停一次,不漏停)。
|
|
57
|
+
*/
|
|
58
|
+
export declare function unmetRequirementChecklistStep(unmet: readonly UnmetServingRequirement[], unreadable?: string): string[];
|
|
59
|
+
/** 起服准入的拒句(`reason` 闭集两词;码由调用方交,本模块零 import)。 */
|
|
60
|
+
export declare function servingRequirementUnmetSentence(code: string, reason: "capability_missing" | "table_absent", unmet: readonly UnmetServingRequirement[], absentTables: readonly string[], releaseLine: string): string;
|
|
16
61
|
//# sourceMappingURL=stop-then-start-sentence.d.ts.map
|
|
@@ -1,7 +1,55 @@
|
|
|
1
|
+
export function olderReplicaEvidenceSentence(e) {
|
|
2
|
+
const parts = [];
|
|
3
|
+
if (e.unregisteredRuns > 0)
|
|
4
|
+
parts.push(`${e.unregisteredRuns} by replicas with no registration on this database (a release that predates replica registration, or a process that skipped the start sequence)`);
|
|
5
|
+
for (const h of e.registeredWithout)
|
|
6
|
+
parts.push(`${h.runs} by instance ${h.instanceId} (release ${h.releaseLine}, host ${h.hostName}, pid ${h.pid}), registered without it`);
|
|
7
|
+
return (`${e.liveRuns} running run(s) on this database heartbeated within the last ${e.windowSec}s (REAP_RUN_STALE_SEC), held by replicas not registered as knowing one-time migration ${e.migration}` +
|
|
8
|
+
` (${parts.join("; ")})`);
|
|
9
|
+
}
|
|
1
10
|
export function stopThenStartAction(after) {
|
|
2
11
|
return ("Stop every replica of the earlier version, then start this version (stop, migrate, start — this release cannot be rolled across replicas of both versions). " +
|
|
3
12
|
(after === undefined
|
|
4
13
|
? "Wait out the heartbeat window (REAP_RUN_STALE_SEC) after the last replica stops, then start this version."
|
|
5
14
|
: `If every replica is already stopped, those are the runs they left behind: start this version again after ${after}`));
|
|
6
15
|
}
|
|
16
|
+
function requirementClause(r) {
|
|
17
|
+
switch (r.state) {
|
|
18
|
+
case "in_force":
|
|
19
|
+
return r.word === "in_force"
|
|
20
|
+
? `${r.migration} (in force: a build that has it was admitted on this database and may have changed data for it)`
|
|
21
|
+
: `${r.migration} (state "${r.word}", which this build does not know — read as in force)`;
|
|
22
|
+
default: {
|
|
23
|
+
const unhandled = r.state;
|
|
24
|
+
throw new Error(`stop-then-start-sentence: unknown requirement state ${String(unhandled)}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const rollbackDelete = (migration) => `DELETE FROM serving_requirement WHERE migration_id = '${migration}';`;
|
|
29
|
+
export function unmetRequirementChecklistStep(unmet, unreadable) {
|
|
30
|
+
if (unreadable !== undefined) {
|
|
31
|
+
return [`Whether this database requires a capability this build lacks could not be read (${unreadable}); read serving_requirement before going on — a row this build does not have means it must not serve here.`];
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
`This database requires every serving replica to have ${unmet.map(requirementClause).join(", ")}; this build does not, and must not serve on it — the statements below do not make it safe.`,
|
|
35
|
+
`Start a build that has ${unmet.map((r) => r.migration).join(", ")} instead. Only to roll back on purpose, after handling the data of that migration: ${unmet.map((r) => rollbackDelete(r.migration)).join(" ")}`,
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
export function servingRequirementUnmetSentence(code, reason, unmet, absentTables, releaseLine) {
|
|
39
|
+
switch (reason) {
|
|
40
|
+
case "capability_missing":
|
|
41
|
+
return (`${code} (reason: capability_missing): this database requires every serving replica to have ${unmet.map(requirementClause).join(", ")}; this build (release ${releaseLine}) does not. ` +
|
|
42
|
+
"No one-time migration ran and no stored data was changed (the section head only registered this replica and removed registrations of other replicas older than 90 days). " +
|
|
43
|
+
`Start a build that has ${unmet.map((r) => r.migration).join(", ")}. ` +
|
|
44
|
+
`Only to roll back on purpose, after handling the data of that migration: ${unmet.map((r) => rollbackDelete(r.migration)).join(" ")}`);
|
|
45
|
+
case "table_absent":
|
|
46
|
+
return (`${code} (reason: table_absent): this database has no ${absentTables.join(" / ")} table — the serving requirements recorded there cannot be read, ` +
|
|
47
|
+
'and an unreadable requirement is not "no requirement", so this build refuses to start. Nothing was written. ' +
|
|
48
|
+
"Open the store with the public sequence createStoreBackend() → ensureSchema() → runOneTimeMigrations(): ensureSchema() creates these tables.");
|
|
49
|
+
default: {
|
|
50
|
+
const unhandled = reason;
|
|
51
|
+
throw new Error(`stop-then-start-sentence: unknown refusal reason ${String(unhandled)}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
7
55
|
//# sourceMappingURL=stop-then-start-sentence.js.map
|