@agimon-ai/po-runner 0.0.0-alpha.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 (322) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +257 -0
  3. package/dist/ansiScrub-CsqTSaVT.mjs +71 -0
  4. package/dist/ansiScrub-CsqTSaVT.mjs.map +1 -0
  5. package/dist/ansiScrub-D5gpHDch.cjs +100 -0
  6. package/dist/ansiScrub-D5gpHDch.cjs.map +1 -0
  7. package/dist/ansiScrub.cjs +7 -0
  8. package/dist/ansiScrub.d.mts +26 -0
  9. package/dist/ansiScrub.d.mts.map +1 -0
  10. package/dist/ansiScrub.mjs +2 -0
  11. package/dist/apiContracts.cjs +162 -0
  12. package/dist/apiContracts.cjs.map +1 -0
  13. package/dist/apiContracts.d.mts +53 -0
  14. package/dist/apiContracts.d.mts.map +1 -0
  15. package/dist/apiContracts.mjs +157 -0
  16. package/dist/apiContracts.mjs.map +1 -0
  17. package/dist/bashResult-DNgtahGR.cjs +629 -0
  18. package/dist/bashResult-DNgtahGR.cjs.map +1 -0
  19. package/dist/bashResult-DcrRaBLv.d.mts +49 -0
  20. package/dist/bashResult-DcrRaBLv.d.mts.map +1 -0
  21. package/dist/bashResult-bIVSzoj-.mjs +546 -0
  22. package/dist/bashResult-bIVSzoj-.mjs.map +1 -0
  23. package/dist/bashRunService-CJ02XaAq.mjs +440 -0
  24. package/dist/bashRunService-CJ02XaAq.mjs.map +1 -0
  25. package/dist/bashRunService-Ci0cGdYO.d.mts +71 -0
  26. package/dist/bashRunService-Ci0cGdYO.d.mts.map +1 -0
  27. package/dist/bashRunService-DyqxOSlx.cjs +445 -0
  28. package/dist/bashRunService-DyqxOSlx.cjs.map +1 -0
  29. package/dist/bashRunService.cjs +3 -0
  30. package/dist/bashRunService.d.mts +36 -0
  31. package/dist/bashRunService.d.mts.map +1 -0
  32. package/dist/bashRunService.mjs +2 -0
  33. package/dist/bashSchema.cjs +5 -0
  34. package/dist/bashSchema.d.mts +7 -0
  35. package/dist/bashSchema.d.mts.map +1 -0
  36. package/dist/bashSchema.mjs +2 -0
  37. package/dist/bashTool-B1EwZLo_.d.mts +20 -0
  38. package/dist/bashTool-B1EwZLo_.d.mts.map +1 -0
  39. package/dist/bashTool-C-k7fmyh.mjs +24 -0
  40. package/dist/bashTool-C-k7fmyh.mjs.map +1 -0
  41. package/dist/bashTool-CdgtqVFD.cjs +41 -0
  42. package/dist/bashTool-CdgtqVFD.cjs.map +1 -0
  43. package/dist/bashTool.cjs +13 -0
  44. package/dist/bashTool.cjs.map +1 -0
  45. package/dist/bashTool.d.mts +8 -0
  46. package/dist/bashTool.d.mts.map +1 -0
  47. package/dist/bashTool.mjs +11 -0
  48. package/dist/bashTool.mjs.map +1 -0
  49. package/dist/bin/cli.cjs +78 -0
  50. package/dist/bin/cli.cjs.map +1 -0
  51. package/dist/bin/cli.d.mts +4 -0
  52. package/dist/bin/cli.d.mts.map +1 -0
  53. package/dist/bin/cli.mjs +77 -0
  54. package/dist/bin/cli.mjs.map +1 -0
  55. package/dist/bin/logSink.cjs +102 -0
  56. package/dist/bin/logSink.cjs.map +1 -0
  57. package/dist/bin/logSink.d.mts +4 -0
  58. package/dist/bin/logSink.d.mts.map +1 -0
  59. package/dist/bin/logSink.mjs +99 -0
  60. package/dist/bin/logSink.mjs.map +1 -0
  61. package/dist/bin/runnerHost.cjs +131 -0
  62. package/dist/bin/runnerHost.cjs.map +1 -0
  63. package/dist/bin/runnerHost.d.mts +4 -0
  64. package/dist/bin/runnerHost.d.mts.map +1 -0
  65. package/dist/bin/runnerHost.mjs +127 -0
  66. package/dist/bin/runnerHost.mjs.map +1 -0
  67. package/dist/cliApp-Dj9nwaOv.cjs +244 -0
  68. package/dist/cliApp-Dj9nwaOv.cjs.map +1 -0
  69. package/dist/cliApp-v8Z3rMCi.mjs +237 -0
  70. package/dist/cliApp-v8Z3rMCi.mjs.map +1 -0
  71. package/dist/cliApp.cjs +3 -0
  72. package/dist/cliApp.d.mts +18 -0
  73. package/dist/cliApp.d.mts.map +1 -0
  74. package/dist/cliApp.mjs +2 -0
  75. package/dist/clock-Cv2pddgo.mjs +16 -0
  76. package/dist/clock-Cv2pddgo.mjs.map +1 -0
  77. package/dist/clock-euJkweLq.d.mts +11 -0
  78. package/dist/clock-euJkweLq.d.mts.map +1 -0
  79. package/dist/clock-jqnLWziT.cjs +21 -0
  80. package/dist/clock-jqnLWziT.cjs.map +1 -0
  81. package/dist/clock.cjs +3 -0
  82. package/dist/clock.d.mts +10 -0
  83. package/dist/clock.d.mts.map +1 -0
  84. package/dist/clock.mjs +2 -0
  85. package/dist/compaction-4QSUsBxq.cjs +40 -0
  86. package/dist/compaction-4QSUsBxq.cjs.map +1 -0
  87. package/dist/compaction-DCw80VZj.mjs +29 -0
  88. package/dist/compaction-DCw80VZj.mjs.map +1 -0
  89. package/dist/compaction.cjs +4 -0
  90. package/dist/compaction.d.mts +10 -0
  91. package/dist/compaction.d.mts.map +1 -0
  92. package/dist/compaction.mjs +2 -0
  93. package/dist/config.cjs +41 -0
  94. package/dist/config.d.mts +2 -0
  95. package/dist/config.mjs +2 -0
  96. package/dist/extensions/mcp-ui.mjs +23 -0
  97. package/dist/extensions/mcp-ui.mjs.map +1 -0
  98. package/dist/extensions/mcp.cjs +142 -0
  99. package/dist/extensions/mcp.cjs.map +1 -0
  100. package/dist/extensions/mcp.d.mts +5 -0
  101. package/dist/extensions/mcp.d.mts.map +1 -0
  102. package/dist/extensions/mcp.mjs +114 -0
  103. package/dist/extensions/mcp.mjs.map +1 -0
  104. package/dist/extensions/server.cjs +1156 -0
  105. package/dist/extensions/server.cjs.map +1 -0
  106. package/dist/extensions/server.d.mts +5 -0
  107. package/dist/extensions/server.d.mts.map +1 -0
  108. package/dist/extensions/server.mjs +1146 -0
  109. package/dist/extensions/server.mjs.map +1 -0
  110. package/dist/extensions/web.mjs +1785 -0
  111. package/dist/extensions/web.mjs.map +1 -0
  112. package/dist/headless-BGYfIlNk.mjs +169 -0
  113. package/dist/headless-BGYfIlNk.mjs.map +1 -0
  114. package/dist/headless-CHUsBGhg.cjs +180 -0
  115. package/dist/headless-CHUsBGhg.cjs.map +1 -0
  116. package/dist/index-BZL7keVW.d.mts +31 -0
  117. package/dist/index-BZL7keVW.d.mts.map +1 -0
  118. package/dist/index-BwB_jTI9.d.mts +12 -0
  119. package/dist/index-BwB_jTI9.d.mts.map +1 -0
  120. package/dist/index-D9-IXax4.d.mts +43 -0
  121. package/dist/index-D9-IXax4.d.mts.map +1 -0
  122. package/dist/index-DBz0DxnL.d.mts +39 -0
  123. package/dist/index-DBz0DxnL.d.mts.map +1 -0
  124. package/dist/index-DM7yJpMs.d.mts +25 -0
  125. package/dist/index-DM7yJpMs.d.mts.map +1 -0
  126. package/dist/index-Dhi8asLH.d.mts +22 -0
  127. package/dist/index-Dhi8asLH.d.mts.map +1 -0
  128. package/dist/index.cjs +19 -0
  129. package/dist/index.d.mts +7 -0
  130. package/dist/index.mjs +6 -0
  131. package/dist/launcher-BDm6-DiQ.mjs +150 -0
  132. package/dist/launcher-BDm6-DiQ.mjs.map +1 -0
  133. package/dist/launcher-BG5t9nvG.d.mts +39 -0
  134. package/dist/launcher-BG5t9nvG.d.mts.map +1 -0
  135. package/dist/launcher-SlyE8R3b.cjs +157 -0
  136. package/dist/launcher-SlyE8R3b.cjs.map +1 -0
  137. package/dist/launcher.cjs +3 -0
  138. package/dist/launcher.d.mts +33 -0
  139. package/dist/launcher.d.mts.map +1 -0
  140. package/dist/launcher.mjs +2 -0
  141. package/dist/lifeline-BZaQA0rm.mjs +88 -0
  142. package/dist/lifeline-BZaQA0rm.mjs.map +1 -0
  143. package/dist/lifeline-BuV_erib.cjs +98 -0
  144. package/dist/lifeline-BuV_erib.cjs.map +1 -0
  145. package/dist/lifeline-eJdZV0nN.d.mts +19 -0
  146. package/dist/lifeline-eJdZV0nN.d.mts.map +1 -0
  147. package/dist/lifeline.cjs +6 -0
  148. package/dist/lifeline.d.mts +21 -0
  149. package/dist/lifeline.d.mts.map +1 -0
  150. package/dist/lifeline.mjs +3 -0
  151. package/dist/logFile-C7oQ_v-g.d.mts +16 -0
  152. package/dist/logFile-C7oQ_v-g.d.mts.map +1 -0
  153. package/dist/logFile-CNvepZh0.cjs +67 -0
  154. package/dist/logFile-CNvepZh0.cjs.map +1 -0
  155. package/dist/logFile-KKPbkC-a.mjs +60 -0
  156. package/dist/logFile-KKPbkC-a.mjs.map +1 -0
  157. package/dist/logFile.cjs +3 -0
  158. package/dist/logFile.d.mts +11 -0
  159. package/dist/logFile.d.mts.map +1 -0
  160. package/dist/logFile.mjs +2 -0
  161. package/dist/logReader-B6J7L7Ua.cjs +282 -0
  162. package/dist/logReader-B6J7L7Ua.cjs.map +1 -0
  163. package/dist/logReader-MdW9ffvV.d.mts +43 -0
  164. package/dist/logReader-MdW9ffvV.d.mts.map +1 -0
  165. package/dist/logReader-UfbDbwQl.mjs +257 -0
  166. package/dist/logReader-UfbDbwQl.mjs.map +1 -0
  167. package/dist/logReader.cjs +4 -0
  168. package/dist/logReader.d.mts +3 -0
  169. package/dist/logReader.mjs +2 -0
  170. package/dist/processControl-BAOa3oo_.d.mts +14 -0
  171. package/dist/processControl-BAOa3oo_.d.mts.map +1 -0
  172. package/dist/processControl-DApTpV16.mjs +26 -0
  173. package/dist/processControl-DApTpV16.mjs.map +1 -0
  174. package/dist/processControl-DNJ1WZ9N.cjs +31 -0
  175. package/dist/processControl-DNJ1WZ9N.cjs.map +1 -0
  176. package/dist/processControl.cjs +3 -0
  177. package/dist/processControl.d.mts +10 -0
  178. package/dist/processControl.d.mts.map +1 -0
  179. package/dist/processControl.mjs +2 -0
  180. package/dist/ptyHost-DWWtRrGn.d.mts +38 -0
  181. package/dist/ptyHost-DWWtRrGn.d.mts.map +1 -0
  182. package/dist/ptyHost-DlQtTB8F.mjs +150 -0
  183. package/dist/ptyHost-DlQtTB8F.mjs.map +1 -0
  184. package/dist/ptyHost-MI2Z6WTG.cjs +157 -0
  185. package/dist/ptyHost-MI2Z6WTG.cjs.map +1 -0
  186. package/dist/ptyHost.cjs +3 -0
  187. package/dist/ptyHost.d.mts +26 -0
  188. package/dist/ptyHost.d.mts.map +1 -0
  189. package/dist/ptyHost.mjs +2 -0
  190. package/dist/ptySpawner-B6GsueZd.d.mts +28 -0
  191. package/dist/ptySpawner-B6GsueZd.d.mts.map +1 -0
  192. package/dist/ptySpawner-DEi1KOnd.mjs +17 -0
  193. package/dist/ptySpawner-DEi1KOnd.mjs.map +1 -0
  194. package/dist/ptySpawner-ijw0g5_T.cjs +22 -0
  195. package/dist/ptySpawner-ijw0g5_T.cjs.map +1 -0
  196. package/dist/ptySpawner.cjs +3 -0
  197. package/dist/ptySpawner.d.mts +14 -0
  198. package/dist/ptySpawner.d.mts.map +1 -0
  199. package/dist/ptySpawner.mjs +2 -0
  200. package/dist/reconcile-BugwYFbV.cjs +133 -0
  201. package/dist/reconcile-BugwYFbV.cjs.map +1 -0
  202. package/dist/reconcile-DMeNSxwn.mjs +114 -0
  203. package/dist/reconcile-DMeNSxwn.mjs.map +1 -0
  204. package/dist/reconcile.cjs +5 -0
  205. package/dist/reconcile.d.mts +36 -0
  206. package/dist/reconcile.d.mts.map +1 -0
  207. package/dist/reconcile.mjs +2 -0
  208. package/dist/responseEnvelope.cjs +19 -0
  209. package/dist/responseEnvelope.d.mts +50 -0
  210. package/dist/responseEnvelope.d.mts.map +1 -0
  211. package/dist/responseEnvelope.mjs +3 -0
  212. package/dist/rmuxBackend-CaEWooWn.d.mts +36 -0
  213. package/dist/rmuxBackend-CaEWooWn.d.mts.map +1 -0
  214. package/dist/rmuxBackend-DfyQwJrc.mjs +509 -0
  215. package/dist/rmuxBackend-DfyQwJrc.mjs.map +1 -0
  216. package/dist/rmuxBackend-DlxgqRZ1.cjs +523 -0
  217. package/dist/rmuxBackend-DlxgqRZ1.cjs.map +1 -0
  218. package/dist/rmuxBackend.cjs +4 -0
  219. package/dist/rmuxBackend.d.mts +3 -0
  220. package/dist/rmuxBackend.mjs +2 -0
  221. package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
  222. package/dist/rtkProcessor-B4_urXQr.mjs +10 -0
  223. package/dist/rtkProcessor-B4_urXQr.mjs.map +1 -0
  224. package/dist/rtkProcessor-B9KPdyzr.mjs +309 -0
  225. package/dist/rtkProcessor-B9KPdyzr.mjs.map +1 -0
  226. package/dist/rtkProcessor-Bc4L4o_8.cjs +335 -0
  227. package/dist/rtkProcessor-Bc4L4o_8.cjs.map +1 -0
  228. package/dist/rtkProcessor-CVZvNhkJ.d.mts +35 -0
  229. package/dist/rtkProcessor-CVZvNhkJ.d.mts.map +1 -0
  230. package/dist/rtkProcessor-CsrCPyTQ.cjs +33 -0
  231. package/dist/rtkProcessor-CsrCPyTQ.cjs.map +1 -0
  232. package/dist/rtkProcessor.cjs +11 -0
  233. package/dist/rtkProcessor.d.mts +7 -0
  234. package/dist/rtkProcessor.d.mts.map +1 -0
  235. package/dist/rtkProcessor.mjs +3 -0
  236. package/dist/runnerConfig-BQBlVAXn.mjs +134 -0
  237. package/dist/runnerConfig-BQBlVAXn.mjs.map +1 -0
  238. package/dist/runnerConfig-BjtulXBI.d.mts +57 -0
  239. package/dist/runnerConfig-BjtulXBI.d.mts.map +1 -0
  240. package/dist/runnerConfig-D2tGq5ZM.cjs +367 -0
  241. package/dist/runnerConfig-D2tGq5ZM.cjs.map +1 -0
  242. package/dist/runnerDependencies-DruByBGS.mjs +647 -0
  243. package/dist/runnerDependencies-DruByBGS.mjs.map +1 -0
  244. package/dist/runnerDependencies-KMZigIxB.cjs +667 -0
  245. package/dist/runnerDependencies-KMZigIxB.cjs.map +1 -0
  246. package/dist/runnerDependencies.cjs +3 -0
  247. package/dist/runnerDependencies.d.mts +2 -0
  248. package/dist/runnerDependencies.mjs +2 -0
  249. package/dist/runnerNamer-B8FH7n2v.mjs +44 -0
  250. package/dist/runnerNamer-B8FH7n2v.mjs.map +1 -0
  251. package/dist/runnerNamer-we1XVYfM.cjs +49 -0
  252. package/dist/runnerNamer-we1XVYfM.cjs.map +1 -0
  253. package/dist/runnerNamer.cjs +3 -0
  254. package/dist/runnerNamer.d.mts +11 -0
  255. package/dist/runnerNamer.d.mts.map +1 -0
  256. package/dist/runnerNamer.mjs +2 -0
  257. package/dist/runnerPaths-BTEuzxw0.cjs +471 -0
  258. package/dist/runnerPaths-BTEuzxw0.cjs.map +1 -0
  259. package/dist/runnerPaths-B_dAAeco.mjs +451 -0
  260. package/dist/runnerPaths-B_dAAeco.mjs.map +1 -0
  261. package/dist/runnerPaths.cjs +3 -0
  262. package/dist/runnerPaths.d.mts +50 -0
  263. package/dist/runnerPaths.d.mts.map +1 -0
  264. package/dist/runnerPaths.mjs +2 -0
  265. package/dist/runnerRegistry-BmkZTJHi.cjs +371 -0
  266. package/dist/runnerRegistry-BmkZTJHi.cjs.map +1 -0
  267. package/dist/runnerRegistry-CeOHEjBv.mjs +339 -0
  268. package/dist/runnerRegistry-CeOHEjBv.mjs.map +1 -0
  269. package/dist/runnerRegistry-CtJiD02R.d.mts +88 -0
  270. package/dist/runnerRegistry-CtJiD02R.d.mts.map +1 -0
  271. package/dist/runnerRegistry.cjs +4 -0
  272. package/dist/runnerRegistry.d.mts +3 -0
  273. package/dist/runnerRegistry.mjs +2 -0
  274. package/dist/runnerSettings-DiV1lvzx.d.mts +34 -0
  275. package/dist/runnerSettings-DiV1lvzx.d.mts.map +1 -0
  276. package/dist/services/lifeline/client.cjs +52 -0
  277. package/dist/services/lifeline/client.cjs.map +1 -0
  278. package/dist/services/lifeline/client.d.mts +22 -0
  279. package/dist/services/lifeline/client.d.mts.map +1 -0
  280. package/dist/services/lifeline/client.mjs +48 -0
  281. package/dist/services/lifeline/client.mjs.map +1 -0
  282. package/dist/services/runnerSupervisor/index.cjs +207 -0
  283. package/dist/services/runnerSupervisor/index.cjs.map +1 -0
  284. package/dist/services/runnerSupervisor/index.d.mts +71 -0
  285. package/dist/services/runnerSupervisor/index.d.mts.map +1 -0
  286. package/dist/services/runnerSupervisor/index.mjs +195 -0
  287. package/dist/services/runnerSupervisor/index.mjs.map +1 -0
  288. package/dist/session-BC43uEyG.cjs +29 -0
  289. package/dist/session-BC43uEyG.cjs.map +1 -0
  290. package/dist/session-Chsb_Nh2.mjs +18 -0
  291. package/dist/session-Chsb_Nh2.mjs.map +1 -0
  292. package/dist/session-DE2Acesp.mjs +6 -0
  293. package/dist/session-DE2Acesp.mjs.map +1 -0
  294. package/dist/session-SfIPtdZO.cjs +11 -0
  295. package/dist/session-SfIPtdZO.cjs.map +1 -0
  296. package/dist/session.cjs +6 -0
  297. package/dist/session.d.mts +11 -0
  298. package/dist/session.d.mts.map +1 -0
  299. package/dist/session.mjs +3 -0
  300. package/dist/spawner-BxFsINXP.cjs +68 -0
  301. package/dist/spawner-BxFsINXP.cjs.map +1 -0
  302. package/dist/spawner-CdrN_HNk.d.mts +35 -0
  303. package/dist/spawner-CdrN_HNk.d.mts.map +1 -0
  304. package/dist/spawner-LoVsn55-.mjs +63 -0
  305. package/dist/spawner-LoVsn55-.mjs.map +1 -0
  306. package/dist/spawner.cjs +3 -0
  307. package/dist/spawner.d.mts +9 -0
  308. package/dist/spawner.d.mts.map +1 -0
  309. package/dist/spawner.mjs +2 -0
  310. package/dist/type-BXM03qSw.d.mts +44 -0
  311. package/dist/type-BXM03qSw.d.mts.map +1 -0
  312. package/dist/type-C31e1gla.d.mts +43 -0
  313. package/dist/type-C31e1gla.d.mts.map +1 -0
  314. package/dist/type-vWQNTahw.d.mts +12 -0
  315. package/dist/type-vWQNTahw.d.mts.map +1 -0
  316. package/dist/types.cjs +0 -0
  317. package/dist/types.d.mts +3 -0
  318. package/dist/types.mjs +1 -0
  319. package/llms.txt +9 -0
  320. package/package.json +303 -0
  321. package/skills/doom-runner/SKILL.md +78 -0
  322. package/src/prompts/po-use-runner/SKILL.md +47 -0
