stitchkit 0.104.2 → 0.105.1

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 (430) hide show
  1. package/CHANGELOG.md +401 -13
  2. package/darwin-native.cjs +4 -2
  3. package/dist/agent-runtime/browser-control-contract.d.ts +32 -2
  4. package/dist/agent-runtime/browser-control-contract.d.ts.map +1 -1
  5. package/dist/agent-runtime/browser-controller.d.ts +21 -3
  6. package/dist/agent-runtime/browser-controller.d.ts.map +1 -1
  7. package/dist/agent-runtime/coding-shell-process.d.ts.map +1 -1
  8. package/dist/agent-runtime/coding-tool-refusals.d.ts +1 -0
  9. package/dist/agent-runtime/coding-tool-refusals.d.ts.map +1 -1
  10. package/dist/agent-runtime/coding-tool-shell.d.ts.map +1 -1
  11. package/dist/agent-runtime/compaction.d.ts.map +1 -1
  12. package/dist/agent-runtime/contained-write.d.ts.map +1 -1
  13. package/dist/agent-runtime/control-schema.d.ts +48 -1
  14. package/dist/agent-runtime/control-schema.d.ts.map +1 -1
  15. package/dist/agent-runtime/deferred-tool-search.d.ts +3 -2
  16. package/dist/agent-runtime/deferred-tool-search.d.ts.map +1 -1
  17. package/dist/agent-runtime/harness-control.d.ts.map +1 -1
  18. package/dist/agent-runtime/harness-realtime.d.ts +34 -4
  19. package/dist/agent-runtime/harness-realtime.d.ts.map +1 -1
  20. package/dist/agent-runtime/runtime-recovery.d.ts.map +1 -1
  21. package/dist/agent-runtime/runtime-state.d.ts.map +1 -1
  22. package/dist/agent-runtime/sandbox-contract.d.ts.map +1 -1
  23. package/dist/agent-runtime/sandbox-process-owner.d.ts +9 -1
  24. package/dist/agent-runtime/sandbox-process-owner.d.ts.map +1 -1
  25. package/dist/agent-runtime/sandbox.d.ts +32 -1
  26. package/dist/agent-runtime/sandbox.d.ts.map +1 -1
  27. package/dist/agent-runtime/schedule-records.d.ts.map +1 -1
  28. package/dist/agent-runtime/schedules.d.ts.map +1 -1
  29. package/dist/agent-runtime/store-events.d.ts +9 -4
  30. package/dist/agent-runtime/store-events.d.ts.map +1 -1
  31. package/dist/agent-runtime/testing.d.ts.map +1 -1
  32. package/dist/application/diagnostic-journal-contract.d.ts +50 -0
  33. package/dist/application/diagnostic-journal-contract.d.ts.map +1 -1
  34. package/dist/application/diagnostic-journal-generations.d.ts +24 -0
  35. package/dist/application/diagnostic-journal-generations.d.ts.map +1 -0
  36. package/dist/application/diagnostic-journal-manager.d.ts.map +1 -1
  37. package/dist/application/diagnostic-journal-open.d.ts +10 -0
  38. package/dist/application/diagnostic-journal-open.d.ts.map +1 -0
  39. package/dist/application/diagnostic-journal-quarantine.d.ts +28 -0
  40. package/dist/application/diagnostic-journal-quarantine.d.ts.map +1 -0
  41. package/dist/application/diagnostic-journal-read-contract.d.ts +73 -3
  42. package/dist/application/diagnostic-journal-read-contract.d.ts.map +1 -1
  43. package/dist/application/diagnostic-journal-reader.d.ts +17 -2
  44. package/dist/application/diagnostic-journal-reader.d.ts.map +1 -1
  45. package/dist/application/diagnostic-journal-recovery.d.ts +18 -2
  46. package/dist/application/diagnostic-journal-recovery.d.ts.map +1 -1
  47. package/dist/application/diagnostic-journal-storage.d.ts +6 -2
  48. package/dist/application/diagnostic-journal-storage.d.ts.map +1 -1
  49. package/dist/application/diagnostic-journal-tail.d.ts +12 -0
  50. package/dist/application/diagnostic-journal-tail.d.ts.map +1 -0
  51. package/dist/application/diagnostic-journal.d.ts +3 -0
  52. package/dist/application/diagnostic-journal.d.ts.map +1 -1
  53. package/dist/application/directory-inbox-accept.d.ts +3 -3
  54. package/dist/application/directory-inbox-accept.d.ts.map +1 -1
  55. package/dist/application/directory-inbox-contract.d.ts +38 -10
  56. package/dist/application/directory-inbox-contract.d.ts.map +1 -1
  57. package/dist/application/directory-inbox-delivery.d.ts +3 -3
  58. package/dist/application/directory-inbox-delivery.d.ts.map +1 -1
  59. package/dist/application/directory-inbox-files.d.ts +17 -2
  60. package/dist/application/directory-inbox-files.d.ts.map +1 -1
  61. package/dist/application/directory-inbox-state.d.ts +1 -1
  62. package/dist/application/directory-inbox-state.d.ts.map +1 -1
  63. package/dist/application/directory-inbox.d.ts +1 -1
  64. package/dist/application/directory-inbox.d.ts.map +1 -1
  65. package/dist/application/file-state-store.d.ts +21 -1
  66. package/dist/application/file-state-store.d.ts.map +1 -1
  67. package/dist/application/grammy.d.ts.map +1 -1
  68. package/dist/application/kernel-contract.d.ts.map +1 -1
  69. package/dist/application/revision-signal.d.ts.map +1 -1
  70. package/dist/application/state-store.d.ts +3 -0
  71. package/dist/application/state-store.d.ts.map +1 -1
  72. package/dist/browser/api-error.d.ts +38 -0
  73. package/dist/browser/api-error.d.ts.map +1 -0
  74. package/dist/browser/chunked-upload.d.ts.map +1 -1
  75. package/dist/browser/client-executors.d.ts.map +1 -1
  76. package/dist/browser/client-url.d.ts.map +1 -1
  77. package/dist/browser/contract-stream.d.ts.map +1 -1
  78. package/dist/browser/http.d.ts +0 -25
  79. package/dist/browser/http.d.ts.map +1 -1
  80. package/dist/browser/resumable.d.ts.map +1 -1
  81. package/dist/contract/define-validation.d.ts +0 -1
  82. package/dist/contract/define-validation.d.ts.map +1 -1
  83. package/dist/contract/define.d.ts.map +1 -1
  84. package/dist/contract/errors-factory.d.ts.map +1 -1
  85. package/dist/contract/errors.d.ts +15 -18
  86. package/dist/contract/errors.d.ts.map +1 -1
  87. package/dist/contract/normalize.d.ts.map +1 -1
  88. package/dist/durability/effect.d.ts.map +1 -1
  89. package/dist/durability/scheduler.d.ts.map +1 -1
  90. package/dist/entrypoints/agent-runtime/browser.js +29 -18
  91. package/dist/entrypoints/agent-runtime/coding-tools.js +8 -7
  92. package/dist/entrypoints/agent-runtime/harness.js +15 -14
  93. package/dist/entrypoints/agent-runtime/realtime.d.ts +1 -1
  94. package/dist/entrypoints/agent-runtime/realtime.d.ts.map +1 -1
  95. package/dist/entrypoints/agent-runtime/realtime.js +119 -54
  96. package/dist/entrypoints/agent-runtime/sandbox.js +23 -17
  97. package/dist/entrypoints/agent-runtime/sqlite/bun.js +4 -3
  98. package/dist/entrypoints/agent-runtime/sqlite/node.js +4 -3
  99. package/dist/entrypoints/agent-runtime/testing.js +8 -6
  100. package/dist/entrypoints/agent-runtime.js +37 -38
  101. package/dist/entrypoints/application/diagnostic-journal.js +305 -111
  102. package/dist/entrypoints/application/directory-inbox.js +174 -77
  103. package/dist/entrypoints/application/grammy.js +5 -2
  104. package/dist/entrypoints/application/opentelemetry.js +2 -2
  105. package/dist/entrypoints/application.d.ts +2 -2
  106. package/dist/entrypoints/application.d.ts.map +1 -1
  107. package/dist/entrypoints/application.js +17 -8
  108. package/dist/entrypoints/cli/publish.d.ts +16 -0
  109. package/dist/entrypoints/cli/publish.d.ts.map +1 -0
  110. package/dist/entrypoints/cli/publish.js +527 -0
  111. package/dist/entrypoints/cli.d.ts +1 -2
  112. package/dist/entrypoints/cli.d.ts.map +1 -1
  113. package/dist/entrypoints/cli.js +59 -966
  114. package/dist/entrypoints/contract.js +3 -3
  115. package/dist/entrypoints/files/packaging.js +161 -66
  116. package/dist/entrypoints/files.d.ts +1 -0
  117. package/dist/entrypoints/files.d.ts.map +1 -1
  118. package/dist/entrypoints/files.js +17 -10
  119. package/dist/entrypoints/index.d.ts +2 -1
  120. package/dist/entrypoints/index.d.ts.map +1 -1
  121. package/dist/entrypoints/index.js +31 -60
  122. package/dist/entrypoints/node.js +8 -8
  123. package/dist/entrypoints/observability.js +3 -3
  124. package/dist/entrypoints/primitives.js +67 -83
  125. package/dist/entrypoints/process.d.ts +1 -1
  126. package/dist/entrypoints/process.d.ts.map +1 -1
  127. package/dist/entrypoints/process.js +2 -2
  128. package/dist/entrypoints/react.js +4 -2
  129. package/dist/entrypoints/remote.js +37 -13
  130. package/dist/entrypoints/server.js +18 -16
  131. package/dist/entrypoints/telegram/screens.js +5 -3
  132. package/dist/entrypoints/telegram.js +31 -46
  133. package/dist/entrypoints/testing.d.ts +1 -1
  134. package/dist/entrypoints/testing.d.ts.map +1 -1
  135. package/dist/entrypoints/testing.js +444 -448
  136. package/dist/entrypoints/tools/connections.js +268 -105
  137. package/dist/entrypoints/tools/contract.js +2 -2
  138. package/dist/entrypoints/tools/invoker.js +8 -7
  139. package/dist/entrypoints/tools/mcp.d.ts +2 -2
  140. package/dist/entrypoints/tools/mcp.d.ts.map +1 -1
  141. package/dist/entrypoints/tools/mcp.js +10 -9
  142. package/dist/entrypoints/tools.d.ts +0 -1
  143. package/dist/entrypoints/tools.d.ts.map +1 -1
  144. package/dist/entrypoints/tools.js +118 -53
  145. package/dist/entrypoints/tracking.js +2 -3
  146. package/dist/files/boundary.d.ts +2 -2
  147. package/dist/files/boundary.d.ts.map +1 -1
  148. package/dist/files/chunk-spool.d.ts.map +1 -1
  149. package/dist/files/file-io.d.ts +2 -2
  150. package/dist/files/file-io.d.ts.map +1 -1
  151. package/dist/files/native-packaging-layout.d.ts +50 -4
  152. package/dist/files/native-packaging-layout.d.ts.map +1 -1
  153. package/dist/files/native-packaging.d.ts +78 -17
  154. package/dist/files/native-packaging.d.ts.map +1 -1
  155. package/dist/{index-r5hsgkz5.js → index-0gs4ymfj.js} +6 -3
  156. package/dist/{index-zax7resm.js → index-0gxvns6s.js} +1 -13
  157. package/dist/index-0s4xebbg.js +8 -0
  158. package/dist/{index-r4r70zmh.js → index-12zsej7b.js} +5 -2
  159. package/dist/{index-269zqj8m.js → index-1ptj98e0.js} +28 -12
  160. package/dist/{index-kemm0ej5.js → index-1pwwan01.js} +65 -22
  161. package/dist/{index-vgkbcnkc.js → index-299sm5tr.js} +1 -1
  162. package/dist/{index-2vnh05w4.js → index-2k91mewf.js} +31 -74
  163. package/dist/{index-wh0ecvyk.js → index-37asdw3a.js} +1 -1
  164. package/dist/index-3h0ztg0z.js +285 -0
  165. package/dist/{index-g95fk660.js → index-4vsby8n8.js} +8 -15
  166. package/dist/index-556g5hsh.js +17 -0
  167. package/dist/{index-f330qqyg.js → index-5c26631f.js} +244 -67
  168. package/dist/{index-adhgd4pe.js → index-5p55xreg.js} +2 -2
  169. package/dist/index-5w6t91ze.js +47 -0
  170. package/dist/{index-9pw0a51a.js → index-6yxhe58g.js} +40 -7
  171. package/dist/{index-6d9xaxw1.js → index-8ks9b85e.js} +33 -5
  172. package/dist/{index-bhb950qs.js → index-916yh4e2.js} +25 -12
  173. package/dist/index-9tqbxv5p.js +44 -0
  174. package/dist/{index-5csmzesf.js → index-azx12jgv.js} +4 -3
  175. package/dist/{index-mbnnw3f2.js → index-b0kddvzw.js} +15 -5
  176. package/dist/{index-n5yqxd3d.js → index-b0w7rbpt.js} +23 -2
  177. package/dist/index-b56nnscm.js +132 -0
  178. package/dist/{index-0ndk4555.js → index-c0hffcmj.js} +2 -2
  179. package/dist/{index-pptyv13k.js → index-c17xcx4k.js} +42 -6
  180. package/dist/index-cazts87s.js +105 -0
  181. package/dist/{index-g2j7pnak.js → index-cmzvhhtd.js} +5 -2
  182. package/dist/{index-ssmd41kh.js → index-d2h99n7d.js} +1 -1
  183. package/dist/{index-z94wht4y.js → index-dky0dcmf.js} +34 -5
  184. package/dist/index-drs41arz.js +455 -0
  185. package/dist/{index-za6j7nwy.js → index-dsnjzb62.js} +104 -51
  186. package/dist/index-eemvahkc.js +21 -0
  187. package/dist/{index-fa4wg312.js → index-f199nfq5.js} +10 -6
  188. package/dist/{index-ck71tbcf.js → index-fsw1ybf3.js} +11 -15
  189. package/dist/{index-fk18k56k.js → index-gr5g3xfw.js} +11 -18
  190. package/dist/{index-jn9g8xdt.js → index-hjvje0pf.js} +6 -4
  191. package/dist/index-j4zh647a.js +59 -0
  192. package/dist/{index-x928baz2.js → index-j9gxbztg.js} +18 -14
  193. package/dist/index-kfjkb396.js +37 -0
  194. package/dist/{index-6drst9sg.js → index-ksfagmyz.js} +45 -345
  195. package/dist/index-m616f0yz.js +120 -0
  196. package/dist/{index-fm1c1a08.js → index-m6w6jtda.js} +40 -21
  197. package/dist/{index-bakgedh8.js → index-msfpyy2f.js} +2 -4
  198. package/dist/{index-ywppsaby.js → index-n1nszyk0.js} +23 -34
  199. package/dist/{index-v14qqmys.js → index-n4689krb.js} +1 -1
  200. package/dist/{index-a0zzh8ak.js → index-pz3y6b6g.js} +3 -3
  201. package/dist/{index-43p08g7t.js → index-pzb63z66.js} +12 -8
  202. package/dist/{index-h97tqqp1.js → index-qaet40b2.js} +5 -3
  203. package/dist/{index-t1sr4aks.js → index-qaqbdm7s.js} +52 -6
  204. package/dist/{index-77nxk6ay.js → index-r393tnfp.js} +16 -10
  205. package/dist/{index-kb8styz3.js → index-rpzewktb.js} +15 -5
  206. package/dist/{index-27a2pj09.js → index-sj28htvf.js} +1 -1
  207. package/dist/{index-hbd32c6a.js → index-w8etpm8j.js} +38 -89
  208. package/dist/{index-2hyavjjj.js → index-wbhdzxar.js} +3 -3
  209. package/dist/{index-4e0ah203.js → index-wdy68sh6.js} +47 -24
  210. package/dist/{index-hp9d77wk.js → index-x7w1z6pf.js} +15 -4
  211. package/dist/{index-ptn0g0gj.js → index-y7k2cdgv.js} +21 -20
  212. package/dist/{index-20yvtn9a.js → index-yt7gyg5x.js} +1 -1
  213. package/dist/{index-cvda079a.js → index-yvfk3y36.js} +12 -2
  214. package/dist/{index-5z6jn897.js → index-z23rfxhj.js} +1 -1
  215. package/dist/internal/abort-race.d.ts +8 -2
  216. package/dist/internal/abort-race.d.ts.map +1 -1
  217. package/dist/internal/atomic-file.d.ts +55 -9
  218. package/dist/internal/atomic-file.d.ts.map +1 -1
  219. package/dist/internal/atomic-publication.d.ts +39 -4
  220. package/dist/internal/atomic-publication.d.ts.map +1 -1
  221. package/dist/internal/atomic-staging.d.ts +47 -0
  222. package/dist/internal/atomic-staging.d.ts.map +1 -0
  223. package/dist/internal/bounded-file-read.d.ts +19 -11
  224. package/dist/internal/bounded-file-read.d.ts.map +1 -1
  225. package/dist/internal/bounded-lines.d.ts.map +1 -1
  226. package/dist/internal/close-after.d.ts +11 -0
  227. package/dist/internal/close-after.d.ts.map +1 -0
  228. package/dist/internal/deadline.d.ts +10 -0
  229. package/dist/internal/deadline.d.ts.map +1 -1
  230. package/dist/internal/exclusive-lock-read.d.ts +10 -12
  231. package/dist/internal/exclusive-lock-read.d.ts.map +1 -1
  232. package/dist/internal/exclusive-lock.d.ts +2 -2
  233. package/dist/internal/exclusive-lock.d.ts.map +1 -1
  234. package/dist/internal/file-observation.d.ts +14 -0
  235. package/dist/internal/file-observation.d.ts.map +1 -0
  236. package/dist/internal/json-data.d.ts +22 -5
  237. package/dist/internal/json-data.d.ts.map +1 -1
  238. package/dist/internal/positive-integer.d.ts +9 -0
  239. package/dist/internal/positive-integer.d.ts.map +1 -0
  240. package/dist/internal/process-instance.d.ts +35 -5
  241. package/dist/internal/process-instance.d.ts.map +1 -1
  242. package/dist/internal/secure-fetch.d.ts.map +1 -1
  243. package/dist/internal/timers.d.ts +11 -0
  244. package/dist/internal/timers.d.ts.map +1 -0
  245. package/dist/internal/with-exclusive-lock.d.ts +5 -4
  246. package/dist/internal/with-exclusive-lock.d.ts.map +1 -1
  247. package/dist/observability/bounded-sink.d.ts.map +1 -1
  248. package/dist/primitives/canonical-json.d.ts +23 -2
  249. package/dist/primitives/canonical-json.d.ts.map +1 -1
  250. package/dist/primitives/delivery.d.ts.map +1 -1
  251. package/dist/primitives/index.d.ts +1 -1
  252. package/dist/primitives/index.d.ts.map +1 -1
  253. package/dist/primitives/money.d.ts.map +1 -1
  254. package/dist/process/cleanup.d.ts +7 -2
  255. package/dist/process/cleanup.d.ts.map +1 -1
  256. package/dist/process/command-lifetime.d.ts +6 -1
  257. package/dist/process/command-lifetime.d.ts.map +1 -1
  258. package/dist/process/command-owner.d.ts +1 -0
  259. package/dist/process/command-owner.d.ts.map +1 -1
  260. package/dist/process/command.d.ts +4 -0
  261. package/dist/process/command.d.ts.map +1 -1
  262. package/dist/process/contract.d.ts +68 -2
  263. package/dist/process/contract.d.ts.map +1 -1
  264. package/dist/process/group.d.ts +42 -3
  265. package/dist/process/group.d.ts.map +1 -1
  266. package/dist/process/launch.d.ts +12 -1
  267. package/dist/process/launch.d.ts.map +1 -1
  268. package/dist/process/terminate.d.ts +40 -0
  269. package/dist/process/terminate.d.ts.map +1 -0
  270. package/dist/react/query-client.d.ts.map +1 -1
  271. package/dist/realtime/rejection.d.ts.map +1 -1
  272. package/dist/server/contract-stream.d.ts.map +1 -1
  273. package/dist/server/handler-state.d.ts.map +1 -1
  274. package/dist/server/implement.d.ts.map +1 -1
  275. package/dist/server/request-body.d.ts +0 -1
  276. package/dist/server/request-body.d.ts.map +1 -1
  277. package/dist/server/unix-client.d.ts.map +1 -1
  278. package/dist/telegram/broadcast-delivery.d.ts.map +1 -1
  279. package/dist/telegram/broadcast-failure.d.ts +10 -2
  280. package/dist/telegram/broadcast-failure.d.ts.map +1 -1
  281. package/dist/telegram/operator-channel.d.ts.map +1 -1
  282. package/dist/telegram/screens/outcome.d.ts.map +1 -1
  283. package/dist/testing/surface-conformance.d.ts +1 -1
  284. package/dist/testing/surface-conformance.d.ts.map +1 -1
  285. package/dist/testing/surface-manifest.d.ts +0 -6
  286. package/dist/testing/surface-manifest.d.ts.map +1 -1
  287. package/dist/tools/agent.d.ts +1 -1
  288. package/dist/tools/agent.d.ts.map +1 -1
  289. package/dist/tools/cli/args.d.ts +1 -1
  290. package/dist/tools/cli/args.d.ts.map +1 -1
  291. package/dist/tools/cli/help.d.ts.map +1 -1
  292. package/dist/tools/cli/invoke.d.ts +2 -2
  293. package/dist/tools/cli/invoke.d.ts.map +1 -1
  294. package/dist/tools/cli/profile.d.ts.map +1 -1
  295. package/dist/tools/cli/publication-assets.d.ts.map +1 -1
  296. package/dist/tools/cli/publication-contract.d.ts +8 -0
  297. package/dist/tools/cli/publication-contract.d.ts.map +1 -1
  298. package/dist/tools/cli/publication-control.d.ts.map +1 -1
  299. package/dist/tools/cli/publication-storage.d.ts +23 -2
  300. package/dist/tools/cli/publication-storage.d.ts.map +1 -1
  301. package/dist/tools/cli/publication.d.ts +8 -1
  302. package/dist/tools/cli/publication.d.ts.map +1 -1
  303. package/dist/tools/connections/errors.d.ts +18 -6
  304. package/dist/tools/connections/errors.d.ts.map +1 -1
  305. package/dist/tools/connections/limits.d.ts +8 -2
  306. package/dist/tools/connections/limits.d.ts.map +1 -1
  307. package/dist/tools/connections/mcp-client.d.ts.map +1 -1
  308. package/dist/tools/connections/mcp-envelope.d.ts.map +1 -1
  309. package/dist/tools/connections/openapi.d.ts.map +1 -1
  310. package/dist/tools/connections/schema-budget.d.ts +1 -1
  311. package/dist/tools/connections/schema-budget.d.ts.map +1 -1
  312. package/dist/tools/connections/sse-session.d.ts.map +1 -1
  313. package/dist/tools/execute-args.d.ts.map +1 -1
  314. package/dist/tools/execute-result.d.ts.map +1 -1
  315. package/dist/tools/internal/surface-projector.d.ts +17 -3
  316. package/dist/tools/internal/surface-projector.d.ts.map +1 -1
  317. package/dist/tools/internal/tool-error-projection.d.ts +16 -0
  318. package/dist/tools/internal/tool-error-projection.d.ts.map +1 -0
  319. package/dist/tools/internal/tool-view.d.ts.map +1 -1
  320. package/dist/tools/invoker.d.ts.map +1 -1
  321. package/dist/tools/list-names.d.ts +3 -2
  322. package/dist/tools/list-names.d.ts.map +1 -1
  323. package/dist/tools/manifest.d.ts +3 -2
  324. package/dist/tools/manifest.d.ts.map +1 -1
  325. package/dist/tools/mcp/handler.d.ts +7 -0
  326. package/dist/tools/mcp/handler.d.ts.map +1 -1
  327. package/dist/tools/mcp/mount.d.ts +18 -2
  328. package/dist/tools/mcp/mount.d.ts.map +1 -1
  329. package/dist/tools/mcp/prepare.d.ts +3 -3
  330. package/dist/tools/mcp/prepare.d.ts.map +1 -1
  331. package/dist/tools/mcp/register.d.ts.map +1 -1
  332. package/dist/tools/mcp/runtime-tools.d.ts.map +1 -1
  333. package/dist/tools/mcp/stdio-signals.d.ts +14 -0
  334. package/dist/tools/mcp/stdio-signals.d.ts.map +1 -1
  335. package/dist/tools/mcp/stdio.d.ts +7 -0
  336. package/dist/tools/mcp/stdio.d.ts.map +1 -1
  337. package/dist/tools/operations/async-operation-runtime-tools.d.ts.map +1 -1
  338. package/dist/tools/operations/async-operation-runtime-types.d.ts +3 -3
  339. package/dist/tools/operations/async-operation-runtime-types.d.ts.map +1 -1
  340. package/dist/tools/operations/define-wait-tool.d.ts +1 -1
  341. package/dist/tools/operations/define-wait-tool.d.ts.map +1 -1
  342. package/dist/tools/operations/wait-core.d.ts +0 -6
  343. package/dist/tools/operations/wait-core.d.ts.map +1 -1
  344. package/dist/tools/registry.d.ts +1 -1
  345. package/dist/tools/registry.d.ts.map +1 -1
  346. package/dist/tools/remote.d.ts +1 -1
  347. package/dist/tools/remote.d.ts.map +1 -1
  348. package/dist/tools/{runtime-tool-execution.d.ts → runtime-tool-declaration.d.ts} +32 -9
  349. package/dist/tools/runtime-tool-declaration.d.ts.map +1 -0
  350. package/dist/tools/runtime-tool-mcp.d.ts +6 -15
  351. package/dist/tools/runtime-tool-mcp.d.ts.map +1 -1
  352. package/dist/tools/runtime-tool.d.ts +14 -12
  353. package/dist/tools/runtime-tool.d.ts.map +1 -1
  354. package/dist/tools/schema/coerce.d.ts +4 -0
  355. package/dist/tools/schema/coerce.d.ts.map +1 -1
  356. package/dist/tools/schema/flatten-join.d.ts.map +1 -1
  357. package/dist/tools/surface.d.ts +7 -11
  358. package/dist/tools/surface.d.ts.map +1 -1
  359. package/dist/tools/transfer/define-download-tool.d.ts +1 -1
  360. package/dist/tools/transfer/define-download-tool.d.ts.map +1 -1
  361. package/dist/tools/transfer/define-upload-tool.d.ts +1 -1
  362. package/dist/tools/transfer/define-upload-tool.d.ts.map +1 -1
  363. package/dist/tools/transfer/define-view-file-tool.d.ts +1 -1
  364. package/dist/tools/transfer/define-view-file-tool.d.ts.map +1 -1
  365. package/dist/tools/transfer/managed-file-error.d.ts.map +1 -1
  366. package/dist/tools/transfer/view-file-contract.d.ts.map +1 -1
  367. package/dist/tools/transfer/view-file.d.ts +1 -1
  368. package/dist/tools/transfer/view-file.d.ts.map +1 -1
  369. package/dist/tools/transports.d.ts +3 -2
  370. package/dist/tools/transports.d.ts.map +1 -1
  371. package/llms/agent-runtime-browser.txt +10 -4
  372. package/llms/agent-runtime-harness.txt +32 -31
  373. package/llms/agent-runtime-react.txt +1 -1
  374. package/llms/agent-runtime-realtime.txt +14 -5
  375. package/llms/agent-runtime-sandbox.txt +3 -11
  376. package/llms/agent-runtime.3.txt +2 -2
  377. package/llms/agent-runtime.txt +0 -9
  378. package/llms/application.2.txt +3 -12
  379. package/llms/application.3.txt +7 -4
  380. package/llms/application.txt +44 -15
  381. package/llms/cli-publish.txt +29 -0
  382. package/llms/cli.2.txt +9 -11
  383. package/llms/cli.txt +26 -14
  384. package/llms/declaration.txt +0 -9
  385. package/llms/files-packaging.txt +18 -8
  386. package/llms/files.txt +4 -2
  387. package/llms/geo.txt +0 -9
  388. package/llms/live.txt +4 -13
  389. package/llms/observability.txt +31 -5
  390. package/llms/primitives.txt +38 -20
  391. package/llms/process.txt +324 -160
  392. package/llms/react-keyboard.txt +0 -9
  393. package/llms/react.txt +0 -18
  394. package/llms/server.4.txt +1 -1
  395. package/llms/server.5.txt +1 -1
  396. package/llms/server.txt +1 -1
  397. package/llms/stitchkit.txt +6 -7
  398. package/llms/telegram-screens.txt +2 -2
  399. package/llms/testing.txt +0 -1
  400. package/llms/tools-mcp.txt +2 -3
  401. package/llms/tools.2.txt +12 -0
  402. package/llms/tools.3.txt +5 -6
  403. package/llms/tools.txt +6 -4
  404. package/llms/upgrading-0.37.0-0.50.0.txt +947 -0
  405. package/llms/{upgrading-0.44.0-0.61.0.txt → upgrading-0.53.0-0.67.0.txt} +576 -506
  406. package/llms/{upgrading-0.62.0-0.80.0.txt → upgrading-0.68.0-0.94.0.txt} +562 -576
  407. package/llms/{upgrading-0.81.0-0.104.0.txt → upgrading-0.95.0-0.105.0.txt} +452 -567
  408. package/llms/upgrading.txt +4 -4
  409. package/llms-full.txt +1068 -412
  410. package/llms.txt +24 -24
  411. package/native-assets.json +11 -3
  412. package/package.json +6 -6
  413. package/dist/agent-runtime/harness-tools.d.ts +0 -11
  414. package/dist/agent-runtime/harness-tools.d.ts.map +0 -1
  415. package/dist/entrypoints/agent-runtime/harness-tools.d.ts +0 -2
  416. package/dist/entrypoints/agent-runtime/harness-tools.d.ts.map +0 -1
  417. package/dist/entrypoints/agent-runtime/harness-tools.js +0 -32
  418. package/dist/index-1a6jtnd9.js +0 -88
  419. package/dist/index-8a9ksm91.js +0 -95
  420. package/dist/index-a3wma1hk.js +0 -48
  421. package/dist/index-jd470k6q.js +0 -109
  422. package/dist/index-n1dqr7gf.js +0 -20
  423. package/dist/index-nggfa2yn.js +0 -34
  424. package/dist/index-s4evrmp5.js +0 -98
  425. package/dist/index-ze1eph1k.js +0 -20
  426. package/dist/tools/connections/error-projection.d.ts +0 -4
  427. package/dist/tools/connections/error-projection.d.ts.map +0 -1
  428. package/dist/tools/runtime-tool-execution.d.ts.map +0 -1
  429. package/llms/agent-runtime-harness-tools.txt +0 -25
  430. package/llms/upgrading-0.37.0-0.44.0.txt +0 -444
