@sema-agent/server 7.146.0 → 7.147.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 (398) hide show
  1. package/MIGRATION.md +384 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/USAGE.md +170 -66
  5. package/deploy/facts/lanes.json +7 -0
  6. package/deploy/sema-up/README.md +2 -2
  7. package/deploy/sema-up/chart/templates/_helpers.tpl +22 -0
  8. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -4
  9. package/deploy/sema-up/chart/templates/server.yaml +5 -4
  10. package/deploy/sema-up/chart/values.yaml +1 -1
  11. package/deploy/sema-up/cluster-up.sh +2 -1
  12. package/deploy/sema-up/lib/flagshape.sh +4 -0
  13. package/deploy/sema-up/lib/lanes.json +2 -5
  14. package/deploy/sema-up/sema-up.sh +12 -9
  15. package/deploy/sema-up/stack/compose.yaml +5 -4
  16. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -3
  17. package/dist/approval-card.d.ts +4 -4
  18. package/dist/approval.d.ts +3 -3
  19. package/dist/audit.js +2 -2
  20. package/dist/bench/s1/live-deps.js +3 -1
  21. package/dist/boot/crash-last.js +2 -1
  22. package/dist/boot/device-lane.js +5 -5
  23. package/dist/boot/engine-lease.d.ts +12 -11
  24. package/dist/boot/execution-env.d.ts +2 -1
  25. package/dist/boot/execution-env.js +45 -33
  26. package/dist/boot/execution-lane.d.ts +37 -9
  27. package/dist/boot/execution-lane.js +74 -20
  28. package/dist/boot/exit-boundary.d.ts +1 -1
  29. package/dist/boot/exit-last.js +2 -1
  30. package/dist/boot/governance-seams.d.ts +2 -2
  31. package/dist/boot/leader.js +1 -1
  32. package/dist/boot/memory-boundary.d.ts +11 -11
  33. package/dist/boot/memory-boundary.js +3 -3
  34. package/dist/boot/memory-consolidation.d.ts +13 -24
  35. package/dist/boot/memory-consolidation.js +0 -13
  36. package/dist/boot/org-memory.js +3 -2
  37. package/dist/boot/parked-revive-gate.d.ts +1 -1
  38. package/dist/boot/parked-revive-gate.js +1 -1
  39. package/dist/boot/reapers.js +1 -1
  40. package/dist/boot/resolve-spec.js +91 -111
  41. package/dist/boot/retention-lane.d.ts +4 -42
  42. package/dist/boot/session-faces.d.ts +1 -0
  43. package/dist/boot/session-faces.js +8 -2
  44. package/dist/boot/stage-01-config.d.ts +1 -1
  45. package/dist/boot/stage-01-config.js +6 -2
  46. package/dist/boot/stage-02-web-admin-pull.d.ts +1 -1
  47. package/dist/boot/stage-02-web-admin-pull.js +10 -8
  48. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  49. package/dist/boot/stage-04-stores.d.ts +1 -1
  50. package/dist/boot/stage-05-execution-env.d.ts +2 -2
  51. package/dist/boot/stage-05-execution-env.js +3 -3
  52. package/dist/boot/stage-06-runners.d.ts +3 -3
  53. package/dist/boot/stage-06-runners.js +1 -3
  54. package/dist/boot/stage-07-capability-layer.d.ts +3 -3
  55. package/dist/boot/stage-07-capability-layer.js +4 -9
  56. package/dist/boot/stage-08-reapers.d.ts +3 -3
  57. package/dist/boot/stage-09-leader.d.ts +4 -3
  58. package/dist/boot/stage-10-http-server.d.ts +4 -3
  59. package/dist/boot/stage-10-http-server.js +2 -1
  60. package/dist/boot/stores.d.ts +9 -0
  61. package/dist/boot/stores.js +18 -7
  62. package/dist/boot/web-admin.js +3 -3
  63. package/dist/capabilities/center-plugins.d.ts +2 -0
  64. package/dist/capabilities/center-plugins.js +6 -2
  65. package/dist/capabilities/composite-members.d.ts +1 -0
  66. package/dist/capabilities/composite-members.js +1 -0
  67. package/dist/capabilities/execution-lane.d.ts +7 -7
  68. package/dist/capabilities/execution-lane.js +2 -2
  69. package/dist/capabilities/hands-lane.d.ts +1 -1
  70. package/dist/capabilities/scenarios.d.ts +32 -18
  71. package/dist/capabilities/scenarios.js +13 -9
  72. package/dist/capabilities/settings-contract.d.ts +29 -0
  73. package/dist/capabilities/settings-contract.js +14 -0
  74. package/dist/capabilities/skills.d.ts +5 -5
  75. package/dist/capability-facts.d.ts +38 -0
  76. package/dist/capability-facts.js +34 -1
  77. package/dist/center-credential-renewer.js +3 -2
  78. package/dist/config-catalog.js +6 -5
  79. package/dist/config-invariants.d.ts +18 -3
  80. package/dist/config-invariants.js +36 -19
  81. package/dist/config-lkg.d.ts +1 -1
  82. package/dist/config-lkg.js +5 -6
  83. package/dist/config-provider.js +2 -0
  84. package/dist/config-types.d.ts +190 -186
  85. package/dist/config.d.ts +68 -5
  86. package/dist/config.js +80 -54
  87. package/dist/degenerate-instrument.js +1 -1
  88. package/dist/deploy-facts.js +3 -2
  89. package/dist/deployment-shape.d.ts +21 -12
  90. package/dist/deployment-shape.js +24 -6
  91. package/dist/env-facts.d.ts +7 -5
  92. package/dist/env-facts.js +10 -6
  93. package/dist/execution-config-root.d.ts +5 -5
  94. package/dist/execution-config-root.js +5 -5
  95. package/dist/execution-env-purpose.d.ts +14 -0
  96. package/dist/execution-env-purpose.js +29 -0
  97. package/dist/execution-lane-caps.d.ts +49 -86
  98. package/dist/execution-lane-caps.js +52 -62
  99. package/dist/execution-placement.d.ts +18 -2
  100. package/dist/execution-placement.js +19 -0
  101. package/dist/file-history-disclosure.d.ts +2 -2
  102. package/dist/fleet/drain-entry.d.ts +17 -10
  103. package/dist/fleet/drain-entry.js +1 -1
  104. package/dist/fleet/serving-lease.js +3 -4
  105. package/dist/history-anchor.d.ts +22 -0
  106. package/dist/history-anchor.js +14 -0
  107. package/dist/hooks/command-spawn.d.ts +1 -4
  108. package/dist/hooks/command-spawn.js +0 -11
  109. package/dist/hooks/hook-runner.d.ts +52 -8
  110. package/dist/hooks/hook-runner.js +160 -36
  111. package/dist/http/approval-sweeps.d.ts +2 -5
  112. package/dist/http/approval-sweeps.js +3 -2
  113. package/dist/http/checkpoint-ctx.d.ts +17 -0
  114. package/dist/http/checkpoint-ctx.js +6 -0
  115. package/dist/http/claim-latency.d.ts +10 -0
  116. package/dist/http/claim-latency.js +12 -0
  117. package/dist/http/dispatch.js +1 -1
  118. package/dist/http/durable-run-leg.js +2 -1
  119. package/dist/http/execution-context.d.ts +3 -1
  120. package/dist/http/execution-context.js +4 -0
  121. package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
  122. package/dist/http/memory-compliance-failure-reply.js +3 -0
  123. package/dist/http/memory-store-refusal-reply.d.ts +3 -3
  124. package/dist/http/memory-store-refusal-reply.js +3 -0
  125. package/dist/http/owner-access.d.ts +11 -0
  126. package/dist/http/owner-access.js +7 -4
  127. package/dist/http/principal-gate.d.ts +3 -14
  128. package/dist/http/principal-gate.js +0 -13
  129. package/dist/http/request-guards.d.ts +1 -1
  130. package/dist/http/resume-legs.d.ts +7 -10
  131. package/dist/http/resume-legs.js +79 -50
  132. package/dist/http/rewind-files-reply.d.ts +34 -0
  133. package/dist/http/rewind-files-reply.js +36 -0
  134. package/dist/http/route-ctx.d.ts +32 -16
  135. package/dist/http/route-table.js +2 -0
  136. package/dist/http/routes/approvals-assistant.js +5 -25
  137. package/dist/http/routes/capabilities.js +8 -2
  138. package/dist/http/routes/devices.js +1 -1
  139. package/dist/http/routes/memory-origin.d.ts +1 -1
  140. package/dist/http/routes/notify-wake.js +2 -1
  141. package/dist/http/routes/projects.d.ts +70 -0
  142. package/dist/http/routes/projects.js +86 -0
  143. package/dist/http/routes/rules.js +30 -2
  144. package/dist/http/routes/runs.js +8 -8
  145. package/dist/http/routes/session-sync.js +27 -10
  146. package/dist/http/routes/sessions.d.ts +7 -1
  147. package/dist/http/routes/sessions.js +104 -2
  148. package/dist/http/routes/tasks.js +9 -3
  149. package/dist/http/server.d.ts +24 -10
  150. package/dist/http/server.js +17 -6
  151. package/dist/http/stored-body-replay.d.ts +5 -3
  152. package/dist/http/stored-body-replay.js +10 -1
  153. package/dist/http/wire-types.d.ts +19 -10
  154. package/dist/index.d.ts +2 -2
  155. package/dist/index.js +1 -1
  156. package/dist/instruction-source-notice.d.ts +1 -1
  157. package/dist/memory-embedder-reembed.d.ts +38 -0
  158. package/dist/memory-embedder-reembed.js +20 -0
  159. package/dist/memory-incident-sink.d.ts +0 -28
  160. package/dist/memory-incident-sink.js +5 -0
  161. package/dist/memory-scope.d.ts +2 -2
  162. package/dist/memory-scope.js +1 -1
  163. package/dist/memory-store-refusal.d.ts +17 -4
  164. package/dist/memory-store-refusal.js +1 -1
  165. package/dist/memory-sync-client.d.ts +2 -0
  166. package/dist/memory-sync-client.js +13 -11
  167. package/dist/memory-sync.js +1 -1
  168. package/dist/model-compat.d.ts +35 -21
  169. package/dist/model-compat.js +49 -21
  170. package/dist/model-entry-refusal.d.ts +11 -1
  171. package/dist/model-entry-refusal.js +7 -0
  172. package/dist/namespaced-rule-name.d.ts +18 -1
  173. package/dist/namespaced-rule-name.js +12 -0
  174. package/dist/observability/fail-open.d.ts +17 -9
  175. package/dist/observability/fail-open.js +17 -9
  176. package/dist/observability/metrics.d.ts +2 -0
  177. package/dist/observability/metrics.js +2 -0
  178. package/dist/observability/secret-env-scrub.d.ts +30 -4
  179. package/dist/observability/secret-env-scrub.js +15 -3
  180. package/dist/orchestration/workflow-agent-session-index.d.ts +7 -12
  181. package/dist/orchestration/workflow-agent-session-index.js +1 -6
  182. package/dist/orchestration/workflow-completion-inbox.d.ts +26 -6
  183. package/dist/orchestration/workflow-completion-inbox.js +63 -45
  184. package/dist/org-memory-admission.d.ts +5 -2
  185. package/dist/org-memory-admission.js +25 -10
  186. package/dist/parked-decide.d.ts +33 -26
  187. package/dist/parked-decide.js +36 -44
  188. package/dist/plugins/approval-ask-store-file.d.ts +10 -2
  189. package/dist/plugins/approval-ask-store-file.js +37 -4
  190. package/dist/plugins/approval-ask-store-memory.d.ts +5 -3
  191. package/dist/plugins/approval-ask-store-memory.js +11 -2
  192. package/dist/plugins/approval-ask-store-sql.d.ts +3 -0
  193. package/dist/plugins/approval-ask-store-sql.js +3 -1
  194. package/dist/plugins/blob-backend.d.ts +38 -195
  195. package/dist/plugins/blob-backend.js +33 -229
  196. package/dist/plugins/caching-session-store.d.ts +9 -4
  197. package/dist/plugins/checkpoint-index-columns.d.ts +1 -1
  198. package/dist/plugins/checkpoint-index-columns.js +3 -2
  199. package/dist/plugins/checkpoint-store-face.d.ts +1 -1
  200. package/dist/plugins/device-store-sql.d.ts +2 -2
  201. package/dist/plugins/device-store-sql.js +5 -10
  202. package/dist/plugins/execution-lane-rename-m40.d.ts +20 -0
  203. package/dist/plugins/execution-lane-rename-m40.js +10 -0
  204. package/dist/plugins/execution-placement-sql.d.ts +63 -88
  205. package/dist/plugins/execution-placement-sql.js +94 -54
  206. package/dist/plugins/file-run-store.d.ts +26 -12
  207. package/dist/plugins/file-run-store.js +63 -63
  208. package/dist/plugins/imported-layer-root-retirement.d.ts +17 -8
  209. package/dist/plugins/imported-layer-root-retirement.js +4 -8
  210. package/dist/plugins/inbox-payload-column.d.ts +14 -0
  211. package/dist/plugins/inbox-payload-column.js +13 -0
  212. package/dist/plugins/local-checkpoint-store.d.ts +5 -0
  213. package/dist/plugins/local-checkpoint-store.js +11 -7
  214. package/dist/plugins/local-data-dir-modes-m39.d.ts +48 -0
  215. package/dist/plugins/local-data-dir-modes-m39.js +182 -0
  216. package/dist/plugins/local-engine-high-water.d.ts +11 -0
  217. package/dist/plugins/local-engine-high-water.js +59 -0
  218. package/dist/plugins/local-session-store.d.ts +91 -25
  219. package/dist/plugins/local-session-store.js +124 -45
  220. package/dist/plugins/local-task-attachment-store.d.ts +2 -0
  221. package/dist/plugins/local-task-attachment-store.js +10 -11
  222. package/dist/plugins/memory-embedder-fingerprint.d.ts +33 -10
  223. package/dist/plugins/memory-embedder-fingerprint.js +52 -12
  224. package/dist/plugins/memory-embedder.d.ts +1 -1
  225. package/dist/plugins/memory-embedder.js +2 -2
  226. package/dist/plugins/memory-engine-pg.d.ts +4 -3
  227. package/dist/plugins/memory-engine-pg.js +4 -4
  228. package/dist/plugins/memory-engine-sql-apply.d.ts +13 -4
  229. package/dist/plugins/memory-engine-sql-apply.js +1 -1
  230. package/dist/plugins/memory-engine-tidb.d.ts +8 -5
  231. package/dist/plugins/memory-engine-tidb.js +7 -8
  232. package/dist/plugins/one-time-migrations.d.ts +145 -35
  233. package/dist/plugins/one-time-migrations.js +272 -120
  234. package/dist/plugins/owner-only-file-mode.d.ts +29 -0
  235. package/dist/plugins/owner-only-file-mode.js +141 -0
  236. package/dist/plugins/permission-rule-store-file.d.ts +8 -8
  237. package/dist/plugins/permission-rule-store-file.js +14 -2
  238. package/dist/plugins/pg-pool.d.ts +2 -1
  239. package/dist/plugins/pg-pool.js +11 -4
  240. package/dist/plugins/release-version.d.ts +20 -0
  241. package/dist/plugins/release-version.js +28 -0
  242. package/dist/plugins/remote-env-adb.d.ts +20 -4
  243. package/dist/plugins/remote-env-adb.js +39 -11
  244. package/dist/plugins/remote-env-e2b.d.ts +12 -3
  245. package/dist/plugins/remote-env-e2b.js +6 -4
  246. package/dist/plugins/remote-env-host.d.ts +9 -1
  247. package/dist/plugins/remote-env-host.js +6 -5
  248. package/dist/plugins/remote-env-k8s.d.ts +5 -2
  249. package/dist/plugins/remote-env-k8s.js +15 -4
  250. package/dist/plugins/remote-env-local-docker.d.ts +4 -1
  251. package/dist/plugins/remote-env-local-docker.js +3 -3
  252. package/dist/plugins/remote-env-ssh.d.ts +8 -2
  253. package/dist/plugins/remote-env-ssh.js +26 -24
  254. package/dist/plugins/remote-shell.d.ts +59 -30
  255. package/dist/plugins/remote-shell.js +175 -62
  256. package/dist/plugins/retention-declaration.d.ts +37 -0
  257. package/dist/plugins/retention-declaration.js +9 -0
  258. package/dist/plugins/retention-deployment.d.ts +126 -0
  259. package/dist/plugins/retention-deployment.js +88 -0
  260. package/dist/plugins/retention-lane-store-sql.d.ts +74 -4
  261. package/dist/plugins/retention-lane-store-sql.js +103 -1
  262. package/dist/plugins/retention-sql.d.ts +29 -0
  263. package/dist/plugins/retention-sql.js +8 -0
  264. package/dist/plugins/schema-consistency.d.ts +0 -6
  265. package/dist/plugins/schema-consistency.js +1 -2
  266. package/dist/plugins/schema-ensure-legs.d.ts +1 -1
  267. package/dist/plugins/schema-ensure-legs.js +11 -1
  268. package/dist/plugins/session-ext-table.d.ts +74 -0
  269. package/dist/plugins/session-ext-table.js +121 -0
  270. package/dist/plugins/session-fork.d.ts +1 -1
  271. package/dist/plugins/session-row-sql.d.ts +8 -7
  272. package/dist/plugins/session-row-sql.js +15 -7
  273. package/dist/plugins/session-store-sql.d.ts +131 -0
  274. package/dist/plugins/session-store-sql.js +298 -0
  275. package/dist/plugins/session-workspace-cell.d.ts +2 -2
  276. package/dist/plugins/session-workspace-cell.js +2 -2
  277. package/dist/plugins/shared-memory-store-sql.d.ts +10 -0
  278. package/dist/plugins/shared-memory-store-sql.js +13 -13
  279. package/dist/plugins/snapshot-bucket-presence.js +1 -1
  280. package/dist/plugins/sql-driver.d.ts +23 -7
  281. package/dist/plugins/sql-driver.js +41 -8
  282. package/dist/plugins/sql-errors.d.ts +5 -2
  283. package/dist/plugins/sql-errors.js +4 -0
  284. package/dist/plugins/store-backend.d.ts +35 -8
  285. package/dist/plugins/store-backend.js +184 -62
  286. package/dist/plugins/store-contracts.d.ts +9 -2
  287. package/dist/plugins/store-contracts.js +1 -0
  288. package/dist/plugins/task-attachment-store.d.ts +6 -8
  289. package/dist/plugins/task-attachment-store.js +15 -10
  290. package/dist/plugins/task-list-store-sql.d.ts +1 -1
  291. package/dist/plugins/text-column-capacity.d.ts +21 -0
  292. package/dist/plugins/text-column-capacity.js +5 -0
  293. package/dist/plugins/tidb-pool.d.ts +3 -2
  294. package/dist/plugins/tidb-pool.js +19 -31
  295. package/dist/plugins/user-input-ledger-sql.d.ts +1 -1
  296. package/dist/read-face-posture.d.ts +6 -6
  297. package/dist/read-face-posture.js +2 -2
  298. package/dist/request-value-closure.d.ts +5 -5
  299. package/dist/request-value-closure.js +1 -1
  300. package/dist/rules-consent.d.ts +41 -13
  301. package/dist/rules-consent.js +101 -53
  302. package/dist/run-local.js +17 -13
  303. package/dist/runs.d.ts +48 -30
  304. package/dist/runs.js +26 -16
  305. package/dist/runtime-caps-resolver.d.ts +15 -8
  306. package/dist/runtime-caps-resolver.js +14 -10
  307. package/dist/sealed-key-layout.d.ts +2 -3
  308. package/dist/sealed-key-layout.js +0 -1
  309. package/dist/sealed-key.js +7 -5
  310. package/dist/security.d.ts +5 -3
  311. package/dist/sema-config-dir.js +2 -2
  312. package/dist/server-secret-env.d.ts +2 -0
  313. package/dist/service-version.d.ts +2 -1
  314. package/dist/service-version.js +2 -2
  315. package/dist/session-error-wire.d.ts +1 -1
  316. package/dist/session-incarnation.d.ts +8 -5
  317. package/dist/session-resident-background.d.ts +85 -32
  318. package/dist/session-resident-background.js +75 -7
  319. package/dist/session-row.d.ts +1 -1
  320. package/dist/session-sync-kernel.d.ts +1 -1
  321. package/dist/session-workspace.d.ts +11 -2
  322. package/dist/session-workspace.js +5 -0
  323. package/dist/sighup-idle.d.ts +1 -1
  324. package/dist/store-posture.d.ts +2 -1
  325. package/dist/stored-request-hooks-m20.d.ts +3 -2
  326. package/dist/stored-request-hooks-m20.js +19 -14
  327. package/dist/stores-sql/blob-index-sql.d.ts +148 -0
  328. package/dist/stores-sql/blob-index-sql.js +154 -0
  329. package/dist/stores-sql/checkpoint-store-sql.d.ts +1 -1
  330. package/dist/stores-sql/checkpoint-store-sql.js +11 -27
  331. package/dist/{plugins → stores-sql}/file-history-store-sql.d.ts +23 -11
  332. package/dist/{plugins → stores-sql}/file-history-store-sql.js +23 -18
  333. package/dist/{plugins → stores-sql}/pg-session-storage.d.ts +23 -76
  334. package/dist/{plugins → stores-sql}/pg-session-storage.js +80 -209
  335. package/dist/{plugins → stores-sql}/retention-store-sql.d.ts +123 -217
  336. package/dist/{plugins → stores-sql}/retention-store-sql.js +66 -190
  337. package/dist/{plugins → stores-sql}/session-event-payload.d.ts +1 -1
  338. package/dist/{plugins → stores-sql}/session-event-payload.js +1 -1
  339. package/dist/stores-sql/session-policy-store-sql.d.ts +1 -1
  340. package/dist/stores-sql/session-write-hooks.d.ts +59 -0
  341. package/dist/stores-sql/session-write-hooks.js +2 -0
  342. package/dist/{plugins → stores-sql}/tidb-session-storage.d.ts +10 -11
  343. package/dist/{plugins → stores-sql}/tidb-session-storage.js +10 -21
  344. package/dist/{plugins → stores-sql}/tidb-session-store.d.ts +32 -122
  345. package/dist/{plugins → stores-sql}/tidb-session-store.js +71 -171
  346. package/dist/stores-sql/tool-result-store-sql.d.ts +1 -1
  347. package/dist/stores-sql/tool-result-store-sql.js +1 -1
  348. package/dist/stores-sql/windowed-session-storage.d.ts +56 -0
  349. package/dist/stores-sql/windowed-session-storage.js +61 -0
  350. package/dist/task-a2a.d.ts +7 -1
  351. package/dist/task-a2a.js +15 -14
  352. package/dist/task-cwd.d.ts +11 -3
  353. package/dist/task-cwd.js +17 -1
  354. package/dist/task-mcp.d.ts +10 -2
  355. package/dist/task-mcp.js +13 -16
  356. package/dist/task-settings.d.ts +9 -4
  357. package/dist/task-settings.js +17 -6
  358. package/dist/tool-approval.d.ts +21 -8
  359. package/dist/tool-approval.js +10 -6
  360. package/dist/trace/core-keyset-guard.d.ts +9 -3
  361. package/dist/trace/engine-notice-wire.d.ts +1 -1
  362. package/dist/trace/engine-notice-wire.js +2 -0
  363. package/dist/trace/exit-seat.d.ts +23 -1
  364. package/dist/trace/exit-seat.js +3 -0
  365. package/dist/trace/project.d.ts +33 -16
  366. package/dist/trace/project.js +12 -9
  367. package/dist/trace/redact.d.ts +1 -1
  368. package/dist/trace/redact.js +61 -73
  369. package/dist/trace/self-minted-wire.d.ts +263 -10
  370. package/dist/trace/self-minted-wire.js +90 -2
  371. package/dist/trace/sema-provenance.d.ts +45 -41
  372. package/dist/trace/sema-provenance.js +81 -10
  373. package/dist/trace/task-notification-facets.d.ts +70 -2
  374. package/dist/trace/task-notification-facets.js +71 -1
  375. package/dist/trace/wire-projection-faces.d.ts +38 -2
  376. package/dist/trace/wire-projection-faces.js +26 -1
  377. package/dist/unread-request-members.d.ts +66 -0
  378. package/dist/unread-request-members.js +41 -0
  379. package/dist/user-input-ledger.d.ts +2 -2
  380. package/dist/web-admin-client/apply-effective.js +22 -26
  381. package/dist/web-admin-client/candidate-gate.d.ts +35 -3
  382. package/dist/web-admin-client/candidate-gate.js +53 -5
  383. package/dist/web-admin-client/center-request.d.ts +4 -1
  384. package/dist/web-admin-client/center-request.js +2 -1
  385. package/dist/web-admin-client/effective-keys.js +0 -1
  386. package/dist/web-admin-client/facade.d.ts +1 -1
  387. package/dist/web-admin-client/http-client.d.ts +1 -0
  388. package/dist/web-admin-client/http-client.js +17 -9
  389. package/dist/web-admin-client/restart-signal.js +5 -2
  390. package/dist/web-admin-client/skills-mcp.d.ts +20 -6
  391. package/dist/web-admin-client/skills-mcp.js +26 -21
  392. package/dist/web-admin-client/types.d.ts +34 -49
  393. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +2 -2
  394. package/package.json +13 -12
  395. package/scripts/drain-check-local.mjs +2 -28
  396. package/scripts/drain-check.mysql.sql +2 -18
  397. package/scripts/drain-check.pg.sql +2 -18
  398. package/wire-changes/server@7.147.0.json +813 -0
