@sema-agent/server 7.138.0 → 7.140.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 (332) hide show
  1. package/MIGRATION.md +457 -7
  2. package/README.md +7 -4
  3. package/README.zh-CN.md +6 -4
  4. package/USAGE.md +91 -41
  5. package/deploy/sema-up/README.md +1 -1
  6. package/deploy/sema-up/lib/lanes.json +3 -2
  7. package/dist/adoption/runner.js +1 -1
  8. package/dist/adoption/sql.js +1 -1
  9. package/dist/adoption/wire.d.ts +3 -3
  10. package/dist/approval-card.d.ts +26 -26
  11. package/dist/bench/s1/arms.d.ts +1 -1
  12. package/dist/bench/s1/arms.js +1 -3
  13. package/dist/bench/s1/live-deps.js +3 -2
  14. package/dist/bench/s1/row.d.ts +5 -2
  15. package/dist/bench/s1/row.js +2 -22
  16. package/dist/bench/s1/run-firm.js +2 -2
  17. package/dist/boot/adoption.js +1 -1
  18. package/dist/boot/device-lane.d.ts +8 -3
  19. package/dist/boot/device-lane.js +7 -2
  20. package/dist/boot/execution-env.d.ts +4 -2
  21. package/dist/boot/execution-env.js +28 -34
  22. package/dist/boot/execution-lane.d.ts +9 -1
  23. package/dist/boot/execution-lane.js +6 -1
  24. package/dist/boot/governance-seams.d.ts +3 -2
  25. package/dist/boot/governance-seams.js +9 -11
  26. package/dist/boot/memory-boundary.d.ts +14 -51
  27. package/dist/boot/memory-boundary.js +10 -20
  28. package/dist/boot/memory-consolidation.d.ts +15 -11
  29. package/dist/boot/memory-consolidation.js +25 -14
  30. package/dist/boot/resolve-spec.d.ts +4 -6
  31. package/dist/boot/resolve-spec.js +10 -13
  32. package/dist/boot/retention-lane.d.ts +5 -5
  33. package/dist/boot/retention-lane.js +0 -6
  34. package/dist/boot/runner-deps.d.ts +6 -4
  35. package/dist/boot/runner-deps.js +3 -1
  36. package/dist/boot/session-faces.d.ts +0 -3
  37. package/dist/boot/session-faces.js +15 -8
  38. package/dist/boot/stage-02-web-admin-pull.js +2 -2
  39. package/dist/boot/stage-03-store-backend.d.ts +2 -6
  40. package/dist/boot/stage-03-store-backend.js +2 -3
  41. package/dist/boot/stage-04-stores.d.ts +2 -6
  42. package/dist/boot/stage-04-stores.js +5 -5
  43. package/dist/boot/stage-05-execution-env.d.ts +2 -6
  44. package/dist/boot/stage-05-execution-env.js +2 -2
  45. package/dist/boot/stage-06-runners.d.ts +2 -6
  46. package/dist/boot/stage-06-runners.js +2 -3
  47. package/dist/boot/stage-07-capability-layer.d.ts +2 -6
  48. package/dist/boot/stage-08-reapers.d.ts +2 -6
  49. package/dist/boot/stage-09-leader.d.ts +2 -6
  50. package/dist/boot/stage-09-leader.js +1 -2
  51. package/dist/boot/stage-10-http-server.d.ts +2 -6
  52. package/dist/boot/stage-10-http-server.js +7 -6
  53. package/dist/boot/stores.d.ts +3 -6
  54. package/dist/boot/stores.js +27 -40
  55. package/dist/boot/task-list-lane.d.ts +1 -1
  56. package/dist/boot/task-list-lane.js +1 -1
  57. package/dist/boot/web-admin.js +37 -11
  58. package/dist/capabilities/execution-lane.d.ts +2 -2
  59. package/dist/capabilities/mcp-probe.js +1 -1
  60. package/dist/capabilities/scenarios.d.ts +1 -1
  61. package/dist/capability-facts.d.ts +15 -7
  62. package/dist/capability-facts.js +8 -3
  63. package/dist/config-catalog.js +9 -8
  64. package/dist/config-invariants.d.ts +23 -3
  65. package/dist/config-invariants.js +42 -0
  66. package/dist/config-provider.d.ts +33 -37
  67. package/dist/config-provider.js +51 -30
  68. package/dist/config-types.d.ts +21 -7
  69. package/dist/config.d.ts +33 -0
  70. package/dist/config.js +46 -16
  71. package/dist/delegated-session-owner.d.ts +4 -3
  72. package/dist/delegated-session-owner.js +1 -1
  73. package/dist/deployment-shape.d.ts +10 -9
  74. package/dist/deployment-shape.js +4 -4
  75. package/dist/device-enrollment.d.ts +41 -2
  76. package/dist/device-enrollment.js +27 -12
  77. package/dist/device-store.d.ts +58 -85
  78. package/dist/device-store.js +19 -49
  79. package/dist/device-ws-hub.js +2 -1
  80. package/dist/env-name-allowlist-knobs.d.ts +5 -4
  81. package/dist/exec-cut.d.ts +60 -0
  82. package/dist/exec-cut.js +36 -0
  83. package/dist/execution-lane-caps.d.ts +115 -105
  84. package/dist/execution-lane-caps.js +76 -82
  85. package/dist/execution-placement.d.ts +259 -0
  86. package/dist/execution-placement.js +199 -0
  87. package/dist/field-conflict.d.ts +3 -2
  88. package/dist/field-conflict.js +1 -0
  89. package/dist/hosted-posture.d.ts +2 -2
  90. package/dist/http/admission.js +8 -19
  91. package/dist/http/checkpoint-ctx.d.ts +21 -12
  92. package/dist/http/checkpoint-ctx.js +4 -2
  93. package/dist/http/claimed-run.d.ts +1 -1
  94. package/dist/http/durable-run-leg.js +9 -5
  95. package/dist/http/execution-context.d.ts +218 -0
  96. package/dist/http/execution-context.js +330 -0
  97. package/dist/http/memory-compliance-failure-reply.d.ts +3 -1
  98. package/dist/http/memory-compliance-failure-reply.js +5 -0
  99. package/dist/http/memory-layer-reply.d.ts +30 -0
  100. package/dist/http/memory-layer-reply.js +24 -0
  101. package/dist/http/resume-legs.js +63 -36
  102. package/dist/http/retired-service-deps.d.ts +1 -1
  103. package/dist/http/retired-service-deps.js +1 -1
  104. package/dist/http/route-ctx.d.ts +14 -8
  105. package/dist/http/routes/adoption.js +1 -1
  106. package/dist/http/routes/background.d.ts +29 -1
  107. package/dist/http/routes/background.js +29 -2
  108. package/dist/http/routes/devices.d.ts +13 -19
  109. package/dist/http/routes/devices.js +21 -26
  110. package/dist/http/routes/memory-bundle.js +3 -0
  111. package/dist/http/routes/memory-compliance.js +8 -1
  112. package/dist/http/routes/memory-consolidation.js +12 -1
  113. package/dist/http/routes/memory-origin.js +14 -2
  114. package/dist/http/routes/memory-policy.js +5 -0
  115. package/dist/http/routes/session-sync.js +110 -15
  116. package/dist/http/routes/sessions.d.ts +6 -0
  117. package/dist/http/routes/sessions.js +143 -22
  118. package/dist/http/routes/side-query.d.ts +12 -4
  119. package/dist/http/routes/side-query.js +4 -5
  120. package/dist/http/routes/tasks.js +41 -33
  121. package/dist/http/server.d.ts +40 -44
  122. package/dist/http/server.js +13 -2
  123. package/dist/http/session-inherit-env.d.ts +3 -4
  124. package/dist/http/session-inherit-env.js +1 -1
  125. package/dist/http/wire-types.d.ts +8 -12
  126. package/dist/identity-source.d.ts +1 -1
  127. package/dist/identity-source.js +1 -1
  128. package/dist/index.d.ts +1 -0
  129. package/dist/lane-home-probe.d.ts +68 -42
  130. package/dist/lane-home-probe.js +53 -30
  131. package/dist/leader/wire.js +5 -4
  132. package/dist/memory-bundle-engine.d.ts +16 -9
  133. package/dist/memory-bundle-engine.js +29 -6
  134. package/dist/memory-operator-faces.d.ts +85 -30
  135. package/dist/memory-operator-faces.js +136 -30
  136. package/dist/memory-project-layer.d.ts +3 -21
  137. package/dist/memory-project-layer.js +11 -8
  138. package/dist/memory-scope-stores.d.ts +73 -0
  139. package/dist/memory-scope-stores.js +86 -0
  140. package/dist/memory-scope.d.ts +29 -5
  141. package/dist/memory-scope.js +16 -4
  142. package/dist/memory-sync-client.d.ts +70 -18
  143. package/dist/memory-sync-client.js +215 -117
  144. package/dist/memory-sync.d.ts +1 -1
  145. package/dist/memory-sync.js +3 -2
  146. package/dist/observability/cost-taxonomy.d.ts +2 -2
  147. package/dist/observability/fail-open.d.ts +12 -0
  148. package/dist/observability/fail-open.js +12 -0
  149. package/dist/observability/run-terminal.js +0 -1
  150. package/dist/orchestration/workflow-notify-journal.js +4 -4
  151. package/dist/org-memory-admission.d.ts +4 -3
  152. package/dist/org-memory-admission.js +6 -6
  153. package/dist/parked-decide.d.ts +34 -9
  154. package/dist/parked-decide.js +12 -19
  155. package/dist/parked-revive-surface.d.ts +12 -15
  156. package/dist/parked-revive-surface.js +3 -6
  157. package/dist/peer-seat.d.ts +13 -7
  158. package/dist/peer-seat.js +37 -3
  159. package/dist/plugins/adoption-log-sql.js +4 -4
  160. package/dist/plugins/approval-ask-store-file.d.ts +7 -0
  161. package/dist/plugins/approval-ask-store-file.js +11 -0
  162. package/dist/plugins/approval-ask-store-memory.d.ts +6 -0
  163. package/dist/plugins/approval-ask-store-memory.js +12 -0
  164. package/dist/plugins/approval-ask-store-sql.d.ts +22 -5
  165. package/dist/plugins/approval-ask-store-sql.js +44 -26
  166. package/dist/plugins/approval-nonce-store.js +4 -4
  167. package/dist/plugins/blob-backend.d.ts +4 -4
  168. package/dist/plugins/blob-backend.js +7 -7
  169. package/dist/plugins/breaker-state-sql.js +2 -2
  170. package/dist/plugins/caching-session-store.d.ts +6 -2
  171. package/dist/plugins/caching-session-store.js +9 -3
  172. package/dist/plugins/checkpoint-index-columns.js +2 -2
  173. package/dist/plugins/checkpoint-store-sql.d.ts +6 -5
  174. package/dist/plugins/checkpoint-store-sql.js +21 -23
  175. package/dist/plugins/device-store-sql.d.ts +25 -51
  176. package/dist/plugins/device-store-sql.js +68 -122
  177. package/dist/plugins/ensure-index.d.ts +1 -2
  178. package/dist/plugins/execution-placement-sql.d.ts +151 -0
  179. package/dist/plugins/execution-placement-sql.js +223 -0
  180. package/dist/plugins/file-history-store-sql.d.ts +9 -8
  181. package/dist/plugins/file-history-store-sql.js +9 -9
  182. package/dist/plugins/file-run-store.d.ts +6 -1
  183. package/dist/plugins/file-run-store.js +4 -0
  184. package/dist/plugins/fork-routing-session-store.d.ts +6 -0
  185. package/dist/plugins/fork-routing-session-store.js +16 -0
  186. package/dist/plugins/image-bake-store-sql.js +9 -9
  187. package/dist/plugins/image-index-sql.js +11 -11
  188. package/dist/plugins/leader-run-store-sql.js +4 -4
  189. package/dist/plugins/local-session-store.d.ts +149 -50
  190. package/dist/plugins/local-session-store.js +382 -107
  191. package/dist/plugins/mailbox-store-sql.d.ts +2 -1
  192. package/dist/plugins/mailbox-store-sql.js +4 -4
  193. package/dist/plugins/memory-engine-tidb.js +5 -5
  194. package/dist/plugins/memory-key-guards.d.ts +4 -0
  195. package/dist/plugins/memory-key-guards.js +1 -0
  196. package/dist/plugins/memory-optout-grant-store-sql.js +1 -1
  197. package/dist/plugins/memory-run-store.d.ts +1 -1
  198. package/dist/plugins/memory-sync-store-tidb.js +3 -3
  199. package/dist/plugins/one-time-migrations.d.ts +117 -8
  200. package/dist/plugins/one-time-migrations.js +408 -38
  201. package/dist/plugins/org-delivery-quota-store.js +2 -2
  202. package/dist/plugins/outcome-ledger-sql.d.ts +2 -2
  203. package/dist/plugins/outcome-ledger-sql.js +2 -2
  204. package/dist/plugins/permission-rule-store-sql.d.ts +17 -19
  205. package/dist/plugins/permission-rule-store-sql.js +29 -32
  206. package/dist/plugins/pg-pool.d.ts +7 -3
  207. package/dist/plugins/pg-session-storage.d.ts +31 -20
  208. package/dist/plugins/pg-session-storage.js +120 -52
  209. package/dist/plugins/remote-env-adb.d.ts +18 -19
  210. package/dist/plugins/remote-env-adb.js +91 -66
  211. package/dist/plugins/remote-env-device.d.ts +23 -31
  212. package/dist/plugins/remote-env-device.js +19 -17
  213. package/dist/plugins/remote-env-e2b.d.ts +27 -21
  214. package/dist/plugins/remote-env-e2b.js +91 -45
  215. package/dist/plugins/remote-env-file-error.d.ts +3 -1
  216. package/dist/plugins/remote-env-file-error.js +9 -3
  217. package/dist/plugins/remote-env-host.d.ts +31 -34
  218. package/dist/plugins/remote-env-host.js +91 -72
  219. package/dist/plugins/remote-env-k8s.d.ts +13 -29
  220. package/dist/plugins/remote-env-k8s.js +63 -55
  221. package/dist/plugins/remote-env-local-docker.d.ts +24 -12
  222. package/dist/plugins/remote-env-local-docker.js +49 -61
  223. package/dist/plugins/remote-env-ssh.d.ts +11 -19
  224. package/dist/plugins/remote-env-ssh.js +74 -57
  225. package/dist/plugins/remote-shell.d.ts +100 -3
  226. package/dist/plugins/remote-shell.js +166 -2
  227. package/dist/plugins/resume-anchor-store-sql.js +2 -2
  228. package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
  229. package/dist/plugins/retention-lane-store-sql.js +2 -2
  230. package/dist/plugins/retention-store-sql.d.ts +10 -7
  231. package/dist/plugins/retention-store-sql.js +13 -7
  232. package/dist/plugins/run-store-sql.d.ts +13 -3
  233. package/dist/plugins/run-store-sql.js +20 -15
  234. package/dist/plugins/schema-consistency.d.ts +21 -11
  235. package/dist/plugins/schema-consistency.js +15 -9
  236. package/dist/plugins/schema-drift-sentence.d.ts +27 -0
  237. package/dist/plugins/schema-drift-sentence.js +38 -0
  238. package/dist/plugins/schema-ensure-legs.d.ts +2 -3
  239. package/dist/plugins/schema-ensure-legs.js +2 -2
  240. package/dist/plugins/schema-live-columns.d.ts +1 -1
  241. package/dist/plugins/session-capture-record-store-sql.js +1 -1
  242. package/dist/plugins/session-fork.d.ts +54 -0
  243. package/dist/plugins/session-fork.js +38 -1
  244. package/dist/plugins/session-row-sql.d.ts +22 -0
  245. package/dist/plugins/session-row-sql.js +81 -0
  246. package/dist/plugins/session-rules-column.d.ts +1 -1
  247. package/dist/plugins/session-rules-column.js +1 -1
  248. package/dist/plugins/session-store.d.ts +1 -1
  249. package/dist/plugins/session-workspace-cell.d.ts +1 -1
  250. package/dist/plugins/session-workspace-cell.js +1 -1
  251. package/dist/plugins/shared-memory-store-sql.js +2 -2
  252. package/dist/plugins/sql-driver.d.ts +10 -5
  253. package/dist/plugins/sql-driver.js +6 -6
  254. package/dist/plugins/sql-errors.js +1 -1
  255. package/dist/plugins/store-backend.d.ts +5 -7
  256. package/dist/plugins/store-backend.js +23 -11
  257. package/dist/plugins/store-contracts.d.ts +25 -5
  258. package/dist/plugins/task-list-store-sql.js +11 -11
  259. package/dist/plugins/tidb-pool.d.ts +12 -7
  260. package/dist/plugins/tidb-pool.js +13 -7
  261. package/dist/plugins/tidb-session-storage.js +4 -4
  262. package/dist/plugins/tidb-session-store.d.ts +57 -26
  263. package/dist/plugins/tidb-session-store.js +127 -59
  264. package/dist/plugins/tool-result-store-sql.d.ts +5 -4
  265. package/dist/plugins/tool-result-store-sql.js +21 -13
  266. package/dist/plugins/user-input-ledger-sql.js +2 -2
  267. package/dist/plugins/workflow-journal-store-sql.js +5 -5
  268. package/dist/plugins/workflow-run-store-sql.js +19 -19
  269. package/dist/plugins/write-behind-counter.d.ts +2 -3
  270. package/dist/plugins/write-behind-counter.js +5 -5
  271. package/dist/project-memory.d.ts +9 -15
  272. package/dist/project-memory.js +5 -4
  273. package/dist/request-key-closure.js +1 -1
  274. package/dist/request-value-closure.d.ts +6 -7
  275. package/dist/request-value-closure.js +1 -3
  276. package/dist/resource-suspend.d.ts +14 -12
  277. package/dist/resource-suspend.js +1 -1
  278. package/dist/resource-window.d.ts +4 -3
  279. package/dist/run-local.d.ts +6 -0
  280. package/dist/run-local.js +34 -35
  281. package/dist/runs.d.ts +10 -5
  282. package/dist/runs.js +52 -66
  283. package/dist/security.d.ts +38 -12
  284. package/dist/security.js +8 -2
  285. package/dist/server-secret-env.d.ts +9 -5
  286. package/dist/session-children-retire.d.ts +27 -9
  287. package/dist/session-children-retire.js +9 -5
  288. package/dist/session-incarnation.d.ts +20 -10
  289. package/dist/session-incarnation.js +5 -3
  290. package/dist/session-policy-wire.d.ts +1 -1
  291. package/dist/session-row.d.ts +114 -5
  292. package/dist/session-row.js +55 -5
  293. package/dist/session-titler.d.ts +2 -2
  294. package/dist/sql-engine-posture.d.ts +1 -1
  295. package/dist/sql-engine-posture.js +1 -1
  296. package/dist/{plugins → stores-sql}/background-agent-store-sql.d.ts +2 -2
  297. package/dist/{plugins → stores-sql}/background-agent-store-sql.js +8 -8
  298. package/dist/{plugins → stores-sql}/session-policy-store-sql.d.ts +7 -5
  299. package/dist/{plugins → stores-sql}/session-policy-store-sql.js +12 -12
  300. package/dist/{plugins → stores-sql}/usage-window-store-sql.d.ts +1 -1
  301. package/dist/{plugins → stores-sql}/usage-window-store-sql.js +3 -3
  302. package/dist/task-a2a.d.ts +1 -1
  303. package/dist/task-a2a.js +5 -6
  304. package/dist/task-cwd.d.ts +6 -1
  305. package/dist/task-mcp.d.ts +22 -9
  306. package/dist/task-mcp.js +17 -9
  307. package/dist/terminal.d.ts +27 -0
  308. package/dist/terminal.js +6 -0
  309. package/dist/tool-approval.d.ts +6 -0
  310. package/dist/tool-approval.js +8 -1
  311. package/dist/trace/project.d.ts +1 -0
  312. package/dist/trace/project.js +1 -0
  313. package/dist/trace/redact.d.ts +3 -1
  314. package/dist/trace/redact.js +80 -28
  315. package/dist/trace/self-minted-wire.d.ts +169 -2
  316. package/dist/trace/self-minted-wire.js +54 -1
  317. package/dist/url-refusal.d.ts +1 -1
  318. package/dist/web-admin-client/apply-effective.d.ts +17 -3
  319. package/dist/web-admin-client/apply-effective.js +20 -10
  320. package/dist/web-admin-client/candidate-gate.d.ts +11 -7
  321. package/dist/web-admin-client/candidate-gate.js +1 -1
  322. package/dist/web-admin-client/http-client.d.ts +5 -4
  323. package/dist/web-admin-client/http-client.js +2 -2
  324. package/dist/web-admin-client/read-warnings.d.ts +7 -17
  325. package/dist/web-admin-client/read-warnings.js +5 -9
  326. package/dist/web-admin-client/skills-mcp.js +3 -2
  327. package/dist/web-admin-client/types.d.ts +6 -0
  328. package/package.json +3 -3
  329. package/wire-changes/server@7.139.0.json +348 -0
  330. package/wire-changes/server@7.140.0.json +184 -0
  331. package/dist/http/device-placement.d.ts +0 -175
  332. package/dist/http/device-placement.js +0 -145
