svamp-cli 0.1.50 → 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 (311) hide show
  1. package/dist/cli.mjs +25 -22
  2. package/dist/{commands-D-nIO_Sf.mjs → commands-1tmye7o_.mjs} +7 -3
  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-BRivSAkK.mjs} +1 -1
  8. package/dist/{package-BYUO-39f.mjs → package-D7EUXtnk.mjs} +1 -1
  9. package/dist/{run-BE_AIJ7z.mjs → run-BYJX5syg.mjs} +1 -1
  10. package/dist/{run-CE4H8ZiN.mjs → run-BnnUavlu.mjs} +199 -65
  11. package/dist/{run-BG3279Kg.mjs → run-Bw6aGHLA.mjs} +1 -1
  12. package/dist/{run-4li60ojK.mjs → run-DOwarObi.mjs} +1 -1
  13. package/dist/{run-C0ecvcRP.mjs → run-DxISzP_V.mjs} +63 -8
  14. package/dist/{run-Bc83CRUn.mjs → run-eYBOEaWw.mjs} +22 -7
  15. package/dist/tunnel-C2_V6y3d.mjs +299 -0
  16. package/package.json +1 -1
  17. package/dist/commands-4_MiOQVp.mjs +0 -1217
  18. package/dist/commands-8UAWGJrC.mjs +0 -1208
  19. package/dist/commands-8Wmq0uak.mjs +0 -1407
  20. package/dist/commands-8Xn02pQg.mjs +0 -1217
  21. package/dist/commands-9DPsh6ku.mjs +0 -1217
  22. package/dist/commands-9rMB13FP.mjs +0 -1214
  23. package/dist/commands-B-XaqFDB.mjs +0 -1407
  24. package/dist/commands-B53zuBHB.mjs +0 -1217
  25. package/dist/commands-B7yLt11i.mjs +0 -1217
  26. package/dist/commands-BDVAO_N2.mjs +0 -1217
  27. package/dist/commands-BD_NjWJL.mjs +0 -1217
  28. package/dist/commands-BEhSQqTp.mjs +0 -507
  29. package/dist/commands-BIFQZZGw.mjs +0 -1375
  30. package/dist/commands-BImRR1Wr.mjs +0 -1217
  31. package/dist/commands-BLmRIMdf.mjs +0 -1217
  32. package/dist/commands-BOYo9cdy.mjs +0 -1741
  33. package/dist/commands-BQ_347V_.mjs +0 -1374
  34. package/dist/commands-BTEmyf2m.mjs +0 -1407
  35. package/dist/commands-BVjcCbWS.mjs +0 -1375
  36. package/dist/commands-BVsLRttq.mjs +0 -1217
  37. package/dist/commands-BVuE0VQU.mjs +0 -507
  38. package/dist/commands-BY09VTpk.mjs +0 -1375
  39. package/dist/commands-Bcdp0X-o.mjs +0 -1217
  40. package/dist/commands-BdnG1cqQ.mjs +0 -1217
  41. package/dist/commands-BdvvRQIo.mjs +0 -1415
  42. package/dist/commands-Bgg_dvDw.mjs +0 -1683
  43. package/dist/commands-Bi0zYJvj.mjs +0 -1407
  44. package/dist/commands-BmirUCVt.mjs +0 -1208
  45. package/dist/commands-BpSUbvmr.mjs +0 -1217
  46. package/dist/commands-BuJ6xTfc.mjs +0 -1217
  47. package/dist/commands-BzbYPx0f.mjs +0 -1208
  48. package/dist/commands-C-RtFjJl.mjs +0 -1217
  49. package/dist/commands-C20_f6oo.mjs +0 -1217
  50. package/dist/commands-C6KDr9Yp.mjs +0 -1407
  51. package/dist/commands-C9TOoTCv.mjs +0 -1395
  52. package/dist/commands-C9TdN_El.mjs +0 -1683
  53. package/dist/commands-CFv6lO0D.mjs +0 -1217
  54. package/dist/commands-CJ2n5jS2.mjs +0 -1375
  55. package/dist/commands-CKEKQ_5B.mjs +0 -1217
  56. package/dist/commands-CQz67Rm1.mjs +0 -1395
  57. package/dist/commands-CRZbJjqN.mjs +0 -1375
  58. package/dist/commands-CToIvBFX.mjs +0 -1375
  59. package/dist/commands-CWsfciHn.mjs +0 -1217
  60. package/dist/commands-CYMSyqYC.mjs +0 -1395
  61. package/dist/commands-CZ7KPLLJ.mjs +0 -1217
  62. package/dist/commands-Cc73uUnP.mjs +0 -1375
  63. package/dist/commands-CdMsAD1-.mjs +0 -1217
  64. package/dist/commands-CdyCWC3y.mjs +0 -1395
  65. package/dist/commands-ClVCprrK.mjs +0 -1217
  66. package/dist/commands-Cnmf8znA.mjs +0 -1196
  67. package/dist/commands-CorUNLRF.mjs +0 -1375
  68. package/dist/commands-Cq0oj5_v.mjs +0 -1217
  69. package/dist/commands-CrdvbXPI.mjs +0 -1395
  70. package/dist/commands-Cw2Od6mc.mjs +0 -1683
  71. package/dist/commands-CwC2aVzu.mjs +0 -1217
  72. package/dist/commands-CxSCUJCB.mjs +0 -1217
  73. package/dist/commands-D-PTwdZz.mjs +0 -1217
  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-BaGfG8vL.mjs +0 -58
  119. package/dist/package-BkBE6ZdN.mjs +0 -57
  120. package/dist/package-BufekbY1.mjs +0 -57
  121. package/dist/package-C1hpYMj4.mjs +0 -57
  122. package/dist/package-CmIBOZtY.mjs +0 -57
  123. package/dist/package-CmVt1kdw.mjs +0 -58
  124. package/dist/package-Cn6Ya4A0.mjs +0 -57
  125. package/dist/package-Csd530Ym.mjs +0 -57
  126. package/dist/package-D6mNQtUs.mjs +0 -57
  127. package/dist/package-DG0AkZdm.mjs +0 -58
  128. package/dist/package-DRO1LpXW.mjs +0 -58
  129. package/dist/package-Dav8qh6X.mjs +0 -57
  130. package/dist/package-DiA55dzE.mjs +0 -57
  131. package/dist/package-UwLIU765.mjs +0 -58
  132. package/dist/package-k3XsdP9k.mjs +0 -58
  133. package/dist/package-rasGC9_z.mjs +0 -58
  134. package/dist/run-4B1XZQB8.mjs +0 -5426
  135. package/dist/run-4eArMb_9.mjs +0 -1050
  136. package/dist/run-67wfoMuo.mjs +0 -5383
  137. package/dist/run-6N2IdEX7.mjs +0 -5410
  138. package/dist/run-6dwQnoBL.mjs +0 -1051
  139. package/dist/run-7iQKryzo.mjs +0 -5383
  140. package/dist/run-7s8lOXqB.mjs +0 -1050
  141. package/dist/run-8kKykzTs.mjs +0 -5367
  142. package/dist/run-8mLZV2lg.mjs +0 -1050
  143. package/dist/run-9x7I9Ck-.mjs +0 -5264
  144. package/dist/run-B-PWtXF-.mjs +0 -5894
  145. package/dist/run-B1ivovUl.mjs +0 -5964
  146. package/dist/run-B1l9Ed8k.mjs +0 -5403
  147. package/dist/run-B2zRMxE0.mjs +0 -5508
  148. package/dist/run-B31biy0V.mjs +0 -1050
  149. package/dist/run-B5o5fMMd.mjs +0 -5369
  150. package/dist/run-B7V-xXM7.mjs +0 -5775
  151. package/dist/run-B9ND6srh.mjs +0 -6154
  152. package/dist/run-BHZNzX1F.mjs +0 -5235
  153. package/dist/run-BKdOv7gX.mjs +0 -1050
  154. package/dist/run-BLySdZ1K.mjs +0 -5251
  155. package/dist/run-BOVkQfM-.mjs +0 -1050
  156. package/dist/run-BQ0lIare.mjs +0 -1050
  157. package/dist/run-BREPr7Yc.mjs +0 -5508
  158. package/dist/run-BTwshVk1.mjs +0 -5728
  159. package/dist/run-BUL3eAqT.mjs +0 -1050
  160. package/dist/run-BVcPemGr.mjs +0 -5947
  161. package/dist/run-BWqEmIiz.mjs +0 -5964
  162. package/dist/run-BWsDPiNe.mjs +0 -1050
  163. package/dist/run-BX4iy6k8.mjs +0 -1050
  164. package/dist/run-BXYfq8mK.mjs +0 -5836
  165. package/dist/run-BY12Ataq.mjs +0 -5732
  166. package/dist/run-BYDOX4yk.mjs +0 -5402
  167. package/dist/run-Bd-t6s63.mjs +0 -5373
  168. package/dist/run-BenYqfwQ.mjs +0 -5273
  169. package/dist/run-BfF4bgA3.mjs +0 -5403
  170. package/dist/run-Bhh05yic.mjs +0 -5369
  171. package/dist/run-BicITYWX.mjs +0 -6138
  172. package/dist/run-BieEN0Pg.mjs +0 -5761
  173. package/dist/run-BjEQi6PN.mjs +0 -1050
  174. package/dist/run-BjZ6SyFy.mjs +0 -1051
  175. package/dist/run-Bl8OkKyC.mjs +0 -5969
  176. package/dist/run-BlEFlhfn.mjs +0 -5510
  177. package/dist/run-BmL1m0Bk.mjs +0 -1050
  178. package/dist/run-Bmx5wEBF.mjs +0 -1051
  179. package/dist/run-BnX5Rw8x.mjs +0 -5403
  180. package/dist/run-BpjmHeht.mjs +0 -1050
  181. package/dist/run-BxTdRjCG.mjs +0 -1051
  182. package/dist/run-ByOVDgvx.mjs +0 -6115
  183. package/dist/run-BzRP6Q5t.mjs +0 -1051
  184. package/dist/run-C0dyMP62.mjs +0 -1051
  185. package/dist/run-C1lS3SwN.mjs +0 -5733
  186. package/dist/run-C3PAp02X.mjs +0 -5252
  187. package/dist/run-C3eaYQub.mjs +0 -1050
  188. package/dist/run-C4pdX4sY.mjs +0 -1051
  189. package/dist/run-C676pHe-.mjs +0 -5423
  190. package/dist/run-C8GkzcfP.mjs +0 -1050
  191. package/dist/run-C9Hrqjy_.mjs +0 -1050
  192. package/dist/run-CC2C8P-U.mjs +0 -6031
  193. package/dist/run-CCcW4asS.mjs +0 -1050
  194. package/dist/run-CDBKhQ1Z.mjs +0 -1051
  195. package/dist/run-CEB6sYzn.mjs +0 -5962
  196. package/dist/run-CF6aXLmA.mjs +0 -5445
  197. package/dist/run-CHyN5U0t.mjs +0 -1050
  198. package/dist/run-CIFezmkC.mjs +0 -5949
  199. package/dist/run-CLA9zw7J.mjs +0 -5907
  200. package/dist/run-COWb9ovq.mjs +0 -1050
  201. package/dist/run-CSUAy5T5.mjs +0 -1051
  202. package/dist/run-CSk7i0Hq.mjs +0 -1050
  203. package/dist/run-CUtqSGWJ.mjs +0 -1050
  204. package/dist/run-CXrEt0TM.mjs +0 -5008
  205. package/dist/run-CY8Y0JPW.mjs +0 -5287
  206. package/dist/run-CZCKBcQ-.mjs +0 -5244
  207. package/dist/run-CZj0sRCs.mjs +0 -1050
  208. package/dist/run-C_1x2cNU.mjs +0 -5381
  209. package/dist/run-C_8iOjO1.mjs +0 -5892
  210. package/dist/run-C_KIew8H.mjs +0 -1051
  211. package/dist/run-CajRcN3C.mjs +0 -1050
  212. package/dist/run-CbzXO7fw.mjs +0 -1050
  213. package/dist/run-CcSr4x2f.mjs +0 -1050
  214. package/dist/run-CcYaXgCy.mjs +0 -6091
  215. package/dist/run-CdihMx0V.mjs +0 -1051
  216. package/dist/run-Cf2Dl_ck.mjs +0 -1051
  217. package/dist/run-CjH1H4vq.mjs +0 -1050
  218. package/dist/run-CkbDK6jA.mjs +0 -1051
  219. package/dist/run-Ckh6JE9F.mjs +0 -1050
  220. package/dist/run-Ckyg9-fm.mjs +0 -6079
  221. package/dist/run-CqL3ZWdr.mjs +0 -5381
  222. package/dist/run-Csj7sJAh.mjs +0 -1050
  223. package/dist/run-Ct--DWF1.mjs +0 -1051
  224. package/dist/run-CtJRxaFC.mjs +0 -1051
  225. package/dist/run-CuIMdkKF.mjs +0 -6099
  226. package/dist/run-CuckJGM-.mjs +0 -1050
  227. package/dist/run-CxGAa9MH.mjs +0 -1050
  228. package/dist/run-CyU4-O-e.mjs +0 -5411
  229. package/dist/run-CymDyu2b.mjs +0 -5389
  230. package/dist/run-CzIY4_RE.mjs +0 -6093
  231. package/dist/run-D0Ha4aWt.mjs +0 -1050
  232. package/dist/run-D0ow-xms.mjs +0 -5905
  233. package/dist/run-D1PFrNZB.mjs +0 -6273
  234. package/dist/run-D2X3jEqg.mjs +0 -1051
  235. package/dist/run-D39C7Ta3.mjs +0 -1050
  236. package/dist/run-D3Lqxasl.mjs +0 -1051
  237. package/dist/run-D3bhRCCb.mjs +0 -1051
  238. package/dist/run-D5N42sVA.mjs +0 -1050
  239. package/dist/run-D691XPXy.mjs +0 -6031
  240. package/dist/run-D7dLDpq3.mjs +0 -5403
  241. package/dist/run-D8mQ_fL5.mjs +0 -1050
  242. package/dist/run-DA-YBjNw.mjs +0 -6018
  243. package/dist/run-DByI8mI0.mjs +0 -1051
  244. package/dist/run-DCINWip4.mjs +0 -1050
  245. package/dist/run-DCrZ3vke.mjs +0 -5406
  246. package/dist/run-DDF-tRbn.mjs +0 -5954
  247. package/dist/run-DGSgljJE.mjs +0 -5421
  248. package/dist/run-DGsXW19O.mjs +0 -5541
  249. package/dist/run-DHrF2xpW.mjs +0 -5776
  250. package/dist/run-DIB0W42M.mjs +0 -1050
  251. package/dist/run-DJ4k0WzZ.mjs +0 -1051
  252. package/dist/run-DMI83W7i.mjs +0 -5434
  253. package/dist/run-DNX3djCI.mjs +0 -1050
  254. package/dist/run-DOPaGRT2.mjs +0 -6027
  255. package/dist/run-DP7KSZqR.mjs +0 -1051
  256. package/dist/run-DQ0yljWr.mjs +0 -1050
  257. package/dist/run-DTkldU6a.mjs +0 -1050
  258. package/dist/run-DU10B3gK.mjs +0 -5728
  259. package/dist/run-DV86VJNG.mjs +0 -5386
  260. package/dist/run-DVZGKdKO.mjs +0 -1050
  261. package/dist/run-DWdtp6VD.mjs +0 -6136
  262. package/dist/run-DWzA1gZ-.mjs +0 -1050
  263. package/dist/run-DXJ2M19k.mjs +0 -1050
  264. package/dist/run-DZOeccNu.mjs +0 -5484
  265. package/dist/run-D_W5YF0D.mjs +0 -6046
  266. package/dist/run-DaReJPf8.mjs +0 -1051
  267. package/dist/run-DaYrEeQ9.mjs +0 -5400
  268. package/dist/run-DbC9-WM4.mjs +0 -1050
  269. package/dist/run-Dd9XkswU.mjs +0 -1051
  270. package/dist/run-De-wkVl3.mjs +0 -5487
  271. package/dist/run-DfU2luyX.mjs +0 -1050
  272. package/dist/run-Dfl3Ze2L.mjs +0 -5541
  273. package/dist/run-DfuHUDIJ.mjs +0 -1051
  274. package/dist/run-DfwfyFqj.mjs +0 -5975
  275. package/dist/run-DgUDGHZy.mjs +0 -1051
  276. package/dist/run-Dge2K7h1.mjs +0 -1050
  277. package/dist/run-Di3I0USw.mjs +0 -1050
  278. package/dist/run-Dm3U4FB5.mjs +0 -6018
  279. package/dist/run-Du0YOs48.mjs +0 -5446
  280. package/dist/run-DuaIQAE4.mjs +0 -5392
  281. package/dist/run-Dwm19YhI.mjs +0 -1050
  282. package/dist/run-DxM7xaBa.mjs +0 -1050
  283. package/dist/run-DysN-cGm.mjs +0 -1050
  284. package/dist/run-DzXohf8-.mjs +0 -1051
  285. package/dist/run-E_MwVOtN.mjs +0 -5272
  286. package/dist/run-FPoL2-FD.mjs +0 -5381
  287. package/dist/run-HU4XjZfs.mjs +0 -6023
  288. package/dist/run-HhiYlJuS.mjs +0 -5414
  289. package/dist/run-JXLlRLFb.mjs +0 -1050
  290. package/dist/run-K-_jahIg.mjs +0 -1051
  291. package/dist/run-K_S7pfZ-.mjs +0 -1050
  292. package/dist/run-LDiT4WF-.mjs +0 -1050
  293. package/dist/run-NToLJWx-.mjs +0 -5442
  294. package/dist/run-RBufRqbs.mjs +0 -1050
  295. package/dist/run-YFYpyThQ.mjs +0 -1051
  296. package/dist/run-YG1Pb9dY.mjs +0 -5385
  297. package/dist/run-ZDa17iLg.mjs +0 -6060
  298. package/dist/run-ZN0qMdS_.mjs +0 -1051
  299. package/dist/run-azpFWM6w.mjs +0 -1050
  300. package/dist/run-coIDvBK_.mjs +0 -6127
  301. package/dist/run-jLp4pbTE.mjs +0 -1050
  302. package/dist/run-m3oAuSg0.mjs +0 -1050
  303. package/dist/run-r9CAcL_U.mjs +0 -5403
  304. package/dist/run-v32uF2bP.mjs +0 -5378
  305. package/dist/run-vTsskoZc.mjs +0 -5340
  306. package/dist/run-vt26p5D7.mjs +0 -1050
  307. package/dist/run-vvQiCHpi.mjs +0 -5427
  308. package/dist/run-w-HVv5py.mjs +0 -5410
  309. package/dist/run-wpUutZ9C.mjs +0 -1051
  310. package/dist/run-yTjJ7noq.mjs +0 -1051
  311. 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 };