@@ -0,0 +1,29 @@
1
+ export declare const OWNER_ONLY_FILE_MODE = 384;
2
+ /**
3
+ * 调用方声明的持久化要求(闭集;两个出口同一参数、必填 —— 没有缺省,每只调用点自己说):
4
+ * · `required` —— 这次写是一道围栏的持久化事实(例:local 数据根的引擎版本高水位):目录项没证落盘就不算写成,目录 fsync 失败 ⇒ 抛;
5
+ * · `best-effort` —— 一般留痕 / 缓存 / 账本:目录 fsync 失败 ⇒ 写算成功(新内容已可见),F 类留痕 `server.atomic-write.dir-fsync-failed`。
6
+ */
7
+ export type AtomicWriteDurability = "required" | "best-effort";
8
+ /** 原子写的选项(两个出口同形)。 */
9
+ export interface AtomicWriteOptions {
10
+ readonly durability: AtomicWriteDurability;
11
+ }
12
+ /**
13
+ * 异步原子写:同目录 tmp 以 `open(tmp, "wx", {@link OWNER_ONLY_FILE_MODE})` 显式独占新建 —— **拿到句柄那一刻起 tmp 归我**(不从错误形推断);
14
+ * 写好、fsync、关句柄、`rename` 到 `target`,再 fsync 目录(失败的去向按 `opts.durability`)—— 读者只见整份旧文件或整份新文件(撞名与清理律见头注)。
15
+ * I/O 经 `node:fs/promises`(与会话店的读口同一只模块):测试对那只模块装的拦点(打开 / 改名)看得见每一次写。
16
+ */
17
+ export declare function atomicWriteFileAsync(target: string, data: string | Uint8Array, opts: AtomicWriteOptions): Promise<void>;
18
+ /**
19
+ * 一只**已在位**的文件的持久化屏障(原子写以它收尾的那两步:fsync 文件、fsync 它的目录;win32 不 fsync 目录)—— 给「相等不写」的调用方:
20
+ * 读到的那一份可能是上一次写落了 `rename` 而目录项没证到的,不重写也要证它在盘上。失败即抛(它只服务 `required` 的事实;不是写口,不改字节、inode、mtime)。
21
+ */
22
+ export declare function proveDurableSync(target: string): void;
23
+ /**
24
+ * 同步原子写:与异步形同一只命名与清理律,外加 core `atomicWriteFile` 的其余语义(先 `ensureDir` 父目录;tmp 写好 `fsync`,`rename` 之后 fsync 目录)。
25
+ * 目录 fsync 失败不回滚(新内容已经可见,也回滚不了);抛不抛按 `opts.durability`(`best-effort` 不抛、留痕;`required` 抛 —— 头注那一座)。
26
+ * win32 不 fsync 目录(打不开目录 fd;NTFS 的目录项由文件系统日志落盘)。
27
+ */
28
+ export declare function atomicWriteFileSync(target: string, data: string | Uint8Array, opts: AtomicWriteOptions): void;
29
+ //# sourceMappingURL=owner-only-file-mode.d.ts.map
@@ -0,0 +1,141 @@
1
+ import { closeSync, fsyncSync, openSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
+ import { open, rename, rm } from "node:fs/promises";
3
+ import { randomBytes } from "node:crypto";
4
+ import { dirname } from "node:path";
5
+ import { ensureDir } from "@sema-agent/core";
6
+ import { IS_WIN32 } from "./host-platform.js";
7
+ import { recordFailOpen } from "../observability/fail-open.js";
8
+ export const OWNER_ONLY_FILE_MODE = 0o600;
9
+ const TMP_RANDOM_BYTES = 6;
10
+ const TMP_ATTEMPTS = 8;
11
+ const tmpPathFor = (target) => `${target}.${process.pid}.${randomBytes(TMP_RANDOM_BYTES).toString("hex")}.tmp`;
12
+ const collided = (err) => typeof err === "object" && err !== null && "code" in err && err.code === "EEXIST";
13
+ const messageOf = (e) => (e instanceof Error ? e.message : String(e));
14
+ const cleanupFailed = (target, tmp, err, cleanup) => new Error(`atomic write of ${target} failed (${messageOf(err)}) and its temporary file ${tmp} could not be removed (${messageOf(cleanup)})`, { cause: err });
15
+ const useAndCloseFailed = (use, close) => Object.assign(new AggregateError([use, close], messageOf(use)), { code: typeof use === "object" && use !== null && "code" in use ? use.code : undefined });
16
+ async function usingHandle(handle, use) {
17
+ try {
18
+ await use(handle);
19
+ }
20
+ catch (err) {
21
+ await handle.close().catch((close) => {
22
+ throw useAndCloseFailed(err, close);
23
+ });
24
+ throw err;
25
+ }
26
+ await handle.close();
27
+ }
28
+ function usingFd(fd, use) {
29
+ try {
30
+ use(fd);
31
+ }
32
+ catch (err) {
33
+ try {
34
+ closeSync(fd);
35
+ }
36
+ catch (close) {
37
+ throw useAndCloseFailed(err, close);
38
+ }
39
+ throw err;
40
+ }
41
+ closeSync(fd);
42
+ }
43
+ function dirFsyncFailed(target, err, durability) {
44
+ switch (durability) {
45
+ case "required":
46
+ throw new Error(`atomic write of ${target} landed but its directory entry could not be made durable (${messageOf(err)}) — the write is visible but not proven on disk`, { cause: err });
47
+ case "best-effort":
48
+ recordFailOpen("server.atomic-write.dir-fsync-failed", `path=${target} err=${messageOf(err)}`);
49
+ return;
50
+ default: {
51
+ const unhandled = durability;
52
+ throw new Error(`atomic write of ${target}: unknown durability ${String(unhandled)}`);
53
+ }
54
+ }
55
+ }
56
+ export async function atomicWriteFileAsync(target, data, opts) {
57
+ const { tmp, handle } = await openOwnTmpAsync(target);
58
+ try {
59
+ await usingHandle(handle, async (h) => {
60
+ await h.writeFile(data);
61
+ await h.sync();
62
+ });
63
+ await rename(tmp, target);
64
+ }
65
+ catch (err) {
66
+ try {
67
+ await rm(tmp, { force: true });
68
+ }
69
+ catch (cleanup) {
70
+ throw cleanupFailed(target, tmp, err, cleanup);
71
+ }
72
+ throw err;
73
+ }
74
+ if (IS_WIN32)
75
+ return;
76
+ try {
77
+ await usingHandle(await open(dirname(target), "r"), (dir) => dir.sync());
78
+ }
79
+ catch (err) {
80
+ dirFsyncFailed(target, err, opts.durability);
81
+ }
82
+ }
83
+ async function openOwnTmpAsync(target) {
84
+ for (let attempt = 1;; attempt += 1) {
85
+ const tmp = tmpPathFor(target);
86
+ try {
87
+ return { tmp, handle: await open(tmp, "wx", OWNER_ONLY_FILE_MODE) };
88
+ }
89
+ catch (err) {
90
+ if (!collided(err) || attempt >= TMP_ATTEMPTS)
91
+ throw err;
92
+ }
93
+ }
94
+ }
95
+ function openOwnTmpSync(target) {
96
+ for (let attempt = 1;; attempt += 1) {
97
+ const tmp = tmpPathFor(target);
98
+ try {
99
+ return { tmp, fd: openSync(tmp, "wx", OWNER_ONLY_FILE_MODE) };
100
+ }
101
+ catch (err) {
102
+ if (!collided(err) || attempt >= TMP_ATTEMPTS)
103
+ throw err;
104
+ }
105
+ }
106
+ }
107
+ export function proveDurableSync(target) {
108
+ usingFd(openSync(target, "r"), fsyncSync);
109
+ if (IS_WIN32)
110
+ return;
111
+ usingFd(openSync(dirname(target), "r"), fsyncSync);
112
+ }
113
+ export function atomicWriteFileSync(target, data, opts) {
114
+ ensureDir(dirname(target));
115
+ const { tmp, fd } = openOwnTmpSync(target);
116
+ try {
117
+ usingFd(fd, (f) => {
118
+ writeFileSync(f, data);
119
+ fsyncSync(f);
120
+ });
121
+ renameSync(tmp, target);
122
+ }
123
+ catch (err) {
124
+ try {
125
+ rmSync(tmp, { force: true });
126
+ }
127
+ catch (cleanup) {
128
+ throw cleanupFailed(target, tmp, err, cleanup);
129
+ }
130
+ throw err;
131
+ }
132
+ if (IS_WIN32)
133
+ return;
134
+ try {
135
+ usingFd(openSync(dirname(target), "r"), fsyncSync);
136
+ }
137
+ catch (err) {
138
+ dirFsyncFailed(target, err, opts.durability);
139
+ }
140
+ }
141
+ //# sourceMappingURL=owner-only-file-mode.js.map
@@ -1,4 +1,5 @@
1
1
  import { FileDurableRulePartitionProvider, type RuleApprovalRecord, type RuleApprovalRecordStore, type StaleRuleApprovalRecord } from "@sema-agent/core";
2
+ import type { RuleBucketCensus } from "./imported-layer-root-retirement.js";
2
3
  import { type RuleImportTicket, type RuleTicketPurpose, type RuleTicketReclaimResult, type RuleTicketRedeemResult, type RuleTicketSnapshot } from "./permission-rule-store-sql.js";
3
4
  import type { PermissionRuleStoreBundle } from "../rules-consent.js";
4
5
  import type { Logger } from "../observability/logger.js";
@@ -27,10 +28,9 @@ export declare class FileRuleApprovalRecordStore implements RuleApprovalRecordSt
27
28
  create(record: RuleApprovalRecord): Promise<void>;
28
29
  cas(id: string, expectRev: number, next: RuleApprovalRecord): Promise<boolean>;
29
30
  /**
30
- * 一次性迁移 M36(窗口见 `plugins/one-time-migrations.ts` 登记表)在 File 店的桶来源之一:本店**导入记录**点名过的每一个属主(逐条记录取、**这里不去重**:
31
- * 多条记录点名同一属主就重复出现,按桶键去重在退役步)。引擎 File 分区的桶文件按属主名的单向摘要命名,桶的属主不写在文件里;File 腿读的桶集是
32
- * {@link fileRuleBucketOwners} 取的并集 = 本店导入记录点名的属主 ∪ 引擎 `listBucketOwners().owners`(自 core 7.64.0 起的列桶口:本机属主那只桶与收编标记点名的身份),
33
- * 所以记录不是 File 腿叫得出桶属主的唯一来源(SQL 店不经记录,直接列规则表)。引擎 `unnamedBuckets` 为什么本步不报、File 侧还剩的缺口,见 `imported-layer-root-retirement.ts` 头注「读哪些桶」。
31
+ * 一次性迁移 M36(窗口见 `plugins/one-time-migrations.ts` 登记表)在 File 店交给引擎列桶口的那一半:本店**导入记录**点名过的每一个属主(逐条记录取、**这里不去重**:
32
+ * 多条记录点名同一属主就重复出现,引擎按名去重)。引擎 File 分区的桶文件按属主名的单向摘要命名,桶的属主不写在文件里;{@link fileRuleBucketOwners} 把这里的身份名
33
+ * 作 `knownOwners` 交给引擎 `listBucketOwners`,由引擎一次答出桶在场的属主与叫不出名字的桶数(SQL 店不经记录,直接列规则表),见 `imported-layer-root-retirement.ts` 头注「读哪些桶」。
34
34
  * 上一形的记录(Stale 信封)读不出种类 ⇒ 属主读得出就算上(多读一只桶零写,少读一只会漏)。
35
35
  * 损坏闸合着 ⇒ 抛(读不全记录就叫不全桶;与本面其余口同一条 fail-closed)。
36
36
  */
@@ -99,11 +99,11 @@ export declare class FileRuleImportTicketStore {
99
99
  /** 三面束在数据根下的目录名(唯一一处;束在第一次装配时建它 —— 没开过规则店的数据根下没有它)。 */
100
100
  export declare const FILE_PERMISSION_RULE_DIR = "permission-rules";
101
101
  /**
102
- * M36 File 腿读哪些桶(窗口见 `plugins/one-time-migrations.ts` 登记表;读法见 `imported-layer-root-retirement.ts` 头注「读哪些桶」):
103
- * 导入记录点名过的属主 ∪ 引擎 File 分区后端列得出名字的属主(本机属主那只桶、收编标记点名的身份)。两源有重 ⇒ 退役步按桶键去重。
104
- * 引擎列桶口的拒(目录用不了 `bucket_damaged`、列不出 `bucket_unreadable`、坏收编标记)原样抛 ⇒ 起服拒(叫不全桶就不判)。
102
+ * M36 File 腿的桶普查(窗口见 `plugins/one-time-migrations.ts` 登记表;读法见 `imported-layer-root-retirement.ts` 头注「读哪些桶」):引擎 File 分区后端的列桶口一次答 ——
103
+ * 目录自己叫得出名字的属主(本机属主那只桶、收编标记点名的身份)+ 导入记录点名过的身份里桶文件在场的那些(`knownOwners`),与两者都叫不出属主的桶数。
104
+ * 引擎列桶口的拒(目录用不了 `bucket_damaged`、列不出 `bucket_unreadable`、坏收编标记、`knownOwners` 里有不是身份名的串 `config.invalid_argument`)原样抛 ⇒ 起服拒(叫不全桶就不判)。
105
105
  */
106
- export declare function fileRuleBucketOwners(stores: Pick<FilePermissionRuleStores, "approvals" | "durable">): Promise<readonly RuleOwner[]>;
106
+ export declare function fileRuleBucketOwners(stores: Pick<FilePermissionRuleStores, "approvals" | "durable">): Promise<RuleBucketCensus>;
107
107
  /**
108
108
  * 这只读桶抛出物是不是引擎 File 分区的**确定性整桶拒**(拒码 `permission_rules.bucket_damaged`:同一份字节每次读都同样拒,读侧零规则、什么都不放行)。
109
109
  * 别的都不是:`permission_rules.bucket_unreadable`(一次读失败,带 `errno`;证明不了以后也读不出)、`permission_rules.later_grammar`(更新的引擎写的桶)、
@@ -333,8 +333,20 @@ export class FileRuleImportTicketStore {
333
333
  }
334
334
  export const FILE_PERMISSION_RULE_DIR = "permission-rules";
335
335
  export async function fileRuleBucketOwners(stores) {
336
- const listed = stores.durable.listBucketOwners();
337
- return [...(await stores.approvals.importRecordOwners()), ...listed.owners];
336
+ const knownOwners = (await stores.approvals.importRecordOwners()).flatMap(principalNameOfOwner);
337
+ return stores.durable.listBucketOwners({ knownOwners });
338
+ }
339
+ function principalNameOfOwner(owner) {
340
+ switch (owner.kind) {
341
+ case "principal":
342
+ return [owner.principal];
343
+ case "local-owner":
344
+ return [];
345
+ default: {
346
+ const unknown = owner;
347
+ throw new Error(`M36: an owner of a kind this pass does not know: ${JSON.stringify(unknown)}`);
348
+ }
349
+ }
338
350
  }
339
351
  export function isFileBucketDamaged(e) {
340
352
  return typeof e === "object" && e !== null && e.code === PERMISSION_RULES_DAMAGED_BUCKET_CODE;
@@ -99,7 +99,8 @@ export declare function acquirePgEnsureSchemaLock(client: pg.PoolClient, tag: st
99
99
  /** {@link acquirePgEnsureSchemaLock} 的释放(尽力而为 —— 锁随连接归还自动释放)。 */
100
100
  export declare function releasePgEnsureSchemaLock(client: pg.PoolClient, tag: string): Promise<void>;
101
101
  /** Idempotent central schema apply (the PG twin of tidb-pool.ts ensureSchema): the run/checkpoint tables here +
102
- * every PG store's own (disjoint) tables. Order is irrelevant (CREATE IF NOT EXISTS, no cross-table FKs).
102
+ * every PG store's own (disjoint) tables. Order is irrelevant (CREATE IF NOT EXISTS) except for the one cross-table FK: the session
103
+ * side table `session_ext` references `session_meta`, so it is created right after the session store's tables.
103
104
  *
104
105
  * Concurrency: callers run this concurrently — tests fan ALL integration suites out in parallel (each beforeAll
105
106
  * calls ensurePgSchema), and in production every replica calls it at boot. Concurrent DDL on the SAME table makes
@@ -2,7 +2,8 @@ import pg from "pg";
2
2
  import { recordFailOpen } from "../observability/fail-open.js";
3
3
  import { pollUntilLocked } from "./ensure-schema-lock-policy.js";
4
4
  import { RUN_IDENTITY_COLUMNS } from "../identity-source.js";
5
- import { ensureSchema as ensureSessionSchema } from "./pg-session-storage.js";
5
+ import { ensureSchema as ensureSessionSchema } from "../stores-sql/pg-session-storage.js";
6
+ import { sessionExtDdl } from "./session-ext-table.js";
6
7
  import { ensureSchema as ensureToolResultSchema } from "../stores-sql/tool-result-store-sql.js";
7
8
  import { ensureSchema as ensureCostQuotaSchema } from "./pg-cost-quota.js";
8
9
  import { ensureSchema as ensureRateLimitSchema } from "./pg-rate-limiter.js";
@@ -16,9 +17,11 @@ import { ensurePgSessionCaptureOptOutSchema } from "./session-capture-record-sto
16
17
  import { ensurePgAdoptionLogSchema } from "./adoption-log-sql.js";
17
18
  import { ensurePgPermissionRuleSchema } from "./permission-rule-store-sql.js";
18
19
  import { ensurePgLeaderRunSchema } from "./leader-run-store-sql.js";
19
- import { ensurePgRetentionSchema } from "./retention-store-sql.js";
20
+ import { PG_RETENTION_TOMBSTONE_SCHEMA, RETENTION_TOMBSTONE_INDEXES } from "../stores-sql/retention-store-sql.js";
21
+ import { PG_RETENTION_LANE_SCHEMA, RETENTION_LANE_INDEXES } from "./retention-lane-store-sql.js";
20
22
  import { ensureIndexes } from "./ensure-index.js";
21
23
  import { SESSION_RULES_COLUMN } from "./session-rules-column.js";
24
+ import { INBOX_PAYLOAD_COLUMN } from "./inbox-payload-column.js";
22
25
  import { CENTRAL_SCHEMA_INDEXES } from "./schema-indexes.js";
23
26
  import { PRINCIPAL_MAX_LENGTH } from "../security.js";
24
27
  export const PG_SCHEMA_STATEMENTS = [
@@ -351,7 +354,8 @@ export const PG_SCHEMA_STATEMENTS = [
351
354
  -- (the engine's own correlation id, verbatim; the engine's diagnostic teaching text, redacted + bounded at enqueue;
352
355
  -- each key absent when the engine minted none, NULL when neither).
353
356
  kind VARCHAR(24) COLLATE "C",
354
- payload TEXT COLLATE "C",
357
+ -- Column definition owner = inbox-payload-column.ts (INBOX_PAYLOAD_COLUMN; TiDB twin same note).
358
+ ${INBOX_PAYLOAD_COLUMN.pg},
355
359
  PRIMARY KEY (session_id, run_id),
356
360
  -- Twin-alignment with TiDB's \`UNIQUE KEY uq_wfinbox_seq (seq)\` (same constraint name on purpose, so the two
357
361
  -- schemas can be diffed by name). This is NOT a correctness fix: seq is BIGSERIAL, so it is already unique in
@@ -485,6 +489,7 @@ export async function ensurePgSchema(pool) {
485
489
  for (const stmt of PG_SCHEMA_STATEMENTS)
486
490
  await client.query(stmt);
487
491
  await ensureSessionSchema(client);
492
+ await client.query(sessionExtDdl("pg"));
488
493
  await ensureToolResultSchema(client);
489
494
  await ensureCostQuotaSchema(client);
490
495
  await ensureRateLimitSchema(client);
@@ -498,7 +503,9 @@ export async function ensurePgSchema(pool) {
498
503
  await ensurePgAdoptionLogSchema((text, params) => client.query(text, params));
499
504
  await ensurePgPermissionRuleSchema((text, params) => client.query(text, params));
500
505
  await ensurePgLeaderRunSchema((text, params) => client.query(text, params));
501
- await ensurePgRetentionSchema((text, params) => client.query(text, params));
506
+ for (const stmt of [...PG_RETENTION_LANE_SCHEMA, ...PG_RETENTION_TOMBSTONE_SCHEMA])
507
+ await client.query(stmt);
508
+ await ensureIndexes((text, params) => client.query(text, params), "pg", [...RETENTION_LANE_INDEXES, ...RETENTION_TOMBSTONE_INDEXES]);
502
509
  await ensureIndexes((text, params) => client.query(text, params), "pg", CENTRAL_SCHEMA_INDEXES);
503
510
  }
504
511
  finally {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * **版本串的两种读法**(唯一一处;两问不同,两个读者各管一问,三段的文法只有一只正则):
3
+ * · {@link releaseTriple} 读 **marker 里的串**(公开契约):纯 `x.y.z` —— 整串三段十进制、无前导零、无 `v` 前缀、无预发布 / 构建后缀、无空白,每段是安全整数;
4
+ * 别的一律读不出(`undefined`),不剥前后缀、不猜;入参先验型(不是字符串 ⇒ 读不出)。与壳侧判官(client-core `compareReleaseVersions` 的 `releaseTriple`)同一读法:
5
+ * 同一对 marker 串两边答案不分叉。
6
+ * · {@link buildReleaseTriple} 读 **本构建 `package.json` 的版本** —— 它属于哪一条发布线:semver 文法的 `x.y.z`,可带 `-<预发布>` 与 / 或 `+<构建>` 后缀;
7
+ * 后缀**只剥不比**(`7.147.0-rc.1` 属于 `7.147.0` 那条线),三段交给 {@link releaseTriple} 同一只正则;不是字符串 / 不合文法 ⇒ 读不出。
8
+ * (钉 `test/local-engine-high-water.test.ts` 的两张读法表逐格对它们。)读者:引擎版本高水位的判与抬(`local-engine-high-water.ts`)。
9
+ */
10
+ /** 一只发布版本的三段(大 · 次 · 补丁)。 */
11
+ export type ReleaseTriple = readonly [number, number, number];
12
+ /** 纯 `x.y.z` → 三段;不是(含不是字符串 —— 先验型、再匹配,正则不强转)⇒ `undefined`。 */
13
+ export declare function releaseTriple(v: unknown): ReleaseTriple | undefined;
14
+ /** 本构建版本 → 它所属发布线的三段(后缀只剥不比);不是字符串 / 不合 semver 文法 / 三段不是纯 `x.y.z` ⇒ `undefined`。 */
15
+ export declare function buildReleaseTriple(v: unknown): ReleaseTriple | undefined;
16
+ /** 三段的纯 `x.y.z` 串(marker 里写的形;{@link releaseTriple} 读回的就是它)。 */
17
+ export declare function releaseText(t: ReleaseTriple): string;
18
+ /** 两只三段按数比(先大版本,再次版本,再补丁):`-1` / `0` / `1`。 */
19
+ export declare function compareReleaseTriples(a: ReleaseTriple, b: ReleaseTriple): -1 | 0 | 1;
20
+ //# sourceMappingURL=release-version.d.ts.map
@@ -0,0 +1,28 @@
1
+ export function releaseTriple(v) {
2
+ if (typeof v !== "string")
3
+ return undefined;
4
+ const m = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(v);
5
+ if (m === null)
6
+ return undefined;
7
+ const t = [Number(m[1]), Number(m[2]), Number(m[3])];
8
+ return t.every((n) => Number.isSafeInteger(n)) ? t : undefined;
9
+ }
10
+ const PRERELEASE_IDENTIFIER = String.raw `(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)`;
11
+ const BUILD_IDENTIFIER = String.raw `[0-9A-Za-z-]+`;
12
+ const BUILD_VERSION = new RegExp(String.raw `^([^-+]*)(?:-${PRERELEASE_IDENTIFIER}(?:\.${PRERELEASE_IDENTIFIER})*)?(?:\+${BUILD_IDENTIFIER}(?:\.${BUILD_IDENTIFIER})*)?$`);
13
+ export function buildReleaseTriple(v) {
14
+ if (typeof v !== "string")
15
+ return undefined;
16
+ const m = BUILD_VERSION.exec(v);
17
+ return m === null ? undefined : releaseTriple(m[1]);
18
+ }
19
+ export function releaseText(t) {
20
+ return `${t[0]}.${t[1]}.${t[2]}`;
21
+ }
22
+ export function compareReleaseTriples(a, b) {
23
+ for (let i = 0; i < 3; i++)
24
+ if (a[i] !== b[i])
25
+ return a[i] < b[i] ? -1 : 1;
26
+ return 0;
27
+ }
28
+ //# sourceMappingURL=release-version.js.map
@@ -15,6 +15,12 @@ export interface AdbEnvConfig extends LaneHomeConfig {
15
15
  maxAttempts?: number;
16
16
  backoffMs?: number;
17
17
  };
18
+ /** 运维日志座(起服装配递本服务的 logger;缺席 ⇒ 本模块自建一只 JSON 行 logger —— 设模式失败那一行不因没人递座而消失)。 */
19
+ logger?: AdbEnvLogger;
20
+ }
21
+ /** 本适配器说话用的那一面(与 k8s / device 车道的 logger 座同形)。 */
22
+ export interface AdbEnvLogger {
23
+ warn(event: string, fields?: Record<string, unknown>): void;
18
24
  }
19
25
  type ConnectResult = {
20
26
  ok: true;
@@ -79,6 +85,7 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
79
85
  * 这条显式授予),没有一条是从本进程继承的 ⇒ `[]`(core 契约:「`[]` when its shell environment is built rather than inherited」)。 */
80
86
  readonly withheldEnv: readonly [];
81
87
  private readonly cfg;
88
+ private readonly logger;
82
89
  private readonly spawnFn;
83
90
  private readonly injectedConnectOnce?;
84
91
  constructor(config: AdbEnvConfig, deps?: AdbEnvDeps);
@@ -164,17 +171,26 @@ export declare class RemoteAdbExecutionEnv implements RemoteExecutionEnv {
164
171
  abortSignal?: AbortSignal;
165
172
  }): Promise<Result<string[], FileError>>;
