charness 3.7.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/DEVELOPMENT.md +6 -2
  3. package/README.md +5 -5
  4. package/SETUP.md +16 -5
  5. package/agent-plugin/skills/charness-manager/SKILL.md +3 -3
  6. package/dist/adapters/openCodeAdapter.d.ts.map +1 -1
  7. package/dist/adapters/openCodeAdapter.js +2 -1
  8. package/dist/adapters/openCodeAdapter.js.map +1 -1
  9. package/dist/bot.d.ts.map +1 -1
  10. package/dist/bot.js +50 -9
  11. package/dist/bot.js.map +1 -1
  12. package/dist/cli.js +44 -1
  13. package/dist/cli.js.map +1 -1
  14. package/dist/configDirFile.d.ts +7 -3
  15. package/dist/configDirFile.d.ts.map +1 -1
  16. package/dist/configDirFile.js +12 -5
  17. package/dist/configDirFile.js.map +1 -1
  18. package/dist/connectors/telegram/commands/botCore.d.ts +5 -1
  19. package/dist/connectors/telegram/commands/botCore.d.ts.map +1 -1
  20. package/dist/connectors/telegram/commands/runners.d.ts +52 -0
  21. package/dist/connectors/telegram/commands/runners.d.ts.map +1 -0
  22. package/dist/connectors/telegram/commands/runners.js +486 -0
  23. package/dist/connectors/telegram/commands/runners.js.map +1 -0
  24. package/dist/connectors/telegram/runnerPairingMessages.d.ts +27 -0
  25. package/dist/connectors/telegram/runnerPairingMessages.d.ts.map +1 -0
  26. package/dist/connectors/telegram/runnerPairingMessages.js +105 -0
  27. package/dist/connectors/telegram/runnerPairingMessages.js.map +1 -0
  28. package/dist/i18n/de.d.ts.map +1 -1
  29. package/dist/i18n/de.js +58 -0
  30. package/dist/i18n/de.js.map +1 -1
  31. package/dist/i18n/en.d.ts.map +1 -1
  32. package/dist/i18n/en.js +58 -0
  33. package/dist/i18n/en.js.map +1 -1
  34. package/dist/i18n/es.d.ts.map +1 -1
  35. package/dist/i18n/es.js +58 -0
  36. package/dist/i18n/es.js.map +1 -1
  37. package/dist/i18n/fr.d.ts.map +1 -1
  38. package/dist/i18n/fr.js +58 -0
  39. package/dist/i18n/fr.js.map +1 -1
  40. package/dist/i18n/hi.d.ts.map +1 -1
  41. package/dist/i18n/hi.js +58 -0
  42. package/dist/i18n/hi.js.map +1 -1
  43. package/dist/i18n/ja.d.ts.map +1 -1
  44. package/dist/i18n/ja.js +58 -0
  45. package/dist/i18n/ja.js.map +1 -1
  46. package/dist/i18n/ka.d.ts.map +1 -1
  47. package/dist/i18n/ka.js +58 -0
  48. package/dist/i18n/ka.js.map +1 -1
  49. package/dist/i18n/pt.d.ts.map +1 -1
  50. package/dist/i18n/pt.js +58 -0
  51. package/dist/i18n/pt.js.map +1 -1
  52. package/dist/i18n/ru.d.ts.map +1 -1
  53. package/dist/i18n/ru.js +58 -0
  54. package/dist/i18n/ru.js.map +1 -1
  55. package/dist/i18n/uk.d.ts.map +1 -1
  56. package/dist/i18n/uk.js +58 -0
  57. package/dist/i18n/uk.js.map +1 -1
  58. package/dist/i18n/uz.d.ts.map +1 -1
  59. package/dist/i18n/uz.js +58 -0
  60. package/dist/i18n/uz.js.map +1 -1
  61. package/dist/i18n/zh.d.ts.map +1 -1
  62. package/dist/i18n/zh.js +58 -0
  63. package/dist/i18n/zh.js.map +1 -1
  64. package/dist/installManager.d.ts +57 -1
  65. package/dist/installManager.d.ts.map +1 -1
  66. package/dist/installManager.js +88 -10
  67. package/dist/installManager.js.map +1 -1
  68. package/dist/instanceSettings.d.ts +12 -2
  69. package/dist/instanceSettings.d.ts.map +1 -1
  70. package/dist/instanceSettings.js +17 -3
  71. package/dist/instanceSettings.js.map +1 -1
  72. package/dist/outputTrace.d.ts +6 -0
  73. package/dist/outputTrace.d.ts.map +1 -1
  74. package/dist/outputTrace.js +24 -1
  75. package/dist/outputTrace.js.map +1 -1
  76. package/dist/remoteRun/cliArgs.d.ts +2 -0
  77. package/dist/remoteRun/cliArgs.d.ts.map +1 -1
  78. package/dist/remoteRun/cliArgs.js +11 -2
  79. package/dist/remoteRun/cliArgs.js.map +1 -1
  80. package/dist/remoteRun/commands.d.ts +21 -0
  81. package/dist/remoteRun/commands.d.ts.map +1 -1
  82. package/dist/remoteRun/commands.js +38 -17
  83. package/dist/remoteRun/commands.js.map +1 -1
  84. package/dist/remoteRun/interrupts.d.ts +10 -0
  85. package/dist/remoteRun/interrupts.d.ts.map +1 -1
  86. package/dist/remoteRun/interrupts.js +43 -6
  87. package/dist/remoteRun/interrupts.js.map +1 -1
  88. package/dist/remoteRun/output.d.ts +2 -0
  89. package/dist/remoteRun/output.d.ts.map +1 -1
  90. package/dist/remoteRun/output.js +45 -0
  91. package/dist/remoteRun/output.js.map +1 -1
  92. package/dist/remoteRun/pairedRunners.d.ts +51 -0
  93. package/dist/remoteRun/pairedRunners.d.ts.map +1 -0
  94. package/dist/remoteRun/pairedRunners.js +165 -0
  95. package/dist/remoteRun/pairedRunners.js.map +1 -0
  96. package/dist/remoteRun/probe.d.ts +23 -1
  97. package/dist/remoteRun/probe.d.ts.map +1 -1
  98. package/dist/remoteRun/probe.js +45 -11
  99. package/dist/remoteRun/probe.js.map +1 -1
  100. package/dist/remoteRun/remoteRunCli.d.ts +13 -6
  101. package/dist/remoteRun/remoteRunCli.d.ts.map +1 -1
  102. package/dist/remoteRun/remoteRunCli.js +34 -59
  103. package/dist/remoteRun/remoteRunCli.js.map +1 -1
  104. package/dist/remoteRun/runnerClient.d.ts +2 -0
  105. package/dist/remoteRun/runnerClient.d.ts.map +1 -1
  106. package/dist/remoteRun/runnerClient.js +5 -1
  107. package/dist/remoteRun/runnerClient.js.map +1 -1
  108. package/dist/remoteRun/runnerSummary.d.ts +24 -0
  109. package/dist/remoteRun/runnerSummary.d.ts.map +1 -0
  110. package/dist/remoteRun/runnerSummary.js +86 -0
  111. package/dist/remoteRun/runnerSummary.js.map +1 -0
  112. package/dist/remoteRun/runnerWait.d.ts +68 -0
  113. package/dist/remoteRun/runnerWait.d.ts.map +1 -0
  114. package/dist/remoteRun/runnerWait.js +137 -0
  115. package/dist/remoteRun/runnerWait.js.map +1 -0
  116. package/dist/remoteRun/runnerWaitTiming.d.ts +16 -0
  117. package/dist/remoteRun/runnerWaitTiming.d.ts.map +1 -0
  118. package/dist/remoteRun/runnerWaitTiming.js +37 -0
  119. package/dist/remoteRun/runnerWaitTiming.js.map +1 -0
  120. package/dist/remoteRun/runners.d.ts +7 -7
  121. package/dist/remoteRun/runners.d.ts.map +1 -1
  122. package/dist/remoteRun/runners.js +45 -17
  123. package/dist/remoteRun/runners.js.map +1 -1
  124. package/dist/remoteRun/runnersCatalog.d.ts +14 -0
  125. package/dist/remoteRun/runnersCatalog.d.ts.map +1 -0
  126. package/dist/remoteRun/runnersCatalog.js +68 -0
  127. package/dist/remoteRun/runnersCatalog.js.map +1 -0
  128. package/dist/remoteRun/runnersConfig.d.ts +29 -20
  129. package/dist/remoteRun/runnersConfig.d.ts.map +1 -1
  130. package/dist/remoteRun/runnersConfig.js +14 -12
  131. package/dist/remoteRun/runnersConfig.js.map +1 -1
  132. package/dist/remoteRun/ssh.d.ts +22 -2
  133. package/dist/remoteRun/ssh.d.ts.map +1 -1
  134. package/dist/remoteRun/ssh.js +41 -7
  135. package/dist/remoteRun/ssh.js.map +1 -1
  136. package/dist/runnerUtility/adminCheck.d.ts +11 -0
  137. package/dist/runnerUtility/adminCheck.d.ts.map +1 -0
  138. package/dist/runnerUtility/adminCheck.js +68 -0
  139. package/dist/runnerUtility/adminCheck.js.map +1 -0
  140. package/dist/runnerUtility/appInstall.d.ts +25 -0
  141. package/dist/runnerUtility/appInstall.d.ts.map +1 -0
  142. package/dist/runnerUtility/appInstall.js +147 -0
  143. package/dist/runnerUtility/appInstall.js.map +1 -0
  144. package/dist/runnerUtility/appUpdate.d.ts +39 -0
  145. package/dist/runnerUtility/appUpdate.d.ts.map +1 -0
  146. package/dist/runnerUtility/appUpdate.js +90 -0
  147. package/dist/runnerUtility/appUpdate.js.map +1 -0
  148. package/dist/runnerUtility/execEnv.d.ts +21 -0
  149. package/dist/runnerUtility/execEnv.d.ts.map +1 -0
  150. package/dist/runnerUtility/execEnv.js +109 -0
  151. package/dist/runnerUtility/execEnv.js.map +1 -0
  152. package/dist/runnerUtility/execSession.d.ts +13 -0
  153. package/dist/runnerUtility/execSession.d.ts.map +1 -0
  154. package/dist/runnerUtility/execSession.js +58 -0
  155. package/dist/runnerUtility/execSession.js.map +1 -0
  156. package/dist/runnerUtility/hubClient.d.ts +30 -0
  157. package/dist/runnerUtility/hubClient.d.ts.map +1 -0
  158. package/dist/runnerUtility/hubClient.js +127 -0
  159. package/dist/runnerUtility/hubClient.js.map +1 -0
  160. package/dist/runnerUtility/injectStream.d.ts +9 -0
  161. package/dist/runnerUtility/injectStream.d.ts.map +1 -0
  162. package/dist/runnerUtility/injectStream.js +12 -0
  163. package/dist/runnerUtility/injectStream.js.map +1 -0
  164. package/dist/runnerUtility/iosCheck.d.ts +62 -0
  165. package/dist/runnerUtility/iosCheck.d.ts.map +1 -0
  166. package/dist/runnerUtility/iosCheck.js +200 -0
  167. package/dist/runnerUtility/iosCheck.js.map +1 -0
  168. package/dist/runnerUtility/launcher.d.ts +5 -0
  169. package/dist/runnerUtility/launcher.d.ts.map +1 -0
  170. package/dist/runnerUtility/launcher.js +85 -0
  171. package/dist/runnerUtility/launcher.js.map +1 -0
  172. package/dist/runnerUtility/linkLoop.d.ts +47 -0
  173. package/dist/runnerUtility/linkLoop.d.ts.map +1 -0
  174. package/dist/runnerUtility/linkLoop.js +281 -0
  175. package/dist/runnerUtility/linkLoop.js.map +1 -0
  176. package/dist/runnerUtility/localLinkStop.d.ts +23 -0
  177. package/dist/runnerUtility/localLinkStop.d.ts.map +1 -0
  178. package/dist/runnerUtility/localLinkStop.js +79 -0
  179. package/dist/runnerUtility/localLinkStop.js.map +1 -0
  180. package/dist/runnerUtility/machineReport.d.ts +39 -0
  181. package/dist/runnerUtility/machineReport.d.ts.map +1 -0
  182. package/dist/runnerUtility/machineReport.js +161 -0
  183. package/dist/runnerUtility/machineReport.js.map +1 -0
  184. package/dist/runnerUtility/packageId.d.ts +5 -0
  185. package/dist/runnerUtility/packageId.d.ts.map +1 -0
  186. package/dist/runnerUtility/packageId.js +64 -0
  187. package/dist/runnerUtility/packageId.js.map +1 -0
  188. package/dist/runnerUtility/pairingRecovery.d.ts +31 -0
  189. package/dist/runnerUtility/pairingRecovery.d.ts.map +1 -0
  190. package/dist/runnerUtility/pairingRecovery.js +24 -0
  191. package/dist/runnerUtility/pairingRecovery.js.map +1 -0
  192. package/dist/runnerUtility/pueueDaemon.d.ts +36 -0
  193. package/dist/runnerUtility/pueueDaemon.d.ts.map +1 -0
  194. package/dist/runnerUtility/pueueDaemon.js +165 -0
  195. package/dist/runnerUtility/pueueDaemon.js.map +1 -0
  196. package/dist/runnerUtility/runnerCli.d.ts +18 -0
  197. package/dist/runnerUtility/runnerCli.d.ts.map +1 -0
  198. package/dist/runnerUtility/runnerCli.js +184 -0
  199. package/dist/runnerUtility/runnerCli.js.map +1 -0
  200. package/dist/runnerUtility/runnerCommands.d.ts +67 -0
  201. package/dist/runnerUtility/runnerCommands.d.ts.map +1 -0
  202. package/dist/runnerUtility/runnerCommands.js +418 -0
  203. package/dist/runnerUtility/runnerCommands.js.map +1 -0
  204. package/dist/runnerUtility/runnerConfig.d.ts +63 -0
  205. package/dist/runnerUtility/runnerConfig.d.ts.map +1 -0
  206. package/dist/runnerUtility/runnerConfig.js +153 -0
  207. package/dist/runnerUtility/runnerConfig.js.map +1 -0
  208. package/dist/runnerUtility/runnerFlags.d.ts +9 -0
  209. package/dist/runnerUtility/runnerFlags.d.ts.map +1 -0
  210. package/dist/runnerUtility/runnerFlags.js +53 -0
  211. package/dist/runnerUtility/runnerFlags.js.map +1 -0
  212. package/dist/runnerUtility/runnerHome.d.ts +30 -0
  213. package/dist/runnerUtility/runnerHome.d.ts.map +1 -0
  214. package/dist/runnerUtility/runnerHome.js +82 -0
  215. package/dist/runnerUtility/runnerHome.js.map +1 -0
  216. package/dist/runnerUtility/runnerKeys.d.ts +11 -0
  217. package/dist/runnerUtility/runnerKeys.d.ts.map +1 -0
  218. package/dist/runnerUtility/runnerKeys.js +80 -0
  219. package/dist/runnerUtility/runnerKeys.js.map +1 -0
  220. package/dist/runnerUtility/runnerServers.d.ts +40 -0
  221. package/dist/runnerUtility/runnerServers.d.ts.map +1 -0
  222. package/dist/runnerUtility/runnerServers.js +79 -0
  223. package/dist/runnerUtility/runnerServers.js.map +1 -0
  224. package/dist/runnerUtility/serviceManager.d.ts +54 -0
  225. package/dist/runnerUtility/serviceManager.d.ts.map +1 -0
  226. package/dist/runnerUtility/serviceManager.js +413 -0
  227. package/dist/runnerUtility/serviceManager.js.map +1 -0
  228. package/dist/runnerUtility/serviceUnits.d.ts +36 -0
  229. package/dist/runnerUtility/serviceUnits.d.ts.map +1 -0
  230. package/dist/runnerUtility/serviceUnits.js +169 -0
  231. package/dist/runnerUtility/serviceUnits.js.map +1 -0
  232. package/dist/runnerUtility/toolInstall.d.ts +95 -0
  233. package/dist/runnerUtility/toolInstall.d.ts.map +1 -0
  234. package/dist/runnerUtility/toolInstall.js +232 -0
  235. package/dist/runnerUtility/toolInstall.js.map +1 -0
  236. package/dist/runnerUtility/versionPollTiming.d.ts +16 -0
  237. package/dist/runnerUtility/versionPollTiming.d.ts.map +1 -0
  238. package/dist/runnerUtility/versionPollTiming.js +36 -0
  239. package/dist/runnerUtility/versionPollTiming.js.map +1 -0
  240. package/dist/runners/authorizedKeys.d.ts +52 -0
  241. package/dist/runners/authorizedKeys.d.ts.map +1 -0
  242. package/dist/runners/authorizedKeys.js +153 -0
  243. package/dist/runners/authorizedKeys.js.map +1 -0
  244. package/dist/runners/bootstrapLine.d.ts +4 -0
  245. package/dist/runners/bootstrapLine.d.ts.map +1 -0
  246. package/dist/runners/bootstrapLine.js +69 -0
  247. package/dist/runners/bootstrapLine.js.map +1 -0
  248. package/dist/runners/gate.d.ts +41 -0
  249. package/dist/runners/gate.d.ts.map +1 -0
  250. package/dist/runners/gate.js +216 -0
  251. package/dist/runners/gate.js.map +1 -0
  252. package/dist/runners/gateLink.d.ts +26 -0
  253. package/dist/runners/gateLink.d.ts.map +1 -0
  254. package/dist/runners/gateLink.js +240 -0
  255. package/dist/runners/gateLink.js.map +1 -0
  256. package/dist/runners/gateProtocol.d.ts +98 -0
  257. package/dist/runners/gateProtocol.d.ts.map +1 -0
  258. package/dist/runners/gateProtocol.js +149 -0
  259. package/dist/runners/gateProtocol.js.map +1 -0
  260. package/dist/runners/gateWrapper.d.ts +6 -0
  261. package/dist/runners/gateWrapper.d.ts.map +1 -0
  262. package/dist/runners/gateWrapper.js +70 -0
  263. package/dist/runners/gateWrapper.js.map +1 -0
  264. package/dist/runners/hubAddress.d.ts +33 -0
  265. package/dist/runners/hubAddress.d.ts.map +1 -0
  266. package/dist/runners/hubAddress.js +88 -0
  267. package/dist/runners/hubAddress.js.map +1 -0
  268. package/dist/runners/hubAddressCandidates.d.ts +16 -0
  269. package/dist/runners/hubAddressCandidates.d.ts.map +1 -0
  270. package/dist/runners/hubAddressCandidates.js +96 -0
  271. package/dist/runners/hubAddressCandidates.js.map +1 -0
  272. package/dist/runners/hubIds.d.ts +16 -0
  273. package/dist/runners/hubIds.d.ts.map +1 -0
  274. package/dist/runners/hubIds.js +25 -0
  275. package/dist/runners/hubIds.js.map +1 -0
  276. package/dist/runners/hubKey.d.ts +6 -0
  277. package/dist/runners/hubKey.d.ts.map +1 -0
  278. package/dist/runners/hubKey.js +78 -0
  279. package/dist/runners/hubKey.js.map +1 -0
  280. package/dist/runners/hubLock.d.ts +7 -0
  281. package/dist/runners/hubLock.d.ts.map +1 -0
  282. package/dist/runners/hubLock.js +230 -0
  283. package/dist/runners/hubLock.js.map +1 -0
  284. package/dist/runners/hubPackage.d.ts +23 -0
  285. package/dist/runners/hubPackage.d.ts.map +1 -0
  286. package/dist/runners/hubPackage.js +184 -0
  287. package/dist/runners/hubPackage.js.map +1 -0
  288. package/dist/runners/hubPairing.d.ts +63 -0
  289. package/dist/runners/hubPairing.d.ts.map +1 -0
  290. package/dist/runners/hubPairing.js +261 -0
  291. package/dist/runners/hubPairing.js.map +1 -0
  292. package/dist/runners/hubPaths.d.ts +38 -0
  293. package/dist/runners/hubPaths.d.ts.map +1 -0
  294. package/dist/runners/hubPaths.js +94 -0
  295. package/dist/runners/hubPaths.js.map +1 -0
  296. package/dist/runners/hubRegistry.d.ts +112 -0
  297. package/dist/runners/hubRegistry.d.ts.map +1 -0
  298. package/dist/runners/hubRegistry.js +210 -0
  299. package/dist/runners/hubRegistry.js.map +1 -0
  300. package/dist/runners/linkControl.d.ts +27 -0
  301. package/dist/runners/linkControl.d.ts.map +1 -0
  302. package/dist/runners/linkControl.js +124 -0
  303. package/dist/runners/linkControl.js.map +1 -0
  304. package/dist/runners/pairCode.d.ts +30 -0
  305. package/dist/runners/pairCode.d.ts.map +1 -0
  306. package/dist/runners/pairCode.js +46 -0
  307. package/dist/runners/pairCode.js.map +1 -0
  308. package/dist/runners/pairingTiming.d.ts +18 -0
  309. package/dist/runners/pairingTiming.d.ts.map +1 -0
  310. package/dist/runners/pairingTiming.js +42 -0
  311. package/dist/runners/pairingTiming.js.map +1 -0
  312. package/dist/runners/runnerProxy.d.ts +9 -0
  313. package/dist/runners/runnerProxy.d.ts.map +1 -0
  314. package/dist/runners/runnerProxy.js +67 -0
  315. package/dist/runners/runnerProxy.js.map +1 -0
  316. package/dist/runners/runnerRemoval.d.ts +21 -0
  317. package/dist/runners/runnerRemoval.d.ts.map +1 -0
  318. package/dist/runners/runnerRemoval.js +82 -0
  319. package/dist/runners/runnerRemoval.js.map +1 -0
  320. package/dist/runners/runnersCli.d.ts +16 -0
  321. package/dist/runners/runnersCli.d.ts.map +1 -0
  322. package/dist/runners/runnersCli.js +214 -0
  323. package/dist/runners/runnersCli.js.map +1 -0
  324. package/dist/runners/runnersList.d.ts +17 -0
  325. package/dist/runners/runnersList.d.ts.map +1 -0
  326. package/dist/runners/runnersList.js +49 -0
  327. package/dist/runners/runnersList.js.map +1 -0
  328. package/dist/runners/runnersOverview.d.ts +20 -0
  329. package/dist/runners/runnersOverview.d.ts.map +1 -0
  330. package/dist/runners/runnersOverview.js +55 -0
  331. package/dist/runners/runnersOverview.js.map +1 -0
  332. package/dist/runners/sshKeys.d.ts +26 -0
  333. package/dist/runners/sshKeys.d.ts.map +1 -0
  334. package/dist/runners/sshKeys.js +60 -0
  335. package/dist/runners/sshKeys.js.map +1 -0
  336. package/dist/runners/tarArchive.d.ts +20 -0
  337. package/dist/runners/tarArchive.d.ts.map +1 -0
  338. package/dist/runners/tarArchive.js +70 -0
  339. package/dist/runners/tarArchive.js.map +1 -0
  340. package/dist/scheduler/mcpSurface.d.ts +11 -5
  341. package/dist/scheduler/mcpSurface.d.ts.map +1 -1
  342. package/dist/scheduler/mcpSurface.js +59 -26
  343. package/dist/scheduler/mcpSurface.js.map +1 -1
  344. package/dist/selfUpdate/selfCheck.js +2 -2
  345. package/dist/selfUpdate/selfCheck.js.map +1 -1
  346. package/dist/testTimings.d.ts +5 -2
  347. package/dist/testTimings.d.ts.map +1 -1
  348. package/dist/testTimings.js +10 -1
  349. package/dist/testTimings.js.map +1 -1
  350. package/dist/utils/agentEnvironment.d.ts +6 -2
  351. package/dist/utils/agentEnvironment.d.ts.map +1 -1
  352. package/dist/utils/agentEnvironment.js +13 -2
  353. package/dist/utils/agentEnvironment.js.map +1 -1
  354. package/dist/utils/runnersScreenPlan.d.ts +130 -0
  355. package/dist/utils/runnersScreenPlan.d.ts.map +1 -0
  356. package/dist/utils/runnersScreenPlan.js +257 -0
  357. package/dist/utils/runnersScreenPlan.js.map +1 -0
  358. package/package.json +5 -2
  359. package/remoteRun/runner.sh +81 -6
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ /**
3
+ * @description Pure plan of the `/runners` screen (`connectors/telegram/commands/runners.ts`): the list of paired machines with
4
+ * what they said about themselves, the buttons, the confirmation of a removal, the address step of the first pairing, the pairing
5
+ * message and the texts that replace it once the code was used or expired. Everything here takes the facts in and gives text and
6
+ * button data out, so the first render and every re-render can never drift apart, and the callback data is checked for Telegram's
7
+ * 64-byte cap in one place.
8
+ *
9
+ * Buttons carry the registry revision AND the runner's position in the WHOLE list (`rnr_<rev>_<i>_<action>`): a keyboard left in the
10
+ * history acts on the list it was drawn from or is refused, never on a neighbour that moved up — whichever page it stands on.
11
+ *
12
+ * The text is BOUNDED: Telegram refuses a message over 4096 characters, and what a machine reports about itself (CPU model, capability
13
+ * details) has no length of its own, so every reported string is clipped and the machines are split over pages of at most
14
+ * {@link maxScreenTextChars}. A page holds at least one machine; a list that fits is one page with no navigation.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.runnerActionCallbackRe = exports.runnersPageCallbackRe = exports.runnersAddressOtherCallback = exports.runnersAddressUseCallback = exports.runnersRefreshCallback = exports.runnersPairCallback = exports.runnersCallbackPrefix = exports.maxReportedTextChars = exports.maxScreenTextChars = exports.maxCallbackDataBytes = void 0;
18
+ exports.buildRunnersPageCallback = buildRunnersPageCallback;
19
+ exports.buildRunnerActionCallback = buildRunnerActionCallback;
20
+ exports.parseRunnersCallback = parseRunnersCallback;
21
+ exports.clipReportedText = clipReportedText;
22
+ exports.paginateBlocks = paginateBlocks;
23
+ exports.buildRunnersScreen = buildRunnersScreen;
24
+ exports.buildRemovalOutcomeText = buildRemovalOutcomeText;
25
+ exports.buildRemoveConfirmation = buildRemoveConfirmation;
26
+ exports.buildAddressStep = buildAddressStep;
27
+ exports.buildPairingMessageParts = buildPairingMessageParts;
28
+ exports.buildPairedText = buildPairedText;
29
+ exports.buildExpiredText = buildExpiredText;
30
+ const probe_1 = require("../remoteRun/probe");
31
+ /** Telegram refuses callback data over 64 BYTES. */
32
+ exports.maxCallbackDataBytes = 64;
33
+ /** The most characters a screen's text may have: Telegram's limit is 4096, the rest is the margin for the title, notes and the page line. */
34
+ exports.maxScreenTextChars = 3600;
35
+ /** The longest a string a machine reported about itself (CPU model, a capability's detail, its OS name) is shown. */
36
+ exports.maxReportedTextChars = 80;
37
+ /** What the page line («Page 2 of 3») and the separators around it may take of the budget. */
38
+ const pageLineReserveChars = 60;
39
+ const sectionSeparator = '\n\n';
40
+ exports.runnersCallbackPrefix = 'rnr_';
41
+ exports.runnersPairCallback = 'rnr_pair';
42
+ exports.runnersRefreshCallback = 'rnr_refresh';
43
+ exports.runnersAddressUseCallback = 'rnr_aduse';
44
+ exports.runnersAddressOtherCallback = 'rnr_adother';
45
+ /** Matches `rnr_pg_<page>` (0-based): a view change that acts on nothing, so it carries no revision. */
46
+ exports.runnersPageCallbackRe = /^rnr_pg_(\d+)$/;
47
+ const actionCodes = { pause: 'p', resume: 'r', remove: 'x', removeYes: 'xy', removeNo: 'xn' };
48
+ /** Matches `rnr_<rev>_<index>_<action code>`. */
49
+ exports.runnerActionCallbackRe = /^rnr_(\d+)_(\d+)_(p|r|x|xy|xn)$/;
50
+ function buildRunnersPageCallback(page) {
51
+ return `${exports.runnersCallbackPrefix}pg_${page}`;
52
+ }
53
+ function buildRunnerActionCallback(revision, index, action) {
54
+ return `${exports.runnersCallbackPrefix}${revision}_${index}_${actionCodes[action]}`;
55
+ }
56
+ /** @description Read a button's callback data; `null` when it is not one of this screen's. */
57
+ function parseRunnersCallback(data) {
58
+ if (data === exports.runnersPairCallback)
59
+ return { kind: 'pair' };
60
+ if (data === exports.runnersRefreshCallback)
61
+ return { kind: 'refresh' };
62
+ if (data === exports.runnersAddressUseCallback)
63
+ return { kind: 'addressUse' };
64
+ if (data === exports.runnersAddressOtherCallback)
65
+ return { kind: 'addressOther' };
66
+ const pageMatch = exports.runnersPageCallbackRe.exec(data);
67
+ if (pageMatch !== null)
68
+ return { kind: 'page', page: Number(pageMatch[1]) };
69
+ const match = exports.runnerActionCallbackRe.exec(data);
70
+ if (match === null)
71
+ return null;
72
+ const action = Object.keys(actionCodes).find((candidate) => actionCodes[candidate] === match[3]);
73
+ return action === undefined ? null : { kind: 'runner', revision: Number(match[1]), index: Number(match[2]), action };
74
+ }
75
+ const serviceKindKeys = {
76
+ foreground: 'runners.serviceForeground',
77
+ 'user-service': 'runners.serviceUserService',
78
+ 'system-service': 'runners.serviceSystemService',
79
+ unknown: 'runners.serviceUnknown',
80
+ };
81
+ /** @description `text` as a string a machine reported: no longer than {@link maxReportedTextChars}, cut with an ellipsis. */
82
+ function clipReportedText(text) {
83
+ return text.length <= exports.maxReportedTextChars ? text : `${text.slice(0, exports.maxReportedTextChars - 1)}…`;
84
+ }
85
+ function describeSystem(entry) {
86
+ const { probe, runner } = entry;
87
+ if (probe === null || probe.osName === '')
88
+ return clipReportedText(`${runner.os} (${runner.arch})`);
89
+ const name = [probe.osName, probe.osVersion].filter((part) => part !== '').join(' ');
90
+ return clipReportedText(probe.arch === '' ? name : `${name} (${probe.arch})`);
91
+ }
92
+ function describeCpu(probe, t, isLive) {
93
+ const model = probe.cpuModel === '' ? 'CPU' : clipReportedText(probe.cpuModel);
94
+ const shape = probe.cpuCores !== null
95
+ ? t('runners.cpuCores', { model, cores: probe.cpuCores })
96
+ : probe.cpuThreads !== null
97
+ ? t('runners.cpuThreads', { model, threads: probe.cpuThreads })
98
+ : model;
99
+ return isLive && probe.load !== null ? `${shape}, ${t('runners.cpuLoad', { load: probe.load })}` : shape;
100
+ }
101
+ function describeCapabilities(probe, t) {
102
+ // What the machine can do first, then what it cannot and why.
103
+ const available = [];
104
+ const unavailable = [];
105
+ for (const name of probe_1.runnerCapabilities) {
106
+ const report = probe.capabilities[name];
107
+ const detail = clipReportedText(report.detail);
108
+ if (report.isAvailable)
109
+ available.push(detail === '' ? name : `${name} (${detail})`);
110
+ else
111
+ unavailable.push(detail === '' ? t('runners.capabilityNo', { name }) : t('runners.capabilityNoWhy', { name, detail }));
112
+ }
113
+ return t('runners.capabilitiesLine', { list: [...available, ...unavailable].join(' · ') });
114
+ }
115
+ function buildEntryBlock(entry, t, formatTime) {
116
+ const { runner, probe } = entry;
117
+ const status = entry.isOnline
118
+ ? t('runners.statusOnline')
119
+ : entry.lastSeenMs === null
120
+ ? t('runners.statusNeverSeen')
121
+ : t('runners.statusOffline', { time: formatTime(entry.lastSeenMs) });
122
+ const heading = [status, ...(runner.isPaused ? [t('runners.pausedMark')] : []), describeSystem(entry), t(serviceKindKeys[runner.serviceKind])].join(' · ');
123
+ const lines = [`${runner.name} — ${heading}`];
124
+ if (probe === null)
125
+ return lines.join('\n');
126
+ if (entry.isOnline) {
127
+ lines.push(` ${t('runners.hardwareLine', { cpu: describeCpu(probe, t, true), ramTotal: (0, probe_1.formatGigabytes)(probe.ramTotalMb), ramFree: (0, probe_1.formatGigabytes)(probe.ramFreeMb), disk: (0, probe_1.formatGigabytes)(probe.diskFreeMb) })}`, ` ${t('runners.jobsLine', { running: probe.jobsRunning, queued: probe.jobsQueued, projects: probe.jobsProjects })}${probe.pueueVersion === null ? ` · ${t('runners.pueueMissing')}` : ''}`, ` ${describeCapabilities(probe, t)}`);
128
+ }
129
+ else {
130
+ lines.push(` ${t('runners.hardwareOldLine', { cpu: describeCpu(probe, t, false), ramTotal: (0, probe_1.formatGigabytes)(probe.ramTotalMb), disk: (0, probe_1.formatGigabytes)(probe.diskFreeMb) })}`);
131
+ }
132
+ return lines.join('\n');
133
+ }
134
+ /**
135
+ * @description Split the entry blocks over pages: each page takes blocks while the text stays within `budget` characters (blocks joined by
136
+ * a blank line), and at least one block, so a block over the budget alone still has a page. Returns each page's first block and the
137
+ * block after its last.
138
+ */
139
+ function paginateBlocks(blocks, budget) {
140
+ const pages = [];
141
+ let start = 0;
142
+ let used = 0;
143
+ blocks.forEach((block, index) => {
144
+ const cost = block.length + (index === start ? 0 : sectionSeparator.length);
145
+ if (index > start && used + cost > budget) {
146
+ pages.push({ start, end: index });
147
+ start = index;
148
+ used = 0;
149
+ }
150
+ used += index === start ? block.length : cost;
151
+ });
152
+ if (blocks.length > 0)
153
+ pages.push({ start, end: blocks.length });
154
+ return pages;
155
+ }
156
+ function buildOpenPairingsSection(expiries, t, formatTime) {
157
+ if (expiries.length === 0)
158
+ return [];
159
+ const lastExpiry = Math.max(...expiries);
160
+ return [expiries.length === 1 ? t('runners.pendingCodeLine', { time: formatTime(lastExpiry) }) : t('runners.pendingCodesLine', { count: expiries.length, time: formatTime(lastExpiry) })];
161
+ }
162
+ /**
163
+ * @description The list screen, page `page` (0-based; a page past the end is the last): the machines on it, a button to pair another, a
164
+ * Pause/Resume and a Remove per machine on the page, the page buttons when there is more than one page, Refresh.
165
+ */
166
+ function buildRunnersScreen(model, t, formatTime, page = 0) {
167
+ const title = t('runners.title');
168
+ const openPairings = buildOpenPairingsSection(model.openPairingExpiries, t, formatTime);
169
+ const checking = model.isChecking ? [t('runners.checkingNote')] : [];
170
+ const blocks = model.entries.map((entry) => buildEntryBlock(entry, t, formatTime));
171
+ const chromeChars = [title, ...openPairings, ...checking].join(sectionSeparator).length + sectionSeparator.length + pageLineReserveChars;
172
+ const pages = paginateBlocks(blocks, exports.maxScreenTextChars - chromeChars);
173
+ const pageCount = Math.max(pages.length, 1);
174
+ const shownPage = Math.min(Math.max(page, 0), pageCount - 1);
175
+ const { start, end } = pages[shownPage] ?? { start: 0, end: 0 };
176
+ const sections = [
177
+ title,
178
+ ...(pageCount > 1 ? [t('runners.pageLine', { page: shownPage + 1, pages: pageCount })] : []),
179
+ ...(model.entries.length === 0 ? [t('runners.emptyText')] : blocks.slice(start, end)),
180
+ ...openPairings,
181
+ ...checking,
182
+ ];
183
+ const rows = [[{ text: t('runners.pairButton'), data: exports.runnersPairCallback }]];
184
+ model.entries.slice(start, end).forEach((entry, offset) => {
185
+ const { name, isPaused } = entry.runner;
186
+ const index = start + offset;
187
+ rows.push([
188
+ isPaused
189
+ ? { text: t('runners.resumeButton', { name }), data: buildRunnerActionCallback(model.revision, index, 'resume') }
190
+ : { text: t('runners.pauseButton', { name }), data: buildRunnerActionCallback(model.revision, index, 'pause') },
191
+ { text: t('runners.removeButton', { name }), data: buildRunnerActionCallback(model.revision, index, 'remove') },
192
+ ]);
193
+ });
194
+ if (pageCount > 1) {
195
+ rows.push([
196
+ ...(shownPage > 0 ? [{ text: t('runners.pagePreviousButton'), data: buildRunnersPageCallback(shownPage - 1) }] : []),
197
+ ...(shownPage < pageCount - 1 ? [{ text: t('runners.pageNextButton'), data: buildRunnersPageCallback(shownPage + 1) }] : []),
198
+ ]);
199
+ }
200
+ rows.push([{ text: t('runners.refreshButton'), data: exports.runnersRefreshCallback }]);
201
+ return { text: sections.join(sectionSeparator), rows, page: shownPage, pageCount };
202
+ }
203
+ /**
204
+ * @description The message that says what a removal came to: the key is deleted in every case, and the jobs were stopped from the hub, or the
205
+ * machine was offline (it stops them itself once it finds out), or they could not be stopped from here (it does the same). Three outcomes,
206
+ * three texts — «offline» is not what «failed» means.
207
+ */
208
+ function buildRemovalOutcomeText(runnerName, jobs, t) {
209
+ const keyByOutcome = {
210
+ stopped: 'runners.removedJobsStoppedText',
211
+ offline: 'runners.removedJobsOfflineText',
212
+ failed: 'runners.removedJobsFailedText',
213
+ };
214
+ return t(keyByOutcome[jobs], { name: runnerName });
215
+ }
216
+ /** @description The question a Remove button turns the screen into. */
217
+ function buildRemoveConfirmation(runnerName, revision, index, t) {
218
+ return {
219
+ text: t('runners.removeConfirmText', { name: runnerName }),
220
+ rows: [[
221
+ { text: t('runners.removeConfirmButton'), data: buildRunnerActionCallback(revision, index, 'removeYes') },
222
+ { text: t('runners.removeCancelButton'), data: buildRunnerActionCallback(revision, index, 'removeNo') },
223
+ ]],
224
+ };
225
+ }
226
+ /**
227
+ * @description The address step of the first pairing. With a proposal (an address of this machine that answered with its own
228
+ * sshd) it offers «Use …» and «Enter another address»; without one only the second, and says no address was found.
229
+ */
230
+ function buildAddressStep(proposedAddress, t) {
231
+ if (proposedAddress === null) {
232
+ return {
233
+ text: `${t('runners.addressIntro')}\n\n${t('runners.addressNotFound')}`,
234
+ rows: [[{ text: t('runners.addressOtherButton'), data: exports.runnersAddressOtherCallback }]],
235
+ };
236
+ }
237
+ return {
238
+ text: `${t('runners.addressIntro')}\n\n${t('runners.addressFound', { address: proposedAddress })}`,
239
+ rows: [[
240
+ { text: t('runners.addressUseButton', { address: proposedAddress }), data: exports.runnersAddressUseCallback },
241
+ { text: t('runners.addressOtherButton'), data: exports.runnersAddressOtherCallback },
242
+ ]],
243
+ };
244
+ }
245
+ /** @description The pairing message's text parts: what stands above the line and below it. The line itself sits between them. */
246
+ function buildPairingMessageParts(pairingLifetimeMinutes, t) {
247
+ return { intro: t('runners.pairingIntro', { minutes: pairingLifetimeMinutes }), outro: t('runners.pairingOutro') };
248
+ }
249
+ /** @description What the pairing message becomes once the code was used. */
250
+ function buildPairedText(runnerName, pairedAtMs, t, formatTime) {
251
+ return t('runners.pairedText', { name: runnerName, time: formatTime(pairedAtMs) });
252
+ }
253
+ /** @description What the pairing message becomes once the code expired unused. */
254
+ function buildExpiredText(t) {
255
+ return t('runners.expiredText');
256
+ }
257
+ //# sourceMappingURL=runnersScreenPlan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runnersScreenPlan.js","sourceRoot":"","sources":["../../src/utils/runnersScreenPlan.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "charness",
3
- "version": "3.7.0",
3
+ "version": "3.8.0",
4
4
  "license": "MIT",
