svamp-cli 0.1.51 → 0.1.52

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 (314) hide show
  1. package/dist/cli.mjs +18 -18
  2. package/dist/{commands-mw8HFkt6.mjs → commands-1tmye7o_.mjs} +3 -2
  3. package/dist/{commands-D1brd9fB.mjs → commands-CI_BVphs.mjs} +7 -3
  4. package/dist/{commands-DHnFOhQC.mjs → commands-DcFOU9nW.mjs} +7 -3
  5. package/dist/commands-DwY2B7KW.mjs +562 -0
  6. package/dist/index.mjs +1 -1
  7. package/dist/{package-BLDik3NY.mjs → package-D7EUXtnk.mjs} +1 -1
  8. package/dist/{run-6dwQnoBL.mjs → run-BYJX5syg.mjs} +1 -1
  9. package/dist/{run-C0ecvcRP.mjs → run-BnnUavlu.mjs} +131 -44
  10. package/dist/{run-3Et1ISd5.mjs → run-Bw6aGHLA.mjs} +1 -1
  11. package/dist/{run-BE_AIJ7z.mjs → run-DOwarObi.mjs} +1 -1
  12. package/dist/{run-Bc83CRUn.mjs → run-DxISzP_V.mjs} +38 -7
  13. package/dist/{run-BdEHYoYE.mjs → run-eYBOEaWw.mjs} +20 -7
  14. package/dist/tunnel-C2_V6y3d.mjs +299 -0
  15. package/package.json +1 -1
  16. package/dist/commands-4_MiOQVp.mjs +0 -1217
  17. package/dist/commands-8UAWGJrC.mjs +0 -1208
  18. package/dist/commands-8Wmq0uak.mjs +0 -1407
  19. package/dist/commands-8Xn02pQg.mjs +0 -1217
  20. package/dist/commands-9DPsh6ku.mjs +0 -1217
  21. package/dist/commands-9rMB13FP.mjs +0 -1214
  22. package/dist/commands-B-XaqFDB.mjs +0 -1407
  23. package/dist/commands-B53zuBHB.mjs +0 -1217
  24. package/dist/commands-B7yLt11i.mjs +0 -1217
  25. package/dist/commands-BDVAO_N2.mjs +0 -1217
  26. package/dist/commands-BD_NjWJL.mjs +0 -1217
  27. package/dist/commands-BEhSQqTp.mjs +0 -507
  28. package/dist/commands-BIFQZZGw.mjs +0 -1375
  29. package/dist/commands-BImRR1Wr.mjs +0 -1217
  30. package/dist/commands-BLmRIMdf.mjs +0 -1217
  31. package/dist/commands-BOYo9cdy.mjs +0 -1741
  32. package/dist/commands-BQ_347V_.mjs +0 -1374
  33. package/dist/commands-BTEmyf2m.mjs +0 -1407
  34. package/dist/commands-BVjcCbWS.mjs +0 -1375
  35. package/dist/commands-BVsLRttq.mjs +0 -1217
  36. package/dist/commands-BVuE0VQU.mjs +0 -507
  37. package/dist/commands-BY09VTpk.mjs +0 -1375
  38. package/dist/commands-Bcdp0X-o.mjs +0 -1217
  39. package/dist/commands-BdnG1cqQ.mjs +0 -1217
  40. package/dist/commands-BdvvRQIo.mjs +0 -1415
  41. package/dist/commands-Bgg_dvDw.mjs +0 -1683
  42. package/dist/commands-Bi0zYJvj.mjs +0 -1407
  43. package/dist/commands-BmirUCVt.mjs +0 -1208
  44. package/dist/commands-BpSUbvmr.mjs +0 -1217
  45. package/dist/commands-BuJ6xTfc.mjs +0 -1217
  46. package/dist/commands-BzbYPx0f.mjs +0 -1208
  47. package/dist/commands-C-RtFjJl.mjs +0 -1217
  48. package/dist/commands-C20_f6oo.mjs +0 -1217
  49. package/dist/commands-C6KDr9Yp.mjs +0 -1407
  50. package/dist/commands-C9TOoTCv.mjs +0 -1395
  51. package/dist/commands-C9TdN_El.mjs +0 -1683
  52. package/dist/commands-CFv6lO0D.mjs +0 -1217
  53. package/dist/commands-CJ2n5jS2.mjs +0 -1375
  54. package/dist/commands-CKEKQ_5B.mjs +0 -1217
  55. package/dist/commands-CQz67Rm1.mjs +0 -1395
  56. package/dist/commands-CRZbJjqN.mjs +0 -1375
  57. package/dist/commands-CToIvBFX.mjs +0 -1375
  58. package/dist/commands-CWsfciHn.mjs +0 -1217
  59. package/dist/commands-CYMSyqYC.mjs +0 -1395
  60. package/dist/commands-CZ7KPLLJ.mjs +0 -1217
  61. package/dist/commands-Cc73uUnP.mjs +0 -1375
  62. package/dist/commands-CdMsAD1-.mjs +0 -1217
  63. package/dist/commands-CdyCWC3y.mjs +0 -1395
  64. package/dist/commands-ClVCprrK.mjs +0 -1217
  65. package/dist/commands-Cnmf8znA.mjs +0 -1196
  66. package/dist/commands-CorUNLRF.mjs +0 -1375
  67. package/dist/commands-Cq0oj5_v.mjs +0 -1217
  68. package/dist/commands-CrdvbXPI.mjs +0 -1395
  69. package/dist/commands-Cw2Od6mc.mjs +0 -1683
  70. package/dist/commands-CwC2aVzu.mjs +0 -1217
  71. package/dist/commands-CxSCUJCB.mjs +0 -1217
  72. package/dist/commands-D-PTwdZz.mjs +0 -1217
  73. package/dist/commands-D-nIO_Sf.mjs +0 -1741
  74. package/dist/commands-D7-NHH5q.mjs +0 -1407
  75. package/dist/commands-D7kH-7Vn.mjs +0 -1217
  76. package/dist/commands-DBv6A3aJ.mjs +0 -507
  77. package/dist/commands-DD3HXakm.mjs +0 -1217
  78. package/dist/commands-DLoe6FyK.mjs +0 -1375
  79. package/dist/commands-DPbH8KF0.mjs +0 -1217
  80. package/dist/commands-DUAQ9MZM.mjs +0 -1217
  81. package/dist/commands-DVw-P6-0.mjs +0 -1407
  82. package/dist/commands-DVygnMsh.mjs +0 -1217
  83. package/dist/commands-DWira-Cz.mjs +0 -1741
  84. package/dist/commands-DYTdUlul.mjs +0 -1217
  85. package/dist/commands-DZfaDmsk.mjs +0 -1374
  86. package/dist/commands-Dd8cn8mW.mjs +0 -1217
  87. package/dist/commands-DsIoygTL.mjs +0 -1395
  88. package/dist/commands-Du-fdLLu.mjs +0 -969
  89. package/dist/commands-DuJGOq1y.mjs +0 -1217
  90. package/dist/commands-DwBr3sBn.mjs +0 -1217
  91. package/dist/commands-DwveR96q.mjs +0 -1683
  92. package/dist/commands-DypTF36z.mjs +0 -506
  93. package/dist/commands-EUMJqBCs.mjs +0 -1407
  94. package/dist/commands-HLu7P96l.mjs +0 -1214
  95. package/dist/commands-HrBaGV-C.mjs +0 -1683
  96. package/dist/commands-Jk5no-DX.mjs +0 -1407
  97. package/dist/commands-KH5dj9dv.mjs +0 -1214
  98. package/dist/commands-LaNHVHjc.mjs +0 -1217
  99. package/dist/commands-O1Q9g00y.mjs +0 -1395
  100. package/dist/commands-OwMfbBrU.mjs +0 -1395
  101. package/dist/commands-SQ0Wp_kD.mjs +0 -1217
  102. package/dist/commands-S_MFQ9n1.mjs +0 -354
  103. package/dist/commands-T3q8VKCY.mjs +0 -1407
  104. package/dist/commands-Ugz9TtRu.mjs +0 -1420
  105. package/dist/commands-Wng0OuNY.mjs +0 -1683
  106. package/dist/commands-YBW5jFpy.mjs +0 -1217
  107. package/dist/commands-Z-CbuF8E.mjs +0 -1217
  108. package/dist/commands-fSZOP80Z.mjs +0 -1217
  109. package/dist/commands-fqBuJe1b.mjs +0 -1217
  110. package/dist/commands-g-1n3_Rp.mjs +0 -1395
  111. package/dist/commands-mC0oe0lj.mjs +0 -1217
  112. package/dist/commands-od2hOku5.mjs +0 -1217
  113. package/dist/commands-otgzprjb.mjs +0 -1375
  114. package/dist/commands-rhHI6Wb2.mjs +0 -1420
  115. package/dist/commands-zGHnUXh5.mjs +0 -1217
  116. package/dist/package-BMCjXPI9.mjs +0 -58
  117. package/dist/package-BPMWPlS0.mjs +0 -57
  118. package/dist/package-BYUO-39f.mjs +0 -60
  119. package/dist/package-BaGfG8vL.mjs +0 -58
  120. package/dist/package-BkBE6ZdN.mjs +0 -57
  121. package/dist/package-BufekbY1.mjs +0 -57
  122. package/dist/package-C1hpYMj4.mjs +0 -57
  123. package/dist/package-CmIBOZtY.mjs +0 -57
  124. package/dist/package-CmVt1kdw.mjs +0 -58
  125. package/dist/package-Cn6Ya4A0.mjs +0 -57
  126. package/dist/package-Csd530Ym.mjs +0 -57
  127. package/dist/package-D6mNQtUs.mjs +0 -57
  128. package/dist/package-DG0AkZdm.mjs +0 -58
  129. package/dist/package-DRO1LpXW.mjs +0 -58
  130. package/dist/package-Dav8qh6X.mjs +0 -57
  131. package/dist/package-DiA55dzE.mjs +0 -57
  132. package/dist/package-UwLIU765.mjs +0 -58
  133. package/dist/package-k3XsdP9k.mjs +0 -58
  134. package/dist/package-rasGC9_z.mjs +0 -58
  135. package/dist/run-4B1XZQB8.mjs +0 -5426
  136. package/dist/run-4eArMb_9.mjs +0 -1050
  137. package/dist/run-4li60ojK.mjs +0 -1051
  138. package/dist/run-67wfoMuo.mjs +0 -5383
  139. package/dist/run-6N2IdEX7.mjs +0 -5410
  140. package/dist/run-7iQKryzo.mjs +0 -5383
  141. package/dist/run-7s8lOXqB.mjs +0 -1050
  142. package/dist/run-8kKykzTs.mjs +0 -5367
  143. package/dist/run-8mLZV2lg.mjs +0 -1050
  144. package/dist/run-9x7I9Ck-.mjs +0 -5264
  145. package/dist/run-B-PWtXF-.mjs +0 -5894
  146. package/dist/run-B1ivovUl.mjs +0 -5964
  147. package/dist/run-B1l9Ed8k.mjs +0 -5403
  148. package/dist/run-B2zRMxE0.mjs +0 -5508
  149. package/dist/run-B31biy0V.mjs +0 -1050
  150. package/dist/run-B5o5fMMd.mjs +0 -5369
  151. package/dist/run-B7V-xXM7.mjs +0 -5775
  152. package/dist/run-B9ND6srh.mjs +0 -6154
  153. package/dist/run-BG3279Kg.mjs +0 -1051
  154. package/dist/run-BHZNzX1F.mjs +0 -5235
  155. package/dist/run-BKdOv7gX.mjs +0 -1050
  156. package/dist/run-BLySdZ1K.mjs +0 -5251
  157. package/dist/run-BOVkQfM-.mjs +0 -1050
  158. package/dist/run-BQ0lIare.mjs +0 -1050
  159. package/dist/run-BREPr7Yc.mjs +0 -5508
  160. package/dist/run-BTwshVk1.mjs +0 -5728
  161. package/dist/run-BUL3eAqT.mjs +0 -1050
  162. package/dist/run-BVcPemGr.mjs +0 -5947
  163. package/dist/run-BWqEmIiz.mjs +0 -5964
  164. package/dist/run-BWsDPiNe.mjs +0 -1050
  165. package/dist/run-BX4iy6k8.mjs +0 -1050
  166. package/dist/run-BXYfq8mK.mjs +0 -5836
  167. package/dist/run-BY12Ataq.mjs +0 -5732
  168. package/dist/run-BYDOX4yk.mjs +0 -5402
  169. package/dist/run-Bd-t6s63.mjs +0 -5373
  170. package/dist/run-BenYqfwQ.mjs +0 -5273
  171. package/dist/run-BfF4bgA3.mjs +0 -5403
  172. package/dist/run-Bhh05yic.mjs +0 -5369
  173. package/dist/run-BicITYWX.mjs +0 -6138
  174. package/dist/run-BieEN0Pg.mjs +0 -5761
  175. package/dist/run-BjEQi6PN.mjs +0 -1050
  176. package/dist/run-BjZ6SyFy.mjs +0 -1051
  177. package/dist/run-Bl8OkKyC.mjs +0 -5969
  178. package/dist/run-BlEFlhfn.mjs +0 -5510
  179. package/dist/run-BmL1m0Bk.mjs +0 -1050
  180. package/dist/run-Bmx5wEBF.mjs +0 -1051
  181. package/dist/run-BnX5Rw8x.mjs +0 -5403
  182. package/dist/run-BpjmHeht.mjs +0 -1050
  183. package/dist/run-BxTdRjCG.mjs +0 -1051
  184. package/dist/run-ByOVDgvx.mjs +0 -6115
  185. package/dist/run-BzRP6Q5t.mjs +0 -1051
  186. package/dist/run-C0dyMP62.mjs +0 -1051
  187. package/dist/run-C1lS3SwN.mjs +0 -5733
  188. package/dist/run-C3PAp02X.mjs +0 -5252
  189. package/dist/run-C3eaYQub.mjs +0 -1050
  190. package/dist/run-C4pdX4sY.mjs +0 -1051
  191. package/dist/run-C676pHe-.mjs +0 -5423
  192. package/dist/run-C8GkzcfP.mjs +0 -1050
  193. package/dist/run-C9Hrqjy_.mjs +0 -1050
  194. package/dist/run-CC2C8P-U.mjs +0 -6031
  195. package/dist/run-CCcW4asS.mjs +0 -1050
  196. package/dist/run-CDBKhQ1Z.mjs +0 -1051
  197. package/dist/run-CE4H8ZiN.mjs +0 -6273
  198. package/dist/run-CEB6sYzn.mjs +0 -5962
  199. package/dist/run-CF6aXLmA.mjs +0 -5445
  200. package/dist/run-CHyN5U0t.mjs +0 -1050
  201. package/dist/run-CIFezmkC.mjs +0 -5949
  202. package/dist/run-CLA9zw7J.mjs +0 -5907
  203. package/dist/run-COWb9ovq.mjs +0 -1050
  204. package/dist/run-CSUAy5T5.mjs +0 -1051
  205. package/dist/run-CSk7i0Hq.mjs +0 -1050
  206. package/dist/run-CUtqSGWJ.mjs +0 -1050
  207. package/dist/run-CXrEt0TM.mjs +0 -5008
  208. package/dist/run-CY8Y0JPW.mjs +0 -5287
  209. package/dist/run-CZCKBcQ-.mjs +0 -5244
  210. package/dist/run-CZj0sRCs.mjs +0 -1050
  211. package/dist/run-C_1x2cNU.mjs +0 -5381
  212. package/dist/run-C_8iOjO1.mjs +0 -5892
  213. package/dist/run-C_KIew8H.mjs +0 -1051
  214. package/dist/run-CajRcN3C.mjs +0 -1050
  215. package/dist/run-CbzXO7fw.mjs +0 -1050
  216. package/dist/run-CcSr4x2f.mjs +0 -1050
  217. package/dist/run-CcYaXgCy.mjs +0 -6091
  218. package/dist/run-CdihMx0V.mjs +0 -1051
  219. package/dist/run-Cf2Dl_ck.mjs +0 -1051
  220. package/dist/run-CjH1H4vq.mjs +0 -1050
  221. package/dist/run-CkbDK6jA.mjs +0 -1051
  222. package/dist/run-Ckh6JE9F.mjs +0 -1050
  223. package/dist/run-Ckyg9-fm.mjs +0 -6079
  224. package/dist/run-CqL3ZWdr.mjs +0 -5381
  225. package/dist/run-Csj7sJAh.mjs +0 -1050
  226. package/dist/run-Ct--DWF1.mjs +0 -1051
  227. package/dist/run-CtJRxaFC.mjs +0 -1051
  228. package/dist/run-CuIMdkKF.mjs +0 -6099
  229. package/dist/run-CuckJGM-.mjs +0 -1050
  230. package/dist/run-CxGAa9MH.mjs +0 -1050
  231. package/dist/run-CyU4-O-e.mjs +0 -5411
  232. package/dist/run-CymDyu2b.mjs +0 -5389
  233. package/dist/run-CzIY4_RE.mjs +0 -6093
  234. package/dist/run-D0Ha4aWt.mjs +0 -1050
  235. package/dist/run-D0ow-xms.mjs +0 -5905
  236. package/dist/run-D1PFrNZB.mjs +0 -6273
  237. package/dist/run-D2X3jEqg.mjs +0 -1051
  238. package/dist/run-D39C7Ta3.mjs +0 -1050
  239. package/dist/run-D3Lqxasl.mjs +0 -1051
  240. package/dist/run-D3bhRCCb.mjs +0 -1051
  241. package/dist/run-D5N42sVA.mjs +0 -1050
  242. package/dist/run-D691XPXy.mjs +0 -6031
  243. package/dist/run-D7dLDpq3.mjs +0 -5403
  244. package/dist/run-D8mQ_fL5.mjs +0 -1050
  245. package/dist/run-DA-YBjNw.mjs +0 -6018
  246. package/dist/run-DByI8mI0.mjs +0 -1051
  247. package/dist/run-DCINWip4.mjs +0 -1050
  248. package/dist/run-DCrZ3vke.mjs +0 -5406
  249. package/dist/run-DDF-tRbn.mjs +0 -5954
  250. package/dist/run-DGSgljJE.mjs +0 -5421
  251. package/dist/run-DGsXW19O.mjs +0 -5541
  252. package/dist/run-DHrF2xpW.mjs +0 -5776
  253. package/dist/run-DIB0W42M.mjs +0 -1050
  254. package/dist/run-DJ4k0WzZ.mjs +0 -1051
  255. package/dist/run-DMI83W7i.mjs +0 -5434
  256. package/dist/run-DNX3djCI.mjs +0 -1050
  257. package/dist/run-DOPaGRT2.mjs +0 -6027
  258. package/dist/run-DP7KSZqR.mjs +0 -1051
  259. package/dist/run-DQ0yljWr.mjs +0 -1050
  260. package/dist/run-DTkldU6a.mjs +0 -1050
  261. package/dist/run-DU10B3gK.mjs +0 -5728
  262. package/dist/run-DV86VJNG.mjs +0 -5386
  263. package/dist/run-DVZGKdKO.mjs +0 -1050
  264. package/dist/run-DWdtp6VD.mjs +0 -6136
  265. package/dist/run-DWzA1gZ-.mjs +0 -1050
  266. package/dist/run-DXJ2M19k.mjs +0 -1050
  267. package/dist/run-DZOeccNu.mjs +0 -5484
  268. package/dist/run-D_W5YF0D.mjs +0 -6046
  269. package/dist/run-DaReJPf8.mjs +0 -1051
  270. package/dist/run-DaYrEeQ9.mjs +0 -5400
  271. package/dist/run-DbC9-WM4.mjs +0 -1050
  272. package/dist/run-Dd9XkswU.mjs +0 -1051
  273. package/dist/run-De-wkVl3.mjs +0 -5487
  274. package/dist/run-DfU2luyX.mjs +0 -1050
  275. package/dist/run-Dfl3Ze2L.mjs +0 -5541
  276. package/dist/run-DfuHUDIJ.mjs +0 -1051
  277. package/dist/run-DfwfyFqj.mjs +0 -5975
  278. package/dist/run-DgUDGHZy.mjs +0 -1051
  279. package/dist/run-Dge2K7h1.mjs +0 -1050
  280. package/dist/run-Di3I0USw.mjs +0 -1050
  281. package/dist/run-Dm3U4FB5.mjs +0 -6018
  282. package/dist/run-Du0YOs48.mjs +0 -5446
  283. package/dist/run-DuaIQAE4.mjs +0 -5392
  284. package/dist/run-Dwm19YhI.mjs +0 -1050
  285. package/dist/run-DxM7xaBa.mjs +0 -1050
  286. package/dist/run-DysN-cGm.mjs +0 -1050
  287. package/dist/run-DzXohf8-.mjs +0 -1051
  288. package/dist/run-E_MwVOtN.mjs +0 -5272
  289. package/dist/run-FPoL2-FD.mjs +0 -5381
  290. package/dist/run-HU4XjZfs.mjs +0 -6023
  291. package/dist/run-HhiYlJuS.mjs +0 -5414
  292. package/dist/run-JXLlRLFb.mjs +0 -1050
  293. package/dist/run-K-_jahIg.mjs +0 -1051
  294. package/dist/run-K_S7pfZ-.mjs +0 -1050
  295. package/dist/run-LDiT4WF-.mjs +0 -1050
  296. package/dist/run-NToLJWx-.mjs +0 -5442
  297. package/dist/run-RBufRqbs.mjs +0 -1050
  298. package/dist/run-YFYpyThQ.mjs +0 -1051
  299. package/dist/run-YG1Pb9dY.mjs +0 -5385
  300. package/dist/run-ZDa17iLg.mjs +0 -6060
  301. package/dist/run-ZN0qMdS_.mjs +0 -1051
  302. package/dist/run-azpFWM6w.mjs +0 -1050
  303. package/dist/run-coIDvBK_.mjs +0 -6127
  304. package/dist/run-jLp4pbTE.mjs +0 -1050
  305. package/dist/run-m3oAuSg0.mjs +0 -1050
  306. package/dist/run-r9CAcL_U.mjs +0 -5403
  307. package/dist/run-v32uF2bP.mjs +0 -5378
  308. package/dist/run-vTsskoZc.mjs +0 -5340
  309. package/dist/run-vt26p5D7.mjs +0 -1050
  310. package/dist/run-vvQiCHpi.mjs +0 -5427
  311. package/dist/run-w-HVv5py.mjs +0 -5410
  312. package/dist/run-wpUutZ9C.mjs +0 -1051
  313. package/dist/run-yTjJ7noq.mjs +0 -1051
  314. package/dist/run-zo5GSoVC.mjs +0 -1050
