@sema-agent/server 1.323.0 → 2.0.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/dist/approval-hmac.d.ts +40 -0
- package/dist/approval-hmac.js +67 -0
- package/dist/approval.d.ts +31 -0
- package/dist/approval.js +72 -4
- package/dist/audit.d.ts +26 -0
- package/dist/audit.js +40 -1
- package/dist/auth-bridge.d.ts +10 -0
- package/dist/auth-bridge.js +47 -4
- package/dist/auth-keys.d.ts +19 -0
- package/dist/auth-keys.js +13 -0
- package/dist/bake-runner/main.d.ts +5 -0
- package/dist/bake-runner/main.js +43 -4
- package/dist/bake-runner/protocol.d.ts +57 -0
- package/dist/bake-runner/protocol.js +58 -3
- package/dist/bake-runner/runner.d.ts +54 -0
- package/dist/bake-runner/runner.js +87 -5
- package/dist/bench/l8/artifact.d.ts +63 -0
- package/dist/bench/l8/artifact.js +61 -2
- package/dist/bench/l8/escape.d.ts +36 -0
- package/dist/bench/l8/escape.js +25 -0
- package/dist/bench/l8/index.d.ts +14 -0
- package/dist/bench/l8/index.js +14 -0
- package/dist/bench/l8/probes.d.ts +74 -0
- package/dist/bench/l8/probes.js +60 -0
- package/dist/bench/l8/run-probes.d.ts +43 -0
- package/dist/bench/l8/run-probes.js +45 -2
- package/dist/bench/s1/arms.d.ts +126 -0
- package/dist/bench/s1/arms.js +188 -13
- package/dist/bench/s1/live-deps.d.ts +66 -0
- package/dist/bench/s1/live-deps.js +249 -11
- package/dist/bench/s1/oracle.d.ts +49 -0
- package/dist/bench/s1/oracle.js +36 -1
- package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
- package/dist/bench/s1/repair-oracle-adapter.js +30 -0
- package/dist/bench/s1/reviewer.d.ts +38 -0
- package/dist/bench/s1/reviewer.js +34 -0
- package/dist/bench/s1/row.d.ts +77 -0
- package/dist/bench/s1/row.js +62 -0
- package/dist/bench/s1/run-firm.d.ts +47 -0
- package/dist/bench/s1/run-firm.js +70 -4
- package/dist/bench/s1/runner-ctx.d.ts +71 -0
- package/dist/bench/s1/runner-ctx.js +36 -0
- package/dist/bench/s1/tasks.d.ts +108 -0
- package/dist/bench/s1/tasks.js +115 -0
- package/dist/boot-reclaim.d.ts +19 -0
- package/dist/boot-reclaim.js +20 -0
- package/dist/brain.d.ts +25 -0
- package/dist/brain.js +61 -1
- package/dist/budget.d.ts +66 -0
- package/dist/budget.js +128 -4
- package/dist/capabilities/builtin-tools.d.ts +3 -0
- package/dist/capabilities/builtin-tools.js +3 -0
- package/dist/capabilities/center-plugins.d.ts +17 -1
- package/dist/capabilities/center-plugins.js +45 -4
- package/dist/capabilities/center-prompts.d.ts +46 -0
- package/dist/capabilities/center-prompts.js +57 -3
- package/dist/capabilities/code-review-council.d.ts +28 -0
- package/dist/capabilities/code-review-council.js +40 -7
- package/dist/capabilities/collab-wire.d.ts +2 -0
- package/dist/capabilities/collab-workflows.d.ts +7 -0
- package/dist/capabilities/collab-workflows.js +44 -1
- package/dist/capabilities/oa-tools.d.ts +6 -0
- package/dist/capabilities/oa-tools.js +10 -0
- package/dist/capabilities/prompt.d.ts +14 -0
- package/dist/capabilities/prompt.js +14 -0
- package/dist/capabilities/prompts/code-review.d.ts +14 -0
- package/dist/capabilities/prompts/code-review.js +14 -0
- package/dist/capabilities/prompts/identity.d.ts +6 -0
- package/dist/capabilities/prompts/identity.js +6 -0
- package/dist/capabilities/prompts/team.d.ts +4 -0
- package/dist/capabilities/prompts/team.js +4 -0
- package/dist/capabilities/repo-tools.d.ts +11 -0
- package/dist/capabilities/repo-tools.js +8 -0
- package/dist/capabilities/sandbox-file-send.d.ts +95 -0
- package/dist/capabilities/sandbox-file-send.js +91 -3
- package/dist/capabilities/scenarios.d.ts +130 -0
- package/dist/capabilities/scenarios.js +180 -7
- package/dist/capabilities/select-environment-tool.d.ts +7 -0
- package/dist/capabilities/select-environment-tool.js +30 -0
- package/dist/capabilities/send-user-file-tool.d.ts +33 -0
- package/dist/capabilities/send-user-file-tool.js +65 -1
- package/dist/capabilities/skills.d.ts +29 -0
- package/dist/capabilities/skills.js +13 -2
- package/dist/capabilities/team.d.ts +22 -0
- package/dist/capabilities/team.js +22 -2
- package/dist/capabilities/tool-defer.d.ts +26 -0
- package/dist/capabilities/tool-defer.js +3 -0
- package/dist/config-center/apply-effective.d.ts +65 -0
- package/dist/config-center/apply-effective.js +204 -12
- package/dist/config-center/http-client.d.ts +34 -0
- package/dist/config-center/http-client.js +68 -0
- package/dist/config-center/restart-signal.d.ts +22 -0
- package/dist/config-center/restart-signal.js +39 -0
- package/dist/config-center/skills-mcp.d.ts +20 -1
- package/dist/config-center/skills-mcp.js +42 -7
- package/dist/config-center/types.d.ts +92 -1
- package/dist/config-lkg.d.ts +12 -0
- package/dist/config-lkg.js +41 -0
- package/dist/config-provider.d.ts +78 -0
- package/dist/config-provider.js +165 -2
- package/dist/config-types.d.ts +546 -0
- package/dist/config.d.ts +64 -0
- package/dist/config.js +455 -60
- package/dist/degenerate-instrument.d.ts +38 -0
- package/dist/degenerate-instrument.js +55 -3
- package/dist/elicitation.d.ts +39 -0
- package/dist/elicitation.js +87 -3
- package/dist/env-facts.d.ts +61 -0
- package/dist/env-facts.js +73 -7
- package/dist/fleet/fleet-bus.d.ts +185 -0
- package/dist/fleet/fleet-bus.js +333 -27
- package/dist/fleet/subagent-tail-bus.d.ts +11 -0
- package/dist/fleet/subagent-tail-bus.js +33 -2
- package/dist/fleet-client.d.ts +38 -0
- package/dist/fleet-client.js +44 -9
- package/dist/fleet-lease.d.ts +46 -0
- package/dist/fleet-lease.js +73 -5
- package/dist/hooks/branch-transcript.d.ts +8 -0
- package/dist/hooks/branch-transcript.js +33 -0
- package/dist/hooks/cc-stop-prompt.d.ts +42 -0
- package/dist/hooks/cc-stop-prompt.js +43 -1
- package/dist/hooks/hook-llm.d.ts +15 -0
- package/dist/hooks/hook-llm.js +47 -0
- package/dist/hooks/hook-runner.d.ts +89 -0
- package/dist/hooks/hook-runner.js +327 -18
- package/dist/http/idempotency.d.ts +31 -0
- package/dist/http/idempotency.js +34 -0
- package/dist/http/principal-gate.d.ts +17 -0
- package/dist/http/principal-gate.js +35 -3
- package/dist/http/route-ctx.d.ts +36 -0
- package/dist/http/routes/approvals-assistant.d.ts +25 -0
- package/dist/http/routes/approvals-assistant.js +253 -23
- package/dist/http/routes/attachments.js +22 -4
- package/dist/http/routes/capabilities.d.ts +7 -0
- package/dist/http/routes/capabilities.js +202 -1
- package/dist/http/routes/fleet.d.ts +6 -0
- package/dist/http/routes/fleet.js +94 -5
- package/dist/http/routes/images.d.ts +17 -0
- package/dist/http/routes/images.js +222 -14
- package/dist/http/routes/leader.d.ts +7 -0
- package/dist/http/routes/leader.js +10 -0
- package/dist/http/routes/memory-policy.d.ts +6 -0
- package/dist/http/routes/memory-policy.js +38 -6
- package/dist/http/routes/notify-wake.d.ts +10 -0
- package/dist/http/routes/notify-wake.js +19 -3
- package/dist/http/routes/observability.d.ts +6 -0
- package/dist/http/routes/observability.js +19 -2
- package/dist/http/routes/runs.d.ts +15 -0
- package/dist/http/routes/runs.js +464 -41
- package/dist/http/routes/session-sync.d.ts +15 -0
- package/dist/http/routes/session-sync.js +229 -19
- package/dist/http/routes/sessions-list.d.ts +6 -0
- package/dist/http/routes/sessions-list.js +35 -4
- package/dist/http/routes/sessions.d.ts +14 -0
- package/dist/http/routes/sessions.js +176 -31
- package/dist/http/routes/side-query.d.ts +8 -0
- package/dist/http/routes/side-query.js +26 -1
- package/dist/http/routes/tasks.d.ts +18 -0
- package/dist/http/routes/tasks.js +501 -38
- package/dist/http/routes/trace-usage.d.ts +10 -0
- package/dist/http/routes/trace-usage.js +66 -14
- package/dist/http/routes/workflows.d.ts +12 -0
- package/dist/http/routes/workflows.js +180 -19
- package/dist/http/run-meta.d.ts +11 -0
- package/dist/http/run-meta.js +6 -0
- package/dist/http/send.d.ts +19 -0
- package/dist/http/send.js +11 -0
- package/dist/http/server.d.ts +255 -0
- package/dist/http/server.js +921 -75
- package/dist/http/sse-log.d.ts +15 -0
- package/dist/http/sse-log.js +16 -0
- package/dist/http/tar.d.ts +9 -0
- package/dist/http/tar.js +21 -5
- package/dist/http/wire-gate.d.ts +9 -0
- package/dist/http/wire-gate.js +9 -0
- package/dist/http/wire-types.d.ts +187 -0
- package/dist/http/workspace-content.d.ts +8 -0
- package/dist/http/workspace-content.js +10 -0
- package/dist/images/bake-validate.d.ts +63 -0
- package/dist/images/bake-validate.js +71 -1
- package/dist/images/manifest.d.ts +19 -0
- package/dist/images/manifest.js +6 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.js +10 -5
- package/dist/key-resolver.d.ts +23 -0
- package/dist/key-resolver.js +27 -2
- package/dist/leader/diffout.d.ts +23 -0
- package/dist/leader/diffout.js +8 -1
- package/dist/leader/diffup.d.ts +32 -0
- package/dist/leader/diffup.js +43 -0
- package/dist/leader/endpoint.d.ts +20 -0
- package/dist/leader/endpoint.js +25 -2
- package/dist/leader/fanout.d.ts +60 -0
- package/dist/leader/fanout.js +29 -3
- package/dist/leader/grader-env-factory.d.ts +74 -0
- package/dist/leader/grader-env-factory.js +62 -3
- package/dist/leader/leader.d.ts +97 -0
- package/dist/leader/leader.js +151 -4
- package/dist/leader/merge.d.ts +94 -0
- package/dist/leader/merge.js +112 -9
- package/dist/leader/planner.d.ts +52 -0
- package/dist/leader/planner.js +47 -3
- package/dist/leader/repair-oracle.d.ts +61 -0
- package/dist/leader/repair-oracle.js +59 -1
- package/dist/leader/repair-wire.d.ts +78 -0
- package/dist/leader/repair-wire.js +79 -2
- package/dist/leader/wire.d.ts +79 -0
- package/dist/leader/wire.js +255 -8
- package/dist/lsp/e2b-bridge.d.ts +16 -0
- package/dist/lsp/e2b-bridge.js +32 -4
- package/dist/lsp/e2b-manager.d.ts +10 -0
- package/dist/lsp/e2b-manager.js +18 -2
- package/dist/lsp/lsp-frames.d.ts +12 -0
- package/dist/lsp/lsp-frames.js +12 -0
- package/dist/lsp/manager.d.ts +12 -0
- package/dist/lsp/manager.js +35 -2
- package/dist/lsp/types.d.ts +10 -0
- package/dist/lsp/ws-transport.d.ts +12 -0
- package/dist/lsp/ws-transport.js +53 -5
- package/dist/lsp-evict.d.ts +14 -0
- package/dist/lsp-evict.js +15 -1
- package/dist/main.js +2132 -96
- package/dist/memory-export.d.ts +1 -0
- package/dist/memory-export.js +4 -0
- package/dist/memory-scope.d.ts +49 -0
- package/dist/memory-scope.js +87 -4
- package/dist/memory-sync-client.d.ts +24 -0
- package/dist/memory-sync-client.js +41 -2
- package/dist/memory-sync.d.ts +23 -0
- package/dist/memory-sync.js +70 -1
- package/dist/model-select.d.ts +39 -0
- package/dist/model-select.js +42 -1
- package/dist/observability/cost-quota.d.ts +20 -0
- package/dist/observability/cost-quota.js +4 -0
- package/dist/observability/cost-taxonomy.d.ts +45 -0
- package/dist/observability/cost-taxonomy.js +34 -0
- package/dist/observability/logger.d.ts +1 -0
- package/dist/observability/logger.js +6 -0
- package/dist/observability/metrics.d.ts +13 -0
- package/dist/observability/metrics.js +63 -0
- package/dist/observability/otel-exporter.d.ts +9 -0
- package/dist/observability/otel-exporter.js +11 -3
- package/dist/observability/principal-context.d.ts +9 -0
- package/dist/observability/principal-context.js +9 -0
- package/dist/observability/prompt-manifest.d.ts +37 -0
- package/dist/observability/prompt-manifest.js +35 -1
- package/dist/observability/rate-limit.d.ts +10 -0
- package/dist/observability/rate-limit.js +1 -0
- package/dist/observability/tool-trace.d.ts +24 -0
- package/dist/observability/tool-trace.js +41 -1
- package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
- package/dist/orchestration/hardened-vm-runner.js +119 -4
- package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
- package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
- package/dist/orchestration/hardened-vm-worker.js +27 -0
- package/dist/orchestration/subagent-steer.d.ts +44 -0
- package/dist/orchestration/subagent-steer.js +45 -1
- package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
- package/dist/orchestration/workflow-agent-steer.js +80 -1
- package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
- package/dist/orchestration/workflow-completion-inbox.js +283 -32
- package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
- package/dist/orchestration/workflow-notify-journal.js +187 -13
- package/dist/parked-decide.d.ts +61 -0
- package/dist/parked-decide.js +58 -1
- package/dist/per-task-image.d.ts +54 -0
- package/dist/per-task-image.js +41 -0
- package/dist/plan-cache-probe.d.ts +35 -0
- package/dist/plan-cache-probe.js +18 -3
- package/dist/plugins/approval-exemption-store.d.ts +7 -0
- package/dist/plugins/approval-exemption-store.js +28 -2
- package/dist/plugins/approval-store-sql.d.ts +64 -0
- package/dist/plugins/approval-store-sql.js +32 -0
- package/dist/plugins/background-agent-store-sql.d.ts +55 -0
- package/dist/plugins/background-agent-store-sql.js +91 -4
- package/dist/plugins/background-shell-support.d.ts +98 -0
- package/dist/plugins/background-shell-support.js +117 -13
- package/dist/plugins/blob-backend.d.ts +104 -0
- package/dist/plugins/blob-backend.js +163 -6
- package/dist/plugins/breaker-state-sql.d.ts +65 -1
- package/dist/plugins/breaker-state-sql.js +46 -8
- package/dist/plugins/caching-session-store.d.ts +42 -0
- package/dist/plugins/caching-session-store.js +63 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
- package/dist/plugins/checkpoint-store-sql.js +239 -11
- package/dist/plugins/file-outcome-sink.d.ts +4 -0
- package/dist/plugins/file-outcome-sink.js +9 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
- package/dist/plugins/file-resume-anchor-store.js +43 -4
- package/dist/plugins/file-run-store.d.ts +90 -0
- package/dist/plugins/file-run-store.js +145 -13
- package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
- package/dist/plugins/file-snapshot-store-sql.js +178 -10
- package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
- package/dist/plugins/file-workflow-journal-store.js +10 -0
- package/dist/plugins/fork-routing-session-store.d.ts +47 -0
- package/dist/plugins/fork-routing-session-store.js +51 -3
- package/dist/plugins/host-platform.d.ts +69 -0
- package/dist/plugins/host-platform.js +81 -2
- package/dist/plugins/image-bake-store-sql.d.ts +136 -1
- package/dist/plugins/image-bake-store-sql.js +241 -7
- package/dist/plugins/image-index-sql.d.ts +46 -0
- package/dist/plugins/image-index-sql.js +113 -4
- package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
- package/dist/plugins/k8s-bg-scripts.js +88 -4
- package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
- package/dist/plugins/k8s-exec-protocol.js +41 -0
- package/dist/plugins/local-checkpoint-store.d.ts +40 -0
- package/dist/plugins/local-checkpoint-store.js +86 -7
- package/dist/plugins/local-session-store.d.ts +157 -0
- package/dist/plugins/local-session-store.js +289 -34
- package/dist/plugins/local-task-attachment-store.js +14 -2
- package/dist/plugins/mailbox-store-sql.d.ts +38 -0
- package/dist/plugins/mailbox-store-sql.js +39 -6
- package/dist/plugins/memory-engine-pg.d.ts +30 -0
- package/dist/plugins/memory-engine-pg.js +122 -4
- package/dist/plugins/memory-engine-tidb.d.ts +26 -0
- package/dist/plugins/memory-engine-tidb.js +115 -5
- package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
- package/dist/plugins/memory-engine-vector-util.js +5 -0
- package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
- package/dist/plugins/memory-resume-anchor-store.js +17 -0
- package/dist/plugins/memory-run-store.d.ts +63 -0
- package/dist/plugins/memory-run-store.js +73 -8
- package/dist/plugins/memory-session-policy-store.d.ts +17 -0
- package/dist/plugins/memory-session-policy-store.js +17 -0
- package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
- package/dist/plugins/memory-sync-store-pg.js +45 -2
- package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
- package/dist/plugins/memory-sync-store-tidb.js +31 -1
- package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
- package/dist/plugins/outcome-ledger-sql.js +97 -3
- package/dist/plugins/pg-approval-store.d.ts +7 -0
- package/dist/plugins/pg-approval-store.js +7 -0
- package/dist/plugins/pg-breaker-state.d.ts +6 -0
- package/dist/plugins/pg-breaker-state.js +6 -0
- package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
- package/dist/plugins/pg-checkpoint-store.js +8 -0
- package/dist/plugins/pg-cost-quota.d.ts +17 -0
- package/dist/plugins/pg-cost-quota.js +6 -0
- package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/pg-file-snapshot-store.js +6 -0
- package/dist/plugins/pg-image-bake.d.ts +9 -0
- package/dist/plugins/pg-image-bake.js +9 -0
- package/dist/plugins/pg-image-index.d.ts +9 -0
- package/dist/plugins/pg-image-index.js +9 -0
- package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
- package/dist/plugins/pg-outcome-ledger.js +9 -0
- package/dist/plugins/pg-pool.d.ts +50 -0
- package/dist/plugins/pg-pool.js +78 -0
- package/dist/plugins/pg-query.d.ts +11 -0
- package/dist/plugins/pg-rate-limiter.d.ts +23 -0
- package/dist/plugins/pg-rate-limiter.js +12 -2
- package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/pg-resume-anchor-store.js +5 -0
- package/dist/plugins/pg-run-store.d.ts +7 -0
- package/dist/plugins/pg-run-store.js +7 -0
- package/dist/plugins/pg-safe-json.d.ts +13 -0
- package/dist/plugins/pg-safe-json.js +40 -4
- package/dist/plugins/pg-session-policy-store.d.ts +5 -0
- package/dist/plugins/pg-session-policy-store.js +5 -0
- package/dist/plugins/pg-session-storage.d.ts +72 -0
- package/dist/plugins/pg-session-storage.js +152 -20
- package/dist/plugins/pg-session-store.d.ts +10 -0
- package/dist/plugins/pg-session-store.js +10 -0
- package/dist/plugins/pg-tool-result-store.d.ts +7 -0
- package/dist/plugins/pg-tool-result-store.js +7 -0
- package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-journal-store.js +7 -0
- package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
- package/dist/plugins/pg-workflow-run-store.js +7 -0
- package/dist/plugins/posix-shell-fs.d.ts +3 -0
- package/dist/plugins/posix-shell-fs.js +31 -1
- package/dist/plugins/remote-env-adb.d.ts +25 -0
- package/dist/plugins/remote-env-adb.js +95 -12
- package/dist/plugins/remote-env-e2b.d.ts +146 -0
- package/dist/plugins/remote-env-e2b.js +371 -40
- package/dist/plugins/remote-env-file-error.d.ts +34 -0
- package/dist/plugins/remote-env-file-error.js +37 -0
- package/dist/plugins/remote-env-host.d.ts +151 -0
- package/dist/plugins/remote-env-host.js +468 -70
- package/dist/plugins/remote-env-k8s.d.ts +135 -0
- package/dist/plugins/remote-env-k8s.js +318 -32
- package/dist/plugins/remote-env-local-docker.d.ts +65 -0
- package/dist/plugins/remote-env-local-docker.js +149 -24
- package/dist/plugins/remote-env-ssh.d.ts +35 -0
- package/dist/plugins/remote-env-ssh.js +117 -20
- package/dist/plugins/remote-scratchpad.d.ts +38 -0
- package/dist/plugins/remote-scratchpad.js +32 -2
- package/dist/plugins/remote-shell.d.ts +22 -0
- package/dist/plugins/remote-shell.js +27 -1
- package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
- package/dist/plugins/resume-anchor-store-sql.js +11 -0
- package/dist/plugins/roster-store-sql.d.ts +27 -0
- package/dist/plugins/roster-store-sql.js +54 -0
- package/dist/plugins/run-store-sql.d.ts +194 -0
- package/dist/plugins/run-store-sql.js +210 -9
- package/dist/plugins/s3-presign.d.ts +20 -0
- package/dist/plugins/s3-presign.js +49 -2
- package/dist/plugins/scheduler-support.d.ts +12 -0
- package/dist/plugins/scheduler-support.js +75 -3
- package/dist/plugins/send-file-ledger.d.ts +15 -0
- package/dist/plugins/send-file-ledger.js +53 -4
- package/dist/plugins/send-user-file.d.ts +77 -0
- package/dist/plugins/send-user-file.js +92 -4
- package/dist/plugins/session-policy-store-sql.d.ts +15 -0
- package/dist/plugins/session-policy-store-sql.js +75 -3
- package/dist/plugins/session-store.d.ts +45 -0
- package/dist/plugins/session-store.js +51 -0
- package/dist/plugins/sql-driver.d.ts +77 -0
- package/dist/plugins/sql-driver.js +4 -0
- package/dist/plugins/sql-escape.d.ts +8 -0
- package/dist/plugins/sql-escape.js +8 -0
- package/dist/plugins/sql-row-helpers.d.ts +25 -0
- package/dist/plugins/sql-row-helpers.js +25 -0
- package/dist/plugins/store-backend.d.ts +103 -0
- package/dist/plugins/store-backend.js +120 -27
- package/dist/plugins/store-contracts.d.ts +62 -0
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/task-attachment-store.d.ts +60 -0
- package/dist/plugins/task-attachment-store.js +49 -3
- package/dist/plugins/task-list-store-sql.d.ts +25 -0
- package/dist/plugins/task-list-store-sql.js +21 -0
- package/dist/plugins/tidb-approval-store.d.ts +6 -0
- package/dist/plugins/tidb-approval-store.js +6 -0
- package/dist/plugins/tidb-breaker-state.d.ts +5 -0
- package/dist/plugins/tidb-breaker-state.js +5 -0
- package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
- package/dist/plugins/tidb-checkpoint-store.js +7 -0
- package/dist/plugins/tidb-cost-quota.d.ts +6 -0
- package/dist/plugins/tidb-cost-quota.js +1 -0
- package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
- package/dist/plugins/tidb-file-snapshot-store.js +6 -0
- package/dist/plugins/tidb-image-bake.d.ts +8 -0
- package/dist/plugins/tidb-image-bake.js +8 -0
- package/dist/plugins/tidb-image-index.d.ts +8 -0
- package/dist/plugins/tidb-image-index.js +8 -0
- package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
- package/dist/plugins/tidb-outcome-ledger.js +10 -0
- package/dist/plugins/tidb-pool.d.ts +56 -0
- package/dist/plugins/tidb-pool.js +181 -1
- package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
- package/dist/plugins/tidb-rate-limiter.js +5 -2
- package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
- package/dist/plugins/tidb-resume-anchor-store.js +5 -0
- package/dist/plugins/tidb-run-store.d.ts +7 -0
- package/dist/plugins/tidb-run-store.js +7 -0
- package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
- package/dist/plugins/tidb-session-policy-store.js +5 -0
- package/dist/plugins/tidb-session-storage.d.ts +43 -0
- package/dist/plugins/tidb-session-storage.js +62 -3
- package/dist/plugins/tidb-session-store.d.ts +142 -0
- package/dist/plugins/tidb-session-store.js +264 -16
- package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
- package/dist/plugins/tidb-tool-result-store.js +7 -0
- package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
- package/dist/plugins/tidb-workflow-journal-store.js +7 -0
- package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
- package/dist/plugins/tidb-workflow-run-store.js +8 -0
- package/dist/plugins/tool-result-store-sql.d.ts +58 -0
- package/dist/plugins/tool-result-store-sql.js +38 -2
- package/dist/plugins/web-search.d.ts +35 -0
- package/dist/plugins/web-search.js +45 -9
- package/dist/plugins/workflow-journal-limits.d.ts +10 -0
- package/dist/plugins/workflow-journal-limits.js +10 -0
- package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
- package/dist/plugins/workflow-journal-store-sql.js +58 -2
- package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
- package/dist/plugins/workflow-run-store-sql.js +84 -6
- package/dist/plugins/worktree-isolation.d.ts +45 -0
- package/dist/plugins/worktree-isolation.js +105 -6
- package/dist/plugins/write-behind-counter.d.ts +56 -1
- package/dist/plugins/write-behind-counter.js +53 -14
- package/dist/principal-jwt.d.ts +24 -0
- package/dist/principal-jwt.js +60 -5
- package/dist/project-memory.d.ts +22 -0
- package/dist/project-memory.js +144 -15
- package/dist/prompts-domain-validate.d.ts +28 -0
- package/dist/prompts-domain-validate.js +42 -1
- package/dist/question.d.ts +33 -0
- package/dist/question.js +69 -2
- package/dist/resource-suspend.d.ts +21 -0
- package/dist/resource-suspend.js +16 -0
- package/dist/router/route-orchestration.d.ts +78 -0
- package/dist/router/route-orchestration.js +77 -0
- package/dist/run-local.d.ts +32 -0
- package/dist/run-local.js +172 -8
- package/dist/runs.d.ts +189 -4
- package/dist/runs.js +465 -24
- package/dist/runtime-caps-resolver.d.ts +106 -0
- package/dist/runtime-caps-resolver.js +89 -4
- package/dist/runtime-governance.d.ts +84 -0
- package/dist/runtime-governance.js +127 -1
- package/dist/sandbox-pkg-source.d.ts +23 -0
- package/dist/sandbox-pkg-source.js +37 -0
- package/dist/sealed-key.d.ts +54 -0
- package/dist/sealed-key.js +68 -3
- package/dist/security.d.ts +108 -0
- package/dist/security.js +145 -6
- package/dist/sema-registry.d.ts +21 -0
- package/dist/sema-registry.js +21 -0
- package/dist/session-leaf-bus.d.ts +31 -0
- package/dist/session-leaf-bus.js +32 -0
- package/dist/session-sync-content.d.ts +46 -0
- package/dist/session-sync-content.js +47 -1
- package/dist/session-sync-kernel.d.ts +89 -0
- package/dist/session-sync-kernel.js +48 -3
- package/dist/session-sync.d.ts +125 -0
- package/dist/session-sync.js +181 -8
- package/dist/session-titler.d.ts +26 -0
- package/dist/session-titler.js +41 -7
- package/dist/session-watch.d.ts +53 -1
- package/dist/session-watch.js +73 -9
- package/dist/sighup-idle.d.ts +30 -0
- package/dist/sighup-idle.js +12 -1
- package/dist/spec-fields.d.ts +91 -3
- package/dist/spec-fields.js +116 -4
- package/dist/task-cwd.d.ts +50 -0
- package/dist/task-cwd.js +68 -1
- package/dist/task-mcp.d.ts +47 -0
- package/dist/task-mcp.js +29 -0
- package/dist/task-settings.d.ts +175 -0
- package/dist/task-settings.js +226 -11
- package/dist/task-workflow.d.ts +67 -0
- package/dist/task-workflow.js +75 -8
- package/dist/tool-approval.d.ts +91 -0
- package/dist/tool-approval.js +215 -0
- package/dist/trace/artifacts.d.ts +9 -0
- package/dist/trace/artifacts.js +30 -5
- package/dist/trace/core-keyset-guard.d.ts +18 -0
- package/dist/trace/ledger-sink.d.ts +43 -0
- package/dist/trace/ledger-sink.js +64 -5
- package/dist/trace/project.d.ts +133 -0
- package/dist/trace/project.js +189 -2
- package/dist/trace/redact.d.ts +19 -0
- package/dist/trace/redact.js +66 -9
- package/dist/usage-analytics.d.ts +26 -0
- package/dist/usage-analytics.js +26 -3
- package/package.json +1 -1
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable approval store for the human-in-the-loop write gate (F4) — SINGLE-FILE DUAL-DIALECT
|
|
3
|
+
* (design/158 A12 定型半场). ONE implementation, TWO dialects; the historical `TiDBApprovalStore` /
|
|
4
|
+
* `PgApprovalStore` class names survive as thin ctor subclasses so every consumer (store-backend.ts,
|
|
5
|
+
* src/index.ts, the approval/audit/security-coverage suites) is untouched.
|
|
6
|
+
*
|
|
7
|
+
* When a gated tool call is about to run, a `pending` row is recorded here; the instance running the
|
|
8
|
+
* task polls it for a decision. Because the row is durable and shared, an operator's approve/deny can
|
|
9
|
+
* land on ANY instance — critical under async runs + a load balancer, where the deciding request and
|
|
10
|
+
* the waiting run are usually on different instances.
|
|
11
|
+
*
|
|
12
|
+
* Unlike the run/checkpoint PG store (whose schema is owned centrally by pg-pool.ts), this file also
|
|
13
|
+
* exports a self-contained PG schema (`PG_APPROVAL_SCHEMA` + `ensureSchema`) — the `approval` table is
|
|
14
|
+
* DISJOINT from the other PG stores' tables, so a CREATE IF NOT EXISTS here shadows nothing. Central
|
|
15
|
+
* aggregation into pg-pool.ts composes it alongside the others. Kept in lock-step with the TiDB store
|
|
16
|
+
* by the shared real-DB integration suite (test/pg-approval-store-integration.test.ts).
|
|
17
|
+
*
|
|
18
|
+
* ── Dialect deltas, kept EXPLICIT ────────────────────────────────────────────────────────────────────
|
|
19
|
+
* - `?` placeholders vs `$n`
|
|
20
|
+
* - null-safe scope compare: `<=>` vs `IS NOT DISTINCT FROM` (a NULL scope row — legacy/untenanted
|
|
21
|
+
* run — is matched by a NULL scope arg; one tenant's scope NEVER matches another's — the
|
|
22
|
+
* single-DB fleet read guard, defense-in-depth)
|
|
23
|
+
* - JSON binding: TiDB `JSON.stringify` verbatim vs PG `pgProtocolJsonStringify` (codex R4-H2: the
|
|
24
|
+
* persisted approval `args` is the operator's REVIEW surface and must agree byte-for-byte with the
|
|
25
|
+
* policy-executed args — a lossy/rewriting envelope would let an operator approve one payload while
|
|
26
|
+
* a different one runs)
|
|
27
|
+
* - affectedRows vs rowCount (via SqlDriver)
|
|
28
|
+
* - schema ownership: TiDB DDL lives in tidb-pool.ts SCHEMA_STATEMENTS; PG DDL is this file's own
|
|
29
|
+
* self-contained `PG_APPROVAL_SCHEMA` (see the PG twin's original header — unlike the other PG
|
|
30
|
+
* stores, `approval` is NOT centrally owned by pg-pool.ts's DDL array, only aggregated into its
|
|
31
|
+
* `ensureSchema` composition).
|
|
32
|
+
* - `getStatus` result shape: `RowDataPacket[]` (mysql2 typed query) vs a plain-record `pg` query —
|
|
33
|
+
* normalized to `SqlRow` by the shared driver, so both arms read the same field names.
|
|
34
|
+
*/
|
|
1
35
|
import type { Pool as MySqlPool } from "mysql2/promise";
|
|
2
36
|
import type { Pool as PgPool, PoolClient } from "pg";
|
|
3
37
|
import { type SqlDriver } from "./sql-driver.js";
|
|
@@ -7,6 +41,7 @@ export interface ApprovalRow {
|
|
|
7
41
|
taskId: string | null;
|
|
8
42
|
sessionId: string | null;
|
|
9
43
|
owner: string | null;
|
|
44
|
+
/** Single-DB fleet scope guard (defense-in-depth): the run's tenant identity, owner-sourced. Reads filter on it. */
|
|
10
45
|
scope: string | null;
|
|
11
46
|
toolName: string;
|
|
12
47
|
args: unknown;
|
|
@@ -16,12 +51,23 @@ export interface ApprovalRow {
|
|
|
16
51
|
createdAt: string;
|
|
17
52
|
decidedAt: string | null;
|
|
18
53
|
}
|
|
54
|
+
/** PG translation of the `approval` DDL in tidb-pool.ts SCHEMA_STATEMENTS (JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3),
|
|
55
|
+
* inline KEY→separate CREATE INDEX).
|
|
56
|
+
*
|
|
57
|
+
* SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are
|
|
58
|
+
* drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead. */
|
|
19
59
|
export declare const PG_APPROVAL_SCHEMA: string[];
|
|
60
|
+
/** Idempotent self-contained schema apply (for the integration test; central aggregation is done separately). */
|
|
20
61
|
export declare function ensureSchema(pool: PgPool | PoolClient): Promise<void>;
|
|
62
|
+
/** Dual-dialect durable approval store. See the file header for the dialect-delta ledger. */
|
|
21
63
|
export declare class SqlApprovalStore {
|
|
22
64
|
protected readonly db: SqlDriver;
|
|
23
65
|
constructor(db: SqlDriver);
|
|
66
|
+
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
24
67
|
private q;
|
|
68
|
+
/** JSON column binding: TiDB stores the string verbatim; PG goes through the LOSSLESS protocol envelope
|
|
69
|
+
* (codex R4-H2 — the approval `args` is the operator's review surface and must agree with the
|
|
70
|
+
* policy-executed args at the NUL position). */
|
|
25
71
|
private json;
|
|
26
72
|
createPending(id: string, scope: string | null, ctx: {
|
|
27
73
|
taskId?: string | null;
|
|
@@ -35,17 +81,35 @@ export declare class SqlApprovalStore {
|
|
|
35
81
|
reason: string | null;
|
|
36
82
|
decidedBy: string | null;
|
|
37
83
|
} | undefined>;
|
|
84
|
+
/** Apply a terminal decision, but only to a still-pending row (CAS). Returns whether it applied. The scope
|
|
85
|
+
* guard (null-safe) is carried on the operator path too for consistency with the read paths. */
|
|
38
86
|
decide(id: string, scope: string | null, decision: "approved" | "denied" | "expired", reason: string | null, decidedBy: string | null): Promise<boolean>;
|
|
87
|
+
/** Pending approvals (operator queue), scoped to one tenant (single-DB fleet read guard, null-safe), optionally
|
|
88
|
+
* further filtered to one owner. */
|
|
39
89
|
listPending(scope: string | null, owner?: string): Promise<ApprovalRow[]>;
|
|
40
90
|
get(id: string, scope: string | null): Promise<ApprovalRow | undefined>;
|
|
91
|
+
/** Operator-only CROSS-tenant by-id read (no scope filter). The F4 operator queue serves/decides across
|
|
92
|
+
* tenants by design; the HTTP layer gates this to an operator and then re-binds decide() to the row's OWN
|
|
93
|
+
* scope. Tenants NEVER reach this — they use the scope-bound {@link get}. */
|
|
41
94
|
getById(id: string): Promise<ApprovalRow | undefined>;
|
|
95
|
+
/** Operator-only CROSS-tenant pending list (no scope filter) — the unfiltered operator queue across all
|
|
96
|
+
* tenants. Tenants use the scope-bound {@link listPending}; this is HTTP-gated to an operator.
|
|
97
|
+
* 🔴 identical SQL text on both dialects (no placeholders, nothing dialect-specific) — kept as ONE literal
|
|
98
|
+
* rather than a `q()` pair so a reader isn't misled into looking for a divergence that isn't there. */
|
|
42
99
|
listPendingAll(): Promise<ApprovalRow[]>;
|
|
100
|
+
/** Expire pending approvals older than `olderThanMs` (a never-answered operator request). Deliberately GLOBAL
|
|
101
|
+
* (NOT scope-filtered): staleness expiry is fleet-level maintenance that protects the worker regardless of
|
|
102
|
+
* tenant — a stale row in any scope must be reaped. Scope isolation applies to the per-tenant READ paths, not
|
|
103
|
+
* to this maintenance sweep. */
|
|
43
104
|
expireStale(olderThanMs: number): Promise<number>;
|
|
44
105
|
}
|
|
106
|
+
/** approval row → {@link ApprovalRow} — shared by BOTH dialects. design/158 S8 归位 / A12 收编. */
|
|
45
107
|
export declare function mapRow(r: Record<string, unknown>): ApprovalRow;
|
|
108
|
+
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
46
109
|
export declare class TiDBApprovalStore extends SqlApprovalStore {
|
|
47
110
|
constructor(pool: MySqlPool);
|
|
48
111
|
}
|
|
112
|
+
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
49
113
|
export declare class PgApprovalStore extends SqlApprovalStore {
|
|
50
114
|
constructor(pool: PgPool);
|
|
51
115
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { parseJsonStrict as parseJson, toIsoOrNull as iso } from "./sql-row-helpers.js";
|
|
2
2
|
import { pgProtocolJsonStringify } from "./pg-safe-json.js";
|
|
3
3
|
import { mysqlDriver, pgDriver } from "./sql-driver.js";
|
|
4
|
+
/** PG translation of the `approval` DDL in tidb-pool.ts SCHEMA_STATEMENTS (JSON→JSONB, DATETIME(3)→TIMESTAMPTZ(3),
|
|
5
|
+
* inline KEY→separate CREATE INDEX).
|
|
6
|
+
*
|
|
7
|
+
* SCHEMA POLICY: see the header of pg-pool.ts — the code is the single source of truth, schema changes are
|
|
8
|
+
* drop-and-recreate, and NO new `ALTER TABLE` seams are added here; fold into the CREATE instead. */
|
|
4
9
|
export const PG_APPROVAL_SCHEMA = [
|
|
5
10
|
`CREATE TABLE IF NOT EXISTS approval (
|
|
6
11
|
id VARCHAR(64) NOT NULL,
|
|
@@ -24,18 +29,24 @@ export const PG_APPROVAL_SCHEMA = [
|
|
|
24
29
|
`CREATE INDEX IF NOT EXISTS idx_approval_status ON approval (status)`,
|
|
25
30
|
`CREATE INDEX IF NOT EXISTS idx_approval_scope_status ON approval (scope, status)`,
|
|
26
31
|
];
|
|
32
|
+
/** Idempotent self-contained schema apply (for the integration test; central aggregation is done separately). */
|
|
27
33
|
export async function ensureSchema(pool) {
|
|
28
34
|
for (const stmt of PG_APPROVAL_SCHEMA)
|
|
29
35
|
await pool.query(stmt);
|
|
30
36
|
}
|
|
37
|
+
/** Dual-dialect durable approval store. See the file header for the dialect-delta ledger. */
|
|
31
38
|
export class SqlApprovalStore {
|
|
32
39
|
db;
|
|
33
40
|
constructor(db) {
|
|
34
41
|
this.db = db;
|
|
35
42
|
}
|
|
43
|
+
/** Pick the dialect's SQL text. Both statements stay written out at the call site ON PURPOSE. */
|
|
36
44
|
q(tidb, pg) {
|
|
37
45
|
return this.db.dialect === "tidb" ? tidb : pg;
|
|
38
46
|
}
|
|
47
|
+
/** JSON column binding: TiDB stores the string verbatim; PG goes through the LOSSLESS protocol envelope
|
|
48
|
+
* (codex R4-H2 — the approval `args` is the operator's review surface and must agree with the
|
|
49
|
+
* policy-executed args at the NUL position). */
|
|
39
50
|
json(value, label) {
|
|
40
51
|
return this.db.dialect === "tidb" ? JSON.stringify(value) : pgProtocolJsonStringify(value, label);
|
|
41
52
|
}
|
|
@@ -54,16 +65,23 @@ export class SqlApprovalStore {
|
|
|
54
65
|
]);
|
|
55
66
|
}
|
|
56
67
|
async getStatus(id, scope) {
|
|
68
|
+
// null-safe scope match (`<=>` / `IS NOT DISTINCT FROM`): a NULL scope row (legacy / untenanted run) is
|
|
69
|
+
// matched by a NULL scope arg, and a tenant's scope NEVER matches another tenant's — the single-DB fleet
|
|
70
|
+
// read guard (defense-in-depth).
|
|
57
71
|
const { rows } = await this.db.query(this.q("SELECT status, reason, decided_by FROM approval WHERE id = ? AND scope <=> ?", "SELECT status, reason, decided_by FROM approval WHERE id = $1 AND scope IS NOT DISTINCT FROM $2"), [id, scope]);
|
|
58
72
|
const r = rows[0];
|
|
59
73
|
if (!r)
|
|
60
74
|
return undefined;
|
|
61
75
|
return { status: r.status, reason: r.reason ?? null, decidedBy: r.decided_by ?? null };
|
|
62
76
|
}
|
|
77
|
+
/** Apply a terminal decision, but only to a still-pending row (CAS). Returns whether it applied. The scope
|
|
78
|
+
* guard (null-safe) is carried on the operator path too for consistency with the read paths. */
|
|
63
79
|
async decide(id, scope, decision, reason, decidedBy) {
|
|
64
80
|
const res = await this.db.query(this.q("UPDATE approval SET status = ?, reason = ?, decided_by = ?, decided_at = ? WHERE id = ? AND scope <=> ? AND status = 'pending'", "UPDATE approval SET status = $1, reason = $2, decided_by = $3, decided_at = $4 WHERE id = $5 AND scope IS NOT DISTINCT FROM $6 AND status = 'pending'"), [decision, reason, decidedBy, new Date(), id, scope]);
|
|
65
81
|
return res.affected === 1;
|
|
66
82
|
}
|
|
83
|
+
/** Pending approvals (operator queue), scoped to one tenant (single-DB fleet read guard, null-safe), optionally
|
|
84
|
+
* further filtered to one owner. */
|
|
67
85
|
async listPending(scope, owner) {
|
|
68
86
|
const { rows } = owner
|
|
69
87
|
? await this.db.query(this.q("SELECT * FROM approval WHERE status = 'pending' AND scope <=> ? AND owner = ? ORDER BY created_at ASC", "SELECT * FROM approval WHERE status = 'pending' AND scope IS NOT DISTINCT FROM $1 AND owner = $2 ORDER BY created_at ASC"), [scope, owner])
|
|
@@ -74,14 +92,25 @@ export class SqlApprovalStore {
|
|
|
74
92
|
const { rows } = await this.db.query(this.q("SELECT * FROM approval WHERE id = ? AND scope <=> ?", "SELECT * FROM approval WHERE id = $1 AND scope IS NOT DISTINCT FROM $2"), [id, scope]);
|
|
75
93
|
return rows[0] ? mapRow(rows[0]) : undefined;
|
|
76
94
|
}
|
|
95
|
+
/** Operator-only CROSS-tenant by-id read (no scope filter). The F4 operator queue serves/decides across
|
|
96
|
+
* tenants by design; the HTTP layer gates this to an operator and then re-binds decide() to the row's OWN
|
|
97
|
+
* scope. Tenants NEVER reach this — they use the scope-bound {@link get}. */
|
|
77
98
|
async getById(id) {
|
|
78
99
|
const { rows } = await this.db.query(this.q("SELECT * FROM approval WHERE id = ?", "SELECT * FROM approval WHERE id = $1"), [id]);
|
|
79
100
|
return rows[0] ? mapRow(rows[0]) : undefined;
|
|
80
101
|
}
|
|
102
|
+
/** Operator-only CROSS-tenant pending list (no scope filter) — the unfiltered operator queue across all
|
|
103
|
+
* tenants. Tenants use the scope-bound {@link listPending}; this is HTTP-gated to an operator.
|
|
104
|
+
* 🔴 identical SQL text on both dialects (no placeholders, nothing dialect-specific) — kept as ONE literal
|
|
105
|
+
* rather than a `q()` pair so a reader isn't misled into looking for a divergence that isn't there. */
|
|
81
106
|
async listPendingAll() {
|
|
82
107
|
const { rows } = await this.db.query("SELECT * FROM approval WHERE status = 'pending' ORDER BY created_at ASC");
|
|
83
108
|
return rows.map(mapRow);
|
|
84
109
|
}
|
|
110
|
+
/** Expire pending approvals older than `olderThanMs` (a never-answered operator request). Deliberately GLOBAL
|
|
111
|
+
* (NOT scope-filtered): staleness expiry is fleet-level maintenance that protects the worker regardless of
|
|
112
|
+
* tenant — a stale row in any scope must be reaped. Scope isolation applies to the per-tenant READ paths, not
|
|
113
|
+
* to this maintenance sweep. */
|
|
85
114
|
async expireStale(olderThanMs) {
|
|
86
115
|
const cutoff = new Date(Date.now() - olderThanMs);
|
|
87
116
|
const res = await this.db.query(this.q("UPDATE approval SET status = 'expired', reason = 'timed out before decision', decided_at = ? " +
|
|
@@ -90,6 +119,7 @@ export class SqlApprovalStore {
|
|
|
90
119
|
return res.affected;
|
|
91
120
|
}
|
|
92
121
|
}
|
|
122
|
+
/** approval row → {@link ApprovalRow} — shared by BOTH dialects. design/158 S8 归位 / A12 收编. */
|
|
93
123
|
export function mapRow(r) {
|
|
94
124
|
return {
|
|
95
125
|
id: String(r.id),
|
|
@@ -106,11 +136,13 @@ export function mapRow(r) {
|
|
|
106
136
|
decidedAt: iso(r.decided_at),
|
|
107
137
|
};
|
|
108
138
|
}
|
|
139
|
+
/** MySQL-protocol (TiDB) binding — historical class name + ctor shape preserved. */
|
|
109
140
|
export class TiDBApprovalStore extends SqlApprovalStore {
|
|
110
141
|
constructor(pool) {
|
|
111
142
|
super(mysqlDriver(pool));
|
|
112
143
|
}
|
|
113
144
|
}
|
|
145
|
+
/** PostgreSQL binding — historical class name + ctor shape preserved. */
|
|
114
146
|
export class PgApprovalStore extends SqlApprovalStore {
|
|
115
147
|
constructor(pool) {
|
|
116
148
|
super(pgDriver(pool));
|
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BackgroundAgentStore SQL twins(design/151 S1 server 半场,[1503] 提货单②)——core
|
|
3
|
+
* `RunnerDeps.backgroundAgentStore` / `SubagentToolOptions.background.agentStore` 的 TiDB/PG
|
|
4
|
+
* 双方言实现:每个后台子代(`a*` 句柄)一行 durable 执行记录。
|
|
5
|
+
*
|
|
6
|
+
* 语义对齐真源 = core `InMemoryBackgroundAgentStore`(dist/core/background-agent-store.js),
|
|
7
|
+
* 契约四条([1503] 必守):
|
|
8
|
+
* 1. `put` create-once:重复 (scope, handle) 键 → `BackgroundAgentStoreError("agent_record.already_exists")`
|
|
9
|
+
* (唯一键原子,多副本安全);scope 缺席/空串拒收(与 core 同文案——default-deny 谓词下无 scope 的
|
|
10
|
+
* 行会经 fallback 面变成公共可读)。
|
|
11
|
+
* 2. `update` rev-CAS:整行替换,`WHERE … AND rev = expect.rev`,命中即 `rev = expect.rev + 1`;
|
|
12
|
+
* 未命中 false(心跳静默主体在 core 调用侧,store 侧诚实——同 roster 语义条 3,绝不吞成假成功)。
|
|
13
|
+
* 3. `listBySession`/`listByScope` content-free:只 SELECT 摘要列(绝不拉 record_json——finalOutput/
|
|
14
|
+
* recentSteps 可能是大 blob);session 锚 = `sessionScoped ? owner : parentSessionId`,写入时物化为
|
|
15
|
+
* `session_anchor` 列(anchor 为 NULL 的行 `= ?` 恒假 = core `anchor !== sessionId` 同义)。
|
|
16
|
+
* 4. `delete` 条件删(可选 rev CAS);`reap` 三策略与 core 逐条同形(staleRunning 翻 failed 走
|
|
17
|
+
* rev-CAS 逐行,竞态输了跳过不计;terminal maxAge/keep 按 spawnedAt DESC)。[1522] LOW6 记账:裸
|
|
18
|
+
* `reap` 的批删 IN 无上界、stale 臂全量拉 record_json——server 自己的 retention 只走
|
|
19
|
+
* reapDurableAgents(core 编排,不触这两条);第三方直调超大 scope 时自行分批。
|
|
20
|
+
*
|
|
21
|
+
* 行形:`record_json` = 全量真源(get 逐位读回);查询/谓词列全是投影,写入时从 record 物化
|
|
22
|
+
* (展示列 name/agent_type 截到列宽 + PG 侧过 lossy 清洗——真源仍在 record_json;身份键列
|
|
23
|
+
* scope/handle/owner/session 锚**不清洗不截断**:改写身份键会让行与 engine 查询键错位,含不可存
|
|
24
|
+
* 字节的身份键=写入失败 fail-loud,与 [1439] 协议数据拒绝式同向)。
|
|
25
|
+
* PG unstorable bytes([1439] 三层定谳):record/usage 走 `pgSafeJsonStringify`(观测/内容面 lossy
|
|
26
|
+
* U+FFFD,与 run 行/journal 同族;终报含真 NUL 的病态输入换替换标记,内容面不失行);TiDB TEXT 存 verbatim。
|
|
27
|
+
*
|
|
28
|
+
* 键列 = 字节等价(TiDB VARBINARY / PG COLLATE "C"——roster F2 同案:PAD SPACE/大小写近撞不得穿过
|
|
29
|
+
* scope 隔离键)。`listReapScopes()` 是 server 侧扩展(非 core 接口)——reaper 的 DISTINCT-scope 枚举,
|
|
30
|
+
* 与 workflow-run store 的 reapAllScopes 同姿势。
|
|
31
|
+
*/
|
|
1
32
|
import type { Pool } from "mysql2/promise";
|
|
2
33
|
import { type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentStore } from "@sema-agent/core";
|
|
3
34
|
import type { PgQueryFn } from "./pg-query.js";
|
|
@@ -21,6 +52,9 @@ export declare class TiDBBackgroundAgentStore implements BackgroundAgentStore {
|
|
|
21
52
|
update(handle: string, scope: string, record: BackgroundAgentRecord, expect: {
|
|
22
53
|
rev: number;
|
|
23
54
|
}): Promise<boolean>;
|
|
55
|
+
/** core 1.383([1565] 提货单)REQUIRED 新方法——原子守卫 CAS(claim 的 reservation/rollback/finalize
|
|
56
|
+
* 绑定字段态非仅 rev:rev 可因无关写移动而字段义已变)。语义逐字对齐 core InMemoryBackgroundAgentStore
|
|
57
|
+
* ({@link parkGuardConditions} 顶注)。 */
|
|
24
58
|
updateIf(handle: string, scope: string, record: BackgroundAgentRecord, expect: {
|
|
25
59
|
rev: number;
|
|
26
60
|
status?: BackgroundAgentRecord["status"];
|
|
@@ -32,7 +66,22 @@ export declare class TiDBBackgroundAgentStore implements BackgroundAgentStore {
|
|
|
32
66
|
delete(handle: string, scope: string, expect?: {
|
|
33
67
|
rev: number;
|
|
34
68
|
}): Promise<boolean>;
|
|
69
|
+
/** 🔴 返回值语义 = **受影响的不同行数**,不是「翻转数 + 删除数」的和(core 1.411 起)。
|
|
70
|
+
*
|
|
71
|
+
* core 1.411 把自己 InMemory 的 `return touched + doomed.size` 改成
|
|
72
|
+
* `return new Set([...flippedKeys, ...doomed]).size` —— 因为一行可能在**同一轮** reap 里既被翻转
|
|
73
|
+
* (stale running → failed)、又因为翻转后变成终态而落进 maxAge/keep 的删除集,旧写法把它算了两次。
|
|
74
|
+
* 这条被真双库对拆套件当场抓到(升 core 1.411 后 `tidb: reaped 计数: expected 4 to be 3`,core 1.404
|
|
75
|
+
* 下同文件全绿 —— A/B 判明是 core 的语义修,我们跟上)。
|
|
76
|
+
*
|
|
77
|
+
* ⚠️ 两个引擎**机制不同但语义一致**:PG 有 `DELETE … RETURNING handle`,可以单语句拿到真被删的 handle
|
|
78
|
+
* 直接并入同一个 Set;TiDB/MySQL **没有 RETURNING**,`affectedRows` 只给数量不给身份,所以按「是否已在
|
|
79
|
+
* 翻转集里」把 doomed 拆两批删 —— 重叠那批照样真删、只是不再计数。两边都不能用「doomed.size 当删除数」
|
|
80
|
+
* 近似:并发写者(真心跳复活)会让 `status <> 'running'` 守卫少删几行,那时 doomed.size 会虚高。 */
|
|
35
81
|
reap(scope: string, now: number, opts?: ReapOpts): Promise<number>;
|
|
82
|
+
/** core 1.368([1516]②)可选接口成员落位(原 server 扩展 listReapScopes 更名对齐):当前持行
|
|
83
|
+
* scope 枚举——reaper 的 per-scope 联合 reap 入口。JS 侧 sort 与 core InMemory 逐字节同序
|
|
84
|
+
* (SQL ORDER BY 按 collation,非码元序)。 */
|
|
36
85
|
listScopes(): Promise<string[]>;
|
|
37
86
|
}
|
|
38
87
|
export declare class PgBackgroundAgentStore implements BackgroundAgentStore {
|
|
@@ -43,6 +92,8 @@ export declare class PgBackgroundAgentStore implements BackgroundAgentStore {
|
|
|
43
92
|
update(handle: string, scope: string, record: BackgroundAgentRecord, expect: {
|
|
44
93
|
rev: number;
|
|
45
94
|
}): Promise<boolean>;
|
|
95
|
+
/** core 1.383([1565] 提货单)REQUIRED 新方法(TiDB twin 同案注释)。PG 侧占位符是显式编号 `$N`
|
|
96
|
+
* (不像 TiDB `?` 靠数组顺序)——`n` 是跑动计数器,只在真正消耗一个占位符(非 IS NULL 分支)时前增。 */
|
|
46
97
|
updateIf(handle: string, scope: string, record: BackgroundAgentRecord, expect: {
|
|
47
98
|
rev: number;
|
|
48
99
|
status?: BackgroundAgentRecord["status"];
|
|
@@ -54,7 +105,11 @@ export declare class PgBackgroundAgentStore implements BackgroundAgentStore {
|
|
|
54
105
|
delete(handle: string, scope: string, expect?: {
|
|
55
106
|
rev: number;
|
|
56
107
|
}): Promise<boolean>;
|
|
108
|
+
/** 返回值 = 受影响的**不同行数**(core 1.411 语义;TiDB twin 的方法头注写了完整由来 + A/B 取证)。
|
|
109
|
+
* PG 这半有 `DELETE … RETURNING handle`,所以真被删的 handle 直接并进同一个 Set —— 不需要 TiDB 那边的
|
|
110
|
+
* 「拆两批发」变通,但两边的**结果**必须逐个相等(真双库对拆套件按 core InMemory 的计数逐字比)。 */
|
|
57
111
|
reap(scope: string, now: number, opts?: ReapOpts): Promise<number>;
|
|
112
|
+
/** core 1.368 可选接口成员(TiDB twin 同案注释)。 */
|
|
58
113
|
listScopes(): Promise<string[]>;
|
|
59
114
|
}
|
|
60
115
|
export {};
|
|
@@ -2,16 +2,28 @@ import { BackgroundAgentStoreError, } from "@sema-agent/core";
|
|
|
2
2
|
import { pgSafeJsonStringify, pgSanitizeText } from "./pg-safe-json.js";
|
|
3
3
|
export const BACKGROUND_AGENT_TABLE = "background_agents";
|
|
4
4
|
const SUMMARY_COLS = "handle, owner, session_scoped, session_id, parent_session_id, root_session_id, name, agent_type, status, spawned_at_ms, updated_at_ms, settled_at_ms, usage_json";
|
|
5
|
+
/** put/update 共用的投影列(scope_key/handle 键列另拼;record_json 恒最后)。core 1.383([1565] 提货单)
|
|
6
|
+
* `updateIf` 的 CAS 守卫需要 `parked_checkpoint_token`/`park_claim_id` 是**专用列**——守卫条件必须在
|
|
7
|
+
* 数据库层面对当前行状态原子求值,不能只靠 record_json 这个 blob(那要求先读后写,读写之间就是
|
|
8
|
+
* CAS 本要堵的竞态窗)。`writerEpoch` 不在此列:updateIf 的 guard 参数集里没有它([1565] 原文/core
|
|
9
|
+
* 类型签名逐字核对过),只是 record_json 全量对象序列化里随手带上的普通字段,不需要专用列——
|
|
10
|
+
* record_json 的写法是 `json(stored)`(stored = `{...record, handle, scope, rev}` 整个对象展开),
|
|
11
|
+
* 任何 record 上有的字段(含 writerEpoch)天然随之落盘/读回,无需逐字段维护投影列表。 */
|
|
5
12
|
const PROJ_COLS = "scope, owner, session_scoped, session_id, parent_session_id, root_session_id, session_anchor, name, agent_type, status, spawned_at_ms, updated_at_ms, settled_at_ms, usage_json, rev, parked_checkpoint_token, park_claim_id, record_json";
|
|
6
|
-
const PROJ_N = PROJ_COLS.split(", ").length;
|
|
13
|
+
const PROJ_N = PROJ_COLS.split(", ").length; // F5: WHERE 占位符序号从列数派生,列序变更单点同步
|
|
7
14
|
function assertScope(record) {
|
|
8
15
|
if (record.scope === undefined || record.scope === "") {
|
|
16
|
+
// core InMemory 同文案(default-deny 谓词下无 scope 行=经 fallback 面公共可读,写入即拒)
|
|
9
17
|
throw new Error("BackgroundAgentStore.put: refusing a row without a scope (world-readable through the fallback)");
|
|
10
18
|
}
|
|
11
19
|
}
|
|
20
|
+
/** stored 形归一(core put/update 语义:handle/scope/rev 以参数为准,record_json 存归一后的整行)。 */
|
|
12
21
|
function storedForm(record, handle, scope, rev) {
|
|
13
22
|
return { ...record, handle, scope, rev };
|
|
14
23
|
}
|
|
24
|
+
/** 投影参数(键列除外,与 PROJ_COLS 同序)。json 序列化器/展示文本清洗器按方言注入([1439]:PG
|
|
25
|
+
* lossy 标记,TiDB verbatim)。展示列截到列宽(#3:超长 name 不该让整行 durable 写失败——真源在
|
|
26
|
+
* record_json,摘要投影截断是诚实形)。 */
|
|
15
27
|
function projParams(stored, json, text) {
|
|
16
28
|
return [
|
|
17
29
|
stored.scope,
|
|
@@ -34,6 +46,7 @@ function projParams(stored, json, text) {
|
|
|
34
46
|
json(stored),
|
|
35
47
|
];
|
|
36
48
|
}
|
|
49
|
+
/** 摘要行 → core BackgroundAgentRowSummary(缺席键省略,core toSummary 形逐字;usage 从 usage_json)。 */
|
|
37
50
|
function rowToSummary(r) {
|
|
38
51
|
return {
|
|
39
52
|
handle: String(r.handle),
|
|
@@ -53,6 +66,7 @@ function rowToSummary(r) {
|
|
|
53
66
|
: {}),
|
|
54
67
|
};
|
|
55
68
|
}
|
|
69
|
+
/** core reap 的 staleRunning 翻转形(逐字段照抄 InMemory:summary 只在缺席时补默认句)。 */
|
|
56
70
|
function flippedForm(live, now) {
|
|
57
71
|
return {
|
|
58
72
|
...live,
|
|
@@ -63,6 +77,7 @@ function flippedForm(live, now) {
|
|
|
63
77
|
updatedAt: now,
|
|
64
78
|
};
|
|
65
79
|
}
|
|
80
|
+
/** terminal doomed 集合(core reap 的 maxAge + keep 两策略;rows 已按 spawnedAt DESC)。 */
|
|
66
81
|
function doomedHandles(rows, now, opts) {
|
|
67
82
|
const doomed = new Set();
|
|
68
83
|
if (opts.maxAgeMs !== undefined) {
|
|
@@ -77,6 +92,11 @@ function doomedHandles(rows, now, opts) {
|
|
|
77
92
|
}
|
|
78
93
|
return doomed;
|
|
79
94
|
}
|
|
95
|
+
/** core 1.383([1565] 提货单,design/153 件3a)`updateIf` 的三个可选守卫条件——dialect-neutral 描述,
|
|
96
|
+
* 各方言自行渲染成 `?`(TiDB)或 `$N`(PG)占位符。core InMemoryBackgroundAgentStore.updateIf 逐字同源
|
|
97
|
+
* (background-agent-store.js:175-187)语义:`value === null` = 该列当前**必须缺席**(SQL `IS NULL`,
|
|
98
|
+
* 对应 core `live.X !== undefined` 的取反);`value` 是字符串 = 必须**字面相等**;字段整体缺席
|
|
99
|
+
* (expect.X === undefined,不在返回数组里)= 不设该条守卫,与该列当前值无关。 */
|
|
80
100
|
function parkGuardConditions(expect) {
|
|
81
101
|
const out = [];
|
|
82
102
|
if (expect.status !== undefined)
|
|
@@ -91,12 +111,38 @@ function reapInert(opts) {
|
|
|
91
111
|
return !opts || (opts.maxAgeMs === undefined && opts.keep === undefined && opts.staleRunningMaxAgeMs === undefined);
|
|
92
112
|
}
|
|
93
113
|
function limitClause(limit) {
|
|
114
|
+
// #2 病态边界与 core slice 语义对齐:Infinity=全量(无 LIMIT),NaN/-Infinity=空(LIMIT 0)
|
|
94
115
|
if (limit === undefined || limit === Infinity)
|
|
95
116
|
return "";
|
|
96
117
|
const n = Math.floor(limit);
|
|
97
118
|
return ` LIMIT ${Number.isFinite(n) ? Math.max(0, n) : 0}`;
|
|
98
119
|
}
|
|
120
|
+
/* ┌─ 历史:曾经的运行期 ADD COLUMN 迁移腿(已折进 CREATE,2026-07-26 clay 裁「删库重建」)──────────┐
|
|
121
|
+
* 两个 ensure 曾在每次 boot 给 `background_agents` 补三列;现已全部折叠为 CREATE TABLE 里的列定义。
|
|
122
|
+
* 保留由来,因为它解释了这些列**为什么存在**,以及当年为什么 TiDB 腿用探针而不是 `IF NOT EXISTS`:
|
|
123
|
+
*
|
|
124
|
+
* ① root_session_id(core 1.367 δ,additive):1.248 建的存量表没有这列,靠迁移补。
|
|
125
|
+
* ② parked_checkpoint_token / park_claim_id(core 1.383,[1565] 提货单 / design/153 件3a,ε,additive):
|
|
126
|
+
* 1.382 前建的表没有这两列。它们**必须是专用列**(不能只躺在 record_json 里)的理由见 {@link PROJ_COLS}
|
|
127
|
+
* 顶注:`updateIf` 的 CAS 守卫要在数据库层面对当前行状态原子求值。
|
|
128
|
+
*
|
|
129
|
+
* ③ 为什么 TiDB 腿曾是 `information_schema.COLUMNS` **探针 + ALTER** 两步,而不是一条
|
|
130
|
+
* `ADD COLUMN IF NOT EXISTS`(复审 F2):**MySQL 8 没有该语法**(TiDB/MariaDB 才有),而本仓
|
|
131
|
+
* MySQL-protocol 口径要求可移植——tidb-pool.ts COLUMN_MIGRATIONS 同姿势。PG 腿则本来就用 IF NOT EXISTS。
|
|
132
|
+
* ⚠️ 这个探针姿势有一个真实缺陷([1522] LOW5,当年如实记并判定可接受):探针→ALTER **不是原子的**,
|
|
133
|
+
* 多副本并发首 boot 存在竞态窗——两个副本双双探到缺列、一方 ALTER 赢、另一方 ALTER 撞
|
|
134
|
+
* 「column exists」砖**当次** boot;下次 boot 探到列在即自愈。
|
|
135
|
+
* → 折叠后该窗**消失**:新库列由 CREATE TABLE 一次建全,不存在「探到缺列再补」的第二步;
|
|
136
|
+
* `CREATE TABLE IF NOT EXISTS` 本身在服务端是单条原子 DDL,并发首 boot 只有「建了」/「已存在」两态。
|
|
137
|
+
*
|
|
138
|
+
* ④ 语义位:当年 `root_session_id IS NULL` 兼有「pre-δ 行」一义。删库重建后**不再产生**这类行——NULL
|
|
139
|
+
* 只剩「该记录没有 root 锚」一义。读侧因此**仍然可达**、一律不动:{@link rowToSummary} 的
|
|
140
|
+
* root_session_id 条件展开、listBySession 的 `root_session_id = ?` 第二臂(NULL 行恒不命中)、
|
|
141
|
+
* 以及 parked 两列的 `IS NULL` 守卫({@link parkGuardConditions}:那是 core 的 CAS 语义,不是迁移遗留)。
|
|
142
|
+
* └────────────────────────────────────────────────────────────────────────────────────────────┘ */
|
|
99
143
|
export async function ensureTiDBBackgroundAgentSchema(pool) {
|
|
144
|
+
// VARBINARY 键列(roster F2 同案):scope/handle 的 '=' 必须是纯字节——utf8mb4_bin 仍 PAD SPACE,
|
|
145
|
+
// 'x' 与 'x ' 会同键。record_json LONGTEXT:终报快照(finalOutput/recentSteps)可超 64K TEXT。
|
|
100
146
|
await pool.query(`CREATE TABLE IF NOT EXISTS ${BACKGROUND_AGENT_TABLE} (
|
|
101
147
|
scope_key VARBINARY(190) NOT NULL,
|
|
102
148
|
handle VARBINARY(190) NOT NULL,
|
|
@@ -127,6 +173,7 @@ export async function ensureTiDBBackgroundAgentSchema(pool) {
|
|
|
127
173
|
) COLLATE utf8mb4_bin`);
|
|
128
174
|
}
|
|
129
175
|
export async function ensurePgBackgroundAgentSchema(q) {
|
|
176
|
+
// COLLATE "C"(roster F2 双方言对齐):隔离键列的 '=' 必须字节等价。
|
|
130
177
|
await q(`CREATE TABLE IF NOT EXISTS ${BACKGROUND_AGENT_TABLE} (
|
|
131
178
|
scope_key VARCHAR(190) COLLATE "C" NOT NULL,
|
|
132
179
|
handle VARCHAR(190) COLLATE "C" NOT NULL,
|
|
@@ -183,6 +230,9 @@ export class TiDBBackgroundAgentStore {
|
|
|
183
230
|
WHERE scope_key = ? AND handle = ? AND rev = ?`, [...projParams(stored, JSON.stringify, (t) => t), scope, handle, expect.rev]));
|
|
184
231
|
return res.affectedRows === 1;
|
|
185
232
|
}
|
|
233
|
+
/** core 1.383([1565] 提货单)REQUIRED 新方法——原子守卫 CAS(claim 的 reservation/rollback/finalize
|
|
234
|
+
* 绑定字段态非仅 rev:rev 可因无关写移动而字段义已变)。语义逐字对齐 core InMemoryBackgroundAgentStore
|
|
235
|
+
* ({@link parkGuardConditions} 顶注)。 */
|
|
186
236
|
async updateIf(handle, scope, record, expect) {
|
|
187
237
|
const stored = storedForm(record, handle, scope, expect.rev + 1);
|
|
188
238
|
const guards = parkGuardConditions(expect);
|
|
@@ -206,6 +256,18 @@ export class TiDBBackgroundAgentStore {
|
|
|
206
256
|
const [res] = (await this.pool.query(`DELETE FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND handle = ?${expect !== undefined ? " AND rev = ?" : ""}`, expect !== undefined ? [scope, handle, expect.rev] : [scope, handle]));
|
|
207
257
|
return res.affectedRows === 1;
|
|
208
258
|
}
|
|
259
|
+
/** 🔴 返回值语义 = **受影响的不同行数**,不是「翻转数 + 删除数」的和(core 1.411 起)。
|
|
260
|
+
*
|
|
261
|
+
* core 1.411 把自己 InMemory 的 `return touched + doomed.size` 改成
|
|
262
|
+
* `return new Set([...flippedKeys, ...doomed]).size` —— 因为一行可能在**同一轮** reap 里既被翻转
|
|
263
|
+
* (stale running → failed)、又因为翻转后变成终态而落进 maxAge/keep 的删除集,旧写法把它算了两次。
|
|
264
|
+
* 这条被真双库对拆套件当场抓到(升 core 1.411 后 `tidb: reaped 计数: expected 4 to be 3`,core 1.404
|
|
265
|
+
* 下同文件全绿 —— A/B 判明是 core 的语义修,我们跟上)。
|
|
266
|
+
*
|
|
267
|
+
* ⚠️ 两个引擎**机制不同但语义一致**:PG 有 `DELETE … RETURNING handle`,可以单语句拿到真被删的 handle
|
|
268
|
+
* 直接并入同一个 Set;TiDB/MySQL **没有 RETURNING**,`affectedRows` 只给数量不给身份,所以按「是否已在
|
|
269
|
+
* 翻转集里」把 doomed 拆两批删 —— 重叠那批照样真删、只是不再计数。两边都不能用「doomed.size 当删除数」
|
|
270
|
+
* 近似:并发写者(真心跳复活)会让 `status <> 'running'` 守卫少删几行,那时 doomed.size 会虚高。 */
|
|
209
271
|
async reap(scope, now, opts) {
|
|
210
272
|
if (reapInert(opts))
|
|
211
273
|
return 0;
|
|
@@ -214,14 +276,22 @@ export class TiDBBackgroundAgentStore {
|
|
|
214
276
|
const [stale] = (await this.pool.query(`SELECT handle, record_json FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND status = 'running' AND updated_at_ms < ?`, [scope, now - opts.staleRunningMaxAgeMs]));
|
|
215
277
|
for (const row of stale) {
|
|
216
278
|
const live = JSON.parse(String(row.record_json));
|
|
279
|
+
// rev-CAS 翻转:并发写者(真心跳复活/别副本先翻)赢了就跳过不计——core 单进程无此窗,SQL 侧诚实
|
|
217
280
|
if (await this.update(String(row.handle), scope, flippedForm(live, now), { rev: live.rev }))
|
|
218
281
|
flipped.add(String(row.handle));
|
|
219
282
|
}
|
|
220
283
|
}
|
|
284
|
+
// core 1.382([1561] 提货单③;InMemoryBackgroundAgentStore.reap 逐字同源,background-agent-store.js:206
|
|
285
|
+
// `r.status !== "running" && r.status !== "parked"`):doomed 候选池排除 parked——parked 是非活非终态
|
|
286
|
+
// (durably suspended pending approval),`doomedHandles` 只按 spawnedAt/settledAt 判定年龄/keep 排名,
|
|
287
|
+
// 完全不看 status,所以排除必须在这条 SQL WHERE 里做到,不能指望 JS 侧再筛一次(它收到的行里根本
|
|
288
|
+
// 没带 status 字段)。
|
|
221
289
|
const [term] = (await this.pool.query(`SELECT handle, spawned_at_ms, settled_at_ms FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = ? AND status <> 'running' AND status <> 'parked' ORDER BY spawned_at_ms DESC, handle DESC`, [scope]));
|
|
222
290
|
const doomed = doomedHandles(term.map((r) => ({ handle: String(r.handle), spawnedAt: Number(r.spawned_at_ms), settledAt: r.settled_at_ms === null ? null : Number(r.settled_at_ms) })), now, opts);
|
|
223
291
|
if (doomed.size === 0)
|
|
224
292
|
return flipped.size;
|
|
293
|
+
// 去重(见方法头注):本轮已翻转过的 handle 若同时落进 doomed,删它但**不再计数**。
|
|
294
|
+
// 无 RETURNING ⇒ 拆两批发,靠「哪一批」而不是靠返回的身份来分辨。
|
|
225
295
|
const alreadyCounted = [...doomed].filter((h) => flipped.has(h));
|
|
226
296
|
const newlyAffected = [...doomed].filter((h) => !flipped.has(h));
|
|
227
297
|
const del = async (handles) => {
|
|
@@ -230,10 +300,16 @@ export class TiDBBackgroundAgentStore {
|
|
|
230
300
|
};
|
|
231
301
|
const deletedNew = newlyAffected.length > 0 ? await del(newlyAffected) : 0;
|
|
232
302
|
if (alreadyCounted.length > 0)
|
|
233
|
-
await del(alreadyCounted);
|
|
303
|
+
await del(alreadyCounted); // 真删,计数已由 flipped 承担
|
|
234
304
|
return flipped.size + deletedNew;
|
|
235
305
|
}
|
|
306
|
+
/** core 1.368([1516]②)可选接口成员落位(原 server 扩展 listReapScopes 更名对齐):当前持行
|
|
307
|
+
* scope 枚举——reaper 的 per-scope 联合 reap 入口。JS 侧 sort 与 core InMemory 逐字节同序
|
|
308
|
+
* (SQL ORDER BY 按 collation,非码元序)。 */
|
|
236
309
|
async listScopes() {
|
|
310
|
+
// [1522] MED1(两路复审撞车坐实):枚举必须走 **scope_key 字节列**——utf8mb4_bin 的 VARCHAR DISTINCT
|
|
311
|
+
// 仍 PAD SPACE,尾空格近撞 scope 被塌缩成一个,塌缩掉的分区永不被 reap(行/转录无界)。键纪律
|
|
312
|
+
// 贯彻到枚举面;VARBINARY 读回 Buffer → utf8 归一。
|
|
237
313
|
const [rows] = (await this.pool.query(`SELECT DISTINCT scope_key FROM ${BACKGROUND_AGENT_TABLE}`));
|
|
238
314
|
return rows.map((r) => (Buffer.isBuffer(r.scope_key) ? r.scope_key.toString("utf8") : String(r.scope_key))).sort();
|
|
239
315
|
}
|
|
@@ -246,6 +322,8 @@ export class PgBackgroundAgentStore {
|
|
|
246
322
|
async put(record) {
|
|
247
323
|
assertScope(record);
|
|
248
324
|
const stored = storedForm(record, record.handle, record.scope, record.rev ?? 0);
|
|
325
|
+
// create-once:ON CONFLICT DO NOTHING + RETURNING——空 rows = 键已存在(PgQueryFn 无 rowCount,
|
|
326
|
+
// RETURNING 是双方言里 PG 侧的 affected 判别;错误码路径留给真障碍)。
|
|
249
327
|
const { rows } = await this.q(`INSERT INTO ${BACKGROUND_AGENT_TABLE} (scope_key, handle, ${PROJ_COLS})
|
|
250
328
|
VALUES (${Array.from({ length: PROJ_N + 2 }, (_, i) => `$${i + 1}`).join(", ")})
|
|
251
329
|
ON CONFLICT (scope_key, handle) DO NOTHING RETURNING handle`, [stored.scope, stored.handle, ...projParams(stored, pgSafeJsonStringify, pgSanitizeText)]);
|
|
@@ -263,11 +341,13 @@ export class PgBackgroundAgentStore {
|
|
|
263
341
|
WHERE scope_key = $${PROJ_N + 1} AND handle = $${PROJ_N + 2} AND rev = $${PROJ_N + 3} RETURNING handle`, [...projParams(stored, pgSafeJsonStringify, pgSanitizeText), scope, handle, expect.rev]);
|
|
264
342
|
return rows.length === 1;
|
|
265
343
|
}
|
|
344
|
+
/** core 1.383([1565] 提货单)REQUIRED 新方法(TiDB twin 同案注释)。PG 侧占位符是显式编号 `$N`
|
|
345
|
+
* (不像 TiDB `?` 靠数组顺序)——`n` 是跑动计数器,只在真正消耗一个占位符(非 IS NULL 分支)时前增。 */
|
|
266
346
|
async updateIf(handle, scope, record, expect) {
|
|
267
347
|
const stored = storedForm(record, handle, scope, expect.rev + 1);
|
|
268
348
|
const setParams = projParams(stored, pgSafeJsonStringify, pgSanitizeText);
|
|
269
349
|
const guards = parkGuardConditions(expect);
|
|
270
|
-
let n = setParams.length + 3;
|
|
350
|
+
let n = setParams.length + 3; // + scope_key/handle/rev,三条基础守卫已固定占用 setParams.length+1..+3
|
|
271
351
|
const guardSql = guards.map((g) => (g.value === null ? `${g.column} IS NULL` : `${g.column} = $${++n}`)).join(" AND ");
|
|
272
352
|
const guardParams = guards.filter((g) => g.value !== null).map((g) => g.value);
|
|
273
353
|
const { rows } = await this.q(`UPDATE ${BACKGROUND_AGENT_TABLE} SET ${PROJ_COLS.split(", ").map((c, i) => `${c} = $${i + 1}`).join(", ")}
|
|
@@ -288,6 +368,9 @@ export class PgBackgroundAgentStore {
|
|
|
288
368
|
const { rows } = await this.q(`DELETE FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = $1 AND handle = $2${expect !== undefined ? " AND rev = $3" : ""} RETURNING handle`, expect !== undefined ? [scope, handle, expect.rev] : [scope, handle]);
|
|
289
369
|
return rows.length === 1;
|
|
290
370
|
}
|
|
371
|
+
/** 返回值 = 受影响的**不同行数**(core 1.411 语义;TiDB twin 的方法头注写了完整由来 + A/B 取证)。
|
|
372
|
+
* PG 这半有 `DELETE … RETURNING handle`,所以真被删的 handle 直接并进同一个 Set —— 不需要 TiDB 那边的
|
|
373
|
+
* 「拆两批发」变通,但两边的**结果**必须逐个相等(真双库对拆套件按 core InMemory 的计数逐字比)。 */
|
|
291
374
|
async reap(scope, now, opts) {
|
|
292
375
|
if (reapInert(opts))
|
|
293
376
|
return 0;
|
|
@@ -300,16 +383,20 @@ export class PgBackgroundAgentStore {
|
|
|
300
383
|
affected.add(String(row.handle));
|
|
301
384
|
}
|
|
302
385
|
}
|
|
386
|
+
// core 1.382([1561] 提货单③;TiDB twin 同案注释)——doomed 候选池排除 parked。
|
|
303
387
|
const { rows: term } = await this.q(`SELECT handle, spawned_at_ms, settled_at_ms FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = $1 AND status <> 'running' AND status <> 'parked' ORDER BY spawned_at_ms DESC, handle DESC`, [scope]);
|
|
304
388
|
const doomed = doomedHandles(term.map((r) => ({ handle: String(r.handle), spawnedAt: Number(r.spawned_at_ms), settledAt: r.settled_at_ms === null ? null : Number(r.settled_at_ms) })), now, opts);
|
|
305
389
|
if (doomed.size === 0)
|
|
306
390
|
return affected.size;
|
|
307
391
|
const { rows: deleted } = await this.q(`DELETE FROM ${BACKGROUND_AGENT_TABLE} WHERE scope_key = $1 AND status <> 'running' AND status <> 'parked' AND handle IN (${[...doomed].map((_, i) => `$${i + 2}`).join(", ")}) RETURNING handle`, [scope, ...doomed]);
|
|
308
392
|
for (const r of deleted)
|
|
309
|
-
affected.add(String(r.handle));
|
|
393
|
+
affected.add(String(r.handle)); // 同一 Set ⇒ 翻转+删除的同一行只算一次
|
|
310
394
|
return affected.size;
|
|
311
395
|
}
|
|
396
|
+
/** core 1.368 可选接口成员(TiDB twin 同案注释)。 */
|
|
312
397
|
async listScopes() {
|
|
398
|
+
// [1522] MED1(TiDB twin 同案注):枚举走 COLLATE "C" 的 scope_key 键列——非确定性缺省 collation
|
|
399
|
+
// 部署下 VARCHAR DISTINCT 同构塌缩,键列字节确定。
|
|
313
400
|
const { rows } = await this.q(`SELECT DISTINCT scope_key FROM ${BACKGROUND_AGENT_TABLE}`);
|
|
314
401
|
return rows.map((r) => String(r.scope_key)).sort();
|
|
315
402
|
}
|