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