5
5
  "author": "Sergei Solo",
6
6
  "description": "Harness for running Claude Code / OpenCode agents in the cloud or on your laptop, controlled from Telegram or Jira.",
@@ -54,6 +54,7 @@
54
54
  "main": "dist/cli.js",
55
55
  "bin": {
56
56
  "charness": "dist/cli.js",
57
+ "charness-runner": "dist/runnerUtility/runnerCli.js",
57
58
  "telegramCode": "dist/cli.js",
58
59
  "telegramcode": "dist/cli.js"
59
60
  },
@@ -61,7 +62,7 @@
61
62
  "node": ">=22.12"
62
63
  },
63
64
  "scripts": {
64
- "build": "tsc && chmod +x dist/cli.js dist/index.js",
65
+ "build": "tsc && chmod +x dist/cli.js dist/index.js dist/runnerUtility/runnerCli.js",
65
66
  "build:watch": "tsc -w",
66
67
  "start": "node dist/cli.js",
67
68
  "dev": "tsx watch src/cli.ts",
@@ -84,11 +85,13 @@
84
85
  "form-data": "^4.0.5",
85
86
  "marklassian": "^1.2.1",
86
87
  "node-pty": "^1.0.0",
88
+ "ssh2": "^1.17.0",
87
89
  "telegraf": "^4.16.3",
88
90
  "zod": "^4.4.3"
89
91
  },
