@graphrefly/graphrefly 0.47.1 → 0.48.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 (303) hide show
  1. package/dist/base/composition/index.cjs +28 -19
  2. package/dist/base/composition/index.cjs.map +1 -1
  3. package/dist/base/composition/index.d.cts +14 -5
  4. package/dist/base/composition/index.d.ts +14 -5
  5. package/dist/base/composition/index.js +9 -9
  6. package/dist/base/index.cjs +294 -164
  7. package/dist/base/index.cjs.map +1 -1
  8. package/dist/base/index.d.cts +2 -2
  9. package/dist/base/index.d.ts +2 -2
  10. package/dist/base/index.js +77 -72
  11. package/dist/base/io/index.cjs +145 -85
  12. package/dist/base/io/index.cjs.map +1 -1
  13. package/dist/base/io/index.d.cts +32 -5
  14. package/dist/base/io/index.d.ts +32 -5
  15. package/dist/base/io/index.js +5 -5
  16. package/dist/base/mutation/index.cjs +21 -0
  17. package/dist/base/mutation/index.cjs.map +1 -1
  18. package/dist/base/mutation/index.d.cts +23 -1
  19. package/dist/base/mutation/index.d.ts +23 -1
  20. package/dist/base/mutation/index.js +3 -1
  21. package/dist/base/sources/browser/index.cjs +18 -12
  22. package/dist/base/sources/browser/index.cjs.map +1 -1
  23. package/dist/base/sources/browser/index.d.cts +20 -2
  24. package/dist/base/sources/browser/index.d.ts +20 -2
  25. package/dist/base/sources/browser/index.js +18 -12
  26. package/dist/base/sources/browser/index.js.map +1 -1
  27. package/dist/base/sources/event/index.cjs +29 -1
  28. package/dist/base/sources/event/index.cjs.map +1 -1
  29. package/dist/base/sources/event/index.d.cts +67 -3
  30. package/dist/base/sources/event/index.d.ts +67 -3
  31. package/dist/base/sources/event/index.js +5 -2
  32. package/dist/base/sources/index.cjs +96 -50
  33. package/dist/base/sources/index.cjs.map +1 -1
  34. package/dist/base/sources/index.d.cts +1 -1
  35. package/dist/base/sources/index.d.ts +1 -1
  36. package/dist/base/sources/index.js +7 -4
  37. package/dist/base/sources/node/index.cjs +43 -37
  38. package/dist/base/sources/node/index.cjs.map +1 -1
  39. package/dist/base/sources/node/index.js +43 -37
  40. package/dist/base/sources/node/index.js.map +1 -1
  41. package/dist/{chunk-J5WFUEO4.js → chunk-23MAWVOJ.js} +3 -3
  42. package/dist/{chunk-YXCPV26R.js → chunk-3REMCHSS.js} +39 -27
  43. package/dist/chunk-3REMCHSS.js.map +1 -0
  44. package/dist/{chunk-CEVNQ74M.js → chunk-3YGXPUHW.js} +2 -2
  45. package/dist/{chunk-CEVNQ74M.js.map → chunk-3YGXPUHW.js.map} +1 -1
  46. package/dist/{chunk-EVYY4X5A.js → chunk-46X2EFQH.js} +16 -5
  47. package/dist/chunk-46X2EFQH.js.map +1 -0
  48. package/dist/{chunk-NY2PYHNC.js → chunk-5UY3PNFY.js} +12 -5
  49. package/dist/chunk-5UY3PNFY.js.map +1 -0
  50. package/dist/{chunk-RGMTUZCL.js → chunk-65OM4XLQ.js} +50 -4
  51. package/dist/chunk-65OM4XLQ.js.map +1 -0
  52. package/dist/{chunk-3PSLNJDU.js → chunk-6DQYBIHW.js} +314 -49
  53. package/dist/chunk-6DQYBIHW.js.map +1 -0
  54. package/dist/{chunk-LDCSZ72P.js → chunk-6YBER5UP.js} +3 -3
  55. package/dist/{chunk-LDCSZ72P.js.map → chunk-6YBER5UP.js.map} +1 -1
  56. package/dist/{chunk-7EGRP2VX.js → chunk-7BULJTL6.js} +2 -2
  57. package/dist/{chunk-7EGRP2VX.js.map → chunk-7BULJTL6.js.map} +1 -1
  58. package/dist/{chunk-VLAGJZSL.js → chunk-7T7WLEPM.js} +25 -4
  59. package/dist/chunk-7T7WLEPM.js.map +1 -0
  60. package/dist/{chunk-PKPO3JTZ.js → chunk-AQAKDE7F.js} +29 -11
  61. package/dist/chunk-AQAKDE7F.js.map +1 -0
  62. package/dist/{chunk-2OB3CEJS.js → chunk-B5Y5GPD5.js} +2 -2
  63. package/dist/{chunk-BXGZFGZ4.js → chunk-C5QD5DQX.js} +22 -1
  64. package/dist/chunk-C5QD5DQX.js.map +1 -0
  65. package/dist/{chunk-4XCHZRUJ.js → chunk-D5YGR4TP.js} +58 -7
  66. package/dist/chunk-D5YGR4TP.js.map +1 -0
  67. package/dist/{chunk-NPRP3MCV.js → chunk-DHDCOOJU.js} +2 -2
  68. package/dist/chunk-DHDCOOJU.js.map +1 -0
  69. package/dist/{chunk-MTTRCEJT.js → chunk-DVTDF5OI.js} +2 -2
  70. package/dist/{chunk-SOOKUYVM.js → chunk-F7EKHR32.js} +13 -9
  71. package/dist/chunk-F7EKHR32.js.map +1 -0
  72. package/dist/{chunk-A7KV5UK4.js → chunk-G7H6PN7P.js} +2 -2
  73. package/dist/{chunk-OCUDSN63.js → chunk-GGKHHG5Y.js} +110 -64
  74. package/dist/chunk-GGKHHG5Y.js.map +1 -0
  75. package/dist/{chunk-RAGGHLCV.js → chunk-GUNIRPEJ.js} +8 -6
  76. package/dist/{chunk-RAGGHLCV.js.map → chunk-GUNIRPEJ.js.map} +1 -1
  77. package/dist/{chunk-YJ4U2D2C.js → chunk-J5TBZFBD.js} +9 -7
  78. package/dist/chunk-J5TBZFBD.js.map +1 -0
  79. package/dist/{chunk-Y52CS6YA.js → chunk-JA67ZQG2.js} +2 -2
  80. package/dist/{chunk-Y52CS6YA.js.map → chunk-JA67ZQG2.js.map} +1 -1
  81. package/dist/{chunk-U225SKB4.js → chunk-K4ZYJ4EM.js} +569 -424
  82. package/dist/chunk-K4ZYJ4EM.js.map +1 -0
  83. package/dist/{chunk-Z4YXAUDN.js → chunk-KUFXLAEY.js} +11 -7
  84. package/dist/{chunk-Z4YXAUDN.js.map → chunk-KUFXLAEY.js.map} +1 -1
  85. package/dist/{chunk-IHTWQEDR.js → chunk-LTSI7ULC.js} +3 -3
  86. package/dist/{chunk-IHTWQEDR.js.map → chunk-LTSI7ULC.js.map} +1 -1
  87. package/dist/{chunk-DKNHAICT.js → chunk-MMHGYX44.js} +25 -9
  88. package/dist/chunk-MMHGYX44.js.map +1 -0
  89. package/dist/{chunk-K7PDZYQE.js → chunk-MQMTRKY3.js} +129 -50
  90. package/dist/chunk-MQMTRKY3.js.map +1 -0
  91. package/dist/{chunk-42FQ27MQ.js → chunk-MTODGQBR.js} +44 -179
  92. package/dist/chunk-MTODGQBR.js.map +1 -0
  93. package/dist/{chunk-O3MT7DYI.js → chunk-N6MNJNHB.js} +2 -2
  94. package/dist/{chunk-FVINAAKA.js → chunk-NBK6QQMG.js} +14 -13
  95. package/dist/{chunk-FVINAAKA.js.map → chunk-NBK6QQMG.js.map} +1 -1
  96. package/dist/{chunk-DM4OMPWK.js → chunk-NSA5K5G2.js} +2 -2
  97. package/dist/{chunk-MLTPJMH6.js → chunk-QQYULEZL.js} +2 -2
  98. package/dist/chunk-QSW4DFKE.js +31 -0
  99. package/dist/chunk-QSW4DFKE.js.map +1 -0
  100. package/dist/{chunk-PZWISPIQ.js → chunk-S7HN5FHL.js} +17 -11
  101. package/dist/chunk-S7HN5FHL.js.map +1 -0
  102. package/dist/{chunk-4S53H2KR.js → chunk-SUNCHMML.js} +2 -2
  103. package/dist/{chunk-4GYMCUDZ.js → chunk-T2U6N3FV.js} +7 -7
  104. package/dist/{chunk-RJOG4IJU.js → chunk-T5URUIIY.js} +50 -35
  105. package/dist/chunk-T5URUIIY.js.map +1 -0
  106. package/dist/{chunk-B4AKFXGE.js → chunk-TPTZZV25.js} +6 -6
  107. package/dist/chunk-TPTZZV25.js.map +1 -0
  108. package/dist/{chunk-BU3SEFA5.js → chunk-V46JWFGV.js} +7 -6
  109. package/dist/chunk-V46JWFGV.js.map +1 -0
  110. package/dist/{chunk-IJRR6YAI.js → chunk-VLDRAMP7.js} +18 -12
  111. package/dist/chunk-VLDRAMP7.js.map +1 -0
  112. package/dist/{chunk-6XZYT4SW.js → chunk-X6ESZDR6.js} +8 -9
  113. package/dist/chunk-X6ESZDR6.js.map +1 -0
  114. package/dist/{chunk-E5OZPDIW.js → chunk-X7BA5PWG.js} +7 -5
  115. package/dist/chunk-X7BA5PWG.js.map +1 -0
  116. package/dist/{chunk-CXANAIZU.js → chunk-XEWV254I.js} +3 -3
  117. package/dist/{chunk-CXANAIZU.js.map → chunk-XEWV254I.js.map} +1 -1
  118. package/dist/{chunk-V4Y3TM7U.js → chunk-YBJVKMTM.js} +38 -16
  119. package/dist/chunk-YBJVKMTM.js.map +1 -0
  120. package/dist/{chunk-7ADWWI2T.js → chunk-ZW32BPXV.js} +17 -6
  121. package/dist/chunk-ZW32BPXV.js.map +1 -0
  122. package/dist/compat/index.cjs +52 -5
  123. package/dist/compat/index.cjs.map +1 -1
  124. package/dist/compat/index.d.cts +1 -1
  125. package/dist/compat/index.d.ts +1 -1
  126. package/dist/compat/index.js +7 -7
  127. package/dist/compat/nestjs/index.cjs +52 -5
  128. package/dist/compat/nestjs/index.cjs.map +1 -1
  129. package/dist/compat/nestjs/index.d.cts +1 -1
  130. package/dist/compat/nestjs/index.d.ts +1 -1
  131. package/dist/compat/nestjs/index.js +4 -4
  132. package/dist/{fallback-Bx46zqky.d.cts → fallback-BROR6ZhO.d.cts} +1 -1
  133. package/dist/{fallback-pIWW8A2d.d.ts → fallback-DO80aM_3.d.ts} +1 -1
  134. package/dist/{index-B_p8tnvf.d.cts → index-D1z3XcF9.d.cts} +1 -0
  135. package/dist/{index-_HDSmPyp.d.ts → index-DZ6yua0Q.d.ts} +1 -0
  136. package/dist/index.cjs +2387 -1707
  137. package/dist/index.cjs.map +1 -1
  138. package/dist/index.d.cts +10 -10
  139. package/dist/index.d.ts +10 -10
  140. package/dist/index.js +173 -150
  141. package/dist/index.js.map +1 -1
  142. package/dist/presets/ai/index.cjs +88 -26
  143. package/dist/presets/ai/index.cjs.map +1 -1
  144. package/dist/presets/ai/index.js +14 -14
  145. package/dist/presets/harness/index.cjs +183 -51
  146. package/dist/presets/harness/index.cjs.map +1 -1
  147. package/dist/presets/harness/index.d.cts +15 -5
  148. package/dist/presets/harness/index.d.ts +15 -5
  149. package/dist/presets/harness/index.js +26 -26
  150. package/dist/presets/index.cjs +298 -101
  151. package/dist/presets/index.cjs.map +1 -1
  152. package/dist/presets/index.d.cts +2 -2
  153. package/dist/presets/index.d.ts +2 -2
  154. package/dist/presets/index.js +49 -49
  155. package/dist/presets/inspect/index.cjs +63 -14
  156. package/dist/presets/inspect/index.cjs.map +1 -1
  157. package/dist/presets/inspect/index.d.cts +1 -1
  158. package/dist/presets/inspect/index.d.ts +1 -1
  159. package/dist/presets/inspect/index.js +6 -6
  160. package/dist/presets/resilience/index.cjs +64 -44
  161. package/dist/presets/resilience/index.cjs.map +1 -1
  162. package/dist/presets/resilience/index.d.cts +12 -8
  163. package/dist/presets/resilience/index.d.ts +12 -8
  164. package/dist/presets/resilience/index.js +6 -6
  165. package/dist/{rate-limiter-DpVbSYdH.d.cts → rate-limiter-DC26FM8J.d.cts} +10 -1
  166. package/dist/{rate-limiter-CEALq4N1.d.ts → rate-limiter-DyWpwpQP.d.ts} +10 -1
  167. package/dist/{reactive-layout-fswlBUvX.d.ts → reactive-layout-BBBWH0V_.d.cts} +85 -4
  168. package/dist/{reactive-layout-fswlBUvX.d.cts → reactive-layout-BBBWH0V_.d.ts} +85 -4
  169. package/dist/solutions/index.cjs +239 -92
  170. package/dist/solutions/index.cjs.map +1 -1
  171. package/dist/solutions/index.d.cts +2 -2
  172. package/dist/solutions/index.d.ts +2 -2
  173. package/dist/solutions/index.js +32 -32
  174. package/dist/{spawnable-5mDY501F.d.cts → spawnable-B2IlW60f.d.cts} +23 -2
  175. package/dist/{spawnable-D3lR0oQu.d.ts → spawnable-tttFz2Nh.d.ts} +23 -2
  176. package/dist/testing/index.cjs +94 -0
  177. package/dist/testing/index.cjs.map +1 -0
  178. package/dist/testing/index.d.cts +59 -0
  179. package/dist/testing/index.d.ts +59 -0
  180. package/dist/testing/index.js +73 -0
  181. package/dist/testing/index.js.map +1 -0
  182. package/dist/{timeout-U5O4ESK3.js → timeout-BEABACRP.js} +2 -2
  183. package/dist/utils/ai/browser.cjs.map +1 -1
  184. package/dist/utils/ai/browser.d.cts +2 -2
  185. package/dist/utils/ai/browser.d.ts +2 -2
  186. package/dist/utils/ai/browser.js +10 -10
  187. package/dist/utils/ai/browser.js.map +1 -1
  188. package/dist/utils/ai/index.cjs +291 -191
  189. package/dist/utils/ai/index.cjs.map +1 -1
  190. package/dist/utils/ai/index.d.cts +108 -12
  191. package/dist/utils/ai/index.d.ts +108 -12
  192. package/dist/utils/ai/index.js +23 -21
  193. package/dist/utils/ai/node.cjs.map +1 -1
  194. package/dist/utils/ai/node.d.cts +5 -5
  195. package/dist/utils/ai/node.d.ts +5 -5
  196. package/dist/utils/ai/node.js +3 -3
  197. package/dist/utils/ai/node.js.map +1 -1
  198. package/dist/utils/cqrs/index.cjs +29 -3
  199. package/dist/utils/cqrs/index.cjs.map +1 -1
  200. package/dist/utils/cqrs/index.d.cts +12 -7
  201. package/dist/utils/cqrs/index.d.ts +12 -7
  202. package/dist/utils/cqrs/index.js +2 -2
  203. package/dist/utils/demo-shell/index.cjs +45 -19
  204. package/dist/utils/demo-shell/index.cjs.map +1 -1
  205. package/dist/utils/demo-shell/index.d.cts +1 -1
  206. package/dist/utils/demo-shell/index.d.ts +1 -1
  207. package/dist/utils/demo-shell/index.js +2 -2
  208. package/dist/utils/domain-templates/index.cjs +1 -1
  209. package/dist/utils/domain-templates/index.cjs.map +1 -1
  210. package/dist/utils/domain-templates/index.js +3 -3
  211. package/dist/utils/graphspec/index.cjs +1 -1
  212. package/dist/utils/graphspec/index.cjs.map +1 -1
  213. package/dist/utils/graphspec/index.js +3 -3
  214. package/dist/utils/harness/index.cjs +16 -10
  215. package/dist/utils/harness/index.cjs.map +1 -1
  216. package/dist/utils/harness/index.js +1 -1
  217. package/dist/utils/index.cjs +1692 -1192
  218. package/dist/utils/index.cjs.map +1 -1
  219. package/dist/utils/index.d.cts +7 -7
  220. package/dist/utils/index.d.ts +7 -7
  221. package/dist/utils/index.js +77 -59
  222. package/dist/utils/inspect/index.cjs +52 -4
  223. package/dist/utils/inspect/index.cjs.map +1 -1
  224. package/dist/utils/inspect/index.d.cts +32 -3
  225. package/dist/utils/inspect/index.d.ts +32 -3
  226. package/dist/utils/inspect/index.js +4 -4
  227. package/dist/utils/job-queue/index.cjs +46 -9
  228. package/dist/utils/job-queue/index.cjs.map +1 -1
  229. package/dist/utils/job-queue/index.d.cts +33 -3
  230. package/dist/utils/job-queue/index.d.ts +33 -3
  231. package/dist/utils/job-queue/index.js +2 -2
  232. package/dist/utils/memory/index.cjs +570 -425
  233. package/dist/utils/memory/index.cjs.map +1 -1
  234. package/dist/utils/memory/index.d.cts +261 -33
  235. package/dist/utils/memory/index.d.ts +261 -33
  236. package/dist/utils/memory/index.js +10 -2
  237. package/dist/utils/messaging/index.cjs.map +1 -1
  238. package/dist/utils/messaging/index.d.cts +4 -3
  239. package/dist/utils/messaging/index.d.ts +4 -3
  240. package/dist/utils/messaging/index.js +2 -2
  241. package/dist/utils/orchestration/index.cjs +14 -3
  242. package/dist/utils/orchestration/index.cjs.map +1 -1
  243. package/dist/utils/orchestration/index.js +3 -3
  244. package/dist/utils/process/index.cjs +32 -2
  245. package/dist/utils/process/index.cjs.map +1 -1
  246. package/dist/utils/process/index.d.cts +4 -3
  247. package/dist/utils/process/index.d.ts +4 -3
  248. package/dist/utils/process/index.js +3 -3
  249. package/dist/utils/reactive-layout/index.cjs +184 -55
  250. package/dist/utils/reactive-layout/index.cjs.map +1 -1
  251. package/dist/utils/reactive-layout/index.d.cts +128 -3
  252. package/dist/utils/reactive-layout/index.d.ts +128 -3
  253. package/dist/utils/reactive-layout/index.js +16 -8
  254. package/dist/utils/reduction/index.cjs +1 -1
  255. package/dist/utils/reduction/index.cjs.map +1 -1
  256. package/dist/utils/reduction/index.js +2 -2
  257. package/dist/utils/resilience/index.cjs +64 -43
  258. package/dist/utils/resilience/index.cjs.map +1 -1
  259. package/dist/utils/resilience/index.d.cts +1 -1
  260. package/dist/utils/resilience/index.d.ts +1 -1
  261. package/dist/utils/resilience/index.js +5 -5
  262. package/dist/utils/surface/index.cjs +1 -1
  263. package/dist/utils/surface/index.cjs.map +1 -1
  264. package/dist/utils/surface/index.js +4 -4
  265. package/package.json +15 -3
  266. package/dist/chunk-3PSLNJDU.js.map +0 -1
  267. package/dist/chunk-42FQ27MQ.js.map +0 -1
  268. package/dist/chunk-4XCHZRUJ.js.map +0 -1
  269. package/dist/chunk-6XZYT4SW.js.map +0 -1
  270. package/dist/chunk-7ADWWI2T.js.map +0 -1
  271. package/dist/chunk-B4AKFXGE.js.map +0 -1
  272. package/dist/chunk-BU3SEFA5.js.map +0 -1
  273. package/dist/chunk-BXGZFGZ4.js.map +0 -1
  274. package/dist/chunk-DKNHAICT.js.map +0 -1
  275. package/dist/chunk-E5OZPDIW.js.map +0 -1
  276. package/dist/chunk-EVYY4X5A.js.map +0 -1
  277. package/dist/chunk-IJRR6YAI.js.map +0 -1
  278. package/dist/chunk-K7PDZYQE.js.map +0 -1
  279. package/dist/chunk-NPRP3MCV.js.map +0 -1
  280. package/dist/chunk-NY2PYHNC.js.map +0 -1
  281. package/dist/chunk-OCUDSN63.js.map +0 -1
  282. package/dist/chunk-PKPO3JTZ.js.map +0 -1
  283. package/dist/chunk-PZWISPIQ.js.map +0 -1
  284. package/dist/chunk-RGMTUZCL.js.map +0 -1
  285. package/dist/chunk-RJOG4IJU.js.map +0 -1
  286. package/dist/chunk-SOOKUYVM.js.map +0 -1
  287. package/dist/chunk-U225SKB4.js.map +0 -1
  288. package/dist/chunk-V4Y3TM7U.js.map +0 -1
  289. package/dist/chunk-VLAGJZSL.js.map +0 -1
  290. package/dist/chunk-W2BOPXTI.js +0 -1
  291. package/dist/chunk-YJ4U2D2C.js.map +0 -1
  292. package/dist/chunk-YXCPV26R.js.map +0 -1
  293. package/dist/timeout-U5O4ESK3.js.map +0 -1
  294. /package/dist/{chunk-J5WFUEO4.js.map → chunk-23MAWVOJ.js.map} +0 -0
  295. /package/dist/{chunk-2OB3CEJS.js.map → chunk-B5Y5GPD5.js.map} +0 -0
  296. /package/dist/{chunk-MTTRCEJT.js.map → chunk-DVTDF5OI.js.map} +0 -0
  297. /package/dist/{chunk-A7KV5UK4.js.map → chunk-G7H6PN7P.js.map} +0 -0
  298. /package/dist/{chunk-O3MT7DYI.js.map → chunk-N6MNJNHB.js.map} +0 -0
  299. /package/dist/{chunk-DM4OMPWK.js.map → chunk-NSA5K5G2.js.map} +0 -0
  300. /package/dist/{chunk-MLTPJMH6.js.map → chunk-QQYULEZL.js.map} +0 -0
  301. /package/dist/{chunk-4S53H2KR.js.map → chunk-SUNCHMML.js.map} +0 -0
  302. /package/dist/{chunk-4GYMCUDZ.js.map → chunk-T2U6N3FV.js.map} +0 -0
  303. /package/dist/{chunk-W2BOPXTI.js.map → timeout-BEABACRP.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/base/sources/node/index.ts","../../../../src/base/sources/node/fs-root.ts","../../../../src/base/sources/node/git-hook.ts","../../../../src/base/sources/node/process.ts"],"sourcesContent":["/**\n * Node-only sources — fs, git, git-hook, process.\n *\n * All entries in this subpath may import node:* builtins.\n * Import via @graphrefly/graphrefly/base/sources/node.\n *\n * @module\n */\n\nexport * from \"./fs.js\";\nexport * from \"./git.js\";\nexport * from \"./git-hook.js\";\nexport * from \"./process.js\";\n","/**\n * Filesystem-watching source. Isolated from `./sources.ts` so bundlers\n * targeting the browser can import browser-safe sources (`fromTimer`,\n * `fromRaf`, etc.) without pulling in `node:fs`/`node:path`.\n */\n\nimport { existsSync, watch } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n\tDATA,\n\tERROR,\n\ttype Message,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport { globToRegExp, matchesAnyPattern } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions<unknown>, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\nexport type FSEventType = \"change\" | \"rename\" | \"create\" | \"delete\";\nexport type FSEvent = {\n\ttype: FSEventType;\n\tpath: string;\n\troot: string;\n\trelative_path: string;\n\tsrc_path?: string;\n\tdest_path?: string;\n\ttimestamp_ns: number;\n};\n\nexport type FromFSWatchOptions = ExtraOpts & {\n\trecursive?: boolean;\n\tdebounce?: number;\n\tinclude?: string[];\n\texclude?: string[];\n};\n\n/**\n * Watches filesystem paths and emits debounced change events.\n *\n * Uses `fs.watch` only (no polling fallback). Teardown closes all watchers.\n *\n * @category extra\n */\nexport function fromFSWatch(paths: string | string[], opts?: FromFSWatchOptions): Node<FSEvent> {\n\tconst list = Array.isArray(paths) ? paths : [paths];\n\tif (list.length === 0) {\n\t\tthrow new RangeError(\"fromFSWatch expects at least one path\");\n\t}\n\tconst { recursive = true, debounce = 100, include, exclude, ...rest } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = (exclude ?? [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"]).map(\n\t\tglobToRegExp,\n\t);\n\treturn node<FSEvent>((_data, a) => {\n\t\tconst pending = new Map<string, FSEvent>();\n\t\tconst watchers: ReturnType<typeof watch>[] = [];\n\t\tlet stopped = false;\n\t\tlet terminalEmitted = false;\n\t\tlet generation = 0;\n\t\tconst closeWatchers = () => {\n\t\t\tfor (const watcher of watchers.splice(0)) watcher.close();\n\t\t};\n\t\tconst emitError = (err: unknown) => {\n\t\t\tif (terminalEmitted) return;\n\t\t\tterminalEmitted = true;\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tpending.clear();\n\t\t\tcloseWatchers();\n\t\t\ta.down([[ERROR, err]]);\n\t\t};\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst flush = (token: number) => {\n\t\t\ttimer = undefined;\n\t\t\tif (stopped || terminalEmitted) return;\n\t\t\tif (pending.size === 0) return;\n\t\t\tconst batchMessages: Message[] = [];\n\t\t\tfor (const evt of pending.values()) batchMessages.push([DATA, evt]);\n\t\t\tpending.clear();\n\t\t\tif (stopped || terminalEmitted || token !== generation) return;\n\t\t\ta.down(batchMessages);\n\t\t};\n\t\ttry {\n\t\t\tfor (const basePath of list) {\n\t\t\t\tconst watcher = watch(\n\t\t\t\t\tbasePath,\n\t\t\t\t\t{ recursive },\n\t\t\t\t\t(eventType: \"rename\" | \"change\", fileName: string | Buffer | null) => {\n\t\t\t\t\t\tif (stopped || terminalEmitted) return;\n\t\t\t\t\t\tif (fileName == null) return;\n\t\t\t\t\t\tconst rel = String(fileName).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst abs = resolvePath(basePath, String(fileName));\n\t\t\t\t\t\tconst normalized = abs.replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst root = resolvePath(basePath).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst relForMatch = rel.startsWith(\"./\") ? rel.slice(2) : rel;\n\t\t\t\t\t\tconst included =\n\t\t\t\t\t\t\tincludePatterns.length === 0 ||\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, includePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, includePatterns);\n\t\t\t\t\t\tif (!included) return;\n\t\t\t\t\t\tconst excluded =\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, excludePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, excludePatterns);\n\t\t\t\t\t\tif (excluded) return;\n\t\t\t\t\t\tlet kind: FSEventType = \"change\";\n\t\t\t\t\t\tif (eventType === \"rename\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tkind = existsSync(normalized) ? \"create\" : \"delete\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tkind = \"rename\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpending.set(normalized, {\n\t\t\t\t\t\t\ttype: kind,\n\t\t\t\t\t\t\tpath: normalized,\n\t\t\t\t\t\t\troot,\n\t\t\t\t\t\t\trelative_path: relForMatch,\n\t\t\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\t\t\tconst token = generation;\n\t\t\t\t\t\ttimer = setTimeout(() => flush(token), debounce);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\twatcher.on(\"error\", (err) => emitError(err));\n\t\t\t\twatchers.push(watcher);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\temitError(err);\n\t\t}\n\t\treturn () => {\n\t\t\tstopped = true;\n\t\t\tgeneration += 1;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tcloseWatchers();\n\t\t\tpending.clear();\n\t\t};\n\t}, sourceOpts(rest));\n}\n","/**\n * Git hook source — Node-only reactive source that polls a repository's HEAD\n * and emits structured `GitEvent`s on every new commit.\n *\n * Isolated from `./adapters.ts` so that the universal `extra/index` barrel\n * stays browser-safe. Access via `@graphrefly/graphrefly/extra/node`, which\n * re-exports this module.\n *\n * @module\n */\n\nimport { ERROR, type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromTimer, globToRegExp, matchesAnyPattern, switchMap } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n/** Git hook type for {@link fromGitHook}. */\nexport type GitHookType = \"post-commit\" | \"post-merge\" | \"post-checkout\" | \"post-rewrite\";\n\n/** Structured git event emitted by {@link fromGitHook}. */\nexport type GitEvent = {\n\thook: GitHookType;\n\tcommit: string;\n\tfiles: string[];\n\tmessage: string;\n\tauthor: string;\n\ttimestamp_ns: number;\n};\n\n/** Options for {@link fromGitHook}. */\nexport type FromGitHookOptions = ExtraOpts & {\n\tpollMs?: number;\n\tinclude?: string[];\n\texclude?: string[];\n\t/**\n\t * Maximum consecutive poll errors before terminating the source. Prevents\n\t * error storms when the repository is unavailable (e.g. deleted, corrupt,\n\t * permissions lost). Default: `1` (terminate on first error — preserves\n\t * pre-switchMap back-compat). Raise it (or set `Infinity`) to keep\n\t * retrying indefinitely (legacy behavior).\n\t */\n\tmaxConsecutiveErrors?: number;\n};\n\n/**\n * Git change detection as a reactive source.\n *\n * @category extra\n */\nexport function fromGitHook(repoPath: string, opts?: FromGitHookOptions): Node<GitEvent> {\n\tconst { pollMs = 5000, include, exclude, maxConsecutiveErrors = 1 } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = exclude?.map(globToRegExp) ?? [];\n\tconst { execFileSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n\n\tconst gitQuery = (args: string[]): string =>\n\t\texecFileSync(\"git\", args, { cwd: repoPath, encoding: \"utf-8\" }).trim();\n\n\t// Shared across ticks: the previous HEAD we committed to. Undefined on the\n\t// very first poll (we record the initial HEAD without emitting).\n\tlet lastSeen: string | undefined;\n\t// Circuit breaker: consecutive error count. Resets on any successful poll.\n\tlet consecutiveErrors = 0;\n\n\t// `fromTimer | switchMap(sync-git-diff)` — ticks drive the poll, switchMap\n\t// cancels any in-flight inner on next tick. First tick at t=0 records the\n\t// baseline HEAD silently; subsequent ticks emit `GitEvent` on HEAD change.\n\treturn switchMap(fromTimer(0, { period: pollMs }), () =>\n\t\tnode<GitEvent>((_data, a) => {\n\t\t\ttry {\n\t\t\t\tconst head = gitQuery([\"rev-parse\", \"HEAD\"]);\n\t\t\t\tif (!head) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tif (lastSeen === undefined) {\n\t\t\t\t\t// First poll: record baseline; stay idle until next tick\n\t\t\t\t\t// disposes this inner.\n\t\t\t\t\tlastSeen = head;\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tif (head === lastSeen) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tlet files = gitQuery([\"diff\", \"--name-only\", `${lastSeen}..${head}`])\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (includePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => matchesAnyPattern(f, includePatterns));\n\t\t\t\t}\n\t\t\t\tif (excludePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => !matchesAnyPattern(f, excludePatterns));\n\t\t\t\t}\n\t\t\t\tconst message = gitQuery([\"log\", \"-1\", \"--format=%s\", head]);\n\t\t\t\tconst author = gitQuery([\"log\", \"-1\", \"--format=%an\", head]);\n\t\t\t\ta.emit({\n\t\t\t\t\thook: \"post-commit\" as GitHookType,\n\t\t\t\t\tcommit: head,\n\t\t\t\t\tfiles,\n\t\t\t\t\tmessage,\n\t\t\t\t\tauthor,\n\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t});\n\t\t\t\tlastSeen = head;\n\t\t\t\tconsecutiveErrors = 0;\n\t\t\t} catch (err) {\n\t\t\t\tconsecutiveErrors += 1;\n\t\t\t\tif (consecutiveErrors >= maxConsecutiveErrors) {\n\t\t\t\t\ta.down([[ERROR, err]]);\n\t\t\t\t}\n\t\t\t\t// else: transient error — next tick will retry; don't spam ERROR.\n\t\t\t}\n\t\t\treturn () => {};\n\t\t}),\n\t);\n}\n","/**\n * Child-process reactive sources — Node-only.\n *\n * Isolated from `./sources.ts` so bundlers targeting the browser can import\n * browser-safe sources without pulling in `node:child_process`.\n *\n * Access via `@graphrefly/graphrefly/extra/node`, which re-exports this module.\n *\n * @module\n */\n\nimport { type SpawnOptions, spawn } from \"node:child_process\";\nimport { COMPLETE, DATA, ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * SpawnEvent — discriminated stream emitted by {@link fromSpawn}.\n *\n * @category extra\n */\nexport type SpawnEvent =\n\t| { kind: \"stdout\"; chunk: Buffer }\n\t| { kind: \"stderr\"; chunk: Buffer }\n\t| { kind: \"exit\"; code: number | null; signal: NodeJS.Signals | null };\n\n/** Options for {@link fromSpawn}. Mirrors `child_process.SpawnOptions`. */\nexport interface FromSpawnOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tshell?: boolean | string;\n\t/**\n\t * Optional caller-owned AbortSignal. When fired, the subprocess is sent\n\t * SIGTERM (per `child_process.spawn` signal semantics). The producer's own\n\t * teardown also sends SIGTERM regardless of caller signal — so `switchMap`\n\t * supersede in `actuatorExecutor` cancels in-flight subprocesses without\n\t * the caller wiring extra signals.\n\t */\n\tsignal?: AbortSignal;\n\t/** Extra args forwarded to spawn — e.g. stdio configuration. */\n\tstdio?: \"pipe\" | readonly (\"pipe\" | \"ignore\" | \"inherit\")[];\n}\n\n// ---------------------------------------------------------------------------\n// fromSpawn\n// ---------------------------------------------------------------------------\n\n/**\n * Spawn `cmd args` as a child process and stream stdout/stderr/exit as a\n * single discriminated `SpawnEvent` stream.\n *\n * Lifecycle:\n * - Stdout/stderr chunks emit as `DATA { kind: \"stdout\"|\"stderr\", chunk }`.\n * - Process exit emits one final `DATA { kind: \"exit\", code, signal }` then\n * `COMPLETE`.\n * - Spawn-error (ENOENT, EPERM, …) emits `ERROR`.\n * - Producer teardown sends `SIGTERM` to the subprocess if it is still alive.\n *\n * **Multicast semantics:** `fromSpawn` returns a node backed by a single\n * `producer` activation — the subprocess is spawned once when the first\n * subscriber connects, and all subsequent subscribers share the same event\n * stream. Unsubscribing the last subscriber tears down the subprocess.\n *\n * @example\n * ```ts\n * import { fromSpawn } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const stream = fromSpawn(\"git\", [\"log\", \"--oneline\"]);\n * stream.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value);\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function fromSpawn(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<SpawnEvent> {\n\treturn node<SpawnEvent>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stdout\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stderr\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tactions.down([\n\t\t\t\t\t[DATA, { kind: \"exit\", code: info.code, signal: info.signal }],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (alive) {\n\t\t\t\t\talive = false;\n\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t{ name: \"from_spawn\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// runProcess\n// ---------------------------------------------------------------------------\n\n/**\n * Run `cmd args` to completion and emit one DATA with aggregated output.\n *\n * Convenience over {@link fromSpawn} for the \"wait for the process to finish,\n * capture stdout/stderr as strings, get exit code\" case.\n *\n * Aggregation policy: stdout and stderr are concatenated as `Buffer`s and\n * decoded as utf-8 once at exit, so multi-byte sequences split across chunks\n * are handled correctly. Actuators that need byte-exact stdout should use\n * `fromSpawn` directly.\n *\n * @example\n * ```ts\n * import { runProcess } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const result = runProcess(\"git\", [\"rev-parse\", \"HEAD\"]);\n * result.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value.stdout.trim());\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function runProcess(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number | null;\n\tsignal: NodeJS.Signals | null;\n}> {\n\ttype Result = {\n\t\tstdout: string;\n\t\tstderr: string;\n\t\texitCode: number | null;\n\t\tsignal: NodeJS.Signals | null;\n\t};\n\treturn node<Result>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tconst stdoutChunks: Buffer[] = [];\n\t\t\tconst stderrChunks: Buffer[] = [];\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstdoutChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstderrChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tconst stdout = Buffer.concat(stdoutChunks).toString(\"utf8\");\n\t\t\t\tconst stderr = Buffer.concat(stderrChunks).toString(\"utf8\");\n\t\t\t\tactions.down([\n\t\t\t\t\t[\n\t\t\t\t\t\tDATA,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstdout,\n\t\t\t\t\t\t\tstderr,\n\t\t\t\t\t\t\texitCode: info.code,\n\t\t\t\t\t\t\tsignal: info.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (alive) {\n\t\t\t\t\talive = false;\n\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t{ name: \"run_process\" },\n\t);\n}\n"],"mappings":"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","names":["resolvePath","import_core","import_extra","import_core"]}
1
+ {"version":3,"sources":["../../../../src/base/sources/node/index.ts","../../../../src/base/sources/node/fs-root.ts","../../../../src/base/sources/node/git-hook.ts","../../../../src/base/sources/node/process.ts"],"sourcesContent":["/**\n * Node-only sources — fs, git, git-hook, process.\n *\n * All entries in this subpath may import node:* builtins.\n * Import via @graphrefly/graphrefly/base/sources/node.\n *\n * @module\n */\n\nexport * from \"./fs.js\";\nexport * from \"./git.js\";\nexport * from \"./git-hook.js\";\nexport * from \"./process.js\";\n","/**\n * Filesystem-watching source. Isolated from `./sources.ts` so bundlers\n * targeting the browser can import browser-safe sources (`fromTimer`,\n * `fromRaf`, etc.) without pulling in `node:fs`/`node:path`.\n */\n\nimport { existsSync, watch } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n\tDATA,\n\tERROR,\n\ttype Message,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport { globToRegExp, matchesAnyPattern } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions<unknown>, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\nexport type FSEventType = \"change\" | \"rename\" | \"create\" | \"delete\";\nexport type FSEvent = {\n\ttype: FSEventType;\n\tpath: string;\n\troot: string;\n\trelative_path: string;\n\tsrc_path?: string;\n\tdest_path?: string;\n\ttimestamp_ns: number;\n};\n\nexport type FromFSWatchOptions = ExtraOpts & {\n\trecursive?: boolean;\n\tdebounce?: number;\n\tinclude?: string[];\n\texclude?: string[];\n};\n\n/**\n * Watches filesystem paths and emits debounced change events.\n *\n * Uses `fs.watch` only (no polling fallback). Teardown closes all watchers.\n *\n * @category extra\n */\nexport function fromFSWatch(paths: string | string[], opts?: FromFSWatchOptions): Node<FSEvent> {\n\tconst list = Array.isArray(paths) ? paths : [paths];\n\tif (list.length === 0) {\n\t\tthrow new RangeError(\"fromFSWatch expects at least one path\");\n\t}\n\tconst { recursive = true, debounce = 100, include, exclude, ...rest } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = (exclude ?? [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"]).map(\n\t\tglobToRegExp,\n\t);\n\treturn node<FSEvent>((_data, a) => {\n\t\tconst pending = new Map<string, FSEvent>();\n\t\tconst watchers: ReturnType<typeof watch>[] = [];\n\t\tlet stopped = false;\n\t\tlet terminalEmitted = false;\n\t\tlet generation = 0;\n\t\tconst closeWatchers = () => {\n\t\t\tfor (const watcher of watchers.splice(0)) watcher.close();\n\t\t};\n\t\tconst emitError = (err: unknown) => {\n\t\t\tif (terminalEmitted) return;\n\t\t\tterminalEmitted = true;\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tpending.clear();\n\t\t\tcloseWatchers();\n\t\t\ta.down([[ERROR, err]]);\n\t\t};\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst flush = (token: number) => {\n\t\t\ttimer = undefined;\n\t\t\tif (stopped || terminalEmitted) return;\n\t\t\tif (pending.size === 0) return;\n\t\t\tconst batchMessages: Message[] = [];\n\t\t\tfor (const evt of pending.values()) batchMessages.push([DATA, evt]);\n\t\t\tpending.clear();\n\t\t\tif (stopped || terminalEmitted || token !== generation) return;\n\t\t\ta.down(batchMessages);\n\t\t};\n\t\ttry {\n\t\t\tfor (const basePath of list) {\n\t\t\t\tconst watcher = watch(\n\t\t\t\t\tbasePath,\n\t\t\t\t\t{ recursive },\n\t\t\t\t\t(eventType: \"rename\" | \"change\", fileName: string | Buffer | null) => {\n\t\t\t\t\t\tif (stopped || terminalEmitted) return;\n\t\t\t\t\t\tif (fileName == null) return;\n\t\t\t\t\t\tconst rel = String(fileName).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst abs = resolvePath(basePath, String(fileName));\n\t\t\t\t\t\tconst normalized = abs.replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst root = resolvePath(basePath).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst relForMatch = rel.startsWith(\"./\") ? rel.slice(2) : rel;\n\t\t\t\t\t\tconst included =\n\t\t\t\t\t\t\tincludePatterns.length === 0 ||\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, includePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, includePatterns);\n\t\t\t\t\t\tif (!included) return;\n\t\t\t\t\t\tconst excluded =\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, excludePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, excludePatterns);\n\t\t\t\t\t\tif (excluded) return;\n\t\t\t\t\t\tlet kind: FSEventType = \"change\";\n\t\t\t\t\t\tif (eventType === \"rename\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tkind = existsSync(normalized) ? \"create\" : \"delete\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tkind = \"rename\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpending.set(normalized, {\n\t\t\t\t\t\t\ttype: kind,\n\t\t\t\t\t\t\tpath: normalized,\n\t\t\t\t\t\t\troot,\n\t\t\t\t\t\t\trelative_path: relForMatch,\n\t\t\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\t\t\tconst token = generation;\n\t\t\t\t\t\ttimer = setTimeout(() => flush(token), debounce);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\twatcher.on(\"error\", (err) => emitError(err));\n\t\t\t\twatchers.push(watcher);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\temitError(err);\n\t\t}\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tstopped = true;\n\t\t\t\tgeneration += 1;\n\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\ttimer = undefined;\n\t\t\t\tcloseWatchers();\n\t\t\t\tpending.clear();\n\t\t\t},\n\t\t};\n\t}, sourceOpts(rest));\n}\n","/**\n * Git hook source — Node-only reactive source that polls a repository's HEAD\n * and emits structured `GitEvent`s on every new commit.\n *\n * Isolated from `./adapters.ts` so that the universal `extra/index` barrel\n * stays browser-safe. Access via `@graphrefly/graphrefly/extra/node`, which\n * re-exports this module.\n *\n * @module\n */\n\nimport { ERROR, type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromTimer, globToRegExp, matchesAnyPattern, switchMap } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n/** Git hook type for {@link fromGitHook}. */\nexport type GitHookType = \"post-commit\" | \"post-merge\" | \"post-checkout\" | \"post-rewrite\";\n\n/** Structured git event emitted by {@link fromGitHook}. */\nexport type GitEvent = {\n\thook: GitHookType;\n\tcommit: string;\n\tfiles: string[];\n\tmessage: string;\n\tauthor: string;\n\ttimestamp_ns: number;\n};\n\n/** Options for {@link fromGitHook}. */\nexport type FromGitHookOptions = ExtraOpts & {\n\tpollMs?: number;\n\tinclude?: string[];\n\texclude?: string[];\n\t/**\n\t * Maximum consecutive poll errors before terminating the source. Prevents\n\t * error storms when the repository is unavailable (e.g. deleted, corrupt,\n\t * permissions lost). Default: `1` (terminate on first error — preserves\n\t * pre-switchMap back-compat). Raise it (or set `Infinity`) to keep\n\t * retrying indefinitely (legacy behavior).\n\t */\n\tmaxConsecutiveErrors?: number;\n};\n\n/**\n * Git change detection as a reactive source.\n *\n * @category extra\n */\nexport function fromGitHook(repoPath: string, opts?: FromGitHookOptions): Node<GitEvent> {\n\tconst { pollMs = 5000, include, exclude, maxConsecutiveErrors = 1 } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = exclude?.map(globToRegExp) ?? [];\n\tconst { execFileSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n\n\tconst gitQuery = (args: string[]): string =>\n\t\texecFileSync(\"git\", args, { cwd: repoPath, encoding: \"utf-8\" }).trim();\n\n\t// Shared across ticks: the previous HEAD we committed to. Undefined on the\n\t// very first poll (we record the initial HEAD without emitting).\n\tlet lastSeen: string | undefined;\n\t// Circuit breaker: consecutive error count. Resets on any successful poll.\n\tlet consecutiveErrors = 0;\n\n\t// `fromTimer | switchMap(sync-git-diff)` — ticks drive the poll, switchMap\n\t// cancels any in-flight inner on next tick. First tick at t=0 records the\n\t// baseline HEAD silently; subsequent ticks emit `GitEvent` on HEAD change.\n\treturn switchMap(fromTimer(0, { period: pollMs }), () =>\n\t\tnode<GitEvent>((_data, a) => {\n\t\t\ttry {\n\t\t\t\tconst head = gitQuery([\"rev-parse\", \"HEAD\"]);\n\t\t\t\tif (!head) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tif (lastSeen === undefined) {\n\t\t\t\t\t// First poll: record baseline; stay idle until next tick\n\t\t\t\t\t// disposes this inner.\n\t\t\t\t\tlastSeen = head;\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tif (head === lastSeen) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tlet files = gitQuery([\"diff\", \"--name-only\", `${lastSeen}..${head}`])\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (includePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => matchesAnyPattern(f, includePatterns));\n\t\t\t\t}\n\t\t\t\tif (excludePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => !matchesAnyPattern(f, excludePatterns));\n\t\t\t\t}\n\t\t\t\tconst message = gitQuery([\"log\", \"-1\", \"--format=%s\", head]);\n\t\t\t\tconst author = gitQuery([\"log\", \"-1\", \"--format=%an\", head]);\n\t\t\t\ta.emit({\n\t\t\t\t\thook: \"post-commit\" as GitHookType,\n\t\t\t\t\tcommit: head,\n\t\t\t\t\tfiles,\n\t\t\t\t\tmessage,\n\t\t\t\t\tauthor,\n\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t});\n\t\t\t\tlastSeen = head;\n\t\t\t\tconsecutiveErrors = 0;\n\t\t\t} catch (err) {\n\t\t\t\tconsecutiveErrors += 1;\n\t\t\t\tif (consecutiveErrors >= maxConsecutiveErrors) {\n\t\t\t\t\ta.down([[ERROR, err]]);\n\t\t\t\t}\n\t\t\t\t// else: transient error — next tick will retry; don't spam ERROR.\n\t\t\t}\n\t\t\treturn { onDeactivation: () => {} };\n\t\t}),\n\t);\n}\n","/**\n * Child-process reactive sources — Node-only.\n *\n * Isolated from `./sources.ts` so bundlers targeting the browser can import\n * browser-safe sources without pulling in `node:child_process`.\n *\n * Access via `@graphrefly/graphrefly/extra/node`, which re-exports this module.\n *\n * @module\n */\n\nimport { type SpawnOptions, spawn } from \"node:child_process\";\nimport { COMPLETE, DATA, ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * SpawnEvent — discriminated stream emitted by {@link fromSpawn}.\n *\n * @category extra\n */\nexport type SpawnEvent =\n\t| { kind: \"stdout\"; chunk: Buffer }\n\t| { kind: \"stderr\"; chunk: Buffer }\n\t| { kind: \"exit\"; code: number | null; signal: NodeJS.Signals | null };\n\n/** Options for {@link fromSpawn}. Mirrors `child_process.SpawnOptions`. */\nexport interface FromSpawnOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tshell?: boolean | string;\n\t/**\n\t * Optional caller-owned AbortSignal. When fired, the subprocess is sent\n\t * SIGTERM (per `child_process.spawn` signal semantics). The producer's own\n\t * teardown also sends SIGTERM regardless of caller signal — so `switchMap`\n\t * supersede in `actuatorExecutor` cancels in-flight subprocesses without\n\t * the caller wiring extra signals.\n\t */\n\tsignal?: AbortSignal;\n\t/** Extra args forwarded to spawn — e.g. stdio configuration. */\n\tstdio?: \"pipe\" | readonly (\"pipe\" | \"ignore\" | \"inherit\")[];\n}\n\n// ---------------------------------------------------------------------------\n// fromSpawn\n// ---------------------------------------------------------------------------\n\n/**\n * Spawn `cmd args` as a child process and stream stdout/stderr/exit as a\n * single discriminated `SpawnEvent` stream.\n *\n * Lifecycle:\n * - Stdout/stderr chunks emit as `DATA { kind: \"stdout\"|\"stderr\", chunk }`.\n * - Process exit emits one final `DATA { kind: \"exit\", code, signal }` then\n * `COMPLETE`.\n * - Spawn-error (ENOENT, EPERM, …) emits `ERROR`.\n * - Producer teardown sends `SIGTERM` to the subprocess if it is still alive.\n *\n * **Multicast semantics:** `fromSpawn` returns a node backed by a single\n * `producer` activation — the subprocess is spawned once when the first\n * subscriber connects, and all subsequent subscribers share the same event\n * stream. Unsubscribing the last subscriber tears down the subprocess.\n *\n * @example\n * ```ts\n * import { fromSpawn } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const stream = fromSpawn(\"git\", [\"log\", \"--oneline\"]);\n * stream.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value);\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function fromSpawn(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<SpawnEvent> {\n\treturn node<SpawnEvent>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stdout\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stderr\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tactions.down([\n\t\t\t\t\t[DATA, { kind: \"exit\", code: info.code, signal: info.signal }],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tif (alive) {\n\t\t\t\t\t\talive = false;\n\t\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ name: \"from_spawn\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// runProcess\n// ---------------------------------------------------------------------------\n\n/**\n * Run `cmd args` to completion and emit one DATA with aggregated output.\n *\n * Convenience over {@link fromSpawn} for the \"wait for the process to finish,\n * capture stdout/stderr as strings, get exit code\" case.\n *\n * Aggregation policy: stdout and stderr are concatenated as `Buffer`s and\n * decoded as utf-8 once at exit, so multi-byte sequences split across chunks\n * are handled correctly. Actuators that need byte-exact stdout should use\n * `fromSpawn` directly.\n *\n * @example\n * ```ts\n * import { runProcess } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const result = runProcess(\"git\", [\"rev-parse\", \"HEAD\"]);\n * result.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value.stdout.trim());\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function runProcess(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number | null;\n\tsignal: NodeJS.Signals | null;\n}> {\n\ttype Result = {\n\t\tstdout: string;\n\t\tstderr: string;\n\t\texitCode: number | null;\n\t\tsignal: NodeJS.Signals | null;\n\t};\n\treturn node<Result>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tconst stdoutChunks: Buffer[] = [];\n\t\t\tconst stderrChunks: Buffer[] = [];\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstdoutChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstderrChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tconst stdout = Buffer.concat(stdoutChunks).toString(\"utf8\");\n\t\t\t\tconst stderr = Buffer.concat(stderrChunks).toString(\"utf8\");\n\t\t\t\tactions.down([\n\t\t\t\t\t[\n\t\t\t\t\t\tDATA,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstdout,\n\t\t\t\t\t\t\tstderr,\n\t\t\t\t\t\t\texitCode: info.code,\n\t\t\t\t\t\t\tsignal: info.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tif (alive) {\n\t\t\t\t\t\talive = false;\n\t\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ name: \"run_process\" },\n\t);\n}\n"],"mappings":"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","names":["resolvePath","import_core","import_extra","import_core"]}
@@ -98,13 +98,15 @@ function fromFSWatch(paths, opts) {
98
98
  } catch (err) {
99
99
  emitError(err);
100
100
  }
101
- return () => {
102
- stopped = true;
103
- generation += 1;
104
- if (timer !== void 0) clearTimeout(timer);
105
- timer = void 0;
106
- closeWatchers();
107
- pending.clear();
101
+ return {
102
+ onDeactivation: () => {
103
+ stopped = true;
104
+ generation += 1;
105
+ if (timer !== void 0) clearTimeout(timer);
106
+ timer = void 0;
107
+ closeWatchers();
108
+ pending.clear();
109
+ }
108
110
  };
109
111
  }, sourceOpts(rest));
110
112
  }
@@ -127,19 +129,19 @@ function fromGitHook(repoPath, opts) {
127
129
  const head = gitQuery(["rev-parse", "HEAD"]);
128
130
  if (!head) {
129
131
  consecutiveErrors = 0;
130
- return () => {
131
- };
132
+ return { onDeactivation: () => {
133
+ } };
132
134
  }
133
135
  if (lastSeen === void 0) {
134
136
  lastSeen = head;
135
137
  consecutiveErrors = 0;
136
- return () => {
137
- };
138
+ return { onDeactivation: () => {
139
+ } };
138
140
  }
139
141
  if (head === lastSeen) {
140
142
  consecutiveErrors = 0;
141
- return () => {
142
- };
143
+ return { onDeactivation: () => {
144
+ } };
143
145
  }
144
146
  let files = gitQuery(["diff", "--name-only", `${lastSeen}..${head}`]).split("\n").filter(Boolean);
145
147
  if (includePatterns.length > 0) {
@@ -166,8 +168,8 @@ function fromGitHook(repoPath, opts) {
166
168
  a.down([[ERROR2, err]]);
167
169
  }
168
170
  }
169
- return () => {
170
- };
171
+ return { onDeactivation: () => {
172
+ } };
171
173
  })
172
174
  );
173
175
  }
@@ -212,17 +214,19 @@ function fromSpawn(cmd, args, opts) {
212
214
  [COMPLETE]
213
215
  ]);
214
216
  });