@@ -0,0 +1,180 @@
1
+ const require_runnerConfig = require("./runnerConfig-D2tGq5ZM.cjs");
2
+ const require_bashTool = require("./bashTool-CdgtqVFD.cjs");
3
+ const require_bashResult = require("./bashResult-DNgtahGR.cjs");
4
+ const require_reconcile = require("./reconcile-BugwYFbV.cjs");
5
+ //#region src/constants/headless.ts
6
+ const MS_PER_SECOND = 1e3;
7
+ //#endregion
8
+ //#region src/constants/runners.ts
9
+ const COMMAND_NAME = "runners";
10
+ const SERVER_COMMAND_DESCRIPTION = "Start and stop supervised background runners without a terminal UI.";
11
+ //#endregion
12
+ //#region src/services/runnersCommand/index.ts
13
+ /** Splits on whitespace but keeps a double-quoted run together, so a path with spaces survives. */
14
+ function tokenize(text) {
15
+ return text.match(/(?:"[^"]*"|\S)+/gu) ?? [];
16
+ }
17
+ function unquote(value) {
18
+ return value.length >= 2 && value.startsWith("\"") && value.endsWith("\"") ? value.slice(1, -1) : value;
19
+ }
20
+ /**
21
+ * Parses `start`'s tail: `key=value` pairs up to the separator, then the
22
+ * command verbatim.
23
+ *
24
+ * Without a separator the whole tail is the command, so typing
25
+ * `/runners start pnpm build` does what it looks like. Options are read only
26
+ * when a separator says where they end, which is what keeps a command such as
27
+ * `FOO=bar pnpm test` from being mistaken for one.
28
+ */
29
+ function parseStart(tail) {
30
+ const tokens = tokenize(tail);
31
+ const separator = tokens.indexOf("--");
32
+ if (separator === -1) return {
33
+ kind: "start",
34
+ command: tail.trim(),
35
+ interactive: false
36
+ };
37
+ const request = {
38
+ kind: "start",
39
+ command: tail.slice(tail.indexOf("--") + 2).trim(),
40
+ interactive: false
41
+ };
42
+ for (const token of tokens.slice(0, separator)) {
43
+ const split = token.indexOf("=");
44
+ if (split <= 0) continue;
45
+ const value = unquote(token.slice(split + 1));
46
+ const key = token.slice(0, split);
47
+ if (key === "name" && value !== "") request.name = value;
48
+ if (key === "cwd" && value !== "") request.cwd = value;
49
+ if (key === "interactive") request.interactive = value === "true";
50
+ }
51
+ return request;
52
+ }
53
+ /**
54
+ * Parses `/runners` arguments. Anything other than a known verb opens Runner
55
+ * Space, which is what the bare command has always done.
56
+ */
57
+ function parseRunnersCommand(args) {
58
+ const trimmed = args.trim();
59
+ const [verb = "", id = "", ...rest] = trimmed.split(/\s+/u).filter(Boolean);
60
+ if (verb === "start") return parseStart(trimmed.slice(verb.length).trim());
61
+ if (verb !== "stop") return { kind: "space" };
62
+ const reason = rest.join(" ").trim();
63
+ return {
64
+ kind: "stop",
65
+ id,
66
+ ...reason ? { reason } : {}
67
+ };
68
+ }
69
+ //#endregion
70
+ //#region src/services/headless/index.ts
71
+ function createHeadlessBashTool(bashRunService, summarizeLog, settings, environment = process.env) {
72
+ return {
73
+ name: require_bashTool.BASH_TOOL_NAME,
74
+ label: require_bashTool.BASH_TOOL_LABEL,
75
+ description: "Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path.",
76
+ promptSnippet: "Execute shell commands with bounded foreground output and supervised background runners",
77
+ promptGuidelines: [
78
+ `A command still running after ${Math.round(require_runnerConfig.getBackgroundThresholdMs() / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,
79
+ "Pass background: true for commands that should remain active, such as dev servers, watchers, and tails.",
80
+ "Stop background runners when they are no longer needed."
81
+ ],
82
+ parameters: require_bashTool.BashParamsSchema,
83
+ executionMode: "serial",
84
+ execute: async (_toolCallId, params, signal, onUpdate, context) => {
85
+ const { command, timeout, background, interactive, name } = params;
86
+ if (signal?.aborted) throw new Error("Operation aborted");
87
+ if (onUpdate) onUpdate(require_bashResult.textResult(`Starting ${interactive === true ? "interactive runner" : background === true ? "background runner" : "command"}...`));
88
+ let onOutput;
89
+ if (background !== true && interactive !== true && onUpdate) onOutput = (output) => onUpdate(require_bashResult.textResult(output));
90
+ const result = await bashRunService.run({
91
+ command,
92
+ timeoutMs: timeout === void 0 ? void 0 : timeout * MS_PER_SECOND,
93
+ background,
94
+ interactive,
95
+ name,
96
+ ...onOutput ? { onOutput } : {},
97
+ ...signal ? { signal } : {},
98
+ cwd: context.cwd,
99
+ sessionId: context.sessionId
100
+ });
101
+ if (signal?.aborted) throw new Error("Operation aborted");
102
+ return require_bashResult.formatRunResult(result, require_bashResult.parseResultPragma(command), summarizeLog, settings, environment);
103
+ }
104
+ };
105
+ }
106
+ function createHeadlessRunnersCommand(dependencies) {
107
+ return {
108
+ name: COMMAND_NAME,
109
+ description: SERVER_COMMAND_DESCRIPTION,
110
+ async execute(args, context) {
111
+ const request = parseRunnersCommand(args);
112
+ if (request.kind === "space") {
113
+ const active = await dependencies.runnerRegistry.listBySession(context.sessionId);
114
+ await context.client.notify({
115
+ body: `${active.length} active runner${active.length === 1 ? "" : "s"}.`,
116
+ level: "info"
117
+ });
118
+ return;
119
+ }
120
+ if (request.kind === "start") {
121
+ if (!request.command) throw new Error("Usage: /runners start [name=x] [cwd=y] [interactive=true] -- <command>");
122
+ const result = await dependencies.bashRunService.run({
123
+ command: request.command,
124
+ background: true,
125
+ sessionId: context.sessionId,
126
+ cwd: request.cwd === void 0 ? context.cwd : request.cwd,
127
+ ...request.name ? { name: request.name } : {},
128
+ ...request.interactive ? { interactive: true } : {}
129
+ });
130
+ await context.client.notify({
131
+ body: require_bashResult.formatRunResult(result, {}, void 0, dependencies.settings, dependencies.environment).content[0]?.text ?? "Runner started.",
132
+ level: "info"
133
+ });
134
+ return;
135
+ }
136
+ if (!request.id) throw new Error("Usage: /runners stop <runner-id> [reason]");
137
+ const record = await dependencies.runnerRegistry.get(request.id, context.sessionId);
138
+ if (!record) {
139
+ await context.client.notify({
140
+ body: `No active runner ${request.id} in this session.`,
141
+ level: "warning"
142
+ });
143
+ return;
144
+ }
145
+ const stopped = await require_reconcile.stopRunnerProcess(record, dependencies.launcher, dependencies.rmuxBackend, {
146
+ registry: dependencies.runnerRegistry,
147
+ intent: {
148
+ reason: "stopped",
149
+ terminationReason: "user_stop",
150
+ ...request.reason ? { stopReason: request.reason } : {}
151
+ }
152
+ });
153
+ if (stopped) await dependencies.runnerRegistry.complete(request.id, {
154
+ reason: "stopped",
155
+ code: null,
156
+ signal: null,
157
+ ...request.reason ? { stopReason: request.reason } : {}
158
+ }, context.sessionId);
159
+ await context.client.notify({
160
+ body: stopped ? `Stopped runner ${request.id}.` : `Could not stop runner ${request.id}.`,
161
+ level: stopped ? "info" : "error"
162
+ });
163
+ }
164
+ };
165
+ }
166
+ //#endregion
167
+ Object.defineProperty(exports, "createHeadlessBashTool", {
168
+ enumerable: true,
169
+ get: function() {
170
+ return createHeadlessBashTool;
171
+ }
172
+ });
173
+ Object.defineProperty(exports, "createHeadlessRunnersCommand", {
174
+ enumerable: true,
175
+ get: function() {
176
+ return createHeadlessRunnersCommand;
177
+ }
178
+ });
179
+
180
+ //# sourceMappingURL=headless-CHUsBGhg.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless-CHUsBGhg.cjs","names":["BASH_TOOL_NAME","BASH_TOOL_LABEL","getBackgroundThresholdMs","BashParamsSchema","textResult","formatRunResult","parseResultPragma","stopRunnerProcess"],"sources":["../src/constants/headless.ts","../src/constants/runners.ts","../src/constants/runnersCommand.ts","../src/services/runnersCommand/index.ts","../src/services/headless/index.ts"],"sourcesContent":["export const MS_PER_SECOND = 1000;\n","export const COMMAND_NAME = 'runners';\nexport const COMMAND_DESCRIPTION =\n 'Open Runner Space: background processes started by bash. `/runners stop <id> [reason]` stops one, `/runners start [name=x] [cwd=y] [interactive=true] -- <command>` starts one.';\nexport const SERVER_COMMAND_DESCRIPTION = 'Start and stop supervised background runners without a terminal UI.';\n","export const RUNNERS_STOP_VERB = 'stop';\nexport const RUNNERS_START_VERB = 'start';\nexport const RUNNERS_COMMAND_SEPARATOR = '--';\nexport const NAME_KEY = 'name';\nexport const CWD_KEY = 'cwd';\nexport const INTERACTIVE_KEY = 'interactive';\n","import {\n CWD_KEY,\n INTERACTIVE_KEY,\n NAME_KEY,\n RUNNERS_COMMAND_SEPARATOR,\n RUNNERS_START_VERB,\n RUNNERS_STOP_VERB,\n} from '../../constants/runnersCommand';\n/** The `/runners` verb that stops one runner without opening Runner Space. */\n/** The `/runners` verb that starts one, for a client that cannot call the bash tool. */\n/**\n * Ends the options and begins the command.\n *\n * A command is arbitrary shell: it may hold `=`, and it may hold flags of its\n * own (`pnpm test -- --watch`). Only the first of these is the separator, so\n * everything the reader typed survives intact after it.\n */\n\nexport interface RunnersStartRequest {\n kind: 'start';\n /** The shell command to run; empty when the reader gave none. */\n command: string;\n cwd?: string;\n name?: string;\n interactive: boolean;\n}\n\nexport type RunnersCommandRequest =\n /** No arguments: open Runner Space. */\n | { kind: 'space' }\n /** `stop <id> [reason]`: stop one runner headlessly; id is empty when it was left out. */\n | { kind: 'stop'; id: string; reason?: string }\n /** `start [key=value ...] -- <command>`: start one headlessly. */\n | RunnersStartRequest;\n\n/** Splits on whitespace but keeps a double-quoted run together, so a path with spaces survives. */\nfunction tokenize(text: string): string[] {\n return text.match(/(?:\"[^\"]*\"|\\S)+/gu) ?? [];\n}\n\nfunction unquote(value: string): string {\n return value.length >= 2 && value.startsWith('\"') && value.endsWith('\"') ? value.slice(1, -1) : value;\n}\n\n/**\n * Parses `start`'s tail: `key=value` pairs up to the separator, then the\n * command verbatim.\n *\n * Without a separator the whole tail is the command, so typing\n * `/runners start pnpm build` does what it looks like. Options are read only\n * when a separator says where they end, which is what keeps a command such as\n * `FOO=bar pnpm test` from being mistaken for one.\n */\nfunction parseStart(tail: string): RunnersStartRequest {\n const tokens = tokenize(tail);\n const separator = tokens.indexOf(RUNNERS_COMMAND_SEPARATOR);\n if (separator === -1) return { kind: 'start', command: tail.trim(), interactive: false };\n\n const request: RunnersStartRequest = {\n kind: 'start',\n // Sliced from the raw text rather than rejoined from tokens: rejoining\n // would collapse the spacing the reader wrote.\n command: tail.slice(tail.indexOf(RUNNERS_COMMAND_SEPARATOR) + RUNNERS_COMMAND_SEPARATOR.length).trim(),\n interactive: false,\n };\n for (const token of tokens.slice(0, separator)) {\n const split = token.indexOf('=');\n if (split <= 0) continue;\n const value = unquote(token.slice(split + 1));\n const key = token.slice(0, split);\n if (key === NAME_KEY && value !== '') request.name = value;\n if (key === CWD_KEY && value !== '') request.cwd = value;\n if (key === INTERACTIVE_KEY) request.interactive = value === 'true';\n }\n return request;\n}\n\n/**\n * Parses `/runners` arguments. Anything other than a known verb opens Runner\n * Space, which is what the bare command has always done.\n */\nexport function parseRunnersCommand(args: string): RunnersCommandRequest {\n const trimmed = args.trim();\n const [verb = '', id = '', ...rest] = trimmed.split(/\\s+/u).filter(Boolean);\n if (verb === RUNNERS_START_VERB) return parseStart(trimmed.slice(verb.length).trim());\n if (verb !== RUNNERS_STOP_VERB) return { kind: 'space' };\n const reason = rest.join(' ').trim();\n return { kind: 'stop', id, ...(reason ? { reason } : {}) };\n}\n","import type {\n DoomHeadlessCommand,\n DoomHeadlessExecutionContext,\n DoomHeadlessTool,\n DoomHeadlessToolResult,\n} from '@agimon-ai/po-core/headless';\n\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME } from '../../constants/bashTool';\nimport { MS_PER_SECOND } from '../../constants/headless';\nimport { COMMAND_NAME, SERVER_COMMAND_DESCRIPTION } from '../../constants/runners';\nimport { type BashParams, BashParamsSchema } from '../../schemas/bashTool';\nimport { formatRunResult, parseResultPragma, textResult } from '../../services/bashResult';\nimport { stopRunnerProcess } from '../../services/reconcile';\nimport { getBackgroundThresholdMs } from '../../services/runnerConfig';\nimport type { RunnerDependencies } from '../../services/runnerDependencies/type';\nimport { parseRunnersCommand } from '../../services/runnersCommand';\nimport { type LogSummarizer } from '../../types/bashResult';\nimport type { IBashRunService } from '../../types/bashRunService';\nimport type { RunnerSettings } from '../../types/runnerSettings';\n\nexport function createHeadlessBashTool(\n bashRunService: IBashRunService,\n summarizeLog?: LogSummarizer,\n settings?: RunnerSettings,\n environment: NodeJS.ProcessEnv = process.env,\n): DoomHeadlessTool<typeof BashParamsSchema> {\n return {\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path.',\n promptSnippet: 'Execute shell commands with bounded foreground output and supervised background runners',\n promptGuidelines: [\n `A command still running after ${Math.round(getBackgroundThresholdMs() / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true for commands that should remain active, such as dev servers, watchers, and tails.',\n 'Stop background runners when they are no longer needed.',\n ],\n parameters: BashParamsSchema,\n executionMode: 'serial',\n execute: async (\n _toolCallId: string,\n params: BashParams,\n signal: AbortSignal | undefined,\n onUpdate: ((result: DoomHeadlessToolResult) => void) | undefined,\n context: DoomHeadlessExecutionContext,\n ) => {\n const { command, timeout, background, interactive, name } = params;\n if (signal?.aborted) throw new Error('Operation aborted');\n if (onUpdate)\n onUpdate(\n textResult(\n `Starting ${interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command'}...`,\n ),\n );\n let onOutput: ((output: string) => void) | undefined;\n if (background !== true && interactive !== true && onUpdate) onOutput = (output) => onUpdate(textResult(output));\n const result = await bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n ...(signal ? { signal } : {}),\n cwd: context.cwd,\n sessionId: context.sessionId,\n });\n if (signal?.aborted) throw new Error('Operation aborted');\n return formatRunResult(result, parseResultPragma(command), summarizeLog, settings, environment);\n },\n };\n}\n\nexport function createHeadlessRunnersCommand(dependencies: RunnerDependencies): DoomHeadlessCommand {\n return {\n name: COMMAND_NAME,\n description: SERVER_COMMAND_DESCRIPTION,\n async execute(args: string, context: DoomHeadlessExecutionContext) {\n const request = parseRunnersCommand(args);\n if (request.kind === 'space') {\n const active = await dependencies.runnerRegistry.listBySession(context.sessionId);\n await context.client.notify({\n body: `${active.length} active runner${active.length === 1 ? '' : 's'}.`,\n level: 'info',\n });\n return;\n }\n if (request.kind === 'start') {\n if (!request.command) throw new Error('Usage: /runners start [name=x] [cwd=y] [interactive=true] -- <command>');\n const result = await dependencies.bashRunService.run({\n command: request.command,\n background: true,\n sessionId: context.sessionId,\n cwd: request.cwd === undefined ? context.cwd : request.cwd,\n ...(request.name ? { name: request.name } : {}),\n ...(request.interactive ? { interactive: true } : {}),\n });\n await context.client.notify({\n body:\n formatRunResult(result, {}, undefined, dependencies.settings, dependencies.environment).content[0]?.text ??\n 'Runner started.',\n level: 'info',\n });\n return;\n }\n if (!request.id) throw new Error('Usage: /runners stop <runner-id> [reason]');\n const record = await dependencies.runnerRegistry.get(request.id, context.sessionId);\n if (!record) {\n await context.client.notify({ body: `No active runner ${request.id} in this session.`, level: 'warning' });\n return;\n }\n const stopped = await stopRunnerProcess(record, dependencies.launcher, dependencies.rmuxBackend, {\n registry: dependencies.runnerRegistry,\n intent: {\n reason: 'stopped',\n terminationReason: 'user_stop',\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n });\n if (stopped) {\n await dependencies.runnerRegistry.complete(\n request.id,\n {\n reason: 'stopped',\n code: null,\n signal: null,\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n context.sessionId,\n );\n }\n await context.client.notify({\n body: stopped ? `Stopped runner ${request.id}.` : `Could not stop runner ${request.id}.`,\n level: stopped ? 'info' : 'error',\n });\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { c as RtkProcessResult, o as RtkFilter, s as RtkProcessRequest, t as IRtkProcessor } from "./rtkProcessor-CVZvNhkJ.mjs";
2
+ import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
3
+ //#region src/services/rtkProcessor/index.d.ts
4
+ type BinaryResolver = () => string | undefined;
5
+ declare class RtkProcessor implements IRtkProcessor {
6
+ private readonly resolveBinary;
7
+ private readonly timeoutMs;
8
+ private readonly env;
9
+ private readonly settings?;
10
+ /**
11
+ * Latched once a binary proves unrunnable on this host.
12
+ *
13
+ * A glibc build installed on a musl host satisfies os and cpu, so it
14
+ * resolves and then fails to exec. Without this the same doomed spawn is
15
+ * paid on every command, and each one is reported as a processing failure
16
+ * rather than the absence it actually is.
17
+ */
18
+ private unrunnable;
19
+ constructor(resolveBinary?: BinaryResolver, timeoutMs?: number, env?: Readonly<Record<string, string | undefined>>, settings?: RunnerSettings | undefined);
20
+ process(request: RtkProcessRequest): Promise<RtkProcessResult>;
21
+ private pipe;
22
+ }
23
+ /**
24
+ * Classifies only whitespace-delimited single commands. Shell syntax, expansion,
25
+ * quoting, and globbing are rejected instead of being partially interpreted.
26
+ */
27
+ declare function classifyRtkFilter(command: string): RtkFilter | undefined;
28
+ declare function rtkPackageForTarget(platform: string, architecture: string): string | undefined;
29
+ //#endregion
30
+ export { classifyRtkFilter as n, rtkPackageForTarget as r, RtkProcessor as t };
31
+ //# sourceMappingURL=index-BZL7keVW.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BZL7keVW.d.mts","names":[],"sources":["../src/services/rtkProcessor/index.ts"],"mappings":";;;KA8EK;cAEQ,wBAAwB;mBAYhB;mBACA;mBACA;mBACA;;;;;;;;;UANX;EAER,YACmB,gBAAe,gBACf,oBACA,MAAK,SAAS,qCACd,WAAW;EAGxB,QAAQ,SAAS,oBAAoB,QAAQ;UA0B3C;;;;;;iBAwGM,kBAAkB,kBAAkB;iBAyDpC,oBAAoB,kBAAkB"}
@@ -0,0 +1,12 @@
1
+ import { a as IBashRunService } from "./bashRunService-Ci0cGdYO.mjs";
2
+ import { n as BashParamsSchema } from "./bashTool-B1EwZLo_.mjs";
3
+ import { r as LogSummarizer } from "./bashResult-DcrRaBLv.mjs";
4
+ import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
5
+ import { t as RunnerDependencies } from "./type-C31e1gla.mjs";
6
+ import { DoomHeadlessCommand, DoomHeadlessTool } from "@agimon-ai/po-core/headless";
7
+ //#region src/services/headless/index.d.ts
8
+ declare function createHeadlessBashTool(bashRunService: IBashRunService, summarizeLog?: LogSummarizer, settings?: RunnerSettings, environment?: NodeJS.ProcessEnv): DoomHeadlessTool<typeof BashParamsSchema>;
9
+ declare function createHeadlessRunnersCommand(dependencies: RunnerDependencies): DoomHeadlessCommand;
10
+ //#endregion
11
+ export { createHeadlessRunnersCommand as n, createHeadlessBashTool as t };
12
+ //# sourceMappingURL=index-BwB_jTI9.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BwB_jTI9.d.mts","names":[],"sources":["../src/services/headless/index.ts"],"mappings":";;;;;;;iBAoBgB,uBACd,gBAAgB,iBAChB,eAAe,eACf,WAAW,gBACX,cAAa,OAAO,aACnB,wBAAwB;iBAgDX,6BAA6B,cAAc,qBAAqB"}
@@ -0,0 +1,43 @@
1
+ import { t as ExitResult } from "./spawner-CdrN_HNk.mjs";
2
+ import { r as RunHandle } from "./launcher-BG5t9nvG.mjs";
3
+ import { r as PtyRun } from "./ptyHost-DWWtRrGn.mjs";
4
+ import { n as RmuxLaunchRequest, t as IRmuxBackend } from "./rmuxBackend-CaEWooWn.mjs";
5
+ import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
6
+ import { t as IRunnerPaths } from "./type-BXM03qSw.mjs";
7
+ //#region src/services/rmuxBackend/index.d.ts
8
+ declare class RmuxBackend implements IRmuxBackend {
9
+ private readonly paths;
10
+ private readonly env;
11
+ private readonly settings?;
12
+ private clientPromise;
13
+ private readonly runs;
14
+ private readonly completions;
15
+ constructor(paths: IRunnerPaths, env?: Readonly<Record<string, string | undefined>>, settings?: RunnerSettings | undefined);
16
+ launch(request: RmuxLaunchRequest): Promise<RunHandle | undefined>;
17
+ stop(target: string, expectedPid: number): Promise<boolean>;
18
+ watch(id: string, target: string, sessionId?: string): Promise<ExitResult | undefined>;
19
+ input(target: string, text: string): Promise<boolean>;
20
+ capture(target: string): Promise<string | undefined>;
21
+ get(name: string): PtyRun | undefined;
22
+ readOutcome(id: string, sessionId: string): ExitResult | undefined;
23
+ private trackCompletion;
24
+ private client;
25
+ private resolveClient;
26
+ private prepareFiles;
27
+ private auxPaths;
28
+ /**
29
+ * The sink the pane pipes into.
30
+ *
31
+ * An interactive run also asks for a raw copy: the scrubbed log it writes
32
+ * beside it has had cursor movement taken out, which is what a terminal
33
+ * needs most. Only interactive runs pay for it, because only they can be
34
+ * attached to.
35
+ */
36
+ private logPipeCommand;
37
+ private monitor;
38
+ private interactiveRun;
39
+ }
40
+ declare function rmuxPackageForTarget(platform: string, architecture: string): string | undefined;
41
+ //#endregion
42
+ export { rmuxPackageForTarget as n, RmuxBackend as t };
43
+ //# sourceMappingURL=index-D9-IXax4.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-D9-IXax4.d.mts","names":[],"sources":["../src/services/rmuxBackend/index.ts"],"mappings":";;;;;;;cAoDa,uBAAuB;mBAMf;mBACA;mBACA;UAPX;mBACS;mBACA;EAEjB,YACmB,OAAO,cACP,MAAK,SAAS,qCACd,WAAW;EAGxB,OAAO,SAAS,oBAAoB,QAAQ;EAuF5C,KAAK,gBAAgB,sBAAsB;EA6B3C,MAAM,YAAY,gBAAgB,qBAAqB,QAAQ;EAe/D,MAAM,gBAAgB,eAAe;EAcrC,QAAQ,iBAAiB;EAa/B,IAAI,eAAe;EAInB,YAAY,YAAY,oBAAoB;UAIpC;UAOA;UAKM;UAkBN;UAUA;;;;;;;;;UAYA;UAaM;UA+BN;;iBA4CM,qBAAqB,kBAAkB"}
@@ -0,0 +1,39 @@
1
+ import { a as RunnerTerminationIntent, i as RunnerRecord, n as IRunnerRegistry, r as RegisterRunnerInput, t as CompleteRunnerInput } from "./runnerRegistry-CtJiD02R.mjs";
2
+ import { t as IProcessControl } from "./processControl-BAOa3oo_.mjs";
3
+ import { t as IRunnerPaths } from "./type-BXM03qSw.mjs";
4
+ import { ProcessRegistryService } from "@agimon-ai/foundation-process-registry";
5
+ //#region src/services/runnerRegistry/index.d.ts
6
+ /** The slice of the shared registry service this wrapper depends on. */
7
+ type ProcessRegistryPort = Pick<ProcessRegistryService, 'registerProcess' | 'releaseProcess' | 'listProcesses' | 'close'>;
8
+ /** Opens the SQLite-backed registry the rest of the monorepo already shares. */
9
+ declare function createDefaultProcessRegistry(env?: Readonly<Record<string, string | undefined>>): ProcessRegistryPort;
10
+ declare class RunnerRegistry implements IRunnerRegistry {
11
+ private readonly paths;
12
+ private readonly processControl;
13
+ private readonly registry;
14
+ private readonly environment;
15
+ private readonly subscriptions;
16
+ constructor(paths: IRunnerPaths, processControl: IProcessControl, registry: ProcessRegistryPort, environment: Readonly<Record<string, string | undefined>>);
17
+ register(input: RegisterRunnerInput): Promise<RunnerRecord>;
18
+ list(): Promise<RunnerRecord[]>;
19
+ listAcrossRepositories(): Promise<RunnerRecord[]>;
20
+ listBySession(sessionId: string): Promise<RunnerRecord[]>;
21
+ listByRootSession(rootSessionId: string): Promise<RunnerRecord[]>;
22
+ listAll(sessionId?: string): Promise<RunnerRecord[]>;
23
+ get(id: string, sessionId?: string): Promise<RunnerRecord | undefined>;
24
+ markPromoted(id: string): Promise<RunnerRecord | undefined>;
25
+ requestTermination(id: string, intent: RunnerTerminationIntent | undefined, sessionId?: string): Promise<RunnerRecord | undefined>;
26
+ complete(id: string, outcome: CompleteRunnerInput, sessionId?: string): Promise<RunnerRecord | undefined>;
27
+ release(id: string, sessionId?: string): Promise<void>;
28
+ pruneDead(): Promise<string[]>;
29
+ subscribe(listener: () => void, sessionId: string): () => void;
30
+ close(): void;
31
+ private notify;
32
+ private removeSubscription;
33
+ private subscriptionKey;
34
+ private repositoryPath;
35
+ private writeRecord;
36
+ }
37
+ //#endregion
38
+ export { RunnerRegistry as n, createDefaultProcessRegistry as r, ProcessRegistryPort as t };
39
+ //# sourceMappingURL=index-DBz0DxnL.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DBz0DxnL.d.mts","names":[],"sources":["../src/services/runnerRegistry/index.ts"],"mappings":";;;;;;KAoCY,sBAAsB,KAChC;;iBAKc,6BACd,MAAK,SAAS,sCACb;cA+CU,0BAA0B;mBAIlB;mBACA;mBACA;mBACA;mBANF;EAEjB,YACmB,OAAO,cACP,gBAAgB,iBAChB,UAAU,qBACV,aAAa,SAAS;EAGnC,SAAS,OAAO,sBAAsB,QAAQ;EAqD9C,QAAQ,QAAQ;EAShB,0BAA0B,QAAQ;EAQlC,cAAc,oBAAoB,QAAQ;EAK1C,kBAAkB,wBAAwB,QAAQ;EAKlD,QAAQ,qBAAqB,QAAQ;EAgBrC,IAAI,YAAY,qBAAqB,QAAQ;EAgB7C,aAAa,aAAa,QAAQ;EASlC,mBACJ,YACA,QAAQ,qCACR,qBACC,QAAQ;EAWL,SAAS,YAAY,SAAS,qBAAqB,qBAAqB,QAAQ;EAiChF,QAAQ,YAAY,qBAAqB;EAiBzC,aAAa;EAQnB,UAAU,sBAAsB;EAUhC;UAKQ;UAUA;UAOA;UAIA;UAIA"}
@@ -0,0 +1,25 @@
1
+ import { c as TruncatedOutput, i as LogSummary } from "./bashResult-DcrRaBLv.mjs";
2
+ import { n as LogQuery, r as LogSlice, t as ILogReader } from "./logReader-MdW9ffvV.mjs";
3
+ import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
4
+ //#region src/services/logReader/index.d.ts
5
+ declare class LogReader implements ILogReader {
6
+ read(logPath: string, query?: LogQuery): LogSlice;
7
+ }
8
+ /**
9
+ * Grep with context, matching the `product-stack logs` semantics so the two
10
+ * surfaces behave the same. Overlapping and adjacent context windows merge.
11
+ */
12
+ declare function filterLogText(text: string, query: Pick<LogQuery, 'grep' | 'ignoreCase' | 'contextLines'>): string;
13
+ /** Reads a bounded head and tail plus exact metadata after the writer has flushed. */
14
+ declare function summarizeLog(path: string, maxLines?: number, maxBytes?: number, maxTokens?: number, settings?: RunnerSettings): LogSummary;
15
+ /**
16
+ * Keeps both ends of an oversized result and points at the file holding the rest.
17
+ *
18
+ * The notice states the file's real size and line count so the model does not
19
+ * guess at offsets when it goes on to read the file, which is the failure this
20
+ * whole policy exists to prevent.
21
+ */
22
+ declare function truncateForResult(text: string, fullOutputPath: string, maxBytes?: number, maxLines?: number): TruncatedOutput;
23
+ //#endregion
24
+ export { truncateForResult as i, filterLogText as n, summarizeLog as r, LogReader as t };
25
+ //# sourceMappingURL=index-DM7yJpMs.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DM7yJpMs.d.mts","names":[],"sources":["../src/services/logReader/index.ts"],"mappings":";;;;cAuBa,qBAAqB;EAChC,KAAK,iBAAiB,QAAO,WAAgB;;;;;;iBA0G/B,cAAc,cAAc,OAAO,KAAK;;iBA8BxC,aACd,cACA,mBACA,mBACA,oBACA,WAAW,iBACV;;;;;;;;iBAmEa,kBACd,cACA,wBACA,mBACA,oBACC"}
@@ -0,0 +1,22 @@
1
+ import { t as RunnerDependencies } from "./type-C31e1gla.mjs";
2
+ import { DoomHostExecutionBudget } from "@agimon-ai/po-core/packageApi";
3
+ //#region src/services/runnerDependencies/index.d.ts
4
+ /**
5
+ * Builds the extension's service graph.
6
+ *
7
+ * A factory rather than a module-level singleton: the extension owns one graph
8
+ * per session, and tests get a fresh one they can substitute ports on through
9
+ * `overrides` without leaking state between cases.
10
+ *
11
+ * Every slot resolves lazily and memoizes, which keeps the previous container's
12
+ * behaviour: nothing is constructed until it is asked for, so opening the SQLite
13
+ * process registry stays deferred until something actually needs a runner.
14
+ */
15
+ declare function createRunnerDependencies(overrides: Partial<RunnerDependencies> & {
16
+ environment: Readonly<Record<string, string | undefined>>;
17
+ cwd?: string;
18
+ executionBudget?: DoomHostExecutionBudget;
19
+ }): RunnerDependencies;
20
+ //#endregion
21
+ export { createRunnerDependencies as t };
22
+ //# sourceMappingURL=index-Dhi8asLH.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Dhi8asLH.d.mts","names":[],"sources":["../src/services/runnerDependencies/index.ts"],"mappings":";;;;;;;;;;;;;;iBA4CgB,yBACd,WAAW,QAAQ;EACjB,aAAa,SAAS;EACtB;EACA,kBAAkB;IAEnB"}
package/dist/index.cjs ADDED
@@ -0,0 +1,19 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runnerConfig = require("./runnerConfig-D2tGq5ZM.cjs");
3
+ const require_headless = require("./headless-CHUsBGhg.cjs");
4
+ const require_rmuxBackend = require("./rmuxBackend-DlxgqRZ1.cjs");
5
+ const require_rtkProcessor = require("./rtkProcessor-Bc4L4o_8.cjs");
6
+ const require_runnerDependencies = require("./runnerDependencies-KMZigIxB.cjs");
7
+ exports.DEFAULT_BG_THRESHOLD_MS = require_runnerConfig.DEFAULT_BG_THRESHOLD_MS;
8
+ exports.DEFAULT_LOG_MAX_BYTES = require_runnerConfig.DEFAULT_LOG_MAX_BYTES;
9
+ exports.DEFAULT_LOG_TTL_MS = require_runnerConfig.DEFAULT_LOG_TTL_MS;
10
+ exports.DEFAULT_RESULT_MAX_BYTES = require_runnerConfig.DEFAULT_RESULT_MAX_BYTES;
11
+ exports.RmuxBackend = require_rmuxBackend.RmuxBackend;
12
+ exports.createHeadlessBashTool = require_headless.createHeadlessBashTool;
13
+ exports.createHeadlessRunnersCommand = require_headless.createHeadlessRunnersCommand;
14
+ exports.createRunnerDependencies = require_runnerDependencies.createRunnerDependencies;
15
+ exports.getBackgroundThresholdMs = require_runnerConfig.getBackgroundThresholdMs;
16
+ exports.getLogMaxBytes = require_runnerConfig.getLogMaxBytes;
17
+ exports.getLogTtlMs = require_runnerConfig.getLogTtlMs;
18
+ exports.getResultMaxBytes = require_runnerConfig.getResultMaxBytes;
19
+ exports.rtkPackageForTarget = require_rtkProcessor.rtkPackageForTarget;
@@ -0,0 +1,7 @@
1
+ import { n as RmuxLaunchRequest, t as IRmuxBackend } from "./rmuxBackend-CaEWooWn.mjs";
2
+ import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./index-BwB_jTI9.mjs";
3
+ import { A as getLogTtlMs, C as getBackgroundThresholdMs, M as getResultMaxBytes, c as DEFAULT_LOG_TTL_MS, k as getLogMaxBytes, n as DEFAULT_BG_THRESHOLD_MS, s as DEFAULT_LOG_MAX_BYTES, u as DEFAULT_RESULT_MAX_BYTES } from "./runnerConfig-BjtulXBI.mjs";
4
+ import { t as RmuxBackend } from "./index-D9-IXax4.mjs";
5
+ import { r as rtkPackageForTarget } from "./index-BZL7keVW.mjs";
6
+ import { t as createRunnerDependencies } from "./index-Dhi8asLH.mjs";
7
+ export { DEFAULT_BG_THRESHOLD_MS, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, type IRmuxBackend, RmuxBackend, type RmuxLaunchRequest, createHeadlessBashTool, createHeadlessRunnersCommand, createRunnerDependencies, getBackgroundThresholdMs, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, rtkPackageForTarget };
package/dist/index.mjs ADDED
@@ -0,0 +1,6 @@
1
+ import { D as DEFAULT_RESULT_MAX_BYTES, T as DEFAULT_LOG_TTL_MS, c as getLogTtlMs, s as getLogMaxBytes, t as getBackgroundThresholdMs, u as getResultMaxBytes, w as DEFAULT_LOG_MAX_BYTES, y as DEFAULT_BG_THRESHOLD_MS } from "./runnerConfig-BQBlVAXn.mjs";
2
+ import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./headless-BGYfIlNk.mjs";
3
+ import { t as RmuxBackend } from "./rmuxBackend-DfyQwJrc.mjs";
4
+ import { r as rtkPackageForTarget } from "./rtkProcessor-B9KPdyzr.mjs";
5
+ import { t as createRunnerDependencies } from "./runnerDependencies-DruByBGS.mjs";
6
+ export { DEFAULT_BG_THRESHOLD_MS, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, RmuxBackend, createHeadlessBashTool, createHeadlessRunnersCommand, createRunnerDependencies, getBackgroundThresholdMs, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, rtkPackageForTarget };
@@ -0,0 +1,150 @@
1
+ import { g as noninteractiveEnvironment, u as getResultMaxBytes } from "./runnerConfig-BQBlVAXn.mjs";
2
+ import { t as PI_SESSION_ID_ENV } from "./session-DE2Acesp.mjs";
3
+ import { NO_TERMINAL_INPUT_ENV, cleanupSupervisorFiles, readExitMetadata, supervisorCommand, supervisorPaths, writeCommandSpec } from "./services/runnerSupervisor/index.mjs";
4
+ import { LIFELINE_ENV } from "./services/lifeline/client.mjs";
5
+ import fs from "node:fs";
6
+ //#region src/constants/launcher.ts
7
+ const NON_INTERACTIVE_ENV = {
8
+ FORCE_COLOR: "1",
9
+ CI: "1"
10
+ };
11
+ const TERM_GRACE_MS = 2e3;
12
+ //#endregion
13
+ //#region src/services/launcher/index.ts
14
+ /**
15
+ * Prompts belong on a screen, not in a log file, so `CI` stays set.
16
+ *
17
+ * Colour is kept: the log is replayed into the transcript, and the scrub keeps
18
+ * SGR while still removing the cursor moves that made raw output unreadable.
19
+ */
20
+ /** In-memory output is a multiple of the result ceiling; the log holds the rest. */
21
+ var Launcher = class {
22
+ spawner;
23
+ processControl;
24
+ logFile;
25
+ clock;
26
+ paths;
27
+ lifeline;
28
+ environment;
29
+ settings;
30
+ constructor(spawner, processControl, logFile, clock, paths, lifeline, environment = process.env, settings) {
31
+ this.spawner = spawner;
32
+ this.processControl = processControl;
33
+ this.logFile = logFile;
34
+ this.clock = clock;
35
+ this.paths = paths;
36
+ this.lifeline = lifeline;
37
+ this.environment = environment;
38
+ this.settings = settings;
39
+ }
40
+ launch(request) {
41
+ const writer = this.logFile.open(request.id);
42
+ const memoryLimit = getResultMaxBytes(this.environment, this.settings) * 2;
43
+ let buffer = "";
44
+ let buffering = true;
45
+ let settled = false;
46
+ let resolveCompletion = () => void 0;
47
+ let rejectCompletion = () => void 0;
48
+ const completion = new Promise((resolve, reject) => {
49
+ resolveCompletion = resolve;
50
+ rejectCompletion = reject;
51
+ });
52
+ this.paths.ensureDirectories(request.sessionId);
53
+ const supervisor = supervisorPaths(this.paths.stateDirectory(request.sessionId), request.id);
54
+ const { [LIFELINE_ENV]: _inheritedLifeline, ...environment } = this.environment;
55
+ const env = {
56
+ ...environment,
57
+ ...NON_INTERACTIVE_ENV,
58
+ ...noninteractiveEnvironment(environment),
59
+ ...NO_TERMINAL_INPUT_ENV,
60
+ [PI_SESSION_ID_ENV]: request.sessionId,
61
+ [LIFELINE_ENV]: this.lifeline?.path()
62
+ };
63
+ cleanupSupervisorFiles(supervisor);
64
+ writeCommandSpec(supervisor.spec, {
65
+ command: request.command,
66
+ cwd: request.cwd,
67
+ env: defined(env)
68
+ });
69
+ fs.writeFileSync(supervisor.gate, "", { mode: 384 });
70
+ const child = this.spawner.spawn({
71
+ command: supervisorCommand(supervisor),
72
+ cwd: request.cwd,
73
+ env,
74
+ detached: true
75
+ });
76
+ const failLaunch = (error) => {
77
+ if (settled) return;
78
+ settled = true;
79
+ writer.close();
80
+ cleanupSupervisorFiles(supervisor);
81
+ try {
82
+ child.kill("SIGTERM");
83
+ } catch (killError) {
84
+ process.emitWarning(`Could not stop runner after log failure: ${String(killError)}`);
85
+ }
86
+ rejectCompletion(error instanceof Error ? error : new Error(String(error)));
87
+ };
88
+ child.onOutput((chunk) => {
89
+ if (settled) return;
90
+ try {
91
+ writer.append(chunk);
92
+ } catch (error) {
93
+ failLaunch(error);
94
+ return;
95
+ }
96
+ if (!buffering) return;
97
+ buffer += chunk;
98
+ if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);
99
+ });
100
+ child.onError(failLaunch);
101
+ child.onExit((result) => {
102
+ if (settled) return;
103
+ settled = true;
104
+ writer.close();
105
+ const outcome = readExitMetadata(supervisor.exit) ?? result;
106
+ cleanupSupervisorFiles(supervisor);
107
+ resolveCompletion(outcome);
108
+ });
109
+ child.unref();
110
+ const stop = async () => child.pid === void 0 ? false : this.stop(child.pid);
111
+ return {
112
+ id: request.id,
113
+ name: request.name,
114
+ pid: child.pid,
115
+ logPath: writer.path,
116
+ backend: "native",
117
+ output: () => buffer,
118
+ completion: () => completion,
119
+ detach: () => {
120
+ buffering = false;
121
+ buffer = "";
122
+ },
123
+ stop
124
+ };
125
+ }
126
+ async stop(pid) {
127
+ if (!this.processControl.isAlive(pid)) return false;
128
+ this.processControl.signalGroup(pid, "SIGTERM");
129
+ const deadline = this.clock.now() + TERM_GRACE_MS;
130
+ while (this.clock.now() < deadline) {
131
+ if (!this.processControl.isAlive(pid)) return true;
132
+ await this.sleep(100);
133
+ }
134
+ this.processControl.signalGroup(pid, "SIGKILL");
135
+ return true;
136
+ }
137
+ sleep(ms) {
138
+ return new Promise((resolve) => {
139
+ this.clock.after(ms, resolve);
140
+ });
141
+ }
142
+ };
143
+ /** The spec is JSON, which has no way to carry an unset variable. */
144
+ function defined(env) {
145
+ return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
146
+ }
147
+ //#endregion
148
+ export { Launcher as t };
149
+
150
+ //# sourceMappingURL=launcher-BDm6-DiQ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher-BDm6-DiQ.mjs","names":[],"sources":["../src/constants/launcher.ts","../src/services/launcher/index.ts"],"sourcesContent":["export const NON_INTERACTIVE_ENV = { FORCE_COLOR: '1', CI: '1' };\nexport const TERM_GRACE_MS = 2_000;\nexport const LIVENESS_POLL_MS = 100;\nexport const MEMORY_BUFFER_FACTOR = 2;\nexport const GATE_MODE = 0o600;\n","import fs from 'node:fs';\n\nimport {\n GATE_MODE,\n LIVENESS_POLL_MS,\n MEMORY_BUFFER_FACTOR,\n NON_INTERACTIVE_ENV,\n TERM_GRACE_MS,\n} from '../../constants/launcher';\nimport { PI_SESSION_ID_ENV } from '../../constants/session';\nimport type { IClock } from '../../types/clock';\nimport type { ILauncher, LaunchRequest, RunHandle } from '../../types/launcher';\nimport type { ILifeline } from '../../types/lifeline';\nimport type { ILogFile } from '../../types/logFile';\nimport type { IProcessControl } from '../../types/processControl';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult, ISpawner } from '../../types/spawner';\nimport { LIFELINE_ENV } from '../lifeline/client';\nimport { getResultMaxBytes, noninteractiveEnvironment } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\nimport {\n cleanupSupervisorFiles,\n NO_TERMINAL_INPUT_ENV,\n readExitMetadata,\n supervisorCommand,\n supervisorPaths,\n writeCommandSpec,\n} from '../runnerSupervisor';\n\n/**\n * Prompts belong on a screen, not in a log file, so `CI` stays set.\n *\n * Colour is kept: the log is replayed into the transcript, and the scrub keeps\n * SGR while still removing the cursor moves that made raw output unreadable.\n */\n/** In-memory output is a multiple of the result ceiling; the log holds the rest. */\n\nexport class Launcher implements ILauncher {\n constructor(\n private readonly spawner: ISpawner,\n private readonly processControl: IProcessControl,\n private readonly logFile: ILogFile,\n private readonly clock: IClock,\n private readonly paths: IRunnerPaths,\n private readonly lifeline?: ILifeline,\n private readonly environment: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n launch(request: LaunchRequest): RunHandle {\n const writer = this.logFile.open(request.id);\n const memoryLimit = getResultMaxBytes(this.environment, this.settings) * MEMORY_BUFFER_FACTOR;\n\n let buffer = '';\n let buffering = true;\n let settled = false;\n let resolveCompletion: (result: ExitResult) => void = () => undefined;\n let rejectCompletion: (error: Error) => void = () => undefined;\n const completion = new Promise<ExitResult>((resolve, reject) => {\n resolveCompletion = resolve;\n rejectCompletion = reject;\n });\n\n this.paths.ensureDirectories(request.sessionId);\n const supervisor = supervisorPaths(this.paths.stateDirectory(request.sessionId), request.id);\n const { [LIFELINE_ENV]: _inheritedLifeline, ...environment } = this.environment;\n const env = {\n ...environment,\n ...NON_INTERACTIVE_ENV,\n ...noninteractiveEnvironment(environment),\n ...NO_TERMINAL_INPUT_ENV,\n [PI_SESSION_ID_ENV]: request.sessionId,\n [LIFELINE_ENV]: this.lifeline?.path(),\n };\n cleanupSupervisorFiles(supervisor);\n writeCommandSpec(supervisor.spec, { command: request.command, cwd: request.cwd, env: defined(env) });\n // Nothing has to be attached before this runner starts, so its gate opens at once.\n fs.writeFileSync(supervisor.gate, '', { mode: GATE_MODE });\n\n const child = this.spawner.spawn({\n // runnerHost supervises the command: it forwards signals and, if the owning\n // pi dies without running its shutdown handler, kills the group itself.\n command: supervisorCommand(supervisor),\n cwd: request.cwd,\n env,\n // Its own process group, so stopping a runner takes the whole tree with it.\n detached: true,\n });\n\n const failLaunch = (error: unknown): void => {\n if (settled) return;\n settled = true;\n writer.close();\n cleanupSupervisorFiles(supervisor);\n try {\n child.kill('SIGTERM');\n } catch (killError) {\n process.emitWarning(`Could not stop runner after log failure: ${String(killError)}`);\n }\n rejectCompletion(error instanceof Error ? error : new Error(String(error)));\n };\n child.onOutput((chunk) => {\n if (settled) return;\n try {\n writer.append(chunk);\n } catch (error) {\n failLaunch(error);\n return;\n }\n if (!buffering) return;\n buffer += chunk;\n if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);\n });\n\n child.onError(failLaunch);\n\n child.onExit((result) => {\n if (settled) return;\n settled = true;\n writer.close();\n // The supervisor collapses a signalled command into an exit code, so its\n // own sidecar is the only place the original signal survives.\n const outcome = readExitMetadata(supervisor.exit) ?? result;\n cleanupSupervisorFiles(supervisor);\n resolveCompletion(outcome);\n });\n\n // The launcher must never hold the pi process open on a runner's behalf.\n child.unref();\n\n const stop = async (): Promise<boolean> => (child.pid === undefined ? false : this.stop(child.pid));\n\n return {\n id: request.id,\n name: request.name,\n pid: child.pid,\n logPath: writer.path,\n backend: 'native',\n output: () => buffer,\n completion: () => completion,\n detach: () => {\n buffering = false;\n buffer = '';\n },\n stop,\n };\n }\n\n async stop(pid: number): Promise<boolean> {\n if (!this.processControl.isAlive(pid)) return false;\n\n this.processControl.signalGroup(pid, 'SIGTERM');\n const deadline = this.clock.now() + TERM_GRACE_MS;\n while (this.clock.now() < deadline) {\n if (!this.processControl.isAlive(pid)) return true;\n await this.sleep(LIVENESS_POLL_MS);\n }\n\n this.processControl.signalGroup(pid, 'SIGKILL');\n return true;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n this.clock.after(ms, resolve);\n });\n }\n}\n\n/** The spec is JSON, which has no way to carry an unset variable. */\nfunction defined(env: Readonly<Record<string, string | undefined>>): Record<string, string> {\n return Object.fromEntries(Object.entries(env).filter((entry): entry is [string, string] => entry[1] !== undefined));\n}\n"],"mappings":"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"}