package/llms/process.txt CHANGED
@@ -9,37 +9,25 @@ Contains: Guide: Native IO (docs/guide/native-io.md) · API reference: `stitchk
9
9
  # Guide: Native IO (docs/guide/native-io.md)
10
10
  ==============================================================================
11
11
 
12
- ---
13
- title: Конечные команды и файловые гарантии
14
- description: Native IO для Bun и Node, с явно выбранной durability, безопасными bounds и caller lifetime.
15
- type: guide
16
- status: active
17
- created: 2026-10-01 20:44 +07:00
18
- updated: 2026-10-04 20:04 +07:00
19
- participants:
20
- - role: authored
21
- harness: Codex
22
- model: GPT-6
23
- at: 2026-10-01 20:44 +07:00
24
- - role: implemented
25
- harness: Codex
26
- model: GPT-6
27
- at: 2026-10-02 00:08 +07:00
28
- - role: implemented
29
- harness: Codex
30
- model: GPT-6
31
- at: 2026-10-03 13:36 +07:00
32
- - role: implemented
33
- harness: Codex
34
- model: GPT-6
35
- at: 2026-10-04 09:21 +07:00
36
- ---
37
-
38
12
  # Native IO
39
13
 
40
- Примеры используют публичные imports и одинаково исполняются в Bun и Node ≥22.
14
+ Shortest working example: publish a file atomically, then run one bounded command.
41
15
 
42
- ## Запись файла
16
+ ```ts
17
+ import { writeFileAtomic } from 'stitchkit/files'
18
+ import { runNativeCommand } from 'stitchkit/process'
19
+
20
+ await writeFileAtomic('/srv/app/state.json', '{"version":2}')
21
+ const { exitCode, stdout } = await runNativeCommand({
22
+ executable: '/usr/bin/git', args: ['rev-parse', 'HEAD'], cwd: '/srv/app',
23
+ capture: true, maxOutputBytes: 4096, timeoutMs: 5000,
24
+ })
25
+ console.log(exitCode, new TextDecoder().decode(stdout))
26
+ ```
27
+
28
+ The examples use public imports and run the same in Bun and Node >= 22.
29
+
30
+ ## Writing a file
43
31
 
44
32
  ```ts