166
173
  /** 暂存写的两只面(规则与提交脚本的唯一属主 = `remote-shell.ts` `writeFileStaged` / `appendFileStaged`;父目录与私有暂存目录由编排的准备那一步建):
167
- * 上传 = `adb push` 到私有目录里的暂存件;提交 = 文件面探针 exec。两者同一身份(push 与 `adb shell` 都由设备上的 adbd 以它的身份落盘 / 起进程)。 */
174
+ * 上传 = `adb push` 到私有目录里的暂存件(阶段一 = 本机落临时件,见 {@link prepareUpload};阶段二 = push);提交 = 文件面探针 exec。两者同一身份(push 与 `adb shell` 都由设备上的 adbd 以它的身份落盘 / 起进程)。 */
168
175
  private stagedLane;
169
176
  /** 整旧或整新(暂存 → 一次 `mv -f`)。修前 push 直落目标:传输中途断 / 取消时目标剩什么取决于设备侧 adbd 的落地实现,本适配器不依赖它。 */
170
177
  writeFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
171
178
  /** 追加(暂存要加的字节 → 一次 `cat >>`;inode 不换、已有字节不重写)。修前 = 读旧 + 拼 + 整份 push(O(文件);中途断 ⇒ 目标没了或半份)。
172
179
  * 目录不收新名字 / 私有目录收不成私有时的退路 = 修前那一形(push 没有追加写,只能把整份文件落到一个路径上):读旧(不在 ⇒ 按空;别的读错照实答、不 push)
173
- * + 拼 + 整份 push 直落目标(与 e2b 共用 `rewriteAppend`)—— 非原子,push 中途断 / 取消 ⇒ 目标可能没了或只剩半份(只有 push 那一步经 `ctx.inPlace`:读旧时取消照答 `aborted`,目标未碰)。
180
+ * + 拼 + 本机落临时件 + 整份 push 直落目标(与 e2b 共用 `rewriteAppend`)—— 非原子,push 中途断 / 取消 ⇒ 目标可能没了或只剩半份;读旧与落临时件是备件阶段:
181
+ * 取消落在这里 ⇒ `aborted`、目标未碰、一次 push 都没发,只有 push 那一步被取消打断才答 `unknown`。
174
182
  * Android 共享存储(权限位由挂载派生)上收紧那一步按 sdcardfs / MediaProvider FUSE 的权限语义**推断**不过(未上真机,真机读数候 test),追加每次走这里。 */
