@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.
Files changed (539) hide show
  1. package/dist/approval-hmac.d.ts +40 -0
  2. package/dist/approval-hmac.js +67 -0
  3. package/dist/approval.d.ts +31 -0
  4. package/dist/approval.js +72 -4
  5. package/dist/audit.d.ts +26 -0
  6. package/dist/audit.js +40 -1
  7. package/dist/auth-bridge.d.ts +10 -0
  8. package/dist/auth-bridge.js +47 -4
  9. package/dist/auth-keys.d.ts +19 -0
  10. package/dist/auth-keys.js +13 -0
  11. package/dist/bake-runner/main.d.ts +5 -0
  12. package/dist/bake-runner/main.js +43 -4
  13. package/dist/bake-runner/protocol.d.ts +57 -0
  14. package/dist/bake-runner/protocol.js +58 -3
  15. package/dist/bake-runner/runner.d.ts +54 -0
  16. package/dist/bake-runner/runner.js +87 -5
  17. package/dist/bench/l8/artifact.d.ts +63 -0
  18. package/dist/bench/l8/artifact.js +61 -2
  19. package/dist/bench/l8/escape.d.ts +36 -0
  20. package/dist/bench/l8/escape.js +25 -0
  21. package/dist/bench/l8/index.d.ts +14 -0
  22. package/dist/bench/l8/index.js +14 -0
  23. package/dist/bench/l8/probes.d.ts +74 -0
  24. package/dist/bench/l8/probes.js +60 -0
  25. package/dist/bench/l8/run-probes.d.ts +43 -0
  26. package/dist/bench/l8/run-probes.js +45 -2
  27. package/dist/bench/s1/arms.d.ts +126 -0
  28. package/dist/bench/s1/arms.js +188 -13
  29. package/dist/bench/s1/live-deps.d.ts +66 -0
  30. package/dist/bench/s1/live-deps.js +249 -11
  31. package/dist/bench/s1/oracle.d.ts +49 -0
  32. package/dist/bench/s1/oracle.js +36 -1
  33. package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
  34. package/dist/bench/s1/repair-oracle-adapter.js +30 -0
  35. package/dist/bench/s1/reviewer.d.ts +38 -0
  36. package/dist/bench/s1/reviewer.js +34 -0
  37. package/dist/bench/s1/row.d.ts +77 -0
  38. package/dist/bench/s1/row.js +62 -0
  39. package/dist/bench/s1/run-firm.d.ts +47 -0
  40. package/dist/bench/s1/run-firm.js +70 -4
  41. package/dist/bench/s1/runner-ctx.d.ts +71 -0
  42. package/dist/bench/s1/runner-ctx.js +36 -0
  43. package/dist/bench/s1/tasks.d.ts +108 -0
  44. package/dist/bench/s1/tasks.js +115 -0
  45. package/dist/boot-reclaim.d.ts +19 -0
  46. package/dist/boot-reclaim.js +20 -0
  47. package/dist/brain.d.ts +25 -0
  48. package/dist/brain.js +61 -1
  49. package/dist/budget.d.ts +66 -0
  50. package/dist/budget.js +128 -4
  51. package/dist/capabilities/builtin-tools.d.ts +3 -0
  52. package/dist/capabilities/builtin-tools.js +3 -0
  53. package/dist/capabilities/center-plugins.d.ts +17 -1
  54. package/dist/capabilities/center-plugins.js +45 -4
  55. package/dist/capabilities/center-prompts.d.ts +46 -0
  56. package/dist/capabilities/center-prompts.js +57 -3
  57. package/dist/capabilities/code-review-council.d.ts +28 -0
  58. package/dist/capabilities/code-review-council.js +40 -7
  59. package/dist/capabilities/collab-wire.d.ts +2 -0
  60. package/dist/capabilities/collab-workflows.d.ts +7 -0
  61. package/dist/capabilities/collab-workflows.js +44 -1
  62. package/dist/capabilities/oa-tools.d.ts +6 -0
  63. package/dist/capabilities/oa-tools.js +10 -0
  64. package/dist/capabilities/prompt.d.ts +14 -0
  65. package/dist/capabilities/prompt.js +14 -0
  66. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  67. package/dist/capabilities/prompts/code-review.js +14 -0
  68. package/dist/capabilities/prompts/identity.d.ts +6 -0
  69. package/dist/capabilities/prompts/identity.js +6 -0
  70. package/dist/capabilities/prompts/team.d.ts +4 -0
  71. package/dist/capabilities/prompts/team.js +4 -0
  72. package/dist/capabilities/repo-tools.d.ts +11 -0
  73. package/dist/capabilities/repo-tools.js +8 -0
  74. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  75. package/dist/capabilities/sandbox-file-send.js +91 -3
  76. package/dist/capabilities/scenarios.d.ts +130 -0
  77. package/dist/capabilities/scenarios.js +180 -7
  78. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  79. package/dist/capabilities/select-environment-tool.js +30 -0
  80. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  81. package/dist/capabilities/send-user-file-tool.js +65 -1
  82. package/dist/capabilities/skills.d.ts +29 -0
  83. package/dist/capabilities/skills.js +13 -2
  84. package/dist/capabilities/team.d.ts +22 -0
  85. package/dist/capabilities/team.js +22 -2
  86. package/dist/capabilities/tool-defer.d.ts +26 -0
  87. package/dist/capabilities/tool-defer.js +3 -0
  88. package/dist/config-center/apply-effective.d.ts +65 -0
  89. package/dist/config-center/apply-effective.js +204 -12
  90. package/dist/config-center/http-client.d.ts +34 -0
  91. package/dist/config-center/http-client.js +68 -0
  92. package/dist/config-center/restart-signal.d.ts +22 -0
  93. package/dist/config-center/restart-signal.js +39 -0
  94. package/dist/config-center/skills-mcp.d.ts +20 -1
  95. package/dist/config-center/skills-mcp.js +42 -7
  96. package/dist/config-center/types.d.ts +92 -1
  97. package/dist/config-lkg.d.ts +12 -0
  98. package/dist/config-lkg.js +41 -0
  99. package/dist/config-provider.d.ts +78 -0
  100. package/dist/config-provider.js +165 -2
  101. package/dist/config-types.d.ts +546 -0
  102. package/dist/config.d.ts +64 -0
  103. package/dist/config.js +455 -60
  104. package/dist/degenerate-instrument.d.ts +38 -0
  105. package/dist/degenerate-instrument.js +55 -3
  106. package/dist/elicitation.d.ts +39 -0
  107. package/dist/elicitation.js +87 -3
  108. package/dist/env-facts.d.ts +61 -0
  109. package/dist/env-facts.js +73 -7
  110. package/dist/fleet/fleet-bus.d.ts +185 -0
  111. package/dist/fleet/fleet-bus.js +333 -27
  112. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  113. package/dist/fleet/subagent-tail-bus.js +33 -2
  114. package/dist/fleet-client.d.ts +38 -0
  115. package/dist/fleet-client.js +44 -9
  116. package/dist/fleet-lease.d.ts +46 -0
  117. package/dist/fleet-lease.js +73 -5
  118. package/dist/hooks/branch-transcript.d.ts +8 -0
  119. package/dist/hooks/branch-transcript.js +33 -0
  120. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  121. package/dist/hooks/cc-stop-prompt.js +43 -1
  122. package/dist/hooks/hook-llm.d.ts +15 -0
  123. package/dist/hooks/hook-llm.js +47 -0
  124. package/dist/hooks/hook-runner.d.ts +89 -0
  125. package/dist/hooks/hook-runner.js +327 -18
  126. package/dist/http/idempotency.d.ts +31 -0
  127. package/dist/http/idempotency.js +34 -0
  128. package/dist/http/principal-gate.d.ts +17 -0
  129. package/dist/http/principal-gate.js +35 -3
  130. package/dist/http/route-ctx.d.ts +36 -0
  131. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  132. package/dist/http/routes/approvals-assistant.js +253 -23
  133. package/dist/http/routes/attachments.js +22 -4
  134. package/dist/http/routes/capabilities.d.ts +7 -0
  135. package/dist/http/routes/capabilities.js +202 -1
  136. package/dist/http/routes/fleet.d.ts +6 -0
  137. package/dist/http/routes/fleet.js +94 -5
  138. package/dist/http/routes/images.d.ts +17 -0
  139. package/dist/http/routes/images.js +222 -14
  140. package/dist/http/routes/leader.d.ts +7 -0
  141. package/dist/http/routes/leader.js +10 -0
  142. package/dist/http/routes/memory-policy.d.ts +6 -0
  143. package/dist/http/routes/memory-policy.js +38 -6
  144. package/dist/http/routes/notify-wake.d.ts +10 -0
  145. package/dist/http/routes/notify-wake.js +19 -3
  146. package/dist/http/routes/observability.d.ts +6 -0
  147. package/dist/http/routes/observability.js +19 -2
  148. package/dist/http/routes/runs.d.ts +15 -0
  149. package/dist/http/routes/runs.js +464 -41
  150. package/dist/http/routes/session-sync.d.ts +15 -0
  151. package/dist/http/routes/session-sync.js +229 -19
  152. package/dist/http/routes/sessions-list.d.ts +6 -0
  153. package/dist/http/routes/sessions-list.js +35 -4
  154. package/dist/http/routes/sessions.d.ts +14 -0
  155. package/dist/http/routes/sessions.js +176 -31
  156. package/dist/http/routes/side-query.d.ts +8 -0
  157. package/dist/http/routes/side-query.js +26 -1
  158. package/dist/http/routes/tasks.d.ts +18 -0
  159. package/dist/http/routes/tasks.js +501 -38
  160. package/dist/http/routes/trace-usage.d.ts +10 -0
  161. package/dist/http/routes/trace-usage.js +66 -14
  162. package/dist/http/routes/workflows.d.ts +12 -0
  163. package/dist/http/routes/workflows.js +180 -19
  164. package/dist/http/run-meta.d.ts +11 -0
  165. package/dist/http/run-meta.js +6 -0
  166. package/dist/http/send.d.ts +19 -0
  167. package/dist/http/send.js +11 -0
  168. package/dist/http/server.d.ts +255 -0
  169. package/dist/http/server.js +921 -75
  170. package/dist/http/sse-log.d.ts +15 -0
  171. package/dist/http/sse-log.js +16 -0
  172. package/dist/http/tar.d.ts +9 -0
  173. package/dist/http/tar.js +21 -5
  174. package/dist/http/wire-gate.d.ts +9 -0
  175. package/dist/http/wire-gate.js +9 -0
  176. package/dist/http/wire-types.d.ts +187 -0
  177. package/dist/http/workspace-content.d.ts +8 -0
  178. package/dist/http/workspace-content.js +10 -0
  179. package/dist/images/bake-validate.d.ts +63 -0
  180. package/dist/images/bake-validate.js +71 -1
  181. package/dist/images/manifest.d.ts +19 -0
  182. package/dist/images/manifest.js +6 -1
  183. package/dist/index.d.ts +1 -5
  184. package/dist/index.js +10 -5
  185. package/dist/key-resolver.d.ts +23 -0
  186. package/dist/key-resolver.js +27 -2
  187. package/dist/leader/diffout.d.ts +23 -0
  188. package/dist/leader/diffout.js +8 -1
  189. package/dist/leader/diffup.d.ts +32 -0
  190. package/dist/leader/diffup.js +43 -0
  191. package/dist/leader/endpoint.d.ts +20 -0
  192. package/dist/leader/endpoint.js +25 -2
  193. package/dist/leader/fanout.d.ts +60 -0
  194. package/dist/leader/fanout.js +29 -3
  195. package/dist/leader/grader-env-factory.d.ts +74 -0
  196. package/dist/leader/grader-env-factory.js +62 -3
  197. package/dist/leader/leader.d.ts +97 -0
  198. package/dist/leader/leader.js +151 -4
  199. package/dist/leader/merge.d.ts +94 -0
  200. package/dist/leader/merge.js +112 -9
  201. package/dist/leader/planner.d.ts +52 -0
  202. package/dist/leader/planner.js +47 -3
  203. package/dist/leader/repair-oracle.d.ts +61 -0
  204. package/dist/leader/repair-oracle.js +59 -1
  205. package/dist/leader/repair-wire.d.ts +78 -0
  206. package/dist/leader/repair-wire.js +79 -2
  207. package/dist/leader/wire.d.ts +79 -0
  208. package/dist/leader/wire.js +255 -8
  209. package/dist/lsp/e2b-bridge.d.ts +16 -0
  210. package/dist/lsp/e2b-bridge.js +32 -4
  211. package/dist/lsp/e2b-manager.d.ts +10 -0
  212. package/dist/lsp/e2b-manager.js +18 -2
  213. package/dist/lsp/lsp-frames.d.ts +12 -0
  214. package/dist/lsp/lsp-frames.js +12 -0
  215. package/dist/lsp/manager.d.ts +12 -0
  216. package/dist/lsp/manager.js +35 -2
  217. package/dist/lsp/types.d.ts +10 -0
  218. package/dist/lsp/ws-transport.d.ts +12 -0
  219. package/dist/lsp/ws-transport.js +53 -5
  220. package/dist/lsp-evict.d.ts +14 -0
  221. package/dist/lsp-evict.js +15 -1
  222. package/dist/main.js +2132 -96
  223. package/dist/memory-export.d.ts +1 -0
  224. package/dist/memory-export.js +4 -0
  225. package/dist/memory-scope.d.ts +49 -0
  226. package/dist/memory-scope.js +87 -4
  227. package/dist/memory-sync-client.d.ts +24 -0
  228. package/dist/memory-sync-client.js +41 -2
  229. package/dist/memory-sync.d.ts +23 -0
  230. package/dist/memory-sync.js +70 -1
  231. package/dist/model-select.d.ts +39 -0
  232. package/dist/model-select.js +42 -1
  233. package/dist/observability/cost-quota.d.ts +20 -0
  234. package/dist/observability/cost-quota.js +4 -0
  235. package/dist/observability/cost-taxonomy.d.ts +45 -0
  236. package/dist/observability/cost-taxonomy.js +34 -0
  237. package/dist/observability/logger.d.ts +1 -0
  238. package/dist/observability/logger.js +6 -0
  239. package/dist/observability/metrics.d.ts +13 -0
  240. package/dist/observability/metrics.js +63 -0
  241. package/dist/observability/otel-exporter.d.ts +9 -0
  242. package/dist/observability/otel-exporter.js +11 -3
  243. package/dist/observability/principal-context.d.ts +9 -0
  244. package/dist/observability/principal-context.js +9 -0
  245. package/dist/observability/prompt-manifest.d.ts +37 -0
  246. package/dist/observability/prompt-manifest.js +35 -1
  247. package/dist/observability/rate-limit.d.ts +10 -0
  248. package/dist/observability/rate-limit.js +1 -0
  249. package/dist/observability/tool-trace.d.ts +24 -0
  250. package/dist/observability/tool-trace.js +41 -1
  251. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  252. package/dist/orchestration/hardened-vm-runner.js +119 -4
  253. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  254. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  255. package/dist/orchestration/hardened-vm-worker.js +27 -0
  256. package/dist/orchestration/subagent-steer.d.ts +44 -0
  257. package/dist/orchestration/subagent-steer.js +45 -1
  258. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  259. package/dist/orchestration/workflow-agent-steer.js +80 -1
  260. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  261. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  262. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  263. package/dist/orchestration/workflow-notify-journal.js +187 -13
  264. package/dist/parked-decide.d.ts +61 -0
  265. package/dist/parked-decide.js +58 -1
  266. package/dist/per-task-image.d.ts +54 -0
  267. package/dist/per-task-image.js +41 -0
  268. package/dist/plan-cache-probe.d.ts +35 -0
  269. package/dist/plan-cache-probe.js +18 -3
  270. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  271. package/dist/plugins/approval-exemption-store.js +28 -2
  272. package/dist/plugins/approval-store-sql.d.ts +64 -0
  273. package/dist/plugins/approval-store-sql.js +32 -0
  274. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  275. package/dist/plugins/background-agent-store-sql.js +91 -4
  276. package/dist/plugins/background-shell-support.d.ts +98 -0
  277. package/dist/plugins/background-shell-support.js +117 -13
  278. package/dist/plugins/blob-backend.d.ts +104 -0
  279. package/dist/plugins/blob-backend.js +163 -6
  280. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  281. package/dist/plugins/breaker-state-sql.js +46 -8
  282. package/dist/plugins/caching-session-store.d.ts +42 -0
  283. package/dist/plugins/caching-session-store.js +63 -3
  284. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  285. package/dist/plugins/checkpoint-store-sql.js +239 -11
  286. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  287. package/dist/plugins/file-outcome-sink.js +9 -0
  288. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  289. package/dist/plugins/file-resume-anchor-store.js +43 -4
  290. package/dist/plugins/file-run-store.d.ts +90 -0
  291. package/dist/plugins/file-run-store.js +145 -13
  292. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  293. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  294. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  295. package/dist/plugins/file-workflow-journal-store.js +10 -0
  296. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  297. package/dist/plugins/fork-routing-session-store.js +51 -3
  298. package/dist/plugins/host-platform.d.ts +69 -0
  299. package/dist/plugins/host-platform.js +81 -2
  300. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  301. package/dist/plugins/image-bake-store-sql.js +241 -7
  302. package/dist/plugins/image-index-sql.d.ts +46 -0
  303. package/dist/plugins/image-index-sql.js +113 -4
  304. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  305. package/dist/plugins/k8s-bg-scripts.js +88 -4
  306. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  307. package/dist/plugins/k8s-exec-protocol.js +41 -0
  308. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  309. package/dist/plugins/local-checkpoint-store.js +86 -7
  310. package/dist/plugins/local-session-store.d.ts +157 -0
  311. package/dist/plugins/local-session-store.js +289 -34
  312. package/dist/plugins/local-task-attachment-store.js +14 -2
  313. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  314. package/dist/plugins/mailbox-store-sql.js +39 -6
  315. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  316. package/dist/plugins/memory-engine-pg.js +122 -4
  317. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  318. package/dist/plugins/memory-engine-tidb.js +115 -5
  319. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  320. package/dist/plugins/memory-engine-vector-util.js +5 -0
  321. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  322. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  323. package/dist/plugins/memory-run-store.d.ts +63 -0
  324. package/dist/plugins/memory-run-store.js +73 -8
  325. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  326. package/dist/plugins/memory-session-policy-store.js +17 -0
  327. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  328. package/dist/plugins/memory-sync-store-pg.js +45 -2
  329. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  330. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  331. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  332. package/dist/plugins/outcome-ledger-sql.js +97 -3
  333. package/dist/plugins/pg-approval-store.d.ts +7 -0
  334. package/dist/plugins/pg-approval-store.js +7 -0
  335. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  336. package/dist/plugins/pg-breaker-state.js +6 -0
  337. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  338. package/dist/plugins/pg-checkpoint-store.js +8 -0
  339. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  340. package/dist/plugins/pg-cost-quota.js +6 -0
  341. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  342. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  343. package/dist/plugins/pg-image-bake.d.ts +9 -0
  344. package/dist/plugins/pg-image-bake.js +9 -0
  345. package/dist/plugins/pg-image-index.d.ts +9 -0
  346. package/dist/plugins/pg-image-index.js +9 -0
  347. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  348. package/dist/plugins/pg-outcome-ledger.js +9 -0
  349. package/dist/plugins/pg-pool.d.ts +50 -0
  350. package/dist/plugins/pg-pool.js +78 -0
  351. package/dist/plugins/pg-query.d.ts +11 -0
  352. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  353. package/dist/plugins/pg-rate-limiter.js +12 -2
  354. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  355. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  356. package/dist/plugins/pg-run-store.d.ts +7 -0
  357. package/dist/plugins/pg-run-store.js +7 -0
  358. package/dist/plugins/pg-safe-json.d.ts +13 -0
  359. package/dist/plugins/pg-safe-json.js +40 -4
  360. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  361. package/dist/plugins/pg-session-policy-store.js +5 -0
  362. package/dist/plugins/pg-session-storage.d.ts +72 -0
  363. package/dist/plugins/pg-session-storage.js +152 -20
  364. package/dist/plugins/pg-session-store.d.ts +10 -0
  365. package/dist/plugins/pg-session-store.js +10 -0
  366. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  367. package/dist/plugins/pg-tool-result-store.js +7 -0
  368. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  369. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  370. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  371. package/dist/plugins/pg-workflow-run-store.js +7 -0
  372. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  373. package/dist/plugins/posix-shell-fs.js +31 -1
  374. package/dist/plugins/remote-env-adb.d.ts +25 -0
  375. package/dist/plugins/remote-env-adb.js +95 -12
  376. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  377. package/dist/plugins/remote-env-e2b.js +371 -40
  378. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  379. package/dist/plugins/remote-env-file-error.js +37 -0
  380. package/dist/plugins/remote-env-host.d.ts +151 -0
  381. package/dist/plugins/remote-env-host.js +468 -70
  382. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  383. package/dist/plugins/remote-env-k8s.js +318 -32
  384. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  385. package/dist/plugins/remote-env-local-docker.js +149 -24
  386. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  387. package/dist/plugins/remote-env-ssh.js +117 -20
  388. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  389. package/dist/plugins/remote-scratchpad.js +32 -2
  390. package/dist/plugins/remote-shell.d.ts +22 -0
  391. package/dist/plugins/remote-shell.js +27 -1
  392. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  393. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  394. package/dist/plugins/roster-store-sql.d.ts +27 -0
  395. package/dist/plugins/roster-store-sql.js +54 -0
  396. package/dist/plugins/run-store-sql.d.ts +194 -0
  397. package/dist/plugins/run-store-sql.js +210 -9
  398. package/dist/plugins/s3-presign.d.ts +20 -0
  399. package/dist/plugins/s3-presign.js +49 -2
  400. package/dist/plugins/scheduler-support.d.ts +12 -0
  401. package/dist/plugins/scheduler-support.js +75 -3
  402. package/dist/plugins/send-file-ledger.d.ts +15 -0
  403. package/dist/plugins/send-file-ledger.js +53 -4
  404. package/dist/plugins/send-user-file.d.ts +77 -0
  405. package/dist/plugins/send-user-file.js +92 -4
  406. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  407. package/dist/plugins/session-policy-store-sql.js +75 -3
  408. package/dist/plugins/session-store.d.ts +45 -0
  409. package/dist/plugins/session-store.js +51 -0
  410. package/dist/plugins/sql-driver.d.ts +77 -0
  411. package/dist/plugins/sql-driver.js +4 -0
  412. package/dist/plugins/sql-escape.d.ts +8 -0
  413. package/dist/plugins/sql-escape.js +8 -0
  414. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  415. package/dist/plugins/sql-row-helpers.js +25 -0
  416. package/dist/plugins/store-backend.d.ts +103 -0
  417. package/dist/plugins/store-backend.js +120 -27
  418. package/dist/plugins/store-contracts.d.ts +62 -0
  419. package/dist/plugins/store-contracts.js +3 -0
  420. package/dist/plugins/task-attachment-store.d.ts +60 -0
  421. package/dist/plugins/task-attachment-store.js +49 -3
  422. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  423. package/dist/plugins/task-list-store-sql.js +21 -0
  424. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  425. package/dist/plugins/tidb-approval-store.js +6 -0
  426. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  427. package/dist/plugins/tidb-breaker-state.js +5 -0
  428. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  429. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  430. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  431. package/dist/plugins/tidb-cost-quota.js +1 -0
  432. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  433. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  434. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  435. package/dist/plugins/tidb-image-bake.js +8 -0
  436. package/dist/plugins/tidb-image-index.d.ts +8 -0
  437. package/dist/plugins/tidb-image-index.js +8 -0
  438. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  439. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  440. package/dist/plugins/tidb-pool.d.ts +56 -0
  441. package/dist/plugins/tidb-pool.js +181 -1
  442. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  443. package/dist/plugins/tidb-rate-limiter.js +5 -2
  444. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  445. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  446. package/dist/plugins/tidb-run-store.d.ts +7 -0
  447. package/dist/plugins/tidb-run-store.js +7 -0
  448. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  449. package/dist/plugins/tidb-session-policy-store.js +5 -0
  450. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  451. package/dist/plugins/tidb-session-storage.js +62 -3
  452. package/dist/plugins/tidb-session-store.d.ts +142 -0
  453. package/dist/plugins/tidb-session-store.js +264 -16
  454. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  455. package/dist/plugins/tidb-tool-result-store.js +7 -0
  456. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  457. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  458. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  459. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  460. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  461. package/dist/plugins/tool-result-store-sql.js +38 -2
  462. package/dist/plugins/web-search.d.ts +35 -0
  463. package/dist/plugins/web-search.js +45 -9
  464. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  465. package/dist/plugins/workflow-journal-limits.js +10 -0
  466. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  467. package/dist/plugins/workflow-journal-store-sql.js +58 -2
  468. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  469. package/dist/plugins/workflow-run-store-sql.js +84 -6
  470. package/dist/plugins/worktree-isolation.d.ts +45 -0
  471. package/dist/plugins/worktree-isolation.js +105 -6
  472. package/dist/plugins/write-behind-counter.d.ts +56 -1
  473. package/dist/plugins/write-behind-counter.js +53 -14
  474. package/dist/principal-jwt.d.ts +24 -0
  475. package/dist/principal-jwt.js +60 -5
  476. package/dist/project-memory.d.ts +22 -0
  477. package/dist/project-memory.js +144 -15
  478. package/dist/prompts-domain-validate.d.ts +28 -0
  479. package/dist/prompts-domain-validate.js +42 -1
  480. package/dist/question.d.ts +33 -0
  481. package/dist/question.js +69 -2
  482. package/dist/resource-suspend.d.ts +21 -0
  483. package/dist/resource-suspend.js +16 -0
  484. package/dist/router/route-orchestration.d.ts +78 -0
  485. package/dist/router/route-orchestration.js +77 -0
  486. package/dist/run-local.d.ts +32 -0
  487. package/dist/run-local.js +172 -8
  488. package/dist/runs.d.ts +189 -4
  489. package/dist/runs.js +465 -24
  490. package/dist/runtime-caps-resolver.d.ts +106 -0
  491. package/dist/runtime-caps-resolver.js +89 -4
  492. package/dist/runtime-governance.d.ts +84 -0
  493. package/dist/runtime-governance.js +127 -1
  494. package/dist/sandbox-pkg-source.d.ts +23 -0
  495. package/dist/sandbox-pkg-source.js +37 -0
  496. package/dist/sealed-key.d.ts +54 -0
  497. package/dist/sealed-key.js +68 -3
  498. package/dist/security.d.ts +108 -0
  499. package/dist/security.js +145 -6
  500. package/dist/sema-registry.d.ts +21 -0
  501. package/dist/sema-registry.js +21 -0
  502. package/dist/session-leaf-bus.d.ts +31 -0
  503. package/dist/session-leaf-bus.js +32 -0
  504. package/dist/session-sync-content.d.ts +46 -0
  505. package/dist/session-sync-content.js +47 -1
  506. package/dist/session-sync-kernel.d.ts +89 -0
  507. package/dist/session-sync-kernel.js +48 -3
  508. package/dist/session-sync.d.ts +125 -0
  509. package/dist/session-sync.js +181 -8
  510. package/dist/session-titler.d.ts +26 -0
  511. package/dist/session-titler.js +41 -7
  512. package/dist/session-watch.d.ts +53 -1
  513. package/dist/session-watch.js +73 -9
  514. package/dist/sighup-idle.d.ts +30 -0
  515. package/dist/sighup-idle.js +12 -1
  516. package/dist/spec-fields.d.ts +91 -3
  517. package/dist/spec-fields.js +116 -4
  518. package/dist/task-cwd.d.ts +50 -0
  519. package/dist/task-cwd.js +68 -1
  520. package/dist/task-mcp.d.ts +47 -0
  521. package/dist/task-mcp.js +29 -0
  522. package/dist/task-settings.d.ts +175 -0
  523. package/dist/task-settings.js +226 -11
  524. package/dist/task-workflow.d.ts +67 -0
  525. package/dist/task-workflow.js +75 -8
  526. package/dist/tool-approval.d.ts +91 -0
  527. package/dist/tool-approval.js +215 -0
  528. package/dist/trace/artifacts.d.ts +9 -0
  529. package/dist/trace/artifacts.js +30 -5
  530. package/dist/trace/core-keyset-guard.d.ts +18 -0
  531. package/dist/trace/ledger-sink.d.ts +43 -0
  532. package/dist/trace/ledger-sink.js +64 -5
  533. package/dist/trace/project.d.ts +133 -0
  534. package/dist/trace/project.js +189 -2
  535. package/dist/trace/redact.d.ts +19 -0
  536. package/dist/trace/redact.js +66 -9
  537. package/dist/usage-analytics.d.ts +26 -0
  538. package/dist/usage-analytics.js +26 -3
  539. 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
  }