@@ -1,3 +1,5 @@
1
+ import type { DeviceBindOutcome, DeviceRebindOutcome, InMemoryExecutionPlacementSeat } from "./execution-placement.js";
2
+ import type { SessionFace } from "./session-incarnation.js";
1
3
  /**
2
4
  * device lane 的 HTTP 错误码闭集(v2 §4.8 逐字)。**唯一导出点** —— 端点车(A-3/车C)从这里取,
3
5
  * 禁在路由里手抄字面量(§4.8 task-R1-12:「下表即闭集全集,禁四份手抄」)。
@@ -33,7 +35,7 @@ export declare const DEVICE_ERROR_CODES: {
33
35
  * (管理面,`http/routes/devices.ts`);adapter/准入链结构上不产它。 */
34
36
  readonly REBIND_REV_CONFLICT: "device.rebind_rev_conflict";
35
37
  /** O4 换绑动词(v2 稿 §2 步 4):该根会话名下有非终态 run(durable 判据 = run store 的 session
36
- * claim;hub 内存在途计数**不作门**——跨副本不可见)—— 体带 `activeTaskId`。铸造点同上一条。 */
38
+ * claim;hub 内存在途计数**不作门**——跨副本不可见;保证 = 设备店换绑事务内锁根行后那一读,池级读只作早拒)—— 体带 `activeTaskId`。铸造点同上一条。 */
37
39
  readonly REBIND_ACTIVE_RUN: "device.rebind_active_run";