45
33
  import { writeFileAtomic, AtomicFilePublicationError } from 'stitchkit/files'
@@ -52,7 +40,7 @@ try {
52
40
  })
53
41
  } catch (error) {
54
42
  if (error instanceof AtomicFilePublicationError) {
55
- // target уже виден. Проверьте receipt, прежде чем решать о повторе.
43
+ // The target is already visible. Check the receipt before deciding whether to retry.
56
44
  console.error(error.phase, error.cause)
57
45
  } else throw error
58
46
  }
@@ -61,25 +49,51 @@ await writeFileAtomic('/srv/app/state.json', '{"version":2}', {
61
49
  })
62
50
  ```
63
51
 
64
- По умолчанию `replace: true`, `durability: 'file'`, `mode: 0o600`: existing вызовы сохраняют
65
- file-fsync и atomic replacement. `durability: 'none'` отключает sync; `'directory'` выполняет
66
- полную запись → exact descriptor chmod → file fsync → rename (replace) либо link (create) →
67
- удаление staging link → parent fsync. `writeFileAtomicSync` имеет те же options и порядок.
68
- Create отказывает с native `EEXIST` при существующем файле, symlink или concurrent winner.
69
- Никогда не переводите этот отказ в replace автоматически.
52
+ The defaults are `replace: true`, `durability: 'file'` and `mode: 0o600`: file fsync and atomic
53
+ replacement. `durability: 'none'` skips every sync. `'directory'` runs the full sequence: write all
54
+ bytes, exact descriptor chmod, file fsync, rename (replace) or link (create), remove the staging
55
+ link, parent directory fsync. `writeFileAtomicSync` takes the same options and runs the same order.
56
+ Create fails with the native `EEXIST` when the target exists, is a symlink, or a concurrent writer
57
+ won. Never turn that refusal into a replace automatically.
58
+
59
+ `AtomicFilePublicationError.published === true` tells a visible target from an unconfirmed
60
+ acknowledgement. `phase` is `cleanup`, `directory-sync` or `directory-close`; the primary cause is
61
+ kept in `cause`. An error before publication leaves the previous target untouched. Cleanup errors are
62
+ secondary to the primary error. While a create is in flight a second hardlink briefly exists, so a
63
+ strict single-link reader may refuse in that window.
70
64
 
71
- `AtomicFilePublicationError.published === true` отличает видимость от неподтверждённого
72
- acknowledgement. `phase` — `cleanup`, `directory-sync` или `directory-close`; первичная причина
73
- сохранена в `cause`. Ошибка до publish оставляет прежний target. Cleanup вторичен к первичной ошибке.
74
- При create кратко существует второй hardlink; strict single-link reader вправе отказать в этом окне.
65
+ ### Abandoned staging files
75
66
 
76
- Directory fsync — native POSIX/filesystem capability. Windows явно отказывает; иной filesystem
77
- может отказать при open/sync. Проверка на Linux не подтверждает поведение macOS, сетевой FS или
78
- сохранность при отключении питания. Состояние диска определяется гарантиями самой FS/ОС.
79
- `createManagedFileBoundary.write(..., { durable: true })` использует тот же publish owner и parent sync;
80
- его create по умолчанию остаётся create, а `replace: true` явно разрешает replacement.
67
+ The bytes are staged beside the target under `.stitchkit-<24 lowercase hex>.tmp`, the same name for
68
+ `writeFileAtomic`, `writeFileAtomicSync`, the managed writer and the chunk spool. A process killed
69
+ between the staging and the publication (SIGKILL, OOM, power loss) leaves that file behind, and no
70
+ later write removes it: a random name alone cannot tell an abandoned write from one in flight.
71
+ Removing it is the caller's responsibility. A directory that does not exist yet has nothing to
72
+ sweep and yields `[]`; a file standing where the directory should be, or a denied listing, throws:
81
73
 
82
- ## Строгое чтение
74
+ ```ts
75
+ import { isAtomicStagingName, sweepAtomicStaging } from 'stitchkit/files'
76
+
77
+ // At startup, or before trusting that a directory holds only your own records:
78
+ const removed = await sweepAtomicStaging({ directory: '/srv/app/registry', olderThanMs: 60 * 60_000 })
79
+
80
+ // Skip staging files when listing a directory of your records:
81
+ const records = (await readdir('/srv/app/registry')).filter((name) => !isAtomicStagingName(name))
82
+ ```
83
+
84
+ `olderThanMs` is required and must exceed the longest write in flight; a younger staging file is
85
+ left alone. The sweep removes only regular files, never follows a symlink and never enters a
86
+ subdirectory. The name form is a stable public contract: changing it is a breaking change of
87
+ `stitchkit/files`. An exclusive lock's `.lock-*.tmp` file is not an atomic-write staging file and
88
+ does not match.
89
+
90
+ Directory fsync is a native POSIX filesystem capability. Windows refuses it explicitly, and another
91
+ filesystem may refuse at open or sync. A check on Linux does not confirm macOS behavior, network
92
+ filesystems or survival of a power loss; the disk state is whatever the filesystem and OS guarantee.
93
+ `createManagedFileBoundary.write(..., { durable: true })` uses the same publish owner and parent sync;
94
+ its create stays a create, and `replace: true` allows replacement explicitly.
95
+
96
+ ## Strict reads
83
97
 
84
98
  ```ts
