@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,2 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility re-export shim — the PG Session event-log center (L1).
|
|
3
|
+
*
|
|
4
|
+
* 🔴 SINGLE SOURCE OF TRUTH: the real PG twin (PgSessionStorage + PgSessionStore + PG_SESSION_SCHEMA +
|
|
5
|
+
* ensureSchema) lives in {@link ./pg-session-storage.ts}. This file previously carried a SECOND, byte-for-byte
|
|
6
|
+
* copy of that same code — a dual source of truth that would silently drift (a fix to one copy leaving the
|
|
7
|
+
* other stale, defeating the very twin/lock-step invariant the integration suite exists to protect). The
|
|
8
|
+
* duplicate has been collapsed: everything is now re-exported from the one storage module so there is exactly
|
|
9
|
+
* ONE PG implementation and the two integration suites both exercise it.
|
|
10
|
+
*/
|
|
1
11
|
export { PgSessionStorage, PgSessionStore, PG_SESSION_SCHEMA, ensureSchema, } from "./pg-session-storage.js";
|
|
2
12
|
//# sourceMappingURL=pg-session-store.d.ts.map
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compatibility re-export shim — the PG Session event-log center (L1).
|
|
3
|
+
*
|
|
4
|
+
* 🔴 SINGLE SOURCE OF TRUTH: the real PG twin (PgSessionStorage + PgSessionStore + PG_SESSION_SCHEMA +
|
|
5
|
+
* ensureSchema) lives in {@link ./pg-session-storage.ts}. This file previously carried a SECOND, byte-for-byte
|
|
6
|
+
* copy of that same code — a dual source of truth that would silently drift (a fix to one copy leaving the
|
|
7
|
+
* other stale, defeating the very twin/lock-step invariant the integration suite exists to protect). The
|
|
8
|
+
* duplicate has been collapsed: everything is now re-exported from the one storage module so there is exactly
|
|
9
|
+
* ONE PG implementation and the two integration suites both exercise it.
|
|
10
|
+
*/
|
|
1
11
|
export { PgSessionStorage, PgSessionStore, PG_SESSION_SCHEMA, ensureSchema, } from "./pg-session-storage.js";
|
|
2
12
|
//# sourceMappingURL=pg-session-store.js.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL `ToolResultStore` — the implementation now lives in the single-file dual-dialect
|
|
3
|
+
* `tool-result-store-sql.ts` (design/158 A12 定型半场), the TiDB twin's sibling
|
|
4
|
+
* (src/plugins/tidb-tool-result-store.ts). This file is the historical import path: the class name, ctor
|
|
5
|
+
* shape, and the PG-only schema helpers (`PG_TOOL_RESULT_SCHEMA` / `ensureSchema`, consumed by pg-pool.ts's
|
|
6
|
+
* central schema apply) are re-exported unchanged, so every consumer and suite is untouched.
|
|
7
|
+
*/
|
|
1
8
|
export { PgToolResultStore, PG_TOOL_RESULT_SCHEMA, ensureSchema } from "./tool-result-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-tool-result-store.d.ts.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostgreSQL `ToolResultStore` — the implementation now lives in the single-file dual-dialect
|
|
3
|
+
* `tool-result-store-sql.ts` (design/158 A12 定型半场), the TiDB twin's sibling
|
|
4
|
+
* (src/plugins/tidb-tool-result-store.ts). This file is the historical import path: the class name, ctor
|
|
5
|
+
* shape, and the PG-only schema helpers (`PG_TOOL_RESULT_SCHEMA` / `ensureSchema`, consumed by pg-pool.ts's
|
|
6
|
+
* central schema apply) are re-exported unchanged, so every consumer and suite is untouched.
|
|
7
|
+
*/
|
|
1
8
|
export { PgToolResultStore, PG_TOOL_RESULT_SCHEMA, ensureSchema } from "./tool-result-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-tool-result-store.js.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin re-export shim (design/158 A12 collapse). The real implementation is the single-file dual-dialect
|
|
3
|
+
* {@link import("./workflow-journal-store-sql.js").SqlWorkflowJournalStore} — see that file for the durable
|
|
4
|
+
* {@link WorkflowJournalStore} contract, the schema, and the TiDB/PG dialect-delta ledger. This name (and ctor
|
|
5
|
+
* arity: `(pool: PgPool)`) survives unchanged so every consumer (store-backend.ts, the extreme/integration/
|
|
6
|
+
* resume-fork-probe suites) is untouched.
|
|
7
|
+
*/
|
|
1
8
|
export { PgWorkflowJournalStore } from "./workflow-journal-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-workflow-journal-store.d.ts.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin re-export shim (design/158 A12 collapse). The real implementation is the single-file dual-dialect
|
|
3
|
+
* {@link import("./workflow-journal-store-sql.js").SqlWorkflowJournalStore} — see that file for the durable
|
|
4
|
+
* {@link WorkflowJournalStore} contract, the schema, and the TiDB/PG dialect-delta ledger. This name (and ctor
|
|
5
|
+
* arity: `(pool: PgPool)`) survives unchanged so every consumer (store-backend.ts, the extreme/integration/
|
|
6
|
+
* resume-fork-probe suites) is untouched.
|
|
7
|
+
*/
|
|
1
8
|
export { PgWorkflowJournalStore } from "./workflow-journal-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-workflow-journal-store.js.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin re-export shim (design/158 A12 扇出): the PG `WorkflowRunStore`/`WorkflowCompletionInbox`/
|
|
3
|
+
* `WorkflowNotifyJournalStore` twins now live collapsed with their TiDB dialect siblings in the
|
|
4
|
+
* single-file dual-dialect `workflow-run-store-sql.ts` (design doc + dialect-delta ledger there).
|
|
5
|
+
* Class names and ctor arity stay EXACTLY as they were — every consumer (store-backend.ts, the
|
|
6
|
+
* DB-integration suite) imports from THIS path unchanged.
|
|
7
|
+
*/
|
|
1
8
|
export { PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore } from "./workflow-run-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-workflow-run-store.d.ts.map
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin re-export shim (design/158 A12 扇出): the PG `WorkflowRunStore`/`WorkflowCompletionInbox`/
|
|
3
|
+
* `WorkflowNotifyJournalStore` twins now live collapsed with their TiDB dialect siblings in the
|
|
4
|
+
* single-file dual-dialect `workflow-run-store-sql.ts` (design doc + dialect-delta ledger there).
|
|
5
|
+
* Class names and ctor arity stay EXACTLY as they were — every consumer (store-backend.ts, the
|
|
6
|
+
* DB-integration suite) imports from THIS path unchanged.
|
|
7
|
+
*/
|
|
1
8
|
export { PgWorkflowRunStore, PgWorkflowCompletionInbox, PgWorkflowNotifyJournalStore } from "./workflow-run-store-sql.js";
|
|
2
9
|
//# sourceMappingURL=pg-workflow-run-store.js.map
|
|
@@ -5,8 +5,11 @@ export interface ShellRunResult {
|
|
|
5
5
|
exitCode: number;
|
|
6
6
|
}
|
|
7
7
|
export interface PosixShellFsDeps {
|
|
8
|
+
/** 腿的传输:k8s/ssh/adb=`this.exec`,local-docker=`docker(execRaw(cmd))` 包一层。 */
|
|
8
9
|
run: (cmd: string, abortSignal?: AbortSignal) => Promise<Result<ShellRunResult, ExecutionError | RemoteExecutionError>>;
|
|
10
|
+
/** 腿的路径绝对化(各腿 cwd 语义不同,留在腿上)。 */
|
|
9
11
|
resolve: (p: string) => string;
|
|
12
|
+
/** R5:临时件落点。返回目录 ⇒ `mktemp -p <dir>`(workspace 腿);null ⇒ `mktemp -t`(ssh,系统 temp)。 */
|
|
10
13
|
tempDir: () => string | null;
|
|
11
14
|
}
|
|
12
15
|
export interface PosixShellFs {
|
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/158 B6 —— POSIX shell-out 族的共享文件面基座。
|
|
3
|
+
*
|
|
4
|
+
* 服务对象 = {k8s, ssh, adb, local-docker} 四条「发一条 shell 命令 + 分类 stderr」的腿(lens3 C2 实测
|
|
5
|
+
* 42–69% 同构)。**host(node:fs)与 e2b(SDK)是原生 API 腿,不并**(13–27% 是假共性,强行合并会造出
|
|
6
|
+
* 一个假基座)。ssh 的 fileInfo/listDir 走 SFTP 原生,只接入本基座的 shell-out 子集。
|
|
7
|
+
*
|
|
8
|
+
* 五条裁决(B6-posix-shell-fs.md,test/posix-shell-fs.test.ts 逐条钉):
|
|
9
|
+
* R1 所有 path 实参前带 `--`(ssh 形):resolve() 先绝对化让风险只剩纵深,但**基座不依赖调用侧不变量**。
|
|
10
|
+
* R2 错误分类走 `classifyFsStderr`(k8s 形:分类 + 硬失败/命令缺失护栏 + 站点显式 fallback)。
|
|
11
|
+
* R3 listDir 用 `ls -1A`(adb 此前 `-1` 丢 dotfiles —— agent 场景 .env/.gitignore 是一等公民)。
|
|
12
|
+
* R4 createTempFile 后缀=尾-X 模板 + `mv`(纯 POSIX;GNU `--suffix` 在 BSD/macOS 远端直接失败;
|
|
13
|
+
* 模板尾-X 约束的复发面见 adb 2026-07-25 修案)。
|
|
14
|
+
* R5 temp 位置参数化(workspace 腿 `-p <dir>`,ssh `-t`)—— 语义差异,不判正形。
|
|
15
|
+
*
|
|
16
|
+
* readLink 契约(逐字承各腿原注):必须返回**原始链接目标**(`readlink` 不带 `-f`),core 拿到后自己拼
|
|
17
|
+
* 相对目标并走带跳数上限的循环;链接目标含换行是病态形,按 trim 处理,不假装支持。
|
|
18
|
+
* statFileInfo 契约:**lstat 语义**(`stat` 不带 `-L`,不跟链)—— symlink 自身可被 fileInfo 判出,
|
|
19
|
+
* core 的敏感路径/写门靠这个(exists→canonicalPath 失败→fileInfo 判 symlink→readLink)。
|
|
20
|
+
*/
|
|
1
21
|
import path from "node:path";
|
|
2
22
|
import { FileError, } from "@sema-agent/core";
|
|
3
23
|
import { shellQuote, kindFromMode } from "./remote-shell.js";
|
|
@@ -33,6 +53,7 @@ export function createPosixShellFs(deps) {
|
|
|
33
53
|
},
|
|
34
54
|
async statFileInfo(p, abortSignal) {
|
|
35
55
|
const abs = resolve(p);
|
|
56
|
+
// %s size / %Y mtime(epoch s)/ %f raw hex mode —— GNU、busybox、toybox 三家一致;无 `-L` = lstat。
|
|
36
57
|
const r = await run(`stat -c '%s %Y %f' -- ${shellQuote(abs)}`, abortSignal);
|
|
37
58
|
if (!r.ok)
|
|
38
59
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
@@ -58,6 +79,7 @@ export function createPosixShellFs(deps) {
|
|
|
58
79
|
const out = [];
|
|
59
80
|
for (const name of names) {
|
|
60
81
|
const info = await fs.statFileInfo(path.posix.join(abs, name), abortSignal);
|
|
82
|
+
// 竞态容忍(承各腿原形):条目在 ls 与 stat 之间消失/不可读时降级为占位行,不让整个列表失败。
|
|
61
83
|
if (info.ok)
|
|
62
84
|
out.push(info.value);
|
|
63
85
|
else
|
|
@@ -67,6 +89,11 @@ export function createPosixShellFs(deps) {
|
|
|
67
89
|
},
|
|
68
90
|
async exists(p, abortSignal) {
|
|
69
91
|
const abs = resolve(p);
|
|
92
|
+
// R6(k8s 形=正形,原注全额承接):`[ -e ]` 经 stdout 答 yes/no —— 不依赖 stderr(鲁棒于 fast-exit
|
|
93
|
+
// 下 stderr 被截断的竞态),单往返。`|| [ -L ]` 是 2026-07-25 补的跨腿分叉:`[ -e ]` **跟随**符号链接,
|
|
94
|
+
// 悬空链接(`latest -> ./build-123` 未构建)会答 false,而 core 的 canonicalizeTarget 第一步就是
|
|
95
|
+
// exists —— 答 false ⇒ 走「目标不存在」分支,敏感路径门拿到的键是无害的链接名而非真目标(core 注释
|
|
96
|
+
// 点名要 fail-closed 防的绕过形)。`[ -e ] || [ -L ]` = lstat 语义,与 host 腿对齐。
|
|
70
97
|
const r = await run(`{ [ -e ${shellQuote(abs)} ] || [ -L ${shellQuote(abs)} ]; } && printf yes || printf no`, abortSignal);
|
|
71
98
|
if (!r.ok)
|
|
72
99
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
@@ -79,6 +106,7 @@ export function createPosixShellFs(deps) {
|
|
|
79
106
|
},
|
|
80
107
|
async createDir(p, options) {
|
|
81
108
|
const abs = resolve(p);
|
|
109
|
+
// sftp/一次性 mkdir 都非递归 ⇒ 恒 `-p`(对已存在目录也幂等)——承 ssh/adb/k8s 原形。
|
|
82
110
|
const r = await run(`mkdir -p -- ${shellQuote(abs)}`, options?.abortSignal);
|
|
83
111
|
if (!r.ok)
|
|
84
112
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
@@ -94,7 +122,7 @@ export function createPosixShellFs(deps) {
|
|
|
94
122
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
95
123
|
if (r.value.exitCode !== 0) {
|
|
96
124
|
if (options?.force && /no such file/i.test(r.value.stderr))
|
|
97
|
-
return ok(undefined);
|
|
125
|
+
return ok(undefined); // force = 幂等删除
|
|
98
126
|
return { ok: false, error: classifyFsStderr(r.value.stderr, abs, "unknown") };
|
|
99
127
|
}
|
|
100
128
|
return ok(undefined);
|
|
@@ -110,6 +138,8 @@ export function createPosixShellFs(deps) {
|
|
|
110
138
|
const sfx = options?.suffix ?? "";
|
|
111
139
|
const dir = deps.tempDir();
|
|
112
140
|
const where = dir === null ? "-t" : `-p ${shellQuote(dir)}`;
|
|
141
|
+
// R4:`mktemp` 要求 X 在**末尾**,后缀不能折进模板(折进去产出的是一个带字面 XXXXXX 的文件名,
|
|
142
|
+
// 第二次调用同名撞车)。正解=合法尾-X 模板建(基名唯一),后缀 `mv` 上去 —— 目标名因基名唯一而唯一。
|
|
113
143
|
const cmd = sfx
|
|
114
144
|
? `f=$(mktemp ${where} ${shellQuote(`${prefix}XXXXXX`)}) && mv -- "$f" "$f"${shellQuote(sfx)} && printf '%s' "$f"${shellQuote(sfx)}`
|
|
115
145
|
: `mktemp ${where} ${shellQuote(`${prefix}XXXXXX`)}`;
|
|
@@ -2,8 +2,11 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { FileError, ExecutionError, RemoteExecutionError, type ExecutionEnv, type RemoteExecutionEnv, type WorkspaceHandle, type FileInfo, type Result, type OutputChunk, type ExecStreamOptions, type RemoteConnectConfig, type SnapshotId, type SessionToken, type VmLifecycleOptions, type ExecutionEnvFactory } from "@sema-agent/core";
|
|
3
3
|
type ExecOpts = Parameters<ExecutionEnv["exec"]>[1];
|
|
4
4
|
export interface AdbEnvConfig {
|
|
5
|
+
/** Device serial or `host:port` (TCP). `host:port` triggers `adb connect` on connect()/reconnect(). */
|
|
5
6
|
serial: string;
|
|
7
|
+
/** Path to the adb binary. Default "adb" (must be on PATH in the runner image). */
|
|
6
8
|
adbPath?: string;
|
|
9
|
+
/** On-device workspace root; relative paths resolve against it. Default "/data/local/tmp". */
|
|
7
10
|
mountPath?: string;
|
|
8
11
|
commandTimeoutMs?: number;
|
|
9
12
|
dataTimeoutMs?: number;
|
|
@@ -19,10 +22,17 @@ type ConnectResult = {
|
|
|
19
22
|
ok: false;
|
|
20
23
|
error: RemoteExecutionError;
|
|
21
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Test seam (design/61 §9.3 fault-injection): inject `spawn` and/or a `connectOnce` that replays an error
|
|
27
|
+
* sequence, so the retry policy + first-attach behaviour is deterministically testable without a real device
|
|
28
|
+
* (the E2B-adapter bug that only surfaced in dogfood is the lesson this guards against).
|
|
29
|
+
*/
|
|
22
30
|
export interface AdbEnvDeps {
|
|
23
31
|
spawn?: typeof spawn;
|
|
24
32
|
connectOnce?: (signal?: AbortSignal) => Promise<ConnectResult>;
|
|
25
33
|
}
|
|
34
|
+
/** [R78]#1: adb stderr markers that mean the DEVICE TRANSPORT died mid-op (not a normal command failure) —
|
|
35
|
+
* typed retryable (reconnect + retry per idempotency), never a fake command result. Exported for tests. */
|
|
26
36
|
export declare function isAdbTransportLost(stderr: string): boolean;
|
|
27
37
|
export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
28
38
|
readonly capabilities: {
|
|
@@ -31,6 +41,12 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
31
41
|
};
|
|
32
42
|
cwd: string;
|
|
33
43
|
private connected;
|
|
44
|
+
/** 🔴 拆除是**终态**(2026-07-25 补齐:此前本适配器是同族里唯一没有这个概念的一条腿)。
|
|
45
|
+
* 没有它的后果实测:`destroy()` 只清 `connected`,于是任何残留引用**一次 `connect()` 就把 env 整个复活**,
|
|
46
|
+
* `exec` 又能在真设备上跑;而 `reconnect(sessionToken)` 就在同一个接缝上摆着。读面更松 —— 它连
|
|
47
|
+
* `connected` 都不查,所以 destroy 之后 `readTextFile` 照样从真设备把文件读出来。
|
|
48
|
+
* 同姿态的 ssh 腿早有先例(`remote-env-ssh.ts`「destroy 后一律不复活,显式 connect/reconnect 同禁」),
|
|
49
|
+
* 五条兄弟腿全部 fail-closed,只有 adb 例外 —— 补齐它。 */
|
|
34
50
|
private destroyed;
|
|
35
51
|
private readonly cfg;
|
|
36
52
|
private readonly spawnFn;
|
|
@@ -74,6 +90,7 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
74
90
|
ok: false;
|
|
75
91
|
error: RemoteExecutionError;
|
|
76
92
|
}>;
|
|
93
|
+
/** `adb disconnect` the TCP device (USB: just drop our flag). Does NOT reset the phone — idempotent, never throws. */
|
|
77
94
|
destroy(): Promise<void>;
|
|
78
95
|
cleanup(): Promise<void>;
|
|
79
96
|
exec(command: string, options?: ExecOpts): Promise<Result<{
|
|
@@ -84,6 +101,8 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
84
101
|
execStream(command: string, options?: ExecStreamOptions): AsyncIterable<OutputChunk>;
|
|
85
102
|
absolutePath(p: string): Promise<Result<string, FileError>>;
|
|
86
103
|
joinPath(parts: string[]): Promise<Result<string, FileError>>;
|
|
104
|
+
/** 文件面的终态门 —— 读面此前**连 `connected` 都不查**,所以 destroy 之后还能从真设备读出文件内容。
|
|
105
|
+
* 与 host/local-docker/k8s/e2b 的姿态对齐(它们的文件面都在 destroy 后 fail-closed)。 */
|
|
87
106
|
private fsGate;
|
|
88
107
|
readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
|
|
89
108
|
readTextFile(p: string, abortSignal?: AbortSignal): Promise<Result<string, FileError>>;
|
|
@@ -115,9 +134,15 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
|
|
|
115
134
|
suffix?: string;
|
|
116
135
|
abortSignal?: AbortSignal;
|
|
117
136
|
}): Promise<Result<string, FileError>>;
|
|
137
|
+
/** Spawn the adb binary with the given args; collect stdout/stderr (+ raw bytes when binary), bound by timeout/abort. */
|
|
118
138
|
private adb;
|
|
119
139
|
private withCwdEnv;
|
|
120
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* `ExecutionEnvFactory` for the ADB backend — one fresh (unconnected) env per task against the same device
|
|
143
|
+
* (lazy: `adb connect` on first use). Config (serial) is control-plane-supplied; the Runner owns the lifetime
|
|
144
|
+
* and calls `destroy()` (= `adb disconnect`, never a device wipe) on task end.
|
|
145
|
+
*/
|
|
121
146
|
export declare function adbExecutionEnvFactory(config: AdbEnvConfig): ExecutionEnvFactory;
|
|
122
147
|
export {};
|
|
123
148
|
//# sourceMappingURL=remote-env-adb.d.ts.map
|
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `RemoteAdbExecutionEnv` — the ADB implementation of core's `RemoteExecutionEnv` seam (design/61). A PEER
|
|
3
|
+
* adapter to SSH/E2B (NOT chained). Use case: an AI driving on-device APP testing over `adb` (a real phone /
|
|
4
|
+
* emulator).
|
|
5
|
+
*
|
|
6
|
+
* 🔴 **An ADB target is a REAL device, not a disposable sandbox** (design/61 §5) — same posture as SSH:
|
|
7
|
+
* - `capabilities = { isolation: false, suspendable: false }` — actions are PERMANENT; the leader tightens
|
|
8
|
+
* autonomy + the design/37 gate + HITL run on a non-isolated env (design/53).
|
|
9
|
+
* - `destroy()` / `cleanup()` **`adb disconnect`** the (TCP) device — they do NOT wipe/reset the phone.
|
|
10
|
+
* - `suspendVM`/`resumeVM`/`postResumeInit` → typed `"unsupported"` (a physical device isn't snapshotable).
|
|
11
|
+
* `reconnect` re-runs `adb connect`.
|
|
12
|
+
*
|
|
13
|
+
* 🔴 **First-attach is flaky → retry** (design/61 §2A): a fresh `adb connect` / a device that is still
|
|
14
|
+
* `unauthorized` (USB-debug prompt) or `offline` surfaces `auth_transient`, which `connect` retries via
|
|
15
|
+
* `withRetry` (idempotent establishment only). A genuinely rejected device → `auth_failed` (permanent).
|
|
16
|
+
*
|
|
17
|
+
* 🔴 **Credentials / device identity** are control-plane config (the device `serial` / `host:port`), injected
|
|
18
|
+
* to the ADAPTER — never the workspace (design/61 §5 #2).
|
|
19
|
+
*
|
|
20
|
+
* **APP install** is NOT a seam method: the agent pushes the APK with `writeFile` then runs `pm install` (or
|
|
21
|
+
* `adb install` is reachable via the device's own shell) through `exec` — the ExecutionEnv stays generic.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ **Device-untested:** built mirroring the SSH adapter (which IS proven against a real host); no physical
|
|
24
|
+
* device/emulator was available to integration-test the `adb` paths. The contracts are locked by unit tests;
|
|
25
|
+
* the live `adb` round-trip needs a device run before production use.
|
|
26
|
+
*/
|
|
1
27
|
import path from "node:path";
|
|
2
28
|
import os from "node:os";
|
|
3
29
|
import fs from "node:fs/promises";
|
|
@@ -13,6 +39,8 @@ const unsupported = (op) => ({
|
|
|
13
39
|
error: new RemoteExecutionError("unsupported", `${op} is not supported on an ADB device (real hardware — not snapshotable; capabilities.suspendable=false)`),
|
|
14
40
|
});
|
|
15
41
|
const isTcp = (serial) => /:\d+$/.test(serial);
|
|
42
|
+
/** [R78]#1: adb stderr markers that mean the DEVICE TRANSPORT died mid-op (not a normal command failure) —
|
|
43
|
+
* typed retryable (reconnect + retry per idempotency), never a fake command result. Exported for tests. */
|
|
16
44
|
export function isAdbTransportLost(stderr) {
|
|
17
45
|
return /device offline|device '.*' not found|no devices\/emulators found|connection reset|protocol fault|device disconnected/i.test(stderr);
|
|
18
46
|
}
|
|
@@ -20,6 +48,12 @@ export class RemoteAdbExecutionEnv {
|
|
|
20
48
|
capabilities = { isolation: false, suspendable: false };
|
|
21
49
|
cwd;
|
|
22
50
|
connected = false;
|
|
51
|
+
/** 🔴 拆除是**终态**(2026-07-25 补齐:此前本适配器是同族里唯一没有这个概念的一条腿)。
|
|
52
|
+
* 没有它的后果实测:`destroy()` 只清 `connected`,于是任何残留引用**一次 `connect()` 就把 env 整个复活**,
|
|
53
|
+
* `exec` 又能在真设备上跑;而 `reconnect(sessionToken)` 就在同一个接缝上摆着。读面更松 —— 它连
|
|
54
|
+
* `connected` 都不查,所以 destroy 之后 `readTextFile` 照样从真设备把文件读出来。
|
|
55
|
+
* 同姿态的 ssh 腿早有先例(`remote-env-ssh.ts`「destroy 后一律不复活,显式 connect/reconnect 同禁」),
|
|
56
|
+
* 五条兄弟腿全部 fail-closed,只有 adb 例外 —— 补齐它。 */
|
|
23
57
|
destroyed = false;
|
|
24
58
|
cfg;
|
|
25
59
|
spawnFn;
|
|
@@ -43,11 +77,14 @@ export class RemoteAdbExecutionEnv {
|
|
|
43
77
|
workspaceHandle() {
|
|
44
78
|
return { sandboxId: this.cfg.serial, provider: PROVIDER, mountPath: this.cwd };
|
|
45
79
|
}
|
|
80
|
+
// ─────────────────────────────── lifecycle ───────────────────────────────
|
|
46
81
|
async connect(config) {
|
|
82
|
+
// 拆除后一律不复活(显式 connect / reconnect 同禁)—— 与 ssh 腿逐字同口径:被拆除的 env 是 teardown
|
|
83
|
+
// 的产物,重连它等于把已释放的真实设备重新挂上,而那时已经没有谁负责再断开它。要新连接就建新 env。
|
|
47
84
|
if (this.destroyed)
|
|
48
85
|
return { ok: false, error: new RemoteExecutionError("connect_failed", "ADB env destroyed — create a fresh env instead of reviving") };
|
|
49
86
|
const policy = {
|
|
50
|
-
retryableCodes: ["auth_transient", "connect_failed", "timeout"],
|
|
87
|
+
retryableCodes: ["auth_transient", "connect_failed", "timeout"], // first-attach flakiness; NOT auth_failed
|
|
51
88
|
maxAttempts: this.cfg.retry.maxAttempts,
|
|
52
89
|
backoffMs: (failed) => this.cfg.retry.backoffMs * failed,
|
|
53
90
|
};
|
|
@@ -67,6 +104,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
67
104
|
if (/cannot connect|connection refused|no route/.test(out))
|
|
68
105
|
return { ok: false, error: new RemoteExecutionError("connect_failed", c.value.stdout.trim()) };
|
|
69
106
|
}
|
|
107
|
+
// Confirm the device is actually usable (not unauthorized/offline) before declaring connected.
|
|
70
108
|
const st = await this.adb(["-s", this.cfg.serial, "get-state"], { signal, timeoutMs: this.cfg.commandTimeoutMs });
|
|
71
109
|
if (!st.ok)
|
|
72
110
|
return { ok: false, error: new RemoteExecutionError("connect_failed", `adb get-state failed: ${st.error.message}`, st.error) };
|
|
@@ -96,19 +134,23 @@ export class RemoteAdbExecutionEnv {
|
|
|
96
134
|
this.connected = false;
|
|
97
135
|
return this.connect();
|
|
98
136
|
}
|
|
137
|
+
/** `adb disconnect` the TCP device (USB: just drop our flag). Does NOT reset the phone — idempotent, never throws. */
|
|
99
138
|
async destroy() {
|
|
100
139
|
if (isTcp(this.cfg.serial))
|
|
101
140
|
await this.adb(["disconnect", this.cfg.serial], { timeoutMs: 10_000 }).catch(() => { });
|
|
102
141
|
this.connected = false;
|
|
103
|
-
this.destroyed = true;
|
|
142
|
+
this.destroyed = true; // 终态(见字段旁注):此后 connect/reconnect 与整个文件面一律 fail-closed
|
|
104
143
|
}
|
|
105
144
|
async cleanup() {
|
|
106
145
|
return this.destroy();
|
|
107
146
|
}
|
|
147
|
+
// ─────────────────────────────── exec ───────────────────────────────
|
|
108
148
|
async exec(command, options) {
|
|
109
149
|
if (!this.connected)
|
|
110
150
|
return { ok: false, error: new ExecutionError("shell_unavailable", "ADB device not connected — call connect() first") };
|
|
111
151
|
const wrapped = this.withCwdEnv(command, options?.cwd, options?.env);
|
|
152
|
+
// exec-out (shell protocol v2, NO pty): clean separated stdout/stderr + a real exit code. `adb shell` allocates
|
|
153
|
+
// a pty that merges stderr into stdout and does CRLF translation — wrong for capture/streaming (council §9.2).
|
|
112
154
|
const r = await this.adb(["-s", this.cfg.serial, "exec-out", wrapped], {
|
|
113
155
|
signal: options?.abortSignal,
|
|
114
156
|
timeoutMs: options?.timeout != null ? options.timeout * 1000 : this.cfg.commandTimeoutMs,
|
|
@@ -117,8 +159,10 @@ export class RemoteAdbExecutionEnv {
|
|
|
117
159
|
});
|
|
118
160
|
if (!r.ok)
|
|
119
161
|
return { ok: false, error: r.error };
|
|
162
|
+
// A device-transport drop mid-op is NOT a command result — typed "transport_lost" since core 1.89
|
|
163
|
+
// (outcome UNKNOWN — reconnect, then retry only per the op's idempotency).
|
|
120
164
|
if (r.value.exitCode !== 0 && isAdbTransportLost(r.value.stderr)) {
|
|
121
|
-
this.connected = false;
|
|
165
|
+
this.connected = false; // dead transport — the next exec fails closed; reconnect() re-establishes
|
|
122
166
|
return { ok: false, error: new ExecutionError("transport_lost", `adb transport lost mid-command: ${r.value.stderr.trim().slice(0, 200)} — reconnect + retry per idempotency`) };
|
|
123
167
|
}
|
|
124
168
|
return ok(r.value);
|
|
@@ -127,7 +171,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
127
171
|
if (!this.connected)
|
|
128
172
|
throw new RemoteExecutionError("connect_failed", "ADB device not connected — call connect() first");
|
|
129
173
|
const wrapped = this.withCwdEnv(command, options?.cwd, options?.env);
|
|
130
|
-
const child = this.spawnFn(this.cfg.adbPath, ["-s", this.cfg.serial, "exec-out", wrapped], { stdio: ["ignore", "pipe", "pipe"] });
|
|
174
|
+
const child = this.spawnFn(this.cfg.adbPath, ["-s", this.cfg.serial, "exec-out", wrapped], { stdio: ["ignore", "pipe", "pipe"] }); // exec-out (no pty) — see exec()
|
|
131
175
|
const queue = [];
|
|
132
176
|
let finished = false;
|
|
133
177
|
let failure;
|
|
@@ -143,6 +187,8 @@ export class RemoteAdbExecutionEnv {
|
|
|
143
187
|
let paused = false;
|
|
144
188
|
let onAbort;
|
|
145
189
|
const teardown = () => {
|
|
190
|
+
// every exit path (normal end, timeout/failure throw, consumer early-break via .return()): drop the abort
|
|
191
|
+
// listener (council #5) + kill the child if still running.
|
|
146
192
|
if (onAbort) {
|
|
147
193
|
options?.signal?.removeEventListener("abort", onAbort);
|
|
148
194
|
onAbort = undefined;
|
|
@@ -152,6 +198,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
152
198
|
child.kill("SIGKILL");
|
|
153
199
|
}
|
|
154
200
|
catch {
|
|
201
|
+
/* noop */
|
|
155
202
|
}
|
|
156
203
|
}
|
|
157
204
|
};
|
|
@@ -171,12 +218,12 @@ export class RemoteAdbExecutionEnv {
|
|
|
171
218
|
lastChunk = Date.now();
|
|
172
219
|
queue.push(chunk);
|
|
173
220
|
if (queue.length >= 512 && !paused) {
|
|
174
|
-
paused = true;
|
|
221
|
+
paused = true; // backpressure: bound queue growth on a fast producer / slow consumer (council design #1)
|
|
175
222
|
child.stdout.pause();
|
|
176
223
|
}
|
|
177
224
|
signalReady();
|
|
178
225
|
};
|
|
179
|
-
let stderrTail = "";
|
|
226
|
+
let stderrTail = ""; // [R78]#1: watch for device-transport-drop markers (bounded tail, not the whole stream)
|
|
180
227
|
child.stdout.on("data", (d) => enqueue({ type: "stdout", data: d.toString() }));
|
|
181
228
|
child.stderr.on("data", (d) => {
|
|
182
229
|
stderrTail = (stderrTail + d.toString()).slice(-512);
|
|
@@ -189,6 +236,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
189
236
|
});
|
|
190
237
|
child.on("close", (code) => {
|
|
191
238
|
if ((code ?? 0) !== 0 && isAdbTransportLost(stderrTail) && !failure) {
|
|
239
|
+
// device transport died mid-stream — typed retryable, not a fake exit ([R78]#1)
|
|
192
240
|
this.connected = false;
|
|
193
241
|
failure = new RemoteExecutionError("transport_lost", `adb transport lost mid-stream: ${stderrTail.trim().slice(0, 200)}`);
|
|
194
242
|
}
|
|
@@ -225,12 +273,15 @@ export class RemoteAdbExecutionEnv {
|
|
|
225
273
|
teardown();
|
|
226
274
|
}
|
|
227
275
|
}
|
|
276
|
+
// ─────────────────────────────── FileSystem (adb shell + push/exec-out) ───────────────────────────────
|
|
228
277
|
async absolutePath(p) {
|
|
229
278
|
return ok(this.resolve(p));
|
|
230
279
|
}
|
|
231
280
|
async joinPath(parts) {
|
|
232
281
|
return ok(path.posix.join(...parts));
|
|
233
282
|
}
|
|
283
|
+
/** 文件面的终态门 —— 读面此前**连 `connected` 都不查**,所以 destroy 之后还能从真设备读出文件内容。
|
|
284
|
+
* 与 host/local-docker/k8s/e2b 的姿态对齐(它们的文件面都在 destroy 后 fail-closed)。 */
|
|
234
285
|
fsGate(p) {
|
|
235
286
|
if (this.destroyed)
|
|
236
287
|
return { ok: false, error: new FileError("unknown", "execution env already destroyed", this.resolve(p)) };
|
|
@@ -241,6 +292,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
241
292
|
if (gated)
|
|
242
293
|
return gated;
|
|
243
294
|
const abs = this.resolve(p);
|
|
295
|
+
// exec-out streams the file's raw bytes (binary-safe); stderr carries cat's error if any.
|
|
244
296
|
const r = await this.adb(["-s", this.cfg.serial, "exec-out", `cat ${shellQuote(abs)}`], { signal: abortSignal, timeoutMs: this.cfg.dataTimeoutMs, binary: true });
|
|
245
297
|
if (!r.ok)
|
|
246
298
|
return { ok: false, error: fileErrorFromExec(r.error, abs) };
|
|
@@ -254,6 +306,8 @@ export class RemoteAdbExecutionEnv {
|
|
|
254
306
|
return { ok: false, error: new FileError("is_directory", errOut, abs) };
|
|
255
307
|
return { ok: false, error: new FileError("unknown", errOut, abs) };
|
|
256
308
|
}
|
|
309
|
+
// exec-out gives no exit code on the wire, but the adb transport itself can fail non-zero with empty stderr
|
|
310
|
+
// (device dropped mid-read) — don't mistake that for a legit empty file (council #6).
|
|
257
311
|
if (r.value.exitCode !== 0)
|
|
258
312
|
return { ok: false, error: new FileError("unknown", `adb exec-out cat exited ${r.value.exitCode}`, abs) };
|
|
259
313
|
return ok(r.value.stdoutBytes ?? new Uint8Array(0));
|
|
@@ -278,11 +332,16 @@ export class RemoteAdbExecutionEnv {
|
|
|
278
332
|
const dir = path.posix.dirname(abs);
|
|
279
333
|
if (dir && dir !== "." && dir !== "/") {
|
|
280
334
|
const mk = await this.exec(`mkdir -p ${shellQuote(dir)}`, { abortSignal });
|
|
335
|
+
// 🔴 `!mk.ok` 也必须 fail-closed(2026-07-25 补):原来只看 `exitCode !== 0`,于是 **exec 本身失败**
|
|
336
|
+
// (设备/连接在这一拍掉线 ⇒ `transport_lost` / `shell_unavailable`)被整条吞掉,后面照样推载荷,
|
|
337
|
+
// 而整个 `writeFile` 返回 **ok:true** —— 调用方看到的成功与真实故障点完全脱节。同族的
|
|
338
|
+
// local-docker / k8s 用的正是 `if (!mk.ok) return`,这两条腿是漏的。
|
|
281
339
|
if (!mk.ok)
|
|
282
340
|
return { ok: false, error: fileErrorFromExec(mk.error, dir) };
|
|
283
341
|
if (mk.value.exitCode !== 0)
|
|
284
342
|
return { ok: false, error: new FileError("unknown", mk.value.stderr.trim() || `mkdir -p failed for ${dir}`, dir) };
|
|
285
343
|
}
|
|
344
|
+
// Stage to a local temp then `adb push` (binary-safe; avoids shell-escaping the payload).
|
|
286
345
|
let local;
|
|
287
346
|
try {
|
|
288
347
|
local = path.join(os.tmpdir(), `adb-push-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
@@ -321,6 +380,9 @@ export class RemoteAdbExecutionEnv {
|
|
|
321
380
|
merged.set(add, base.length);
|
|
322
381
|
return this.writeFile(abs, merged, abortSignal);
|
|
323
382
|
}
|
|
383
|
+
// ── design/158 B6:以下 POSIX shell-out 文件面全部委托共享基座(posix-shell-fs.ts)──────────────
|
|
384
|
+
// 五裁决(`--`/classifyFsStderr/ls -1A/mv 后缀形/temp 位置参数化)与 readLink・lstat 契约见基座头注;
|
|
385
|
+
// 委托钉在 test/posix-shell-fs.test.ts(腿内不再自拼 readlink/realpath 命令串)。
|
|
324
386
|
posixFsInst;
|
|
325
387
|
get posixFs() {
|
|
326
388
|
return (this.posixFsInst ??= createPosixShellFs({
|
|
@@ -356,27 +418,42 @@ export class RemoteAdbExecutionEnv {
|
|
|
356
418
|
async createTempFile(options) {
|
|
357
419
|
return this.posixFs.createTempFile(options);
|
|
358
420
|
}
|
|
421
|
+
// ─────────────────────────────── helpers ───────────────────────────────
|
|
422
|
+
/** Spawn the adb binary with the given args; collect stdout/stderr (+ raw bytes when binary), bound by timeout/abort. */
|
|
359
423
|
adb(args, opts) {
|
|
360
424
|
return new Promise((resolve) => {
|
|
361
425
|
let settled = false;
|
|
426
|
+
// D5 pipe-destroy grace: armed by killGrace() on abort/timeout; destroys stdout/stderr pipes if `close`
|
|
427
|
+
// never fires (a re-parented grandchild holding the FD). Cleared in finish() — the real `close` routes
|
|
428
|
+
// through finish() — so the timer never leaks. Does NOT change the synchronous settle below.
|
|
362
429
|
let forceSettleTimer;
|
|
363
430
|
const child = this.spawnFn(this.cfg.adbPath, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
431
|
+
// SIGKILL the child then arm the D5 pipe-destroy grace (only on the abort/timeout paths — a normal `close`
|
|
432
|
+
// never calls this). Idempotent: only one timer is ever armed.
|
|
364
433
|
const killGrace = () => {
|
|
365
434
|
try {
|
|
366
435
|
child.kill("SIGKILL");
|
|
367
436
|
}
|
|
368
|
-
catch { }
|
|
437
|
+
catch { /* noop */ }
|
|
369
438
|
forceSettleTimer ??= armPipeDestroyGrace(child);
|
|
370
439
|
};
|
|
440
|
+
// 🔴 binary caveat (D2): this helper is SHARED by the model-facing TEXT exec (must be bounded — a
|
|
441
|
+
// `yes`/`cat big` could OOM the durable worker) and by readBinaryFile (`exec-out cat`, opts.binary=true,
|
|
442
|
+
// which MUST keep EVERY byte or binary/large reads silently corrupt). So we branch on opts.binary:
|
|
443
|
+
// - binary=true → full Buffer[] + concat (byte-exact stdoutBytes; readBinaryFile path).
|
|
444
|
+
// - binary=false → bounded rolling-TAIL for stdout (keep last 8MB + dropped-byte marker, O(maxBytes)).
|
|
445
|
+
// stderr is ALWAYS bounded — it never carries the binary payload (just cat's error text).
|
|
371
446
|
const binary = !!opts?.binary;
|
|
372
|
-
const outBufs = [];
|
|
373
|
-
const outTail = binary ? undefined : new RollingTailBuffer();
|
|
374
|
-
const errBuf = new RollingTailBuffer();
|
|
447
|
+
const outBufs = []; // binary path only: full bytes for stdoutBytes
|
|
448
|
+
const outTail = binary ? undefined : new RollingTailBuffer(); // text path only: bounded stdout
|
|
449
|
+
const errBuf = new RollingTailBuffer(); // Buffer[]+concat replaced by rolling-tail — same O(n) push, bounded total
|
|
375
450
|
const finish = (r) => {
|
|
376
451
|
if (settled)
|
|
377
452
|
return;
|
|
378
453
|
settled = true;
|
|
379
454
|
clearTimeout(timer);
|
|
455
|
+
// D5 grace cleared in the `close` handler (pipes closed naturally), NOT here — abort/timeout reaches
|
|
456
|
+
// finish() BEFORE `close`, so clearing here would cancel the grace before it can free a leaked FD.
|
|
380
457
|
opts?.signal?.removeEventListener("abort", onAbort);
|
|
381
458
|
resolve(r);
|
|
382
459
|
};
|
|
@@ -399,7 +476,7 @@ export class RemoteAdbExecutionEnv {
|
|
|
399
476
|
outBufs.push(d);
|
|
400
477
|
else
|
|
401
478
|
outTail.push(d);
|
|
402
|
-
opts?.onStdout?.(d.toString());
|
|
479
|
+
opts?.onStdout?.(d.toString()); // streaming callback still gets the full chunk; only the buffered return is bounded
|
|
403
480
|
});
|
|
404
481
|
child.stderr.on("data", (d) => {
|
|
405
482
|
errBuf.push(d);
|
|
@@ -408,10 +485,11 @@ export class RemoteAdbExecutionEnv {
|
|
|
408
485
|
child.on("error", (e) => finish({ ok: false, error: new ExecutionError("spawn_error", `adb spawn failed (is '${this.cfg.adbPath}' installed?): ${e.message}`, e) }));
|
|
409
486
|
child.on("close", (code) => {
|
|
410
487
|
if (forceSettleTimer)
|
|
411
|
-
clearTimeout(forceSettleTimer);
|
|
488
|
+
clearTimeout(forceSettleTimer); // `close` fired → pipes closed naturally; clear D5 grace
|
|
412
489
|
const err = errBuf.result();
|
|
413
490
|
const stderr = markTruncated(err.text, err.droppedBytes);
|
|
414
491
|
if (binary) {
|
|
492
|
+
// byte-exact: readBinaryFile decodes stdoutBytes; never truncate.
|
|
415
493
|
const stdoutBytes = Buffer.concat(outBufs);
|
|
416
494
|
finish(ok({ stdout: stdoutBytes.toString("utf8"), stderr, exitCode: code ?? 0, stdoutBytes: new Uint8Array(stdoutBytes) }));
|
|
417
495
|
}
|
|
@@ -434,6 +512,11 @@ export class RemoteAdbExecutionEnv {
|
|
|
434
512
|
return parts.join(" ");
|
|
435
513
|
}
|
|
436
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* `ExecutionEnvFactory` for the ADB backend — one fresh (unconnected) env per task against the same device
|
|
517
|
+
* (lazy: `adb connect` on first use). Config (serial) is control-plane-supplied; the Runner owns the lifetime
|
|
518
|
+
* and calls `destroy()` (= `adb disconnect`, never a device wipe) on task end.
|
|
519
|
+
*/
|
|
437
520
|
export function adbExecutionEnvFactory(config) {
|
|
438
521
|
return (_ctx) => new RemoteAdbExecutionEnv(config);
|
|
439
522
|
}
|