38
40
  };
39
41
  /** {@link DEVICE_ERROR_CODES} 的值联合 —— 闭集(未知码 = 编译错误,[ref] 词表纪律)。 */
@@ -113,14 +115,6 @@ export interface DeviceRow {
113
115
  createdAtMs: number;
114
116
  rev: number;
115
117
  }
116
- export interface DeviceSessionRow {
117
- /** 键 = **根**会话(task-R1-3:后代继承不另绑)。 */
118
- rootSessionId: string;
119
- deviceId: string;
120
- owner: DeviceOwner;
121
- boundAtMs: number;
122
- rev: number;
123
- }
124
118
  export interface DeviceAuditRow {
125
119
  id: number;
126
120
  atMs: number;
@@ -147,7 +141,7 @@ export interface DeviceEnrollTokenRow {
147
141
  export declare const DEVICE_KEY_MAX_BYTES = 190;
148
142
  /** `device_id` 列宽(`dev_` + 26 位 Crockford base32 ULID = 30 字节,64 是三倍余量)。 */
149
143
  export declare const DEVICE_ID_MAX_BYTES = 64;
150
- /** `root_session_id` 列宽(提交入口硬拒 >64 的 sessionId,128 留一倍余量)。 */
144
+ /** 根会话 id 的形门上界(换绑路由的路径段;会话行 `session_id` 宽 64,提交入口硬拒 >64 的 sessionId,128 留一倍余量 —— 超宽的 id 等值读不到任何行)。 */
151
145
  export declare const DEVICE_SESSION_ID_MAX_BYTES = 128;
152
146
  /** `pubkey` / `token_hash` 列宽(Ed25519 b64 = 44,sha256 hex = 64)。 */
153
147
  export declare const DEVICE_PUBKEY_MAX_BYTES = 128;
@@ -176,10 +170,12 @@ export declare function assertDevicePubkeyShape(pubkey: string): void;
176
170
  export declare function assertNewDeviceShape(input: NewDeviceInput): void;
177
171
  export declare function assertIssueTokenShape(input: IssueEnrollTokenInput): void;
178
172
  export declare function assertRevokeShape(input: RevokeDeviceInput): void;
173
+ /** device 首绑入参的整形门(三形共用:内存参照实现与两方言从同一处过)。 */
174
+ export declare function assertPlaceDeviceShape(input: PlaceDeviceExecutionInput): void;
179
175
  /** O4 换绑入参的整形门(三形共用)。`expectedRev` 收窄为非负整数:它要进 SQL 等值谓词,小数/负数/NaN
180
176
  * 在两方言的 BIGINT 比对下不是「不匹配」而是各自的隐式转换歧义面 —— 在门口拒,方言分歧面消失。
181
177
  * ⚠️ HTTP 层对坏形先答 400(业务拒绝);这里的抛是**编程/装配错误**的兜底,不是 wire 分支。 */
182
- export declare function assertRebindShape(input: RebindSessionInput): void;
178
+ export declare function assertRebindShape(input: RebindDeviceExecutionInput): void;
183
179
  export declare function assertAcquireShape(input: AcquireConnectionInput): void;
184
180
  /** token 摘要必须是**规范形**(小写 sha256 hex):大小写混形在 VARBINARY/COLLATE "C" 下是两个键,
185
181
  * 于是同一个明文 token 能被消费两次 —— 这是 §7-T5 ③「一次性 CAS」的直接跳过面。 */
@@ -268,73 +264,53 @@ export type ConsumeEnrollTokenResult =
268
264
  | {
269
265
  outcome: "pubkey_taken";
270
266
  };
271
- export interface BindSessionInput {
272
- rootSessionId: string;
273
- deviceId: string;
274
- /** 验证过的复合身份;与 devices 行的 owner 在**同一事务**内比对(§4.3.2 首绑)。 */
275
- owner: DeviceOwner;
276
- }
277
- /** §4.3.2 首绑协议的判别式结果 —— 并发争抢**单赢家,无未定义态**。 */
278
- export type BindSessionResult = {
279
- outcome: "bound";
280
- row: DeviceSessionRow;
281
- }
282
- /** 并发输家或重试,但绑的是**同一台**设备 ⇒ 幂等成功。 */
283
- | {
284
- outcome: "idempotent";
285
- row: DeviceSessionRow;
286
- }
287
- /** 根会话已绑**另一台**设备(或另一个 owner)⇒ `device.claim_conflict`。 */
288
- | {
289
- outcome: "conflict";
290
- row: DeviceSessionRow;
267
+ /**
268
+ * device 车道的**首绑**(§4.3.2;认领之后的初始放置写,§3.3 转换表 place / bind 两行):根会话行上这一位住客的执行格
269
+ * absent → writer(device, D),或迁移回填的 writer(device, ∅) → writer(device, D)。绑定**住在会话行上**(唯一载体;
270
+ * 列与语句的属主 = `plugins/execution-placement-sql.ts`),本店只负责「设备行判 + 写格」同一事务(锁序:设备行 → 根 `session_meta`)。
271
+ */
272
+ export interface PlaceDeviceExecutionInput {
273
+ /** 根会话(放置键;后代继承,不另绑)。 */
274
+ readonly root: string;
275
+ /** 意图那一读的住客(会话店执行席 `seat.read(root)` 交出的那一位)—— 写按住客谓词定址:住客换了 ⇒ `gone`,永不写到新住客身上。 */
276
+ readonly occupant: SessionFace;
277
+ readonly deviceId: string;
278
+ /** 验证过的复合身份;与设备行的 owner 在**同一事务**内比对,写进格的两属主列(绑定属主 = 设备属主)。 */
279
+ readonly owner: DeviceOwner;
291
280
  }
292
- /** 设备不存在**或**不是请求方的 —— 反枚举同形(见文件头注)。 */
293
- | {
294
- outcome: "device_not_found";
281
+ /**
282
+ * 首绑的判别式结果 —— 并发争抢**单赢家,无未定义态**。格的那几臂与判官同一张表(`DeviceBindOutcome`:`bound` / 同设备 `same`(幂等成功)/
283
+ * 异设备 `device_conflict` / 异车道 `tree_bound` / `mirror` / 住客不是判过的那一位或行不在 `gone`),外加设备行的两臂:
284
+ * 设备不存在**或**不是请求方的(反枚举同形,见文件头注)/ 已吊销。
285
+ */
286
+ export type PlaceDeviceExecutionResult = DeviceBindOutcome | {
287
+ readonly outcome: "device_not_found";
295
288
  } | {
296
- outcome: "device_revoked";
289
+ readonly outcome: "device_revoked";
297
290
  };
298
291
  /**
299
- * O4 显式换绑(2026-08-30 v2 稿 §2)。`owner` = **绑定行的**复合身份(HTTP 层已裁决:属主同域或
300
- * explicit operator;operator 代操作时传的也是行的 owner,不是操作员自己)——店内所有谓词恒带它,
301
- * 判别位在店里就消失(反枚举,文件头注)。`expectedRev` = 壳从 S-4 读面拿到的前态(强制显式,
302
- * 防两操作员并发换绑互踩)。
292
+ * O4 显式换绑(2026-08-30 v2 稿 §2;§3.3 转换表 rebind 行)。`occupant` = 换绑门那一读的住客;`owner` = 门判过的**格上**两属主列
293
+ * (HTTP 层已裁决:属主同域或 explicit operator;operator 代操作时传的也是格上的 owner,不是操作员自己)——店内所有谓词恒带它,
294
+ * 判别位在店里就消失(反枚举,文件头注)。`expectedRev` = 壳从执行放置读面拿到的前态(强制显式,防两操作员并发换绑互踩)。
303
295
  */
304
- export interface RebindSessionInput {
305
- rootSessionId: string;
306
- toDeviceId: string;
307
- expectedRev: number;
308
- owner: DeviceOwner;
296
+ export interface RebindDeviceExecutionInput {
297
+ readonly root: string;
298
+ readonly occupant: SessionFace;
299
+ readonly owner: DeviceOwner;
300
+ readonly expectedRev: number;
301
+ readonly targetDeviceId: string;
309
302
  }
310
303
  /**
311
- * O4 换绑的判别式结果(门序 = v2 稿 §2:目标设备在场 → 幂等短路 → 前态 CAS → 审计;活跃 run 门在
312
- * **HTTP 层**、CAS 之前判 —— run store 是另一只店,CAS 语句不兼职)。
304
+ * O4 换绑的判别式结果(门序 = v2 稿 §2 + 读写序律:目标设备在场 → 锁根行读认领 → 幂等短路 → 前态 CAS → 审计)。格的那几臂与判官同一张表
305
+ * (`DeviceRebindOutcome`:`rebound` 带被换下的那台 / 真幂等 `idempotent` / 前态输 `rev_conflict` 携当前格 / `gone` = 行不在、住客换了、不是 writer(device, D)、
306
+ * 或绑定属主不是判过的那一位 —— 反枚举同形),外加:目标设备不在 / 不是该 owner 的 / **已吊销**(三臂同折 404;吊销不单列 = 判别位在店里就消失);
307
+ * 写事务内锁根行后读到认领 `active_run`(SQL 后端;读写序律只在 SQL 后端立 —— 内存参照实现没有认领表,答不出这一臂,内存走廊的认领判据是路由的早拒)。
313
308
  */
314
- export type RebindSessionResult =
315
- /** CAS 赢家:`rev+1` + `bound_at` 刷新 + `session_rebound` 审计行**同一事务**提交。 */
316
- {
317
- outcome: "rebound";
318
- row: DeviceSessionRow;
319
- }
320
- /** 真幂等:`toDeviceId` ≡ 当前绑定 ∧ `expectedRev` ≡ 当前 rev ⇒ 回显不加 rev、不写审计。 */
321
- | {
322
- outcome: "idempotent";
323
- row: DeviceSessionRow;
324
- }
325
- /** 前态输(rev 不符,含「toDeviceId 同但 rev 错」——前态错就是错)⇒ 携当前行供壳一跳重定位。 */
326
- | {
327
- outcome: "rev_conflict";
328
- row: DeviceSessionRow;
329
- }
330
- /** 绑定行不在**或**不是该 owner 的 —— 反枚举同形(HTTP 层折 404 同串)。 */
331
- | {
332
- outcome: "binding_not_found";
333
- }
334
- /** 目标设备不在 / 不是该 owner 的 / **已吊销** —— v2 稿 §2 步 2:三臂同折 404(设备 id 也是
335
- * 不可枚举面);吊销不单列 = 判别位在店里就消失,消费层想泄也泄不出来。 */
336
- | {
337
- outcome: "device_not_found";
309
+ export type RebindDeviceExecutionResult = DeviceRebindOutcome | {
310
+ readonly outcome: "device_not_found";
311
+ } | {
312
+ readonly outcome: "active_run";
313
+ readonly activeTaskId: string;
338
314
  };
339
315
  export interface RevokeDeviceInput {
340
316
  deviceId: string;
@@ -415,14 +391,10 @@ export interface DeviceStore {
415
391
  /** 世代谓词命中 = true;0 行 = 已失权。 */
416
392
  heartbeatConnection(input: HeartbeatConnectionInput): Promise<boolean>;
417
393
  releaseConnection(deviceId: string, generation: number): Promise<boolean>;
418
- bindSession(input: BindSessionInput): Promise<BindSessionResult>;
419
- /** O4 显式换绑(v2 稿 §2 步 2/3/5):目标设备门 + 前态 CAS + `session_rebound` 审计行同一事务。
420
- * 活跃 run 门**不在这里**(run store 是另一只店)—— 由 HTTP 层在调用前判(v2 稿 §2 步 4)。 */
421
- rebindSession(input: RebindSessionInput): Promise<RebindSessionResult>;
422
- getSessionBinding(rootSessionId: string): Promise<DeviceSessionRow | null>;
423
- /** purge coordinator 座(§6 注②:core 的会话删除是**逐 store 显式调用**,不是 DB 自动扫;
424
- * 只建表不接 purge = 删会话后绑定残留 ⇒ sessionId 重用致旧设备粘连/claim conflict/隐私残留)。 */
425
- deleteByRootSession(rootSessionId: string): Promise<number>;
394
+ /** 首绑(认领之后的初始放置写):设备行判(active ∧ 属主)+ 写格同一事务,按住客谓词定址。 */
395
+ placeDeviceExecution(input: PlaceDeviceExecutionInput): Promise<PlaceDeviceExecutionResult>;
396
+ /** O4 显式换绑(v2 稿 §2 步 2/3/5):目标设备门 + 写事务内锁根行读认领 + 前态 CAS + `session_rebound` 审计行同一事务。 */
397
+ rebindDeviceExecution(input: RebindDeviceExecutionInput): Promise<RebindDeviceExecutionResult>;
426
398
  appendAudit(input: AppendAuditInput): Promise<void>;
427
399
  listAudit(filter?: ListAuditFilter): Promise<DeviceAuditRow[]>;
428
400
  }
@@ -432,15 +404,19 @@ declare function cloneOwner(o: DeviceOwner): DeviceOwner;
432
404
  * 语义 oracle。**单线程 JS 的原子性**替代 SQL 事务:每个方法体内没有 `await`(除了返回值),所以
433
405
  * 「读-判-写」在事件循环上不可分割 —— 与 SQL 侧的单事务 CAS 语义等价,这也是为什么并发格
434
406
  * (两个并发消费同一 token)在这一形上必须给出与真库**同一个**赢家/输家分布。
407
+ *
408
+ * 绑定不在本店:它是会话行上的执行格。构造**必收**测试走廊的会话行 {@link InMemoryExecutionPlacementSeat}(同为参照实现,生产零引用)——
409
+ * 首绑 / 换绑在它上面做(判官与 SQL 语句模块同一组),读者经同一只席的 `read(root)` 读。
435
410
  */
436
411
  export declare class InMemoryDeviceStore implements DeviceStore {
437
412
  private readonly devices;
438
- private readonly sessions;
439
413
  private readonly tokens;
440
414
  private readonly audit;
441
415
  private auditSeq;
442
416
  private readonly now;
443
- constructor(opts?: {
417
+ private readonly seat;
418
+ constructor(opts: {
419
+ seat: InMemoryExecutionPlacementSeat;
444
420
  now?: () => number;
445
421
  });
446
422
  issueEnrollToken(input: IssueEnrollTokenInput): Promise<DeviceEnrollTokenRow>;
@@ -454,17 +430,14 @@ export declare class InMemoryDeviceStore implements DeviceStore {
454
430
  acquireConnection(input: AcquireConnectionInput): Promise<AcquireConnectionResult>;
455
431
  heartbeatConnection(input: HeartbeatConnectionInput): Promise<boolean>;
456
432
  releaseConnection(deviceId: string, generation: number): Promise<boolean>;
457
- bindSession(input: BindSessionInput): Promise<BindSessionResult>;
458
- rebindSession(input: RebindSessionInput): Promise<RebindSessionResult>;
459
- getSessionBinding(rootSessionId: string): Promise<DeviceSessionRow | null>;
460
- deleteByRootSession(rootSessionId: string): Promise<number>;
433
+ placeDeviceExecution(input: PlaceDeviceExecutionInput): Promise<PlaceDeviceExecutionResult>;
434
+ rebindDeviceExecution(input: RebindDeviceExecutionInput): Promise<RebindDeviceExecutionResult>;
461
435
  appendAudit(input: AppendAuditInput): Promise<void>;
462
436
  listAudit(filter?: ListAuditFilter): Promise<DeviceAuditRow[]>;
463
437
  private isOnline;
464
438
  private pushAudit;
465
439
  /** 返回**拷贝**:调用方拿到的行改了也不能污染店内状态(SQL 侧天然如此,InMemory 必须显式做)。 */
466
440
  private snapshotDevice;
467
- private snapshotSession;
468
441
  }
469
442
  export { sameOwner as sameDeviceOwner, cloneOwner as cloneDeviceOwner };
470
443
  //# sourceMappingURL=device-store.d.ts.map
@@ -123,9 +123,14 @@ export function assertRevokeShape(input) {
123
123
  assertBoundedText("revokedBy", input.revokedBy, DEVICE_TEXT_LIMITS.actor);
124
124
  assertBoundedText("revokeReason", input.reason ?? "", DEVICE_TEXT_LIMITS.revokeReason);
125
125
  }
126
+ export function assertPlaceDeviceShape(input) {
127
+ assertRootSessionIdShape(input.root);
128
+ assertDeviceIdShape(input.deviceId);
129
+ assertDeviceOwnerShape(input.owner);
130
+ }
126
131
  export function assertRebindShape(input) {
127
- assertRootSessionIdShape(input.rootSessionId);
128
- assertDeviceIdShape(input.toDeviceId);
132
+ assertRootSessionIdShape(input.root);
133
+ assertDeviceIdShape(input.targetDeviceId);
129
134
  assertDeviceOwnerShape(input.owner);
130
135
  if (!Number.isInteger(input.expectedRev) || input.expectedRev < 0) {
131
136
  throw new Error(`device-store: expectedRev must be a non-negative integer (got ${input.expectedRev}) — it enters a byte-exact BIGINT equality predicate`);
@@ -194,13 +199,14 @@ function cloneOwner(o) {
194
199
  }
195
200
  export class InMemoryDeviceStore {
196
201
  devices = new Map();
197
- sessions = new Map();
198
202
  tokens = new Map();
199
203
  audit = [];
200
204
  auditSeq = 0;
201
205
  now;
206
+ seat;
202
207
  constructor(opts) {
203
- this.now = opts?.now ?? (() => Date.now());
208
+ this.seat = opts.seat;
209
+ this.now = opts.now ?? (() => Date.now());
204
210
  }
205
211
  async issueEnrollToken(input) {
206
212
  assertIssueTokenShape(input);
@@ -361,57 +367,24 @@ export class InMemoryDeviceStore {
361
367
  row.rev += 1;
362
368
  return true;
363
369
  }
364
- async bindSession(input) {
365
- assertRootSessionIdShape(input.rootSessionId);
366
- assertDeviceIdShape(input.deviceId);
367
- assertDeviceOwnerShape(input.owner);
370
+ async placeDeviceExecution(input) {
371
+ assertPlaceDeviceShape(input);
368
372
  const device = this.devices.get(input.deviceId);
369
373
  if (!device || !sameOwner(device.owner, input.owner))
370
374
  return { outcome: "device_not_found" };
371
375
  if (device.status !== "active")
372
376
  return { outcome: "device_revoked" };
373
- const existing = this.sessions.get(input.rootSessionId);
374
- if (existing) {
375
- const same = existing.deviceId === input.deviceId && sameOwner(existing.owner, input.owner);
376
- return { outcome: same ? "idempotent" : "conflict", row: this.snapshotSession(existing) };
377
- }
378
- const row = {
379
- rootSessionId: input.rootSessionId,
380
- deviceId: input.deviceId,
381
- owner: cloneOwner(input.owner),
382
- boundAtMs: this.now(),
383
- rev: 0,
384
- };
385
- this.sessions.set(row.rootSessionId, row);
386
- return { outcome: "bound", row: this.snapshotSession(row) };
377
+ return this.seat.bindDevice(input.root, input.occupant, { id: input.deviceId, owner: cloneOwner(input.owner) }, new Date(this.now()).toISOString());
387
378
  }
388
- async rebindSession(input) {
379
+ async rebindDeviceExecution(input) {
389
380
  assertRebindShape(input);
390
- const device = this.devices.get(input.toDeviceId);
381
+ const device = this.devices.get(input.targetDeviceId);
391
382
  if (!device || !sameOwner(device.owner, input.owner) || device.status !== "active")
392
383
  return { outcome: "device_not_found" };
393
- const row = this.sessions.get(input.rootSessionId);
394
- if (!row || !sameOwner(row.owner, input.owner))
395
- return { outcome: "binding_not_found" };
396
- if (row.deviceId === input.toDeviceId && row.rev === input.expectedRev)
397
- return { outcome: "idempotent", row: this.snapshotSession(row) };
398
- if (row.rev !== input.expectedRev)
399
- return { outcome: "rev_conflict", row: this.snapshotSession(row) };
400
- const from = row.deviceId;
401
- row.deviceId = input.toDeviceId;
402
- row.boundAtMs = this.now();
403
- row.rev += 1;
404
- this.pushAudit({ event: "session_rebound", deviceId: input.toDeviceId, owner: row.owner, detail: { from, to: input.toDeviceId, rev: row.rev } });
405
- return { outcome: "rebound", row: this.snapshotSession(row) };
406
- }
407
- async getSessionBinding(rootSessionId) {
408
- assertRootSessionIdShape(rootSessionId);
409
- const row = this.sessions.get(rootSessionId);
410
- return row ? this.snapshotSession(row) : null;
411
- }
412
- async deleteByRootSession(rootSessionId) {
413
- assertRootSessionIdShape(rootSessionId);
414
- return this.sessions.delete(rootSessionId) ? 1 : 0;
384
+ const out = this.seat.rebindDevice(input.root, input.occupant, cloneOwner(input.owner), input.expectedRev, input.targetDeviceId, new Date(this.now()).toISOString());
385
+ if (out.outcome === "rebound")
386
+ this.pushAudit({ event: "session_rebound", deviceId: input.targetDeviceId, owner: input.owner, detail: { from: out.from, to: input.targetDeviceId, rev: out.device.rev } });
387
+ return out;
415
388
  }
416
389
  async appendAudit(input) {
417
390
  this.pushAudit(input);
@@ -440,9 +413,6 @@ export class InMemoryDeviceStore {
440
413
  snapshotDevice(row) {
441
414
  return { ...row, owner: cloneOwner(row.owner) };
442
415
  }
443
- snapshotSession(row) {
444
- return { ...row, owner: cloneOwner(row.owner) };
445
- }
446
416
  }
447
417
  export { sameOwner as sameDeviceOwner, cloneOwner as cloneDeviceOwner };
448
418
  //# sourceMappingURL=device-store.js.map
@@ -832,7 +832,8 @@ export function createDeviceWsHub(options) {
832
832
  return { kind: "rejected", reject: rejection(DEVICE_DRAINING_CODE, "this device hub is closed for shutdown — the instruction was never dispatched (safe to retry once the device reconnects on a replacement replica)", DRAIN_RETRY_AFTER_SEC) };
833
833
  if (draining)
834
834
  return drainingRejectResult();
835
- const admitted = await enrollment.admitSession({ rootSessionId: input.rootSessionId, requester: input.requester });
835
+ const placement = await enrollment.readPlacement(input.rootSessionId);
836
+ const admitted = await enrollment.admitSession({ rootSessionId: input.rootSessionId, placement, requester: input.requester });
836
837
  if (!admitted.ok)
837
838
  return { kind: "rejected", reject: admitted.reject };
838
839
  if (abortedNow())
@@ -10,12 +10,13 @@
10
10
  * 带外凭据(e2b / docker / k8s 车道本来就是多租户 fleet 的主形),与 LSP 那条「本机子进程」的形不同;多租户下起服说一句。
11
11
  * · `BAKE_ENV_ALLOW`([ref] 残余,7.103.0)由 **bake-runner 进程**读(构建宿主守护进程:没有主体、没有租户 ⇒ 没有姿态列,
12
12
  * 不进 {@link describeAllowlistPostures} 的姿态句)。它与服务侧四只旋钮同一只解析器、同一只「点名放行」谓词、同一条「原文按凭据类」律。
13
- * · `channel` = 这张名单**交给谁、在谁的减法之上**(闭集两词,解析器按它定「不许点哪些名」):
13
+ * · `channel` = 这张名单**交给谁、在谁的减法之上**(闭集两词)。它只定拒句里「交到哪里」那半句与出路的主语,**不定拒不拒**:「不许点哪些名」对五只一律
14
+ * = 名单型旋钮名 ∪ 本服务自有凭据名(引擎此刻的声明:起服解析时判一次,声明增长时由换代声明对活配置里每只服务侧名单此刻交出去的名重判一次;判官 = 引擎
15
+ * `inheritEnvPolicyProblem`,与引擎拒嵌入方白名单同句),规则全文在解析器头注 ②。
14
16
  * - `host-put-back`(`LSP_ENV_ALLOW` / `BAKE_ENV_ALLOW`)—— 剥后放回形:宿主子进程的 env 先经唯一组合(引擎扣掉本服务自有凭据 + 形状剥),
15
- * 名单点到的键再从本进程环境**原样**取回叠上去。点到本服务自有凭据名 = 把引擎刚扣下的那枚交回去 ⇒ 起服拒,判官 = 引擎同一只
16
- * (`inheritEnvPolicyProblem`,读起服声明;与引擎拒嵌入方白名单同句)。
17
+ * 名单点到的键再从本进程环境**原样**取回叠上去;点到本服务自有凭据名 = 把引擎刚扣下的那枚交回那只子进程。
17
18
  * - `sandbox-grant`(三只沙箱名单)—— 沙箱 env 的唯一来源(沙箱不从本进程继承任何东西),部署方显式交出的带外凭据([ref] 照转发);
18
- * 本列不在「自有凭据」律的射程里,只拒点名名单型旋钮(原文按凭据类)。
19
+ * 点到本服务自有凭据名 = 把它装进模型读得到的沙箱 env。沙箱要凭据 ⇒ 部署方给沙箱另铸一把(名与值都不同于本服务的任何凭据)。
19
20
  * 表是 `Record<旋钮, …>`:闭集加一只旋钮而不补行 = 编译红;行形随读它的进程定(服务进程 ⇒ 必须写姿态列)。
20
21
  *
21
22
  * 🔴 **姿态列只在这里写一次**([ref];7.101.0 合并复审 O9):凡要对人说「多租户下哪只旋钮忽略、哪只照转发」的句子,一律取
@@ -0,0 +1,60 @@
1
+ /**
2
+ * 一条**跑过**才被切的命令,执行错误怎么造、切断那一刻输出往哪去的**唯一一条律**(七只 adapter —— host〔管道 / spool 两形〕/ adb / e2b / ssh / k8s /
3
+ * local-docker / device —— 同读这一只):
4
+ *
5
+ * 命令已经起跑、之后被切 —— 墙钟(`timeout`)、静默界(`liveness_no_output`)、调用方中止(`aborted`)、宿主侧输出回调失败(`callback_error`)—— 它在被切之前
6
+ * 写出的 stdout / stderr 是真实的工作成果,必须原样带在 `ExecutionError.partialStdout` / `partialStderr` 上(core 合同:参考行为是超时保留**全部**已捕获的输出,
7
+ * 只追加一句「超时了」;丢掉 600 s 的构建日志会逼模型盲重跑)。引擎只从这两个字段读输出拼工具结果,从 `message` 读不到 ——
8
+ * 缺席就报「(no output was produced before the cutoff)」,模型对着一个其实已写了进度的命令说「什么也没产出」。
9
+ *
10
+ * **切断即落定**:切断时本层手里还没交出的输出(远端 shell 腿 cwd 过滤器压着的 stderr 尾巴、host spool 还没泵的字节)只**记账**(尾窗 / detach tee),
11
+ * 随错误交回,不经调用方的输出回调**外发**。**落定先于构造,构造只记账**:构造结局会做事的腿(ssh / adb / k8s / host spool —— 冲刷压着的尾巴、泵 spool、
12
+ * 杀进程)的 `finish` 收一只构造结局的函数,先置落定,再构造、收尾、解决 —— 构造期间不调调用方的代码,重入的 detach / abort / close 读到的都是「已落定」。
13
+ * 正常结束同一顺序:压着的尾巴先记账、解决,**之后**才交给回调(那是流本身的结尾,不是切断)—— 回调里发生什么(重入、抛错)都改不了、也挂不住结局。
14
+ * 构造只读尾窗 / SDK 句柄字段的腿(host 管道 / local-docker / e2b)造错误即读,没有可重入的东西;device 的错误在投递结算之后才造。
15
+ *
16
+ * 与 `exec-bounds.ts` 的分工:那一只定「什么界在何时切、切断报哪个码、哪句话、几秒」(`buildLivenessCut` 等);这一只定「切断的错误带什么」。静默切断的
17
+ * 数据(`buildLivenessCut` 的返回)直接就是这里的 {@link ExecCut};墙钟与中止切断各 adapter 自己说句子(它们的成因词各车道不同),错误一律经 {@link createCutError} 造;
18
+ * 码是数据的腿(device:码由对端说,经映射表落到本侧)经 {@link createExecFailure} 按同一判别造。
19
+ *
20
+ * 输出的口径 = 同一条命令正常收口时 `exec` 会交出的那一份,切断不另设一道界、不二次切片:自带有界滚动尾窗(`RollingTailBuffer`)的腿读尾窗的当前文本,被丢掉的字节照旧附
21
+ * `markTruncated` 的记号({@link buildCapturedOutput});收口交出的是 SDK 整串的腿(e2b)读 SDK 句柄自己的记录;device 读它自己收齐的两路串。远端 shell 腿(ssh / adb / k8s)
22
+ * 的 stderr 在读之前先把 cwd 过滤器压着的尾巴记进账,与正常收口同一步。`message` 只陈述事实(哪一界、多少毫秒),不再夹输出。
23
+ *
24
+ * 不在本律里:命令**没起跑**就失败的码(`spawn_error` / `shell_unavailable` / 起跑前的 `aborted` / device 投递门之前的拒)按定义没有输出;结果未知
25
+ * (`transport_lost` / `outcome_unknown`)与未分类(`unknown`)的码引擎不读它的 partial —— 判别只有 {@link isRanThenCutCode} 一处。
26
+ */
27
+ import { ExecutionError, type ExecutionErrorCode, type RollingTailBuffer } from "@sema-agent/core";
28
+ /** 命令已起跑、随后被切的四个码(core `ExecutionError` 注:`partialStdout` / `partialStderr` 为这四个码而设)。 */
29
+ export type RanThenCutCode = Extract<ExecutionErrorCode, "timeout" | "liveness_no_output" | "aborted" | "callback_error">;
30
+ /**
31
+ * 一次切断的数据:码 + 句。`noOutputSec` 只属静默切断(静默窗口的整秒数,core `ExecutionError` 第五构造参)—— 与 `exec-bounds.ts` 的
32
+ * `buildLivenessCut` 返回值同形,可直接传入。
33
+ */
34
+ export type ExecCut = {
35
+ readonly code: Exclude<RanThenCutCode, "liveness_no_output">;
36
+ readonly message: string;
37
+ } | {
38
+ readonly code: "liveness_no_output";
39
+ readonly message: string;
40
+ readonly noOutputSec?: number;
41
+ };
42
+ /** 切断那一刻命令已写出的输出(纯数据;两路都是字符串,没写 = 空串)。 */
43
+ export interface CapturedOutput {
44
+ readonly stdout: string;
45
+ readonly stderr: string;
46
+ }
47
+ /**
48
+ * 切断那一刻两路滚动尾窗里的内容 = 该命令正常收口时 `exec` 交出的那一份(滚出窗外的字节照旧附 {@link markTruncated} 的记号)。
49
+ * `stdout` 缺席 = 这一次往返把 stdout 整份留作**数据载荷**(字节精确的文件读取:adb / local-docker 的 `binary`、k8s 的非 `boundOutput`)—— 载荷不是
50
+ * 命令输出,被切的数据读取没有「已写出的输出」可交给读者,stdout 记空串;stderr 恒是命令输出。
51
+ */
52
+ export declare function buildCapturedOutput(stdout: RollingTailBuffer | undefined, stderr: RollingTailBuffer): CapturedOutput;
53
+ /** 一条起跑后被切的命令的执行错误 —— 唯一造法(见文件头注):码 / 句取自 `cut`,输出取自 `captured`(逐字,不截)。 */
54
+ export declare function createCutError(cut: ExecCut, captured: CapturedOutput): ExecutionError;
55
+ /**
56
+ * 码是**数据**时的执行错误(device:对端说的词经映射表落到本侧,这一刻才知道是哪个码)—— 同一条律:命令起跑过(`ran` = 它已写出的输出)且码是起跑后被切的
57
+ * 四个之一 ⇒ 经 {@link createCutError} 带输出;其余(没起跑 = `ran` 缺席 / 结果未知 / 未分类)按律不带。码在调用处就是字面量的腿直接用 {@link createCutError}。
58
+ */
59
+ export declare function createExecFailure(code: ExecutionErrorCode, message: string, ran?: CapturedOutput): ExecutionError;
60
+ //# sourceMappingURL=exec-cut.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { ExecutionError, markTruncated } from "@sema-agent/core";
2
+ function isRanThenCutCode(code) {
3
+ switch (code) {
4
+ case "timeout":
5
+ case "liveness_no_output":
6
+ case "aborted":
7
+ case "callback_error":
8
+ return true;
9
+ case "shell_unavailable":
10
+ case "spawn_error":
11
+ case "transport_lost":
12
+ case "suspended":
13
+ case "auth_failed":
14
+ case "outcome_unknown":
15
+ case "target_unavailable":
16
+ case "unknown":
17
+ return false;
18
+ }
19
+ }
20
+ export function buildCapturedOutput(stdout, stderr) {
21
+ const err = stderr.result();
22
+ const out = stdout?.result();
23
+ return {
24
+ stdout: out === undefined ? "" : markTruncated(out.text, out.droppedBytes),
25
+ stderr: markTruncated(err.text, err.droppedBytes),
26
+ };
27
+ }
28
+ export function createCutError(cut, captured) {
29
+ return new ExecutionError(cut.code, cut.message, undefined, { stdout: captured.stdout, stderr: captured.stderr }, cut.code === "liveness_no_output" ? cut.noOutputSec : undefined);
30
+ }
31
+ export function createExecFailure(code, message, ran) {
32
+ if (ran !== undefined && isRanThenCutCode(code))
33
+ return createCutError({ code, message }, ran);
34
+ return new ExecutionError(code, message);
35
+ }
36
+ //# sourceMappingURL=exec-cut.js.map