85
99
  import { createManagedFileBoundary } from 'stitchkit/files'
@@ -90,25 +104,27 @@ const source = await files.read('receipt.json', {
90
104
  })
91
105
  console.log(source.observation) // dev, ino, size, nlink, mtimeMs, ctimeMs
92
106
  const receipt = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(source.bytes))
93
- // schema.parse(receipt) и проверка digest принадлежат приложению.
107
+ // Schema parsing and digest checks belong to the application.
94
108
  ```
95
109
 
96
- Без новых options ответ сохраняет `{ ref, bytes }`, допускает trusted in-root symlink и hardlink.
97
- `rejectSymlinks` запрещает requested leaf, `singleLink` проверяет `nlink` открытого descriptor,
98
- `stable` сравнивает dev/ino/size/mtime/ctime/nlink вокруг byte read; `observe` добавляет metadata.
99
- `FILE_NOT_FOUND`, `FILE_NOT_REGULAR`, `FILE_UNSAFE_LINK`, `FILE_TOO_LARGE`, `FILE_CHANGED`,
100
- `FILE_UNSUPPORTED` и `FILE_IO_ERROR` различаются. Abort сохраняет caller reason.
101
- Nonblocking open позволяет отказать FIFO без ожидания writer. Bytes ограничены во время чтения,
102
- включая рост файла, не только initial stat. Chunk allocation ≤ maxBytes+1+64 KiB, flatten ≤ maxBytes;
103
- FD закрывается при success, отказе, abort и IO error.
104
- Ошибка close сохраняет первичную ошибку чтения; после успешного чтения ошибка close возвращается caller.
105
-
106
- Root и ancestors принадлежат trusted actor. Эти options не дают descriptor-relative containment
107
- при hostile concurrent ancestor replacement. Отдельного переключателя «считать ancestors безопасными»
108
- нет: portable owner не предоставляет такую capability. Metadata stability не доказывает immutable
109
- snapshot против произвольного hostile writer; используйте application lock/immutable publication.
110
-
111
- ## Команды
110
+ Without options the result is `{ ref, bytes }` and a trusted in-root symlink or hardlink is
111
+ allowed. `rejectSymlinks` refuses a symlink at the requested leaf, `singleLink` checks `nlink` of
112
+ the opened descriptor, `stable` compares dev/ino/size/mtime/ctime/nlink around the byte read, and
113
+ `observe` adds the metadata. These refusals are distinct: `FILE_NOT_FOUND`, `FILE_NOT_REGULAR`,
114
+ `FILE_UNSAFE_LINK`, `FILE_TOO_LARGE`, `FILE_CHANGED`, `FILE_UNSUPPORTED` and `FILE_IO_ERROR`. Abort
115
+ keeps the caller's reason. A nonblocking open lets a FIFO be refused without waiting for a writer.
116
+ Bytes are bounded while reading, including a file that grows, not only by the initial stat. Chunk
117
+ allocation is at most `maxBytes + 1 + 64 KiB` and the flattened result at most `maxBytes`. The
118
+ descriptor closes on success, refusal, abort and IO error. A close error keeps the primary read error;
119
+ after a successful read a close error is returned to the caller.
120
+
121
+ The root and its ancestors belong to a trusted actor. These options do not give
122
+ descriptor-relative containment against a hostile concurrent ancestor replacement, and there is no
123
+ switch to treat ancestors as safe: the portable owner has no such capability. Metadata stability does
124
+ not prove an immutable snapshot against an arbitrary hostile writer; use an application lock or
125
+ immutable publication.
126
+
127
+ ## Commands
112
128
 
113
129
  ```ts