90
92
  "devDependencies": {
91
93
  "@types/node": "^22.10.0",
94
+ "@types/ssh2": "^1",
92
95
  "nodemon": "^3.1.0",
93
96
  "playwright-core": "1.59.1",
94
97
  "tsx": "^4.21.0",
@@ -5,11 +5,18 @@
5
5
  # the runner's work dir first: runner.sh <subcommand> <workDir> [arguments…]
6
6
  # Pueue is reached through PUEUE_BIN / PUEUE_CONFIG (both optional), set by the caller on every call.
7
7
  #
8
+ # A PAIRED runner (`charness-runner`, src/runnerUtility) keeps its work dir as <state>/work in its own state folder; `probe` reads three
9
+ # files there and reports them — nothing else in this script knows about pairing. A hand-made runner has none of them:
10
+ # <state>/paused exists → paused=yes (written by `charness-runner pause`; the main box never sends a job to a paused runner)
11
+ # <state>/service one word: user-service | system-service (no file = run by hand: service=foreground)
12
+ # <state>/ios-check.json the runner's iOS Simulator boot check (one JSON line): "status": "pass"|"fail"|"skipped" and "reason": "…"|null
13
+ # <state> counts only when it holds config.json and keys/ (a work dir that merely is called «work» is not one).
14
+ #
8
15
  # bash 3.2-compatible on purpose (the stock bash of macOS): no associative arrays, no `wait -n`, no `mapfile`, no
9
16
  # `timeout(1)`, no `read -t` (its timeout status differs between 3.2 and 4+), no GNU-only flags. Time limits are done by background watchdogs.
10
17
  #
11
18
  # Subcommands (the contract is in src/remoteRun/README.md):
12
- # probe key=value lines: OS, CPU, RAM, disk, jobs, capabilities
19
+ # probe key=value lines: OS, CPU, RAM, disk, jobs, capabilities (paused / service / iOS boot check of a paired runner)
13
20
  # prepare layout for a job, Pueue daemon + groups, prune
14
21
  # lease add the job to Pueue, stream its log, kill it when the caller's heartbeat stops (foreground run)
15
22
  # submit add the job to Pueue and return (--bg)
@@ -123,6 +130,14 @@ read_file() {
123
130
  cat "$1" 2>/dev/null
124
131
  }
125
132
 
133
+ # A Mac that idle-sleeps in the middle of a job drops the link and stalls the build: while the process $1 runs, `caffeinate -i -w` holds
134
+ # the idle-sleep assertion and ends by itself with it. A sibling, not a wrapper: the command keeps its own signals and exit status.
135
+ # Nothing on other systems, or where caffeinate is missing.
136
+ keep_awake_while() {
137
+ [ "$(uname -s)" = Darwin ] && command -v caffeinate > /dev/null 2>&1 || return 0
138
+ caffeinate -i -w "$1" > /dev/null 2>&1 < /dev/null &
139
+ }
140
+
126
141
  # ─────────────────────────── probe ───────────────────────────
127
142
 
128
143
  kb_to_mb() {
@@ -305,12 +320,29 @@ probe_slow() {
305
320
  elif [ "$(probe_step_status xcode)" = 0 ]; then
306
321
  local xcode_version
307
322
  xcode_version=$(probe_step_output xcode | head -n 1 | sed 's/^Xcode //')
308
- echo "cap_ios=yes"
309
- if [ "$(probe_step_status simctl)" = 0 ]; then
310
- echo "cap_ios_detail=Xcode $xcode_version, $(probe_step_output simctl | grep -c '(Shutdown)\|(Booted)') simulators"
323
+ if [ "${ios_boot_status:-}" = failed ]; then
324
+ # Xcode is there, but the runner's own check failed. The Simulator refusing to boot is Apple's rule (none is available outside a login
325
+ # session); any other reason (no runtime installed, the device could not be created) is shown as it is — the login session would be a
326
+ # wrong cure. «the Simulator did not» is `iosBootFailureReasonPrefix` in runnerUtility/iosCheck.ts.
327
+ echo "cap_ios=no"
328
+ case "$ios_boot_detail" in
329
+ "the Simulator did not"*) echo "cap_ios_detail=needs the runner user's login session" ;;
330
+ ?*) echo "cap_ios_detail=the iOS Simulator check failed: $ios_boot_detail" ;;
331
+ *) echo "cap_ios_detail=the iOS Simulator check failed" ;;
332
+ esac
333
+ elif [ -n "$runner_state" ] && [ -z "$ios_boot_status" ]; then
334
+ # A paired runner writes its record every time its link starts: none yet means the check of THIS start is still running, and an
335
+ # answer from an earlier start (another account, another kind of service) must not be offered meanwhile.
336
+ echo "cap_ios=no"
337
+ echo "cap_ios_detail=the iOS Simulator is being checked"
311
338
  else