175
183
  appendFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
176
- /** 把整份内容 `adb push` 到设备上的 `dest`(建或覆盖)。本机这一侧先落一只本地临时件再 push(二进制安全,不经 shell 转义载荷)——
177
- * 临时件同样只在私有目录里出现(`mkdtemp` 建的目录生来 0700),本机别的用户读不到;文件自己的权限位照缺省(push 把它带到设备上,与修前同)。 */
184
+ /** 阶段一(备件):把整份内容在本机落一只临时件(二进制安全,不经 shell 转义载荷)—— 临时件同样只在私有目录里出现(`mkdtemp` 建的目录生来 0700,本机别的用户读不到);
185
+ * 文件自己带 {@link OWNER_ONLY_FILE_MODE}(0600,不靠上层私有目录兜:内容是要上设备的文件,可能含凭据)。设备侧的模式**不随它走**:`adb push` 会把本机文件的模式位带到设备上
186
+ * 〔推断,未上真机;adbd 还会先把属主位扩到组 / 他人位、再交文件系统策略〕,所以阶段二在 push 之后把目的地显式设回 {@link DEVICE_PUSHED_FILE_MODE}(尽力而为)。这一段只碰本机,没有一个字节发往设备:编排在它之后复核取消、再起阶段二;`release` 删临时件。
187
+ * 阶段二({@link push})把临时件 `adb push` 到设备上的 `dest`。 */
188
+ private prepareUpload;
189
+ /** 阶段二:把本机临时件 `adb push` 到设备上的 `dest`(建或覆盖),**同一步内**紧跟一次 `chmod -- 0644 <dest>`:设备目标的模式是显式的 {@link DEVICE_PUSHED_FILE_MODE},
190
+ * 不依赖临时件的模式传播(升级前它来自本机 umask 的缺省 0644)。push 的结局就是这一步的结局:push 失败 ⇒ 既有错误形;取消落在 push 里 ⇒ `aborted`(编排按阶段二读)。
191
+ * 设模式是**尽力而为**(「传完之后设模式」全树一种失败策略,与 `remote-shell.ts` 的 `carryMode` 同):字节已经落地,设不上(文件系统不认改模式 / 设备掉线 / 取消落在 chmod 上)
192
+ * ⇒ 这一步照样成功,只多一行运维 warn `remote_env_file_mode_failed`(目的地经出口座、设备回话只取首行;不记 fail-open:模式是显式加固,目标文件系统不支持时无从加固,
193
+ * 不是放宽 —— 升级前同一只文件落成的位也由文件系统定)。答失败会让调用方以为没写成,而目标已是新字节。 */
178
194
  private push;