114
130
  import { runNativeCommand } from 'stitchkit/process'
@@ -130,21 +146,23 @@ await runNativeCommand({
130
146
  })
131
147
  ```
132
148
 
133
- Команда требует caller signal или finite `timeoutMs` (1–2147483647 ms: native timer range; большее значение отказывается, не превращается в 1 ms). Streaming имеет caller lifetime, без скрытого
134
- 60-second timeout или 1-MiB output limit. `capture` по умолчанию false; true требует
135
- `maxOutputBytes` для суммарных stdout+stderr. Лимит считает исходные bytes; API возвращает
136
- `Uint8Array`, не преобразует invalid UTF-8. Result содержит наблюдаемый `exitCode: number | null`
137
- и `signal: string | null`; signal termination не превращается в выдуманный exit code. `maxOutputBytes` может ограничивать и streaming.
138
- `stdin` — bytes с `maxStdinBytes` (default 1 MiB). `envPolicy` default `declared-only`: отсутствие env
139
- означает пустой environment; `ambient` явно разрешает наследование. Cwd/executable policy остаётся
140
- приложению; этот primitive запускает native executable и сам не создаёт shell.
141
-
142
- Машинная классификация limit error использует `NativeCommandError.reason`: `deadline` при
143
- истечении собственного `timeoutMs`, `output-budget` при превышении суммарных bytes stdout+stderr
144
- в capture или streaming. Оба случая сохраняют `code: 'COMMAND_LIMIT'`; `message` служит
145
- диагностике, не протоколу. У `COMMAND_UNAVAILABLE` и `COMMAND_CLEANUP` reason отсутствует;
146
- caller abort и sink failure сохраняют исходную ошибку. При cleanup failure первоначальный
147
- limit вместе с reason остаётся внутри `AggregateError` cause.
149
+ A command needs a caller `signal` or a finite `timeoutMs` (1 to 2147483647 ms, the native timer
150
+ range; a larger value is refused, never turned into 1 ms). Streaming runs for the caller's lifetime,
151
+ with no hidden 60-second timeout or 1 MiB output limit. `capture` defaults to false; `true` requires
152
+ `maxOutputBytes` for the combined stdout and stderr. The limit counts source bytes; the API returns
153
+ `Uint8Array` and does not decode invalid UTF-8. The result holds the observed `exitCode: number | null`
154
+ and `signal: string | null`; a signal termination is never turned into an invented exit code.
155
+ `maxOutputBytes` may bound streaming too. `stdin` is bytes bounded by `maxStdinBytes` (default 1 MiB).
156
+ `envPolicy` defaults to `declared-only`: no `env` means an empty environment, and `ambient` inherits
157
+ explicitly. The application owns cwd and executable policy; the primitive launches a native
158
+ executable and never creates a shell.
159
+
160
+ `NativeCommandError.reason` classifies a limit error by machine: `deadline` when the command's own
161
+ `timeoutMs` expires, `output-budget` when the combined stdout and stderr bytes exceed the limit, in
162
+ capture or streaming. Both keep `code: 'COMMAND_LIMIT'`; `message` is for diagnosis, not for
163
+ protocols. `COMMAND_UNAVAILABLE` and `COMMAND_CLEANUP` have no reason. A caller abort and a sink
164
+ failure keep the original error. When cleanup fails, the original limit and its reason stay inside the
165
+ `AggregateError` cause.
148
166
 
149
167
  ```ts
150
168
  import { NativeCommandError } from 'stitchkit/process'
@@ -160,38 +178,137 @@ try {
160
178
  }