@@ -1,1395 +0,0 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { resolve, join } from 'node:path';
3
- import os from 'node:os';
4
- import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-D_W5YF0D.mjs';
5
- import 'os';
6
- import 'fs/promises';
7
- import 'fs';
8
- import 'path';
9
- import 'url';
10
- import 'child_process';
11
- import 'crypto';
12
- import 'node:crypto';
13
- import 'node:child_process';
14
- import '@agentclientprotocol/sdk';
15
- import '@modelcontextprotocol/sdk/client/index.js';
16
- import '@modelcontextprotocol/sdk/client/stdio.js';
17
- import '@modelcontextprotocol/sdk/types.js';
18
- import 'zod';
19
- import 'node:fs/promises';
20
- import 'node:util';
21
-
22
- function toMarkdownInline(value) {
23
- const escaped = value.replace(/`/g, "\\`");
24
- return `\`${escaped}\``;
25
- }
26
- function formatSessionStatus(data) {
27
- const lines = [
28
- "## Session Status",
29
- "",
30
- `- Session ID: ${toMarkdownInline(data.sessionId)}`,
31
- `- Agent: ${data.flavor}`
32
- ];
33
- if (data.name) lines.push(`- Name: ${data.name}`);
34
- if (data.summary) lines.push(`- Summary: ${data.summary}`);
35
- if (data.path) lines.push(`- Path: ${data.path}`);
36
- if (data.host) lines.push(`- Host: ${data.host}`);
37
- if (data.lifecycleState) lines.push(`- Lifecycle: ${data.lifecycleState}`);
38
- lines.push(`- Active: ${data.active ? "yes" : "no"}`);
39
- lines.push(`- Thinking: ${data.thinking ? "yes" : "no"}`);
40
- lines.push(`- Agent Status: ${data.active ? "busy" : "idle"}`);
41
- if (data.startedBy) lines.push(`- Started By: ${data.startedBy}`);
42
- if (data.claudeSessionId) lines.push(`- Claude Session: ${data.claudeSessionId}`);
43
- if (data.sessionLink) lines.push(`- Link: ${data.sessionLink}`);
44
- return lines.join("\n");
45
- }
46
- function formatJson(data) {
47
- return JSON.stringify(data, null, 2);
48
- }
49
-
50
- const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
51
- const DAEMON_STATE_FILE = join(SVAMP_HOME, "daemon.state.json");
52
- const ENV_FILE = join(SVAMP_HOME, ".env");
53
- function loadDotEnv() {
54
- if (!existsSync(ENV_FILE)) return;
55
- const lines = readFileSync(ENV_FILE, "utf-8").split("\n");
56
- for (const line of lines) {
57
- const trimmed = line.trim();
58
- if (!trimmed || trimmed.startsWith("#")) continue;
59
- const eqIdx = trimmed.indexOf("=");
60
- if (eqIdx === -1) continue;
61
- const key = trimmed.slice(0, eqIdx).trim();
62
- const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
63
- if (!process.env[key]) {
64
- process.env[key] = value;
65
- }
66
- }
67
- }
68
- function readDaemonState() {
69
- if (!existsSync(DAEMON_STATE_FILE)) return null;
70
- try {
71
- return JSON.parse(readFileSync(DAEMON_STATE_FILE, "utf-8"));
72
- } catch {
73
- return null;
74
- }
75
- }
76
- function isDaemonAlive(state) {
77
- try {
78
- process.kill(state.pid, 0);
79
- return true;
80
- } catch {
81
- return false;
82
- }
83
- }
84
- async function connectAndGetMachine(machineId) {
85
- loadDotEnv();
86
- const state = readDaemonState();
87
- if (!state || !isDaemonAlive(state)) {
88
- console.error('Daemon is not running. Start it with "svamp daemon start".');
89
- process.exit(1);
90
- }
91
- const serverUrl = process.env.HYPHA_SERVER_URL || state.hyphaServerUrl;
92
- const token = process.env.HYPHA_TOKEN;
93
- if (!serverUrl) {
94
- console.error('No Hypha server URL. Run "svamp login <url>" first.');
95
- process.exit(1);
96
- }
97
- const origLog = console.log;
98
- const origWarn = console.warn;
99
- const origInfo = console.info;
100
- const origError = console.error;
101
- const stdoutWrite = process.stdout.write.bind(process.stdout);
102
- const stderrWrite = process.stderr.write.bind(process.stderr);
103
- const isHyphaLog = (chunk) => typeof chunk === "string" && (chunk.includes("WebSocket connection") || chunk.includes("Connection established") || chunk.includes("registering service built-in") || chunk.includes("registered service") || chunk.includes("registered all") || chunk.includes("Subscribing to client_") || chunk.includes("subscribed to client_") || chunk.includes("subscribe to client_") || chunk.includes("Cleaning up all sessions") || chunk.includes("WebSocket connection disconnected") || chunk.includes("local RPC disconnection") || chunk.includes("Timeout registering service") || chunk.includes("Failed to subscribe to client_disconnected") || chunk.includes("Timeout subscribing to client_disconnected"));
104
- console.log = () => {
105
- };
106
- console.warn = () => {
107
- };
108
- console.info = () => {
109
- };
110
- console.error = (...args) => {
111
- if (args.some((a) => isHyphaLog(a))) return;
112
- origError(...args);
113
- };
114
- process.stdout.write = (chunk, ...args) => {
115
- if (isHyphaLog(chunk)) return true;
116
- return stdoutWrite(chunk, ...args);
117
- };
118
- process.stderr.write = (chunk, ...args) => {
119
- if (isHyphaLog(chunk)) return true;
120
- return stderrWrite(chunk, ...args);
121
- };
122
- const restoreConsole = () => {
123
- console.log = origLog;
124
- console.warn = origWarn;
125
- console.info = origInfo;
126
- console.error = origError;
127
- };
128
- let server;
129
- try {
130
- server = await connectToHypha({
131
- serverUrl,
132
- token,
133
- name: "svamp-session-cli"
134
- });
135
- } catch (err) {
136
- restoreConsole();
137
- console.error(`Failed to connect to Hypha: ${err.message}`);
138
- process.exit(1);
139
- }
140
- let machine;
141
- try {
142
- const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
143
- if (services.length === 0) {
144
- restoreConsole();
145
- console.error("No machine service found. Is the daemon registered on Hypha?");
146
- await server.disconnect();
147
- process.exit(1);
148
- }
149
- let selectedService;
150
- if (machineId) {
151
- const exact = services.find((s) => (s.id || s.name) === machineId);
152
- if (exact) {
153
- selectedService = exact;
154
- } else {
155
- const prefixMatches = services.filter((s) => {
156
- const id = s.id || s.name;
157
- return id.startsWith(machineId);
158
- });
159
- if (prefixMatches.length === 1) {
160
- selectedService = prefixMatches[0];
161
- } else if (prefixMatches.length === 0) {
162
- const substringMatches = services.filter((s) => {
163
- const id = s.id || s.name || "";
164
- return id.includes(machineId);
165
- });
166
- if (substringMatches.length === 1) {
167
- selectedService = substringMatches[0];
168
- } else {
169
- restoreConsole();
170
- console.error(`No machine found matching: ${machineId}`);
171
- console.error("Available machines:");
172
- for (const s of services) {
173
- console.error(` ${s.id || s.name}`);
174
- }
175
- await server.disconnect();
176
- process.exit(1);
177
- }
178
- } else {
179
- restoreConsole();
180
- console.error(`Ambiguous machine ID "${machineId}". Matches:`);
181
- for (const s of prefixMatches) {
182
- console.error(` ${s.id || s.name}`);
183
- }
184
- await server.disconnect();
185
- process.exit(1);
186
- }
187
- }
188
- } else {
189
- if (state.hyphaClientId) {
190
- const localMatch = services.find((s) => {
191
- const id = s.id || s.name || "";
192
- return id.includes(state.hyphaClientId);
193
- });
194
- selectedService = localMatch || services[0];
195
- } else if (state.machineId) {
196
- const localMatch = services.find((s) => {
197
- const id = s.id || s.name || "";
198
- return id.includes(state.machineId);
199
- });
200
- selectedService = localMatch || services[0];
201
- } else {
202
- selectedService = services[0];
203
- }
204
- }
205
- const svcId = selectedService.id || selectedService.name;
206
- machine = await server.getService(svcId);
207
- } catch (err) {
208
- restoreConsole();
209
- console.error(`Failed to discover machine service: ${err.message}`);
210
- await server.disconnect();
211
- process.exit(1);
212
- }
213
- restoreConsole();
214
- return { server, machine };
215
- }
216
- async function connectAndGetAllMachines() {
217
- loadDotEnv();
218
- const state = readDaemonState();
219
- if (!state || !isDaemonAlive(state)) {
220
- console.error('Daemon is not running. Start it with "svamp daemon start".');
221
- process.exit(1);
222
- }
223
- const serverUrl = process.env.HYPHA_SERVER_URL || state.hyphaServerUrl;
224
- const token = process.env.HYPHA_TOKEN;
225
- if (!serverUrl) {
226
- console.error('No Hypha server URL. Run "svamp login <url>" first.');
227
- process.exit(1);
228
- }
229
- const origLog = console.log;
230
- const origWarn = console.warn;
231
- const origInfo = console.info;
232
- const origError = console.error;
233
- const stdoutWrite = process.stdout.write.bind(process.stdout);
234
- const stderrWrite = process.stderr.write.bind(process.stderr);
235
- const isHyphaLog = (chunk) => typeof chunk === "string" && (chunk.includes("WebSocket connection") || chunk.includes("Connection established") || chunk.includes("registering service built-in") || chunk.includes("registered service") || chunk.includes("registered all") || chunk.includes("Subscribing to client_") || chunk.includes("subscribed to client_") || chunk.includes("subscribe to client_") || chunk.includes("Cleaning up all sessions") || chunk.includes("WebSocket connection disconnected") || chunk.includes("local RPC disconnection") || chunk.includes("Timeout registering service") || chunk.includes("Failed to subscribe to client_disconnected") || chunk.includes("Timeout subscribing to client_disconnected"));
236
- console.log = () => {
237
- };
238
- console.warn = () => {
239
- };
240
- console.info = () => {
241
- };
242
- console.error = (...args) => {
243
- if (!args.some((a) => isHyphaLog(a))) origError(...args);
244
- };
245
- process.stdout.write = (chunk, ...args) => {
246
- if (isHyphaLog(chunk)) return true;
247
- return stdoutWrite(chunk, ...args);
248
- };
249
- process.stderr.write = (chunk, ...args) => {
250
- if (isHyphaLog(chunk)) return true;
251
- return stderrWrite(chunk, ...args);
252
- };
253
- const restoreConsole = () => {
254
- console.log = origLog;
255
- console.warn = origWarn;
256
- console.info = origInfo;
257
- console.error = origError;
258
- };
259
- let server;
260
- try {
261
- server = await connectToHypha({ serverUrl, token, name: "svamp-session-cli" });
262
- } catch (err) {
263
- restoreConsole();
264
- console.error(`Failed to connect to Hypha: ${err.message}`);
265
- process.exit(1);
266
- }
267
- const machines = [];
268
- try {
269
- const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
270
- for (const svc of services) {
271
- try {
272
- const svcId = svc.id || svc.name;
273
- machines.push(await server.getService(svcId));
274
- } catch {
275
- }
276
- }
277
- } catch (err) {
278
- restoreConsole();
279
- console.error(`Failed to discover machine services: ${err.message}`);
280
- await server.disconnect();
281
- process.exit(1);
282
- }
283
- restoreConsole();
284
- if (machines.length === 0) {
285
- console.error("No machine service found. Is the daemon registered on Hypha?");
286
- await server.disconnect();
287
- process.exit(1);
288
- }
289
- return { server, machines };
290
- }
291
- async function sessionMachines() {
292
- loadDotEnv();
293
- const state = readDaemonState();
294
- if (!state || !isDaemonAlive(state)) {
295
- console.error('Daemon is not running. Start it with "svamp daemon start".');
296
- process.exit(1);
297
- }
298
- const serverUrl = process.env.HYPHA_SERVER_URL || state.hyphaServerUrl;
299
- const token = process.env.HYPHA_TOKEN;
300
- if (!serverUrl) {
301
- console.error('No Hypha server URL. Run "svamp login <url>" first.');
302
- process.exit(1);
303
- }
304
- const origLog = console.log;
305
- const origWarn = console.warn;
306
- const origInfo = console.info;
307
- const origError = console.error;
308
- const stdoutWrite = process.stdout.write.bind(process.stdout);
309
- const stderrWrite = process.stderr.write.bind(process.stderr);
310
- const isHyphaLog = (chunk) => typeof chunk === "string" && (chunk.includes("WebSocket connection") || chunk.includes("Connection established") || chunk.includes("registering service built-in") || chunk.includes("registered service") || chunk.includes("registered all") || chunk.includes("Subscribing to client_") || chunk.includes("subscribed to client_") || chunk.includes("subscribe to client_") || chunk.includes("Cleaning up all sessions") || chunk.includes("WebSocket connection disconnected") || chunk.includes("local RPC disconnection") || chunk.includes("Timeout registering service") || chunk.includes("Failed to subscribe to client_disconnected") || chunk.includes("Timeout subscribing to client_disconnected"));
311
- console.log = () => {
312
- };
313
- console.warn = () => {
314
- };
315
- console.info = () => {
316
- };
317
- console.error = (...args) => {
318
- if (args.some((a) => isHyphaLog(a))) return;
319
- origError(...args);
320
- };
321
- process.stdout.write = (chunk, ...args) => {
322
- if (isHyphaLog(chunk)) return true;
323
- return stdoutWrite(chunk, ...args);
324
- };
325
- process.stderr.write = (chunk, ...args) => {
326
- if (isHyphaLog(chunk)) return true;
327
- return stderrWrite(chunk, ...args);
328
- };
329
- const restoreConsole = () => {
330
- console.log = origLog;
331
- console.warn = origWarn;
332
- console.info = origInfo;
333
- console.error = origError;
334
- };
335
- let server;
336
- try {
337
- server = await connectToHypha({
338
- serverUrl,
339
- token,
340
- name: "svamp-session-cli"
341
- });
342
- } catch (err) {
343
- restoreConsole();
344
- console.error(`Failed to connect to Hypha: ${err.message}`);
345
- process.exit(1);
346
- }
347
- try {
348
- const services = await server.listServices({ query: { type: "svamp-machine" }, include_unlisted: true, _rkwargs: true });
349
- restoreConsole();
350
- if (services.length === 0) {
351
- console.log("No machines found.");
352
- return;
353
- }
354
- const machines = [];
355
- for (const svc of services) {
356
- const svcId = svc.id || svc.name;
357
- try {
358
- const machineSvc = await server.getService(svcId);
359
- const info = await machineSvc.getMachineInfo();
360
- const sessions = await machineSvc.listSessions();
361
- machines.push({
362
- serviceId: svcId,
363
- machineId: info.machineId || svcId,
364
- displayName: info.metadata?.displayName || info.metadata?.host || "-",
365
- platform: info.metadata?.platform || "-",
366
- host: info.metadata?.host || "-",
367
- sessions: sessions.length,
368
- status: info.daemonState?.status || "unknown"
369
- });
370
- } catch {
371
- machines.push({
372
- serviceId: svcId,
373
- machineId: svcId,
374
- displayName: "-",
375
- platform: "-",
376
- host: "-",
377
- sessions: -1,
378
- status: "unreachable"
379
- });
380
- }
381
- }
382
- const header = `${"MACHINE ID".padEnd(20)} ${"NAME".padEnd(20)} ${"PLATFORM".padEnd(12)} ${"HOST".padEnd(25)} ${"SESSIONS".padEnd(10)} ${"STATUS"}`;
383
- console.log(header);
384
- console.log("-".repeat(header.length));
385
- for (const m of machines) {
386
- const id = truncate(m.machineId, 18).padEnd(20);
387
- const name = truncate(m.displayName, 18).padEnd(20);
388
- const platform = m.platform.padEnd(12);
389
- const host = truncate(m.host, 23).padEnd(25);
390
- const sessions = m.sessions >= 0 ? String(m.sessions).padEnd(10) : "-".padEnd(10);
391
- const status = m.status === "running" ? `\x1B[32m${m.status}\x1B[0m` : m.status === "unreachable" ? `\x1B[31m${m.status}\x1B[0m` : m.status;
392
- console.log(`${id} ${name} ${platform} ${host} ${sessions} ${status}`);
393
- }
394
- console.log(`
395
- ${machines.length} machine(s) found.`);
396
- console.log("Use --machine <id> to target a specific machine.");
397
- } finally {
398
- await server.disconnect();
399
- }
400
- }
401
- function resolveSessionId(sessions, partial) {
402
- const exact = sessions.find((s) => s.sessionId === partial);
403
- if (exact) return exact;
404
- const matches = sessions.filter((s) => s.sessionId.startsWith(partial));
405
- if (matches.length === 1) return matches[0];
406
- if (matches.length === 0) {
407
- console.error(`No session found matching: ${partial}`);
408
- console.error('Run "svamp session list" to see active sessions.');
409
- process.exit(1);
410
- }
411
- console.error(`Ambiguous session ID "${partial}". Matches:`);
412
- for (const s of matches) {
413
- console.error(` ${s.sessionId}`);
414
- }
415
- process.exit(1);
416
- }
417
- function truncate(str, max) {
418
- if (str.length <= max) return str;
419
- return "..." + str.slice(str.length - max + 3);
420
- }
421
- function renderMessage(msg) {
422
- const content = msg.content;
423
- if (!content) return;
424
- const role = content.role;
425
- if (role === "user") {
426
- const data = content.content;
427
- let text;
428
- if (typeof data === "string") {
429
- try {
430
- const parsed = JSON.parse(data);
431
- text = parsed?.text || parsed?.content?.text || data;
432
- } catch {
433
- text = data;
434
- }
435
- } else if (data?.text) {
436
- text = data.text;
437
- } else if (data?.type === "text") {
438
- text = data.text || "";
439
- } else {
440
- text = typeof data === "object" ? JSON.stringify(data) : String(data || "");
441
- }
442
- console.log(`\x1B[36m[user]\x1B[0m ${text}`);
443
- } else if (role === "agent" || role === "assistant") {
444
- const data = content.content?.data || content.content;
445
- if (!data) return;
446
- if (data.type === "assistant" && Array.isArray(data.content)) {
447
- for (const block of data.content) {
448
- if (block.type === "text" && block.text) {
449
- process.stdout.write(block.text);
450
- if (!block.text.endsWith("\n")) process.stdout.write("\n");
451
- } else if (block.type === "tool_use") {
452
- const argsStr = JSON.stringify(block.input || {}).slice(0, 120);
453
- console.log(`\x1B[33m[tool]\x1B[0m ${block.name}(${argsStr})`);
454
- } else if (block.type === "tool_result") {
455
- const resultStr = typeof block.content === "string" ? block.content : JSON.stringify(block.content || "");
456
- console.log(`\x1B[90m[result]\x1B[0m ${resultStr.slice(0, 200)}${resultStr.length > 200 ? "..." : ""}`);
457
- } else if (block.type === "thinking") {
458
- const text = block.thinking || block.text || "";
459
- if (text) console.log(`\x1B[90m[thinking] ${text.slice(0, 200)}\x1B[0m`);
460
- }
461
- }
462
- } else if (data.type === "result") {
463
- if (data.result) console.log(`\x1B[32m[done]\x1B[0m ${data.result}`);
464
- } else if (data.type === "output") {
465
- const inner = data.data;
466
- if (inner?.type === "assistant" && Array.isArray(inner.content)) {
467
- for (const block of inner.content) {
468
- if (block.type === "text" && block.text) {
469
- process.stdout.write(block.text);
470
- if (!block.text.endsWith("\n")) process.stdout.write("\n");
471
- } else if (block.type === "tool_use") {
472
- const argsStr = JSON.stringify(block.input || {}).slice(0, 120);
473
- console.log(`\x1B[33m[tool]\x1B[0m ${block.name}(${argsStr})`);
474
- } else if (block.type === "tool_result") {
475
- const resultStr = typeof block.content === "string" ? block.content : JSON.stringify(block.content || "");
476
- console.log(`\x1B[90m[result]\x1B[0m ${resultStr.slice(0, 200)}${resultStr.length > 200 ? "..." : ""}`);
477
- }
478
- }
479
- } else if (inner?.type === "result") {
480
- if (inner.result) console.log(`\x1B[32m[done]\x1B[0m ${inner.result}`);
481
- }
482
- }
483
- } else if (role === "session") {
484
- const data = content.content?.data;
485
- if (data?.type === "system" && data?.subtype === "init") {
486
- console.log(`\x1B[90m[session init]\x1B[0m`);
487
- }
488
- }
489
- }
490
- function extractMessageText(msg) {
491
- const content = msg.content;
492
- if (!content) return null;
493
- const role = content.role || "unknown";
494
- let text = "";
495
- if (role === "user") {
496
- const data = content.content;
497
- if (typeof data === "string") {
498
- try {
499
- const parsed = JSON.parse(data);
500
- text = parsed?.text || parsed?.content?.text || data;
501
- } catch {
502
- text = data;
503
- }
504
- } else if (data?.text) {
505
- text = data.text;
506
- } else if (data?.type === "text") {
507
- text = data.text || "";
508
- } else {
509
- text = typeof data === "object" ? JSON.stringify(data) : String(data || "");
510
- }
511
- } else if (role === "agent" || role === "assistant") {
512
- const data = content.content?.data || content.content;
513
- if (!data) return null;
514
- if (data.type === "assistant" && Array.isArray(data.content)) {
515
- const parts = [];
516
- for (const block of data.content) {
517
- if (block.type === "text" && block.text) {
518
- parts.push(block.text);
519
- } else if (block.type === "tool_use") {
520
- parts.push(`[tool: ${block.name}]`);
521
- }
522
- }
523
- text = parts.join("\n");
524
- } else if (data.type === "result") {
525
- text = data.result || "";
526
- } else if (data.type === "output") {
527
- const inner = data.data;
528
- if (inner?.type === "assistant" && Array.isArray(inner.content)) {
529
- const parts = [];
530
- for (const block of inner.content) {
531
- if (block.type === "text" && block.text) {
532
- parts.push(block.text);
533
- } else if (block.type === "tool_use") {
534
- parts.push(`[tool: ${block.name}]`);
535
- }
536
- }
537
- text = parts.join("\n");
538
- } else if (inner?.type === "result") {
539
- text = inner.result || "";
540
- }
541
- }
542
- } else if (role === "session") {
543
- text = "[session event]";
544
- }
545
- return {
546
- id: msg.id || "",
547
- seq: msg.seq || 0,
548
- role,
549
- text,
550
- createdAt: msg.createdAt || 0
551
- };
552
- }
553
- async function waitForIdle(server, sessionId, timeoutMs) {
554
- const svc = await server.getService(`svamp-session-${sessionId}`);
555
- const pollInterval = 2e3;
556
- const deadline = Date.now() + timeoutMs;
557
- while (Date.now() < deadline) {
558
- const activity = await svc.getActivityState();
559
- if (activity && !activity.thinking) {
560
- return;
561
- }
562
- await new Promise((r) => setTimeout(r, pollInterval));
563
- }
564
- throw new Error("Timeout waiting for agent to become idle");
565
- }
566
- async function waitForBusyThenIdle(server, sessionId, timeoutMs = 3e5, busyTimeoutMs = 1e4) {
567
- const svc = await server.getService(`svamp-session-${sessionId}`);
568
- const pollInterval = 2e3;
569
- const deadline = Date.now() + timeoutMs;
570
- const busyDeadline = Date.now() + busyTimeoutMs;
571
- let sawBusy = false;
572
- while (Date.now() < deadline) {
573
- const activity = await svc.getActivityState();
574
- const isBusy = activity?.thinking === true;
575
- if (isBusy) {
576
- sawBusy = true;
577
- }
578
- if (activity && !activity.active) {
579
- return;
580
- }
581
- if (sawBusy && !isBusy) {
582
- return;
583
- }
584
- if (!sawBusy && Date.now() > busyDeadline) {
585
- return;
586
- }
587
- await new Promise((r) => setTimeout(r, pollInterval));
588
- }
589
- throw new Error("Timeout waiting for agent to become idle");
590
- }
591
- async function sessionList(machineId, opts) {
592
- if (machineId) {
593
- const { server, machine } = await connectAndGetMachine(machineId);
594
- try {
595
- await listSessionsFromMachines(server, [machine], opts);
596
- } finally {
597
- await server.disconnect();
598
- }
599
- } else {
600
- const { server, machines } = await connectAndGetAllMachines();
601
- try {
602
- await listSessionsFromMachines(server, machines, opts);
603
- } finally {
604
- await server.disconnect();
605
- }
606
- }
607
- }
608
- async function listSessionsFromMachines(server, machines, opts) {
609
- const allSessions = [];
610
- for (const machine of machines) {
611
- try {
612
- const info = await machine.getMachineInfo();
613
- const sessions = await machine.listSessions();
614
- for (const s of sessions) {
615
- s.machineHost = info.metadata?.displayName || info.metadata?.host || info.machineId;
616
- }
617
- allSessions.push(...sessions);
618
- } catch {
619
- }
620
- }
621
- const filtered = opts?.active ? allSessions.filter((s) => s.active) : allSessions;
622
- if (filtered.length === 0) {
623
- if (opts?.json) {
624
- console.log(formatJson([]));
625
- } else {
626
- console.log("No active sessions.");
627
- }
628
- return;
629
- }
630
- const enriched = [];
631
- for (const s of filtered) {
632
- let flavor = "claude";
633
- let name = "";
634
- let path = s.directory || "";
635
- let host = s.machineHost || "";
636
- if (s.metadata) {
637
- flavor = s.metadata.flavor || "claude";
638
- name = s.metadata.name || "";
639
- }
640
- if (s.active) {
641
- try {
642
- const svc = await server.getService(`svamp-session-${s.sessionId}`);
643
- const { metadata } = await svc.getMetadata();
644
- flavor = metadata?.flavor || flavor;
645
- name = metadata?.name || name;
646
- path = metadata?.path || path;
647
- host = metadata?.host || host;
648
- } catch {
649
- }
650
- }
651
- enriched.push({ ...s, flavor, name, path, host });
652
- }
653
- if (opts?.json) {
654
- console.log(formatJson(enriched.map((s) => ({
655
- sessionId: s.sessionId,
656
- agent: s.flavor,
657
- name: s.name,
658
- path: s.path,
659
- host: s.host,
660
- active: s.active,
661
- directory: s.directory
662
- }))));
663
- } else {
664
- const header = `${"ID".padEnd(10)} ${"AGENT".padEnd(10)} ${"STATUS".padEnd(9)} ${"NAME".padEnd(25)} ${"MACHINE".padEnd(18)} ${"DIRECTORY".padEnd(35)}`;
665
- console.log(header);
666
- console.log("-".repeat(header.length));
667
- for (const s of enriched) {
668
- const id = s.sessionId.slice(0, 8);
669
- const agent = (s.flavor || "claude").padEnd(10);
670
- const status = s.active ? "\x1B[32mactive\x1B[0m " : "\x1B[90minactive\x1B[0m";
671
- const name = truncate(s.name || "-", 25).padEnd(25);
672
- const machine = truncate(s.host || "-", 16).padEnd(18);
673
- const dir = truncate(s.directory || "-", 33).padEnd(35);
674
- console.log(`${id.padEnd(10)} ${agent} ${status} ${name} ${machine} ${dir}`);
675
- }
676
- }
677
- }
678
- function parseShareArg(arg) {
679
- const parts = arg.split(":");
680
- const email = parts[0];
681
- const role = parts[1] || "interact";
682
- if (!["view", "interact", "admin"].includes(role)) {
683
- throw new Error(`Invalid role "${role}" in --share ${arg}. Must be view, interact, or admin.`);
684
- }
685
- return { email, role };
686
- }
687
- async function sessionSpawn(agent, directory, machineId, opts) {
688
- const { server, machine } = await connectAndGetMachine(machineId);
689
- try {
690
- let sharing;
691
- if (opts?.share?.length) {
692
- sharing = {
693
- enabled: true,
694
- owner: "",
695
- // will be auto-set by machine service from Hypha context
696
- allowedUsers: opts.share.map((s) => ({
697
- email: s.email,
698
- role: s.role || "interact",
699
- addedAt: Date.now(),
700
- addedBy: "cli"
701
- }))
702
- };
703
- }
704
- let securityContext;
705
- if (opts?.securityContextPath) {
706
- const configPath = resolve(opts.securityContextPath);
707
- const config = loadSecurityContextConfig(configPath);
708
- securityContext = resolveSecurityContext(config, void 0);
709
- }
710
- if (opts?.denyRead?.length || opts?.allowWrite?.length || opts?.denyNetwork || opts?.allowDomain?.length) {
711
- const flagCtx = buildSecurityContextFromFlags({
712
- denyRead: opts.denyRead,
713
- allowWrite: opts.allowWrite,
714
- denyNetwork: opts.denyNetwork,
715
- allowDomain: opts.allowDomain
716
- });
717
- securityContext = mergeSecurityContexts(securityContext, flagCtx);
718
- }
719
- const forceIsolation = opts?.isolate || !!securityContext;
720
- if (securityContext?.filesystem?.allowWrite?.length) {
721
- const absDir = resolve(directory);
722
- const writePaths = securityContext.filesystem.allowWrite;
723
- const dirCovered = writePaths.some((p) => absDir.startsWith(resolve(p)) || resolve(p).startsWith(absDir));
724
- if (!dirCovered) {
725
- console.warn(`Warning: Working directory ${absDir} is not covered by allowWrite paths: ${writePaths.join(", ")}`);
726
- console.warn(` The agent may not be able to write files in the working directory.`);
727
- }
728
- }
729
- console.log(`Spawning ${agent} session in ${directory}...`);
730
- if (forceIsolation) {
731
- console.log(`Isolation: enabled (workspace: ${resolve(directory)})`);
732
- }
733
- if (securityContext) {
734
- console.log(`Security context: ${JSON.stringify(securityContext, null, 2)}`);
735
- }
736
- if (sharing) {
737
- console.log(`Sharing with: ${sharing.allowedUsers.map((u) => `${u.email} (${u.role})`).join(", ")}`);
738
- }
739
- const result = await machine.spawnSession({
740
- directory,
741
- agent,
742
- sharing,
743
- securityContext,
744
- forceIsolation
745
- });
746
- if (result.type === "success") {
747
- console.log(`Session started: ${result.sessionId}`);
748
- if (result.message) console.log(` ${result.message}`);
749
- if (opts?.message && result.sessionId) {
750
- const svc = await server.getService(`svamp-session-${result.sessionId}`);
751
- const sendResult = await svc.sendMessage(
752
- JSON.stringify({
753
- role: "user",
754
- content: { type: "text", text: opts.message },
755
- meta: { sentFrom: "svamp-cli" }
756
- })
757
- );
758
- console.log(`Message sent (seq: ${sendResult.seq})`);
759
- if (opts.wait) {
760
- console.log("Waiting for agent to become idle...");
761
- await waitForBusyThenIdle(server, result.sessionId);
762
- console.log("Agent is idle.");
763
- }
764
- }
765
- } else if (result.type === "requestToApproveDirectoryCreation") {
766
- console.error(`Directory ${result.directory} does not exist. Create it first or use an existing directory.`);
767
- process.exit(1);
768
- } else {
769
- console.error(`Failed: ${result.errorMessage || "Unknown error"}`);
770
- process.exit(1);
771
- }
772
- } finally {
773
- await server.disconnect();
774
- }
775
- }
776
- async function sessionStop(sessionId, machineId) {
777
- const { server, machine } = await connectAndGetMachine(machineId);
778
- try {
779
- const sessions = await machine.listSessions();
780
- const match = resolveSessionId(sessions, sessionId);
781
- const success = await machine.stopSession(match.sessionId);
782
- if (success) {
783
- console.log(`Session ${match.sessionId.slice(0, 8)} stopped.`);
784
- } else {
785
- console.error("Failed to stop session (not found on daemon).");
786
- process.exit(1);
787
- }
788
- } finally {
789
- await server.disconnect();
790
- }
791
- }
792
- async function sessionInfo(sessionId, machineId, opts) {
793
- const { server, machine } = await connectAndGetMachine(machineId);
794
- try {
795
- const sessions = await machine.listSessions();
796
- const match = resolveSessionId(sessions, sessionId);
797
- const fullId = match.sessionId;
798
- let metadata = {};
799
- let activity = {};
800
- try {
801
- const svc = await server.getService(`svamp-session-${fullId}`);
802
- const metaResult = await svc.getMetadata();
803
- metadata = metaResult.metadata || {};
804
- activity = await svc.getActivityState();
805
- } catch {
806
- }
807
- const statusData = {
808
- sessionId: fullId,
809
- flavor: metadata.flavor || "claude",
810
- name: metadata.name || "",
811
- path: metadata.path || match.directory || "",
812
- host: metadata.host || "",
813
- lifecycleState: metadata.lifecycleState || "unknown",
814
- active: activity.active ?? false,
815
- thinking: activity.thinking ?? false,
816
- startedBy: metadata.startedBy || match.startedBy || "",
817
- summary: metadata.summary?.text || void 0,
818
- claudeSessionId: metadata.claudeSessionId || void 0,
819
- sessionLink: metadata.sessionLink?.url || void 0
820
- };
821
- if (opts?.json) {
822
- console.log(formatJson(statusData));
823
- } else {
824
- console.log(formatSessionStatus(statusData));
825
- }
826
- } finally {
827
- await server.disconnect();
828
- }
829
- }
830
- async function sessionMessages(sessionId, machineId, opts) {
831
- const { server, machine } = await connectAndGetMachine(machineId);
832
- try {
833
- const sessions = await machine.listSessions();
834
- const match = resolveSessionId(sessions, sessionId);
835
- const fullId = match.sessionId;
836
- const svc = await server.getService(`svamp-session-${fullId}`);
837
- const afterSeq = opts?.after ?? 0;
838
- const apiLimit = opts?.limit ?? 1e3;
839
- const { messages } = await svc.getMessages(afterSeq, apiLimit);
840
- const toShow = opts?.last ? messages.slice(-opts.last) : messages;
841
- if (toShow.length === 0) {
842
- if (opts?.json) {
843
- console.log(formatJson([]));
844
- } else {
845
- console.log("No messages yet.");
846
- }
847
- return;
848
- }
849
- if (opts?.json) {
850
- const formatted = [];
851
- for (const msg of toShow) {
852
- const extracted = extractMessageText(msg);
853
- if (extracted) {
854
- formatted.push(extracted);
855
- }
856
- }
857
- formatted.sort((a, b) => a.createdAt - b.createdAt);
858
- console.log(formatJson(formatted));
859
- } else {
860
- for (const msg of toShow) {
861
- renderMessage(msg);
862
- }
863
- }
864
- } finally {
865
- await server.disconnect();
866
- }
867
- }
868
- async function sessionAttach(sessionId, machineId) {
869
- const { server, machine } = await connectAndGetMachine(machineId);
870
- const sessions = await machine.listSessions();
871
- const match = resolveSessionId(sessions, sessionId);
872
- const fullId = match.sessionId;
873
- let svc;
874
- try {
875
- svc = await server.getService(`svamp-session-${fullId}`);
876
- } catch (err) {
877
- console.error(`Could not find session service: ${err.message}`);
878
- await server.disconnect();
879
- process.exit(1);
880
- }
881
- const { metadata } = await svc.getMetadata();
882
- const flavor = metadata?.flavor || "claude";
883
- const name = metadata?.name || fullId.slice(0, 8);
884
- console.log(`Attached to ${flavor} session "${name}". Commands: /quit /abort /kill
885
- `);
886
- const seenMessageIds = /* @__PURE__ */ new Set();
887
- let replayDone = false;
888
- await svc.registerListener({
889
- onUpdate: (update) => {
890
- if (update.type === "new-message") {
891
- const msg = update.message;
892
- if (!msg?.id) return;
893
- if (seenMessageIds.has(msg.id)) return;
894
- seenMessageIds.add(msg.id);
895
- if (!replayDone) return;
896
- renderMessage(msg);
897
- } else if (update.type === "activity") {
898
- if (!replayDone) return;
899
- if (update.thinking) {
900
- process.stdout.write("\x1B[90m[thinking...]\x1B[0m\r");
901
- } else if (!update.thinking) {
902
- process.stdout.write("\n> ");
903
- }
904
- } else if (update.type === "update-session") ;
905
- }
906
- });
907
- await new Promise((r) => setTimeout(r, 500));
908
- replayDone = true;
909
- console.log(`\x1B[90m(${seenMessageIds.size} messages in history)\x1B[0m`);
910
- process.stdout.write("> ");
911
- const readline = await import('readline');
912
- const rl = readline.createInterface({
913
- input: process.stdin,
914
- output: process.stdout,
915
- terminal: true
916
- });
917
- rl.on("line", async (line) => {
918
- const trimmed = line.trim();
919
- if (!trimmed) {
920
- process.stdout.write("> ");
921
- return;
922
- }
923
- if (trimmed === "/quit" || trimmed === "/detach") {
924
- console.log("Detaching (session continues running)...");
925
- rl.close();
926
- await server.disconnect();
927
- process.exit(0);
928
- }
929
- if (trimmed === "/abort" || trimmed === "/cancel") {
930
- try {
931
- await svc.abort();
932
- console.log("Abort sent.");
933
- } catch (err) {
934
- console.error(`Abort failed: ${err.message}`);
935
- }
936
- process.stdout.write("> ");
937
- return;
938
- }
939
- if (trimmed === "/kill") {
940
- try {
941
- await svc.killSession();
942
- console.log("Session killed.");
943
- } catch (err) {
944
- console.error(`Kill failed: ${err.message}`);
945
- }
946
- rl.close();
947
- await server.disconnect();
948
- process.exit(0);
949
- }
950
- if (trimmed === "/info") {
951
- try {
952
- const { metadata: m } = await svc.getMetadata();
953
- const act = await svc.getActivityState();
954
- console.log(` Agent: ${m?.flavor || "claude"}, State: ${m?.lifecycleState || "?"}, Active: ${act?.active}, Thinking: ${act?.thinking}`);
955
- } catch (err) {
956
- console.error(`Info failed: ${err.message}`);
957
- }
958
- process.stdout.write("> ");
959
- return;
960
- }
961
- try {
962
- await svc.sendMessage(
963
- JSON.stringify({
964
- role: "user",
965
- content: { type: "text", text: trimmed }
966
- })
967
- );
968
- } catch (err) {
969
- console.error(`Send failed: ${err.message}`);
970
- process.stdout.write("> ");
971
- }
972
- });
973
- rl.on("close", async () => {
974
- await server.disconnect();
975
- process.exit(0);
976
- });
977
- process.on("SIGINT", async () => {
978
- console.log("\nDetaching (session continues running)...");
979
- rl.close();
980
- await server.disconnect();
981
- process.exit(0);
982
- });
983
- }
984
- async function sessionSend(sessionId, message, machineId, opts) {
985
- const { server, machine } = await connectAndGetMachine(machineId);
986
- try {
987
- const sessions = await machine.listSessions();
988
- const match = resolveSessionId(sessions, sessionId);
989
- const fullId = match.sessionId;
990
- const svc = await server.getService(`svamp-session-${fullId}`);
991
- const result = await svc.sendMessage(
992
- JSON.stringify({
993
- role: "user",
994
- content: { type: "text", text: message },
995
- meta: { sentFrom: "svamp-cli" }
996
- })
997
- );
998
- if (opts?.wait) {
999
- const timeoutMs = (opts.timeout || 300) * 1e3;
1000
- await waitForBusyThenIdle(server, fullId, timeoutMs);
1001
- }
1002
- if (opts?.json) {
1003
- console.log(formatJson({
1004
- sessionId: fullId,
1005
- message,
1006
- sent: true,
1007
- seq: result.seq,
1008
- waited: !!opts.wait
1009
- }));
1010
- } else {
1011
- console.log(`Message sent to session ${fullId.slice(0, 8)} (seq: ${result.seq})`);
1012
- if (opts?.wait) {
1013
- console.log("Agent is idle.");
1014
- }
1015
- }
1016
- } finally {
1017
- await server.disconnect();
1018
- }
1019
- }
1020
- async function sessionWait(sessionId, machineId, opts) {
1021
- const { server, machine } = await connectAndGetMachine(machineId);
1022
- try {
1023
- const sessions = await machine.listSessions();
1024
- const match = resolveSessionId(sessions, sessionId);
1025
- const fullId = match.sessionId;
1026
- const timeoutMs = (opts?.timeout || 300) * 1e3;
1027
- await waitForIdle(server, fullId, timeoutMs);
1028
- console.log(`Session ${fullId.slice(0, 8)} is idle.`);
1029
- } catch (err) {
1030
- const msg = err instanceof Error ? err.message : String(err);
1031
- console.error(msg);
1032
- process.exitCode = 1;
1033
- } finally {
1034
- await server.disconnect();
1035
- }
1036
- }
1037
- async function sessionShare(sessionIdPartial, machineId, opts) {
1038
- const { server, machine } = await connectAndGetMachine(machineId);
1039
- try {
1040
- const sessions = await machine.listSessions();
1041
- const match = resolveSessionId(sessions, sessionIdPartial);
1042
- const fullId = match.sessionId;
1043
- const svc = await server.getService(`svamp-session-${fullId}`);
1044
- if (opts.list) {
1045
- const metaResult = await svc.getMetadata();
1046
- const sharing = metaResult.metadata?.sharing;
1047
- if (!sharing || !sharing.enabled) {
1048
- console.log("Sharing is not enabled for this session.");
1049
- return;
1050
- }
1051
- console.log(`Owner: ${sharing.owner}`);
1052
- if (sharing.publicAccess) {
1053
- console.log(`Public access: ${sharing.publicAccess} (anyone with the link)`);
1054
- }
1055
- if (sharing.allowedUsers.length === 0) {
1056
- console.log("No shared users.");
1057
- } else {
1058
- console.log("Shared users:");
1059
- for (const u of sharing.allowedUsers) {
1060
- console.log(` ${u.email.padEnd(30)} ${u.role.padEnd(10)} (added ${new Date(u.addedAt).toISOString().slice(0, 10)})`);
1061
- }
1062
- }
1063
- const secCtx = metaResult.metadata?.securityContext;
1064
- if (secCtx) {
1065
- console.log(`
1066
- Security context:`);
1067
- console.log(JSON.stringify(secCtx, null, 2));
1068
- }
1069
- return;
1070
- }
1071
- if (opts.add) {
1072
- const { email, role } = parseShareArg(opts.add);
1073
- const metaResult = await svc.getMetadata();
1074
- let sharing = metaResult.metadata?.sharing || {
1075
- enabled: true,
1076
- owner: "",
1077
- allowedUsers: []
1078
- };
1079
- sharing.enabled = true;
1080
- sharing.allowedUsers = sharing.allowedUsers.filter(
1081
- (u) => u.email.toLowerCase() !== email.toLowerCase()
1082
- );
1083
- sharing.allowedUsers.push({
1084
- email,
1085
- role,
1086
- addedAt: Date.now(),
1087
- addedBy: "cli"
1088
- });
1089
- await svc.updateSharing(sharing);
1090
- console.log(`Shared session ${fullId.slice(0, 8)} with ${email} (${role}).`);
1091
- return;
1092
- }
1093
- if (opts.remove) {
1094
- const email = opts.remove;
1095
- const metaResult = await svc.getMetadata();
1096
- const sharing = metaResult.metadata?.sharing;
1097
- if (!sharing) {
1098
- console.error("Sharing is not enabled for this session.");
1099
- process.exit(1);
1100
- }
1101
- const before = sharing.allowedUsers.length;
1102
- sharing.allowedUsers = sharing.allowedUsers.filter(
1103
- (u) => u.email.toLowerCase() !== email.toLowerCase()
1104
- );
1105
- if (sharing.allowedUsers.length === before) {
1106
- console.error(`User ${email} is not in the shared users list.`);
1107
- process.exit(1);
1108
- }
1109
- await svc.updateSharing(sharing);
1110
- console.log(`Removed ${email} from session ${fullId.slice(0, 8)}.`);
1111
- return;
1112
- }
1113
- if (opts.public !== void 0) {
1114
- const value = opts.public.toLowerCase();
1115
- if (value === "off" || value === "none" || value === "no") {
1116
- const metaResult = await svc.getMetadata();
1117
- const sharing = metaResult.metadata?.sharing || {
1118
- enabled: true,
1119
- owner: "",
1120
- allowedUsers: []
1121
- };
1122
- sharing.publicAccess = null;
1123
- await svc.updateSharing(sharing);
1124
- console.log(`Public access disabled for session ${fullId.slice(0, 8)}.`);
1125
- } else if (value === "view" || value === "interact") {
1126
- const metaResult = await svc.getMetadata();
1127
- const sharing = metaResult.metadata?.sharing || {
1128
- enabled: true,
1129
- owner: "",
1130
- allowedUsers: []
1131
- };
1132
- sharing.enabled = true;
1133
- sharing.publicAccess = value;
1134
- await svc.updateSharing(sharing);
1135
- console.log(`Public access set to '${value}' for session ${fullId.slice(0, 8)}.`);
1136
- } else {
1137
- console.error("Invalid --public value. Use: view, interact, or off");
1138
- process.exit(1);
1139
- }
1140
- return;
1141
- }
1142
- console.error("Usage: svamp session share <id> --add <email>[:<role>] | --remove <email> | --list | --public <view|interact|off>");
1143
- process.exit(1);
1144
- } finally {
1145
- await server.disconnect();
1146
- }
1147
- }
1148
- async function machineShare(machineId, opts) {
1149
- const { server, machine } = await connectAndGetMachine(machineId);
1150
- try {
1151
- if (opts.list) {
1152
- const info = await machine.getMachineInfo();
1153
- const sharing = info.metadata?.sharing;
1154
- if (!sharing || !sharing.enabled) {
1155
- console.log("Sharing is not enabled for this machine.");
1156
- } else {
1157
- console.log(`Owner: ${sharing.owner}`);
1158
- if (sharing.allowedUsers.length === 0) {
1159
- console.log("No shared users.");
1160
- } else {
1161
- console.log("Shared users:");
1162
- for (const u of sharing.allowedUsers) {
1163
- console.log(` ${u.email.padEnd(30)} ${u.role.padEnd(10)} (added ${new Date(u.addedAt).toISOString().slice(0, 10)})`);
1164
- }
1165
- }
1166
- }
1167
- const iso = info.metadata?.isolationCapabilities;
1168
- if (iso) {
1169
- console.log(`
1170
- Isolation: ${iso.available.length > 0 ? iso.available.join(", ") : "none available"} (preferred: ${iso.preferred || "none"})`);
1171
- }
1172
- return;
1173
- }
1174
- if (opts.showConfig) {
1175
- const result = await machine.getSecurityContextConfig();
1176
- const config = result?.securityContextConfig;
1177
- if (!config) {
1178
- console.log("No security context config set for this machine.");
1179
- } else {
1180
- console.log(JSON.stringify(config, null, 2));
1181
- }
1182
- return;
1183
- }
1184
- if (opts.configPath) {
1185
- const configPath = resolve(opts.configPath);
1186
- const config = loadSecurityContextConfig(configPath);
1187
- await machine.updateSecurityContextConfig(config);
1188
- const userCount = config.users ? Object.keys(config.users).length : 0;
1189
- console.log(`Security context config applied to machine.`);
1190
- console.log(` Default context: ${config.default ? "yes" : "none"}`);
1191
- console.log(` User-specific entries: ${userCount}`);
1192
- if (config.users) {
1193
- for (const email of Object.keys(config.users)) {
1194
- const ctx = config.users[email];
1195
- console.log(` ${email}: role=${ctx.role || "default"}`);
1196
- }
1197
- }
1198
- return;
1199
- }
1200
- if (opts.add) {
1201
- const { email, role } = parseShareArg(opts.add);
1202
- const info = await machine.getMachineInfo();
1203
- let sharing = info.metadata?.sharing || {
1204
- enabled: true,
1205
- owner: "",
1206
- allowedUsers: []
1207
- };
1208
- sharing.enabled = true;
1209
- sharing.allowedUsers = sharing.allowedUsers.filter(
1210
- (u) => u.email.toLowerCase() !== email.toLowerCase()
1211
- );
1212
- sharing.allowedUsers.push({
1213
- email,
1214
- role,
1215
- addedAt: Date.now(),
1216
- addedBy: "cli"
1217
- });
1218
- await machine.updateSharing(sharing);
1219
- console.log(`Shared machine with ${email} (${role}).`);
1220
- return;
1221
- }
1222
- if (opts.remove) {
1223
- const email = opts.remove;
1224
- const info = await machine.getMachineInfo();
1225
- const sharing = info.metadata?.sharing;
1226
- if (!sharing) {
1227
- console.error("Sharing is not enabled for this machine.");
1228
- process.exit(1);
1229
- }
1230
- const before = sharing.allowedUsers.length;
1231
- sharing.allowedUsers = sharing.allowedUsers.filter(
1232
- (u) => u.email.toLowerCase() !== email.toLowerCase()
1233
- );
1234
- if (sharing.allowedUsers.length === before) {
1235
- console.error(`User ${email} is not in the shared users list.`);
1236
- process.exit(1);
1237
- }
1238
- await machine.updateSharing(sharing);
1239
- console.log(`Removed ${email} from machine sharing.`);
1240
- return;
1241
- }
1242
- console.error("Usage: svamp machine share --add <email>[:<role>] | --remove <email> | --list | --config <path> | --show-config");
1243
- process.exit(1);
1244
- } finally {
1245
- await server.disconnect();
1246
- }
1247
- }
1248
- async function sessionRalphStart(sessionIdPartial, task, machineId, opts) {
1249
- const { server, machine } = await connectAndGetMachine(machineId);
1250
- try {
1251
- const sessions = await machine.listSessions();
1252
- const match = resolveSessionId(sessions, sessionIdPartial);
1253
- const fullId = match.sessionId;
1254
- const svc = await server.getService(`svamp-session-${fullId}`);
1255
- const { metadata } = await svc.getMetadata();
1256
- if (metadata?.ralphLoop?.active) {
1257
- console.error(`Ralph loop is already active (iteration ${metadata.ralphLoop.currentIteration}). Cancel it first with: svamp session ralph-cancel ${sessionIdPartial}`);
1258
- process.exit(1);
1259
- }
1260
- const completionPromise = opts?.completionPromise || "DONE";
1261
- const maxIterations = opts?.maxIterations ?? 0;
1262
- const cooldownSeconds = opts?.cooldownSeconds ?? 1;
1263
- await svc.updateConfig({
1264
- ralph_loop: {
1265
- task,
1266
- completion_promise: completionPromise,
1267
- max_iterations: maxIterations,
1268
- cooldown_seconds: cooldownSeconds
1269
- }
1270
- });
1271
- console.log(`Ralph loop started on session ${fullId.slice(0, 8)}`);
1272
- console.log(` Task: ${task.slice(0, 100)}${task.length > 100 ? "..." : ""}`);
1273
- console.log(` Completion promise: ${completionPromise}`);
1274
- console.log(` Max iterations: ${maxIterations > 0 ? maxIterations : "unlimited"}`);
1275
- } finally {
1276
- await server.disconnect();
1277
- }
1278
- }
1279
- async function sessionRalphCancel(sessionIdPartial, machineId) {
1280
- const { server, machine } = await connectAndGetMachine(machineId);
1281
- try {
1282
- const sessions = await machine.listSessions();
1283
- const match = resolveSessionId(sessions, sessionIdPartial);
1284
- const fullId = match.sessionId;
1285
- const svc = await server.getService(`svamp-session-${fullId}`);
1286
- const { metadata } = await svc.getMetadata();
1287
- if (!metadata?.ralphLoop?.active) {
1288
- console.log("No active Ralph loop on this session.");
1289
- return;
1290
- }
1291
- const iteration = metadata.ralphLoop.currentIteration;
1292
- await svc.updateConfig({ ralph_loop: null });
1293
- console.log(`Ralph loop cancelled on session ${fullId.slice(0, 8)} (was at iteration ${iteration})`);
1294
- } finally {
1295
- await server.disconnect();
1296
- }
1297
- }
1298
- async function sessionRalphStatus(sessionIdPartial, machineId) {
1299
- const { server, machine } = await connectAndGetMachine(machineId);
1300
- try {
1301
- const sessions = await machine.listSessions();
1302
- const match = resolveSessionId(sessions, sessionIdPartial);
1303
- const fullId = match.sessionId;
1304
- const svc = await server.getService(`svamp-session-${fullId}`);
1305
- const { metadata } = await svc.getMetadata();
1306
- const ralph = metadata?.ralphLoop;
1307
- if (!ralph || !ralph.active) {
1308
- console.log("No Ralph loop configured on this session.");
1309
- return;
1310
- }
1311
- console.log(`Ralph loop on session ${fullId.slice(0, 8)}:`);
1312
- console.log(` Active: ${ralph.active}`);
1313
- console.log(` Task: ${ralph.task?.slice(0, 100)}${ralph.task?.length > 100 ? "..." : ""}`);
1314
- console.log(` Completion promise: ${ralph.completionPromise}`);
1315
- console.log(` Iteration: ${ralph.currentIteration}${ralph.maxIterations > 0 ? `/${ralph.maxIterations}` : " (unlimited)"}`);
1316
- console.log(` Started at: ${ralph.startedAt}`);
1317
- } finally {
1318
- await server.disconnect();
1319
- }
1320
- }
1321
- async function sessionQueueAdd(sessionIdPartial, message, machineId) {
1322
- const { server, machine } = await connectAndGetMachine(machineId);
1323
- try {
1324
- const sessions = await machine.listSessions();
1325
- const match = resolveSessionId(sessions, sessionIdPartial);
1326
- const fullId = match.sessionId;
1327
- const svc = await server.getService(`svamp-session-${fullId}`);
1328
- const { metadata, version } = await svc.getMetadata();
1329
- const existingQueue = metadata?.messageQueue || [];
1330
- const newMsg = {
1331
- id: `cli-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
1332
- text: message,
1333
- createdAt: Date.now()
1334
- };
1335
- const updatedQueue = [...existingQueue, newMsg];
1336
- const updatedMetadata = { ...metadata, messageQueue: updatedQueue };
1337
- const result = await svc.updateMetadata(updatedMetadata, version);
1338
- if (result.result !== "success") {
1339
- console.error(`Failed to add to queue: ${result.result}`);
1340
- process.exit(1);
1341
- }
1342
- console.log(`Message queued on session ${fullId.slice(0, 8)} (${updatedQueue.length} total)`);
1343
- } finally {
1344
- await server.disconnect();
1345
- }
1346
- }
1347
- async function sessionQueueList(sessionIdPartial, machineId) {
1348
- const { server, machine } = await connectAndGetMachine(machineId);
1349
- try {
1350
- const sessions = await machine.listSessions();
1351
- const match = resolveSessionId(sessions, sessionIdPartial);
1352
- const fullId = match.sessionId;
1353
- const svc = await server.getService(`svamp-session-${fullId}`);
1354
- const { metadata } = await svc.getMetadata();
1355
- const queue = metadata?.messageQueue || [];
1356
- if (queue.length === 0) {
1357
- console.log("Queue is empty.");
1358
- return;
1359
- }
1360
- console.log(`Queue for session ${fullId.slice(0, 8)} (${queue.length} messages):`);
1361
- for (let i = 0; i < queue.length; i++) {
1362
- const msg = queue[i];
1363
- const time = new Date(msg.createdAt).toLocaleTimeString();
1364
- console.log(` ${i + 1}. [${time}] ${msg.text.slice(0, 80)}${msg.text.length > 80 ? "..." : ""}`);
1365
- }
1366
- } finally {
1367
- await server.disconnect();
1368
- }
1369
- }
1370
- async function sessionQueueClear(sessionIdPartial, machineId) {
1371
- const { server, machine } = await connectAndGetMachine(machineId);
1372
- try {
1373
- const sessions = await machine.listSessions();
1374
- const match = resolveSessionId(sessions, sessionIdPartial);
1375
- const fullId = match.sessionId;
1376
- const svc = await server.getService(`svamp-session-${fullId}`);
1377
- const { metadata, version } = await svc.getMetadata();
1378
- const count = (metadata?.messageQueue || []).length;
1379
- if (count === 0) {
1380
- console.log("Queue is already empty.");
1381
- return;
1382
- }
1383
- const updatedMetadata = { ...metadata, messageQueue: void 0 };
1384
- const result = await svc.updateMetadata(updatedMetadata, version);
1385
- if (result.result !== "success") {
1386
- console.error(`Failed to clear queue: ${result.result}`);
1387
- process.exit(1);
1388
- }
1389
- console.log(`Cleared ${count} message(s) from queue on session ${fullId.slice(0, 8)}`);
1390
- } finally {
1391
- await server.disconnect();
1392
- }
1393
- }
1394
-
1395
- export { connectAndGetMachine, machineShare, parseShareArg, renderMessage, resolveSessionId, sessionAttach, sessionInfo, sessionList, sessionMachines, sessionMessages, sessionQueueAdd, sessionQueueClear, sessionQueueList, sessionRalphCancel, sessionRalphStart, sessionRalphStatus, sessionSend, sessionShare, sessionSpawn, sessionStop, sessionWait };