179
195
  private posixFsInst?;
180
196
  private get posixFs();
@@ -5,6 +5,7 @@ import { spawn } from "node:child_process";
5
5
  import { hostSubprocessEnv } from "../server-secret-env.js";
6
6
  import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
7
7
  import { appendFileStaged, rewriteAppend, buildCwdEnvCommand, createCwdGuardedCall, shellQuote, armPipeDestroyGrace, writeFileStaged } from "./remote-shell.js";
8
+ import { OWNER_ONLY_FILE_MODE } from "./owner-only-file-mode.js";
8
9
  import { signalNumber } from "./host-platform.js";
9
10
  import { buildLivenessCut, commandBoundsOf } from "../exec-bounds.js";
10
11
  import { buildCapturedOutput, createCutError } from "../exec-cut.js";
@@ -12,7 +13,10 @@ import { FileError, ExecutionError, RemoteExecutionError, withRetry, RollingTail
12
13
  import { capabilitiesFor } from "../execution-lane-caps.js";
13
14
  import { classifyFsStderr, fileErrorFromExec } from "./remote-env-file-error.js";
14
15
  import { createPosixShellFs } from "./posix-shell-fs.js";
16
+ import { createLogger } from "../observability/logger.js";
17
+ import { seatText } from "../trace/exit-seat.js";
15
18
  const PROVIDER = "adb";
19
+ const DEVICE_PUSHED_FILE_MODE = "0644";
16
20
  const ok = (value) => ({ ok: true, value });
17
21
  const unsupported = (op) => ({
18
22
  ok: false,
@@ -42,6 +46,7 @@ export class RemoteAdbExecutionEnv {
42
46
  cdPath = "unknown";
43
47
  withheldEnv = [];
44
48
  cfg;
49
+ logger;
45
50
  spawnFn;
46
51
  injectedConnectOnce;
47
52
  constructor(config, deps) {
@@ -54,6 +59,7 @@ export class RemoteAdbExecutionEnv {
54
59
  retry: { maxAttempts: config.retry?.maxAttempts ?? 3, backoffMs: config.retry?.backoffMs ?? 800 },
55
60
  };
56
61
  this.cwd = this.cfg.mountPath;
62
+ this.logger = config.logger ?? createLogger();
57
63
  this.homeSeat = new LaneHomeSeat(PROVIDER, config);
58
64
  this.spawnFn = deps?.spawn ?? spawn;
59
65
  this.injectedConnectOnce = deps?.connectOnce;
@@ -360,7 +366,7 @@ export class RemoteAdbExecutionEnv {
360
366
  return ok(lines);
361
367
  }
362
368
  stagedLane(content) {
363
- return { upload: (dest, signal) => this.push(content, dest, signal), run: (cmd, signal) => this.fsExec(cmd, signal) };
369
+ return { prepare: this.prepareUpload(content), run: (cmd, signal) => this.fsExec(cmd, signal), provider: PROVIDER, logger: this.logger };
364
370
  }
365
371
  async writeFile(p, content, abortSignal) {
366
372
  const gated = await this.fsGate(p);
@@ -373,14 +379,29 @@ export class RemoteAdbExecutionEnv {
373
379
  if (gated)
374
380
  return gated;
375
381
  const abs = this.resolve(p);
376
- return appendFileStaged(this.stagedLane(content), abs, abortSignal, (ctx) => rewriteAppend((signal) => this.readBinaryFile(abs, signal), (bytes, signal) => this.push(bytes, abs, signal), content, ctx));
382
+ return appendFileStaged(this.stagedLane(content), abs, abortSignal, rewriteAppend((signal) => this.readBinaryFile(abs, signal), (merged) => this.prepareUpload(merged), content));
383
+ }
384
+ prepareUpload(content) {
385
+ return async () => {
386
+ let localDir;
387
+ const release = async () => {
388
+ if (localDir)
389
+ await fs.rm(localDir, { recursive: true, force: true }).catch(() => { });
390
+ };
391
+ try {
392
+ localDir = await fs.mkdtemp(path.join(os.tmpdir(), "sema-adb-push-"));
393
+ const local = path.join(localDir, "data");
394
+ await fs.writeFile(local, typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content), { mode: OWNER_ONLY_FILE_MODE });
395
+ return ok({ upload: (dest, signal) => this.push(local, dest, signal), release });
396
+ }
397
+ catch (e) {
398
+ await release();
399
+ return { ok: false, error: new FileError("unknown", e instanceof Error ? e.message : String(e)) };
400
+ }
401
+ };
377
402
  }
378
- async push(content, dest, abortSignal) {
379
- let localDir;
403
+ async push(local, dest, abortSignal) {
380
404
  try {
381
- localDir = await fs.mkdtemp(path.join(os.tmpdir(), "sema-adb-push-"));
382
- const local = path.join(localDir, "data");
383
- await fs.writeFile(local, typeof content === "string" ? Buffer.from(content, "utf8") : Buffer.from(content));
384
405
  const r = await this.adb(["-s", this.cfg.serial, "push", local, dest], { signal: abortSignal, timeoutMs: this.cfg.dataTimeoutMs });
385
406
  if (!r.ok)
386
407
  return { ok: false, error: fileErrorFromExec(r.error, dest) };
@@ -389,15 +410,22 @@ export class RemoteAdbExecutionEnv {
389
410
  return { ok: false, error: new FileError("permission_denied", out.trim(), dest) };
390
411
  if (r.value.exitCode !== 0)
391
412
  return { ok: false, error: new FileError("unknown", r.value.stderr.trim() || `adb push failed for ${dest}`, dest) };
413
+ const m = await this.fsExec(`chmod -- ${DEVICE_PUSHED_FILE_MODE} ${shellQuote(dest)}`, abortSignal);
414
+ const unset = !m.ok ? m.error.message : m.value.exitCode !== 0 ? m.value.stderr.trim() || `chmod exited ${m.value.exitCode}` : undefined;
415
+ if (unset !== undefined) {
416
+ this.logger.warn("remote_env_file_mode_failed", {
417
+ provider: PROVIDER,
418
+ path: seatText("operator-log-arg", dest),
419
+ mode: DEVICE_PUSHED_FILE_MODE,
420
+ error: seatText("operator-log-text", unset.split(/\r?\n/, 1)[0] ?? ""),
421
+ effect: "the bytes landed; the file keeps the mode the device filesystem gave it (setting the mode is best effort, as adbd itself treats it)",
422
+ });
423
+ }
392
424
  return ok(undefined);
393
425
  }
394
426
  catch (e) {
395
427
  return { ok: false, error: new FileError("unknown", e instanceof Error ? e.message : String(e), dest) };
396
428
  }
397
- finally {
398
- if (localDir)
399
- await fs.rm(localDir, { recursive: true, force: true }).catch(() => { });
400
- }
401
429
  }
402
430
  posixFsInst;
403
431
  get posixFs() {
@@ -291,12 +291,21 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
291
291
  readBinaryFile(p: string, abortSignal?: AbortSignal): Promise<Result<Uint8Array, FileError>>;
292
292
  /** 暂存写的两只面(规则与提交脚本的唯一属主 = `remote-shell.ts` `writeFileStaged` / `appendFileStaged`;本腿是原生 SDK 腿,与四条
293
293
  * shell 腿共用的是这只编排,不是 `posix-shell-fs` 基座;父目录与私有暂存目录由编排的准备那一步建):上传 = `files.write` 整份写到私有目录里的
294
- * 暂存件;提交 = 一次 `exec`。两者同一身份(`files.write` 与 `commands.run` 都不带 `user`,沙箱侧取同一个缺省用户)。 */
294
+ * 暂存件;提交 = 一次 `exec`。
295
+ *
296
+ * **身份怎么读(出处:e2b 2.36.0 的 `dist/index.d.ts`,按符号名 + 文档原句引,不引行号 —— 上游 dist 的行号随提货漂)**:上传的 `files.write` 不带 `user`(下面 `upload`);
297
+ * `FilesystemRequestOpts.user` 的文档说它影响「解析相对路径与 `ownership of the created filesystem objects`」(所建文件系统对象的**属主**),
298
+ * 文件接口 REST 参数 `username` 的文档句是 `Defaults to the sandbox's default user`(缺省 = 沙箱的缺省用户)⇒ 上传落下的东西**属主**是沙箱缺省用户。
299
+ * 提交 / 清理的 `commands.run`:`CommandStartOpts.user` 的缺省是 `default Sandbox user (as specified in the template)`(模板的缺省用户);本腿的起动经 {@link startIn} 的起动编码,身份只由那一处给
300
+ * (读地板守着时外层以 root 起、监督者再降到工作区属主,见 `sandbox-read-floor.ts` 的 `laneLaunchPlan`)。
301
+ * 所以编排要的「提交方拿得走、清得掉上传落下的东西」靠的是**属主**(缺省用户 = 命令的缺省执行用户);SDK 类型**没有**说上传是以该用户的**权限**去写 ——
302
+ * [I:读 SDK 类型,推断由沙箱守护进程代写再改属主;未上真沙箱]。这一差别的后果:准备脚本建的 0700 私有目录属提交方,上传能写进去是守护进程代写的结果、
303
+ * 不是「同一个用户自己写」;目录收不成私有而退到直接写目标时,`files.write` 整份写目标,落地后的属主 / 权限位由沙箱侧定(与 7.138.x 同权,无用户可见回归)。 */
295
304
  private stagedLane;
296
305
  /** 整旧或整新(暂存 → 一次 `mv -f`)。修前 `files.write` 直落目标:上传中途断 / 取消时目标剩什么取决于沙箱侧的落地实现,本适配器不依赖它。 */
297
306
  writeFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
298
307
  /** 追加(暂存要加的字节 → 一次 `cat >>`;inode 不换、已有字节不重写)。修前 = 读旧 + 拼 + 整份 `files.write`(O(文件);中途断 ⇒
299
- * 半份)。目录不收新名字 / 私有目录收不成私有时的退路 = 旧形(`rewriteAppend`:读旧 + 拼 + 整份 `files.write` 到目标;只有写那一步经 `ctx.inPlace`)。 */
308
+ * 半份)。目录不收新名字 / 私有目录收不成私有时的退路 = 旧形(`rewriteAppend`:读旧 + 拼是备件阶段,取消落在那里 ⇒ `aborted`、目标未碰;整份 `files.write` 到目标是传输那一步,被取消打断 ⇒ `unknown`)。 */
300
309
  appendFile(p: string, content: string | Uint8Array, abortSignal?: AbortSignal): Promise<Result<void, FileError>>;
301
310
  fileInfo(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo, FileError>>;
302
311
  listDir(p: string, abortSignal?: AbortSignal): Promise<Result<FileInfo[], FileError>>;
@@ -390,7 +399,7 @@ export declare class RemoteContainerExecutionEnv implements RemoteExecutionEnv,
390
399
  /**
391
400
  * Build the deployment-level `RunnerDeps.executionEnvFactory` ([ref] v1b). Wiring this onto a
392
401
  * deployment makes it a "code-agent worker": every task's hand runs in a per-task E2B VM. Deployments that do
393
- * NOT set this (e.g. OA / review) keep the in-process stub env — routing is **deployment-level** (the factory
402
+ * declare another lane run that lane's factory (or none, for `REMOTE_EXEC=none`) — routing is **deployment-level** (the factory
394
403
  * ctx carries only sessionId/taskId, never a service scenario; that stays out of the generic core seam).
395
404
  *
396
405
  * The factory returns the env **unconnected** (lazy): the VM is provisioned on first FS/Shell/execStream use,
@@ -5,7 +5,7 @@ import { capabilitiesFor } from "../execution-lane-caps.js";
5
5
  import { ADAPTER_START, BOOTSTRAP_START, createSandboxReadFloor, e2bFloorCommand, engineStart, } from "./sandbox-read-floor.js";
6
6
  import { LANE_HOME_PROBE_COMMAND, LaneHomeSeat } from "../lane-home-probe.js";
7
7
  import { fileErrorFromExec } from "./remote-env-file-error.js";
8
- import { appendFileStaged, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
8
+ import { appendFileStaged, readyUpload, rewriteAppend, numEnvOr, runSymlinkChain, shellQuote, writeFileStaged } from "./remote-shell.js";
9
9
  import { buildLivenessCut, commandBoundsOf, firstBoundOf, laneLivenessOf, LIVENESS_MS_DEFAULT } from "../exec-bounds.js";
10
10
  import { createCutError } from "../exec-cut.js";
11
11
  import { BackgroundShellManager } from "./background-shell-support.js";
@@ -904,7 +904,7 @@ export class RemoteContainerExecutionEnv {
904
904
  stagedLane(sbx, content) {
905
905
  const data = typeof content === "string" ? content : toArrayBuffer(content);
906
906
  return {
907
- upload: async (dest, signal) => {
907
+ prepare: readyUpload(async (dest, signal) => {
908
908
  try {
909
909
  await this.rpc("files.write", (s) => sbx.files.write(dest, data, { signal: s }), signal, this.cfg.dataTimeoutMs);
910
910
  return ok(undefined);
@@ -912,8 +912,10 @@ export class RemoteContainerExecutionEnv {
912
912
  catch (e) {
913
913
  return { ok: false, error: this.fileError(e, dest, signal) };
914
914
  }
915
- },
915
+ }),
916
916
  run: (cmd, signal) => this.execInternal(cmd, { cwd: "/", ...(signal !== undefined ? { abortSignal: signal } : {}) }),
917
+ provider: PROVIDER,
918
+ logger: this.cfg.logger,
917
919
  };
918
920
  }
919
921
  async writeFile(p, content, abortSignal) {
@@ -927,7 +929,7 @@ export class RemoteContainerExecutionEnv {
927
929
  if (!sbx.ok)
928
930
  return sbx;
929
931
  const abs = this.resolve(p);
930
- return appendFileStaged(this.stagedLane(sbx.value, content), abs, abortSignal, (ctx) => rewriteAppend((signal) => this.readBinaryFile(abs, signal), (bytes, signal) => this.stagedLane(sbx.value, bytes).upload(abs, signal), content, ctx));
932
+ return appendFileStaged(this.stagedLane(sbx.value, content), abs, abortSignal, rewriteAppend((signal) => this.readBinaryFile(abs, signal), (merged) => this.stagedLane(sbx.value, merged).prepare, content));
931
933
  }
932
934
  async fileInfo(p, abortSignal) {
933
935
  const sbx = await this.fsReady(p);
@@ -54,6 +54,12 @@ export interface HostEnvConfig extends LaneHomeConfig {
54
54
  * single-user TOC host lane. `HOST_BG_ENABLED=false` is an additional global kill switch(🪦 旧名
55
55
  * `HOST_BG_DISABLED` 自 server 3.0.0 起是 fail-loud 墓碑:设了即拒启并指路新名,不再被读取)。 */
56
56
  backgroundShell?: boolean;
57
+ /**
58
+ * `true` = 本服务自己的 git worktree 基环境(`git worktree add / remove / prune`;`boot/execution-env.ts` 铸一只):它**从不交给引擎**,引擎不读它的 {@link withheldEnv},
59
+ * 所以它扣了哪些名字没有引擎通告替它说 —— 它的 spawn 记在自己的现场 `server.remote-env-host.git-base`(披露行是唯一读法)。缺省(交给引擎的环境:工厂产物、
60
+ * worktree 子代环境、嵌入方交给 `Runner` 的环境)记在 `server.remote-env-host.spawn-env`:名字由引擎的 `inherit_env.names_withheld` 说,只记计数。
61
+ */
62
+ gitBase?: true;
57
63
  }
58
64
  export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, SchedulerCapability, BackgroundShellCapability {
59
65
  /** 能力块的唯一作者 = `capabilitiesFor`(`execution-lane-caps.ts`;逐键表态与理由在那里,本类零能力字面量)。 */
@@ -428,7 +434,9 @@ export declare class RemoteHostExecutionEnv implements RemoteExecutionEnv, Sched
428
434
  * `inheritedHostEnv(policy)`:三个继承词(`"all"` / `"scrub"` / `[names]`)只在引擎一处判,本进程自有凭据名(起服声明)任何词都不交 ——
429
435
  * 本类不再有三臂字面(7.129.0 / core 7.51.1;修前 `all` 是 `{ ...process.env }` 零剥除)。**不碰 shell**,所以读面(如 {@link cdPath})任何时候
430
436
  * 都能读,不依赖 shell 是否已落定。
431
- * · **spawn 层**(`spawnShell` 在场)—— 这一次是真要交给子进程:经 `hostSubprocessEnv` 记剥除(`spawnShell` 缺席 ⇒ 只读组合 `composeHostSubprocessEnv`,
437
+ * · **spawn 层**(`spawnShell` 在场)—— 这一次是真要交给子进程:经 `hostSubprocessEnv` 记剥除。交给引擎的环境(缺省)只记**计数**、不写名字:扣了哪些名字由引擎读
438
+ * {@link withheldEnv} 说(`inherit_env.names_withheld`;现场 `server.remote-env-host.spawn-env`,表里 `told:"engine-notice"`);本服务自己的 git 基环境({@link HostEnvConfig.gitBase})
439
+ * 引擎读不到,记在 `server.remote-env-host.git-base`,披露行照写(`spawnShell` 缺席 ⇒ 只读组合 `composeHostSubprocessEnv`,
432
440
  * 不计数:一次没发生的 spawn 不进剥除账),win32 上把 `SHELL` 钉到已解析的 Git Bash({@link pinHostShell},在大小写折叠**之前**)。
433
441
  * 披露与钉同一个开关(`spawnShell`)—— 「真 spawn」只有一种说法,不再有 `disclose` 与钉各自一个布尔。
434
442
  * 引擎对点到自有凭据名的白名单在这里**抛**(spawn 时的拒;构造器已先问过同一只判)—— 子进程不起,拒句带名。