161
179
  ```
162
180
 
163
- Конструктор сохраняет вызов `new NativeCommandError(code, message, { cause })` и принимает
164
- `{ cause, reason: 'deadline' | 'output-budget' }` только для `COMMAND_LIMIT`. Owner всегда
165
- заполняет reason для собственных limits. Созданная вызывающей стороной ошибка без reason
166
- не получает выдуманную причину из текста; её reason остаётся `undefined`.
167
-
168
- Вывод читается с backpressure отдельно для stdout/stderr: один выполняющийся sink на канал плюс
169
- bounded native Readable buffer; накопления всей истории при streaming нет. Callback получает
170
- lifetime signal. Abort освобождает ожидание даже игнорирующего signal callback, но не способен
171
- отменить сторонние действия, которые сам callback продолжит после abort. Sink обязан отменять свои
172
- IO, не сохранять бесконечную историю и не изменять shared descriptor flags. После abort новых
173
- callbacks owner не запускает. Normal completion ждёт всех bytes и sinks.
174
-
175
- Cleanup: POSIX process group, TERM, `killGraceMs` (default 100, maximum 10 000), затем KILL;
176
- `cleanupTimeoutMs` (default 2000, maximum 30 000) ограничивает ожидание close после сигналов.
177
- На Darwin временный `EPERM` при сигнале группе может означать zombies, ещё не убранные
178
- OS reaper. Повтор ограничен `cleanupTimeoutMs`; успех требует доставленного сигнала или
179
- `ESRCH`, постоянный отказ сохраняется в cause. Закрытие каждого owned pipe и выход leader
180
- наблюдаются отдельно, включая отсутствие общего `child.close` при teardown.
181
- Сохраняется caller/sink причина; failure cleanup — `NativeCommandError` с `COMMAND_CLEANUP` и
182
- AggregateError cause. Даже вышедший parent не исключает helper, удерживающий pipe. Windows
183
- отказывает с `COMMAND_UNAVAILABLE`; потомок, самостоятельно покинувший группу через setsid,
184
- лежит за границей этой capability. Это one-shot execution, не PTY, supervisor или daemon host.
185
-
186
- ## Механическая адаптация
187
-
188
- Atomic file wrapper заменяется одним вызовом `writeFileAtomic` с выбранными options. Bounded
189
- regular-file read заменяется `files.read`; JSON/schema, receipt conflicts, journal rotation и
190
- application locks сохраняются. Spawn/drain/capture/cancellation wrapper заменяется `runNativeCommand`;
191
- shell policy, command admission, логирование, redaction, bytes→text decoder и operator sink сохраняются.
192
- Длительные signal-only команды остаются streaming; bounded tar/capture получают свои явные limits.
193
- Импорт leaf не делает установку всего npm package маленькой; выбирайте dependency после измерения
194
- packed размера и dependency closure.
181
+ The constructor is `new NativeCommandError(code, message, { cause })`; it accepts
182
+ `{ cause, reason: 'deadline' | 'output-budget' }` only for `COMMAND_LIMIT`. The owner always sets the
183
+ reason for its own limits. An error a caller constructs without a reason gets none inferred from the
184
+ text; its `reason` is `undefined`.
185
+
186
+ Output is read with backpressure, stdout and stderr separately: one running sink per channel plus a
187
+ bounded native Readable buffer, with no accumulation of the whole history while streaming. The
188
+ callback receives the lifetime signal. Abort releases the wait even for a callback that ignores the
189
+ signal, but it cannot cancel third-party work the callback continues after the abort. A sink must
190
+ cancel its own IO, must not keep an unbounded history and must not change shared descriptor flags.
191
+ After an abort the owner starts no new callbacks. Normal completion waits for all bytes and sinks.
192
+
193
+ Cleanup uses the POSIX process group under the `stop` policy, then KILL; `cleanupTimeoutMs`
194
+ (default 2000, maximum 30 000) bounds the wait for close after the signals. On
195
+ Darwin a transient `EPERM` when signalling a group can mean zombies the OS reaper has not collected
196
+ yet. The retry is bounded by `cleanupTimeoutMs`; success needs a delivered signal or `ESRCH`, and a
197
+ permanent refusal is kept in the cause. The close of every owned pipe and the leader's exit are
198
+ observed separately, including the absence of a shared `child.close` during teardown. The caller or
199
+ sink cause is kept; a cleanup failure is a `NativeCommandError` with `COMMAND_CLEANUP` and an
200
+ `AggregateError` cause. Even an exited parent does not exclude a helper that holds a pipe. Windows
201
+ refuses with `COMMAND_UNAVAILABLE`; a descendant that has left the group on its own with `setsid` is
202
+ outside this capability. This is one-shot execution, not a PTY, a supervisor or a daemon host.
203
+
204
+ ### Stopping a command: the `stop` policy
205
+
206
+ A caller abort, the `timeoutMs` deadline, an exceeded output budget and a failing sink all stop the
207
+ command the same way, by its `stop` policy:
208
+
209
+ | field | meaning |
210
+ |---|---|
211
+ | `target` | `'group'`: `signal` goes to every member of the group. `'leader'`: `signal` goes to the leader alone; the leader's exit ends the grace at once. Required. |
212
+ | `signal` | `SIGTERM` (default), `SIGINT`, `SIGHUP`, `SIGQUIT`, `SIGUSR1` or `SIGUSR2`. KILL is not a stop signal: it is what the grace ends in. |
213
+ | `graceMs` | How long the leader (or the group) has to leave before the whole group gets KILL. 0 to 3 600 000 (one hour). Required. |
214
+ | `killOn` | Optional `AbortSignal`. Its abort stops the command with KILL to the whole group at once, also in the middle of a grace. |
215
+
216
+ Omitting `stop` means `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }`.
217
+
218
+ ```ts
219
+ // Cooperative cancellation: the leader rolls its work back, its helpers are not asked.
220
+ await runNativeCommand({
221
+ executable: '/usr/local/bin/migrate', args: ['apply'], signal: request.signal,
222
+ stop: { target: 'leader', signal: 'SIGINT', graceMs: 15 * 60_000, killOn: shutdown.signal },
223
+ })
224
+ ```
225
+
226
+ With `target: 'leader'` the rest of the group never receives the cooperative signal: they are
227
+ processes the leader started, and the leader decides what happens to them. Whatever is left in the
228
+ group when the leader exits, or when the grace ends, gets KILL, including a helper with its stdio
229
+ closed that no pipe would have revealed. A leader that has already exited is never signalled again.
230
+
231
+ The output pipes stay open until the stop sequence ends. Output a stopping command writes is read and
232
+ dropped, never passed to `onOutput` and never captured, so a leader that writes while it shuts down
233
+ does not meet a broken pipe. The result rejects with the abort reason once the group is gone and the
234
+ pipes are closed, so it can take `graceMs` plus `cleanupTimeoutMs` after the abort.
235
+
236
+ The grace is a timer inside the process that runs the command. If that process exits first, the
237
+ timer is gone and the group, which is detached into its own session, keeps running: nothing in this
238
+ package can bound it from outside. Abort `killOn` in your shutdown path, so the group is killed
239
+ before the process exits, and let the supervisor own the case where the process dies without a
240
+ shutdown. Under systemd, keep `KillMode=control-group` (the default) so the stop of the unit
241
+ reaches every process in its cgroup, whatever its process group; launchd only kills the job's own
242
+ process group, which a command's group is not.
243
+
244
+ ### Stopping a group and its descendants
245
+
246
+ A group is signalled only while the kernel still reports members. `ESRCH` from the first signal,
247
+ or from the existence probe that follows it during the grace, means no member is left: no KILL
248
+ is sent afterwards, because a numeric group id that has vanished can already belong to an
249
+ unrelated group. A group that is still visible after the grace period receives KILL.
250
+
251
+ `descendants` declares what happens to processes the leader left running once it has exited
252
+ successfully:
253
+
254
+ | `descendants` | After the leader exits |
255
+ |---|---|
256
+ | `'terminate-after-leader'` (the default) | The group is stopped right after `onLeaderSettled` returns and before the pipes drain: with `target: 'group'` by the same signal, grace, KILL sequence as cancellation; with `target: 'leader'` by KILL at once, since the leader has already exited. A descendant that had already left the group with `setsid` when the leader exited stays out of reach. |
257
+ | `'leave'` | Nothing. A helper started with its stdio detached keeps running. One that inherited stdout or stderr keeps the pipes open, and the command then waits for it until its deadline or abort. |
258
+
259
+ Omitting the option means `'terminate-after-leader'`: a command does not leak the helpers it
260
+ started. The result's `descendantsStopped` is `true` when the group still had members after the
261
+ leader exited and they were stopped, so a helper that was ended this way is visible to the caller
262
+ rather than only missing afterwards; under `'leave'` it is always `false`.
263
+
264
+ A real daemon detaches into its own session (`setsid`, as `daemon(3)` does), is no member of the
265
+ group and is unaffected, provided it has left the group **before the leader exits**. Leaving is
266
+ the daemon's own system call, and the group is stopped as soon as the leader's exit is observed,
267
+ so a helper started in the background races the leader:
268
+
269
+ | launched by the leader as | after the leader exits |
270
+ |---|---|
271
+ | `setsid -f helper` (returns once the new session exists) | survives |
272
+ | `setsid helper &`, `(setsid helper &)`, `nohup helper &` | stopped: the leader usually exits before the background job has left the group |
273
+ | any of these under `descendants: 'leave'` | survives |
274
+
275
+ Start a daemon so that the session exists before the leader returns (`setsid -f`, or the
276
+ daemon's own double fork followed by the leader waiting for it), or declare `'leave'`. Declare
277
+ `'leave'` only for a helper that has to outlive the command while staying in its group:
278
+
279
+ ```ts
280
+ await runNativeCommand({
281
+ executable: '/usr/local/bin/start-helper', timeoutMs: 60_000,
282
+ // the helper started here outlives this command on purpose
283
+ descendants: 'leave',
284
+ })
285
+ ```
286
+
287
+ A command whose group this package did not create (a structural
288
+ launcher supplied by a host) has no group to stop, and `descendants` has nothing to act on there.
289
+
290
+
291
+ ## Replacing hand-written wrappers
292
+
293
+ An atomic-file wrapper becomes one `writeFileAtomic` call with the chosen options. A bounded
294
+ regular-file read becomes `files.read`; JSON and schema parsing, receipt conflicts, journal rotation
295
+ and application locks stay with the application. A spawn, drain, capture and cancellation wrapper
296
+ becomes `runNativeCommand`; shell policy, command admission, logging, redaction, the bytes-to-text
297
+ decoder and the operator sink stay with the application. Long signal-only commands stay streaming;
298
+ bounded tar or capture commands get their own explicit limits.
299
+
300
+ A child the caller holds until it exits is the same call. A guardian that forwards its own SIGTERM
301
+ passes an abort signal and `stop: { target: 'leader', signal: 'SIGTERM', graceMs }`; it reads the
302
+ exit code in `onLeaderSettled`, before the pipes drain, and stderr through `onOutput` or `capture`
303
+ with `maxOutputBytes`, and `cleanupTimeoutMs` bounds the drain (`COMMAND_CLEANUP` when a holder
304
+ keeps the pipe past it). A worker whose whole group must stop on abort is the default
305
+ `target: 'group'`. A child that inherits the caller's terminal is outside this capability: every
306
+ command runs in a group of its own, and a background group that reads the terminal is stopped
307
+ by the kernel (`SIGTTIN`), so an interactive re-execution stays a plain spawn in the caller's
308
+ group. Importing one leaf does not make
309
+ installing the whole npm package smaller; choose a dependency after measuring packed size and its
310
+ dependency closure.
311
+
195
312
  ## Resource-scoped launchers and shared owners
196
313
 
197
314
  `onLeaderSettled(event, signal)` observes leader exit before inherited stdout/stderr pipes
@@ -233,8 +350,23 @@ syscall interruptible or provide a snapshot against a hostile writer.
233
350
  An exclusive lock applies exact requested permissions through its creating descriptor,
234
351
  independent of umask. Default `0600` stays private. Shared `0640` requires a common group and
235
352
  traversable directories; another UID also needs directory write permission to reclaim a
236
- proven-dead owner's file. Set `ownerlessGraceMs: null` to refuse every age-only reclaim,
237
- including ownerless reclaim guards. The default remains 5000 ms for existing clients.
353
+ proven-dead owner's file.
354
+
355
+ The lock is published with its owner already recorded: the owner record is written to a
356
+ private temporary file in the lock's directory, then hard-linked to the lock name. `link`
357
+ fails with `EEXIST` for every caller but one, and the name never exists without a complete
358
+ record, so a holder that stalls or dies before publishing leaves no lock and cannot be
359
+ displaced. The directory must therefore be on a filesystem that supports hard links. A crash
360
+ between the temporary write and the link can leave a `.lock-*.tmp` file behind; it is not a
361
+ lock and nothing waits on it.
362
+
363
+ `ownerlessGraceMs` defaults to `null`: a lock file with no readable owner is never taken
364
+ because of its age. This library does not produce such a file; only a writer that creates the name
365
+ before its owner record can leave one (for example an empty file from a crashed process).
366
+ `ownerlessGraceMs: <ms>` opts in to reclaiming an empty lock file older than that, and also governs
367
+ abandoned empty reclaim guards.
368
+ When unset, an empty reclaim guard left by an older writer is taken after 5 000 ms so recovery
369
+ is never disabled for good; `null` refuses that too.
238
370
  Stale reclaim guards use the same lock owner and a child guard for the inode check and
239
371
  unlink. Recovery depth is capped at 16; a deeper stale chain refuses recovery with a depth diagnosis retained as the cause of
240
372
  the bounded `LOCK_TIMEOUT`. Live owners, unknown process-lifetime evidence and unsafe records are never
@@ -260,27 +392,26 @@ version: carry their reachable relative `.d.ts` closure, rather than emitting re
260
392
  instead emit declarations for only that DTO contract. Keep the library's manifest at runtime
261
393
  `dependencies: {}` and `peerDependencies: { zod: ... }` when that is its declared promise.
262
394
 
263
- The packaged Darwin loader has static references to both architecture addons. Bun compilation
264
- embeds the matching `.node` asset; ordinary Bun bundling emits native assets alongside its JS
265
- output. Publish **every output returned by `Bun.build`**, preserving relative paths. Copying only
266
- the JS file drops its native dependency. No runtime Stitchkit installation or manually chosen
267
- native path is required for these bundled artifacts.
395
+ The packaged Darwin loader names its addons by a path computed at run time, so a bundler
396
+ never follows it: bundling `stitchkit/server`, `stitchkit/files` or `stitchkit/process` yields
397
+ the same single JS file on every operating system, with no `.node` output, and
398
+ `bun build --outfile` works. Such a bundle looks for the addon beside the original package
399
+ files, never inside itself. Where that file is absent (an artifact moved to another machine)
400
+ the Darwin backend is `unavailable`: process identity cannot be recorded, so a lock held by a
401
+ crashed owner is not reclaimed. An artifact that must carry the Darwin addon uses the packaging
402
+ plugin of the next section; it is the only way a static loader enters a bundle.
268
403
 
269
404
  ```sh