312
- # A slow simctl is no reason to say there is no Xcode, nor to invent a simulator count.
313
- echo "cap_ios_detail=Xcode $xcode_version"
339
+ echo "cap_ios=yes"
340
+ if [ "$(probe_step_status simctl)" = 0 ]; then
341
+ echo "cap_ios_detail=Xcode $xcode_version, $(probe_step_output simctl | grep -c '(Shutdown)\|(Booted)') simulators"
342
+ else
343
+ # A slow simctl is no reason to say there is no Xcode, nor to invent a simulator count.
344
+ echo "cap_ios_detail=Xcode $xcode_version"
345
+ fi
314
346
  fi
315
347
  else
316
348
  echo "cap_ios=no"
@@ -333,9 +365,49 @@ probe_slow() {
333
365
  rm -rf "$probe_dir"
334
366
  }
335
367
 
368
+ # The state folder of the charness-runner this work dir belongs to (sets runner_state; empty for a hand-made runner), and what it says
369
+ # about the machine: sets ios_boot_status (ok | failed | unchecked, empty off a Mac or without a check) and ios_boot_detail.
370
+ read_runner_state() {
371
+ runner_state=
372
+ ios_boot_status=
373
+ ios_boot_detail=
374
+ local candidate
375
+ candidate=$(dirname "$work")
376
+ [ "$(basename "$work")" = work ] && [ -f "$candidate/config.json" ] && [ -d "$candidate/keys" ] || return 0
377
+ runner_state=$candidate
378
+ local check="$runner_state/ios-check.json"
379
+ [ -f "$check" ] || return 0
380
+ if grep -q '"status"[[:space:]]*:[[:space:]]*"pass"' "$check"; then
381
+ ios_boot_status=ok
382
+ elif grep -q '"status"[[:space:]]*:[[:space:]]*"fail"' "$check"; then
383
+ ios_boot_status=failed
384
+ else
385
+ ios_boot_status=unchecked
386
+ fi
387
+ ios_boot_detail=$(sed -n 's/.*"reason"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$check" | head -n 1)
388
+ }
389
+
390
+ # paused= / service= / runner_version= / ios_boot= of a paired runner (nothing for a hand-made one).
391
+ probe_runner_state() {
392
+ [ -n "$runner_state" ] || return 0
393
+ if [ -f "$runner_state/paused" ]; then echo "paused=yes"; else echo "paused=no"; fi
394
+ local service
395
+ service=$(head -n 1 "$runner_state/service" 2> /dev/null)
396
+ case $service in
397
+ user-service | system-service) echo "service=$service" ;;
398
+ '') echo "service=foreground" ;;
399
+ *) echo "service=unknown" ;;
400
+ esac
401
+ echo "runner_version=$(sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$runner_state/current/package.json" 2> /dev/null | head -n 1)"
402
+ [ -n "$ios_boot_status" ] && echo "ios_boot=$ios_boot_status"
403
+ [ -n "$ios_boot_detail" ] && echo "ios_boot_detail=$ios_boot_detail"
404
+ return 0
405
+ }
406
+
336
407
  cmd_probe() {
337
408
  work=$1
338
409
  mkdir -p "$work" 2> /dev/null
410
+ read_runner_state
339
411
  echo "os=$(uname -s)"
340
412
  echo "arch=$(uname -m)"
341
413
  echo "kernel=$(uname -r)"
@@ -347,6 +419,7 @@ cmd_probe() {
347
419
  probe_jobs
348
420
  probe_android
349
421
  probe_playwright
422
+ probe_runner_state
350
423
  }
351
424
 
352
425
  # ─────────────────────────── pueue ───────────────────────────
@@ -962,6 +1035,7 @@ run_step() {
962
1035
  exec bash -c "$command_text"
963
1036
  ) < /dev/null &
964
1037
  local step_pid=$!
1038
+ keep_awake_while "$step_pid"
965
1039
  # The notices bash prints when it reaps a signalled child ("Terminated") are not the job's output.
966
1040
  { wait "$step_pid"; } 2> /dev/null
967
1041
  step_code=$?
@@ -1155,6 +1229,7 @@ cmd_exec() {
1155
1229
  set -m
1156
1230
  ( cd "$tree/$subfolder" && exec bash -c "$*" ) < /dev/null &
1157
1231
  local exec_pid=$!
1232
+ keep_awake_while "$exec_pid"
1158
1233
  set +m
1159
1234
  (
1160
1235
  if ! watch_lease "$lease_sec"; then