@agimon-ai/doompi-runner 0.0.1-alpha.2 → 0.0.1-alpha.21

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 (293) hide show
  1. package/README.md +25 -16
  2. package/dist/adapters/RunnerPaths.cjs +2 -0
  3. package/dist/adapters/RunnerPaths.cjs.map +1 -0
  4. package/dist/adapters/RunnerPaths.d.cts +35 -0
  5. package/dist/adapters/RunnerPaths.d.cts.map +1 -0
  6. package/dist/adapters/RunnerPaths.d.mts +35 -0
  7. package/dist/adapters/RunnerPaths.d.mts.map +1 -0
  8. package/dist/adapters/RunnerPaths.mjs +2 -0
  9. package/dist/adapters/RunnerPaths.mjs.map +1 -0
  10. package/dist/adapters/pi/extension.cjs +3 -0
  11. package/dist/adapters/pi/extension.cjs.map +1 -0
  12. package/dist/adapters/pi/extension.d.cts +10 -0
  13. package/dist/adapters/pi/extension.d.cts.map +1 -0
  14. package/dist/adapters/pi/extension.d.mts +10 -0
  15. package/dist/adapters/pi/extension.d.mts.map +1 -0
  16. package/dist/adapters/pi/extension.mjs +3 -0
  17. package/dist/adapters/pi/extension.mjs.map +1 -0
  18. package/dist/adapters/pty/ptyProvider.cjs +2 -0
  19. package/dist/adapters/pty/ptyProvider.cjs.map +1 -0
  20. package/dist/adapters/pty/ptyProvider.d.cts +13 -0
  21. package/dist/adapters/pty/ptyProvider.d.cts.map +1 -0
  22. package/dist/adapters/pty/ptyProvider.d.mts +13 -0
  23. package/dist/adapters/pty/ptyProvider.d.mts.map +1 -0
  24. package/dist/adapters/pty/ptyProvider.mjs +2 -0
  25. package/dist/adapters/pty/ptyProvider.mjs.map +1 -0
  26. package/dist/bin/cli.cjs +1 -1
  27. package/dist/bin/cli.cjs.map +1 -1
  28. package/dist/bin/cli.mjs +1 -1
  29. package/dist/bin/cli.mjs.map +1 -1
  30. package/dist/bin/logSink.cjs.map +1 -1
  31. package/dist/bin/logSink.mjs.map +1 -1
  32. package/dist/bin/runnerHost.cjs.map +1 -1
  33. package/dist/bin/runnerHost.mjs.map +1 -1
  34. package/dist/cli/cliApp.cjs +1 -6
  35. package/dist/cli/cliApp.d.cts +2 -23
  36. package/dist/cli/cliApp.d.mts +2 -23
  37. package/dist/cli/cliApp.mjs +1 -6
  38. package/dist/commands/bash/bashTool.cjs +7 -0
  39. package/dist/commands/bash/bashTool.cjs.map +1 -0
  40. package/dist/commands/bash/bashTool.d.cts +25 -0
  41. package/dist/commands/bash/bashTool.d.cts.map +1 -0
  42. package/dist/commands/bash/bashTool.d.mts +25 -0
  43. package/dist/commands/bash/bashTool.d.mts.map +1 -0
  44. package/dist/commands/bash/bashTool.mjs +7 -0
  45. package/dist/commands/bash/bashTool.mjs.map +1 -0
  46. package/dist/commands/bash/responseEnvelope.cjs +10 -0
  47. package/dist/commands/bash/responseEnvelope.cjs.map +1 -0
  48. package/dist/commands/bash/responseEnvelope.d.cts +45 -0
  49. package/dist/commands/bash/responseEnvelope.d.cts.map +1 -0
  50. package/dist/commands/bash/responseEnvelope.d.mts +45 -0
  51. package/dist/commands/bash/responseEnvelope.d.mts.map +1 -0
  52. package/dist/commands/bash/responseEnvelope.mjs +10 -0
  53. package/dist/{tool/responseEnvelope.cjs.map → commands/bash/responseEnvelope.mjs.map} +1 -1
  54. package/dist/commands/cli/cliApp.cjs +6 -0
  55. package/dist/commands/cli/cliApp.cjs.map +1 -0
  56. package/dist/commands/cli/cliApp.d.cts +23 -0
  57. package/dist/commands/cli/cliApp.d.cts.map +1 -0
  58. package/dist/commands/cli/cliApp.d.mts +23 -0
  59. package/dist/commands/cli/cliApp.d.mts.map +1 -0
  60. package/dist/commands/cli/cliApp.mjs +6 -0
  61. package/dist/commands/cli/cliApp.mjs.map +1 -0
  62. package/dist/compaction.cjs +1 -4
  63. package/dist/compaction.d.cts +2 -14
  64. package/dist/compaction.d.mts +2 -14
  65. package/dist/compaction.mjs +1 -4
  66. package/dist/config.cjs +1 -2
  67. package/dist/config.d.cts +2 -32
  68. package/dist/config.d.mts +2 -32
  69. package/dist/config.mjs +1 -2
  70. package/dist/container/index.cjs +1 -1
  71. package/dist/container/index.cjs.map +1 -1
  72. package/dist/container/index.mjs +1 -1
  73. package/dist/container/index.mjs.map +1 -1
  74. package/dist/extension.cjs +1 -3
  75. package/dist/extension.d.cts +2 -10
  76. package/dist/extension.d.mts +2 -10
  77. package/dist/extension.mjs +1 -3
  78. package/dist/extensions/pi.cjs +1 -1
  79. package/dist/extensions/pi.cjs.map +1 -1
  80. package/dist/extensions/pi.d.cts +1 -1
  81. package/dist/extensions/pi.d.mts +1 -1
  82. package/dist/extensions/pi.mjs +1 -1
  83. package/dist/extensions/pi.mjs.map +1 -1
  84. package/dist/index.cjs +1 -1
  85. package/dist/index.d.cts +2 -2
  86. package/dist/index.d.mts +2 -2
  87. package/dist/index.mjs +1 -1
  88. package/dist/ptyProvider.cjs +1 -2
  89. package/dist/ptyProvider.d.cts +2 -13
  90. package/dist/ptyProvider.d.mts +2 -13
  91. package/dist/ptyProvider.mjs +1 -2
  92. package/dist/reconcile.cjs +1 -2
  93. package/dist/reconcile.d.cts +2 -37
  94. package/dist/reconcile.d.mts +2 -37
  95. package/dist/reconcile.mjs +1 -2
  96. package/dist/runnerSpec.cjs +1 -2
  97. package/dist/runnerSpec.d.cts +2 -50
  98. package/dist/runnerSpec.d.mts +2 -50
  99. package/dist/runnerSpec.mjs +1 -2
  100. package/dist/schemas/bashTool.cjs +2 -0
  101. package/dist/schemas/bashTool.cjs.map +1 -0
  102. package/dist/schemas/bashTool.d.cts +25 -0
  103. package/dist/schemas/bashTool.d.cts.map +1 -0
  104. package/dist/schemas/bashTool.d.mts +25 -0
  105. package/dist/schemas/bashTool.d.mts.map +1 -0
  106. package/dist/schemas/bashTool.mjs +2 -0
  107. package/dist/schemas/bashTool.mjs.map +1 -0
  108. package/dist/schemas/runnerSpec.cjs +2 -0
  109. package/dist/schemas/runnerSpec.cjs.map +1 -0
  110. package/dist/schemas/runnerSpec.d.cts +50 -0
  111. package/dist/schemas/runnerSpec.d.cts.map +1 -0
  112. package/dist/schemas/runnerSpec.d.mts +50 -0
  113. package/dist/schemas/runnerSpec.d.mts.map +1 -0
  114. package/dist/schemas/runnerSpec.mjs +2 -0
  115. package/dist/schemas/runnerSpec.mjs.map +1 -0
  116. package/dist/services/AnsiScrub/ansiScrub.cjs +1 -1
  117. package/dist/services/AnsiScrub/ansiScrub.cjs.map +1 -1
  118. package/dist/services/AnsiScrub/ansiScrub.mjs +1 -1
  119. package/dist/services/AnsiScrub/ansiScrub.mjs.map +1 -1
  120. package/dist/services/BashRunService/BashRunService.cjs +1 -1
  121. package/dist/services/BashRunService/BashRunService.cjs.map +1 -1
  122. package/dist/services/BashRunService/BashRunService.mjs +1 -1
  123. package/dist/services/BashRunService/BashRunService.mjs.map +1 -1
  124. package/dist/services/Launcher/Launcher.cjs +1 -1
  125. package/dist/services/Launcher/Launcher.cjs.map +1 -1
  126. package/dist/services/Launcher/Launcher.mjs +1 -1
  127. package/dist/services/Launcher/Launcher.mjs.map +1 -1
  128. package/dist/services/Lifeline/NodeLifeline.cjs +1 -1
  129. package/dist/services/Lifeline/NodeLifeline.cjs.map +1 -1
  130. package/dist/services/Lifeline/NodeLifeline.mjs +1 -1
  131. package/dist/services/Lifeline/NodeLifeline.mjs.map +1 -1
  132. package/dist/services/LogFile/LogFile.cjs +1 -1
  133. package/dist/services/LogFile/LogFile.cjs.map +1 -1
  134. package/dist/services/LogFile/LogFile.mjs +1 -1
  135. package/dist/services/LogFile/LogFile.mjs.map +1 -1
  136. package/dist/services/PtyHost/PtyHost.cjs +1 -1
  137. package/dist/services/PtyHost/PtyHost.cjs.map +1 -1
  138. package/dist/services/PtyHost/PtyHost.mjs +1 -1
  139. package/dist/services/PtyHost/PtyHost.mjs.map +1 -1
  140. package/dist/services/RmuxBackend/RmuxBackend.cjs +1 -1
  141. package/dist/services/RmuxBackend/RmuxBackend.cjs.map +1 -1
  142. package/dist/services/RmuxBackend/RmuxBackend.mjs +1 -1
  143. package/dist/services/RmuxBackend/RmuxBackend.mjs.map +1 -1
  144. package/dist/services/RunnerNamer/RunnerNamer.cjs +1 -1
  145. package/dist/services/RunnerNamer/RunnerNamer.cjs.map +1 -1
  146. package/dist/services/RunnerNamer/RunnerNamer.mjs +1 -1
  147. package/dist/services/RunnerNamer/RunnerNamer.mjs.map +1 -1
  148. package/dist/services/RunnerPaths/RunnerPaths.cjs +1 -2
  149. package/dist/services/RunnerPaths/RunnerPaths.d.cts +2 -31
  150. package/dist/services/RunnerPaths/RunnerPaths.d.mts +2 -31
  151. package/dist/services/RunnerPaths/RunnerPaths.mjs +1 -2
  152. package/dist/services/RunnerPaths/index.cjs +1 -1
  153. package/dist/services/RunnerPaths/index.d.cts +2 -1
  154. package/dist/services/RunnerPaths/index.d.mts +2 -1
  155. package/dist/services/RunnerPaths/index.mjs +1 -1
  156. package/dist/services/RunnerPaths/types.d.cts +2 -0
  157. package/dist/services/RunnerPaths/types.d.cts.map +1 -1
  158. package/dist/services/RunnerPaths/types.d.mts +2 -0
  159. package/dist/services/RunnerPaths/types.d.mts.map +1 -1
  160. package/dist/services/RunnerRegistry/RunnerRegistry.cjs +1 -1
  161. package/dist/services/RunnerRegistry/RunnerRegistry.cjs.map +1 -1
  162. package/dist/services/RunnerRegistry/RunnerRegistry.mjs +1 -1
  163. package/dist/services/RunnerRegistry/RunnerRegistry.mjs.map +1 -1
  164. package/dist/services/runs/compaction.cjs +4 -0
  165. package/dist/services/runs/compaction.cjs.map +1 -0
  166. package/dist/services/runs/compaction.d.cts +14 -0
  167. package/dist/services/runs/compaction.d.cts.map +1 -0
  168. package/dist/services/runs/compaction.d.mts +14 -0
  169. package/dist/services/runs/compaction.d.mts.map +1 -0
  170. package/dist/services/runs/compaction.mjs +4 -0
  171. package/dist/services/runs/compaction.mjs.map +1 -0
  172. package/dist/services/runs/reconcile.cjs +2 -0
  173. package/dist/services/runs/reconcile.cjs.map +1 -0
  174. package/dist/services/runs/reconcile.d.cts +37 -0
  175. package/dist/services/runs/reconcile.d.cts.map +1 -0
  176. package/dist/services/runs/reconcile.d.mts +37 -0
  177. package/dist/services/runs/reconcile.d.mts.map +1 -0
  178. package/dist/services/runs/reconcile.mjs +2 -0
  179. package/dist/services/runs/reconcile.mjs.map +1 -0
  180. package/dist/services/runs/session.cjs +2 -0
  181. package/dist/services/runs/session.cjs.map +1 -0
  182. package/dist/services/runs/session.d.cts +10 -0
  183. package/dist/services/runs/session.d.cts.map +1 -0
  184. package/dist/services/runs/session.d.mts +10 -0
  185. package/dist/services/runs/session.d.mts.map +1 -0
  186. package/dist/services/runs/session.mjs +2 -0
  187. package/dist/services/runs/session.mjs.map +1 -0
  188. package/dist/session.cjs +1 -2
  189. package/dist/session.d.cts +2 -10
  190. package/dist/session.d.mts +2 -10
  191. package/dist/session.mjs +1 -2
  192. package/dist/tool/bashTool.cjs +1 -7
  193. package/dist/tool/bashTool.d.cts +2 -25
  194. package/dist/tool/bashTool.d.mts +2 -25
  195. package/dist/tool/bashTool.mjs +1 -7
  196. package/dist/tool/responseEnvelope.cjs +1 -10
  197. package/dist/tool/responseEnvelope.d.cts +2 -45
  198. package/dist/tool/responseEnvelope.d.mts +2 -45
  199. package/dist/tool/responseEnvelope.mjs +1 -10
  200. package/dist/tool/schema.cjs +1 -2
  201. package/dist/tool/schema.d.cts +2 -25
  202. package/dist/tool/schema.d.mts +2 -25
  203. package/dist/tool/schema.mjs +1 -2
  204. package/dist/tui/bashRender.cjs +4 -7
  205. package/dist/tui/bashRender.cjs.map +1 -1
  206. package/dist/tui/bashRender.d.cts +5 -5
  207. package/dist/tui/bashRender.d.cts.map +1 -1
  208. package/dist/tui/bashRender.d.mts +5 -5
  209. package/dist/tui/bashRender.d.mts.map +1 -1
  210. package/dist/tui/bashRender.mjs +4 -7
  211. package/dist/tui/bashRender.mjs.map +1 -1
  212. package/dist/tui/format.cjs +1 -1
  213. package/dist/tui/format.cjs.map +1 -1
  214. package/dist/tui/format.mjs +1 -1
  215. package/dist/tui/format.mjs.map +1 -1
  216. package/dist/tui/runnerSpace.cjs +4 -4
  217. package/dist/tui/runnerSpace.cjs.map +1 -1
  218. package/dist/tui/runnerSpace.d.cts.map +1 -1
  219. package/dist/tui/runnerSpace.d.mts.map +1 -1
  220. package/dist/tui/runnerSpace.mjs +4 -4
  221. package/dist/tui/runnerSpace.mjs.map +1 -1
  222. package/dist/types/config.cjs +2 -0
  223. package/dist/types/config.cjs.map +1 -0
  224. package/dist/types/config.d.cts +32 -0
  225. package/dist/types/config.d.cts.map +1 -0
  226. package/dist/types/config.d.mts +32 -0
  227. package/dist/types/config.d.mts.map +1 -0
  228. package/dist/types/config.mjs +2 -0
  229. package/dist/types/config.mjs.map +1 -0
  230. package/dist/types/index.cjs +2 -0
  231. package/dist/types/index.cjs.map +1 -0
  232. package/dist/types/index.d.cts +28 -0
  233. package/dist/types/index.d.cts.map +1 -0
  234. package/dist/types/index.d.mts +28 -0
  235. package/dist/types/index.d.mts.map +1 -0
  236. package/dist/types/index.mjs +2 -0
  237. package/dist/types/index.mjs.map +1 -0
  238. package/dist/types.cjs +1 -2
  239. package/dist/types.d.cts +2 -28
  240. package/dist/types.d.mts +2 -28
  241. package/dist/types.mjs +1 -2
  242. package/package.json +20 -13
  243. package/dist/cli/cliApp.cjs.map +0 -1
  244. package/dist/cli/cliApp.d.cts.map +0 -1
  245. package/dist/cli/cliApp.d.mts.map +0 -1
  246. package/dist/cli/cliApp.mjs.map +0 -1
  247. package/dist/compaction.cjs.map +0 -1
  248. package/dist/compaction.d.cts.map +0 -1
  249. package/dist/compaction.d.mts.map +0 -1
  250. package/dist/compaction.mjs.map +0 -1
  251. package/dist/config.cjs.map +0 -1
  252. package/dist/config.d.cts.map +0 -1
  253. package/dist/config.d.mts.map +0 -1
  254. package/dist/config.mjs.map +0 -1
  255. package/dist/extension.cjs.map +0 -1
  256. package/dist/extension.d.cts.map +0 -1
  257. package/dist/extension.d.mts.map +0 -1
  258. package/dist/extension.mjs.map +0 -1
  259. package/dist/ptyProvider.cjs.map +0 -1
  260. package/dist/ptyProvider.d.cts.map +0 -1
  261. package/dist/ptyProvider.d.mts.map +0 -1
  262. package/dist/ptyProvider.mjs.map +0 -1
  263. package/dist/reconcile.cjs.map +0 -1
  264. package/dist/reconcile.d.cts.map +0 -1
  265. package/dist/reconcile.d.mts.map +0 -1
  266. package/dist/reconcile.mjs.map +0 -1
  267. package/dist/runnerSpec.cjs.map +0 -1
  268. package/dist/runnerSpec.d.cts.map +0 -1
  269. package/dist/runnerSpec.d.mts.map +0 -1
  270. package/dist/runnerSpec.mjs.map +0 -1
  271. package/dist/services/RunnerPaths/RunnerPaths.cjs.map +0 -1
  272. package/dist/services/RunnerPaths/RunnerPaths.d.cts.map +0 -1
  273. package/dist/services/RunnerPaths/RunnerPaths.d.mts.map +0 -1
  274. package/dist/services/RunnerPaths/RunnerPaths.mjs.map +0 -1
  275. package/dist/session.cjs.map +0 -1
  276. package/dist/session.d.cts.map +0 -1
  277. package/dist/session.d.mts.map +0 -1
  278. package/dist/session.mjs.map +0 -1
  279. package/dist/tool/bashTool.cjs.map +0 -1
  280. package/dist/tool/bashTool.d.cts.map +0 -1
  281. package/dist/tool/bashTool.d.mts.map +0 -1
  282. package/dist/tool/bashTool.mjs.map +0 -1
  283. package/dist/tool/responseEnvelope.d.cts.map +0 -1
  284. package/dist/tool/responseEnvelope.d.mts.map +0 -1
  285. package/dist/tool/responseEnvelope.mjs.map +0 -1
  286. package/dist/tool/schema.cjs.map +0 -1
  287. package/dist/tool/schema.d.cts.map +0 -1
  288. package/dist/tool/schema.d.mts.map +0 -1
  289. package/dist/tool/schema.mjs.map +0 -1
  290. package/dist/types.cjs.map +0 -1
  291. package/dist/types.d.cts.map +0 -1
  292. package/dist/types.d.mts.map +0 -1
  293. package/dist/types.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"cli.cjs","names":["createDoomTelemetry","createRunnerContainer","TYPES","runCli","pathToFileURL"],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { createRunnerContainer } from '../container/index.ts';\nimport { pathToFileURL } from 'node:url';\nimport type { ILauncher } from '../services/Launcher/index.ts';\nimport type { ILogReader } from '../services/LogReader/index.ts';\nimport type { IRunnerRegistry } from '../services/RunnerRegistry/index.ts';\nimport type { IRmuxBackend } from '../services/RmuxBackend/index.ts';\nimport { TYPES } from '../types.ts';\nimport { runCli } from '../cli/cliApp.ts';\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf8');\n}\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-cli',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const container = createRunnerContainer();\n const registry = container.get<IRunnerRegistry>(TYPES.RunnerRegistry);\n let stdoutBytes = 0;\n let stderrBytes = 0;\n try {\n const exitCode = await runCli(argv, {\n registry,\n launcher: container.get<ILauncher>(TYPES.Launcher),\n rmuxBackend: container.get<IRmuxBackend>(TYPES.RmuxBackend),\n logReader: container.get<ILogReader>(TYPES.LogReader),\n env: process.env,\n stdout: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stdoutBytes += Buffer.byteLength(output, 'utf8');\n process.stdout.write(output);\n },\n stderr: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stderrBytes += Buffer.byteLength(output, 'utf8');\n process.stderr.write(output);\n },\n readStdin,\n });\n await telemetry.recordEvent('doom_runner.cli_finished', {\n outcome: exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError('doom_runner.cli_failed', error, {\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n throw error;\n } finally {\n registry.close();\n await telemetry.shutdown();\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":";yOAYA,eAAe,GAA6B,CAC1C,IAAM,EAAmB,CAAC,EAC1B,UAAW,IAAM,KAAS,QAAQ,MAAO,EAAO,KAAK,OAAO,SAAS,CAAK,EAAI,EAAQ,OAAO,KAAK,CAAK,CAAC,EACxG,OAAO,OAAO,OAAO,CAAM,CAAC,CAAC,SAAS,MAAM,CAC9C,CAEA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,GAAA,EAAYA,EAAAA,oBAAAA,CAAoB,CACpC,YAAa,kBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAYC,EAAAA,sBAAsB,EAClC,EAAW,EAAU,IAAqBC,EAAAA,MAAM,cAAc,EAChE,EAAc,EACd,EAAc,EAClB,GAAI,CACF,IAAM,EAAW,MAAMC,EAAAA,OAAO,EAAM,CAClC,WACA,SAAU,EAAU,IAAeD,EAAAA,MAAM,QAAQ,EACjD,YAAa,EAAU,IAAkBA,EAAAA,MAAM,WAAW,EAC1D,UAAW,EAAU,IAAgBA,EAAAA,MAAM,SAAS,EACpD,IAAK,QAAQ,IACb,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,WACF,CAAC,EASD,OARA,MAAM,EAAU,YAAY,2BAA4B,CACtD,QAAS,IAAa,EAAI,YAAc,SACxC,mBAAoB,EACpB,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACM,CACT,OAAS,EAAO,CAOd,MANA,MAAM,EAAU,YAAY,yBAA0B,EAAO,CAC3D,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACK,CACR,QAAU,CACR,EAAS,MAAM,EACf,MAAM,EAAU,SAAS,CAC3B,CACF,CAEI,QAAQ,KAAK,IAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,QAAA,EAA0BE,EAAAA,cAAAA,CAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
1
+ {"version":3,"file":"cli.cjs","names":["createDoomTelemetry","createRunnerContainer","TYPES","runCli","pathToFileURL"],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { runCli } from '../commands/cli/cliApp.ts';\nimport { createRunnerContainer } from '../container/index.ts';\nimport type { ILauncher } from '../services/Launcher/index.ts';\nimport type { ILogReader } from '../services/LogReader/index.ts';\nimport type { IRmuxBackend } from '../services/RmuxBackend/index.ts';\nimport type { IRunnerRegistry } from '../services/RunnerRegistry/index.ts';\nimport { TYPES } from '../types/index.ts';\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf8');\n}\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-cli',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const container = createRunnerContainer();\n const registry = container.get<IRunnerRegistry>(TYPES.RunnerRegistry);\n let stdoutBytes = 0;\n let stderrBytes = 0;\n try {\n const exitCode = await runCli(argv, {\n registry,\n launcher: container.get<ILauncher>(TYPES.Launcher),\n rmuxBackend: container.get<IRmuxBackend>(TYPES.RmuxBackend),\n logReader: container.get<ILogReader>(TYPES.LogReader),\n env: process.env,\n stdout: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stdoutBytes += Buffer.byteLength(output, 'utf8');\n process.stdout.write(output);\n },\n stderr: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stderrBytes += Buffer.byteLength(output, 'utf8');\n process.stderr.write(output);\n },\n readStdin,\n });\n await telemetry.recordEvent('doom_runner.cli_finished', {\n outcome: exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError('doom_runner.cli_failed', error, {\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n throw error;\n } finally {\n registry.close();\n await telemetry.shutdown();\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":";wPAYA,eAAe,GAA6B,CAC1C,IAAM,EAAmB,CAAC,EAC1B,UAAW,IAAM,KAAS,QAAQ,MAAO,EAAO,KAAK,OAAO,SAAS,CAAK,EAAI,EAAQ,OAAO,KAAK,CAAK,CAAC,EACxG,OAAO,OAAO,OAAO,CAAM,CAAC,CAAC,SAAS,MAAM,CAC9C,CAEA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,GAAA,EAAYA,EAAAA,oBAAAA,CAAoB,CACpC,YAAa,kBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAYC,EAAAA,sBAAsB,EAClC,EAAW,EAAU,IAAqBC,EAAAA,MAAM,cAAc,EAChE,EAAc,EACd,EAAc,EAClB,GAAI,CACF,IAAM,EAAW,MAAMC,EAAAA,OAAO,EAAM,CAClC,WACA,SAAU,EAAU,IAAeD,EAAAA,MAAM,QAAQ,EACjD,YAAa,EAAU,IAAkBA,EAAAA,MAAM,WAAW,EAC1D,UAAW,EAAU,IAAgBA,EAAAA,MAAM,SAAS,EACpD,IAAK,QAAQ,IACb,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,WACF,CAAC,EASD,OARA,MAAM,EAAU,YAAY,2BAA4B,CACtD,QAAS,IAAa,EAAI,YAAc,SACxC,mBAAoB,EACpB,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACM,CACT,OAAS,EAAO,CAOd,MANA,MAAM,EAAU,YAAY,yBAA0B,EAAO,CAC3D,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACK,CACR,QAAU,CACR,EAAS,MAAM,EACf,MAAM,EAAU,SAAS,CAC3B,CACF,CAEI,QAAQ,KAAK,IAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,QAAA,EAA0BE,EAAAA,cAAAA,CAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
package/dist/bin/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{TYPES as e}from"../types.mjs";import{createRunnerContainer as t}from"../container/index.mjs";import{runCli as n}from"../cli/cliApp.mjs";import{pathToFileURL as r}from"node:url";import{createDoomTelemetry as i}from"@agimon-ai/doompi-telemetry";async function a(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString(`utf8`)}async function o(r=process.argv.slice(2)){let o=Date.now(),s=i({serviceName:`doom-runner-cli`,packageName:`@agimon-ai/doompi-runner`,env:process.env,enableLogs:!0,enableTraces:!0}),c=t(),l=c.get(e.RunnerRegistry),u=0,d=0;try{let t=await n(r,{registry:l,launcher:c.get(e.Launcher),rmuxBackend:c.get(e.RmuxBackend),logReader:c.get(e.LogReader),env:process.env,stdout:e=>{let t=e.endsWith(`
2
+ import{TYPES as e}from"../types/index.mjs";import{createRunnerContainer as t}from"../container/index.mjs";import{runCli as n}from"../commands/cli/cliApp.mjs";import{pathToFileURL as r}from"node:url";import{createDoomTelemetry as i}from"@agimon-ai/doompi-telemetry";async function a(){let e=[];for await(let t of process.stdin)e.push(Buffer.isBuffer(t)?t:Buffer.from(t));return Buffer.concat(e).toString(`utf8`)}async function o(r=process.argv.slice(2)){let o=Date.now(),s=i({serviceName:`doom-runner-cli`,packageName:`@agimon-ai/doompi-runner`,env:process.env,enableLogs:!0,enableTraces:!0}),c=t(),l=c.get(e.RunnerRegistry),u=0,d=0;try{let t=await n(r,{registry:l,launcher:c.get(e.Launcher),rmuxBackend:c.get(e.RmuxBackend),logReader:c.get(e.LogReader),env:process.env,stdout:e=>{let t=e.endsWith(`
3
3
  `)?e:`${e}\n`;u+=Buffer.byteLength(t,`utf8`),process.stdout.write(t)},stderr:e=>{let t=e.endsWith(`
4
4
  `)?e:`${e}\n`;d+=Buffer.byteLength(t,`utf8`),process.stderr.write(t)},readStdin:a});return await s.recordEvent(`doom_runner.cli_finished`,{outcome:t===0?`completed`:`failed`,"runner.exit_code":t,duration_ms:Date.now()-o,"runner.argument_count":r.length,"runner.stdout_bytes":u,"runner.stderr_bytes":d}),t}catch(e){throw await s.recordError(`doom_runner.cli_failed`,e,{duration_ms:Date.now()-o,"runner.argument_count":r.length,"runner.stdout_bytes":u,"runner.stderr_bytes":d}),e}finally{l.close(),await s.shutdown()}}process.argv[1]&&import.meta.url===r(process.argv[1]).href&&o().then(e=>{process.exitCode=e},e=>{process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1});export{o as main};
5
5
  //# sourceMappingURL=cli.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { createRunnerContainer } from '../container/index.ts';\nimport { pathToFileURL } from 'node:url';\nimport type { ILauncher } from '../services/Launcher/index.ts';\nimport type { ILogReader } from '../services/LogReader/index.ts';\nimport type { IRunnerRegistry } from '../services/RunnerRegistry/index.ts';\nimport type { IRmuxBackend } from '../services/RmuxBackend/index.ts';\nimport { TYPES } from '../types.ts';\nimport { runCli } from '../cli/cliApp.ts';\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf8');\n}\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-cli',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const container = createRunnerContainer();\n const registry = container.get<IRunnerRegistry>(TYPES.RunnerRegistry);\n let stdoutBytes = 0;\n let stderrBytes = 0;\n try {\n const exitCode = await runCli(argv, {\n registry,\n launcher: container.get<ILauncher>(TYPES.Launcher),\n rmuxBackend: container.get<IRmuxBackend>(TYPES.RmuxBackend),\n logReader: container.get<ILogReader>(TYPES.LogReader),\n env: process.env,\n stdout: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stdoutBytes += Buffer.byteLength(output, 'utf8');\n process.stdout.write(output);\n },\n stderr: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stderrBytes += Buffer.byteLength(output, 'utf8');\n process.stderr.write(output);\n },\n readStdin,\n });\n await telemetry.recordEvent('doom_runner.cli_finished', {\n outcome: exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError('doom_runner.cli_failed', error, {\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n throw error;\n } finally {\n registry.close();\n await telemetry.shutdown();\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":";0PAYA,eAAe,GAA6B,CAC1C,IAAM,EAAmB,CAAC,EAC1B,UAAW,IAAM,KAAS,QAAQ,MAAO,EAAO,KAAK,OAAO,SAAS,CAAK,EAAI,EAAQ,OAAO,KAAK,CAAK,CAAC,EACxG,OAAO,OAAO,OAAO,CAAM,CAAC,CAAC,SAAS,MAAM,CAC9C,CAEA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,EAAY,EAAoB,CACpC,YAAa,kBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAY,EAAsB,EAClC,EAAW,EAAU,IAAqB,EAAM,cAAc,EAChE,EAAc,EACd,EAAc,EAClB,GAAI,CACF,IAAM,EAAW,MAAM,EAAO,EAAM,CAClC,WACA,SAAU,EAAU,IAAe,EAAM,QAAQ,EACjD,YAAa,EAAU,IAAkB,EAAM,WAAW,EAC1D,UAAW,EAAU,IAAgB,EAAM,SAAS,EACpD,IAAK,QAAQ,IACb,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,WACF,CAAC,EASD,OARA,MAAM,EAAU,YAAY,2BAA4B,CACtD,QAAS,IAAa,EAAI,YAAc,SACxC,mBAAoB,EACpB,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACM,CACT,OAAS,EAAO,CAOd,MANA,MAAM,EAAU,YAAY,yBAA0B,EAAO,CAC3D,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACK,CACR,QAAU,CACR,EAAS,MAAM,EACf,MAAM,EAAU,SAAS,CAC3B,CACF,CAEI,QAAQ,KAAK,IAAM,YAAY,MAAQ,EAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../../src/bin/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { runCli } from '../commands/cli/cliApp.ts';\nimport { createRunnerContainer } from '../container/index.ts';\nimport type { ILauncher } from '../services/Launcher/index.ts';\nimport type { ILogReader } from '../services/LogReader/index.ts';\nimport type { IRmuxBackend } from '../services/RmuxBackend/index.ts';\nimport type { IRunnerRegistry } from '../services/RunnerRegistry/index.ts';\nimport { TYPES } from '../types/index.ts';\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n return Buffer.concat(chunks).toString('utf8');\n}\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-cli',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const container = createRunnerContainer();\n const registry = container.get<IRunnerRegistry>(TYPES.RunnerRegistry);\n let stdoutBytes = 0;\n let stderrBytes = 0;\n try {\n const exitCode = await runCli(argv, {\n registry,\n launcher: container.get<ILauncher>(TYPES.Launcher),\n rmuxBackend: container.get<IRmuxBackend>(TYPES.RmuxBackend),\n logReader: container.get<ILogReader>(TYPES.LogReader),\n env: process.env,\n stdout: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stdoutBytes += Buffer.byteLength(output, 'utf8');\n process.stdout.write(output);\n },\n stderr: (text) => {\n const output = text.endsWith('\\n') ? text : `${text}\\n`;\n stderrBytes += Buffer.byteLength(output, 'utf8');\n process.stderr.write(output);\n },\n readStdin,\n });\n await telemetry.recordEvent('doom_runner.cli_finished', {\n outcome: exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError('doom_runner.cli_failed', error, {\n duration_ms: Date.now() - startedAt,\n 'runner.argument_count': argv.length,\n 'runner.stdout_bytes': stdoutBytes,\n 'runner.stderr_bytes': stderrBytes,\n });\n throw error;\n } finally {\n registry.close();\n await telemetry.shutdown();\n }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":";yQAYA,eAAe,GAA6B,CAC1C,IAAM,EAAmB,CAAC,EAC1B,UAAW,IAAM,KAAS,QAAQ,MAAO,EAAO,KAAK,OAAO,SAAS,CAAK,EAAI,EAAQ,OAAO,KAAK,CAAK,CAAC,EACxG,OAAO,OAAO,OAAO,CAAM,CAAC,CAAC,SAAS,MAAM,CAC9C,CAEA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,EAAY,EAAoB,CACpC,YAAa,kBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,EAAY,EAAsB,EAClC,EAAW,EAAU,IAAqB,EAAM,cAAc,EAChE,EAAc,EACd,EAAc,EAClB,GAAI,CACF,IAAM,EAAW,MAAM,EAAO,EAAM,CAClC,WACA,SAAU,EAAU,IAAe,EAAM,QAAQ,EACjD,YAAa,EAAU,IAAkB,EAAM,WAAW,EAC1D,UAAW,EAAU,IAAgB,EAAM,SAAS,EACpD,IAAK,QAAQ,IACb,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,OAAS,GAAS,CAChB,IAAM,EAAS,EAAK,SAAS;CAAI,EAAI,EAAO,GAAG,EAAK,IACpD,GAAe,OAAO,WAAW,EAAQ,MAAM,EAC/C,QAAQ,OAAO,MAAM,CAAM,CAC7B,EACA,WACF,CAAC,EASD,OARA,MAAM,EAAU,YAAY,2BAA4B,CACtD,QAAS,IAAa,EAAI,YAAc,SACxC,mBAAoB,EACpB,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACM,CACT,OAAS,EAAO,CAOd,MANA,MAAM,EAAU,YAAY,yBAA0B,EAAO,CAC3D,YAAa,KAAK,IAAI,EAAI,EAC1B,wBAAyB,EAAK,OAC9B,sBAAuB,EACvB,sBAAuB,CACzB,CAAC,EACK,CACR,QAAU,CACR,EAAS,MAAM,EACf,MAAM,EAAU,SAAS,CAC3B,CACF,CAEI,QAAQ,KAAK,IAAM,YAAY,MAAQ,EAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"logSink.cjs","names":["createDoomTelemetry","fs","scrubTerminalOutput","pathToFileURL"],"sources":["../../src/bin/logSink.ts"],"sourcesContent":["import { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport { scrubTerminalOutput } from '../services/AnsiScrub/index.ts';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-log-sink',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [logPath, rotatedPath, maxBytesRaw, donePath] = argv;\n let maxBytes: number;\n try {\n if (!logPath || !rotatedPath || !maxBytesRaw || !donePath) {\n throw new Error('logSink requires log, rotated log, max bytes, and completion paths');\n }\n maxBytes = Number(maxBytesRaw);\n if (!Number.isFinite(maxBytes) || maxBytes <= 0) throw new Error('logSink max bytes must be positive');\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n\n let handle: number;\n let written: number;\n try {\n handle = fs.openSync(logPath, 'a');\n written = fs.statSync(logPath).size;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let chunks = 0;\n let rotations = 0;\n try {\n process.stdin.setEncoding('utf8');\n for await (const chunk of process.stdin) {\n const text = scrubTerminalOutput(String(chunk));\n if (!text) continue;\n const bytes = Buffer.from(text, 'utf8');\n if (written + bytes.byteLength > maxBytes) {\n fs.closeSync(handle);\n fs.renameSync(logPath, rotatedPath);\n handle = fs.openSync(logPath, 'w');\n written = 0;\n rotations += 1;\n }\n fs.writeSync(handle, bytes);\n written += bytes.byteLength;\n chunks += 1;\n }\n fs.closeSync(handle);\n writeDone(donePath);\n await telemetry.recordEvent('doom_runner.file_sink_finished', {\n outcome: 'completed',\n 'runner.chunk_count': chunks,\n 'runner.bytes_written': written,\n 'runner.rotation_count': rotations,\n duration_ms: Date.now() - startedAt,\n });\n return 0;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n await telemetry.shutdown();\n }\n}\n\nfunction writeDone(target: string): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, '', { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"iUAKA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,GAAA,EAAYA,EAAAA,oBAAAA,CAAoB,CACpC,YAAa,uBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,CAAC,EAAS,EAAa,EAAa,GAAY,EAClD,EACJ,GAAI,CACF,GAAI,CAAC,GAAW,CAAC,GAAe,CAAC,GAAe,CAAC,EAC/C,MAAU,MAAM,oEAAoE,EAGtF,GADA,EAAW,OAAO,CAAW,EACzB,CAAC,OAAO,SAAS,CAAQ,GAAK,GAAY,EAAG,MAAU,MAAM,oCAAoC,CACvG,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CAEA,IAAI,EACA,EACJ,GAAI,CACF,EAASC,EAAAA,QAAG,SAAS,EAAS,GAAG,EACjC,EAAUA,EAAAA,QAAG,SAAS,CAAO,CAAC,CAAC,IACjC,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CACA,IAAI,EAAS,EACT,EAAY,EAChB,GAAI,CACF,QAAQ,MAAM,YAAY,MAAM,EAChC,UAAW,IAAM,KAAS,QAAQ,MAAO,CACvC,IAAM,EAAOC,EAAAA,oBAAoB,OAAO,CAAK,CAAC,EAC9C,GAAI,CAAC,EAAM,SACX,IAAM,EAAQ,OAAO,KAAK,EAAM,MAAM,EAClC,EAAU,EAAM,WAAa,IAC/B,EAAA,QAAG,UAAU,CAAM,EACnB,EAAA,QAAG,WAAW,EAAS,CAAW,EAClC,EAASD,EAAAA,QAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EACV,GAAa,GAEf,EAAA,QAAG,UAAU,EAAQ,CAAK,EAC1B,GAAW,EAAM,WACjB,GAAU,CACZ,CAUA,OATA,EAAA,QAAG,UAAU,CAAM,EACnB,EAAU,CAAQ,EAClB,MAAM,EAAU,YAAY,iCAAkC,CAC5D,QAAS,YACT,qBAAsB,EACtB,uBAAwB,EACxB,wBAAyB,EACzB,YAAa,KAAK,IAAI,EAAI,CAC5B,CAAC,EACM,CACT,OAAS,EAAO,CAEd,MADA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EACpG,CACR,QAAU,CACR,MAAM,EAAU,SAAS,CAC3B,CACF,CAEA,SAAS,EAAU,EAAsB,CACvC,IAAM,EAAY,GAAG,EAAO,GAAG,QAAQ,IAAI,MAC3C,EAAA,QAAG,cAAc,EAAW,GAAI,CAAE,KAAM,GAAM,CAAC,EAC/C,EAAA,QAAG,WAAW,EAAW,CAAM,CACjC,CAEI,QAAQ,KAAK,IAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,QAAA,EAA0BE,EAAAA,cAAAA,CAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
1
+ {"version":3,"file":"logSink.cjs","names":["createDoomTelemetry","fs","scrubTerminalOutput","pathToFileURL"],"sources":["../../src/bin/logSink.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { scrubTerminalOutput } from '../services/AnsiScrub/index.ts';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-log-sink',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [logPath, rotatedPath, maxBytesRaw, donePath] = argv;\n let maxBytes: number;\n try {\n if (!logPath || !rotatedPath || !maxBytesRaw || !donePath) {\n throw new Error('logSink requires log, rotated log, max bytes, and completion paths');\n }\n maxBytes = Number(maxBytesRaw);\n if (!Number.isFinite(maxBytes) || maxBytes <= 0) throw new Error('logSink max bytes must be positive');\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n\n let handle: number;\n let written: number;\n try {\n handle = fs.openSync(logPath, 'a');\n written = fs.statSync(logPath).size;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let chunks = 0;\n let rotations = 0;\n try {\n process.stdin.setEncoding('utf8');\n for await (const chunk of process.stdin) {\n const text = scrubTerminalOutput(String(chunk));\n if (!text) continue;\n const bytes = Buffer.from(text, 'utf8');\n if (written + bytes.byteLength > maxBytes) {\n fs.closeSync(handle);\n fs.renameSync(logPath, rotatedPath);\n handle = fs.openSync(logPath, 'w');\n written = 0;\n rotations += 1;\n }\n fs.writeSync(handle, bytes);\n written += bytes.byteLength;\n chunks += 1;\n }\n fs.closeSync(handle);\n writeDone(donePath);\n await telemetry.recordEvent('doom_runner.file_sink_finished', {\n outcome: 'completed',\n 'runner.chunk_count': chunks,\n 'runner.bytes_written': written,\n 'runner.rotation_count': rotations,\n duration_ms: Date.now() - startedAt,\n });\n return 0;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n await telemetry.shutdown();\n }\n}\n\nfunction writeDone(target: string): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, '', { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"iUAKA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,GAAA,EAAYA,EAAAA,oBAAAA,CAAoB,CACpC,YAAa,uBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,CAAC,EAAS,EAAa,EAAa,GAAY,EAClD,EACJ,GAAI,CACF,GAAI,CAAC,GAAW,CAAC,GAAe,CAAC,GAAe,CAAC,EAC/C,MAAU,MAAM,oEAAoE,EAGtF,GADA,EAAW,OAAO,CAAW,EACzB,CAAC,OAAO,SAAS,CAAQ,GAAK,GAAY,EAAG,MAAU,MAAM,oCAAoC,CACvG,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CAEA,IAAI,EACA,EACJ,GAAI,CACF,EAASC,EAAAA,QAAG,SAAS,EAAS,GAAG,EACjC,EAAUA,EAAAA,QAAG,SAAS,CAAO,CAAC,CAAC,IACjC,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CACA,IAAI,EAAS,EACT,EAAY,EAChB,GAAI,CACF,QAAQ,MAAM,YAAY,MAAM,EAChC,UAAW,IAAM,KAAS,QAAQ,MAAO,CACvC,IAAM,EAAOC,EAAAA,oBAAoB,OAAO,CAAK,CAAC,EAC9C,GAAI,CAAC,EAAM,SACX,IAAM,EAAQ,OAAO,KAAK,EAAM,MAAM,EAClC,EAAU,EAAM,WAAa,IAC/B,EAAA,QAAG,UAAU,CAAM,EACnB,EAAA,QAAG,WAAW,EAAS,CAAW,EAClC,EAASD,EAAAA,QAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EACV,GAAa,GAEf,EAAA,QAAG,UAAU,EAAQ,CAAK,EAC1B,GAAW,EAAM,WACjB,GAAU,CACZ,CAUA,OATA,EAAA,QAAG,UAAU,CAAM,EACnB,EAAU,CAAQ,EAClB,MAAM,EAAU,YAAY,iCAAkC,CAC5D,QAAS,YACT,qBAAsB,EACtB,uBAAwB,EACxB,wBAAyB,EACzB,YAAa,KAAK,IAAI,EAAI,CAC5B,CAAC,EACM,CACT,OAAS,EAAO,CAEd,MADA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EACpG,CACR,QAAU,CACR,MAAM,EAAU,SAAS,CAC3B,CACF,CAEA,SAAS,EAAU,EAAsB,CACvC,IAAM,EAAY,GAAG,EAAO,GAAG,QAAQ,IAAI,MAC3C,EAAA,QAAG,cAAc,EAAW,GAAI,CAAE,KAAM,GAAM,CAAC,EAC/C,EAAA,QAAG,WAAW,EAAW,CAAM,CACjC,CAEI,QAAQ,KAAK,IAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,QAAA,EAA0BE,EAAAA,cAAAA,CAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"logSink.mjs","names":[],"sources":["../../src/bin/logSink.ts"],"sourcesContent":["import { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport { scrubTerminalOutput } from '../services/AnsiScrub/index.ts';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-log-sink',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [logPath, rotatedPath, maxBytesRaw, donePath] = argv;\n let maxBytes: number;\n try {\n if (!logPath || !rotatedPath || !maxBytesRaw || !donePath) {\n throw new Error('logSink requires log, rotated log, max bytes, and completion paths');\n }\n maxBytes = Number(maxBytesRaw);\n if (!Number.isFinite(maxBytes) || maxBytes <= 0) throw new Error('logSink max bytes must be positive');\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n\n let handle: number;\n let written: number;\n try {\n handle = fs.openSync(logPath, 'a');\n written = fs.statSync(logPath).size;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let chunks = 0;\n let rotations = 0;\n try {\n process.stdin.setEncoding('utf8');\n for await (const chunk of process.stdin) {\n const text = scrubTerminalOutput(String(chunk));\n if (!text) continue;\n const bytes = Buffer.from(text, 'utf8');\n if (written + bytes.byteLength > maxBytes) {\n fs.closeSync(handle);\n fs.renameSync(logPath, rotatedPath);\n handle = fs.openSync(logPath, 'w');\n written = 0;\n rotations += 1;\n }\n fs.writeSync(handle, bytes);\n written += bytes.byteLength;\n chunks += 1;\n }\n fs.closeSync(handle);\n writeDone(donePath);\n await telemetry.recordEvent('doom_runner.file_sink_finished', {\n outcome: 'completed',\n 'runner.chunk_count': chunks,\n 'runner.bytes_written': written,\n 'runner.rotation_count': rotations,\n duration_ms: Date.now() - startedAt,\n });\n return 0;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n await telemetry.shutdown();\n }\n}\n\nfunction writeDone(target: string): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, '', { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"oPAKA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,EAAY,EAAoB,CACpC,YAAa,uBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,CAAC,EAAS,EAAa,EAAa,GAAY,EAClD,EACJ,GAAI,CACF,GAAI,CAAC,GAAW,CAAC,GAAe,CAAC,GAAe,CAAC,EAC/C,MAAU,MAAM,oEAAoE,EAGtF,GADA,EAAW,OAAO,CAAW,EACzB,CAAC,OAAO,SAAS,CAAQ,GAAK,GAAY,EAAG,MAAU,MAAM,oCAAoC,CACvG,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CAEA,IAAI,EACA,EACJ,GAAI,CACF,EAAS,EAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EAAG,SAAS,CAAO,CAAC,CAAC,IACjC,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CACA,IAAI,EAAS,EACT,EAAY,EAChB,GAAI,CACF,QAAQ,MAAM,YAAY,MAAM,EAChC,UAAW,IAAM,KAAS,QAAQ,MAAO,CACvC,IAAM,EAAO,EAAoB,OAAO,CAAK,CAAC,EAC9C,GAAI,CAAC,EAAM,SACX,IAAM,EAAQ,OAAO,KAAK,EAAM,MAAM,EAClC,EAAU,EAAM,WAAa,IAC/B,EAAG,UAAU,CAAM,EACnB,EAAG,WAAW,EAAS,CAAW,EAClC,EAAS,EAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EACV,GAAa,GAEf,EAAG,UAAU,EAAQ,CAAK,EAC1B,GAAW,EAAM,WACjB,GAAU,CACZ,CAUA,OATA,EAAG,UAAU,CAAM,EACnB,EAAU,CAAQ,EAClB,MAAM,EAAU,YAAY,iCAAkC,CAC5D,QAAS,YACT,qBAAsB,EACtB,uBAAwB,EACxB,wBAAyB,EACzB,YAAa,KAAK,IAAI,EAAI,CAC5B,CAAC,EACM,CACT,OAAS,EAAO,CAEd,MADA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EACpG,CACR,QAAU,CACR,MAAM,EAAU,SAAS,CAC3B,CACF,CAEA,SAAS,EAAU,EAAsB,CACvC,IAAM,EAAY,GAAG,EAAO,GAAG,QAAQ,IAAI,MAC3C,EAAG,cAAc,EAAW,GAAI,CAAE,KAAM,GAAM,CAAC,EAC/C,EAAG,WAAW,EAAW,CAAM,CACjC,CAEI,QAAQ,KAAK,IAAM,YAAY,MAAQ,EAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
1
+ {"version":3,"file":"logSink.mjs","names":[],"sources":["../../src/bin/logSink.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { scrubTerminalOutput } from '../services/AnsiScrub/index.ts';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-log-sink',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [logPath, rotatedPath, maxBytesRaw, donePath] = argv;\n let maxBytes: number;\n try {\n if (!logPath || !rotatedPath || !maxBytesRaw || !donePath) {\n throw new Error('logSink requires log, rotated log, max bytes, and completion paths');\n }\n maxBytes = Number(maxBytesRaw);\n if (!Number.isFinite(maxBytes) || maxBytes <= 0) throw new Error('logSink max bytes must be positive');\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n\n let handle: number;\n let written: number;\n try {\n handle = fs.openSync(logPath, 'a');\n written = fs.statSync(logPath).size;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let chunks = 0;\n let rotations = 0;\n try {\n process.stdin.setEncoding('utf8');\n for await (const chunk of process.stdin) {\n const text = scrubTerminalOutput(String(chunk));\n if (!text) continue;\n const bytes = Buffer.from(text, 'utf8');\n if (written + bytes.byteLength > maxBytes) {\n fs.closeSync(handle);\n fs.renameSync(logPath, rotatedPath);\n handle = fs.openSync(logPath, 'w');\n written = 0;\n rotations += 1;\n }\n fs.writeSync(handle, bytes);\n written += bytes.byteLength;\n chunks += 1;\n }\n fs.closeSync(handle);\n writeDone(donePath);\n await telemetry.recordEvent('doom_runner.file_sink_finished', {\n outcome: 'completed',\n 'runner.chunk_count': chunks,\n 'runner.bytes_written': written,\n 'runner.rotation_count': rotations,\n duration_ms: Date.now() - startedAt,\n });\n return 0;\n } catch (error) {\n await telemetry.recordError('doom_runner.file_sink_failed', error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n await telemetry.shutdown();\n }\n}\n\nfunction writeDone(target: string): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, '', { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"oPAKA,eAAsB,EAAK,EAA0B,QAAQ,KAAK,MAAM,CAAC,EAAoB,CAC3F,IAAM,EAAY,KAAK,IAAI,EACrB,EAAY,EAAoB,CACpC,YAAa,uBACb,YAAa,2BACb,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACK,CAAC,EAAS,EAAa,EAAa,GAAY,EAClD,EACJ,GAAI,CACF,GAAI,CAAC,GAAW,CAAC,GAAe,CAAC,GAAe,CAAC,EAC/C,MAAU,MAAM,oEAAoE,EAGtF,GADA,EAAW,OAAO,CAAW,EACzB,CAAC,OAAO,SAAS,CAAQ,GAAK,GAAY,EAAG,MAAU,MAAM,oCAAoC,CACvG,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CAEA,IAAI,EACA,EACJ,GAAI,CACF,EAAS,EAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EAAG,SAAS,CAAO,CAAC,CAAC,IACjC,OAAS,EAAO,CAGd,MAFA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EAC1G,MAAM,EAAU,SAAS,EACnB,CACR,CACA,IAAI,EAAS,EACT,EAAY,EAChB,GAAI,CACF,QAAQ,MAAM,YAAY,MAAM,EAChC,UAAW,IAAM,KAAS,QAAQ,MAAO,CACvC,IAAM,EAAO,EAAoB,OAAO,CAAK,CAAC,EAC9C,GAAI,CAAC,EAAM,SACX,IAAM,EAAQ,OAAO,KAAK,EAAM,MAAM,EAClC,EAAU,EAAM,WAAa,IAC/B,EAAG,UAAU,CAAM,EACnB,EAAG,WAAW,EAAS,CAAW,EAClC,EAAS,EAAG,SAAS,EAAS,GAAG,EACjC,EAAU,EACV,GAAa,GAEf,EAAG,UAAU,EAAQ,CAAK,EAC1B,GAAW,EAAM,WACjB,GAAU,CACZ,CAUA,OATA,EAAG,UAAU,CAAM,EACnB,EAAU,CAAQ,EAClB,MAAM,EAAU,YAAY,iCAAkC,CAC5D,QAAS,YACT,qBAAsB,EACtB,uBAAwB,EACxB,wBAAyB,EACzB,YAAa,KAAK,IAAI,EAAI,CAC5B,CAAC,EACM,CACT,OAAS,EAAO,CAEd,MADA,MAAM,EAAU,YAAY,+BAAgC,EAAO,CAAE,YAAa,KAAK,IAAI,EAAI,CAAU,CAAC,EACpG,CACR,QAAU,CACR,MAAM,EAAU,SAAS,CAC3B,CACF,CAEA,SAAS,EAAU,EAAsB,CACvC,IAAM,EAAY,GAAG,EAAO,GAAG,QAAQ,IAAI,MAC3C,EAAG,cAAc,EAAW,GAAI,CAAE,KAAM,GAAM,CAAC,EAC/C,EAAG,WAAW,EAAW,CAAM,CACjC,CAEI,QAAQ,KAAK,IAAM,YAAY,MAAQ,EAAc,QAAQ,KAAK,EAAE,CAAC,CAAC,MACxE,EAAK,CAAC,CAAC,KACJ,GAAS,CACR,QAAQ,SAAW,CACrB,EACC,GAAmB,CAClB,QAAQ,OAAO,MAAM,GAAG,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAAE,GAAG,EAClF,QAAQ,SAAW,CACrB,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"runnerHost.cjs","names":["createDoomTelemetry","spawn","watchOwner","LIFELINE_ENV","os","fs","pathToFileURL"],"sources":["../../src/bin/runnerHost.ts"],"sourcesContent":["import { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { pathToFileURL } from 'node:url';\nimport { LIFELINE_ENV, watchOwner } from '../services/Lifeline/client.ts';\n\ninterface CommandSpec {\n command: string;\n cwd: string;\n env: Record<string, string>;\n}\n\nconst POLL_MS = 10;\nconst FORWARDED_SIGNAL_GRACE_MS = 2_000;\nconst HOST_FAILED_EVENT = 'doom_runner.host_failed';\nconst INVALID_COMMAND_SPEC_ERROR = 'invalid runner command spec';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-host',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [specPath, gatePath, exitPath] = argv;\n let spec: CommandSpec;\n try {\n if (!specPath || !gatePath || !exitPath) throw new Error('runnerHost requires spec, gate, and exit paths');\n spec = readSpec(specPath);\n await waitForGate(gatePath);\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let child: ChildProcess | undefined;\n let forwardedSignal: NodeJS.Signals | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n const signalChild = (signal: NodeJS.Signals): void => {\n if (!child?.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch {\n child.kill(signal);\n }\n };\n const forward = (signal: NodeJS.Signals): void => {\n forwardedSignal = signal;\n signalChild(signal);\n escalationTimer ??= setTimeout(() => signalChild('SIGKILL'), FORWARDED_SIGNAL_GRACE_MS);\n };\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];\n for (const signal of signals) process.once(signal, () => forward(signal));\n\n child = spawn(spec.command, {\n cwd: spec.cwd,\n env: spec.env,\n shell: '/bin/bash',\n stdio: 'inherit',\n detached: true,\n });\n if (forwardedSignal) forward(forwardedSignal);\n\n // This process supervises the command for its whole life, so it is also the\n // right place to notice an owner that died without stopping it.\n //\n // The lifeline comes from the spec rather than this process's environment: an\n // rmux server outlives the session that started it, so its own environment can\n // still name a previous session's socket.\n const detachLifeline = watchOwner(() => forward('SIGTERM'), spec.env[LIFELINE_ENV]);\n\n try {\n const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n child?.once('error', reject);\n child?.once('exit', (code, signal) => resolve({ code, signal: signal ?? forwardedSignal }));\n });\n writeAtomic(exitPath, result);\n const exitCode = result.code !== null ? result.code : result.signal ? 128 + os.constants.signals[result.signal] : 1;\n await telemetry.recordEvent('doom_runner.host_finished', {\n outcome: result.signal || forwardedSignal ? 'signaled' : exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n ...(result.signal || forwardedSignal ? { 'runner.signal': result.signal ?? forwardedSignal ?? '' } : {}),\n duration_ms: Date.now() - startedAt,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n detachLifeline();\n if (escalationTimer) clearTimeout(escalationTimer);\n await telemetry.shutdown();\n }\n}\n\nfunction readSpec(target: string): CommandSpec {\n const value: unknown = JSON.parse(fs.readFileSync(target, 'utf8'));\n if (typeof value !== 'object' || value === null) throw new Error(INVALID_COMMAND_SPEC_ERROR);\n const spec = value as Partial<CommandSpec>;\n if (typeof spec.command !== 'string' || typeof spec.cwd !== 'string' || !spec.env) {\n throw new Error(INVALID_COMMAND_SPEC_ERROR);\n }\n return { command: spec.command, cwd: spec.cwd, env: spec.env };\n}\n\nasync function waitForGate(target: string): Promise<void> {\n while (!fs.existsSync(target)) await new Promise((resolve) => setTimeout(resolve, POLL_MS));\n}\n\nfunction writeAtomic(target: string, value: unknown): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(value)}\\n`, { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runnerHost.cjs","names":["createDoomTelemetry","spawn","watchOwner","LIFELINE_ENV","os","fs","pathToFileURL"],"sources":["../../src/bin/runnerHost.ts"],"sourcesContent":["import { type ChildProcess, spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { LIFELINE_ENV, watchOwner } from '../services/Lifeline/client.ts';\n\ninterface CommandSpec {\n command: string;\n cwd: string;\n env: Record<string, string>;\n}\n\nconst POLL_MS = 10;\nconst FORWARDED_SIGNAL_GRACE_MS = 2_000;\nconst HOST_FAILED_EVENT = 'doom_runner.host_failed';\nconst INVALID_COMMAND_SPEC_ERROR = 'invalid runner command spec';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-host',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [specPath, gatePath, exitPath] = argv;\n let spec: CommandSpec;\n try {\n if (!specPath || !gatePath || !exitPath) throw new Error('runnerHost requires spec, gate, and exit paths');\n spec = readSpec(specPath);\n await waitForGate(gatePath);\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let child: ChildProcess | undefined;\n let forwardedSignal: NodeJS.Signals | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n const signalChild = (signal: NodeJS.Signals): void => {\n if (!child?.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch {\n child.kill(signal);\n }\n };\n const forward = (signal: NodeJS.Signals): void => {\n forwardedSignal = signal;\n signalChild(signal);\n escalationTimer ??= setTimeout(() => signalChild('SIGKILL'), FORWARDED_SIGNAL_GRACE_MS);\n };\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];\n for (const signal of signals) process.once(signal, () => forward(signal));\n\n child = spawn(spec.command, {\n cwd: spec.cwd,\n env: spec.env,\n shell: '/bin/bash',\n stdio: 'inherit',\n detached: true,\n });\n if (forwardedSignal) forward(forwardedSignal);\n\n // This process supervises the command for its whole life, so it is also the\n // right place to notice an owner that died without stopping it.\n //\n // The lifeline comes from the spec rather than this process's environment: an\n // rmux server outlives the session that started it, so its own environment can\n // still name a previous session's socket.\n const detachLifeline = watchOwner(() => forward('SIGTERM'), spec.env[LIFELINE_ENV]);\n\n try {\n const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n child?.once('error', reject);\n child?.once('exit', (code, signal) => resolve({ code, signal: signal ?? forwardedSignal }));\n });\n writeAtomic(exitPath, result);\n const exitCode = result.code !== null ? result.code : result.signal ? 128 + os.constants.signals[result.signal] : 1;\n await telemetry.recordEvent('doom_runner.host_finished', {\n outcome: result.signal || forwardedSignal ? 'signaled' : exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n ...(result.signal || forwardedSignal ? { 'runner.signal': result.signal ?? forwardedSignal ?? '' } : {}),\n duration_ms: Date.now() - startedAt,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n detachLifeline();\n if (escalationTimer) clearTimeout(escalationTimer);\n await telemetry.shutdown();\n }\n}\n\nfunction readSpec(target: string): CommandSpec {\n const value: unknown = JSON.parse(fs.readFileSync(target, 'utf8'));\n if (typeof value !== 'object' || value === null) throw new Error(INVALID_COMMAND_SPEC_ERROR);\n const spec = value as Partial<CommandSpec>;\n if (typeof spec.command !== 'string' || typeof spec.cwd !== 'string' || !spec.env) {\n throw new Error(INVALID_COMMAND_SPEC_ERROR);\n }\n return { command: spec.command, cwd: spec.cwd, env: spec.env };\n}\n\nasync function waitForGate(target: string): Promise<void> {\n while (!fs.existsSync(target)) await new Promise((resolve) => setTimeout(resolve, POLL_MS));\n}\n\nfunction writeAtomic(target: string, value: unknown): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(value)}\\n`, { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runnerHost.mjs","names":[],"sources":["../../src/bin/runnerHost.ts"],"sourcesContent":["import { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { pathToFileURL } from 'node:url';\nimport { LIFELINE_ENV, watchOwner } from '../services/Lifeline/client.ts';\n\ninterface CommandSpec {\n command: string;\n cwd: string;\n env: Record<string, string>;\n}\n\nconst POLL_MS = 10;\nconst FORWARDED_SIGNAL_GRACE_MS = 2_000;\nconst HOST_FAILED_EVENT = 'doom_runner.host_failed';\nconst INVALID_COMMAND_SPEC_ERROR = 'invalid runner command spec';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-host',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [specPath, gatePath, exitPath] = argv;\n let spec: CommandSpec;\n try {\n if (!specPath || !gatePath || !exitPath) throw new Error('runnerHost requires spec, gate, and exit paths');\n spec = readSpec(specPath);\n await waitForGate(gatePath);\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let child: ChildProcess | undefined;\n let forwardedSignal: NodeJS.Signals | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n const signalChild = (signal: NodeJS.Signals): void => {\n if (!child?.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch {\n child.kill(signal);\n }\n };\n const forward = (signal: NodeJS.Signals): void => {\n forwardedSignal = signal;\n signalChild(signal);\n escalationTimer ??= setTimeout(() => signalChild('SIGKILL'), FORWARDED_SIGNAL_GRACE_MS);\n };\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];\n for (const signal of signals) process.once(signal, () => forward(signal));\n\n child = spawn(spec.command, {\n cwd: spec.cwd,\n env: spec.env,\n shell: '/bin/bash',\n stdio: 'inherit',\n detached: true,\n });\n if (forwardedSignal) forward(forwardedSignal);\n\n // This process supervises the command for its whole life, so it is also the\n // right place to notice an owner that died without stopping it.\n //\n // The lifeline comes from the spec rather than this process's environment: an\n // rmux server outlives the session that started it, so its own environment can\n // still name a previous session's socket.\n const detachLifeline = watchOwner(() => forward('SIGTERM'), spec.env[LIFELINE_ENV]);\n\n try {\n const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n child?.once('error', reject);\n child?.once('exit', (code, signal) => resolve({ code, signal: signal ?? forwardedSignal }));\n });\n writeAtomic(exitPath, result);\n const exitCode = result.code !== null ? result.code : result.signal ? 128 + os.constants.signals[result.signal] : 1;\n await telemetry.recordEvent('doom_runner.host_finished', {\n outcome: result.signal || forwardedSignal ? 'signaled' : exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n ...(result.signal || forwardedSignal ? { 'runner.signal': result.signal ?? forwardedSignal ?? '' } : {}),\n duration_ms: Date.now() - startedAt,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n detachLifeline();\n if (escalationTimer) clearTimeout(escalationTimer);\n await telemetry.shutdown();\n }\n}\n\nfunction readSpec(target: string): CommandSpec {\n const value: unknown = JSON.parse(fs.readFileSync(target, 'utf8'));\n if (typeof value !== 'object' || value === null) throw new Error(INVALID_COMMAND_SPEC_ERROR);\n const spec = value as Partial<CommandSpec>;\n if (typeof spec.command !== 'string' || typeof spec.cwd !== 'string' || !spec.env) {\n throw new Error(INVALID_COMMAND_SPEC_ERROR);\n }\n return { command: spec.command, cwd: spec.cwd, env: spec.env };\n}\n\nasync function waitForGate(target: string): Promise<void> {\n while (!fs.existsSync(target)) await new Promise((resolve) => setTimeout(resolve, POLL_MS));\n}\n\nfunction writeAtomic(target: string, value: unknown): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(value)}\\n`, { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runnerHost.mjs","names":[],"sources":["../../src/bin/runnerHost.ts"],"sourcesContent":["import { type ChildProcess, spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport { pathToFileURL } from 'node:url';\nimport { createDoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport { LIFELINE_ENV, watchOwner } from '../services/Lifeline/client.ts';\n\ninterface CommandSpec {\n command: string;\n cwd: string;\n env: Record<string, string>;\n}\n\nconst POLL_MS = 10;\nconst FORWARDED_SIGNAL_GRACE_MS = 2_000;\nconst HOST_FAILED_EVENT = 'doom_runner.host_failed';\nconst INVALID_COMMAND_SPEC_ERROR = 'invalid runner command spec';\n\nexport async function main(argv: readonly string[] = process.argv.slice(2)): Promise<number> {\n const startedAt = Date.now();\n const telemetry = createDoomTelemetry({\n serviceName: 'doom-runner-host',\n packageName: '@agimon-ai/doompi-runner',\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n const [specPath, gatePath, exitPath] = argv;\n let spec: CommandSpec;\n try {\n if (!specPath || !gatePath || !exitPath) throw new Error('runnerHost requires spec, gate, and exit paths');\n spec = readSpec(specPath);\n await waitForGate(gatePath);\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n await telemetry.shutdown();\n throw error;\n }\n let child: ChildProcess | undefined;\n let forwardedSignal: NodeJS.Signals | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n const signalChild = (signal: NodeJS.Signals): void => {\n if (!child?.pid) return;\n try {\n process.kill(-child.pid, signal);\n } catch {\n child.kill(signal);\n }\n };\n const forward = (signal: NodeJS.Signals): void => {\n forwardedSignal = signal;\n signalChild(signal);\n escalationTimer ??= setTimeout(() => signalChild('SIGKILL'), FORWARDED_SIGNAL_GRACE_MS);\n };\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT', 'SIGHUP'];\n for (const signal of signals) process.once(signal, () => forward(signal));\n\n child = spawn(spec.command, {\n cwd: spec.cwd,\n env: spec.env,\n shell: '/bin/bash',\n stdio: 'inherit',\n detached: true,\n });\n if (forwardedSignal) forward(forwardedSignal);\n\n // This process supervises the command for its whole life, so it is also the\n // right place to notice an owner that died without stopping it.\n //\n // The lifeline comes from the spec rather than this process's environment: an\n // rmux server outlives the session that started it, so its own environment can\n // still name a previous session's socket.\n const detachLifeline = watchOwner(() => forward('SIGTERM'), spec.env[LIFELINE_ENV]);\n\n try {\n const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n child?.once('error', reject);\n child?.once('exit', (code, signal) => resolve({ code, signal: signal ?? forwardedSignal }));\n });\n writeAtomic(exitPath, result);\n const exitCode = result.code !== null ? result.code : result.signal ? 128 + os.constants.signals[result.signal] : 1;\n await telemetry.recordEvent('doom_runner.host_finished', {\n outcome: result.signal || forwardedSignal ? 'signaled' : exitCode === 0 ? 'completed' : 'failed',\n 'runner.exit_code': exitCode,\n ...(result.signal || forwardedSignal ? { 'runner.signal': result.signal ?? forwardedSignal ?? '' } : {}),\n duration_ms: Date.now() - startedAt,\n });\n return exitCode;\n } catch (error) {\n await telemetry.recordError(HOST_FAILED_EVENT, error, { duration_ms: Date.now() - startedAt });\n throw error;\n } finally {\n detachLifeline();\n if (escalationTimer) clearTimeout(escalationTimer);\n await telemetry.shutdown();\n }\n}\n\nfunction readSpec(target: string): CommandSpec {\n const value: unknown = JSON.parse(fs.readFileSync(target, 'utf8'));\n if (typeof value !== 'object' || value === null) throw new Error(INVALID_COMMAND_SPEC_ERROR);\n const spec = value as Partial<CommandSpec>;\n if (typeof spec.command !== 'string' || typeof spec.cwd !== 'string' || !spec.env) {\n throw new Error(INVALID_COMMAND_SPEC_ERROR);\n }\n return { command: spec.command, cwd: spec.cwd, env: spec.env };\n}\n\nasync function waitForGate(target: string): Promise<void> {\n while (!fs.existsSync(target)) await new Promise((resolve) => setTimeout(resolve, POLL_MS));\n}\n\nfunction writeAtomic(target: string, value: unknown): void {\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(value)}\\n`, { mode: 0o600 });\n fs.renameSync(temporary, target);\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n main().then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n },\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../session.cjs"),n=require("../tool/responseEnvelope.cjs");let r=require("node:fs");r=e.__toESM(r,1);const i=`completed`,a=`rmux`,o=`stopped`,s=`SIGTERM`;async function c(e,n){let[r,...i]=e;if(r!==void 0&&r!==`--help`&&r!==`-h`&&!t.inheritedSessionId(n.env))return n.stderr(`PI_SESSION_ID is required for doom-runner commands`),1;switch(r){case`list`:return l(i,n);case`status`:return u(i,n);case`logs`:return d(i,n);case`stop`:return f(i,n);case`stop-all`:return p(i,n);case`input`:return m(i,n);case`--help`:case`-h`:case void 0:return n.stdout(S()),0;default:return n.stderr(`Unknown command: ${r}\n\n${S()}`),1}}async function l(e,n){let r=t.requiredSessionId(n.env),i=e.includes(`--all`)?await n.registry.listAll(r):await n.registry.listBySession(r);return n.stdout(i.length>0?i.map(g).join(`
2
- `):`No runners`),0}async function u(e,t){let n=await h(e[0],t);return n?(t.stdout([`ID: ${n.id}`,`Name: ${n.name}`,`State: ${n.state}`,`Backend: ${n.backend}`,...n.backendTarget?[`Backend target: ${n.backendTarget}`]:[],`PID: ${n.pid}`,`Command: ${n.command}`,`CWD: ${n.cwd}`,`Session: ${n.sessionId}`,`Log: ${n.logPath}`,...n.exit?[`Exit: ${_(n)}`]:[]].join(`
3
- `)),0):1}async function d(e,t){let n=await h(e[0],t);if(!n)return 1;let r=y(v(e,`--lines`))??200,i=t.logReader.read(n.logPath,{lines:r});return i.exists?(i.text&&t.stdout(i.text),e.includes(`--follow`)?b(n,i.fileSize,t):0):(t.stderr(`Runner ${n.id} has not written a log yet`),1)}async function f(e,t){let n=await h(e[0],t);if(!n)return 1;if(n.state!==`running`)return t.stderr(`Runner ${n.id} is already ${n.state}`),1;await x(n,t);let r=v(e,`--reason`);return await t.registry.complete(n.id,{reason:o,code:null,signal:s,...r?{stopReason:r}:{}},n.sessionId),t.stdout(`Stopped ${n.id}\nLog: ${n.logPath}`),0}async function p(e,n){let r=t.requiredSessionId(n.env),i=await n.registry.listBySession(r),a=v(e,`--reason`);for(let e of i)await x(e,n),await n.registry.complete(e.id,{reason:o,code:null,signal:s,...a?{stopReason:a}:{}},e.sessionId);return n.stdout(i.length>0?`Stopped ${i.length} runner(s) for session ${r}: ${i.map(e=>e.id).join(`, `)}`:`No active runners for session ${r}`),0}async function m(e,t){let n=await h(e[0],t);if(!n)return 1;if(n.state===i)return t.stderr(`Runner ${n.id} is already completed; use doom-runner logs ${n.id}`),1;if(!n.interactive)return t.stderr(`Runner ${n.id} was not started with interactive: true`),1;let r=v(e,`--text`)??await t.readStdin(),o=e.includes(`--enter`)&&!r.endsWith(`
4
- `)?`${r}\n`:r;return n.backend!==a||!n.backendTarget?(t.stderr(`Runner ${n.id} uses the ${n.backend} backend, which does not expose CLI input`),1):await t.rmuxBackend.input(n.backendTarget,o)?(t.stdout(`Sent input to ${n.id}`),0):(t.stderr(`Runner ${n.id} is no longer accepting RMUX input`),1)}async function h(e,n){if(!e){n.stderr(`A runner ID is required`);return}let r=t.requiredSessionId(n.env),i=await n.registry.get(e,r);if(!i){n.stderr(`No runner with id ${e}`);return}return i}function g(e){let t=n.formatRunnerLine(e);return`${e.id} ${e.state} ${e.backend} ${t}`}function _(e){let t=e.exit;if(!t)return`unknown`;let n=t.code===null?t.signal?` ${t.signal}`:``:` code ${t.code}`,r=t.stopReason?` (${t.stopReason})`:``;return`${t.reason}${n}${r}`}function v(e,t){let n=e.indexOf(t);return n>=0?e[n+1]:void 0}function y(e){if(e===void 0)return;let t=Number(e);return Number.isInteger(t)&&t>0?t:void 0}async function b(e,t,n){let a=t;return new Promise(t=>{let o=!1,s,c=t=>{if(t.size<a&&(a=0),t.size===a)return;let i=t.size-a,o=Buffer.alloc(i),s=r.default.openSync(e.logPath,`r`);try{let e=r.default.readSync(s,o,0,i,a);e>0&&n.stdout(o.subarray(0,e).toString(`utf8`))}finally{r.default.closeSync(s)}a=t.size},l=()=>{if(!o){o=!0;try{c(r.default.statSync(e.logPath))}catch(t){t.code!==`ENOENT`&&n.stderr(`Runner ${e.id} failed to flush its final log output: ${t.message}`)}r.default.unwatchFile(e.logPath,c),clearInterval(s),process.off(`SIGINT`,l),t(0)}};process.once(`SIGINT`,l),r.default.watchFile(e.logPath,{interval:250},c),s=setInterval(()=>{n.registry.get(e.id).then(e=>{e?.state===i&&l()})},250)})}async function x(e,t){return e.backend===a&&e.backendTarget?t.rmuxBackend.stop(e.backendTarget,e.pid):t.launcher.stop(e.pid)}function S(){return[`Usage: doom-runner <command>`,``,`Commands:`,` list [--all]`,` status <id>`,` logs <id> [--lines N] [--follow]`,` stop <id> [--reason <text>]`,` stop-all [--reason <text>]`,` input <id> [--text <text>] [--enter]`].join(`
5
- `)}exports.runCli=c;
6
- //# sourceMappingURL=cliApp.cjs.map
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../commands/cli/cliApp.cjs");exports.runCli=e.runCli;
@@ -1,23 +1,2 @@
1
- import { ILauncher } from "../services/Launcher/types.cjs";
2
- import "../services/Launcher/index.cjs";
3
- import { ILogReader } from "../services/LogReader/types.cjs";
4
- import "../services/LogReader/index.cjs";
5
- import { IRmuxBackend } from "../services/RmuxBackend/types.cjs";
6
- import "../services/RmuxBackend/index.cjs";
7
- import { IRunnerRegistry } from "../services/RunnerRegistry/types.cjs";
8
- import "../services/RunnerRegistry/index.cjs";
9
- //#region src/cli/cliApp.d.ts
10
- interface CliDependencies {
11
- registry: IRunnerRegistry;
12
- launcher: ILauncher;
13
- rmuxBackend: IRmuxBackend;
14
- logReader: ILogReader;
15
- env?: NodeJS.ProcessEnv;
16
- stdout(text: string): void;
17
- stderr(text: string): void;
18
- readStdin(): Promise<string>;
19
- }
20
- declare function runCli(argv: readonly string[], dependencies: CliDependencies): Promise<number>;
21
- //#endregion
22
- export { CliDependencies, runCli };
23
- //# sourceMappingURL=cliApp.d.cts.map
1
+ import { CliDependencies, runCli } from "../commands/cli/cliApp.cjs";
2
+ export { CliDependencies, runCli };
@@ -1,23 +1,2 @@
1
- import { ILauncher } from "../services/Launcher/types.mjs";
2
- import "../services/Launcher/index.mjs";
3
- import { ILogReader } from "../services/LogReader/types.mjs";
4
- import "../services/LogReader/index.mjs";
5
- import { IRmuxBackend } from "../services/RmuxBackend/types.mjs";
6
- import "../services/RmuxBackend/index.mjs";
7
- import { IRunnerRegistry } from "../services/RunnerRegistry/types.mjs";
8
- import "../services/RunnerRegistry/index.mjs";
9
- //#region src/cli/cliApp.d.ts
10
- interface CliDependencies {
11
- registry: IRunnerRegistry;
12
- launcher: ILauncher;
13
- rmuxBackend: IRmuxBackend;
14
- logReader: ILogReader;
15
- env?: NodeJS.ProcessEnv;
16
- stdout(text: string): void;
17
- stderr(text: string): void;
18
- readStdin(): Promise<string>;
19
- }
20
- declare function runCli(argv: readonly string[], dependencies: CliDependencies): Promise<number>;
21
- //#endregion
22
- export { CliDependencies, runCli };
23
- //# sourceMappingURL=cliApp.d.mts.map
1
+ import { CliDependencies, runCli } from "../commands/cli/cliApp.mjs";
2
+ export { CliDependencies, runCli };
@@ -1,6 +1 @@
1
- import{inheritedSessionId as e,requiredSessionId as t}from"../session.mjs";import{formatRunnerLine as n}from"../tool/responseEnvelope.mjs";import r from"node:fs";const i=`completed`,a=`rmux`,o=`stopped`,s=`SIGTERM`;async function c(t,n){let[r,...i]=t;if(r!==void 0&&r!==`--help`&&r!==`-h`&&!e(n.env))return n.stderr(`PI_SESSION_ID is required for doom-runner commands`),1;switch(r){case`list`:return l(i,n);case`status`:return u(i,n);case`logs`:return d(i,n);case`stop`:return f(i,n);case`stop-all`:return p(i,n);case`input`:return m(i,n);case`--help`:case`-h`:case void 0:return n.stdout(S()),0;default:return n.stderr(`Unknown command: ${r}\n\n${S()}`),1}}async function l(e,n){let r=t(n.env),i=e.includes(`--all`)?await n.registry.listAll(r):await n.registry.listBySession(r);return n.stdout(i.length>0?i.map(g).join(`
2
- `):`No runners`),0}async function u(e,t){let n=await h(e[0],t);return n?(t.stdout([`ID: ${n.id}`,`Name: ${n.name}`,`State: ${n.state}`,`Backend: ${n.backend}`,...n.backendTarget?[`Backend target: ${n.backendTarget}`]:[],`PID: ${n.pid}`,`Command: ${n.command}`,`CWD: ${n.cwd}`,`Session: ${n.sessionId}`,`Log: ${n.logPath}`,...n.exit?[`Exit: ${_(n)}`]:[]].join(`
3
- `)),0):1}async function d(e,t){let n=await h(e[0],t);if(!n)return 1;let r=y(v(e,`--lines`))??200,i=t.logReader.read(n.logPath,{lines:r});return i.exists?(i.text&&t.stdout(i.text),e.includes(`--follow`)?b(n,i.fileSize,t):0):(t.stderr(`Runner ${n.id} has not written a log yet`),1)}async function f(e,t){let n=await h(e[0],t);if(!n)return 1;if(n.state!==`running`)return t.stderr(`Runner ${n.id} is already ${n.state}`),1;await x(n,t);let r=v(e,`--reason`);return await t.registry.complete(n.id,{reason:o,code:null,signal:s,...r?{stopReason:r}:{}},n.sessionId),t.stdout(`Stopped ${n.id}\nLog: ${n.logPath}`),0}async function p(e,n){let r=t(n.env),i=await n.registry.listBySession(r),a=v(e,`--reason`);for(let e of i)await x(e,n),await n.registry.complete(e.id,{reason:o,code:null,signal:s,...a?{stopReason:a}:{}},e.sessionId);return n.stdout(i.length>0?`Stopped ${i.length} runner(s) for session ${r}: ${i.map(e=>e.id).join(`, `)}`:`No active runners for session ${r}`),0}async function m(e,t){let n=await h(e[0],t);if(!n)return 1;if(n.state===i)return t.stderr(`Runner ${n.id} is already completed; use doom-runner logs ${n.id}`),1;if(!n.interactive)return t.stderr(`Runner ${n.id} was not started with interactive: true`),1;let r=v(e,`--text`)??await t.readStdin(),o=e.includes(`--enter`)&&!r.endsWith(`
4
- `)?`${r}\n`:r;return n.backend!==a||!n.backendTarget?(t.stderr(`Runner ${n.id} uses the ${n.backend} backend, which does not expose CLI input`),1):await t.rmuxBackend.input(n.backendTarget,o)?(t.stdout(`Sent input to ${n.id}`),0):(t.stderr(`Runner ${n.id} is no longer accepting RMUX input`),1)}async function h(e,n){if(!e){n.stderr(`A runner ID is required`);return}let r=t(n.env),i=await n.registry.get(e,r);if(!i){n.stderr(`No runner with id ${e}`);return}return i}function g(e){let t=n(e);return`${e.id} ${e.state} ${e.backend} ${t}`}function _(e){let t=e.exit;if(!t)return`unknown`;let n=t.code===null?t.signal?` ${t.signal}`:``:` code ${t.code}`,r=t.stopReason?` (${t.stopReason})`:``;return`${t.reason}${n}${r}`}function v(e,t){let n=e.indexOf(t);return n>=0?e[n+1]:void 0}function y(e){if(e===void 0)return;let t=Number(e);return Number.isInteger(t)&&t>0?t:void 0}async function b(e,t,n){let a=t;return new Promise(t=>{let o=!1,s,c=t=>{if(t.size<a&&(a=0),t.size===a)return;let i=t.size-a,o=Buffer.alloc(i),s=r.openSync(e.logPath,`r`);try{let e=r.readSync(s,o,0,i,a);e>0&&n.stdout(o.subarray(0,e).toString(`utf8`))}finally{r.closeSync(s)}a=t.size},l=()=>{if(!o){o=!0;try{c(r.statSync(e.logPath))}catch(t){t.code!==`ENOENT`&&n.stderr(`Runner ${e.id} failed to flush its final log output: ${t.message}`)}r.unwatchFile(e.logPath,c),clearInterval(s),process.off(`SIGINT`,l),t(0)}};process.once(`SIGINT`,l),r.watchFile(e.logPath,{interval:250},c),s=setInterval(()=>{n.registry.get(e.id).then(e=>{e?.state===i&&l()})},250)})}async function x(e,t){return e.backend===a&&e.backendTarget?t.rmuxBackend.stop(e.backendTarget,e.pid):t.launcher.stop(e.pid)}function S(){return[`Usage: doom-runner <command>`,``,`Commands:`,` list [--all]`,` status <id>`,` logs <id> [--lines N] [--follow]`,` stop <id> [--reason <text>]`,` stop-all [--reason <text>]`,` input <id> [--text <text>] [--enter]`].join(`
5
- `)}export{c as runCli};
6
- //# sourceMappingURL=cliApp.mjs.map
1
+ import{runCli as e}from"../commands/cli/cliApp.mjs";export{e as runCli};
@@ -0,0 +1,7 @@
1
+ const e=require("../../types/config.cjs"),t=require("../../services/AnsiScrub/ansiScrub.cjs");require("../../services/AnsiScrub/index.cjs");const n=require("./responseEnvelope.cjs"),r=require("../../schemas/bashTool.cjs"),i=require("../../tui/bashRender.cjs"),a=1e3,o=`Options:`,s={requested:`Started in the background`,threshold:`Still running after the background threshold, so it was moved to the background`,interactive:`Started on a terminal so it can prompt, which means it runs in the background`},c=`Execute bash commands, with long-running ones supervised in the background`;function l(t=e.getBackgroundThresholdMs()){return[`A command still running after ${Math.round(t/a)} seconds remains active as a background runner. You get its unique id and streaming log path, then inspect it with the doom-runner CLI.`,`Pass background: true for commands you already know will not finish on their own (dev servers, watchers, tails). Waiting the full threshold first wastes a turn.`,`Pass interactive: true only when the command will prompt for confirmation or input. Use Runner Space for terminal input. Interactive logs are noisier, so avoid it otherwise.`,`Do not re-run a command to recover output. Read its saved log with doom-runner logs <id>.`,`Stop runners you no longer need. Every runner is stopped automatically when the session ends.`]}function u(e,t){e.registerTool({name:r.BASH_TOOL_NAME,label:r.BASH_TOOL_LABEL,description:`Execute a bash command in the current working directory. A command that outlives the background threshold keeps running under doom-runner and returns a unique id plus a streaming log path. Completed commands return a bounded log tail with exact file metadata. Optionally provide a timeout in seconds, background: true to background it immediately, or interactive: true if it will prompt.`,promptSnippet:c,promptGuidelines:l(),parameters:r.BashParamsSchema,renderShell:`self`,async execute(e,r,i,s,c){let{command:l,timeout:u,background:f,interactive:p,name:m}=r,h;s&&s(n.textResult(`Starting ${p===!0?`interactive runner`:f===!0?`background runner`:`command`}...`)),f!==!0&&p!==!0&&s&&(h=e=>s(n.textResult(e)));let g;try{g=await t.bashRunService.run({command:l,timeoutMs:u===void 0?void 0:u*a,background:f,interactive:p,name:m,...h?{onOutput:h}:{},sessionId:t.getSessionId()})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error([`Could not execute the command: ${t}`,``,o,`- Check the command, runtime, and working directory, then retry once.`,`- Use a read-only diagnostic to confirm the missing dependency or environment value.`,`- Ask the user if recovery requires changing the requested approach.`].join(`
2
+ `),{cause:e})}return g.kind===`promoted`&&t.onRunnerStarted(g.id),d(g)},renderCall(e,t,n){return i.renderBashCall(e,t)},renderResult(e,t,n,r){return i.renderBashResult(e,{...t,isError:r.isError},n)}})}function d(e){if(e.kind===`failed`)throw Error([`Could not start runner "${e.name}": ${e.error}`,``,o,`- Correct the command or missing executable, then retry once.`,`- Use a read-only diagnostic to inspect the runtime environment.`,`- Ask the user if a different execution approach is required.`].join(`
3
+ `));if(e.kind===`promoted`){let t=[`${s[e.reason]} as runner "${e.name}".`,`Runner ID: ${e.id}`,`Backend: ${e.backend}`,`Log (streaming): ${e.logPath}`,`Inspect it with: doom-runner logs ${e.id}`].filter(e=>e.length>0).join(`
4
+ `);return{...n.textResult(t,{id:e.id,runner:e.name,pid:e.pid,logPath:e.logPath,promoted:!0,reason:e.reason})}}let r=n.summarizeLog(e.logPath),i=[];e.timedOut?i.push(`Command stopped: it exceeded the requested timeout.`):e.exitCode===null?e.signal!==null&&i.push(`Terminated by ${e.signal}`):i.push(`Exit: completed with code ${e.exitCode}.`);let a=t.stripAnsi(r.tail),c=[a.length>0?`Log tail (${r.tailLines} lines):\n${a}`:`Log tail: (no output)`,`Runner ID: ${e.id}`,...i,`Log: ${e.logPath}`,`File size: ${n.formatSize(r.bytes)}`,`Lines: ${r.lines.toLocaleString(`en-US`)}`].join(`
5
+ `),l={id:e.id,runner:e.name,exitCode:e.exitCode,logPath:e.logPath,backend:e.backend,fileSize:r.bytes,lines:r.lines,tail:r.tail,tailLines:r.tailLines,...e.timedOut?{timedOut:!0}:{}};if(e.timedOut||e.signal!==null||e.exitCode!==null&&e.exitCode!==0)throw Error([c,``,o,`- Inspect the full log at ${e.logPath}, correct the cause, then retry once.`,`- Run a read-only diagnostic if the output does not explain the failure.`,`- Ask the user if the failure requires changing the requested approach.`].join(`
6
+ `));return n.textResult(c,l)}exports.BASH_PROMPT_SNIPPET=c,exports.bashPromptGuidelines=l,exports.formatRunResult=d,exports.registerBashTool=u;
7
+ //# sourceMappingURL=bashTool.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bashTool.cjs","names":["getBackgroundThresholdMs","BASH_TOOL_NAME","BASH_TOOL_LABEL","BashParamsSchema","textResult","renderBashCall","renderBashResult","summarizeLog","stripAnsi","formatSize"],"sources":["../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/index.ts';\nimport type { BashRunResult, IBashRunService } from '../../services/BashRunService/index.ts';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport { getBackgroundThresholdMs } from '../../types/config.ts';\nimport { formatSize, summarizeLog, type ToolResult, textResult } from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\nconst ERROR_OPTIONS_HEADING = 'Options:';\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold, so it was moved to the background',\n interactive: 'Started on a terminal so it can prompt, which means it runs in the background',\n};\n\nexport const BASH_PROMPT_SNIPPET = 'Execute bash commands, with long-running ones supervised in the background';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner. You get its unique id and streaming log path, then inspect it with the doom-runner CLI.`,\n 'Pass background: true for commands you already know will not finish on their own (dev servers, watchers, tails). Waiting the full threshold first wastes a turn.',\n 'Pass interactive: true only when the command will prompt for confirmation or input. Use Runner Space for terminal input. Interactive logs are noisier, so avoid it otherwise.',\n 'Do not re-run a command to recover output. Read its saved log with doom-runner logs <id>.',\n 'Stop runners you no longer need. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute a bash command in the current working directory. A command that outlives the background threshold keeps running under doom-runner and returns a unique id plus a streaming log path. Completed commands return a bounded log tail with exact file metadata. Optionally provide a timeout in seconds, background: true to background it immediately, or interactive: true if it will prompt.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute the command: ${message}`,\n '',\n ERROR_OPTIONS_HEADING,\n '- Check the command, runtime, and working directory, then retry once.',\n '- Use a read-only diagnostic to confirm the missing dependency or environment value.',\n '- Ask the user if recovery requires changing the requested approach.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result);\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nexport function formatRunResult(result: BashRunResult): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n '',\n ERROR_OPTIONS_HEADING,\n '- Correct the command or missing executable, then retry once.',\n '- Use a read-only diagnostic to inspect the runtime environment.',\n '- Ask the user if a different execution approach is required.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason} as runner \"${result.name}\".`,\n `Runner ID: ${result.id}`,\n `Backend: ${result.backend}`,\n `Log (streaming): ${result.logPath}`,\n `Inspect it with: doom-runner logs ${result.id}`,\n ]\n .filter((line) => line.length > 0)\n .join('\\n');\n\n return {\n ...textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n }),\n };\n }\n\n const log = summarizeLog(result.logPath);\n const notes: string[] = [];\n if (result.timedOut) notes.push('Command stopped: it exceeded the requested timeout.');\n else if (result.exitCode !== null) notes.push(`Exit: completed with code ${result.exitCode}.`);\n else if (result.signal !== null) notes.push(`Terminated by ${result.signal}`);\n\n // The model reads plain text; only the renderer gets the coloured copy below.\n const plainTail = stripAnsi(log.tail);\n const text = [\n plainTail.length > 0 ? `Log tail (${log.tailLines} lines):\\n${plainTail}` : 'Log tail: (no output)',\n `Runner ID: ${result.id}`,\n ...notes,\n `Log: ${result.logPath}`,\n `File size: ${formatSize(log.bytes)}`,\n `Lines: ${log.lines.toLocaleString('en-US')}`,\n ].join('\\n');\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: log.lines,\n // Carried structurally so renderResult shows the output instead of the footer.\n tail: log.tail,\n tailLines: log.tailLines,\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n if (result.timedOut || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0)) {\n throw new Error(\n [\n text,\n '',\n ERROR_OPTIONS_HEADING,\n `- Inspect the full log at ${result.logPath}, correct the cause, then retry once.`,\n '- Run a read-only diagnostic if the output does not explain the failure.',\n '- Ask the user if the failure requires changing the requested approach.',\n ].join('\\n'),\n );\n }\n return textResult(text, details);\n}\n"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { BashRunResult, IBashRunService } from "../../services/BashRunService/types.cjs";
2
+ import "../../services/BashRunService/index.cjs";
3
+ import { ToolResult } from "./responseEnvelope.cjs";
4
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
+ //#region src/commands/bash/bashTool.d.ts
6
+ declare const BASH_PROMPT_SNIPPET = "Execute bash commands, with long-running ones supervised in the background";
7
+ /** Written at registration time so the stated threshold matches the configured one. */
8
+ declare function bashPromptGuidelines(thresholdMs?: number): string[];
9
+ interface BashToolDependencies {
10
+ bashRunService: IBashRunService;
11
+ getSessionId(): string;
12
+ /** Called after a runner is promoted, so UI state can refresh. */
13
+ onRunnerStarted(id: string): void;
14
+ }
15
+ /**
16
+ * Registers a tool named `bash`, replacing pi's built-in.
17
+ *
18
+ * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on
19
+ * `bash`, and they keep working only while the replacement keeps the name.
20
+ */
21
+ declare function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void;
22
+ declare function formatRunResult(result: BashRunResult): ToolResult;
23
+ //#endregion
24
+ export { BASH_PROMPT_SNIPPET, BashToolDependencies, bashPromptGuidelines, formatRunResult, registerBashTool };
25
+ //# sourceMappingURL=bashTool.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bashTool.d.cts","names":[],"sources":["../../../src/commands/bash/bashTool.ts"],"mappings":";;;;;cAiBa;;iBAGG,qBAAqB;UAUpB;EACf,gBAAgB;EAChB;;EAEA,gBAAgB;;;;;;;;iBASF,iBAAiB,IAAI,cAAc,cAAc;iBAmEjD,gBAAgB,QAAQ,gBAAgB"}
@@ -0,0 +1,25 @@
1
+ import { BashRunResult, IBashRunService } from "../../services/BashRunService/types.mjs";
2
+ import "../../services/BashRunService/index.mjs";
3
+ import { ToolResult } from "./responseEnvelope.mjs";
4
+ import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
5
+ //#region src/commands/bash/bashTool.d.ts
6
+ declare const BASH_PROMPT_SNIPPET = "Execute bash commands, with long-running ones supervised in the background";
7
+ /** Written at registration time so the stated threshold matches the configured one. */
8
+ declare function bashPromptGuidelines(thresholdMs?: number): string[];
9
+ interface BashToolDependencies {
10
+ bashRunService: IBashRunService;
11
+ getSessionId(): string;
12
+ /** Called after a runner is promoted, so UI state can refresh. */
13
+ onRunnerStarted(id: string): void;
14
+ }
15
+ /**
16
+ * Registers a tool named `bash`, replacing pi's built-in.
17
+ *
18
+ * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on
19
+ * `bash`, and they keep working only while the replacement keeps the name.
20
+ */
21
+ declare function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void;
22
+ declare function formatRunResult(result: BashRunResult): ToolResult;
23
+ //#endregion
24
+ export { BASH_PROMPT_SNIPPET, BashToolDependencies, bashPromptGuidelines, formatRunResult, registerBashTool };
25
+ //# sourceMappingURL=bashTool.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bashTool.d.mts","names":[],"sources":["../../../src/commands/bash/bashTool.ts"],"mappings":";;;;;cAiBa;;iBAGG,qBAAqB;UAUpB;EACf,gBAAgB;EAChB;;EAEA,gBAAgB;;;;;;;;iBASF,iBAAiB,IAAI,cAAc,cAAc;iBAmEjD,gBAAgB,QAAQ,gBAAgB"}
@@ -0,0 +1,7 @@
1
+ import{getBackgroundThresholdMs as e}from"../../types/config.mjs";import{stripAnsi as t}from"../../services/AnsiScrub/ansiScrub.mjs";import"../../services/AnsiScrub/index.mjs";import{formatSize as n,summarizeLog as r,textResult as i}from"./responseEnvelope.mjs";import{BASH_TOOL_LABEL as a,BASH_TOOL_NAME as o,BashParamsSchema as s}from"../../schemas/bashTool.mjs";import{renderBashCall as c,renderBashResult as l}from"../../tui/bashRender.mjs";const u=1e3,d=`Options:`,f={requested:`Started in the background`,threshold:`Still running after the background threshold, so it was moved to the background`,interactive:`Started on a terminal so it can prompt, which means it runs in the background`},p=`Execute bash commands, with long-running ones supervised in the background`;function m(t=e()){return[`A command still running after ${Math.round(t/u)} seconds remains active as a background runner. You get its unique id and streaming log path, then inspect it with the doom-runner CLI.`,`Pass background: true for commands you already know will not finish on their own (dev servers, watchers, tails). Waiting the full threshold first wastes a turn.`,`Pass interactive: true only when the command will prompt for confirmation or input. Use Runner Space for terminal input. Interactive logs are noisier, so avoid it otherwise.`,`Do not re-run a command to recover output. Read its saved log with doom-runner logs <id>.`,`Stop runners you no longer need. Every runner is stopped automatically when the session ends.`]}function h(e,t){e.registerTool({name:o,label:a,description:`Execute a bash command in the current working directory. A command that outlives the background threshold keeps running under doom-runner and returns a unique id plus a streaming log path. Completed commands return a bounded log tail with exact file metadata. Optionally provide a timeout in seconds, background: true to background it immediately, or interactive: true if it will prompt.`,promptSnippet:p,promptGuidelines:m(),parameters:s,renderShell:`self`,async execute(e,n,r,a,o){let{command:s,timeout:c,background:l,interactive:f,name:p}=n,m;a&&a(i(`Starting ${f===!0?`interactive runner`:l===!0?`background runner`:`command`}...`)),l!==!0&&f!==!0&&a&&(m=e=>a(i(e)));let h;try{h=await t.bashRunService.run({command:s,timeoutMs:c===void 0?void 0:c*u,background:l,interactive:f,name:p,...m?{onOutput:m}:{},sessionId:t.getSessionId()})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error([`Could not execute the command: ${t}`,``,d,`- Check the command, runtime, and working directory, then retry once.`,`- Use a read-only diagnostic to confirm the missing dependency or environment value.`,`- Ask the user if recovery requires changing the requested approach.`].join(`
2
+ `),{cause:e})}return h.kind===`promoted`&&t.onRunnerStarted(h.id),g(h)},renderCall(e,t,n){return c(e,t)},renderResult(e,t,n,r){return l(e,{...t,isError:r.isError},n)}})}function g(e){if(e.kind===`failed`)throw Error([`Could not start runner "${e.name}": ${e.error}`,``,d,`- Correct the command or missing executable, then retry once.`,`- Use a read-only diagnostic to inspect the runtime environment.`,`- Ask the user if a different execution approach is required.`].join(`
3
+ `));if(e.kind===`promoted`){let t=[`${f[e.reason]} as runner "${e.name}".`,`Runner ID: ${e.id}`,`Backend: ${e.backend}`,`Log (streaming): ${e.logPath}`,`Inspect it with: doom-runner logs ${e.id}`].filter(e=>e.length>0).join(`
4
+ `);return{...i(t,{id:e.id,runner:e.name,pid:e.pid,logPath:e.logPath,promoted:!0,reason:e.reason})}}let a=r(e.logPath),o=[];e.timedOut?o.push(`Command stopped: it exceeded the requested timeout.`):e.exitCode===null?e.signal!==null&&o.push(`Terminated by ${e.signal}`):o.push(`Exit: completed with code ${e.exitCode}.`);let s=t(a.tail),c=[s.length>0?`Log tail (${a.tailLines} lines):\n${s}`:`Log tail: (no output)`,`Runner ID: ${e.id}`,...o,`Log: ${e.logPath}`,`File size: ${n(a.bytes)}`,`Lines: ${a.lines.toLocaleString(`en-US`)}`].join(`
5
+ `),l={id:e.id,runner:e.name,exitCode:e.exitCode,logPath:e.logPath,backend:e.backend,fileSize:a.bytes,lines:a.lines,tail:a.tail,tailLines:a.tailLines,...e.timedOut?{timedOut:!0}:{}};if(e.timedOut||e.signal!==null||e.exitCode!==null&&e.exitCode!==0)throw Error([c,``,d,`- Inspect the full log at ${e.logPath}, correct the cause, then retry once.`,`- Run a read-only diagnostic if the output does not explain the failure.`,`- Ask the user if the failure requires changing the requested approach.`].join(`
6
+ `));return i(c,l)}export{p as BASH_PROMPT_SNIPPET,m as bashPromptGuidelines,g as formatRunResult,h as registerBashTool};
7
+ //# sourceMappingURL=bashTool.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bashTool.mjs","names":[],"sources":["../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/index.ts';\nimport type { BashRunResult, IBashRunService } from '../../services/BashRunService/index.ts';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport { getBackgroundThresholdMs } from '../../types/config.ts';\nimport { formatSize, summarizeLog, type ToolResult, textResult } from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\nconst ERROR_OPTIONS_HEADING = 'Options:';\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold, so it was moved to the background',\n interactive: 'Started on a terminal so it can prompt, which means it runs in the background',\n};\n\nexport const BASH_PROMPT_SNIPPET = 'Execute bash commands, with long-running ones supervised in the background';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner. You get its unique id and streaming log path, then inspect it with the doom-runner CLI.`,\n 'Pass background: true for commands you already know will not finish on their own (dev servers, watchers, tails). Waiting the full threshold first wastes a turn.',\n 'Pass interactive: true only when the command will prompt for confirmation or input. Use Runner Space for terminal input. Interactive logs are noisier, so avoid it otherwise.',\n 'Do not re-run a command to recover output. Read its saved log with doom-runner logs <id>.',\n 'Stop runners you no longer need. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute a bash command in the current working directory. A command that outlives the background threshold keeps running under doom-runner and returns a unique id plus a streaming log path. Completed commands return a bounded log tail with exact file metadata. Optionally provide a timeout in seconds, background: true to background it immediately, or interactive: true if it will prompt.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute the command: ${message}`,\n '',\n ERROR_OPTIONS_HEADING,\n '- Check the command, runtime, and working directory, then retry once.',\n '- Use a read-only diagnostic to confirm the missing dependency or environment value.',\n '- Ask the user if recovery requires changing the requested approach.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result);\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nexport function formatRunResult(result: BashRunResult): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n '',\n ERROR_OPTIONS_HEADING,\n '- Correct the command or missing executable, then retry once.',\n '- Use a read-only diagnostic to inspect the runtime environment.',\n '- Ask the user if a different execution approach is required.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason} as runner \"${result.name}\".`,\n `Runner ID: ${result.id}`,\n `Backend: ${result.backend}`,\n `Log (streaming): ${result.logPath}`,\n `Inspect it with: doom-runner logs ${result.id}`,\n ]\n .filter((line) => line.length > 0)\n .join('\\n');\n\n return {\n ...textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n }),\n };\n }\n\n const log = summarizeLog(result.logPath);\n const notes: string[] = [];\n if (result.timedOut) notes.push('Command stopped: it exceeded the requested timeout.');\n else if (result.exitCode !== null) notes.push(`Exit: completed with code ${result.exitCode}.`);\n else if (result.signal !== null) notes.push(`Terminated by ${result.signal}`);\n\n // The model reads plain text; only the renderer gets the coloured copy below.\n const plainTail = stripAnsi(log.tail);\n const text = [\n plainTail.length > 0 ? `Log tail (${log.tailLines} lines):\\n${plainTail}` : 'Log tail: (no output)',\n `Runner ID: ${result.id}`,\n ...notes,\n `Log: ${result.logPath}`,\n `File size: ${formatSize(log.bytes)}`,\n `Lines: ${log.lines.toLocaleString('en-US')}`,\n ].join('\\n');\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: log.lines,\n // Carried structurally so renderResult shows the output instead of the footer.\n tail: log.tail,\n tailLines: log.tailLines,\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n if (result.timedOut || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0)) {\n throw new Error(\n [\n text,\n '',\n ERROR_OPTIONS_HEADING,\n `- Inspect the full log at ${result.logPath}, correct the cause, then retry once.`,\n '- Run a read-only diagnostic if the output does not explain the failure.',\n '- Ask the user if the failure requires changing the requested approach.',\n ].join('\\n'),\n );\n }\n return textResult(text, details);\n}\n"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../types/config.cjs");let n=require("node:fs");n=e.__toESM(n,1);const r=1024,i=r*r;function a(e,t={}){return{content:[{type:`text`,text:e}],details:t}}function o(e){return a(`Error: ${e}`,{error:e})}function s(e){return e<r?`${e} B`:e<i?`${(e/r).toFixed(1)} KB`:`${(e/i).toFixed(1)} MB`}function c(e){return e.toLocaleString(`en-US`)}function l(e){return e.length===0?0:e.endsWith(`
2
+ `)?e.split(`
3
+ `).length-1:e.split(`
4
+ `).length}function u(e,r=200,i=t.getResultMaxBytes()){try{let t=n.default.readFileSync(e,`utf8`),a=l(t),o=t.split(`
5
+ `).slice(-Math.max(1,r)-+!!t.endsWith(`
6
+ `)).join(`
7
+ `),s=Buffer.byteLength(o,`utf8`),c=s>i?Buffer.from(o,`utf8`).subarray(s-i).toString(`utf8`):o,u=s>i?c.indexOf(`
8
+ `):-1,d=u>=0?c.slice(u+1):c;return{tail:d,bytes:n.default.statSync(e).size,lines:a,tailLines:l(d)}}catch{return{tail:``,bytes:0,lines:0,tailLines:0}}}function d(e,n,r=t.getResultMaxBytes()){let i=Buffer.byteLength(e,`utf8`);if(i<=r)return{text:e,truncated:!1,outputLines:l(e)};let a=Buffer.from(e,`utf8`).subarray(i-r).toString(`utf8`),o=a.indexOf(`
9
+ `),s=o===-1?a:a.slice(o+1);return{text:`${s}\n${f(s,n,e,i)}`,truncated:!0,outputLines:l(s)}}function f(e,t,n,r){let i=l(e),a=p(t),o=a?.lines??l(n),u=a?.bytes??r;return[`[output truncated: showing the last ${c(i)} lines.`,`Full output is at ${t} (${s(u)}, ${c(o)} lines).`,`Inspect it with doom-runner logs, or read the file with an offset near line ${c(o)}.]`].join(` `)}function p(e){try{let t=n.default.readFileSync(e,`utf8`);return{bytes:n.default.statSync(e).size,lines:l(t)}}catch{return}}function m(e,t=Date.now()){let n=e.interactive?` interactive`:``;return`${e.name} pid ${e.pid} up ${h(e.startedAt,t)}${n} ${e.command}`}function h(e,t){let n=Date.parse(e);if(Number.isNaN(n))return`unknown`;let r=Math.max(0,Math.floor((t-n)/1e3));if(r<60)return`${r}s`;let i=Math.floor(r/60);if(i<60)return`${i}m`;let a=Math.floor(i/60);return a<24?`${a}h`:`${Math.floor(a/24)}d`}exports.countLines=l,exports.errorResult=o,exports.formatRunnerLine=m,exports.formatSize=s,exports.formatUptime=h,exports.summarizeLog=u,exports.textResult=a,exports.truncateForResult=d;
10
+ //# sourceMappingURL=responseEnvelope.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responseEnvelope.cjs","names":["getResultMaxBytes","fs"],"sources":["../../../src/commands/bash/responseEnvelope.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { RunnerRecord } from '../../services/RunnerRegistry/index.ts';\nimport { getResultMaxBytes } from '../../types/config.ts';\n\nconst BYTES_PER_KB = 1024;\nconst BYTES_PER_MB = BYTES_PER_KB * BYTES_PER_KB;\n\nexport interface ToolResult {\n content: Array<{ type: 'text'; text: string }>;\n details: Record<string, unknown>;\n /** Tools this result makes available from here on in the transcript. */\n addedToolNames?: string[];\n}\n\nexport function textResult(text: string, details: Record<string, unknown> = {}): ToolResult {\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function errorResult(message: string): ToolResult {\n return textResult(`Error: ${message}`, { error: message });\n}\n\n/** Human-readable byte count, matching how pi reports output sizes. */\nexport function formatSize(bytes: number): string {\n if (bytes < BYTES_PER_KB) return `${bytes} B`;\n if (bytes < BYTES_PER_MB) return `${(bytes / BYTES_PER_KB).toFixed(1)} KB`;\n return `${(bytes / BYTES_PER_MB).toFixed(1)} MB`;\n}\n\nfunction formatCount(value: number): string {\n return value.toLocaleString('en-US');\n}\n\nexport function countLines(text: string): number {\n if (text.length === 0) return 0;\n return text.endsWith('\\n') ? text.split('\\n').length - 1 : text.split('\\n').length;\n}\n\nexport interface TruncatedOutput {\n text: string;\n truncated: boolean;\n /** Lines returned, which is what the model actually received. */\n outputLines: number;\n}\n\nexport interface LogSummary {\n tail: string;\n bytes: number;\n lines: number;\n tailLines: number;\n}\n\n/** Reads a bounded tail plus exact metadata after the writer has flushed. */\nexport function summarizeLog(path: string, maxLines = 200, maxBytes = getResultMaxBytes()): LogSummary {\n try {\n const contents = fs.readFileSync(path, 'utf8');\n const lines = countLines(contents);\n const lineTail = contents\n .split('\\n')\n .slice(-Math.max(1, maxLines) - (contents.endsWith('\\n') ? 1 : 0))\n .join('\\n');\n const bytes = Buffer.byteLength(lineTail, 'utf8');\n const byteTail =\n bytes > maxBytes\n ? Buffer.from(lineTail, 'utf8')\n .subarray(bytes - maxBytes)\n .toString('utf8')\n : lineTail;\n const firstNewline = bytes > maxBytes ? byteTail.indexOf('\\n') : -1;\n const tail = firstNewline >= 0 ? byteTail.slice(firstNewline + 1) : byteTail;\n return { tail, bytes: fs.statSync(path).size, lines, tailLines: countLines(tail) };\n } catch {\n return { tail: '', bytes: 0, lines: 0, tailLines: 0 };\n }\n}\n\n/**\n * Keeps the tail of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\nexport function truncateForResult(\n text: string,\n fullOutputPath: string,\n maxBytes = getResultMaxBytes(),\n): TruncatedOutput {\n const totalBytes = Buffer.byteLength(text, 'utf8');\n if (totalBytes <= maxBytes) return { text, truncated: false, outputLines: countLines(text) };\n\n const kept = Buffer.from(text, 'utf8')\n .subarray(totalBytes - maxBytes)\n .toString('utf8');\n // Drop the leading partial line rather than hand back a fragment.\n const newline = kept.indexOf('\\n');\n const tail = newline === -1 ? kept : kept.slice(newline + 1);\n\n return {\n text: `${tail}\\n${truncationNotice(tail, fullOutputPath, text, totalBytes)}`,\n truncated: true,\n outputLines: countLines(tail),\n };\n}\n\nfunction truncationNotice(tail: string, fullOutputPath: string, text: string, totalBytes: number): string {\n const shown = countLines(tail);\n // Counted from the file, never from `text`. What the caller holds in memory\n // is itself capped, so using it here would understate the file by orders of\n // magnitude and send the reader looking past the end of a much longer file.\n const file = measureFile(fullOutputPath);\n const totalLines = file?.lines ?? countLines(text);\n const fileSize = file?.bytes ?? totalBytes;\n\n return [\n `[output truncated: showing the last ${formatCount(shown)} lines.`,\n `Full output is at ${fullOutputPath} (${formatSize(fileSize)}, ${formatCount(totalLines)} lines).`,\n `Inspect it with doom-runner logs, or read the file with an offset near line ${formatCount(totalLines)}.]`,\n ].join(' ');\n}\n\n/** Real size and line count of the file the notice points at. */\nfunction measureFile(path: string): { bytes: number; lines: number } | undefined {\n try {\n const contents = fs.readFileSync(path, 'utf8');\n return { bytes: fs.statSync(path).size, lines: countLines(contents) };\n } catch {\n return undefined;\n }\n}\n\n/** `name pid 1234 up 3m sleep 60` — one runner per line. */\nexport function formatRunnerLine(record: RunnerRecord, now = Date.now()): string {\n const mode = record.interactive ? ' interactive' : '';\n return `${record.name} pid ${record.pid} up ${formatUptime(record.startedAt, now)}${mode} ${record.command}`;\n}\n\nexport function formatUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { RunnerRecord } from "../../services/RunnerRegistry/types.cjs";
2
+ import "../../services/RunnerRegistry/index.cjs";
3
+ //#region src/commands/bash/responseEnvelope.d.ts
4
+ interface ToolResult {
5
+ content: Array<{
6
+ type: 'text';
7
+ text: string;
8
+ }>;
9
+ details: Record<string, unknown>;
10
+ /** Tools this result makes available from here on in the transcript. */
11
+ addedToolNames?: string[];
12
+ }
13
+ declare function textResult(text: string, details?: Record<string, unknown>): ToolResult;
14
+ declare function errorResult(message: string): ToolResult;
15
+ /** Human-readable byte count, matching how pi reports output sizes. */
16
+ declare function formatSize(bytes: number): string;
17
+ declare function countLines(text: string): number;
18
+ interface TruncatedOutput {
19
+ text: string;
20
+ truncated: boolean;
21
+ /** Lines returned, which is what the model actually received. */
22
+ outputLines: number;
23
+ }
24
+ interface LogSummary {
25
+ tail: string;
26
+ bytes: number;
27
+ lines: number;
28
+ tailLines: number;
29
+ }
30
+ /** Reads a bounded tail plus exact metadata after the writer has flushed. */
31
+ declare function summarizeLog(path: string, maxLines?: number, maxBytes?: number): LogSummary;
32
+ /**
33
+ * Keeps the tail of an oversized result and points at the file holding the rest.
34
+ *
35
+ * The notice states the file's real size and line count so the model does not
36
+ * guess at offsets when it goes on to read the file, which is the failure this
37
+ * whole policy exists to prevent.
38
+ */
39
+ declare function truncateForResult(text: string, fullOutputPath: string, maxBytes?: number): TruncatedOutput;
40
+ /** `name pid 1234 up 3m sleep 60` — one runner per line. */
41
+ declare function formatRunnerLine(record: RunnerRecord, now?: number): string;
42
+ declare function formatUptime(startedAt: string, now: number): string;
43
+ //#endregion
44
+ export { LogSummary, ToolResult, TruncatedOutput, countLines, errorResult, formatRunnerLine, formatSize, formatUptime, summarizeLog, textResult, truncateForResult };
45
+ //# sourceMappingURL=responseEnvelope.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responseEnvelope.d.cts","names":[],"sources":["../../../src/commands/bash/responseEnvelope.ts"],"mappings":";;;UAOiB;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;EAET;;iBAGc,WAAW,cAAc,UAAS,0BAA+B;iBAIjE,YAAY,kBAAkB;;iBAK9B,WAAW;iBAUX,WAAW;UAKV;EACf;EACA;;EAEA;;UAGe;EACf;EACA;EACA;EACA;;;iBAIc,aAAa,cAAc,mBAAgB,oBAAiC;;;;;;;;iBA8B5E,kBACd,cACA,wBACA,oBACC;;iBA6Ca,iBAAiB,QAAQ,cAAc;iBAKvC,aAAa,mBAAmB"}
@@ -0,0 +1,45 @@
1
+ import { RunnerRecord } from "../../services/RunnerRegistry/types.mjs";
2
+ import "../../services/RunnerRegistry/index.mjs";
3
+ //#region src/commands/bash/responseEnvelope.d.ts
4
+ interface ToolResult {
5
+ content: Array<{
6
+ type: 'text';
7
+ text: string;
8
+ }>;
9
+ details: Record<string, unknown>;
10
+ /** Tools this result makes available from here on in the transcript. */
11
+ addedToolNames?: string[];
12
+ }
13
+ declare function textResult(text: string, details?: Record<string, unknown>): ToolResult;
14
+ declare function errorResult(message: string): ToolResult;
15
+ /** Human-readable byte count, matching how pi reports output sizes. */
16
+ declare function formatSize(bytes: number): string;
17
+ declare function countLines(text: string): number;
18
+ interface TruncatedOutput {
19
+ text: string;
20
+ truncated: boolean;
21
+ /** Lines returned, which is what the model actually received. */
22
+ outputLines: number;
23
+ }
24
+ interface LogSummary {
25
+ tail: string;
26
+ bytes: number;
27
+ lines: number;
28
+ tailLines: number;
29
+ }
30
+ /** Reads a bounded tail plus exact metadata after the writer has flushed. */
31
+ declare function summarizeLog(path: string, maxLines?: number, maxBytes?: number): LogSummary;
32
+ /**
33
+ * Keeps the tail of an oversized result and points at the file holding the rest.
34
+ *
35
+ * The notice states the file's real size and line count so the model does not
36
+ * guess at offsets when it goes on to read the file, which is the failure this
37
+ * whole policy exists to prevent.
38
+ */
39
+ declare function truncateForResult(text: string, fullOutputPath: string, maxBytes?: number): TruncatedOutput;
40
+ /** `name pid 1234 up 3m sleep 60` — one runner per line. */
41
+ declare function formatRunnerLine(record: RunnerRecord, now?: number): string;
42
+ declare function formatUptime(startedAt: string, now: number): string;
43
+ //#endregion
44
+ export { LogSummary, ToolResult, TruncatedOutput, countLines, errorResult, formatRunnerLine, formatSize, formatUptime, summarizeLog, textResult, truncateForResult };
45
+ //# sourceMappingURL=responseEnvelope.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responseEnvelope.d.mts","names":[],"sources":["../../../src/commands/bash/responseEnvelope.ts"],"mappings":";;;UAOiB;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;EAET;;iBAGc,WAAW,cAAc,UAAS,0BAA+B;iBAIjE,YAAY,kBAAkB;;iBAK9B,WAAW;iBAUX,WAAW;UAKV;EACf;EACA;;EAEA;;UAGe;EACf;EACA;EACA;EACA;;;iBAIc,aAAa,cAAc,mBAAgB,oBAAiC;;;;;;;;iBA8B5E,kBACd,cACA,wBACA,oBACC;;iBA6Ca,iBAAiB,QAAQ,cAAc;iBAKvC,aAAa,mBAAmB"}