270
- bun build src/native.ts --target=bun --minify --outdir=dist
271
- bun build src/native.ts --compile --bytecode --format=esm --outfile=dist/native
405
+ bun build src/native.ts --target=bun --minify --outfile=dist/native.js
272
406
  ```
273
407
 
274
- For a JS build that previously used `--outfile=dist/native.js`, use
275
- `--outdir=dist --entry-naming=native.js` instead: the output can now include native assets.
276
- The standalone executable still uses `--outfile` because those assets are embedded inside it.
277
-
278
408
  Qualify the complete output outside its build tree and installed dependency graph. Test process
279
- identity, live-owner refusal, dead-owner recovery and contained file operations in the resulting
280
- JS bundle and standalone executable. Bun and Node package imports retain the same lazy loader;
281
- importing a portable leaf does not load a Darwin addon on another OS. Test declarations too,
282
- and check that importing an unbundled Stitchkit leaf fails in a deliberately isolated library
283
- distribution. A separate schema-only entry must not import the native entry.
409
+ identity, live-owner refusal, dead-owner recovery and contained file operations in artifacts built
410
+ with the packaging plugin, and check that an unpackaged build reports the backend `unavailable`
411
+ rather than certifying a dead owner. Bun and Node package imports retain the same
412
+ lazy loader; importing a portable leaf does not load a Darwin addon on another OS. Test
413
+ declarations too, and check that importing an unbundled Stitchkit leaf fails in a deliberately
414
+ isolated library distribution. A separate schema-only entry must not import the native entry.
284
415
 
285
416
  If the Darwin backend cannot load, `observeProcessInstance` still returns `unavailable`.
286
417
  Its backend `Error` preserves the original `cause`; JSON serialization carries only the stable
@@ -296,17 +427,21 @@ Stitchkit installation or create an independent lightweight npm package.
296
427
  ## Public native packaging
297
428
 
298
429
  Custom archives and installers use `stitchkit/files/packaging` at **build time**.
299
- `createNativePackaging` resolves the installed version and target addon with its original SHA256;
300
- its Bun-compatible plugin integrates that asset with the same lazy native loader.
430
+ `createNativePackaging` resolves the installed version and target addon, reads the addon once and
431
+ checks it against the size and SHA256 that Stitchkit published in its `native-assets.json` when the
432
+ package was built. A ready asset carries those verified `bytes` with the published `size` and
433
+ `sha256`; its Bun-compatible plugin integrates the same bytes with the same lazy native loader.
434
+ Each call reads and hashes the selected addons, so call it once per build and reuse the result.
301
435
  The leaf is evolving. It requires no optional peer or Bun ambient declarations for Node imports.
302
- It must run unbundled from its installed package, never from an application's runtime artifact.
303
- This contract is available from 0.104.1; versions 0.103.13–0.104.0 use the complete-output recipe
304
- in the previous section.
436
+ Calling it must happen in a process that runs it from its installed package: it locates the
437
+ package's `native-assets.json` beside its own file and throws `Native packaging must run from its
438
+ installed Stitchkit package` anywhere else, such as inside an application's runtime artifact.
439
+ Importing the leaf is side-effect free (it loads no addon and reads no file), so a module that
440
+ both builds and is bundled may import it; only the call has to stay in the build step.
305
441
 
306
442
  ```ts
307
443
  import { createNativePackaging } from 'stitchkit/files/packaging'
308
- import { createHash } from 'node:crypto'
309
- import { copyFileSync, mkdirSync, readFileSync } from 'node:fs'
444
+ import { mkdirSync, writeFileSync } from 'node:fs'
310
445
  import { dirname, join } from 'node:path'
311
446
 
