@sema-agent/server 7.145.0 → 7.147.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 +876 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +374 -99
- package/deploy/facts/CHANGES.json +25 -0
- package/deploy/facts/README.md +57 -0
- package/deploy/facts/lanes.json +61 -0
- package/deploy/facts/lanes.schema.json +57 -0
- package/deploy/facts/sandbox-rbac.json +113 -0
- package/deploy/facts/sandbox-rbac.schema.json +74 -0
- package/deploy/facts/sealed-key.json +9 -0
- package/deploy/facts/sealed-key.schema.json +52 -0
- package/deploy/sema-up/README.md +2 -2
- package/deploy/sema-up/chart/templates/_helpers.tpl +41 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +9 -4
- package/deploy/sema-up/chart/templates/server.yaml +9 -4
- package/deploy/sema-up/chart/values.yaml +8 -1
- package/deploy/sema-up/cluster-up.sh +2 -1
- package/deploy/sema-up/lib/flagshape.sh +4 -0
- package/deploy/sema-up/lib/lanes.json +2 -5
- package/deploy/sema-up/sema-up.sh +12 -9
- package/deploy/sema-up/stack/compose.yaml +5 -4
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +34 -17
- package/dist/adoption/import-limits.d.ts +6 -0
- package/dist/adoption/import-limits.js +7 -0
- package/dist/adoption/import.d.ts +62 -0
- package/dist/adoption/import.js +107 -0
- package/dist/adoption/wire.d.ts +52 -0
- package/dist/adoption/wire.js +9 -0
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +7 -16
- package/dist/approval-card.js +0 -4
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-gate-currency.js +1 -1
- package/dist/approval-reconciler.d.ts +1 -1
- package/dist/approval.d.ts +3 -3
- package/dist/audit.js +2 -2
- package/dist/bench/s1/live-deps.js +3 -1
- package/dist/boot/crash-last.js +2 -1
- package/dist/boot/deployment-mods.d.ts +11 -1
- package/dist/boot/deployment-mods.js +15 -2
- package/dist/boot/device-lane.js +7 -5
- package/dist/boot/engine-lease.d.ts +195 -22
- package/dist/boot/engine-lease.js +146 -20
- package/dist/boot/execution-env.d.ts +5 -0
- package/dist/boot/execution-env.js +57 -33
- package/dist/boot/execution-lane.d.ts +37 -9
- package/dist/boot/execution-lane.js +74 -20
- package/dist/boot/exit-boundary.d.ts +50 -0
- package/dist/boot/exit-boundary.js +32 -0
- package/dist/boot/exit-last.d.ts +20 -4
- package/dist/boot/exit-last.js +23 -5
- package/dist/boot/governance-seams.d.ts +2 -2
- package/dist/boot/governance-seams.js +1 -0
- package/dist/boot/leader.js +1 -1
- package/dist/boot/memory-boundary.d.ts +11 -11
- package/dist/boot/memory-boundary.js +3 -3
- package/dist/boot/memory-consolidation.d.ts +42 -41
- package/dist/boot/memory-consolidation.js +26 -28
- package/dist/boot/org-memory.js +3 -2
- package/dist/boot/parked-revive-gate.d.ts +1 -1
- package/dist/boot/parked-revive-gate.js +1 -1
- package/dist/boot/reapers.d.ts +12 -4
- package/dist/boot/reapers.js +40 -16
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +126 -123
- package/dist/boot/retention-lane.d.ts +4 -42
- package/dist/boot/runner-deps.js +1 -1
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +11 -3
- package/dist/boot/shutdown.js +27 -9
- package/dist/boot/stage-01-config.d.ts +1 -1
- package/dist/boot/stage-01-config.js +7 -3
- package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
- package/dist/boot/stage-02-web-admin-pull.js +10 -8
- package/dist/boot/stage-03-store-backend.d.ts +2 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +2 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -1
- package/dist/boot/stage-05-execution-env.js +6 -6
- package/dist/boot/stage-06-runners.d.ts +5 -2
- package/dist/boot/stage-06-runners.js +12 -13
- package/dist/boot/stage-07-capability-layer.d.ts +5 -2
- package/dist/boot/stage-07-capability-layer.js +7 -7
- package/dist/boot/stage-08-reapers.d.ts +5 -2
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +6 -2
- package/dist/boot/stage-10-http-server.d.ts +6 -2
- package/dist/boot/stage-10-http-server.js +5 -3
- package/dist/boot/stores.d.ts +10 -0
- package/dist/boot/stores.js +53 -26
- package/dist/boot/web-admin.js +3 -3
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/capabilities/center-plugins.d.ts +2 -0
- package/dist/capabilities/center-plugins.js +6 -2
- package/dist/capabilities/composite-members.d.ts +4 -1
- package/dist/capabilities/composite-members.js +4 -1
- package/dist/capabilities/execution-lane.d.ts +7 -7
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +1 -1
- package/dist/capabilities/scenarios.d.ts +34 -20
- package/dist/capabilities/scenarios.js +13 -9
- package/dist/capabilities/settings-contract.d.ts +29 -0
- package/dist/capabilities/settings-contract.js +14 -0
- package/dist/capabilities/skills.d.ts +5 -5
- package/dist/capability-facts.d.ts +56 -1
- package/dist/capability-facts.js +59 -8
- package/dist/center-credential-renewer.js +3 -2
- package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
- package/dist/config-catalog.js +19 -9
- package/dist/config-invariants.d.ts +18 -3
- package/dist/config-invariants.js +36 -19
- package/dist/config-lkg.d.ts +1 -1
- package/dist/config-lkg.js +5 -6
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-provider.js +2 -0
- package/dist/config-types.d.ts +228 -185
- package/dist/config.d.ts +74 -6
- package/dist/config.js +146 -64
- package/dist/degenerate-instrument.js +1 -1
- package/dist/deleted-session-ids.d.ts +19 -0
- package/dist/deleted-session-ids.js +26 -0
- package/dist/deploy-facts.d.ts +155 -0
- package/dist/deploy-facts.js +95 -0
- package/dist/deployment-shape.d.ts +21 -12
- package/dist/deployment-shape.js +24 -6
- package/dist/device-ws-hub.d.ts +48 -3
- package/dist/device-ws-hub.js +48 -2
- package/dist/env-facts.d.ts +7 -5
- package/dist/env-facts.js +10 -6
- package/dist/error-code-family.d.ts +35 -0
- package/dist/error-code-family.js +26 -0
- package/dist/execution-config-root.d.ts +5 -5
- package/dist/execution-config-root.js +5 -5
- package/dist/execution-env-purpose.d.ts +14 -0
- package/dist/execution-env-purpose.js +29 -0
- package/dist/execution-lane-caps.d.ts +49 -86
- package/dist/execution-lane-caps.js +52 -62
- package/dist/execution-placement.d.ts +18 -2
- package/dist/execution-placement.js +19 -0
- package/dist/file-history-disclosure.d.ts +2 -2
- package/dist/fleet/drain-entry.d.ts +46 -3
- package/dist/fleet/drain-entry.js +6 -0
- package/dist/fleet/fleet-bus.d.ts +2 -1
- package/dist/fleet/serving-lease.js +3 -4
- package/dist/history-anchor.d.ts +22 -0
- package/dist/history-anchor.js +14 -0
- package/dist/hooks/branch-transcript.d.ts +1 -1
- package/dist/hooks/branch-transcript.js +1 -0
- package/dist/hooks/classic-stations.d.ts +25 -8
- package/dist/hooks/classic-stations.js +29 -3
- package/dist/hooks/command-spawn.d.ts +1 -4
- package/dist/hooks/command-spawn.js +0 -11
- package/dist/hooks/hook-runner.d.ts +85 -24
- package/dist/hooks/hook-runner.js +326 -109
- package/dist/hooks/hook-source.d.ts +14 -2
- package/dist/hooks/hook-source.js +8 -0
- package/dist/http/active-run-conflict.d.ts +1 -1
- package/dist/http/active-run-conflict.js +1 -1
- package/dist/http/admission.js +11 -1
- package/dist/http/approval-sweeps.d.ts +2 -5
- package/dist/http/approval-sweeps.js +3 -2
- package/dist/http/checkpoint-ctx.d.ts +76 -71
- package/dist/http/checkpoint-ctx.js +40 -40
- package/dist/http/claim-latency.d.ts +10 -0
- package/dist/http/claim-latency.js +12 -0
- package/dist/http/dispatch.js +19 -3
- package/dist/http/durable-run-leg.d.ts +5 -0
- package/dist/http/durable-run-leg.js +3 -1
- package/dist/http/execution-context.d.ts +7 -1
- package/dist/http/execution-context.js +13 -0
- package/dist/http/health-self-report.d.ts +6 -2
- package/dist/http/health-self-report.js +3 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +2 -2
- package/dist/http/memory-compliance-failure-reply.js +5 -15
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
- package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
- package/dist/http/memory-store-refusal-reply.d.ts +3 -3
- package/dist/http/memory-store-refusal-reply.js +3 -0
- package/dist/http/owner-access.d.ts +11 -0
- package/dist/http/owner-access.js +7 -4
- package/dist/http/principal-gate.d.ts +28 -16
- package/dist/http/principal-gate.js +10 -19
- package/dist/http/request-guards.d.ts +2 -2
- package/dist/http/request-guards.js +5 -5
- package/dist/http/resume-legs.d.ts +29 -10
- package/dist/http/resume-legs.js +94 -56
- package/dist/http/rewind-files-reply.d.ts +34 -0
- package/dist/http/rewind-files-reply.js +36 -0
- package/dist/http/route-ctx.d.ts +43 -26
- package/dist/http/route-table.js +4 -0
- package/dist/http/routes/adoption.d.ts +11 -0
- package/dist/http/routes/adoption.js +80 -6
- package/dist/http/routes/agents-roster.js +1 -0
- package/dist/http/routes/approvals-assistant.js +7 -26
- package/dist/http/routes/background.js +1 -0
- package/dist/http/routes/capabilities.js +12 -3
- package/dist/http/routes/devices.js +1 -1
- package/dist/http/routes/diagnostics.d.ts +9 -14
- package/dist/http/routes/diagnostics.js +10 -20
- package/dist/http/routes/engine.d.ts +31 -0
- package/dist/http/routes/engine.js +81 -0
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-consolidation.js +3 -5
- package/dist/http/routes/memory-origin.d.ts +2 -2
- package/dist/http/routes/memory-origin.js +2 -4
- package/dist/http/routes/memory-policy.js +5 -1
- package/dist/http/routes/notify-wake.js +2 -1
- package/dist/http/routes/observability.js +3 -6
- package/dist/http/routes/projects.d.ts +70 -0
- package/dist/http/routes/projects.js +86 -0
- package/dist/http/routes/rules.js +30 -2
- package/dist/http/routes/runs.js +15 -11
- package/dist/http/routes/session-sync.js +39 -35
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.d.ts +7 -1
- package/dist/http/routes/sessions.js +108 -2
- package/dist/http/routes/tasks.js +32 -8
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/run-concurrency-cap.d.ts +86 -0
- package/dist/http/run-concurrency-cap.js +54 -0
- package/dist/http/server.d.ts +31 -14
- package/dist/http/server.js +29 -3
- package/dist/http/stored-body-replay.d.ts +12 -7
- package/dist/http/stored-body-replay.js +28 -5
- package/dist/http/wire-types.d.ts +27 -13
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/instruction-source-notice.d.ts +1 -1
- package/dist/json-body-limit.d.ts +8 -0
- package/dist/json-body-limit.js +2 -0
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/local-data-root.d.ts +2 -2
- package/dist/memory-embedder-reembed.d.ts +38 -0
- package/dist/memory-embedder-reembed.js +20 -0
- package/dist/memory-incident-sink.d.ts +0 -28
- package/dist/memory-incident-sink.js +5 -0
- package/dist/memory-operator-faces.d.ts +9 -4
- package/dist/memory-scope-stores.d.ts +9 -7
- package/dist/memory-scope-stores.js +3 -14
- package/dist/memory-scope.d.ts +38 -2
- package/dist/memory-scope.js +33 -2
- package/dist/memory-store-refusal.d.ts +17 -4
- package/dist/memory-store-refusal.js +1 -1
- package/dist/memory-sync-client.d.ts +2 -0
- package/dist/memory-sync-client.js +13 -11
- package/dist/memory-sync.js +1 -1
- package/dist/model-compat.d.ts +35 -21
- package/dist/model-compat.js +49 -21
- package/dist/model-entry-refusal.d.ts +11 -1
- package/dist/model-entry-refusal.js +7 -0
- package/dist/namespaced-rule-name.d.ts +18 -1
- package/dist/namespaced-rule-name.js +12 -0
- package/dist/net-address.d.ts +53 -0
- package/dist/net-address.js +111 -0
- package/dist/observability/fail-open.d.ts +29 -17
- package/dist/observability/fail-open.js +29 -17
- package/dist/observability/metrics.d.ts +2 -0
- package/dist/observability/metrics.js +2 -0
- package/dist/observability/secret-env-scrub.d.ts +30 -4
- package/dist/observability/secret-env-scrub.js +15 -3
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
- package/dist/orchestration/workflow-agent-session-index.js +1 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
- package/dist/orchestration/workflow-completion-inbox.js +63 -45
- package/dist/orchestration/workflow-notify-journal.js +2 -3
- package/dist/org-delivery-gate.js +1 -1
- package/dist/org-memory-admission.d.ts +5 -2
- package/dist/org-memory-admission.js +25 -10
- package/dist/parked-decide.d.ts +33 -26
- package/dist/parked-decide.js +36 -44
- package/dist/peer-directory.d.ts +6 -12
- package/dist/peer-directory.js +5 -1
- package/dist/plugins/approval-ask-store-file.d.ts +10 -2
- package/dist/plugins/approval-ask-store-file.js +37 -4
- package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
- package/dist/plugins/approval-ask-store-memory.js +11 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
- package/dist/plugins/approval-ask-store-sql.js +3 -1
- package/dist/plugins/blob-backend.d.ts +38 -195
- package/dist/plugins/blob-backend.js +33 -229
- package/dist/plugins/caching-session-store.d.ts +12 -5
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
- package/dist/plugins/checkpoint-index-columns.js +3 -2
- package/dist/plugins/checkpoint-store-face.d.ts +426 -0
- package/dist/plugins/checkpoint-store-face.js +152 -0
- package/dist/plugins/device-store-sql.d.ts +2 -2
- package/dist/plugins/device-store-sql.js +5 -10
- package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
- package/dist/plugins/execution-lane-rename-m40.js +10 -0
- package/dist/plugins/execution-placement-sql.d.ts +63 -88
- package/dist/plugins/execution-placement-sql.js +94 -54
- package/dist/plugins/file-run-store.d.ts +26 -18
- package/dist/plugins/file-run-store.js +64 -75
- package/dist/plugins/fork-routing-session-store.d.ts +6 -2
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/imported-layer-root-retirement.d.ts +22 -11
- package/dist/plugins/imported-layer-root-retirement.js +4 -8
- package/dist/plugins/inbox-payload-column.d.ts +14 -0
- package/dist/plugins/inbox-payload-column.js +13 -0
- package/dist/plugins/local-checkpoint-store.d.ts +7 -2
- package/dist/plugins/local-checkpoint-store.js +13 -8
- package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
- package/dist/plugins/local-data-dir-modes-m39.js +182 -0
- package/dist/plugins/local-engine-high-water.d.ts +11 -0
- package/dist/plugins/local-engine-high-water.js +59 -0
- package/dist/plugins/local-session-store.d.ts +119 -30
- package/dist/plugins/local-session-store.js +156 -53
- package/dist/plugins/local-task-attachment-store.d.ts +2 -0
- package/dist/plugins/local-task-attachment-store.js +10 -11
- package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
- package/dist/plugins/memory-embedder-fingerprint.js +52 -12
- package/dist/plugins/memory-embedder.d.ts +1 -1
- package/dist/plugins/memory-embedder.js +2 -2
- package/dist/plugins/memory-engine-pg.d.ts +30 -6
- package/dist/plugins/memory-engine-pg.js +96 -214
- package/dist/plugins/memory-engine-sql-apply.d.ts +130 -0
- package/dist/plugins/memory-engine-sql-apply.js +358 -0
- package/dist/plugins/memory-engine-tidb.d.ts +38 -9
- package/dist/plugins/memory-engine-tidb.js +99 -230
- package/dist/plugins/memory-key-guards.d.ts +1 -1
- package/dist/plugins/memory-origin-law.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +169 -83
- package/dist/plugins/one-time-migrations.js +295 -235
- package/dist/plugins/owner-only-file-mode.d.ts +29 -0
- package/dist/plugins/owner-only-file-mode.js +141 -0
- package/dist/plugins/permission-rule-store-file.d.ts +17 -3
- package/dist/plugins/permission-rule-store-file.js +20 -1
- package/dist/plugins/pg-pool.d.ts +2 -1
- package/dist/plugins/pg-pool.js +12 -5
- package/dist/plugins/release-version.d.ts +20 -0
- package/dist/plugins/release-version.js +28 -0
- package/dist/plugins/remote-env-adb.d.ts +20 -4
- package/dist/plugins/remote-env-adb.js +39 -11
- package/dist/plugins/remote-env-e2b.d.ts +12 -3
- package/dist/plugins/remote-env-e2b.js +6 -4
- package/dist/plugins/remote-env-host.d.ts +9 -1
- package/dist/plugins/remote-env-host.js +6 -5
- package/dist/plugins/remote-env-k8s.d.ts +5 -2
- package/dist/plugins/remote-env-k8s.js +15 -4
- package/dist/plugins/remote-env-local-docker.d.ts +4 -1
- package/dist/plugins/remote-env-local-docker.js +3 -3
- package/dist/plugins/remote-env-ssh.d.ts +8 -2
- package/dist/plugins/remote-env-ssh.js +26 -24
- package/dist/plugins/remote-shell.d.ts +59 -30
- package/dist/plugins/remote-shell.js +175 -62
- package/dist/plugins/retention-declaration.d.ts +37 -0
- package/dist/plugins/retention-declaration.js +9 -0
- package/dist/plugins/retention-deployment.d.ts +126 -0
- package/dist/plugins/retention-deployment.js +88 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
- package/dist/plugins/retention-lane-store-sql.js +103 -1
- package/dist/plugins/retention-sql.d.ts +29 -0
- package/dist/plugins/retention-sql.js +8 -0
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/schema-consistency.d.ts +0 -6
- package/dist/plugins/schema-consistency.js +1 -2
- package/dist/plugins/schema-ensure-legs.d.ts +1 -1
- package/dist/plugins/schema-ensure-legs.js +13 -3
- package/dist/plugins/session-ext-table.d.ts +74 -0
- package/dist/plugins/session-ext-table.js +121 -0
- package/dist/plugins/session-fork.d.ts +31 -9
- package/dist/plugins/session-fork.js +3 -2
- package/dist/plugins/session-placement.d.ts +4 -2
- package/dist/plugins/session-row-sql.d.ts +8 -7
- package/dist/plugins/session-row-sql.js +15 -7
- package/dist/plugins/session-store-sql.d.ts +131 -0
- package/dist/plugins/session-store-sql.js +298 -0
- package/dist/plugins/session-workspace-cell.d.ts +2 -2
- package/dist/plugins/session-workspace-cell.js +2 -2
- package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
- package/dist/plugins/shared-memory-store-sql.js +13 -13
- package/dist/plugins/snapshot-bucket-presence.js +1 -1
- package/dist/plugins/sql-driver.d.ts +23 -7
- package/dist/plugins/sql-driver.js +41 -8
- package/dist/plugins/sql-errors.d.ts +5 -2
- package/dist/plugins/sql-errors.js +4 -0
- package/dist/plugins/sql-json-column.d.ts +5 -1
- package/dist/plugins/store-backend.d.ts +46 -16
- package/dist/plugins/store-backend.js +192 -69
- package/dist/plugins/store-contracts.d.ts +10 -13
- package/dist/plugins/store-contracts.js +1 -9
- package/dist/plugins/store-sweep.d.ts +63 -0
- package/dist/plugins/store-sweep.js +48 -0
- package/dist/plugins/task-attachment-store.d.ts +6 -8
- package/dist/plugins/task-attachment-store.js +15 -10
- package/dist/plugins/task-list-store-sql.d.ts +1 -1
- package/dist/plugins/text-column-capacity.d.ts +21 -0
- package/dist/plugins/text-column-capacity.js +5 -0
- package/dist/plugins/tidb-pool.d.ts +3 -2
- package/dist/plugins/tidb-pool.js +20 -32
- package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
- package/dist/prompt-screen.d.ts +6 -9
- package/dist/prompt-screen.js +2 -5
- package/dist/read-face-posture.d.ts +6 -6
- package/dist/read-face-posture.js +2 -2
- package/dist/request-value-closure.d.ts +5 -5
- package/dist/request-value-closure.js +1 -1
- package/dist/rules-consent.d.ts +48 -27
- package/dist/rules-consent.js +147 -23
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/run-local.js +17 -13
- package/dist/runs.d.ts +48 -30
- package/dist/runs.js +27 -17
- package/dist/runtime-caps-resolver.d.ts +15 -8
- package/dist/runtime-caps-resolver.js +14 -10
- package/dist/sandbox-egress-policy.js +6 -11
- package/dist/sandbox-rbac-rules.d.ts +88 -0
- package/dist/sandbox-rbac-rules.js +80 -0
- package/dist/sealed-key-layout.d.ts +16 -0
- package/dist/sealed-key-layout.js +3 -0
- package/dist/sealed-key.js +8 -6
- package/dist/security.d.ts +43 -9
- package/dist/security.js +9 -2
- package/dist/sema-config-dir.js +2 -2
- package/dist/server-secret-env.d.ts +2 -0
- package/dist/service-version.d.ts +2 -1
- package/dist/service-version.js +2 -2
- package/dist/session-error-wire.d.ts +1 -1
- package/dist/session-incarnation.d.ts +8 -5
- package/dist/session-notify-door.d.ts +5 -3
- package/dist/session-resident-background.d.ts +110 -0
- package/dist/session-resident-background.js +88 -0
- package/dist/session-row.d.ts +1 -1
- package/dist/session-sync-kernel.d.ts +53 -14
- package/dist/session-sync-kernel.js +70 -1
- package/dist/session-sync.d.ts +5 -3
- package/dist/session-workspace.d.ts +12 -2
- package/dist/session-workspace.js +6 -0
- package/dist/sighup-idle.d.ts +9 -7
- package/dist/sighup-idle.js +4 -5
- package/dist/spec-fields.d.ts +16 -0
- package/dist/spec-fields.js +7 -0
- package/dist/store-posture.d.ts +2 -1
- package/dist/stored-request-env-credentials-m38.d.ts +3 -0
- package/dist/stored-request-env-credentials-m38.js +8 -0
- package/dist/stored-request-hooks-m20.d.ts +3 -2
- package/dist/stored-request-hooks-m20.js +19 -14
- package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
- package/dist/stores-sql/blob-index-sql.d.ts +148 -0
- package/dist/stores-sql/blob-index-sql.js +154 -0
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +14 -428
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +43 -220
- package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
- package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
- package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
- package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +27 -67
- package/dist/{plugins → stores-sql}/pg-session-storage.js +82 -207
- package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
- package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
- package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
- package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
- package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
- package/dist/stores-sql/session-write-hooks.d.ts +59 -0
- package/dist/stores-sql/session-write-hooks.js +2 -0
- package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
- package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
- package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +35 -112
- package/dist/{plugins → stores-sql}/tidb-session-store.js +73 -169
- package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +3 -3
- package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
- package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
- package/dist/stores-sql/windowed-session-storage.js +61 -0
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
- package/dist/task-a2a.d.ts +7 -1
- package/dist/task-a2a.js +15 -14
- package/dist/task-cwd.d.ts +11 -3
- package/dist/task-cwd.js +17 -1
- package/dist/task-mcp.d.ts +10 -2
- package/dist/task-mcp.js +13 -16
- package/dist/task-settings.d.ts +68 -8
- package/dist/task-settings.js +63 -6
- package/dist/tool-approval.d.ts +23 -10
- package/dist/tool-approval.js +10 -6
- package/dist/trace/core-keyset-guard.d.ts +17 -10
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +4 -0
- package/dist/trace/exit-seat.d.ts +29 -1
- package/dist/trace/exit-seat.js +4 -0
- package/dist/trace/project.d.ts +33 -16
- package/dist/trace/project.js +21 -9
- package/dist/trace/redact.d.ts +13 -2
- package/dist/trace/redact.js +347 -78
- package/dist/trace/self-minted-wire.d.ts +587 -16
- package/dist/trace/self-minted-wire.js +215 -9
- package/dist/trace/sema-provenance.d.ts +45 -41
- package/dist/trace/sema-provenance.js +81 -10
- package/dist/trace/task-notification-facets.d.ts +70 -2
- package/dist/trace/task-notification-facets.js +71 -1
- package/dist/trace/wire-projection-faces.d.ts +39 -3
- package/dist/trace/wire-projection-faces.js +27 -2
- package/dist/unread-request-members.d.ts +66 -0
- package/dist/unread-request-members.js +41 -0
- package/dist/usage-analytics.d.ts +4 -0
- package/dist/user-input-ledger.d.ts +2 -2
- package/dist/web-admin-client/apply-effective.js +22 -26
- package/dist/web-admin-client/candidate-gate.d.ts +35 -3
- package/dist/web-admin-client/candidate-gate.js +53 -5
- package/dist/web-admin-client/center-request.d.ts +4 -1
- package/dist/web-admin-client/center-request.js +2 -1
- package/dist/web-admin-client/effective-keys.js +0 -1
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/http-client.d.ts +1 -0
- package/dist/web-admin-client/http-client.js +17 -9
- package/dist/web-admin-client/restart-signal.js +5 -2
- package/dist/web-admin-client/skills-mcp.d.ts +20 -6
- package/dist/web-admin-client/skills-mcp.js +26 -21
- package/dist/web-admin-client/types.d.ts +34 -49
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
- package/package.json +22 -13
- package/scripts/drain-check-local.mjs +8 -55
- package/scripts/drain-check.mysql.sql +3 -40
- package/scripts/drain-check.pg.sql +3 -40
- package/skills/update-config.md +1 -1
- package/wire-changes/server@7.146.0.json +3221 -0
- package/wire-changes/server@7.147.0.json +813 -0
- package/dist/approval-batch-census.d.ts +0 -27
- package/dist/approval-batch-census.js +0 -27
|
@@ -12,19 +12,15 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { type AcquiredSession, type PlacedSessionRow, type SessionHead, type SessionPlacementRecord, type SessionStore, type SessionTreeEntry } from "@sema-agent/core";
|
|
14
14
|
import type { Pool } from "mysql2/promise";
|
|
15
|
-
import { type InstructionSourceBaseline } from "../instruction-source-notice.js";
|
|
16
|
-
import type { SessionWorkspace } from "../session-workspace.js";
|
|
17
15
|
import type { RetentionDeclaration } from "@sema-agent/core";
|
|
18
|
-
import type {
|
|
19
|
-
import { type
|
|
20
|
-
import { type PlacementAcquireOpts } from "./session-placement.js";
|
|
16
|
+
import type { SessionWriteHooks } from "./session-write-hooks.js";
|
|
17
|
+
import { type PlacementAcquireOpts } from "../plugins/session-placement.js";
|
|
21
18
|
import { type StagingHandle } from "../session-sync-kernel.js";
|
|
22
|
-
import { type ForkTarget, type ForkToOutcome } from "
|
|
23
|
-
import { type ExecutionPlacementSeat } from "../execution-placement.js";
|
|
19
|
+
import { type ForkPlacement, type ForkTarget, type ForkToOutcome } from "../plugins/session-fork.js";
|
|
24
20
|
export declare class TiDBSessionStore implements SessionStore {
|
|
25
21
|
private readonly pool;
|
|
26
22
|
/** 托管留存声明 = 装配交给它的词(后端按扫车道开不开给;不给 ⇒ `"none"`)。读法逐字见
|
|
27
|
-
* `retention-
|
|
23
|
+
* `retention-declaration.ts` 的 {@link MANAGED_RETENTION}。 */
|
|
28
24
|
readonly retention: RetentionDeclaration;
|
|
29
25
|
/** [ref] C18(core 5.48.0 [ref]):placement **声明**。六条义务的实装点逐条见
|
|
30
26
|
* {@link SESSION_PLACEMENTS} 顶注与本类的 acquire / listSessions / release / listPlaced /
|
|
@@ -39,15 +35,11 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
39
35
|
readonly durability: "durable";
|
|
40
36
|
/** In-flight acquisitions keyed by id, so concurrent acquire(sameId) in one process share one. */
|
|
41
37
|
private readonly pending;
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
*/
|
|
46
|
-
readonly executionPlacement: ExecutionPlacementSeat;
|
|
47
|
-
/** 本店的池包成的 SqlDriver:执行席与会话行格写原语的事务都经它借连接(连接初始化钉住事务读语义,`sql-driver.ts`)。 */
|
|
48
|
-
private readonly db;
|
|
49
|
-
constructor(pool: Pool, opts?: {
|
|
38
|
+
/** 部署的事务内钩(组合座交入;导入 / 删除 / fork 的写事务锁住根行之后、写之前调,`session-write-hooks.ts`)。 */
|
|
39
|
+
private readonly hooks;
|
|
40
|
+
constructor(pool: Pool, opts: {
|
|
50
41
|
readonly retention?: RetentionDeclaration;
|
|
42
|
+
readonly hooks: SessionWriteHooks;
|
|
51
43
|
});
|
|
52
44
|
acquire(sessionId?: string, opts?: PlacementAcquireOpts): Promise<AcquiredSession>;
|
|
53
45
|
private load;
|
|
@@ -111,77 +103,6 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
111
103
|
/** 真删除一只 placed 会话的两张表(条件删门在 `placement_kind IS NOT NULL`;事务内 meta 先删=提交点,
|
|
112
104
|
* 与 {@link deleteSession} 同序)。任何 I/O 失败上浮成 `SessionError("storage")`,绝不吞。 */
|
|
113
105
|
private deletePlacedSession;
|
|
114
|
-
/**
|
|
115
|
-
* E16 — list the caller's sessions (CC /resume picker), keyset-paginated newest-first by last activity.
|
|
116
|
-
* Session IDENTITY/enumeration comes from `session_meta` (owner-filtered on the service's OWN owner column);
|
|
117
|
-
* a LEFT JOIN onto the `task_run` runs ledger supplies run-level PREVIEW (latest run's objective/status,
|
|
118
|
-
* run count) but never gates which sessions exist — a session with zero runs still lists (preview null/0).
|
|
119
|
-
* Keyset on `(updated_at, session_id)`; `updated_at` is the session's last-activity marker (touch on every
|
|
120
|
-
* run/append). The shipped {@link SessionSummary} shape is preserved (additive): `lastActivityAt` =
|
|
121
|
-
* `session_meta.updated_at`, `firstActivityAt` = `session_meta.created_at`.
|
|
122
|
-
*/
|
|
123
|
-
listSessions(opts: {
|
|
124
|
-
owner?: string;
|
|
125
|
-
includeUnowned?: boolean;
|
|
126
|
-
cursor?: {
|
|
127
|
-
lastActivityAt: string;
|
|
128
|
-
sessionId: string;
|
|
129
|
-
};
|
|
130
|
-
limit: number;
|
|
131
|
-
q?: string;
|
|
132
|
-
}): Promise<SessionSummary[]>;
|
|
133
|
-
/** ONE session's list row — {@link listSessions}' projection (same SELECT, same mapper) scoped to one id; `undefined` = not a
|
|
134
|
-
* row of the list face (no such session / placed). The run-preview subqueries are scoped to the same id (an index read on
|
|
135
|
-
* `task_run.session_id`, not the whole-ledger aggregate the list pays). */
|
|
136
|
-
sessionSummaryOf(sessionId: string): Promise<SessionSummary | undefined>;
|
|
137
|
-
/** {@link sessionSummaryOf} 那一读 + 读到它时行上的住客(写原语的应答行要复核住客,`settleSessionRowWrite`)。 */
|
|
138
|
-
private listRowOf;
|
|
139
|
-
/**
|
|
140
|
-
* 会话行格写原语 —— 用户标题 / 置顶的唯一写口(规则与判序:`src/session-row.ts` 头注「写原语」;事务与语句:`session-row-sql.ts`,PG 孪生同一只实现)。
|
|
141
|
-
* 一只经 `SqlDriver.connect()` 的事务锁住根行、交 core 判官判行期望(属主 + 化身)→ 写者身份(客户端写在镜像上 ⇒ `mirror`)→ 标签 → 写;
|
|
142
|
-
* 应答行在提交 / 回滚之后另读(列表行同一只投影,含新 `rowTag`)、复核仍是判过的那一位住客。只写列表面上的行(委派分区行 ⇒ `absent`);
|
|
143
|
-
* `updated_at` 不动(改名不是活动)。重载按入口分:`replay` 的结局只有 `written` / `absent`。
|
|
144
|
-
*/
|
|
145
|
-
writeSessionRowCells(sessionId: string, cells: SessionRowPatch, how: ClientSessionRowWrite): Promise<SessionRowWriteOutcome<SessionSummary>>;
|
|
146
|
-
writeSessionRowCells(sessionId: string, cells: SessionRowPatch, how: ReplaySessionRowWrite): Promise<ReplaySessionRowWriteOutcome<SessionSummary>>;
|
|
147
|
-
/**
|
|
148
|
-
* The list projection's ONE SELECT + row mapper ({@link listSessions} and {@link sessionSummaryOf} both read through it).
|
|
149
|
-
* `runSessionId` scopes the two run-preview subqueries to one session (the single-row read); the list leaves them whole.
|
|
150
|
-
* Placeholder order follows the text: subquery params, then `where` params, then the LIMIT.
|
|
151
|
-
* `sm.incarnation` is read for the row tag only (`rowTag`, `sessionRowTagKey` — present-iff the row has a token) and the answer row's occupant
|
|
152
|
-
* check; it never enters the list row itself.
|
|
153
|
-
*/
|
|
154
|
-
private selectListRows;
|
|
155
|
-
/** Cheap pre-LLM probe: "none" = session_meta row not yet REGISTERED (createRun fires
|
|
156
|
-
* before the Runner's session acquire — the titler retries), "untitled" / "titled" as read. */
|
|
157
|
-
probeTitle(sessionId: string): Promise<"none" | "untitled" | "titled">;
|
|
158
|
-
/** The auto-titler's write: lands ONLY when title IS NULL (a concurrent/prior title — the user's included — wins;
|
|
159
|
-
* writer order: `src/session-row.ts`). Returns whether this call set it. */
|
|
160
|
-
setTitleIfNull(sessionId: string, title: string): Promise<boolean>;
|
|
161
|
-
/**
|
|
162
|
-
* [ref] —— 换源通告的基线读(一行 PK SELECT;列的三态读法见 `tidb-pool.ts` 的列注)。行不在 ⇒ 读作「没记过」
|
|
163
|
-
* (loader 跑在 acquire 之后,行恒在;不在 = 被带外删了,没有下一 run 可比)。
|
|
164
|
-
*/
|
|
165
|
-
readInstructionSource(sessionId: string): Promise<InstructionSourceBaseline>;
|
|
166
|
-
/**
|
|
167
|
-
* [ref] —— CAS 覆写基线(期望值 = 调用方读到的那一份;不符 ⇒ 0 行、不抛 —— 契约见 `InstructionSourceStore`)。
|
|
168
|
-
* **不**碰 `updated_at`(那是会话活动时刻,留存腿按它判龄;记基线不是一次会话活动)。
|
|
169
|
-
* 两条基线查询都带每查询超时(`BASELINE_IO_DEADLINE_MS`,mysql2 的 `{sql, timeout}` 形):被行锁卡住的写由查询自己
|
|
170
|
-
* 在期限内拒。⚠️ mysql2 的超时是客户端侧的 —— 拒之后那条连接仍被挂着的命令占到服务端结束(S-9 同形,如实披露)。
|
|
171
|
-
*/
|
|
172
|
-
recordInstructionSource(sessionId: string, expected: InstructionSourceBaseline, source: string | null): Promise<void>;
|
|
173
|
-
/**
|
|
174
|
-
* 会话行的位置与项目那一格(`session_meta.workspace`;域律 `src/session-workspace.ts`,列属主 `session-workspace-cell.ts`)。
|
|
175
|
-
* 一行 PK 读,按文本投影、恰好解一次;行不在 / 格为 NULL ⇒ `undefined`;格读不出 ⇒ 读作没有记录并计一次(F 类,见列属主头注)。
|
|
176
|
-
*/
|
|
177
|
-
readSessionWorkspace(sessionId: string): Promise<SessionWorkspace | undefined>;
|
|
178
|
-
/**
|
|
179
|
-
* 整格覆写(最后一帧胜;唯一调用方 = 腿的记录座,它在腿的流循环里一笔一笔等写完)。**住客围栏**:只写化身仍是 `incarnation` 的那一行 ——
|
|
180
|
-
* 行不在、或同 id 已换了住客 ⇒ 0 行、不抛(那一行不是这条腿的)。**不**碰 `updated_at`(那是会话活动时刻,留存腿按它判龄;记下站在哪里不是一次会话活动)。
|
|
181
|
-
* 走店的一般查询面(与腿循环里的账本追加同一形,不另设每查询的客户端超时):mysql2 的客户端超时只是不再等,服务端照把那条 UPDATE 跑完 ——
|
|
182
|
-
* 一笔「放弃等待却仍会落地」的写正是这条腿离开之后还能盖掉下一条腿的那一形。卡住的上界归服务端(锁等待超时)与部署的池策略。
|
|
183
|
-
*/
|
|
184
|
-
recordSessionWorkspace(sessionId: string, incarnation: string, workspace: SessionWorkspace): Promise<void>;
|
|
185
106
|
/**
|
|
186
107
|
* E17 — fork a session: copy its WHOLE durable history to a NEW uuidv7 session owned by `owner`, mirroring
|
|
187
108
|
* core's `PgSessionRepo.fork`. Entry ids / parent links are per-session and copy VERBATIM; only `seq` is
|
|
@@ -194,14 +115,17 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
194
115
|
* We instead SELECT the entire `session_event` log ordered by seq — every durable entry, compaction floor
|
|
195
116
|
* bypassed — and re-seq it dense from 0 into the new session, ids/parents/payload byte-verbatim.
|
|
196
117
|
*/
|
|
197
|
-
fork(sourceId: string, owner?: string | null
|
|
118
|
+
fork(sourceId: string, owner?: string | null, opts?: {
|
|
119
|
+
placement?: ForkPlacement;
|
|
120
|
+
}): Promise<string | null>;
|
|
198
121
|
/**
|
|
199
122
|
* **fork 续写的店契约**(三店同一只私有体;core `fork` 是它的投影):把源会话的整份历史拷进调用方给的目标 id。
|
|
200
|
-
* 1. **原子目标创建**:事务首句 `INSERT INTO session_meta (
|
|
201
|
-
*
|
|
123
|
+
* 1. **原子目标创建**:事务首句 `INSERT INTO session_meta (…) VALUES (:target, …)`,主键即排他(meta 先,随后事务内钩 `fork` —— 部署在同一事务里记下 fork 键
|
|
124
|
+
* (部署格,旁表)—— 再拷事件、COMMIT);
|
|
125
|
+
* 2. **赢家分类**:撞上已在的目标 ⇒ 输方整笔回滚,经钩读目标那一行的属主与 fork 键(一次读)、分类({@link classifyForkTarget});读不到(赢方在分类前回滚或被删)
|
|
202
126
|
* ⇒ 整笔重跑一次,再撞而仍读不到 ⇒ {@link ForkTargetUnsettledError}(不猜);
|
|
203
|
-
* 3. 单事务 ⇒
|
|
204
|
-
* 源不在 ⇒ `null`(先于目标判:源被删之后的同键重试答「源不在」)。新行 = 新住客(化身新铸)
|
|
127
|
+
* 3. 单事务 ⇒ 无中间态;fork 键只由这一钩写。
|
|
128
|
+
* 源不在 ⇒ `null`(先于目标判:源被删之后的同键重试答「源不在」)。新行 = 新住客(化身新铸),部署格全缺省(执行格 absent)。
|
|
205
129
|
*/
|
|
206
130
|
forkTo(sourceId: string, owner: string | null, target: ForkTarget): Promise<ForkToOutcome | null>;
|
|
207
131
|
/** {@link forkTo} 的一次尝试:`"unsettled"` = 撞上目标而回滚之后读不到它(交给外层重跑一次)。 */
|
|
@@ -253,33 +177,32 @@ export declare class TiDBSessionStore implements SessionStore {
|
|
|
253
177
|
* re-implement any of those checks in SQL ([[core-service-boundary]]; the same discipline fork's hand-SQL
|
|
254
178
|
* was warned about). A violation throws `SessionError("invalid_session")` and NOTHING is written.
|
|
255
179
|
* The write: re-seq dense from 0, entry_id/parent_id/payload/ts verbatim, in ONE txn (COMMIT is the sole commit point), written
|
|
256
|
-
* **lock-or-create, meta first
|
|
257
|
-
*
|
|
258
|
-
*
|
|
180
|
+
* **lock-or-create, meta first**:the `session_meta` row is occupied first (an existing row ⇒ refused before anything else about it is read), locked,
|
|
181
|
+
* then the deployment's transaction hook `import` runs on THIS connection (its run claim on the root ⇒ refused, nothing written; its cells for an
|
|
182
|
+
* imported row), then the entries. The leaf is the replayed leaf (core's `leafIdAfterEntry`), matching core's import.
|
|
259
183
|
*/
|
|
260
184
|
importEntries(sessionId: string, owner: string | null, entries: SessionTreeEntry[]): Promise<void>;
|
|
261
185
|
/**
|
|
262
|
-
* 2c session-sync (§7/§8) — IDEMPOTENT REPLACE:
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* the write logic
|
|
186
|
+
* 2c session-sync (§7/§8) — IDEMPOTENT REPLACE: rewrite the conversation log of `sessionId` with `entries` verbatim under `owner`, ALL in ONE txn.
|
|
187
|
+
* Unlike {@link importEntries} (fresh-only: an existing session at the destination is refused), replace is safe to run OVER an existing
|
|
188
|
+
* session — the §7 fast-forward path and a §8 retry-to-completion both land on it. The validate gate runs FIRST (fail-closed, before any write),
|
|
189
|
+
* then the row: an absent id is created (a fresh occupant, like {@link importEntries}); an existing row is rewritten IN PLACE only when it is the
|
|
190
|
+
* importer's (`owner <=> ?`, defense-in-depth — a wrong-owner caller can never replace another tenant's session: nothing is written) and not a
|
|
191
|
+
* delegation transcript — the same occupant keeps its incarnation and its deployment cells (the side table row is not touched by the store), its
|
|
192
|
+
* created time is the replace's (the log is new). Then the SAME shared write body importEntries uses (the hook, then the events swapped) —
|
|
193
|
+
* ONE source of the write logic. COMMIT is the sole commit point: a mid-replace crash rolls the whole swap back.
|
|
270
194
|
*/
|
|
271
195
|
replaceEntries(sessionId: string, owner: string | null, entries: SessionTreeEntry[]): Promise<void>;
|
|
272
196
|
/**
|
|
273
197
|
* Shared write half of {@link importEntries} / {@link replaceEntries} (ONE source of the write logic, no drift), in the global lock
|
|
274
|
-
* order (根 `session_meta` 先于 `task_
|
|
275
|
-
* ① session_meta FIRST — `create` occupies the row (`ON DUPLICATE KEY UPDATE
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* ②
|
|
280
|
-
*
|
|
281
|
-
* ③
|
|
282
|
-
* ④ the validated entries re-seq dense from 0 (entry_id/parent_id/type/ts verbatim); `replace` drops the old log first.
|
|
198
|
+
* order (根 `session_meta` 先于 `task_*`、部署格与 `session_event`):
|
|
199
|
+
* ① session_meta FIRST — `create` occupies the row (`ON DUPLICATE KEY UPDATE leaf_seq = leaf_seq`: an existing row is left as it is) and then
|
|
200
|
+
* locks it and judges it is the one this call occupied (化身 = 本次铸的;a row that existed before ⇒ refused before anything else about it is
|
|
201
|
+
* read — no hook on someone else's row); `replace` rewrites the locked row in place (owner-guarded, not placed — 0 rows = another owner's row,
|
|
202
|
+
* refused, nothing written). owner = the RE-STAMPED authenticated principal (never the bundle's);
|
|
203
|
+
* ② the deployment's transaction hook `import` on THIS connection after the row lock (`session-write-hooks.ts`):its run claim on the root ⇒
|
|
204
|
+
* refused; its cells for an imported row (a writer here ⇒ refused; otherwise the row is a mirror —「写者在别处」);
|
|
205
|
+
* ③ the validated entries re-seq dense from 0 (entry_id/parent_id/type/ts verbatim); `replace` drops the old log first.
|
|
283
206
|
* Runs inside the caller's open transaction (`conn`) so the caller owns begin/commit/rollback (COMMIT is the sole commit point).
|
|
284
207
|
* `validated` is the OUTPUT of {@link validateEntriesForImport} (the caller runs the gate before opening the txn).
|
|
285
208
|
*/
|
|
@@ -1,38 +1,43 @@
|
|
|
1
1
|
import { StoredSession, SessionError, uuidv7, validateEntriesForImport, leafIdAfterEntry, admitSessionPlacement } from "@sema-agent/core";
|
|
2
2
|
import { TiDBSessionStorage } from "./tidb-session-storage.js";
|
|
3
3
|
import { decodeSessionEventPayload } from "./session-event-payload.js";
|
|
4
|
-
import { jsonColumnText } from "
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { decodeSessionWorkspaceCell, encodeSessionWorkspaceCell } from "./session-workspace-cell.js";
|
|
8
|
-
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "./retention-store-sql.js";
|
|
9
|
-
import { carriedRowCells, headFromRow, incarnationFromCell, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
|
|
10
|
-
import { sessionRowTagKey } from "../session-row.js";
|
|
11
|
-
import { writeSessionRowCellsSql } from "./session-row-sql.js";
|
|
4
|
+
import { jsonColumnText } from "../plugins/sql-json-column.js";
|
|
5
|
+
import { MANAGED_RETENTION, UNMANAGED_RETENTION } from "../plugins/retention-declaration.js";
|
|
6
|
+
import { headFromRow, mintSessionIncarnation, sessionFaceFromRow } from "../session-incarnation.js";
|
|
12
7
|
import { contentForkRelation, fastForwardSharedContentDiverged } from "../session-sync-content.js";
|
|
13
|
-
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SESSION_DURABILITY, SESSION_PLACEMENTS, } from "
|
|
8
|
+
import { placementCapabilityOf, LIST_PLACED_BATCH, PLACEMENT_SELECT_COLUMNS, placedRowFromRow, placementFromRow, placementInsertValues, SESSION_DURABILITY, SESSION_PLACEMENTS, } from "../plugins/session-placement.js";
|
|
14
9
|
import { classifySyncRelationshipByIds, SyncConflictError, StagedCommitOwnerChangedError, stagingIdFor, STAGING_ID_MARKER, STAGING_GC_GRACE_MS, } from "../session-sync-kernel.js";
|
|
15
|
-
import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue, placedSessionOwnerOf } from "
|
|
10
|
+
import { assertFirstOwnerWritable, forkOwnerOf, isSessionOwnerValue, placedSessionOwnerOf } from "../plugins/session-ownership.js";
|
|
16
11
|
import { selectForkRows } from "@sema-agent/core";
|
|
17
|
-
import { FORK_LOG_ROW_SHAPE, ForkTargetUnsettledError, classifyForkTarget, forkByFreshId, forkPointOf } from "
|
|
18
|
-
import { isMysqlDupKeyError } from "
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
import { FORK_LOG_ROW_SHAPE, ForkTargetUnsettledError, classifyForkTarget, forkByFreshId, forkPointOf } from "../plugins/session-fork.js";
|
|
13
|
+
import { isMysqlDupKeyError } from "../plugins/sql-errors.js";
|
|
14
|
+
const statementsOn = (conn) => ({
|
|
15
|
+
async query(sql, params) {
|
|
16
|
+
const [res] = await conn.query(sql, params ?? []);
|
|
17
|
+
return Array.isArray(res) ? { rows: res, affected: 0 } : { rows: [], affected: res.affectedRows };
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
class HookRefusal {
|
|
21
|
+
refuse;
|
|
22
|
+
constructor(refuse) {
|
|
23
|
+
this.refuse = refuse;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function settleHookVerdict(verdict) {
|
|
27
|
+
if (verdict !== "proceed")
|
|
28
|
+
throw new HookRefusal(verdict.refuse);
|
|
29
|
+
}
|
|
23
30
|
export class TiDBSessionStore {
|
|
24
31
|
pool;
|
|
25
32
|
retention;
|
|
26
33
|
placements = SESSION_PLACEMENTS;
|
|
27
34
|
durability = SESSION_DURABILITY;
|
|
28
35
|
pending = new Map();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
constructor(pool, opts = {}) {
|
|
36
|
+
hooks;
|
|
37
|
+
constructor(pool, opts) {
|
|
32
38
|
this.pool = pool;
|
|
33
39
|
this.retention = opts.retention ?? UNMANAGED_RETENTION;
|
|
34
|
-
this.
|
|
35
|
-
this.executionPlacement = createSqlExecutionPlacementSeat(this.db);
|
|
40
|
+
this.hooks = opts.hooks;
|
|
36
41
|
}
|
|
37
42
|
async acquire(sessionId, opts) {
|
|
38
43
|
if (!sessionId) {
|
|
@@ -83,7 +88,7 @@ export class TiDBSessionStore {
|
|
|
83
88
|
const now = new Date();
|
|
84
89
|
await this.pool.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, " +
|
|
85
90
|
"placement_kind, placement_scope, placement_parent_session_id, placement_root_session_id, placement_handle, placed_at) " +
|
|
86
|
-
"VALUES (?,?,?,?,NULL,0,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE
|
|
91
|
+
"VALUES (?,?,?,?,NULL,0,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE leaf_seq = leaf_seq", [sessionId, owner, now, now, mintSessionIncarnation(), ...placementInsertValues(placement, now)]);
|
|
87
92
|
}
|
|
88
93
|
async placementOf(sessionId) {
|
|
89
94
|
const [rows] = await this.pool.query(`SELECT ${PLACEMENT_SELECT_COLUMNS} FROM session_meta WHERE session_id = ?`, [sessionId]);
|
|
@@ -151,103 +156,8 @@ export class TiDBSessionStore {
|
|
|
151
156
|
conn.release();
|
|
152
157
|
}
|
|
153
158
|
}
|
|
154
|
-
async
|
|
155
|
-
|
|
156
|
-
const where = ["sm.placement_kind IS NULL"];
|
|
157
|
-
if (opts.owner !== undefined) {
|
|
158
|
-
where.push(opts.includeUnowned ? "(sm.owner = ? OR sm.owner IS NULL)" : "sm.owner = ?");
|
|
159
|
-
params.push(opts.owner);
|
|
160
|
-
}
|
|
161
|
-
if (opts.q) {
|
|
162
|
-
where.push("EXISTS (SELECT 1 FROM task_run tr WHERE tr.session_id = sm.session_id AND LOWER(tr.objective_preview) LIKE LOWER(?) ESCAPE '\\\\')");
|
|
163
|
-
params.push(`%${escapeLike(opts.q)}%`);
|
|
164
|
-
}
|
|
165
|
-
if (opts.cursor) {
|
|
166
|
-
where.push("(sm.updated_at < ? OR (sm.updated_at = ? AND sm.session_id < ?))");
|
|
167
|
-
params.push(new Date(opts.cursor.lastActivityAt), new Date(opts.cursor.lastActivityAt), opts.cursor.sessionId);
|
|
168
|
-
}
|
|
169
|
-
return (await this.selectListRows({ where, params, limit: opts.limit })).map((a) => a.row);
|
|
170
|
-
}
|
|
171
|
-
async sessionSummaryOf(sessionId) {
|
|
172
|
-
return (await this.listRowOf(sessionId))?.row;
|
|
173
|
-
}
|
|
174
|
-
async listRowOf(sessionId) {
|
|
175
|
-
return (await this.selectListRows({ where: ["sm.placement_kind IS NULL", "sm.session_id = ?"], params: [sessionId], limit: 1, runSessionId: sessionId }))[0];
|
|
176
|
-
}
|
|
177
|
-
async writeSessionRowCells(sessionId, cells, how) {
|
|
178
|
-
return writeSessionRowCellsSql(this.db, sessionId, cells, how, (id) => this.listRowOf(id));
|
|
179
|
-
}
|
|
180
|
-
async selectListRows(q) {
|
|
181
|
-
const runWhere = q.runSessionId !== undefined ? " WHERE session_id = ?" : "";
|
|
182
|
-
const runParams = q.runSessionId !== undefined ? [q.runSessionId, q.runSessionId] : [];
|
|
183
|
-
const sql = "SELECT sm.session_id, sm.owner, sm.incarnation, sm.updated_at AS last_activity, sm.created_at AS first_activity, sm.title, sm.pinned, " +
|
|
184
|
-
" COALESCE(r.run_count, 0) AS run_count, latest.objective_preview, latest.status, latest.task_id AS last_run_id, latest.last_task_run_id " +
|
|
185
|
-
"FROM session_meta sm " +
|
|
186
|
-
"LEFT JOIN (SELECT session_id, COUNT(*) AS run_count FROM task_run" + runWhere + " GROUP BY session_id) r ON r.session_id = sm.session_id " +
|
|
187
|
-
"LEFT JOIN (SELECT session_id, objective_preview, status, task_id, last_task_run_id FROM (" +
|
|
188
|
-
" SELECT session_id, objective_preview, status, task_id, JSON_UNQUOTE(JSON_EXTRACT(result, '$.runId')) AS last_task_run_id, " +
|
|
189
|
-
" ROW_NUMBER() OVER (PARTITION BY session_id ORDER BY created_at DESC, task_id DESC) AS rn FROM task_run" + runWhere +
|
|
190
|
-
" ) lr WHERE rn = 1) latest ON latest.session_id = sm.session_id " +
|
|
191
|
-
(q.where.length ? "WHERE " + q.where.join(" AND ") + " " : "") +
|
|
192
|
-
"ORDER BY sm.updated_at DESC, sm.session_id DESC LIMIT ?";
|
|
193
|
-
const [rows] = await this.pool.query(sql, [...runParams, ...q.params, q.limit]);
|
|
194
|
-
return rows.map((r) => {
|
|
195
|
-
const runId = r.last_task_run_id;
|
|
196
|
-
const sessionId = String(r.session_id);
|
|
197
|
-
const owner = r.owner ?? null;
|
|
198
|
-
const incarnation = incarnationFromCell(sessionId, r.incarnation, "absent");
|
|
199
|
-
const title = r.title ?? null;
|
|
200
|
-
const pinned = Number(r.pinned) === 1;
|
|
201
|
-
const row = {
|
|
202
|
-
sessionId,
|
|
203
|
-
owner,
|
|
204
|
-
lastActivityAt: r.last_activity instanceof Date ? r.last_activity.toISOString() : String(r.last_activity),
|
|
205
|
-
firstActivityAt: r.first_activity instanceof Date ? r.first_activity.toISOString() : String(r.first_activity),
|
|
206
|
-
runCount: Number(r.run_count),
|
|
207
|
-
objectivePreview: r.objective_preview ?? null,
|
|
208
|
-
lastStatus: r.status == null ? "" : String(r.status),
|
|
209
|
-
lastRunId: r.last_run_id ?? null,
|
|
210
|
-
...(typeof runId === "string" && runId !== "" ? { lastTaskRunId: runId } : {}),
|
|
211
|
-
title,
|
|
212
|
-
pinned,
|
|
213
|
-
...sessionRowTagKey({ sessionId, owner, incarnation, cells: { title, pinned } }),
|
|
214
|
-
};
|
|
215
|
-
return { row, occupant: { owner, incarnation } };
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
async probeTitle(sessionId) {
|
|
219
|
-
const [rows] = await this.pool.query("SELECT title FROM session_meta WHERE session_id = ?", [sessionId]);
|
|
220
|
-
if (!rows[0])
|
|
221
|
-
return "none";
|
|
222
|
-
return rows[0].title == null ? "untitled" : "titled";
|
|
223
|
-
}
|
|
224
|
-
async setTitleIfNull(sessionId, title) {
|
|
225
|
-
const [r] = await this.pool.query("UPDATE session_meta SET title = ? WHERE session_id = ? AND title IS NULL", [title, sessionId]);
|
|
226
|
-
return r.affectedRows > 0;
|
|
227
|
-
}
|
|
228
|
-
async readInstructionSource(sessionId) {
|
|
229
|
-
const [rows] = await this.pool.query({ sql: "SELECT instruction_source FROM session_meta WHERE session_id = ?", timeout: BASELINE_IO_DEADLINE_MS }, [sessionId]);
|
|
230
|
-
return decodeInstructionSource(rows[0]?.instruction_source);
|
|
231
|
-
}
|
|
232
|
-
async recordInstructionSource(sessionId, expected, source) {
|
|
233
|
-
const next = encodeInstructionSource(source);
|
|
234
|
-
if (expected.recorded) {
|
|
235
|
-
await this.pool.query({ sql: "UPDATE session_meta SET instruction_source = ? WHERE session_id = ? AND instruction_source = ?", timeout: BASELINE_IO_DEADLINE_MS }, [next, sessionId, encodeInstructionSource(expected.source)]);
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
await this.pool.query({ sql: "UPDATE session_meta SET instruction_source = ? WHERE session_id = ? AND instruction_source IS NULL", timeout: BASELINE_IO_DEADLINE_MS }, [next, sessionId]);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
async readSessionWorkspace(sessionId) {
|
|
242
|
-
const [rows] = await this.pool.query(`SELECT ${jsonColumnText("mysql", "workspace")} FROM session_meta WHERE session_id = ?`, [sessionId]);
|
|
243
|
-
const row = rows[0];
|
|
244
|
-
return row === undefined ? undefined : decodeSessionWorkspaceCell(row.workspace, sessionId);
|
|
245
|
-
}
|
|
246
|
-
async recordSessionWorkspace(sessionId, incarnation, workspace) {
|
|
247
|
-
await this.pool.query("UPDATE session_meta SET workspace = ? WHERE session_id = ? AND incarnation = ?", [encodeSessionWorkspaceCell(workspace, JSON.stringify, sessionId), sessionId, incarnation]);
|
|
248
|
-
}
|
|
249
|
-
async fork(sourceId, owner) {
|
|
250
|
-
return forkByFreshId((s, o, t) => this.forkTo(s, o, t), sourceId, owner);
|
|
159
|
+
async fork(sourceId, owner, opts) {
|
|
160
|
+
return forkByFreshId((s, o, t) => this.forkTo(s, o, t), sourceId, owner, opts);
|
|
251
161
|
}
|
|
252
162
|
async forkTo(sourceId, owner, target) {
|
|
253
163
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
@@ -275,7 +185,8 @@ export class TiDBSessionStore {
|
|
|
275
185
|
try {
|
|
276
186
|
await conn.beginTransaction();
|
|
277
187
|
try {
|
|
278
|
-
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation,
|
|
188
|
+
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, " +
|
|
189
|
+
"placement_kind, placement_scope, placement_parent_session_id, placement_root_session_id, placement_handle, placed_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", [target.id, forkOwner, now, now, forkLeafId, eventRows.length, mintSessionIncarnation(), ...placementInsertValues(target.placement, now)]);
|
|
279
190
|
}
|
|
280
191
|
catch (err) {
|
|
281
192
|
if (!isMysqlDupKeyError(err))
|
|
@@ -283,6 +194,8 @@ export class TiDBSessionStore {
|
|
|
283
194
|
collided = true;
|
|
284
195
|
}
|
|
285
196
|
if (!collided) {
|
|
197
|
+
if (target.key !== undefined)
|
|
198
|
+
await this.hooks.keyedFork.record(statementsOn(conn), { rootSessionId: target.id, forkKey: target.key });
|
|
286
199
|
for (let seq = 0; seq < eventRows.length; seq++) {
|
|
287
200
|
const r = eventRows[seq];
|
|
288
201
|
const payload = String(r.payload);
|
|
@@ -299,14 +212,15 @@ export class TiDBSessionStore {
|
|
|
299
212
|
}
|
|
300
213
|
catch {
|
|
301
214
|
}
|
|
215
|
+
if (err instanceof HookRefusal)
|
|
216
|
+
throw err.refuse;
|
|
302
217
|
throw err instanceof SessionError ? err : new SessionError("storage", `fork of session ${sourceId} failed`, err instanceof Error ? err : undefined);
|
|
303
218
|
}
|
|
304
219
|
finally {
|
|
305
220
|
conn.release();
|
|
306
221
|
}
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
return row === undefined ? "unsettled" : classifyForkTarget(target, { owner: row.owner ?? null, forkKey: row.fork_key ?? null }, forkOwner);
|
|
222
|
+
const existing = await this.hooks.keyedFork.targetOf(target.id);
|
|
223
|
+
return existing === undefined ? "unsettled" : classifyForkTarget(target, existing, forkOwner);
|
|
310
224
|
}
|
|
311
225
|
async exportEntries(sessionId) {
|
|
312
226
|
const [metaRows] = await this.pool.query("SELECT 1 FROM session_meta WHERE session_id = ?", [sessionId]);
|
|
@@ -346,7 +260,7 @@ export class TiDBSessionStore {
|
|
|
346
260
|
const conn = await this.pool.getConnection();
|
|
347
261
|
try {
|
|
348
262
|
await conn.beginTransaction();
|
|
349
|
-
await this.writeImportedLog(conn, sessionId, owner, validated,
|
|
263
|
+
await this.writeImportedLog(conn, sessionId, owner, validated, "create");
|
|
350
264
|
await conn.commit();
|
|
351
265
|
}
|
|
352
266
|
catch (err) {
|
|
@@ -355,7 +269,9 @@ export class TiDBSessionStore {
|
|
|
355
269
|
}
|
|
356
270
|
catch {
|
|
357
271
|
}
|
|
358
|
-
if (err instanceof
|
|
272
|
+
if (err instanceof HookRefusal)
|
|
273
|
+
throw err.refuse;
|
|
274
|
+
if (err instanceof SessionError)
|
|
359
275
|
throw err;
|
|
360
276
|
throw new SessionError("storage", `import of session ${sessionId} failed`, err instanceof Error ? err : undefined);
|
|
361
277
|
}
|
|
@@ -369,21 +285,13 @@ export class TiDBSessionStore {
|
|
|
369
285
|
const conn = await this.pool.getConnection();
|
|
370
286
|
try {
|
|
371
287
|
await conn.beginTransaction();
|
|
372
|
-
const [
|
|
373
|
-
const prior =
|
|
288
|
+
const [lockedRows] = await conn.query("SELECT placement_kind FROM session_meta WHERE session_id = ? FOR UPDATE", [sessionId]);
|
|
289
|
+
const prior = lockedRows[0];
|
|
374
290
|
if (prior?.placement_kind != null) {
|
|
375
291
|
await conn.rollback();
|
|
376
292
|
throw new SessionError("placement_refused", `session ${sessionId} belongs to the ${String(prior.placement_kind)} placement partition — a session-sync replace cannot overwrite a delegation transcript`);
|
|
377
293
|
}
|
|
378
|
-
|
|
379
|
-
const swapped = purged.affectedRows === 1 ? prior : undefined;
|
|
380
|
-
const cells = carriedRowCells(sessionId, swapped === undefined ? undefined : { incarnation: swapped.incarnation, forkKey: swapped.fork_key });
|
|
381
|
-
const priorCell = swapped === undefined ? undefined : placementCellFromRow(sessionId, swapped);
|
|
382
|
-
if (priorCell?.role === "writer") {
|
|
383
|
-
await conn.rollback();
|
|
384
|
-
throw new SessionWriterPresentError(sessionId, priorCell.lane);
|
|
385
|
-
}
|
|
386
|
-
await this.writeImportedLog(conn, sessionId, owner, validated, cells, "replace");
|
|
294
|
+
await this.writeImportedLog(conn, sessionId, owner, validated, prior === undefined ? "create" : "replace");
|
|
387
295
|
await conn.commit();
|
|
388
296
|
}
|
|
389
297
|
catch (err) {
|
|
@@ -392,7 +300,9 @@ export class TiDBSessionStore {
|
|
|
392
300
|
}
|
|
393
301
|
catch {
|
|
394
302
|
}
|
|
395
|
-
if (err instanceof
|
|
303
|
+
if (err instanceof HookRefusal)
|
|
304
|
+
throw err.refuse;
|
|
305
|
+
if (err instanceof SessionError)
|
|
396
306
|
throw err;
|
|
397
307
|
throw new SessionError("storage", `replace of session ${sessionId} failed`, err instanceof Error ? err : undefined);
|
|
398
308
|
}
|
|
@@ -400,23 +310,26 @@ export class TiDBSessionStore {
|
|
|
400
310
|
conn.release();
|
|
401
311
|
}
|
|
402
312
|
}
|
|
403
|
-
async writeImportedLog(conn, sessionId, owner, validated,
|
|
313
|
+
async writeImportedLog(conn, sessionId, owner, validated, mode) {
|
|
404
314
|
let leafId = null;
|
|
405
315
|
for (const e of validated)
|
|
406
316
|
leafId = leafIdAfterEntry(e);
|
|
407
317
|
const now = new Date();
|
|
408
|
-
const imported = importedRowCells(cells.forkKey);
|
|
409
|
-
await conn.query(`INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation, ${imported.columns}) VALUES (?,?,?,?,?,?,?,?,?)` +
|
|
410
|
-
(mode === "create" ? " ON DUPLICATE KEY UPDATE session_id = session_id" : ""), [sessionId, owner, now, now, leafId, validated.length, cells.incarnation, ...imported.values]);
|
|
411
318
|
if (mode === "create") {
|
|
319
|
+
const minted = mintSessionIncarnation();
|
|
320
|
+
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation) VALUES (?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE leaf_seq = leaf_seq", [sessionId, owner, now, now, leafId, validated.length, minted]);
|
|
412
321
|
const [held] = await conn.query("SELECT incarnation FROM session_meta WHERE session_id = ? FOR UPDATE", [sessionId]);
|
|
413
|
-
if (String(held[0]?.incarnation) !==
|
|
322
|
+
if (String(held[0]?.incarnation) !== minted) {
|
|
414
323
|
throw new SessionError("storage", `import of session ${sessionId} failed`, new Error(`session ${sessionId} already exists — importEntries only creates a session (replaceEntries rewrites one); nothing was written`));
|
|
415
324
|
}
|
|
416
325
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
326
|
+
else {
|
|
327
|
+
const [rewritten] = await conn.query("UPDATE session_meta SET owner = ?, created_at = ?, updated_at = ?, leaf_id = ?, leaf_seq = ? WHERE session_id = ? AND owner <=> ? AND placement_kind IS NULL", [owner, now, now, leafId, validated.length, sessionId, owner]);
|
|
328
|
+
if (rewritten.affectedRows !== 1) {
|
|
329
|
+
throw new SessionError("storage", `replace of session ${sessionId} failed`, new Error(`session ${sessionId} belongs to another owner — a replace rewrites only the importer's own session; nothing was written`));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
settleHookVerdict(await this.hooks.beforeCommit(statementsOn(conn), { op: "import", rootSessionId: sessionId }));
|
|
420
333
|
if (mode === "replace")
|
|
421
334
|
await conn.query("DELETE FROM session_event WHERE session_id = ?", [sessionId]);
|
|
422
335
|
for (let seq = 0; seq < validated.length; seq++) {
|
|
@@ -425,7 +338,7 @@ export class TiDBSessionStore {
|
|
|
425
338
|
}
|
|
426
339
|
}
|
|
427
340
|
beginImportStaging(realSessionId, token) {
|
|
428
|
-
return new TiDBStagingHandle(this.pool, realSessionId, stagingIdFor(realSessionId, token));
|
|
341
|
+
return new TiDBStagingHandle(this.pool, this.hooks, realSessionId, stagingIdFor(realSessionId, token));
|
|
429
342
|
}
|
|
430
343
|
async assertNotPlaced(sessionId, what) {
|
|
431
344
|
const placed = await this.placementOf(sessionId);
|
|
@@ -453,11 +366,9 @@ export class TiDBSessionStore {
|
|
|
453
366
|
const conn = await this.pool.getConnection();
|
|
454
367
|
try {
|
|
455
368
|
await conn.beginTransaction();
|
|
456
|
-
const
|
|
457
|
-
if (
|
|
458
|
-
await
|
|
459
|
-
throw new SessionActiveRunError(sessionId, claim.activeTaskId);
|
|
460
|
-
}
|
|
369
|
+
const [locked] = await conn.query("SELECT session_id FROM session_meta WHERE session_id = ? FOR UPDATE", [sessionId]);
|
|
370
|
+
if (locked.length > 0)
|
|
371
|
+
settleHookVerdict(await this.hooks.beforeCommit(statementsOn(conn), { op: "delete", rootSessionId: sessionId }));
|
|
461
372
|
const [metaRes] = await conn.query("DELETE FROM session_meta WHERE session_id = ? AND owner <=> ?", [sessionId, owner]);
|
|
462
373
|
if (metaRes.affectedRows > 0)
|
|
463
374
|
await conn.query("DELETE FROM session_event WHERE session_id = ?", [sessionId]);
|
|
@@ -470,6 +381,8 @@ export class TiDBSessionStore {
|
|
|
470
381
|
}
|
|
471
382
|
catch {
|
|
472
383
|
}
|
|
384
|
+
if (err instanceof HookRefusal)
|
|
385
|
+
throw err.refuse;
|
|
473
386
|
throw err;
|
|
474
387
|
}
|
|
475
388
|
finally {
|
|
@@ -485,12 +398,14 @@ export class TiDBSessionStore {
|
|
|
485
398
|
}
|
|
486
399
|
class TiDBStagingHandle {
|
|
487
400
|
pool;
|
|
401
|
+
hooks;
|
|
488
402
|
realSessionId;
|
|
489
403
|
stagingId;
|
|
490
404
|
nextSeq = 0;
|
|
491
405
|
seen = new Set();
|
|
492
|
-
constructor(pool, realSessionId, stagingId) {
|
|
406
|
+
constructor(pool, hooks, realSessionId, stagingId) {
|
|
493
407
|
this.pool = pool;
|
|
408
|
+
this.hooks = hooks;
|
|
494
409
|
this.realSessionId = realSessionId;
|
|
495
410
|
this.stagingId = stagingId;
|
|
496
411
|
}
|
|
@@ -529,18 +444,14 @@ class TiDBStagingHandle {
|
|
|
529
444
|
}
|
|
530
445
|
}
|
|
531
446
|
else {
|
|
532
|
-
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation) VALUES (?,?,?,?,NULL,0,?) ON DUPLICATE KEY UPDATE
|
|
447
|
+
await conn.query("INSERT INTO session_meta (session_id, owner, created_at, updated_at, leaf_id, leaf_seq, incarnation) VALUES (?,?,?,?,NULL,0,?) ON DUPLICATE KEY UPDATE leaf_seq = leaf_seq", [this.realSessionId, owner, now, now, minted]);
|
|
533
448
|
const [claimed] = await conn.query("SELECT incarnation FROM session_meta WHERE session_id = ? FOR UPDATE", [this.realSessionId]);
|
|
534
449
|
if (String(claimed[0]?.incarnation) !== minted) {
|
|
535
450
|
await conn.rollback();
|
|
536
451
|
throw new StagedCommitOwnerChangedError(this.realSessionId);
|
|
537
452
|
}
|
|
538
453
|
}
|
|
539
|
-
|
|
540
|
-
if (claim.activeTaskId !== null) {
|
|
541
|
-
await conn.rollback();
|
|
542
|
-
throw new SessionActiveRunError(this.realSessionId, claim.activeTaskId);
|
|
543
|
-
}
|
|
454
|
+
settleHookVerdict(await this.hooks.beforeCommit(statementsOn(conn), { op: "import", rootSessionId: this.realSessionId }));
|
|
544
455
|
const [stagedRows] = await conn.query("SELECT entry_id FROM session_event WHERE session_id = ? ORDER BY seq ASC FOR UPDATE", [this.stagingId]);
|
|
545
456
|
const [dstRows] = await conn.query("SELECT entry_id FROM session_event WHERE session_id = ? ORDER BY seq ASC FOR UPDATE", [this.realSessionId]);
|
|
546
457
|
const [dstMeta] = await conn.query("SELECT placement_kind FROM session_meta WHERE session_id = ?", [this.realSessionId]);
|
|
@@ -575,16 +486,7 @@ class TiDBStagingHandle {
|
|
|
575
486
|
let leafId = null;
|
|
576
487
|
if (lastRow[0])
|
|
577
488
|
leafId = leafIdAfterEntry(decodeSessionEventPayload(lastRow[0].payload, this.realSessionId, "last staged row"));
|
|
578
|
-
|
|
579
|
-
if (settle.affectedRows !== 1) {
|
|
580
|
-
const locked = readPlacementRowStatement("mysql", this.realSessionId, { lock: true });
|
|
581
|
-
const [lockedRows] = await conn.query(locked.text, [...locked.values]);
|
|
582
|
-
const cell = lockedRows[0] === undefined ? undefined : placementCellFromRow(this.realSessionId, lockedRows[0]);
|
|
583
|
-
await conn.rollback();
|
|
584
|
-
if (cell?.role === "writer")
|
|
585
|
-
throw new SessionWriterPresentError(this.realSessionId, cell.lane);
|
|
586
|
-
throw new SessionError("storage", `staged commit for ${this.realSessionId}: the commit point matched no row under a held row lock and the row is not a writer — refusing to guess`);
|
|
587
|
-
}
|
|
489
|
+
await conn.query("UPDATE session_meta SET owner = ?, updated_at = ?, leaf_id = ?, leaf_seq = ? WHERE session_id = ?", [owner, now, leafId, srcIds.length, this.realSessionId]);
|
|
588
490
|
const [afterMeta] = await conn.query("SELECT placement_kind, owner, incarnation FROM session_meta WHERE session_id = ?", [this.realSessionId]);
|
|
589
491
|
if (afterMeta[0]?.placement_kind != null) {
|
|
590
492
|
await conn.rollback();
|
|
@@ -599,7 +501,9 @@ class TiDBStagingHandle {
|
|
|
599
501
|
await conn.rollback();
|
|
600
502
|
}
|
|
601
503
|
catch { }
|
|
602
|
-
if (err instanceof
|
|
504
|
+
if (err instanceof HookRefusal)
|
|
505
|
+
throw err.refuse;
|
|
506
|
+
if (err instanceof SyncConflictError || err instanceof SessionError)
|
|
603
507
|
throw err;
|
|
604
508
|
throw new SessionError("storage", `staged commit for ${this.realSessionId} failed`, err instanceof Error ? err : undefined);
|
|
605
509
|
}
|