@sema-agent/server 1.322.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 +59 -3
- 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,43 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/103 — shared support for the remote (TOB) `BackgroundShellCapability` implementations.
|
|
3
|
+
*
|
|
4
|
+
* core defines the seam (`@sema-agent/core` `BackgroundShellCapability` + `hasBackgroundShell`) and ships the TOC
|
|
5
|
+
* reference (`NodeExecutionEnv`). This module centralises the **security + lifecycle red-lines** that EVERY remote
|
|
6
|
+
* adapter (E2B, kata/k8s, …) must enforce identically, so a transport author only writes the 4 transport
|
|
7
|
+
* primitives and cannot accidentally re-implement (or skip) an invariant:
|
|
8
|
+
*
|
|
9
|
+
* - **opaque shellId** — a fresh `bg_<n>_<uuid>` brand, NEVER derived from the provider's job/pid (越权红线,
|
|
10
|
+
* design/103 §3.8). The provider id lives only inside the driver state.
|
|
11
|
+
* - **owned-id isolation** — `poll`/`kill` look the shellId up in THIS manager's registry; an id from another env
|
|
12
|
+
* (or a forged one) is `not_found`, never resolved against the provider (design/103 §3.8 / interface 越权契约).
|
|
13
|
+
* - **maxConcurrent** — counts only `running` shells (terminal entries are kept for residual polling but free their
|
|
14
|
+
* slot, so "KillShell one first" is actionable — matches the TOC `maxConcurrent 终态占槽` review fix).
|
|
15
|
+
* - **timeout hard wall** — a control-plane timer kills the shell and flips it to `killed` at the bounded BG
|
|
16
|
+
* timeout (design/103 §3.6); the driver may set an additional provider-level backstop ≥ this wall.
|
|
17
|
+
* - **dispose** — kills + cleans up EVERY shell, best-effort, MUST NOT throw, idempotent (design/103 §3.7).
|
|
18
|
+
*
|
|
19
|
+
* The two transports legitimately take different "按-id-可重读" paths (design/103 §5.2): E2B holds a resident
|
|
20
|
+
* `CommandHandle` reader feeding a control-plane tail buffer (path ②); kata/k8s buffers into pod-side files
|
|
21
|
+
* re-read by byte cursor on each poll (path ①). Both are expressed through {@link BackgroundShellDriver}.
|
|
22
|
+
*/
|
|
1
23
|
import { BackgroundShellError } from "@sema-agent/core";
|
|
2
24
|
import type { BackgroundShellId, BackgroundPoll, BackgroundSpawnOptions, Result } from "@sema-agent/core";
|
|
3
25
|
import { StringDecoder } from "node:string_decoder";
|
|
26
|
+
/** Per-端 background capability bounds, surfaced as `backgroundCapabilities` on the env (design/103 §3.1/§3.6).
|
|
27
|
+
*
|
|
28
|
+
* ⚠️ 有据不接:core 契约的 `retainBackgroundProcesses` 能力字段【有意】不在此声明(2026-07-08 定谳):
|
|
29
|
+
* TB 的声明与兑现全在 core 自己 runtime 内闭环(sema-tb bin 进程内 TOC local env 声明,core task-registry
|
|
30
|
+
* settle/reap 双门控读取)——service env 全程不在链上;k8s/e2b 隔离 env 拆机进程必然消亡,声明只是名义。
|
|
31
|
+
* 接单信号=「远端 TB / 常驻服务题落到 service host env」,届时切片很薄(dispose `{except}` 管道已通,
|
|
32
|
+
* retain 只是 env 级常开白名单)。 */
|
|
4
33
|
export interface BackgroundCaps {
|
|
5
34
|
readonly supported: boolean;
|
|
6
35
|
readonly maxConcurrent: number;
|
|
7
36
|
readonly defaultBgTimeoutSec: number;
|
|
8
37
|
readonly maxBgTimeoutSec: number;
|
|
9
38
|
}
|
|
39
|
+
/** One stream's adopt-mode drain state. `pendingBytes` = queued-undrained (≤ cap); `totalBytes` = cursor metadata. */
|
|
10
40
|
export interface BgMemStream {
|
|
11
41
|
chunks: string[];
|
|
12
42
|
pendingBytes: number;
|
|
13
43
|
totalBytes: number;
|
|
14
44
|
droppedBytes: number;
|
|
45
|
+
/** Per-stream stateful UTF-8 decoder for Buffer inputs (WS frames / pipe chunks split at arbitrary byte offsets —
|
|
46
|
+
* a multibyte codepoint straddling two chunks must NOT decode to U+FFFD; the incomplete tail rides to the next
|
|
47
|
+
* write). Mirrors the fg-path `StringDecoder` (remote-env-k8s.ts runExec, council BUG#1). Undefined until first
|
|
48
|
+
* Buffer feed. STRING inputs (E2B-style, already decoded by the SDK) bypass it. */
|
|
15
49
|
decoder?: StringDecoder;
|
|
16
50
|
}
|
|
51
|
+
/** Fresh drain buffer pre-seeded with the output captured before adoption (rides the first poll). `initialDropped` =
|
|
52
|
+
* bytes the fg segment's rolling-tail already evicted (surfaced as `truncated` on the first drain — the seed text is
|
|
53
|
+
* RAW, so the truncation marker is NOT baked into the stream content: review LOW, avoids double-marking + accounting
|
|
54
|
+
* pollution). */
|
|
17
55
|
export declare function seedMemStream(text: string, initialDropped?: number): BgMemStream;
|
|
56
|
+
/** Append a live chunk, evicting the OLDEST queued chunks beyond `cap` (counted → surfaced as `truncated`). A Buffer
|
|
57
|
+
* goes through the per-stream StringDecoder (multibyte-safe across chunk boundaries); a string passes through. */
|
|
18
58
|
export declare function feedMemStream(s: BgMemStream, d: Buffer | string, cap: number): void;
|
|
59
|
+
/** Drain everything queued since the last read (a driver `read`); resets the pending queue + dropped counter. */
|
|
19
60
|
export declare function drainMemStream(s: BgMemStream): {
|
|
20
61
|
text: string;
|
|
21
62
|
dropped: number;
|
|
22
63
|
};
|
|
64
|
+
/** Context handed to {@link BackgroundShellDriver.launch}. */
|
|
23
65
|
export interface LaunchCtx {
|
|
66
|
+
/**
|
|
67
|
+
* Push-model terminal notification (E2B `CommandHandle.wait()` resolves/rejects): the driver invokes this exactly
|
|
68
|
+
* once when the process ends. Pull-model drivers (k8s, which discovers termination during {@link
|
|
69
|
+
* BackgroundShellDriver.read}) simply never call it and return `terminal` from `read` instead. The manager
|
|
70
|
+
* ignores either source once a shell has left `running` (kill/timeout win).
|
|
71
|
+
*/
|
|
24
72
|
onTerminal(failed: boolean, exitCode?: number): void;
|
|
73
|
+
/** Bounded effective BG timeout (sec) the driver MAY use as a provider-level backstop. ≥ the manager hard wall. */
|
|
25
74
|
readonly bgTimeoutSec: number;
|
|
26
75
|
}
|
|
76
|
+
/** One poll's worth of driver output: raw increment since the driver's own cursor + head-evict accounting. */
|
|
27
77
|
export interface DriverPoll {
|
|
78
|
+
/** New stdout since last read (RAW — core's `BashOutput` tool applies `filter` + display truncation). */
|
|
28
79
|
stdout: string;
|
|
80
|
+
/** New stderr since last read. */
|
|
29
81
|
stderr: string;
|
|
82
|
+
/** Total output bytes the process has produced from start (cursor metadata; design/103 §3.4). */
|
|
30
83
|
bytesFromStart: number;
|
|
84
|
+
/** Bytes permanently lost to head-eviction before this read's cursor (0 if none). */
|
|
31
85
|
bytesDroppedBeforeCursor: number;
|
|
86
|
+
/**
|
|
87
|
+
* Pull-model termination signal (k8s): the process is no longer running. `undefined` ⇒ still running / unknown.
|
|
88
|
+
* Push-model drivers (E2B) leave this `undefined` and use {@link LaunchCtx.onTerminal} instead.
|
|
89
|
+
*/
|
|
32
90
|
terminal?: {
|
|
33
91
|
failed: boolean;
|
|
34
92
|
exitCode?: number;
|
|
35
93
|
};
|
|
36
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Transport primitives a remote adapter implements. The driver owns its per-shell state `S` (handles, tail buffers,
|
|
97
|
+
* pod-side cursors) and the transport mechanics; the {@link BackgroundShellManager} owns all the shared invariants.
|
|
98
|
+
*/
|
|
37
99
|
export interface BackgroundShellDriver<S> {
|
|
100
|
+
/** Launch a detached process. Return per-shell transport state. MUST NOT block on exit. Throw `BackgroundShellError` on failure. */
|
|
38
101
|
launch(command: string, options: BackgroundSpawnOptions | undefined, ctx: LaunchCtx): Promise<S>;
|
|
102
|
+
/** Read incremental output (+ maybe terminal). Safe to call repeatedly across independent poll calls. */
|
|
39
103
|
read(state: S): Promise<DriverPoll>;
|
|
104
|
+
/** Transport-level kill (best-effort, idempotent — killing an already-dead process is a no-op). */
|
|
40
105
|
kill(state: S): Promise<void>;
|
|
106
|
+
/** Best-effort cleanup of ONE shell's transport resources (kill + remove temp dirs/handles). Should not throw. */
|
|
41
107
|
disposeOne(state: S): Promise<void>;
|
|
42
108
|
}
|
|
43
109
|
export declare class BackgroundShellManager<S> {
|
|
@@ -46,18 +112,50 @@ export declare class BackgroundShellManager<S> {
|
|
|
46
112
|
private readonly shells;
|
|
47
113
|
private counter;
|
|
48
114
|
constructor(driver: BackgroundShellDriver<S>, caps: BackgroundCaps);
|
|
115
|
+
/** [1116] 六轮复审:destroy 端判「还有 shell 依赖 spool 文件吗」——running(驻留 keep-alive)与
|
|
116
|
+
* terminal 残余(dispose 前仍可轮询)都算;有=env 不得整树删 spool 根(逐 shell 清理归 dispose 面)。 */
|
|
49
117
|
hasShells(): boolean;
|
|
118
|
+
/** Count live shells; KillShell/timeout flip a shell out of `running` and free its slot. */
|
|
50
119
|
private liveCount;
|
|
120
|
+
/** Bound heap: evict the OLDEST terminal entries (never a running one) once the registry exceeds the retention cap. */
|
|
51
121
|
private evictOldTerminal;
|
|
52
122
|
spawn(command: string, options?: BackgroundSpawnOptions): Promise<Result<{
|
|
53
123
|
shellId: BackgroundShellId;
|
|
54
124
|
}, BackgroundShellError>>;
|
|
125
|
+
/**
|
|
126
|
+
* design/116 detach (clay 排,1.81): adopt an EXTERNALLY-created RUNNING process as a background shell — the
|
|
127
|
+
* mid-flight ctrl+b path, where the process was spawned by a FOREGROUND `exec` and must move under this
|
|
128
|
+
* manager's ownership instead of being killed. The `builder` receives the same {@link LaunchCtx} a driver
|
|
129
|
+
* `launch` would (terminal notification + the bounded BG timeout it may use as a backstop) and returns the
|
|
130
|
+
* driver state the normal `read`/`kill`/`disposeOne` primitives operate on — after adoption the shell is
|
|
131
|
+
* indistinguishable from a spawned one (poll/kill/dispose/timeout wall all apply). Returns `undefined` when
|
|
132
|
+
* the live-shell limit is hit OR the builder throws: detach REFUSED, the caller keeps the process running in
|
|
133
|
+
* the foreground (core NodeExecutionEnv semantics — never a silently dropped process).
|
|
134
|
+
*
|
|
135
|
+
* 🔴 SYNCHRONOUS by contract (double-review of the first async cut, 3 confirmed findings): the builder must
|
|
136
|
+
* attach the live child's pipe listeners in the SAME synchronous tick it snapshots the seed, with NO `await`
|
|
137
|
+
* before registration — otherwise (a) output produced during an async open/mkdir window is lost, (b) file fds
|
|
138
|
+
* leak on natural exit, and (c) an exec-settle can race the async adoption and orphan a shell. A sync builder
|
|
139
|
+
* (memory-buffered, no files) closes all three: no Node data/close event can interleave a synchronous block.
|
|
140
|
+
*
|
|
141
|
+
* 🔴 builder side-effect contract (Fable-5 review #5): the catch below returns undefined WITHOUT undoing any
|
|
142
|
+
* side effects the builder already performed (listener attach, stream reroute). A builder must therefore be
|
|
143
|
+
* all-or-nothing: put every operation that can throw BEFORE the first side effect, or clean up on the throw
|
|
144
|
+
* path itself. Today's three lane builders are entirely non-throwing (listener attach + object construction).
|
|
145
|
+
*/
|
|
55
146
|
adoptSync(builder: (ctx: LaunchCtx) => S, timeoutSec?: number): {
|
|
56
147
|
shellId: BackgroundShellId;
|
|
57
148
|
} | undefined;
|
|
149
|
+
/** The shared spawn/adopt body: limit check, opaque id, terminal-latch buffering, BG-timeout hard wall. */
|
|
58
150
|
private register;
|
|
59
151
|
poll(shellId: BackgroundShellId): Promise<Result<BackgroundPoll, BackgroundShellError>>;
|
|
60
152
|
kill(shellId: BackgroundShellId): Promise<Result<void, BackgroundShellError>>;
|
|
153
|
+
/** Kill + clean up EVERY shell. Best-effort, MUST NOT throw, idempotent (design/103 §3.7).
|
|
154
|
+
*
|
|
155
|
+
* core `except` 契约(background-shell.d.ts:core runtask 尾调 `{except: keepAlive}`):
|
|
156
|
+
* 这些 shellId **留活**——session 驻留 persistent Monitor 的进程,其全部意义就是跨 turn 存活;run-end
|
|
157
|
+
* 全灭会留下「registry handle 活着、进程死了」的孤儿 watch。留活条目连注册表一起保留(poll/kill 继续
|
|
158
|
+
* 可用,timeout 墙钟 timer 不清=到点照杀)。无参=既有全灭行为(suspend/review 前的 dispose 不带 except)。 */
|
|
61
159
|
dispose(opts?: {
|
|
62
160
|
except?: readonly BackgroundShellId[];
|
|
63
161
|
}): Promise<void>;
|
|
@@ -1,16 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/103 — shared support for the remote (TOB) `BackgroundShellCapability` implementations.
|
|
3
|
+
*
|
|
4
|
+
* core defines the seam (`@sema-agent/core` `BackgroundShellCapability` + `hasBackgroundShell`) and ships the TOC
|
|
5
|
+
* reference (`NodeExecutionEnv`). This module centralises the **security + lifecycle red-lines** that EVERY remote
|
|
6
|
+
* adapter (E2B, kata/k8s, …) must enforce identically, so a transport author only writes the 4 transport
|
|
7
|
+
* primitives and cannot accidentally re-implement (or skip) an invariant:
|
|
8
|
+
*
|
|
9
|
+
* - **opaque shellId** — a fresh `bg_<n>_<uuid>` brand, NEVER derived from the provider's job/pid (越权红线,
|
|
10
|
+
* design/103 §3.8). The provider id lives only inside the driver state.
|
|
11
|
+
* - **owned-id isolation** — `poll`/`kill` look the shellId up in THIS manager's registry; an id from another env
|
|
12
|
+
* (or a forged one) is `not_found`, never resolved against the provider (design/103 §3.8 / interface 越权契约).
|
|
13
|
+
* - **maxConcurrent** — counts only `running` shells (terminal entries are kept for residual polling but free their
|
|
14
|
+
* slot, so "KillShell one first" is actionable — matches the TOC `maxConcurrent 终态占槽` review fix).
|
|
15
|
+
* - **timeout hard wall** — a control-plane timer kills the shell and flips it to `killed` at the bounded BG
|
|
16
|
+
* timeout (design/103 §3.6); the driver may set an additional provider-level backstop ≥ this wall.
|
|
17
|
+
* - **dispose** — kills + cleans up EVERY shell, best-effort, MUST NOT throw, idempotent (design/103 §3.7).
|
|
18
|
+
*
|
|
19
|
+
* The two transports legitimately take different "按-id-可重读" paths (design/103 §5.2): E2B holds a resident
|
|
20
|
+
* `CommandHandle` reader feeding a control-plane tail buffer (path ②); kata/k8s buffers into pod-side files
|
|
21
|
+
* re-read by byte cursor on each poll (path ①). Both are expressed through {@link BackgroundShellDriver}.
|
|
22
|
+
*/
|
|
1
23
|
import { BackgroundShellError } from "@sema-agent/core";
|
|
2
24
|
import { randomUUID } from "node:crypto";
|
|
3
25
|
import { StringDecoder } from "node:string_decoder";
|
|
4
26
|
const ok = (value) => ({ ok: true, value });
|
|
5
27
|
const fail = (error) => ({ ok: false, error });
|
|
28
|
+
/** Fresh drain buffer pre-seeded with the output captured before adoption (rides the first poll). `initialDropped` =
|
|
29
|
+
* bytes the fg segment's rolling-tail already evicted (surfaced as `truncated` on the first drain — the seed text is
|
|
30
|
+
* RAW, so the truncation marker is NOT baked into the stream content: review LOW, avoids double-marking + accounting
|
|
31
|
+
* pollution). */
|
|
6
32
|
export function seedMemStream(text, initialDropped = 0) {
|
|
7
33
|
const n = Buffer.byteLength(text, "utf8");
|
|
8
34
|
return { chunks: text ? [text] : [], pendingBytes: n, totalBytes: n, droppedBytes: initialDropped };
|
|
9
35
|
}
|
|
36
|
+
/** Append a live chunk, evicting the OLDEST queued chunks beyond `cap` (counted → surfaced as `truncated`). A Buffer
|
|
37
|
+
* goes through the per-stream StringDecoder (multibyte-safe across chunk boundaries); a string passes through. */
|
|
10
38
|
export function feedMemStream(s, d, cap) {
|
|
11
39
|
const text = typeof d === "string" ? d : (s.decoder ??= new StringDecoder("utf8")).write(d);
|
|
12
40
|
if (!text)
|
|
13
|
-
return;
|
|
41
|
+
return; // decoder buffered an incomplete-codepoint tail → nothing to enqueue this frame
|
|
14
42
|
const n = Buffer.byteLength(text, "utf8");
|
|
15
43
|
s.chunks.push(text);
|
|
16
44
|
s.pendingBytes += n;
|
|
@@ -21,14 +49,21 @@ export function feedMemStream(s, d, cap) {
|
|
|
21
49
|
s.pendingBytes -= db;
|
|
22
50
|
s.droppedBytes += db;
|
|
23
51
|
}
|
|
52
|
+
// A SINGLE chunk larger than the cap (a giant WS frame / one enormous SDK string) is not covered by the
|
|
53
|
+
// drop-oldest loop above (it never evicts the last chunk) — trim its HEAD so the retained bytes stay ~cap
|
|
54
|
+
// instead of max(cap, largestChunk) (the cap comment otherwise promised more than the
|
|
55
|
+
// code delivered). Byte-slice like RollingTailBuffer's partial head-drop: a multibyte codepoint cut at the trim
|
|
56
|
+
// point decodes to replacement char(s) at the very start of the retained tail (may exceed cap by a few bytes on
|
|
57
|
+
// re-measure) — harmless, the stream is already marked truncated.
|
|
24
58
|
if (s.pendingBytes > cap && s.chunks.length === 1) {
|
|
25
59
|
const only = Buffer.from(s.chunks[0], "utf8");
|
|
26
60
|
const over = only.length - cap;
|
|
27
61
|
s.chunks[0] = only.subarray(over).toString("utf8");
|
|
28
|
-
s.pendingBytes = Buffer.byteLength(s.chunks[0], "utf8");
|
|
62
|
+
s.pendingBytes = Buffer.byteLength(s.chunks[0], "utf8"); // re-measure: the cut may add a replacement char
|
|
29
63
|
s.droppedBytes += over;
|
|
30
64
|
}
|
|
31
65
|
}
|
|
66
|
+
/** Drain everything queued since the last read (a driver `read`); resets the pending queue + dropped counter. */
|
|
32
67
|
export function drainMemStream(s) {
|
|
33
68
|
const text = s.chunks.join("");
|
|
34
69
|
s.chunks = [];
|
|
@@ -37,6 +72,17 @@ export function drainMemStream(s) {
|
|
|
37
72
|
s.droppedBytes = 0;
|
|
38
73
|
return { text, dropped };
|
|
39
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Drives the {@link BackgroundShellCapability} contract over a {@link BackgroundShellDriver}. One instance per env
|
|
77
|
+
* (its registry == that env's owned shells), so cross-env / forged ids never resolve.
|
|
78
|
+
*/
|
|
79
|
+
/**
|
|
80
|
+
* Recent terminal (exited/killed/failed) shells are kept pollable for residual output until dispose (design/103),
|
|
81
|
+
* but an unbounded run that spawns thousands of short background shells would otherwise accumulate them — and each
|
|
82
|
+
* E2B entry pins an 8MB tail buffer — until the task ends (workflow MED, worker-heap bound). Cap how many terminal
|
|
83
|
+
* entries linger: evicting the OLDEST → a later poll of it is `not_found` ("already reaped"), which the BashOutput
|
|
84
|
+
* tool already handles gracefully.
|
|
85
|
+
*/
|
|
40
86
|
const RETAIN_TERMINAL = 32;
|
|
41
87
|
export class BackgroundShellManager {
|
|
42
88
|
driver;
|
|
@@ -47,9 +93,12 @@ export class BackgroundShellManager {
|
|
|
47
93
|
this.driver = driver;
|
|
48
94
|
this.caps = caps;
|
|
49
95
|
}
|
|
96
|
+
/** [1116] 六轮复审:destroy 端判「还有 shell 依赖 spool 文件吗」——running(驻留 keep-alive)与
|
|
97
|
+
* terminal 残余(dispose 前仍可轮询)都算;有=env 不得整树删 spool 根(逐 shell 清理归 dispose 面)。 */
|
|
50
98
|
hasShells() {
|
|
51
99
|
return this.shells.size > 0;
|
|
52
100
|
}
|
|
101
|
+
/** Count live shells; KillShell/timeout flip a shell out of `running` and free its slot. */
|
|
53
102
|
liveCount() {
|
|
54
103
|
let n = 0;
|
|
55
104
|
for (const e of this.shells.values())
|
|
@@ -57,6 +106,7 @@ export class BackgroundShellManager {
|
|
|
57
106
|
n++;
|
|
58
107
|
return n;
|
|
59
108
|
}
|
|
109
|
+
/** Bound heap: evict the OLDEST terminal entries (never a running one) once the registry exceeds the retention cap. */
|
|
60
110
|
evictOldTerminal() {
|
|
61
111
|
const max = this.caps.maxConcurrent + RETAIN_TERMINAL;
|
|
62
112
|
if (this.shells.size <= max)
|
|
@@ -65,7 +115,7 @@ export class BackgroundShellManager {
|
|
|
65
115
|
if (this.shells.size <= max)
|
|
66
116
|
break;
|
|
67
117
|
if (e.status === "running")
|
|
68
|
-
continue;
|
|
118
|
+
continue; // never evict a live shell
|
|
69
119
|
this.shells.delete(id);
|
|
70
120
|
if (e.timer)
|
|
71
121
|
clearTimeout(e.timer);
|
|
@@ -75,11 +125,33 @@ export class BackgroundShellManager {
|
|
|
75
125
|
async spawn(command, options) {
|
|
76
126
|
return this.register((ctx) => this.driver.launch(command, options, ctx), options?.timeout);
|
|
77
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* design/116 detach (clay 排,1.81): adopt an EXTERNALLY-created RUNNING process as a background shell — the
|
|
130
|
+
* mid-flight ctrl+b path, where the process was spawned by a FOREGROUND `exec` and must move under this
|
|
131
|
+
* manager's ownership instead of being killed. The `builder` receives the same {@link LaunchCtx} a driver
|
|
132
|
+
* `launch` would (terminal notification + the bounded BG timeout it may use as a backstop) and returns the
|
|
133
|
+
* driver state the normal `read`/`kill`/`disposeOne` primitives operate on — after adoption the shell is
|
|
134
|
+
* indistinguishable from a spawned one (poll/kill/dispose/timeout wall all apply). Returns `undefined` when
|
|
135
|
+
* the live-shell limit is hit OR the builder throws: detach REFUSED, the caller keeps the process running in
|
|
136
|
+
* the foreground (core NodeExecutionEnv semantics — never a silently dropped process).
|
|
137
|
+
*
|
|
138
|
+
* 🔴 SYNCHRONOUS by contract (double-review of the first async cut, 3 confirmed findings): the builder must
|
|
139
|
+
* attach the live child's pipe listeners in the SAME synchronous tick it snapshots the seed, with NO `await`
|
|
140
|
+
* before registration — otherwise (a) output produced during an async open/mkdir window is lost, (b) file fds
|
|
141
|
+
* leak on natural exit, and (c) an exec-settle can race the async adoption and orphan a shell. A sync builder
|
|
142
|
+
* (memory-buffered, no files) closes all three: no Node data/close event can interleave a synchronous block.
|
|
143
|
+
*
|
|
144
|
+
* 🔴 builder side-effect contract (Fable-5 review #5): the catch below returns undefined WITHOUT undoing any
|
|
145
|
+
* side effects the builder already performed (listener attach, stream reroute). A builder must therefore be
|
|
146
|
+
* all-or-nothing: put every operation that can throw BEFORE the first side effect, or clean up on the throw
|
|
147
|
+
* path itself. Today's three lane builders are entirely non-throwing (listener attach + object construction).
|
|
148
|
+
*/
|
|
78
149
|
adoptSync(builder, timeoutSec) {
|
|
79
150
|
if (this.liveCount() >= this.caps.maxConcurrent)
|
|
80
|
-
return undefined;
|
|
151
|
+
return undefined; // refused → exec keeps the foreground
|
|
152
|
+
// Bounded BG timeout — never unbounded (design/103 §3.6). `maxBgTimeoutSec` is the fail-closed ceiling.
|
|
81
153
|
const bgTimeoutSec = Math.min(Math.max(1, timeoutSec ?? this.caps.defaultBgTimeoutSec), this.caps.maxBgTimeoutSec);
|
|
82
|
-
const shellId = `bg_${++this.counter}_${randomUUID()}`;
|
|
154
|
+
const shellId = `bg_${++this.counter}_${randomUUID()}`; // opaque — never the provider pid (§3.8)
|
|
83
155
|
const applyTerminal = (e, failed, exitCode) => {
|
|
84
156
|
if (e.status !== "running")
|
|
85
157
|
return;
|
|
@@ -89,6 +161,8 @@ export class BackgroundShellManager {
|
|
|
89
161
|
if (e.timer)
|
|
90
162
|
clearTimeout(e.timer);
|
|
91
163
|
};
|
|
164
|
+
// terminal-latch: an already-exited adopted child fires onTerminal DURING the builder (before shells.set) —
|
|
165
|
+
// buffer it, drain after registration (else the shell lies "running" until the timeout wall).
|
|
92
166
|
let entry;
|
|
93
167
|
let pending;
|
|
94
168
|
const onTerminal = (failed, exitCode) => {
|
|
@@ -99,10 +173,10 @@ export class BackgroundShellManager {
|
|
|
99
173
|
};
|
|
100
174
|
let state;
|
|
101
175
|
try {
|
|
102
|
-
state = builder({ onTerminal, bgTimeoutSec });
|
|
176
|
+
state = builder({ onTerminal, bgTimeoutSec }); // SYNC — no await, no interleaving event
|
|
103
177
|
}
|
|
104
178
|
catch {
|
|
105
|
-
return undefined;
|
|
179
|
+
return undefined; // adoption failed → exec keeps the foreground (never a dropped process)
|
|
106
180
|
}
|
|
107
181
|
const timer = setTimeout(() => {
|
|
108
182
|
const e = this.shells.get(shellId);
|
|
@@ -119,21 +193,29 @@ export class BackgroundShellManager {
|
|
|
119
193
|
this.evictOldTerminal();
|
|
120
194
|
return { shellId };
|
|
121
195
|
}
|
|
196
|
+
/** The shared spawn/adopt body: limit check, opaque id, terminal-latch buffering, BG-timeout hard wall. */
|
|
122
197
|
async register(launch, timeoutSec) {
|
|
123
198
|
if (this.liveCount() >= this.caps.maxConcurrent) {
|
|
124
199
|
return fail(new BackgroundShellError("limit_exceeded", `Too many running background shells (max ${this.caps.maxConcurrent}); KillShell one first.`));
|
|
125
200
|
}
|
|
201
|
+
// Bounded BG timeout — never unbounded (design/103 §3.6). `maxBgTimeoutSec` is the fail-closed ceiling.
|
|
126
202
|
const bgTimeoutSec = Math.min(Math.max(1, timeoutSec ?? this.caps.defaultBgTimeoutSec), this.caps.maxBgTimeoutSec);
|
|
203
|
+
// Opaque brand — NOT derived from the provider job/pid (design/103 §3.8 越权红线).
|
|
127
204
|
const shellId = `bg_${++this.counter}_${randomUUID()}`;
|
|
128
205
|
const applyTerminal = (e, failed, exitCode) => {
|
|
129
206
|
if (e.status !== "running")
|
|
130
|
-
return;
|
|
207
|
+
return; // kill / timeout already classified it (terminal-latch)
|
|
131
208
|
e.status = failed ? "failed" : "exited";
|
|
132
209
|
if (exitCode !== undefined)
|
|
133
210
|
e.exitCode = exitCode;
|
|
134
211
|
if (e.timer)
|
|
135
212
|
clearTimeout(e.timer);
|
|
136
213
|
};
|
|
214
|
+
// 🔴 A FAST-exiting process can settle `handle.wait()` and fire `onTerminal` (a microtask) BEFORE this method's
|
|
215
|
+
// post-`launch` continuation registers the entry — so onTerminal MUST buffer into `pendingTerminal` when the
|
|
216
|
+
// entry isn't live yet, and the continuation drains it after `shells.set` (else the shell would lie "running"
|
|
217
|
+
// until the timeout, wedging a maxConcurrent slot). (An ADOPTED child can equally have already
|
|
218
|
+
// exited between the detach request and adoption — the same latch covers it.)
|
|
137
219
|
let entry;
|
|
138
220
|
let pendingTerminal;
|
|
139
221
|
const onTerminal = (failed, exitCode) => {
|
|
@@ -153,21 +235,32 @@ export class BackgroundShellManager {
|
|
|
153
235
|
const e = this.shells.get(shellId);
|
|
154
236
|
if (!e || e.status !== "running")
|
|
155
237
|
return;
|
|
156
|
-
e.status = "killed";
|
|
238
|
+
e.status = "killed"; // BG timeout is a HARD wall → killed (design/103 §3.6)
|
|
157
239
|
void this.driver.kill(e.state).catch(() => { });
|
|
158
240
|
}, bgTimeoutSec * 1000);
|
|
159
241
|
timer.unref?.();
|
|
160
242
|
entry = { state, status: "running", timer };
|
|
161
243
|
this.shells.set(shellId, entry);
|
|
162
244
|
if (pendingTerminal)
|
|
163
|
-
applyTerminal(entry, pendingTerminal.failed, pendingTerminal.exitCode);
|
|
164
|
-
this.evictOldTerminal();
|
|
245
|
+
applyTerminal(entry, pendingTerminal.failed, pendingTerminal.exitCode); // process already exited during launch
|
|
246
|
+
this.evictOldTerminal(); // bound the heap (recent terminal shells stay pollable; old ones are reaped)
|
|
165
247
|
return ok({ shellId });
|
|
166
248
|
}
|
|
167
249
|
async poll(shellId) {
|
|
168
250
|
const entry = this.shells.get(shellId);
|
|
251
|
+
// Owned-id isolation: unknown / cross-env / forged id → not_found, never leak existence (design/103 §3.8).
|
|
169
252
|
if (!entry)
|
|
170
253
|
return fail(new BackgroundShellError("not_found", `Unknown background shell: ${shellId}`));
|
|
254
|
+
// 🔴 **状态快照必须在 read 之前取**(2026-07-26,一条整天间歇红的 CI 追下来的真缺陷)。
|
|
255
|
+
// push 模型的终态是**异步**落地的(host: `child.on("close") → ctx.onTerminal`;E2B: `wait()` resolve),
|
|
256
|
+
// 所以「先 read 再读 entry.status」存在这个窗口:
|
|
257
|
+
// 读完输出(尾巴还没写完)→ 进程写完尾巴并结束 → status 变终态 → 返回 `{stdout: 缺尾巴, status: 终态}`。
|
|
258
|
+
// 而 `BashOutput` 这类消费方**看到终态就停止轮询** ⇒ 那段尾巴此后没有任何人会去读 = **静默丢输出**。
|
|
259
|
+
// (单跑时窗口极窄——隔离跑 12/12 全绿;高并行负载下两个 await 之间被调度出去,窗口变宽就复现。)
|
|
260
|
+
// ⇒ 只把「read **之前**就已经是终态」或「本次 read **自己**带回 terminal」这两种情况报为终态:
|
|
261
|
+
// 前者说明这次读发生在进程结束之后(输出必然完整),后者是同一次读里的一致视图(输出与终态同源)。
|
|
262
|
+
// 终态若是在读**之后**才到的,这一拍如实报 `running` —— 消费方多轮询一拍即可拿到尾巴 + 终态。
|
|
263
|
+
// 代价:最多多一拍轮询。收益:「终态 ⇒ 输出已完整」这条消费方真正依赖的保证成立。
|
|
171
264
|
const statusBeforeRead = entry.status;
|
|
172
265
|
let r;
|
|
173
266
|
try {
|
|
@@ -176,6 +269,7 @@ export class BackgroundShellManager {
|
|
|
176
269
|
catch (e) {
|
|
177
270
|
return fail(e instanceof BackgroundShellError ? e : new BackgroundShellError("io", e instanceof Error ? e.message : String(e), e));
|
|
178
271
|
}
|
|
272
|
+
// Pull-model terminal reconciliation (k8s): apply only if not already classified by kill/timeout.
|
|
179
273
|
if (r.terminal && entry.status === "running") {
|
|
180
274
|
entry.status = r.terminal.failed ? "failed" : "exited";
|
|
181
275
|
if (r.terminal.exitCode !== undefined)
|
|
@@ -183,12 +277,14 @@ export class BackgroundShellManager {
|
|
|
183
277
|
if (entry.timer)
|
|
184
278
|
clearTimeout(entry.timer);
|
|
185
279
|
}
|
|
280
|
+
// 见上方旁注:读之后才到的终态,本拍不报(下一拍的快照就是终态,那时输出已完整)。
|
|
186
281
|
const reportTerminal = statusBeforeRead !== "running" || r.terminal !== undefined;
|
|
187
282
|
const reportedStatus = reportTerminal ? entry.status : "running";
|
|
188
283
|
return ok({
|
|
189
284
|
stdout: r.stdout,
|
|
190
285
|
stderr: r.stderr,
|
|
191
286
|
status: reportedStatus,
|
|
287
|
+
// exitCode 只随终态一起报——报 running 却带 exitCode 会让消费方读出自相矛盾的一拍。
|
|
192
288
|
...(reportTerminal && entry.exitCode !== undefined ? { exitCode: entry.exitCode } : {}),
|
|
193
289
|
...(r.bytesDroppedBeforeCursor > 0 ? { truncated: true, bytesDroppedBeforeCursor: r.bytesDroppedBeforeCursor } : {}),
|
|
194
290
|
bytesFromStart: r.bytesFromStart,
|
|
@@ -206,24 +302,31 @@ export class BackgroundShellManager {
|
|
|
206
302
|
await this.driver.kill(entry.state);
|
|
207
303
|
}
|
|
208
304
|
catch {
|
|
305
|
+
/* idempotent: killing an already-dead shell is a no-op success (design/103 §4.3) */
|
|
209
306
|
}
|
|
210
307
|
}
|
|
211
308
|
return ok(undefined);
|
|
212
309
|
}
|
|
310
|
+
/** Kill + clean up EVERY shell. Best-effort, MUST NOT throw, idempotent (design/103 §3.7).
|
|
311
|
+
*
|
|
312
|
+
* core `except` 契约(background-shell.d.ts:core runtask 尾调 `{except: keepAlive}`):
|
|
313
|
+
* 这些 shellId **留活**——session 驻留 persistent Monitor 的进程,其全部意义就是跨 turn 存活;run-end
|
|
314
|
+
* 全灭会留下「registry handle 活着、进程死了」的孤儿 watch。留活条目连注册表一起保留(poll/kill 继续
|
|
315
|
+
* 可用,timeout 墙钟 timer 不清=到点照杀)。无参=既有全灭行为(suspend/review 前的 dispose 不带 except)。 */
|
|
213
316
|
async dispose(opts) {
|
|
214
317
|
const keep = opts?.except?.length ? new Set(opts.except) : undefined;
|
|
215
318
|
const doomed = [];
|
|
216
319
|
if (keep) {
|
|
217
320
|
for (const [id, entry] of [...this.shells]) {
|
|
218
321
|
if (keep.has(id))
|
|
219
|
-
continue;
|
|
322
|
+
continue; // 留活:不 kill、不清 timer、不出注册表
|
|
220
323
|
this.shells.delete(id);
|
|
221
324
|
doomed.push(entry);
|
|
222
325
|
}
|
|
223
326
|
}
|
|
224
327
|
else {
|
|
225
328
|
doomed.push(...this.shells.values());
|
|
226
|
-
this.shells.clear();
|
|
329
|
+
this.shells.clear(); // idempotent: a second dispose iterates nothing
|
|
227
330
|
}
|
|
228
331
|
for (const entry of doomed) {
|
|
229
332
|
try {
|
|
@@ -234,6 +337,7 @@ export class BackgroundShellManager {
|
|
|
234
337
|
await this.driver.disposeOne(entry.state);
|
|
235
338
|
}
|
|
236
339
|
catch {
|
|
340
|
+
/* best-effort; disposeBackgroundShells MUST never throw (design/103 §3.7) */
|
|
237
341
|
}
|
|
238
342
|
}
|
|
239
343
|
}
|
|
@@ -1,26 +1,76 @@
|
|
|
1
1
|
import type { Pool as MysqlPool } from "mysql2/promise";
|
|
2
2
|
import type { Pool as PgPool } from "pg";
|
|
3
|
+
/** (a)(clay 拍 a+c,2026-07-27)tidb 方言的默认 per-blob 帽 = **6 MiB,TiDB 自己的默认
|
|
4
|
+
* `txn-entry-size-limit`**。两堵墙真库实测(k3s8 tidb-test v7.5.1 默认配置,2026-07-27 探针):
|
|
5
|
+
* 7MiB=`entry too large`(entry 墙,默认 6291456)、31MiB=同、32MiB=`max_allowed_packet`(包墙,
|
|
6
|
+
* 64MiB ÷ ~2× 文本协议膨胀)——矮墙是 entry 的 6MiB,不是先前推测的包墙 ~31MiB。帽=诚实拒绝:
|
|
7
|
+
* 超限 blob 在 query 之前 typed 拒(消费面 HTTP 413 / capture warn 拿到可行动信息);**帽拒绝的
|
|
8
|
+
* 在默认配置下本来也落不进去 ⇒ 零回归**。调大过 entry 限/packet 的部署用 SNAPSHOT_BLOB_SQL_MAX_BYTES
|
|
9
|
+
* 放宽(两方言都生效)。**pg 方言默认不设帽**(扩展协议无这两堵墙,不人为降档)。D-1 附件战役同墙
|
|
10
|
+
* 教训:task-attachment-store.ts:19。 */
|
|
3
11
|
export declare const SQL_BLOB_DEFAULT_MAX_BYTES = 6291456;
|
|
12
|
+
/** typed 判别错:blob 超过 SQL 店的承载帽。判别码供店侧结果映射/HTTP 面/日志使用——绝不能与
|
|
13
|
+
* transient 写失败混在一类(那类是可重试的 502;这类重试永远不会成功)。 */
|
|
4
14
|
export declare class BlobTooLargeError extends Error {
|
|
5
15
|
readonly code: "blob_too_large_for_sql";
|
|
6
16
|
constructor(byteLen: number, capBytes: number);
|
|
7
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* The content-addressed byte store. All four methods are keyed on the sha256 `hash` of the bytes:
|
|
20
|
+
* - putBlob: store bytes (idempotent — a repeat for the same hash is a no-op-equivalent; the SQL twin refreshes
|
|
21
|
+
* created_at so a just-written/re-used blob is GC-grace-protected). MinIO PUTs the object AND upserts the SQL INDEX.
|
|
22
|
+
* - getBlob: the bytes for `hash`, or undefined if absent. A TRANSIENT backend fault THROWS (so a restore/import fails
|
|
23
|
+
* LOUD, not a silent "missing blob"); only a genuine absence / corruption is undefined.
|
|
24
|
+
* - hasBlobs: the subset of `hashes` that already exist — a single SQL `IN(...)` over the index for BOTH backends
|
|
25
|
+
* (migration idempotency + reap probing + the §10 import presence pre-check; cheaper than a HEAD-per-hash on MinIO).
|
|
26
|
+
* - deleteBlobs: byte-delete the given hashes (called ONLY by the async sweep reaper). Honors the SAME created_at
|
|
27
|
+
* grace window as the SQL backend (MinIO reads the index's created_at) — delete-in-use is impossible. Returns the
|
|
28
|
+
* count ACTUALLY deleted (the grace-passed subset), so the sweep reports real work, not the pre-grace orphan count.
|
|
29
|
+
*/
|
|
8
30
|
export interface BlobBackend {
|
|
9
31
|
putBlob(hash: string, bytes: Uint8Array): Promise<void>;
|
|
10
32
|
getBlob(hash: string): Promise<Uint8Array | undefined>;
|
|
11
33
|
hasBlobs(hashes: string[]): Promise<Set<string>>;
|
|
12
34
|
deleteBlobs(hashes: string[]): Promise<number>;
|
|
13
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* SQL BlobBackend — the `snapshot_blob` table ops EXTRACTED VERBATIM from the tidb/pg file-snapshot stores (the
|
|
38
|
+
* created_at-refreshing upsert, the bytes SELECT, the grace-window orphan DELETE→deleteBlobs, a has via SELECT). Two
|
|
39
|
+
* dialect twins selected by `dialect`. Keeping the SQL byte-identical means the existing behaviour + the env-gated
|
|
40
|
+
* real-DB integration suite are unchanged when MinIO is unset (the DEFAULT backend the file-snapshot stores construct).
|
|
41
|
+
*
|
|
42
|
+
* NOTE deleteBlobs here is the BYTE delete ONLY — it does NOT do the `NOT IN (SELECT … snapshot_manifest)` orphan
|
|
43
|
+
* filter (that reference check stays in the file-snapshot store, which computes the orphan hash SET from the manifest
|
|
44
|
+
* and hands it here). The grace-window `created_at < cutoff` guard is RETAINED on the delete so a just-written blob
|
|
45
|
+
* that a concurrent in-flight snapshot still needs is never byte-deleted (delete-in-use is data loss; under-delete is
|
|
46
|
+
* harmless — the next sweep collects it).
|
|
47
|
+
*/
|
|
14
48
|
export declare class SqlBlobBackend implements BlobBackend {
|
|
15
49
|
private readonly dialect;
|
|
16
50
|
private readonly pool;
|
|
51
|
+
/** Effective per-blob cap: explicit ctor value wins; else tidb=SQL_BLOB_DEFAULT_MAX_BYTES, pg=uncapped. */
|
|
17
52
|
private readonly capBytes;
|
|
18
53
|
constructor(dialect: "tidb" | "pg", pool: MysqlPool | PgPool, maxBytes?: number);
|
|
54
|
+
/** The created_at-refreshing content-addressed upsert — VERBATIM the tidb/pg stores' `putBlobRow`. Refreshes
|
|
55
|
+
* created_at even on a dedup hit so a re-used/just-written blob is "touched=now" and GC-grace-protected.
|
|
56
|
+
* (a): an over-cap blob is REJECTED (typed {@link BlobTooLargeError}) BEFORE the driver ever sees the bytes —
|
|
57
|
+
* the alternative is an inscrutable packet-limit error deep in the driver, and on the HTTP face a 502 that
|
|
58
|
+
* invites the peer to retry a blob that can never land. */
|
|
19
59
|
putBlob(hash: string, bytes: Uint8Array): Promise<void>;
|
|
60
|
+
/** The bytes for `hash` (undefined if absent) — VERBATIM the tidb/pg stores' getBlob SELECT. A pool/query error
|
|
61
|
+
* PROPAGATES (a transient DB fault is loud, not a silent "missing blob" — parity with the MinIO backend's throw). */
|
|
20
62
|
getBlob(hash: string): Promise<Uint8Array | undefined>;
|
|
63
|
+
/** The subset of `hashes` that exist — a single `blob_hash IN (...)` SELECT (idempotency / reap probe). */
|
|
21
64
|
hasBlobs(hashes: string[]): Promise<Set<string>>;
|
|
65
|
+
/** Byte-delete the given hashes (the orphan SET is computed by the caller from snapshot_manifest). Retains the
|
|
66
|
+
* grace-window guard so a just-written blob a concurrent in-flight snapshot needs is never delete-in-use — VERBATIM
|
|
67
|
+
* the tidb/pg stores' gcOrphanBlobs delete, minus the `NOT IN (SELECT … manifest)` clause (the caller already
|
|
68
|
+
* excluded referenced hashes). Best-effort: a delete error is swallowed (under-delete is harmless). */
|
|
22
69
|
deleteBlobs(hashes: string[]): Promise<number>;
|
|
23
70
|
}
|
|
71
|
+
/** SHARED index op(workspace 浏览面 #3,[1894]②)—— per-blob 字节数,读 SQL INDEX 的 `byte_len`
|
|
72
|
+
* 列(sqlHasBlobs 同款单 IN 查询;MinIO 后端的 bytes-NULL 索引行同样带 byte_len,两后端同源)。
|
|
73
|
+
* tree/file 面的 size 投影与「超限先拒后拉」都靠它——绝不为拿大小去 getBlob 整块字节。 */
|
|
24
74
|
export declare function sqlBlobSizes(dialect: "tidb" | "pg", pool: MysqlPool | PgPool, hashes: string[]): Promise<Map<string, number>>;
|
|
25
75
|
export interface MinioBlobBackendConfig {
|
|
26
76
|
endpoint: string;
|
|
@@ -28,14 +78,38 @@ export interface MinioBlobBackendConfig {
|
|
|
28
78
|
accessKey: string;
|
|
29
79
|
secretKey: string;
|
|
30
80
|
region?: string;
|
|
81
|
+
/** Key prefix for blob objects, e.g. "blobs/". Object key = keyPrefix + hash. Default "blobs/". */
|
|
31
82
|
keyPrefix?: string;
|
|
83
|
+
/** Presigned-URL TTL (seconds). Default 3600 (1h) — must comfortably exceed a ~64 MiB single-PUT/GET on a slow link
|
|
84
|
+
* (a SigV4 X-Amz-Expires bounds the WHOLE transfer from X-Amz-Date; a too-short TTL fails mid-stream). */
|
|
32
85
|
presignTtlSec?: number;
|
|
86
|
+
/** 测试注入口(listObjects 分页钉用);生产缺省 global fetch。 */
|
|
33
87
|
fetchImpl?: typeof fetch;
|
|
34
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* MinIO BlobBackend — content-addressed bytes in an S3-compatible object store, via the zero-dependency
|
|
91
|
+
* {@link presignS3Url} SigV4 generator + `fetch` (NO S3 SDK; the repo's no-SDK posture). The object key is
|
|
92
|
+
* `keyPrefix + hash` (content-addressed → idempotent PUT, dedup across snapshots is automatic).
|
|
93
|
+
*
|
|
94
|
+
* THE SQL INDEX: the bytes go to MinIO, but a `snapshot_blob` INDEX row `(blob_hash, byte_len, created_at)` with bytes
|
|
95
|
+
* NULL is kept in SQL (same pool/dialect). This is what makes the orphan-reference computation + the created_at grace
|
|
96
|
+
* window + the §10 presence pre-check work identically to the SQL backend (see the file header). hasBlobs reads the
|
|
97
|
+
* index; putBlob PUTs then upserts the index (created_at-refresh on conflict); deleteBlobs deletes the grace-passed
|
|
98
|
+
* index rows AND the matching MinIO objects (called ONLY from the async sweep reaper).
|
|
99
|
+
*
|
|
100
|
+
* INTEGRITY (security-critical): getBlob VERIFIES sha256(bytes) === hash before returning. A content-addressed store's
|
|
101
|
+
* whole safety rests on bytes-match-hash; a mismatch means corruption (network) or POISONING (a hostile object written
|
|
102
|
+
* under a hash it doesn't match) — treated as ABSENT (undefined), NEVER returning wrong bytes. This mirrors the
|
|
103
|
+
* importManifest content-address check the SQL stores already do.
|
|
104
|
+
*/
|
|
35
105
|
export declare class MinioBlobBackend implements BlobBackend {
|
|
36
106
|
private readonly cfg;
|
|
37
107
|
private readonly keyPrefix;
|
|
38
108
|
private readonly ttl;
|
|
109
|
+
/** The SQL index pool+dialect, or undefined for an index-LESS backend (the migration script + the unit suite, which
|
|
110
|
+
* exercise ONLY the object I/O — put/get/has-by-HEAD/delete — with no DB). When undefined, hasBlobs falls back to a
|
|
111
|
+
* HEAD-per-hash probe and deleteBlobs ignores the grace window (the script is a stop-the-world copy, not the live GC
|
|
112
|
+
* path). The file-snapshot stores ALWAYS pass the pool, so the live reference-tracking always has the index. */
|
|
39
113
|
private readonly indexPool?;
|
|
40
114
|
private readonly indexDialect?;
|
|
41
115
|
constructor(cfg: MinioBlobBackendConfig, index?: {
|
|
@@ -44,16 +118,46 @@ export declare class MinioBlobBackend implements BlobBackend {
|
|
|
44
118
|
});
|
|
45
119
|
private objectKey;
|
|
46
120
|
private presign;
|
|
121
|
+
/** PUT the bytes under the content-addressed key, THEN upsert the SQL INDEX row (bytes NULL, created_at refresh on
|
|
122
|
+
* conflict — the SAME grace discipline as SqlBlobBackend, so a just-PUT blob an in-flight snapshot needs is touched=
|
|
123
|
+
* now and protected). Idempotent (same hash ⇒ overwrite-with-identical-bytes + created_at bump). A non-2xx PUT throws
|
|
124
|
+
* (an upload failure must surface — a silent drop would later read_failed on restore). The PUT happens BEFORE the
|
|
125
|
+
* index upsert so an index row never claims a blob the object store doesn't hold (an index row with no object would
|
|
126
|
+
* let hasBlobs report a phantom present; the reverse — an object with no index — is harmless and pruned by a bucket
|
|
127
|
+
* lifecycle if it ever happens). NOTE no post-PUT read-back verify on the LIVE path (perf): content-addressing
|
|
128
|
+
* catches a corrupted PUT at the next getBlob sha-check (fail-closed); the one-time migration script DOES read-back. */
|
|
47
129
|
putBlob(hash: string, bytes: Uint8Array): Promise<void>;
|
|
130
|
+
/** GET the bytes for `hash`, then VERIFY content-address (sha256(bytes)===hash). THREE branches (finding 11):
|
|
131
|
+
* - 404 → undefined (genuinely ABSENT — the file-snapshot store treats undefined as a missing blob).
|
|
132
|
+
* - sha256 MISMATCH → undefined (corruption/poisoning; treat corrupt-as-absent, fail-CLOSED, NEVER wrong bytes).
|
|
133
|
+
* - a NON-2xx-NON-404 (5xx/throttle) OR a network/fetch REJECT → THROW (a TRANSIENT fault must fail LOUD so the
|
|
134
|
+
* restore/import surfaces an error, NOT silently drop a file as "missing"; the SQL backend likewise propagates a
|
|
135
|
+
* pool error). The snapshot store's restore() wraps applyManifest so this throw becomes a {ok:false} restore_failed. */
|
|
48
136
|
getBlob(hash: string): Promise<Uint8Array | undefined>;
|
|
137
|
+
/** The subset of `hashes` present — reads the SQL INDEX (cheaper than a HEAD-per-hash AND consistent with the SQL
|
|
138
|
+
* backend). Falls back to a presigned HEAD per hash ONLY in object-only mode (no index pool: the migration / unit
|
|
139
|
+
* path). The caller passes DISTINCT hashes (migration idempotency batch / reap orphan set / §10 presence pre-check). */
|
|
49
140
|
hasBlobs(hashes: string[]): Promise<Set<string>>;
|
|
141
|
+
/** D-1 孤儿对象 GC(clay 拍 2026-07-28):列举本后端 keyPrefix 下的全部对象(ListObjectsV2 分页,
|
|
142
|
+
* 零依赖 XML 取 <Key>/<LastModified>/<NextContinuationToken>)。**server 端 sweep 专用**——presign 的
|
|
143
|
+
* bucket-GET 列举能力绝不外发。响应非 2xx 即 throw(sweep 调用方自 catch:列举失败=本轮跳过,
|
|
144
|
+
* 绝不把「列不出来」当「没有孤儿」)。 */
|
|
50
145
|
listObjects(): AsyncGenerator<{
|
|
51
146
|
hash: string;
|
|
52
147
|
lastModifiedMs: number;
|
|
53
148
|
}>;
|
|
149
|
+
/** 单对象 HEAD 探针(复审 B-F1 的删前复查面):返回当前 LastModified(缺席=对象已不在)。
|
|
150
|
+
* put 会 PUT 同键 ⇒ 刷新 LastModified,所以「删前再 HEAD 一次」能看见「刚刚被重新引用」的对象。 */
|
|
54
151
|
headObject(hash: string): Promise<{
|
|
55
152
|
lastModifiedMs: number;
|
|
56
153
|
} | undefined>;
|
|
154
|
+
/** Byte-delete the given hashes — called ONLY from the async sweepOrphanBlobs reaper (NEVER the synchronous purge
|
|
155
|
+
* path). Honors the SAME created_at grace window as the SQL backend: with an index, DELETE the grace-passed index
|
|
156
|
+
* rows first (the index's created_at is the authoritative age — an S3 object carries no service-controlled timestamp
|
|
157
|
+
* the backend reads), then delete the MinIO objects ONLY for those grace-passed hashes (so a just-PUT blob an
|
|
158
|
+
* in-flight snapshot needs is NOT delete-in-use). ERROR-TOLERANT + BOUNDED: each object delete is independent (a
|
|
159
|
+
* failure is skipped → retried next sweep), at most MINIO_OP_CONCURRENCY in flight (no FD/throttle storm). In
|
|
160
|
+
* object-only mode (no index pool: the migration/unit cleanup path) it deletes every given hash with no grace. */
|
|
57
161
|
deleteBlobs(hashes: string[]): Promise<number>;
|
|
58
162
|
}
|
|
59
163
|
//# sourceMappingURL=blob-backend.d.ts.map
|