312
447
  const native = createNativePackaging({
@@ -320,28 +455,33 @@ const result = await Bun.build({
320
455
  plugins: [native.plugin],
321
456
  })
322
457
  if (!result.success) throw new AggregateError(result.logs, 'Build failed')
323
- // Preserve every result.outputs file under dist, then add the selected companion.
458
+ // Preserve every result.outputs file under dist, then write the verified companion bytes.
324
459
  for (const asset of native.assets) {
325
- const bytes = readFileSync(asset.sourcePath)
326
- if (createHash('sha256').update(bytes).digest('hex') !== asset.sha256)
327
- throw new Error('Native asset changed during build')
328
460
  const destination = join('dist', asset.outputPath)
329
461
  mkdirSync(dirname(destination), { recursive: true })
330
- copyFileSync(asset.sourcePath, destination)
462
+ writeFileSync(destination, asset.bytes)
331
463
  }
332
464
  ```
333
465
 
334
466
  `entryPath` and `assetPath` are relative paths inside the application's output root, without
335
- absolute paths, traversal or overlapping file/directory paths. `entryPath` is fixed, without
467
+ absolute paths, traversal or overlapping file/directory paths. `assetPath` may contain `[hash]`,
468
+ which becomes the first 16 hex digits of that addon's published SHA256: the digest is known before
469
+ the build, so `addons/darwin-arm64-[hash].node` gives two installed versions of the package
470
+ different companion names, and the loader requires exactly that name. It is the only template an
471
+ addon path accepts. `entryPath` is fixed, without
336
472
  Bun naming templates such as `[dir]` or `[name]`. Companion JS builds require one entry, no splitting,
337
473
  and `naming.entry` exactly matching `entryPath`; the plugin rejects a mismatching layout.
338
474
  Choose any application layout; the framework does not prescribe an app directory or installer.
339
- Keep every bundler output, then verify copied addon bytes against the original SHA256.
340
- Archive the complete output directory with an integrity manifest, unpack to a clean directory,
341
- verify the same hashes there, and run offline without the build tree or `node_modules`.
342
- A digest provides integrity, not authenticity: signature and trust policy remain application-owned.
475
+ Keep every bundler output and write `asset.bytes`; never read the addon from `node_modules` a
476
+ second time. An installed addon whose size or SHA256 differs from the published manifest refuses
477
+ with `mismatch` / `NATIVE_ASSET_DIGEST_MISMATCH`, so a file substituted after installation never
478
+ reaches an artifact. Archive the complete output directory with an integrity manifest that records
479
+ `asset.sha256`, unpack to a clean directory, verify the same hashes there, and run offline without
480
+ the build tree or `node_modules`. The published digest ties the bytes to the package Stitchkit
481
+ built; the package itself is only as trusted as its tarball (the lockfile integrity of the install).
482
+ Signature and trust policy remain application-owned.
343
483
 
344
- From 0.104.2, one JS artifact can run on both Darwin architectures; change only the packaging inputs:
484
+ One JS artifact can run on both Darwin architectures; change only the packaging inputs:
345
485
 
346
486
  ```ts
347
487
  const native = createNativePackaging({
@@ -351,10 +491,10 @@ const native = createNativePackaging({
351
491
  })
352
492
  ```
353
493
 
354
- Use the same single plugin and copy loop above. A single-target loader deliberately refuses the
494
+ Use the same single plugin and write loop above. A single-target loader deliberately refuses the
355
495
  other architecture; two competing plugins cannot produce a universal loader. The array form
356
496
  requires exactly one distinct output path per declared target. A ready result carries the target
357
- array and both original asset hashes; `NativePackagingOptions<true>` /
497
+ array and both verified assets with their published digests; `NativePackagingOptions<true>` /
358
498
  `NativePackagingResult<true>` describe this form when explicitly annotating variables.
359
499
  The loader selects only `process.arch`: a missing or wrong-architecture selected addon refuses,
360
500
  even when the other valid addon is present. Linux runtime imports remain lazy and use Linux
@@ -363,17 +503,36 @@ Darwin arm64 and x64 machines, with both companions preserved through archive de
363
503
  Build-machine architecture and cross-build success cannot establish universal native support.
364
504
 
365
505
  For a standalone executable use `delivery: 'embedded'` and the same plugin in `Bun.build`
366
- with `compile: { outfile: ... }`. Bun embeds the selected addon; `assets` identifies its
367
- original bytes for qualification, not a companion that must be installed beside the executable.
506
+ with `compile: { outfile: ... }`. Bun embeds the selected addon from the verified bytes the
507
+ plugin holds, not from a second read of the file; `assets` identifies those bytes and their
508
+ published digest for qualification, not a companion that must be installed beside the executable.
368
509
  Cross-builds must select the requested architecture explicitly; the artifact must run on that target.
369
510
  The installed package must contain that target's addon. No automatic fallback/downgrade occurs.
370
511
 
371
- The API returns `unsupported` / `NATIVE_TARGET_UNSUPPORTED` for non-Darwin or unsupported
372
- architectures, and `missing` / `NATIVE_ASSET_MISSING` for a missing addon. Portable Linux libraries
373
- use their normal build, without a Darwin plugin; merely importing the build leaf loads no addon.
374
- Malformed inputs, unsupported metadata versions and other IO errors throw before packaging.
375
- Runtime missing/corrupt companions preserve the native `unavailable` result and safe stage/code
376
- from the existing observer; they never certify a dead owner. Preserve the raw cause internally.
512
+ `platform` is the closed set of platforms with native addons, today `'darwin'`: another name is a
513
+ type error and a schema refusal that throws, so pass the literal (or narrow `process.platform`
514
+ with `=== 'darwin'`) rather than a free string. The API returns `unsupported` /
515
+ `NATIVE_TARGET_UNSUPPORTED` for an unsupported architecture, `missing` / `NATIVE_ASSET_MISSING` for
516
+ an addon the package does not publish or whose file is gone, and `mismatch` /
517
+ `NATIVE_ASSET_DIGEST_MISMATCH` for an addon whose bytes differ from the published size or SHA256.
518
+ A `mismatch` names the first differing `architecture` and carries `expected` (the published
519
+ `{ size, sha256 }`) and `actual` (the installed file's size and the SHA256 of the bytes read), so
520
+ a build log can tell a truncated copy from a substituted one:
521
+
522
+ ```ts
523
+ if (native.state === 'mismatch')
524
+ throw new Error(
525
+ `${native.architecture} addon: expected ${native.expected.size} bytes ` +
526
+ `${native.expected.sha256}, found ${native.actual.size} bytes ${native.actual.sha256}`,
527
+ )
528
+ ```
529
+
530
+ Portable libraries
531
+ and Linux builds use their normal build, without a Darwin plugin; merely importing the build leaf
532
+ loads no addon.
533
+ Malformed inputs, a manifest whose `formatVersion` is not 2 and other IO errors throw before packaging.
534
+ A missing or corrupt companion at runtime yields the native `unavailable` result with the safe
535
+ stage and code from the observer; it never certifies a dead owner. Preserve the raw cause internally.
377
536
  The plugin does not parse consumer JS or establish a second runtime native implementation.
378
537
 
379
538
  ## Qualification boundaries
@@ -392,9 +551,13 @@ the qualification for native Darwin behavior.
392
551
 
393
552
  Local filesystem tests do not attest delayed NFS visibility, shared-volume microVM or gVisor
394
553
  ownership, actual PGID reuse, power-loss durability or macOS full-sync behavior. Those
395
- require their actual topology or failure environment. The default ownerless grace remains
396
- 5000 ms; stricter callers can retain `ownerlessGraceMs: null`. No age-only observation
397
- proves a partially published owner's process dead.
554
+ require their actual topology or failure environment. No age-only observation proves a
555
+ process dead; the lock's owner record exists before its name does.
556
+
557
+ A sandbox admission slot is released once a direct command's pipes have closed and its owner has settled.
558
+ A `COMMAND_CLEANUP` outcome means the death of its group was not proven, so the slot stays
559
+ occupied, `stop` keeps rejecting with the cleanup error, and the sandbox session is recreated to
560
+ recover.
398
561
 
399
562
  ==============================================================================
400
563
  # API reference: `stitchkit/process` (docs/api/reference.md)
@@ -407,8 +570,9 @@ Native POSIX Bun/Node one-shot command execution. See [native IO](../guide/nativ
407
570
  | Export | Kind | Purpose |
408
571
  |---|---|---|
409
572
  | `runNativeCommand` | function | caller-lifetime streaming or explicitly bounded binary capture |
410
- | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink and finite cleanup limits |
411
- | `NativeCommandResult` | type | observed nullable exit code/signal and captured stdout/stderr bytes |
573
+ | `NativeCommandOptions` | type | executable/args, env policy, signal/deadline, bytes sink, finite cleanup limits, the `stop` policy and `descendants` (`'terminate-after-leader'`, the default: stop the group after the leader exits, or `'leave'`); an unknown key is refused by name, a removed one (`killGraceMs`) with its replacement |
574
+ | `NativeCommandStopPolicy` | type | how a cancelled command stops: `target` `'group'` (signal every member) or `'leader'` (signal only the leader; its exit ends the grace), `signal` (default `SIGTERM`), `graceMs` (at most one hour) before KILL to the group, and `killOn`, an `AbortSignal` that skips the grace; default `{ target: 'group', signal: 'SIGTERM', graceMs: 100 }` |
575
+ | `NativeCommandResult` | type | observed nullable exit code/signal, `descendantsStopped` (members left in the group after the leader exited were stopped) and captured stdout/stderr bytes |
412
576
  | `NativeCommandError` | class | COMMAND_LIMIT with machine reason `deadline` or `output-budget`; COMMAND_UNAVAILABLE / COMMAND_CLEANUP have no limit reason. Preserves internal cause and existing constructor; caller-created limits without supplied reason remain unclassified |
413
577
 
414
578
  | `NativeCommandSettlement` | type | observed leader `exit` or terminal `error`, including synchronous native launch failure; `onLeaderSettled` runs once before drain, bounded by cleanupTimeoutMs, with a cancellable settlement signal; schema/pre-abort refusal creates no settlement obligation |