215
- return () => {
216
- if (alive) {
217
- alive = false;
218
- child.stdout?.removeAllListeners();
219
- child.stderr?.removeAllListeners();
220
- child.removeAllListeners("error");
221
- child.removeAllListeners("exit");
222
- child.removeAllListeners("close");
223
- try {
224
- child.kill("SIGTERM");
225
- } catch {
217
+ return {
218
+ onDeactivation: () => {
219
+ if (alive) {
220
+ alive = false;
221
+ child.stdout?.removeAllListeners();
222
+ child.stderr?.removeAllListeners();
223
+ child.removeAllListeners("error");
224
+ child.removeAllListeners("exit");
225
+ child.removeAllListeners("close");
226
+ try {
227
+ child.kill("SIGTERM");
228
+ } catch {
229
+ }
226
230
  }
227
231
  }
228
232
  };
@@ -279,17 +283,19 @@ function runProcess(cmd, args, opts) {
279
283
  [COMPLETE]
280
284
  ]);
281
285
  });
282
- return () => {
283
- if (alive) {
284
- alive = false;
285
- child.stdout?.removeAllListeners();
286
- child.stderr?.removeAllListeners();
287
- child.removeAllListeners("error");
288
- child.removeAllListeners("exit");
289
- child.removeAllListeners("close");
290
- try {
291
- child.kill("SIGTERM");
292
- } catch {
286
+ return {
287
+ onDeactivation: () => {
288
+ if (alive) {
289
+ alive = false;
290
+ child.stdout?.removeAllListeners();
291
+ child.stderr?.removeAllListeners();
292
+ child.removeAllListeners("error");
293
+ child.removeAllListeners("exit");
294
+ child.removeAllListeners("close");
295
+ try {
296
+ child.kill("SIGTERM");
297
+ } catch {
298
+ }
293
299
  }
294
300
  }
295
301
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/base/sources/node/fs-root.ts","../../../../src/base/sources/node/git-hook.ts","../../../../src/base/sources/node/process.ts"],"sourcesContent":["/**\n * Filesystem-watching source. Isolated from `./sources.ts` so bundlers\n * targeting the browser can import browser-safe sources (`fromTimer`,\n * `fromRaf`, etc.) without pulling in `node:fs`/`node:path`.\n */\n\nimport { existsSync, watch } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n\tDATA,\n\tERROR,\n\ttype Message,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport { globToRegExp, matchesAnyPattern } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions<unknown>, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\nexport type FSEventType = \"change\" | \"rename\" | \"create\" | \"delete\";\nexport type FSEvent = {\n\ttype: FSEventType;\n\tpath: string;\n\troot: string;\n\trelative_path: string;\n\tsrc_path?: string;\n\tdest_path?: string;\n\ttimestamp_ns: number;\n};\n\nexport type FromFSWatchOptions = ExtraOpts & {\n\trecursive?: boolean;\n\tdebounce?: number;\n\tinclude?: string[];\n\texclude?: string[];\n};\n\n/**\n * Watches filesystem paths and emits debounced change events.\n *\n * Uses `fs.watch` only (no polling fallback). Teardown closes all watchers.\n *\n * @category extra\n */\nexport function fromFSWatch(paths: string | string[], opts?: FromFSWatchOptions): Node<FSEvent> {\n\tconst list = Array.isArray(paths) ? paths : [paths];\n\tif (list.length === 0) {\n\t\tthrow new RangeError(\"fromFSWatch expects at least one path\");\n\t}\n\tconst { recursive = true, debounce = 100, include, exclude, ...rest } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = (exclude ?? [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"]).map(\n\t\tglobToRegExp,\n\t);\n\treturn node<FSEvent>((_data, a) => {\n\t\tconst pending = new Map<string, FSEvent>();\n\t\tconst watchers: ReturnType<typeof watch>[] = [];\n\t\tlet stopped = false;\n\t\tlet terminalEmitted = false;\n\t\tlet generation = 0;\n\t\tconst closeWatchers = () => {\n\t\t\tfor (const watcher of watchers.splice(0)) watcher.close();\n\t\t};\n\t\tconst emitError = (err: unknown) => {\n\t\t\tif (terminalEmitted) return;\n\t\t\tterminalEmitted = true;\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tpending.clear();\n\t\t\tcloseWatchers();\n\t\t\ta.down([[ERROR, err]]);\n\t\t};\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst flush = (token: number) => {\n\t\t\ttimer = undefined;\n\t\t\tif (stopped || terminalEmitted) return;\n\t\t\tif (pending.size === 0) return;\n\t\t\tconst batchMessages: Message[] = [];\n\t\t\tfor (const evt of pending.values()) batchMessages.push([DATA, evt]);\n\t\t\tpending.clear();\n\t\t\tif (stopped || terminalEmitted || token !== generation) return;\n\t\t\ta.down(batchMessages);\n\t\t};\n\t\ttry {\n\t\t\tfor (const basePath of list) {\n\t\t\t\tconst watcher = watch(\n\t\t\t\t\tbasePath,\n\t\t\t\t\t{ recursive },\n\t\t\t\t\t(eventType: \"rename\" | \"change\", fileName: string | Buffer | null) => {\n\t\t\t\t\t\tif (stopped || terminalEmitted) return;\n\t\t\t\t\t\tif (fileName == null) return;\n\t\t\t\t\t\tconst rel = String(fileName).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst abs = resolvePath(basePath, String(fileName));\n\t\t\t\t\t\tconst normalized = abs.replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst root = resolvePath(basePath).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst relForMatch = rel.startsWith(\"./\") ? rel.slice(2) : rel;\n\t\t\t\t\t\tconst included =\n\t\t\t\t\t\t\tincludePatterns.length === 0 ||\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, includePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, includePatterns);\n\t\t\t\t\t\tif (!included) return;\n\t\t\t\t\t\tconst excluded =\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, excludePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, excludePatterns);\n\t\t\t\t\t\tif (excluded) return;\n\t\t\t\t\t\tlet kind: FSEventType = \"change\";\n\t\t\t\t\t\tif (eventType === \"rename\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tkind = existsSync(normalized) ? \"create\" : \"delete\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tkind = \"rename\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpending.set(normalized, {\n\t\t\t\t\t\t\ttype: kind,\n\t\t\t\t\t\t\tpath: normalized,\n\t\t\t\t\t\t\troot,\n\t\t\t\t\t\t\trelative_path: relForMatch,\n\t\t\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\t\t\tconst token = generation;\n\t\t\t\t\t\ttimer = setTimeout(() => flush(token), debounce);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\twatcher.on(\"error\", (err) => emitError(err));\n\t\t\t\twatchers.push(watcher);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\temitError(err);\n\t\t}\n\t\treturn () => {\n\t\t\tstopped = true;\n\t\t\tgeneration += 1;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tcloseWatchers();\n\t\t\tpending.clear();\n\t\t};\n\t}, sourceOpts(rest));\n}\n","/**\n * Git hook source — Node-only reactive source that polls a repository's HEAD\n * and emits structured `GitEvent`s on every new commit.\n *\n * Isolated from `./adapters.ts` so that the universal `extra/index` barrel\n * stays browser-safe. Access via `@graphrefly/graphrefly/extra/node`, which\n * re-exports this module.\n *\n * @module\n */\n\nimport { ERROR, type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromTimer, globToRegExp, matchesAnyPattern, switchMap } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n/** Git hook type for {@link fromGitHook}. */\nexport type GitHookType = \"post-commit\" | \"post-merge\" | \"post-checkout\" | \"post-rewrite\";\n\n/** Structured git event emitted by {@link fromGitHook}. */\nexport type GitEvent = {\n\thook: GitHookType;\n\tcommit: string;\n\tfiles: string[];\n\tmessage: string;\n\tauthor: string;\n\ttimestamp_ns: number;\n};\n\n/** Options for {@link fromGitHook}. */\nexport type FromGitHookOptions = ExtraOpts & {\n\tpollMs?: number;\n\tinclude?: string[];\n\texclude?: string[];\n\t/**\n\t * Maximum consecutive poll errors before terminating the source. Prevents\n\t * error storms when the repository is unavailable (e.g. deleted, corrupt,\n\t * permissions lost). Default: `1` (terminate on first error — preserves\n\t * pre-switchMap back-compat). Raise it (or set `Infinity`) to keep\n\t * retrying indefinitely (legacy behavior).\n\t */\n\tmaxConsecutiveErrors?: number;\n};\n\n/**\n * Git change detection as a reactive source.\n *\n * @category extra\n */\nexport function fromGitHook(repoPath: string, opts?: FromGitHookOptions): Node<GitEvent> {\n\tconst { pollMs = 5000, include, exclude, maxConsecutiveErrors = 1 } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = exclude?.map(globToRegExp) ?? [];\n\tconst { execFileSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n\n\tconst gitQuery = (args: string[]): string =>\n\t\texecFileSync(\"git\", args, { cwd: repoPath, encoding: \"utf-8\" }).trim();\n\n\t// Shared across ticks: the previous HEAD we committed to. Undefined on the\n\t// very first poll (we record the initial HEAD without emitting).\n\tlet lastSeen: string | undefined;\n\t// Circuit breaker: consecutive error count. Resets on any successful poll.\n\tlet consecutiveErrors = 0;\n\n\t// `fromTimer | switchMap(sync-git-diff)` — ticks drive the poll, switchMap\n\t// cancels any in-flight inner on next tick. First tick at t=0 records the\n\t// baseline HEAD silently; subsequent ticks emit `GitEvent` on HEAD change.\n\treturn switchMap(fromTimer(0, { period: pollMs }), () =>\n\t\tnode<GitEvent>((_data, a) => {\n\t\t\ttry {\n\t\t\t\tconst head = gitQuery([\"rev-parse\", \"HEAD\"]);\n\t\t\t\tif (!head) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tif (lastSeen === undefined) {\n\t\t\t\t\t// First poll: record baseline; stay idle until next tick\n\t\t\t\t\t// disposes this inner.\n\t\t\t\t\tlastSeen = head;\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tif (head === lastSeen) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn () => {};\n\t\t\t\t}\n\t\t\t\tlet files = gitQuery([\"diff\", \"--name-only\", `${lastSeen}..${head}`])\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (includePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => matchesAnyPattern(f, includePatterns));\n\t\t\t\t}\n\t\t\t\tif (excludePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => !matchesAnyPattern(f, excludePatterns));\n\t\t\t\t}\n\t\t\t\tconst message = gitQuery([\"log\", \"-1\", \"--format=%s\", head]);\n\t\t\t\tconst author = gitQuery([\"log\", \"-1\", \"--format=%an\", head]);\n\t\t\t\ta.emit({\n\t\t\t\t\thook: \"post-commit\" as GitHookType,\n\t\t\t\t\tcommit: head,\n\t\t\t\t\tfiles,\n\t\t\t\t\tmessage,\n\t\t\t\t\tauthor,\n\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t});\n\t\t\t\tlastSeen = head;\n\t\t\t\tconsecutiveErrors = 0;\n\t\t\t} catch (err) {\n\t\t\t\tconsecutiveErrors += 1;\n\t\t\t\tif (consecutiveErrors >= maxConsecutiveErrors) {\n\t\t\t\t\ta.down([[ERROR, err]]);\n\t\t\t\t}\n\t\t\t\t// else: transient error — next tick will retry; don't spam ERROR.\n\t\t\t}\n\t\t\treturn () => {};\n\t\t}),\n\t);\n}\n","/**\n * Child-process reactive sources — Node-only.\n *\n * Isolated from `./sources.ts` so bundlers targeting the browser can import\n * browser-safe sources without pulling in `node:child_process`.\n *\n * Access via `@graphrefly/graphrefly/extra/node`, which re-exports this module.\n *\n * @module\n */\n\nimport { type SpawnOptions, spawn } from \"node:child_process\";\nimport { COMPLETE, DATA, ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * SpawnEvent — discriminated stream emitted by {@link fromSpawn}.\n *\n * @category extra\n */\nexport type SpawnEvent =\n\t| { kind: \"stdout\"; chunk: Buffer }\n\t| { kind: \"stderr\"; chunk: Buffer }\n\t| { kind: \"exit\"; code: number | null; signal: NodeJS.Signals | null };\n\n/** Options for {@link fromSpawn}. Mirrors `child_process.SpawnOptions`. */\nexport interface FromSpawnOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tshell?: boolean | string;\n\t/**\n\t * Optional caller-owned AbortSignal. When fired, the subprocess is sent\n\t * SIGTERM (per `child_process.spawn` signal semantics). The producer's own\n\t * teardown also sends SIGTERM regardless of caller signal — so `switchMap`\n\t * supersede in `actuatorExecutor` cancels in-flight subprocesses without\n\t * the caller wiring extra signals.\n\t */\n\tsignal?: AbortSignal;\n\t/** Extra args forwarded to spawn — e.g. stdio configuration. */\n\tstdio?: \"pipe\" | readonly (\"pipe\" | \"ignore\" | \"inherit\")[];\n}\n\n// ---------------------------------------------------------------------------\n// fromSpawn\n// ---------------------------------------------------------------------------\n\n/**\n * Spawn `cmd args` as a child process and stream stdout/stderr/exit as a\n * single discriminated `SpawnEvent` stream.\n *\n * Lifecycle:\n * - Stdout/stderr chunks emit as `DATA { kind: \"stdout\"|\"stderr\", chunk }`.\n * - Process exit emits one final `DATA { kind: \"exit\", code, signal }` then\n * `COMPLETE`.\n * - Spawn-error (ENOENT, EPERM, …) emits `ERROR`.\n * - Producer teardown sends `SIGTERM` to the subprocess if it is still alive.\n *\n * **Multicast semantics:** `fromSpawn` returns a node backed by a single\n * `producer` activation — the subprocess is spawned once when the first\n * subscriber connects, and all subsequent subscribers share the same event\n * stream. Unsubscribing the last subscriber tears down the subprocess.\n *\n * @example\n * ```ts\n * import { fromSpawn } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const stream = fromSpawn(\"git\", [\"log\", \"--oneline\"]);\n * stream.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value);\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function fromSpawn(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<SpawnEvent> {\n\treturn node<SpawnEvent>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stdout\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stderr\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tactions.down([\n\t\t\t\t\t[DATA, { kind: \"exit\", code: info.code, signal: info.signal }],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (alive) {\n\t\t\t\t\talive = false;\n\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t{ name: \"from_spawn\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// runProcess\n// ---------------------------------------------------------------------------\n\n/**\n * Run `cmd args` to completion and emit one DATA with aggregated output.\n *\n * Convenience over {@link fromSpawn} for the \"wait for the process to finish,\n * capture stdout/stderr as strings, get exit code\" case.\n *\n * Aggregation policy: stdout and stderr are concatenated as `Buffer`s and\n * decoded as utf-8 once at exit, so multi-byte sequences split across chunks\n * are handled correctly. Actuators that need byte-exact stdout should use\n * `fromSpawn` directly.\n *\n * @example\n * ```ts\n * import { runProcess } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const result = runProcess(\"git\", [\"rev-parse\", \"HEAD\"]);\n * result.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value.stdout.trim());\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function runProcess(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number | null;\n\tsignal: NodeJS.Signals | null;\n}> {\n\ttype Result = {\n\t\tstdout: string;\n\t\tstderr: string;\n\t\texitCode: number | null;\n\t\tsignal: NodeJS.Signals | null;\n\t};\n\treturn node<Result>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tconst stdoutChunks: Buffer[] = [];\n\t\t\tconst stderrChunks: Buffer[] = [];\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstdoutChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstderrChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tconst stdout = Buffer.concat(stdoutChunks).toString(\"utf8\");\n\t\t\t\tconst stderr = Buffer.concat(stderrChunks).toString(\"utf8\");\n\t\t\t\tactions.down([\n\t\t\t\t\t[\n\t\t\t\t\t\tDATA,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstdout,\n\t\t\t\t\t\t\tstderr,\n\t\t\t\t\t\t\texitCode: info.code,\n\t\t\t\t\t\t\tsignal: info.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn () => {\n\t\t\t\tif (alive) {\n\t\t\t\t\talive = false;\n\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\t{ name: \"run_process\" },\n\t);\n}\n"],"mappings":"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","names":["ERROR","node","wallClockNs","globToRegExp","matchesAnyPattern","DATA","ERROR","node"]}
1
+ {"version":3,"sources":["../../../../src/base/sources/node/fs-root.ts","../../../../src/base/sources/node/git-hook.ts","../../../../src/base/sources/node/process.ts"],"sourcesContent":["/**\n * Filesystem-watching source. Isolated from `./sources.ts` so bundlers\n * targeting the browser can import browser-safe sources (`fromTimer`,\n * `fromRaf`, etc.) without pulling in `node:fs`/`node:path`.\n */\n\nimport { existsSync, watch } from \"node:fs\";\nimport { resolve as resolvePath } from \"node:path\";\nimport {\n\tDATA,\n\tERROR,\n\ttype Message,\n\ttype Node,\n\ttype NodeOptions,\n\tnode,\n\twallClockNs,\n} from \"@graphrefly/pure-ts/core\";\nimport { globToRegExp, matchesAnyPattern } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions<unknown>, \"describeKind\">;\n\nfunction sourceOpts<T = unknown>(opts?: ExtraOpts): NodeOptions<T> {\n\treturn { describeKind: \"producer\", ...opts } as NodeOptions<T>;\n}\n\nexport type FSEventType = \"change\" | \"rename\" | \"create\" | \"delete\";\nexport type FSEvent = {\n\ttype: FSEventType;\n\tpath: string;\n\troot: string;\n\trelative_path: string;\n\tsrc_path?: string;\n\tdest_path?: string;\n\ttimestamp_ns: number;\n};\n\nexport type FromFSWatchOptions = ExtraOpts & {\n\trecursive?: boolean;\n\tdebounce?: number;\n\tinclude?: string[];\n\texclude?: string[];\n};\n\n/**\n * Watches filesystem paths and emits debounced change events.\n *\n * Uses `fs.watch` only (no polling fallback). Teardown closes all watchers.\n *\n * @category extra\n */\nexport function fromFSWatch(paths: string | string[], opts?: FromFSWatchOptions): Node<FSEvent> {\n\tconst list = Array.isArray(paths) ? paths : [paths];\n\tif (list.length === 0) {\n\t\tthrow new RangeError(\"fromFSWatch expects at least one path\");\n\t}\n\tconst { recursive = true, debounce = 100, include, exclude, ...rest } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = (exclude ?? [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\"]).map(\n\t\tglobToRegExp,\n\t);\n\treturn node<FSEvent>((_data, a) => {\n\t\tconst pending = new Map<string, FSEvent>();\n\t\tconst watchers: ReturnType<typeof watch>[] = [];\n\t\tlet stopped = false;\n\t\tlet terminalEmitted = false;\n\t\tlet generation = 0;\n\t\tconst closeWatchers = () => {\n\t\t\tfor (const watcher of watchers.splice(0)) watcher.close();\n\t\t};\n\t\tconst emitError = (err: unknown) => {\n\t\t\tif (terminalEmitted) return;\n\t\t\tterminalEmitted = true;\n\t\t\tstopped = true;\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t\tpending.clear();\n\t\t\tcloseWatchers();\n\t\t\ta.down([[ERROR, err]]);\n\t\t};\n\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\tconst flush = (token: number) => {\n\t\t\ttimer = undefined;\n\t\t\tif (stopped || terminalEmitted) return;\n\t\t\tif (pending.size === 0) return;\n\t\t\tconst batchMessages: Message[] = [];\n\t\t\tfor (const evt of pending.values()) batchMessages.push([DATA, evt]);\n\t\t\tpending.clear();\n\t\t\tif (stopped || terminalEmitted || token !== generation) return;\n\t\t\ta.down(batchMessages);\n\t\t};\n\t\ttry {\n\t\t\tfor (const basePath of list) {\n\t\t\t\tconst watcher = watch(\n\t\t\t\t\tbasePath,\n\t\t\t\t\t{ recursive },\n\t\t\t\t\t(eventType: \"rename\" | \"change\", fileName: string | Buffer | null) => {\n\t\t\t\t\t\tif (stopped || terminalEmitted) return;\n\t\t\t\t\t\tif (fileName == null) return;\n\t\t\t\t\t\tconst rel = String(fileName).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst abs = resolvePath(basePath, String(fileName));\n\t\t\t\t\t\tconst normalized = abs.replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst root = resolvePath(basePath).replaceAll(\"\\\\\", \"/\");\n\t\t\t\t\t\tconst relForMatch = rel.startsWith(\"./\") ? rel.slice(2) : rel;\n\t\t\t\t\t\tconst included =\n\t\t\t\t\t\t\tincludePatterns.length === 0 ||\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, includePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, includePatterns);\n\t\t\t\t\t\tif (!included) return;\n\t\t\t\t\t\tconst excluded =\n\t\t\t\t\t\t\tmatchesAnyPattern(normalized, excludePatterns) ||\n\t\t\t\t\t\t\tmatchesAnyPattern(relForMatch, excludePatterns);\n\t\t\t\t\t\tif (excluded) return;\n\t\t\t\t\t\tlet kind: FSEventType = \"change\";\n\t\t\t\t\t\tif (eventType === \"rename\") {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tkind = existsSync(normalized) ? \"create\" : \"delete\";\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tkind = \"rename\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tpending.set(normalized, {\n\t\t\t\t\t\t\ttype: kind,\n\t\t\t\t\t\t\tpath: normalized,\n\t\t\t\t\t\t\troot,\n\t\t\t\t\t\t\trelative_path: relForMatch,\n\t\t\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\t\t\tconst token = generation;\n\t\t\t\t\t\ttimer = setTimeout(() => flush(token), debounce);\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\twatcher.on(\"error\", (err) => emitError(err));\n\t\t\t\twatchers.push(watcher);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\temitError(err);\n\t\t}\n\t\treturn {\n\t\t\tonDeactivation: () => {\n\t\t\t\tstopped = true;\n\t\t\t\tgeneration += 1;\n\t\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\t\ttimer = undefined;\n\t\t\t\tcloseWatchers();\n\t\t\t\tpending.clear();\n\t\t\t},\n\t\t};\n\t}, sourceOpts(rest));\n}\n","/**\n * Git hook source — Node-only reactive source that polls a repository's HEAD\n * and emits structured `GitEvent`s on every new commit.\n *\n * Isolated from `./adapters.ts` so that the universal `extra/index` barrel\n * stays browser-safe. Access via `@graphrefly/graphrefly/extra/node`, which\n * re-exports this module.\n *\n * @module\n */\n\nimport { ERROR, type Node, type NodeOptions, node, wallClockNs } from \"@graphrefly/pure-ts/core\";\nimport { fromTimer, globToRegExp, matchesAnyPattern, switchMap } from \"@graphrefly/pure-ts/extra\";\n\ntype ExtraOpts = Omit<NodeOptions, \"describeKind\">;\n\n/** Git hook type for {@link fromGitHook}. */\nexport type GitHookType = \"post-commit\" | \"post-merge\" | \"post-checkout\" | \"post-rewrite\";\n\n/** Structured git event emitted by {@link fromGitHook}. */\nexport type GitEvent = {\n\thook: GitHookType;\n\tcommit: string;\n\tfiles: string[];\n\tmessage: string;\n\tauthor: string;\n\ttimestamp_ns: number;\n};\n\n/** Options for {@link fromGitHook}. */\nexport type FromGitHookOptions = ExtraOpts & {\n\tpollMs?: number;\n\tinclude?: string[];\n\texclude?: string[];\n\t/**\n\t * Maximum consecutive poll errors before terminating the source. Prevents\n\t * error storms when the repository is unavailable (e.g. deleted, corrupt,\n\t * permissions lost). Default: `1` (terminate on first error — preserves\n\t * pre-switchMap back-compat). Raise it (or set `Infinity`) to keep\n\t * retrying indefinitely (legacy behavior).\n\t */\n\tmaxConsecutiveErrors?: number;\n};\n\n/**\n * Git change detection as a reactive source.\n *\n * @category extra\n */\nexport function fromGitHook(repoPath: string, opts?: FromGitHookOptions): Node<GitEvent> {\n\tconst { pollMs = 5000, include, exclude, maxConsecutiveErrors = 1 } = opts ?? {};\n\tconst includePatterns = include?.map(globToRegExp) ?? [];\n\tconst excludePatterns = exclude?.map(globToRegExp) ?? [];\n\tconst { execFileSync } = require(\"node:child_process\") as typeof import(\"node:child_process\");\n\n\tconst gitQuery = (args: string[]): string =>\n\t\texecFileSync(\"git\", args, { cwd: repoPath, encoding: \"utf-8\" }).trim();\n\n\t// Shared across ticks: the previous HEAD we committed to. Undefined on the\n\t// very first poll (we record the initial HEAD without emitting).\n\tlet lastSeen: string | undefined;\n\t// Circuit breaker: consecutive error count. Resets on any successful poll.\n\tlet consecutiveErrors = 0;\n\n\t// `fromTimer | switchMap(sync-git-diff)` — ticks drive the poll, switchMap\n\t// cancels any in-flight inner on next tick. First tick at t=0 records the\n\t// baseline HEAD silently; subsequent ticks emit `GitEvent` on HEAD change.\n\treturn switchMap(fromTimer(0, { period: pollMs }), () =>\n\t\tnode<GitEvent>((_data, a) => {\n\t\t\ttry {\n\t\t\t\tconst head = gitQuery([\"rev-parse\", \"HEAD\"]);\n\t\t\t\tif (!head) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tif (lastSeen === undefined) {\n\t\t\t\t\t// First poll: record baseline; stay idle until next tick\n\t\t\t\t\t// disposes this inner.\n\t\t\t\t\tlastSeen = head;\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tif (head === lastSeen) {\n\t\t\t\t\tconsecutiveErrors = 0;\n\t\t\t\t\treturn { onDeactivation: () => {} };\n\t\t\t\t}\n\t\t\t\tlet files = gitQuery([\"diff\", \"--name-only\", `${lastSeen}..${head}`])\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\tif (includePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => matchesAnyPattern(f, includePatterns));\n\t\t\t\t}\n\t\t\t\tif (excludePatterns.length > 0) {\n\t\t\t\t\tfiles = files.filter((f) => !matchesAnyPattern(f, excludePatterns));\n\t\t\t\t}\n\t\t\t\tconst message = gitQuery([\"log\", \"-1\", \"--format=%s\", head]);\n\t\t\t\tconst author = gitQuery([\"log\", \"-1\", \"--format=%an\", head]);\n\t\t\t\ta.emit({\n\t\t\t\t\thook: \"post-commit\" as GitHookType,\n\t\t\t\t\tcommit: head,\n\t\t\t\t\tfiles,\n\t\t\t\t\tmessage,\n\t\t\t\t\tauthor,\n\t\t\t\t\ttimestamp_ns: wallClockNs(),\n\t\t\t\t});\n\t\t\t\tlastSeen = head;\n\t\t\t\tconsecutiveErrors = 0;\n\t\t\t} catch (err) {\n\t\t\t\tconsecutiveErrors += 1;\n\t\t\t\tif (consecutiveErrors >= maxConsecutiveErrors) {\n\t\t\t\t\ta.down([[ERROR, err]]);\n\t\t\t\t}\n\t\t\t\t// else: transient error — next tick will retry; don't spam ERROR.\n\t\t\t}\n\t\t\treturn { onDeactivation: () => {} };\n\t\t}),\n\t);\n}\n","/**\n * Child-process reactive sources — Node-only.\n *\n * Isolated from `./sources.ts` so bundlers targeting the browser can import\n * browser-safe sources without pulling in `node:child_process`.\n *\n * Access via `@graphrefly/graphrefly/extra/node`, which re-exports this module.\n *\n * @module\n */\n\nimport { type SpawnOptions, spawn } from \"node:child_process\";\nimport { COMPLETE, DATA, ERROR, type Messages, type Node, node } from \"@graphrefly/pure-ts/core\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * SpawnEvent — discriminated stream emitted by {@link fromSpawn}.\n *\n * @category extra\n */\nexport type SpawnEvent =\n\t| { kind: \"stdout\"; chunk: Buffer }\n\t| { kind: \"stderr\"; chunk: Buffer }\n\t| { kind: \"exit\"; code: number | null; signal: NodeJS.Signals | null };\n\n/** Options for {@link fromSpawn}. Mirrors `child_process.SpawnOptions`. */\nexport interface FromSpawnOptions {\n\tcwd?: string;\n\tenv?: NodeJS.ProcessEnv;\n\tshell?: boolean | string;\n\t/**\n\t * Optional caller-owned AbortSignal. When fired, the subprocess is sent\n\t * SIGTERM (per `child_process.spawn` signal semantics). The producer's own\n\t * teardown also sends SIGTERM regardless of caller signal — so `switchMap`\n\t * supersede in `actuatorExecutor` cancels in-flight subprocesses without\n\t * the caller wiring extra signals.\n\t */\n\tsignal?: AbortSignal;\n\t/** Extra args forwarded to spawn — e.g. stdio configuration. */\n\tstdio?: \"pipe\" | readonly (\"pipe\" | \"ignore\" | \"inherit\")[];\n}\n\n// ---------------------------------------------------------------------------\n// fromSpawn\n// ---------------------------------------------------------------------------\n\n/**\n * Spawn `cmd args` as a child process and stream stdout/stderr/exit as a\n * single discriminated `SpawnEvent` stream.\n *\n * Lifecycle:\n * - Stdout/stderr chunks emit as `DATA { kind: \"stdout\"|\"stderr\", chunk }`.\n * - Process exit emits one final `DATA { kind: \"exit\", code, signal }` then\n * `COMPLETE`.\n * - Spawn-error (ENOENT, EPERM, …) emits `ERROR`.\n * - Producer teardown sends `SIGTERM` to the subprocess if it is still alive.\n *\n * **Multicast semantics:** `fromSpawn` returns a node backed by a single\n * `producer` activation — the subprocess is spawned once when the first\n * subscriber connects, and all subsequent subscribers share the same event\n * stream. Unsubscribing the last subscriber tears down the subprocess.\n *\n * @example\n * ```ts\n * import { fromSpawn } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const stream = fromSpawn(\"git\", [\"log\", \"--oneline\"]);\n * stream.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value);\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function fromSpawn(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<SpawnEvent> {\n\treturn node<SpawnEvent>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stdout\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tactions.down([[DATA, { kind: \"stderr\", chunk }]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tactions.down([\n\t\t\t\t\t[DATA, { kind: \"exit\", code: info.code, signal: info.signal }],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tif (alive) {\n\t\t\t\t\t\talive = false;\n\t\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ name: \"from_spawn\" },\n\t);\n}\n\n// ---------------------------------------------------------------------------\n// runProcess\n// ---------------------------------------------------------------------------\n\n/**\n * Run `cmd args` to completion and emit one DATA with aggregated output.\n *\n * Convenience over {@link fromSpawn} for the \"wait for the process to finish,\n * capture stdout/stderr as strings, get exit code\" case.\n *\n * Aggregation policy: stdout and stderr are concatenated as `Buffer`s and\n * decoded as utf-8 once at exit, so multi-byte sequences split across chunks\n * are handled correctly. Actuators that need byte-exact stdout should use\n * `fromSpawn` directly.\n *\n * @example\n * ```ts\n * import { runProcess } from \"@graphrefly/graphrefly/extra/node\";\n *\n * const result = runProcess(\"git\", [\"rev-parse\", \"HEAD\"]);\n * result.subscribe((msgs) => {\n * for (const [type, value] of msgs) {\n * if (type === DATA) console.log(value.stdout.trim());\n * }\n * });\n * ```\n *\n * @category extra\n */\nexport function runProcess(\n\tcmd: string,\n\targs: readonly string[],\n\topts?: FromSpawnOptions,\n): Node<{\n\tstdout: string;\n\tstderr: string;\n\texitCode: number | null;\n\tsignal: NodeJS.Signals | null;\n}> {\n\ttype Result = {\n\t\tstdout: string;\n\t\tstderr: string;\n\t\texitCode: number | null;\n\t\tsignal: NodeJS.Signals | null;\n\t};\n\treturn node<Result>(\n\t\t(_data, actions) => {\n\t\t\tconst child = spawn(cmd, args as string[], {\n\t\t\t\tcwd: opts?.cwd,\n\t\t\t\tenv: opts?.env,\n\t\t\t\tshell: opts?.shell,\n\t\t\t\tsignal: opts?.signal,\n\t\t\t\tstdio: (opts?.stdio as SpawnOptions[\"stdio\"]) ?? \"pipe\",\n\t\t\t});\n\n\t\t\tlet alive = true;\n\t\t\tconst stdoutChunks: Buffer[] = [];\n\t\t\tconst stderrChunks: Buffer[] = [];\n\t\t\tlet exitInfo: { code: number | null; signal: NodeJS.Signals | null } | null = null;\n\n\t\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstdoutChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\tstderrChunks.push(chunk);\n\t\t\t});\n\n\t\t\tchild.on(\"error\", (err) => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tactions.down([[ERROR, err]] satisfies Messages);\n\t\t\t});\n\n\t\t\tchild.on(\"exit\", (code, signal) => {\n\t\t\t\t// Capture exit info, but defer terminal emission to \"close\" — by which\n\t\t\t\t// time all stdout/stderr \"data\" events have been delivered.\n\t\t\t\tif (exitInfo == null) exitInfo = { code, signal: signal as NodeJS.Signals | null };\n\t\t\t});\n\n\t\t\tchild.on(\"close\", () => {\n\t\t\t\tif (!alive) return;\n\t\t\t\talive = false;\n\t\t\t\tconst info = exitInfo ?? { code: null, signal: null };\n\t\t\t\tconst stdout = Buffer.concat(stdoutChunks).toString(\"utf8\");\n\t\t\t\tconst stderr = Buffer.concat(stderrChunks).toString(\"utf8\");\n\t\t\t\tactions.down([\n\t\t\t\t\t[\n\t\t\t\t\t\tDATA,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstdout,\n\t\t\t\t\t\t\tstderr,\n\t\t\t\t\t\t\texitCode: info.code,\n\t\t\t\t\t\t\tsignal: info.signal,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\t[COMPLETE],\n\t\t\t\t] satisfies Messages);\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tonDeactivation: () => {\n\t\t\t\t\tif (alive) {\n\t\t\t\t\t\talive = false;\n\t\t\t\t\t\tchild.stdout?.removeAllListeners();\n\t\t\t\t\t\tchild.stderr?.removeAllListeners();\n\t\t\t\t\t\tchild.removeAllListeners(\"error\");\n\t\t\t\t\t\tchild.removeAllListeners(\"exit\");\n\t\t\t\t\t\tchild.removeAllListeners(\"close\");\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// already dead — ignore\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\t{ name: \"run_process\" },\n\t);\n}\n"],"mappings":"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","names":["ERROR","node","wallClockNs","globToRegExp","matchesAnyPattern","DATA","ERROR","node"]}
@@ -5,10 +5,10 @@ import {
5
5
  memoryWithKG,
6
6
  memoryWithTiers,
7
7
  memoryWithVectors
8
- } from "./chunk-YXCPV26R.js";
8
+ } from "./chunk-3REMCHSS.js";
9
9
  import {
10
10
  distill
11
- } from "./chunk-A7KV5UK4.js";
11
+ } from "./chunk-G7H6PN7P.js";
12
12
 
13
13
  // src/presets/ai/agent-memory.ts
14
14
  import { DATA, node, placeholderArgs, RESOLVED } from "@graphrefly/pure-ts/core";
@@ -204,4 +204,4 @@ export {
204
204
  AgentMemoryGraph,
205
205
  agentMemory
206
206
  };
207
- //# sourceMappingURL=chunk-J5WFUEO4.js.map
207
+ //# sourceMappingURL=chunk-23MAWVOJ.js.map
@@ -3,7 +3,10 @@ import {
3
3
  cosineSimilarity,
4
4
  knowledgeGraph,
5
5
  vectorIndex
6
- } from "./chunk-U225SKB4.js";
6
+ } from "./chunk-K4ZYJ4EM.js";
7
+ import {
8
+ retry
9
+ } from "./chunk-KUFXLAEY.js";
7
10
  import {
8
11
  DEFAULT_DECAY_RATE,
9
12
  decay
@@ -13,13 +16,10 @@ import {
13
16
  } from "./chunk-FMPF42Q4.js";
14
17
  import {
15
18
  distill
16
- } from "./chunk-A7KV5UK4.js";
19
+ } from "./chunk-G7H6PN7P.js";
17
20
  import {
18
21
  nodeSignal
19
- } from "./chunk-O3MT7DYI.js";
20
- import {
21
- retry
22
- } from "./chunk-Z4YXAUDN.js";
22
+ } from "./chunk-N6MNJNHB.js";
23
23
 
24
24
  // src/utils/ai/agents/chat-stream.ts
25
25
  import { node as node2, RESOLVED } from "@graphrefly/pure-ts/core";
@@ -131,9 +131,11 @@ function _oneShotLlmCall(adapter, messages, config) {
131
131
  invokeResult = adapter.invoke(messages, { ...config.invokeOpts, signal: ac.signal });
132
132
  } catch (err) {
133
133
  emitOnce(config.onFailure("throw", err));
134
- return () => {
135
- unlinkParent();
136
- ac.abort();
134
+ return {
135
+ onDeactivation: () => {
136
+ unlinkParent();
137
+ ac.abort();
138
+ }
137
139
  };
138
140
  }
139
141
  const callNode = fromAny(invokeResult, { signal: ac.signal });
@@ -162,11 +164,13 @@ function _oneShotLlmCall(adapter, messages, config) {
162
164
  unsub();
163
165
  unsub = null;
164
166
  }
165
- return () => {
166
- unlinkParent();
167
- ac.abort();
168
- unsub?.();
169
- unsub = null;
167
+ return {
168
+ onDeactivation: () => {
169
+ unlinkParent();
170
+ ac.abort();
171
+ unsub?.();
172
+ unsub = null;
173
+ }
170
174
  };
171
175
  },
172
176
  { describeKind: "producer" }
@@ -390,16 +394,20 @@ var ToolRegistryGraph = class extends Graph2 {
390
394
  inner = handlerResultToNode(raw, ac.signal);
391
395
  } catch (err) {
392
396
  actions.down([[ERROR2, err]]);
393
- return () => {
394
- ac.abort();
397
+ return {
398
+ onDeactivation: () => {
399
+ ac.abort();
400
+ }
395
401
  };
396
402
  }
397
403
  const unsub = inner.subscribe((batch2) => {
398
404
  actions.down(batch2);
399
405
  });
400
- return () => {
401
- ac.abort();
402
- unsub();
406
+ return {
407
+ onDeactivation: () => {
408
+ ac.abort();
409
+ unsub();
410
+ }
403
411
  };
404
412
  },
405
413
  {
@@ -999,8 +1007,10 @@ function promptNode(adapter, deps, prompt, opts) {
999
1007
  } catch (err) {
1000
1008
  done = true;
1001
1009
  actions.down([[ERROR3, err]]);
1002
- return () => {
1003
- abortDispose?.();
1010
+ return {
1011
+ onDeactivation: () => {
1012
+ abortDispose?.();
1013
+ }
1004
1014
  };
1005
1015
  }
1006
1016
  const callNode = fromAny3(invokeResult);
@@ -1058,11 +1068,13 @@ function promptNode(adapter, deps, prompt, opts) {
1058
1068
  }
1059
1069
  }
1060
1070
  });
1061
- return () => {
1062
- cancelled = true;
1063
- sub();
1064
- abortDispose?.();
1065
- abortDispose = void 0;
1071
+ return {
1072
+ onDeactivation: () => {
1073
+ cancelled = true;
1074
+ sub();
1075
+ abortDispose?.();
1076
+ abortDispose = void 0;
1077
+ }
1066
1078
  };
1067
1079
  },
1068
1080
  {
@@ -1150,4 +1162,4 @@ export {
1150
1162
  llmExtractor,
1151
1163
  llmConsolidator
1152
1164
  };
1153
- //# sourceMappingURL=chunk-YXCPV26R.js.map
1165
+ //# sourceMappingURL=chunk-3REMCHSS.js.map