@redscope-ai/redscope 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (619) hide show
  1. package/README.md +224 -0
  2. package/dist/chunk-090920rk.js +288 -0
  3. package/dist/chunk-0afb2r78.js +141 -0
  4. package/dist/chunk-0d4ekx1g.js +73 -0
  5. package/dist/chunk-0g6nwbhq.js +15 -0
  6. package/dist/chunk-0qj905nt.js +18 -0
  7. package/dist/chunk-0s5btnn1.js +186 -0
  8. package/dist/chunk-0s8fars0.js +91 -0
  9. package/dist/chunk-10ev3dvh.js +312 -0
  10. package/dist/chunk-10k5jfc5.js +1295 -0
  11. package/dist/chunk-12tspwqa.js +240 -0
  12. package/dist/chunk-13qesvnw.js +17 -0
  13. package/dist/chunk-143eh1e0.js +121 -0
  14. package/dist/chunk-14p6wvsq.js +39 -0
  15. package/dist/chunk-19f3zb1m.js +342 -0
  16. package/dist/chunk-1a5cep8h.js +145 -0
  17. package/dist/chunk-1abw9kkn.js +34 -0
  18. package/dist/chunk-1aer7c78.js +118 -0
  19. package/dist/chunk-1dazz4g6.js +154 -0
  20. package/dist/chunk-1fcf4ty1.js +142 -0
  21. package/dist/chunk-1gnxhyf8.js +62 -0
  22. package/dist/chunk-1he3944e.js +8124 -0
  23. package/dist/chunk-1jpayz7y.js +952 -0
  24. package/dist/chunk-1qd6f6vk.js +269 -0
  25. package/dist/chunk-1v0kpe62.js +2547 -0
  26. package/dist/chunk-1w20m7gw.js +445 -0
  27. package/dist/chunk-1y7kp51j.js +72 -0
  28. package/dist/chunk-1ycb5sxt.js +247 -0
  29. package/dist/chunk-1zbwhcbt.js +1124 -0
  30. package/dist/chunk-20psem54.js +116 -0
  31. package/dist/chunk-23h69r5b.js +30 -0
  32. package/dist/chunk-23x86ptv.js +473 -0
  33. package/dist/chunk-24fyv3jz.js +378 -0
  34. package/dist/chunk-24kv69g3.js +97 -0
  35. package/dist/chunk-2azx8zsc.js +125 -0
  36. package/dist/chunk-2d1gwzz9.js +524 -0
  37. package/dist/chunk-2g0ytd9d.js +29058 -0
  38. package/dist/chunk-2hfp9kat.js +21 -0
  39. package/dist/chunk-2j875eq6.js +37 -0
  40. package/dist/chunk-2kcgxnvp.js +39 -0
  41. package/dist/chunk-2kz09j2s.js +23 -0
  42. package/dist/chunk-2mwnwp0n.js +17 -0
  43. package/dist/chunk-2p1cqhcn.js +921 -0
  44. package/dist/chunk-2p369q9z.js +61 -0
  45. package/dist/chunk-2rf6asgf.js +151 -0
  46. package/dist/chunk-2vr7mqx1.js +384 -0
  47. package/dist/chunk-2xcg933e.js +205 -0
  48. package/dist/chunk-2ypwckbz.js +40310 -0
  49. package/dist/chunk-30wnahyg.js +626 -0
  50. package/dist/chunk-326zehp8.js +204 -0
  51. package/dist/chunk-32s6jzgw.js +183 -0
  52. package/dist/chunk-35yzt1a7.js +202 -0
  53. package/dist/chunk-38frkej6.js +62 -0
  54. package/dist/chunk-3abaq08g.js +34 -0
  55. package/dist/chunk-3h59ttr5.js +32 -0
  56. package/dist/chunk-3nk9q8dr.js +154 -0
  57. package/dist/chunk-3prrxevm.js +224 -0
  58. package/dist/chunk-3tv8p9xw.js +127 -0
  59. package/dist/chunk-3txyekes.js +19 -0
  60. package/dist/chunk-3vfxjn7g.js +19 -0
  61. package/dist/chunk-3w9sye8h.js +81 -0
  62. package/dist/chunk-3y69j7y8.js +24 -0
  63. package/dist/chunk-3zwjpkjh.js +1603 -0
  64. package/dist/chunk-40t1d75v.js +3442 -0
  65. package/dist/chunk-470kmby4.js +318 -0
  66. package/dist/chunk-47jc141z.js +335 -0
  67. package/dist/chunk-48rz50ct.js +868 -0
  68. package/dist/chunk-49wv03ts.js +232 -0
  69. package/dist/chunk-4a189mn2.js +103 -0
  70. package/dist/chunk-4c4fmh7a.js +15 -0
  71. package/dist/chunk-4ct8dsj5.js +49 -0
  72. package/dist/chunk-4kqt1pm1.js +100 -0
  73. package/dist/chunk-4ng0xy0e.js +802 -0
  74. package/dist/chunk-4spgkgr3.js +43 -0
  75. package/dist/chunk-4tjdwtyy.js +19 -0
  76. package/dist/chunk-4tr60273.js +370 -0
  77. package/dist/chunk-4vnaeng5.js +29 -0
  78. package/dist/chunk-4wbqpeaw.js +871 -0
  79. package/dist/chunk-4wgkv3fv.js +1140 -0
  80. package/dist/chunk-4yjskjb6.js +40 -0
  81. package/dist/chunk-50m3a23z.js +35 -0
  82. package/dist/chunk-511f79az.js +182 -0
  83. package/dist/chunk-51sgztvv.js +161 -0
  84. package/dist/chunk-563fcpv1.js +290 -0
  85. package/dist/chunk-564cnq6v.js +735 -0
  86. package/dist/chunk-569r8cxc.js +31 -0
  87. package/dist/chunk-570x55d4.js +12 -0
  88. package/dist/chunk-571556cm.js +80 -0
  89. package/dist/chunk-59t4c56e.js +63 -0
  90. package/dist/chunk-5axjhkma.js +36 -0
  91. package/dist/chunk-5b188q5e.js +157 -0
  92. package/dist/chunk-5dmn1865.js +439 -0
  93. package/dist/chunk-5ks4829r.js +267 -0
  94. package/dist/chunk-5mmhfbxb.js +1078 -0
  95. package/dist/chunk-5rdt14hy.js +742 -0
  96. package/dist/chunk-5ssryexj.js +121 -0
  97. package/dist/chunk-5v95pnq4.js +15 -0
  98. package/dist/chunk-5xvjt2t9.js +68 -0
  99. package/dist/chunk-5zyq6t1q.js +118 -0
  100. package/dist/chunk-60fkafk2.js +15 -0
  101. package/dist/chunk-62fjkf5q.js +46 -0
  102. package/dist/chunk-64gazrrb.js +8067 -0
  103. package/dist/chunk-65tq2yjx.js +126 -0
  104. package/dist/chunk-65zbgg1n.js +14 -0
  105. package/dist/chunk-66v8mty3.js +264 -0
  106. package/dist/chunk-6acx5heq.js +292 -0
  107. package/dist/chunk-6hr7742d.js +61 -0
  108. package/dist/chunk-6hygvrhn.js +143 -0
  109. package/dist/chunk-6kjh280m.js +128 -0
  110. package/dist/chunk-6s0q1s5r.js +66 -0
  111. package/dist/chunk-6x35ffpx.js +690 -0
  112. package/dist/chunk-71jfy1hh.js +570 -0
  113. package/dist/chunk-71sdcaq6.js +15 -0
  114. package/dist/chunk-754qdxs5.js +92 -0
  115. package/dist/chunk-79v5bkj4.js +1176 -0
  116. package/dist/chunk-7br0w7j5.js +151 -0
  117. package/dist/chunk-7cjgrzz1.js +298 -0
  118. package/dist/chunk-7d41ks0y.js +133 -0
  119. package/dist/chunk-7f40pmtr.js +71 -0
  120. package/dist/chunk-7g15x8hm.js +131 -0
  121. package/dist/chunk-7gtnzdet.js +120 -0
  122. package/dist/chunk-7h0z4aqx.js +702 -0
  123. package/dist/chunk-7h7e5a7d.js +25 -0
  124. package/dist/chunk-7m2cznwr.js +40 -0
  125. package/dist/chunk-7nvday0n.js +252 -0
  126. package/dist/chunk-7qey87th.js +145 -0
  127. package/dist/chunk-7qx3xhv3.js +9076 -0
  128. package/dist/chunk-7tfdhkpy.js +61 -0
  129. package/dist/chunk-80m511j6.js +121 -0
  130. package/dist/chunk-80ysxfe9.js +784 -0
  131. package/dist/chunk-8375zk8t.js +17200 -0
  132. package/dist/chunk-85bpkyy9.js +412 -0
  133. package/dist/chunk-85tcn547.js +876 -0
  134. package/dist/chunk-85vqgbc8.js +13 -0
  135. package/dist/chunk-86626jb4.js +49 -0
  136. package/dist/chunk-87ms17f6.js +444 -0
  137. package/dist/chunk-87mz239c.js +118 -0
  138. package/dist/chunk-89vdzt4e.js +254 -0
  139. package/dist/chunk-89z3e99z.js +159 -0
  140. package/dist/chunk-8cwrz1dd.js +1806 -0
  141. package/dist/chunk-8gv2pjby.js +21 -0
  142. package/dist/chunk-8hdevr3s.js +140 -0
  143. package/dist/chunk-8hdsk6qc.js +710 -0
  144. package/dist/chunk-8kct9arg.js +724 -0
  145. package/dist/chunk-8kf8h7xf.js +23 -0
  146. package/dist/chunk-8qed8ymj.js +605 -0
  147. package/dist/chunk-8sdgr592.js +101 -0
  148. package/dist/chunk-8we9w8pw.js +111 -0
  149. package/dist/chunk-8xnm5637.js +72 -0
  150. package/dist/chunk-8y3q0eqy.js +67 -0
  151. package/dist/chunk-8yvsnrkr.js +3449 -0
  152. package/dist/chunk-8zz4z1q3.js +42 -0
  153. package/dist/chunk-90eyff3k.js +119 -0
  154. package/dist/chunk-92bjkrf2.js +121 -0
  155. package/dist/chunk-92zrc7c6.js +327 -0
  156. package/dist/chunk-935nrvdb.js +13 -0
  157. package/dist/chunk-94pfyv6a.js +48 -0
  158. package/dist/chunk-9568p8se.js +115 -0
  159. package/dist/chunk-96km1ywr.js +37 -0
  160. package/dist/chunk-980bg4w4.js +163 -0
  161. package/dist/chunk-9a9g5hbj.js +205 -0
  162. package/dist/chunk-9cm4725d.js +4395 -0
  163. package/dist/chunk-9ds3vzq8.js +847 -0
  164. package/dist/chunk-9ffc9n60.js +618 -0
  165. package/dist/chunk-9fstrwv2.js +184 -0
  166. package/dist/chunk-9gt0g0qe.js +153 -0
  167. package/dist/chunk-9h9k5vz3.js +2761 -0
  168. package/dist/chunk-9he8bmhy.js +17 -0
  169. package/dist/chunk-9hn8e6h1.js +12 -0
  170. package/dist/chunk-9j0n3g8e.js +179 -0
  171. package/dist/chunk-9j6pa3ft.js +251 -0
  172. package/dist/chunk-9jpg9dn7.js +122 -0
  173. package/dist/chunk-9mycnwj5.js +46 -0
  174. package/dist/chunk-9npy2c17.js +517 -0
  175. package/dist/chunk-9p6sec8n.js +34 -0
  176. package/dist/chunk-9pnym83h.js +4584 -0
  177. package/dist/chunk-9skwrnd2.js +25 -0
  178. package/dist/chunk-9tsfaqr8.js +459 -0
  179. package/dist/chunk-9tsw3cqv.js +5924 -0
  180. package/dist/chunk-9w6ckyk4.js +49 -0
  181. package/dist/chunk-a15bwzv6.js +147 -0
  182. package/dist/chunk-a9t6cp69.js +28 -0
  183. package/dist/chunk-ad2yk19p.js +102 -0
  184. package/dist/chunk-ad4cw4nw.js +336 -0
  185. package/dist/chunk-ad69fbsk.js +347 -0
  186. package/dist/chunk-ae76ded0.js +30 -0
  187. package/dist/chunk-aeysytks.js +216 -0
  188. package/dist/chunk-ag81m9bq.js +61 -0
  189. package/dist/chunk-ahx7gp6r.js +4448 -0
  190. package/dist/chunk-aj4tk4tk.js +23 -0
  191. package/dist/chunk-an82t9jc.js +104 -0
  192. package/dist/chunk-apg95qd7.js +1393 -0
  193. package/dist/chunk-aq5n2adz.js +27 -0
  194. package/dist/chunk-aw4s3a99.js +208 -0
  195. package/dist/chunk-awgdfggg.js +14 -0
  196. package/dist/chunk-ayymxgn1.js +164 -0
  197. package/dist/chunk-azbab59e.js +637 -0
  198. package/dist/chunk-azdxq2a3.js +293 -0
  199. package/dist/chunk-b0tjx3k1.js +523 -0
  200. package/dist/chunk-b5pp4g2g.js +371 -0
  201. package/dist/chunk-b5zm8dt6.js +26 -0
  202. package/dist/chunk-bcnye5a0.js +109 -0
  203. package/dist/chunk-beqz3k49.js +190 -0
  204. package/dist/chunk-bf906wpw.js +147 -0
  205. package/dist/chunk-bgan4cpf.js +13 -0
  206. package/dist/chunk-bhzp13h7.js +1178 -0
  207. package/dist/chunk-bk403kpw.js +142 -0
  208. package/dist/chunk-bmq4c135.js +489 -0
  209. package/dist/chunk-bprbeda7.js +35 -0
  210. package/dist/chunk-bst7czdd.js +888 -0
  211. package/dist/chunk-bths4xgn.js +111 -0
  212. package/dist/chunk-btjn3qby.js +13 -0
  213. package/dist/chunk-bwb1vxnt.js +120 -0
  214. package/dist/chunk-bxa6tw4m.js +643 -0
  215. package/dist/chunk-bxfjr8qb.js +27 -0
  216. package/dist/chunk-bxpzhrej.js +73 -0
  217. package/dist/chunk-bzyzrq0k.js +51 -0
  218. package/dist/chunk-c0k7b0jw.js +4265 -0
  219. package/dist/chunk-c17f0h2s.js +16 -0
  220. package/dist/chunk-c1yc761e.js +6748 -0
  221. package/dist/chunk-c5g9shkw.js +298 -0
  222. package/dist/chunk-c696122m.js +69 -0
  223. package/dist/chunk-c92b3yxx.js +109 -0
  224. package/dist/chunk-c9aqz56y.js +143 -0
  225. package/dist/chunk-cba7c5w3.js +345 -0
  226. package/dist/chunk-cbcxbbe6.js +6543 -0
  227. package/dist/chunk-cdfjb87h.js +11 -0
  228. package/dist/chunk-ce8zjt1y.js +136 -0
  229. package/dist/chunk-cep7e37k.js +22740 -0
  230. package/dist/chunk-chs5qm8d.js +258 -0
  231. package/dist/chunk-ckydq33g.js +144 -0
  232. package/dist/chunk-cnge6wpj.js +514 -0
  233. package/dist/chunk-cpnsvqf1.js +13 -0
  234. package/dist/chunk-cqqebkv4.js +32 -0
  235. package/dist/chunk-cvqpp7dk.js +627 -0
  236. package/dist/chunk-cwc33j40.js +65 -0
  237. package/dist/chunk-cypvrq2a.js +155 -0
  238. package/dist/chunk-d1ha0swn.js +475 -0
  239. package/dist/chunk-d2an0138.js +35 -0
  240. package/dist/chunk-d2tt72ck.js +343 -0
  241. package/dist/chunk-d6wvcqrw.js +9507 -0
  242. package/dist/chunk-d7ys2kka.js +991 -0
  243. package/dist/chunk-dbts5q5p.js +122 -0
  244. package/dist/chunk-dct29ggs.js +295 -0
  245. package/dist/chunk-de0qnnf7.js +1059 -0
  246. package/dist/chunk-dep72ce4.js +513 -0
  247. package/dist/chunk-dgpvgy8x.js +47 -0
  248. package/dist/chunk-dhhd7dtc.js +20 -0
  249. package/dist/chunk-dhzpmxv6.js +594 -0
  250. package/dist/chunk-djes4da7.js +413 -0
  251. package/dist/chunk-dnhv3vx7.js +166 -0
  252. package/dist/chunk-dqtvafan.js +2365 -0
  253. package/dist/chunk-dr4a3tcp.js +60 -0
  254. package/dist/chunk-dz2xk9kb.js +100 -0
  255. package/dist/chunk-dz7nc6rf.js +15 -0
  256. package/dist/chunk-e3abfxpy.js +1486 -0
  257. package/dist/chunk-e3cq9z89.js +85 -0
  258. package/dist/chunk-e3j7m7k2.js +642 -0
  259. package/dist/chunk-e4dsy4g1.js +9951 -0
  260. package/dist/chunk-e5592pnn.js +197 -0
  261. package/dist/chunk-e55hdegh.js +129 -0
  262. package/dist/chunk-e5r5r04e.js +1030 -0
  263. package/dist/chunk-e60zztbt.js +442 -0
  264. package/dist/chunk-e7qq6vn0.js +372 -0
  265. package/dist/chunk-e9aat7xw.js +80 -0
  266. package/dist/chunk-e9d5v3zs.js +143 -0
  267. package/dist/chunk-eax32zk4.js +87 -0
  268. package/dist/chunk-ebfwmbx1.js +117 -0
  269. package/dist/chunk-ec71pb8t.js +971 -0
  270. package/dist/chunk-eemjb825.js +17252 -0
  271. package/dist/chunk-ees8xdhd.js +256 -0
  272. package/dist/chunk-eewg66y1.js +112 -0
  273. package/dist/chunk-eg22v12d.js +266 -0
  274. package/dist/chunk-enzzk67f.js +313 -0
  275. package/dist/chunk-eskhp70f.js +117 -0
  276. package/dist/chunk-ewx6z4g8.js +55 -0
  277. package/dist/chunk-eyvx461k.js +76 -0
  278. package/dist/chunk-eztq2b5f.js +94 -0
  279. package/dist/chunk-f0ffwzdd.js +321 -0
  280. package/dist/chunk-f80n68mf.js +119 -0
  281. package/dist/chunk-fae2hjxp.js +99 -0
  282. package/dist/chunk-fbtfp370.js +60 -0
  283. package/dist/chunk-fc6ndtgf.js +94 -0
  284. package/dist/chunk-fdwabr8p.js +13870 -0
  285. package/dist/chunk-fejeqe61.js +785 -0
  286. package/dist/chunk-fh0d6mvk.js +168 -0
  287. package/dist/chunk-fh19zcaf.js +304 -0
  288. package/dist/chunk-fh8bd39r.js +186 -0
  289. package/dist/chunk-fj2ebbpn.js +33 -0
  290. package/dist/chunk-fjn632v7.js +194 -0
  291. package/dist/chunk-fncpkzs5.js +1389 -0
  292. package/dist/chunk-fpd1gpt8.js +332 -0
  293. package/dist/chunk-fq9snrnh.js +295 -0
  294. package/dist/chunk-fqcfzg3j.js +207 -0
  295. package/dist/chunk-ftt3vqj2.js +1919 -0
  296. package/dist/chunk-g06pm4n9.js +395 -0
  297. package/dist/chunk-g4m5pf4g.js +8 -0
  298. package/dist/chunk-g72h52y6.js +36 -0
  299. package/dist/chunk-g79ej71s.js +1627 -0
  300. package/dist/chunk-g7fwk59d.js +19 -0
  301. package/dist/chunk-g9jnkrtm.js +663 -0
  302. package/dist/chunk-g9vg5d7t.js +38 -0
  303. package/dist/chunk-ga1jkyqy.js +1636 -0
  304. package/dist/chunk-gaaap2nk.js +676 -0
  305. package/dist/chunk-gc6erq5q.js +483 -0
  306. package/dist/chunk-gjrcmf0a.js +752 -0
  307. package/dist/chunk-gmdy2w3z.js +238999 -0
  308. package/dist/chunk-gsz4yrrk.js +81 -0
  309. package/dist/chunk-gy47rjy8.js +3830 -0
  310. package/dist/chunk-h12a4f4x.js +11 -0
  311. package/dist/chunk-h1yratmg.js +725 -0
  312. package/dist/chunk-h9y0jnsy.js +155 -0
  313. package/dist/chunk-hbhs3mwy.js +133 -0
  314. package/dist/chunk-hbs8cmb4.js +8 -0
  315. package/dist/chunk-hdk0t1ht.js +940 -0
  316. package/dist/chunk-hef8dx4s.js +178 -0
  317. package/dist/chunk-hgsca8mt.js +381 -0
  318. package/dist/chunk-hhsxm2yr.js +67 -0
  319. package/dist/chunk-hj5tzzpd.js +39 -0
  320. package/dist/chunk-hjxqmtg5.js +94 -0
  321. package/dist/chunk-hn4w9pkj.js +68 -0
  322. package/dist/chunk-hnprkjgp.js +25 -0
  323. package/dist/chunk-hq3n5ex7.js +183 -0
  324. package/dist/chunk-hqjspfma.js +158 -0
  325. package/dist/chunk-hqxp6b72.js +1198 -0
  326. package/dist/chunk-hs6nrmq6.js +94 -0
  327. package/dist/chunk-hwba5xdc.js +267 -0
  328. package/dist/chunk-hy566ev3.js +430 -0
  329. package/dist/chunk-hzmzwte2.js +153 -0
  330. package/dist/chunk-hzxzvzw8.js +274 -0
  331. package/dist/chunk-j139fzgs.js +114 -0
  332. package/dist/chunk-j1mep9ck.js +62 -0
  333. package/dist/chunk-j3xveeg4.js +273 -0
  334. package/dist/chunk-j5y1s11j.js +100 -0
  335. package/dist/chunk-j9475b46.js +26 -0
  336. package/dist/chunk-j9rgqs8m.js +1192 -0
  337. package/dist/chunk-jccjaddz.js +74 -0
  338. package/dist/chunk-jdkwfy9e.js +35 -0
  339. package/dist/chunk-jdqp0r4h.js +6157 -0
  340. package/dist/chunk-jdzk4zwn.js +587 -0
  341. package/dist/chunk-jfafmkte.js +49 -0
  342. package/dist/chunk-jg3r989b.js +16 -0
  343. package/dist/chunk-jhtccjc9.js +54 -0
  344. package/dist/chunk-jj2ff1pr.js +688 -0
  345. package/dist/chunk-jmv7k0jn.js +37 -0
  346. package/dist/chunk-jmxzmwpw.js +65 -0
  347. package/dist/chunk-jnjxdqyr.js +353 -0
  348. package/dist/chunk-jsbbez9j.js +138 -0
  349. package/dist/chunk-jvpt2dc0.js +424 -0
  350. package/dist/chunk-jwd7cka0.js +34 -0
  351. package/dist/chunk-jy5er3st.js +15 -0
  352. package/dist/chunk-jyby79z5.js +121 -0
  353. package/dist/chunk-jzyr6j5n.js +332 -0
  354. package/dist/chunk-k49xc781.js +63 -0
  355. package/dist/chunk-k7dt2g4a.js +41 -0
  356. package/dist/chunk-k7hexw3v.js +969 -0
  357. package/dist/chunk-k7wwkraa.js +117 -0
  358. package/dist/chunk-kb3758f7.js +51 -0
  359. package/dist/chunk-kc67kt75.js +3119 -0
  360. package/dist/chunk-kdhmfxmh.js +3149 -0
  361. package/dist/chunk-kejdd6zc.js +51 -0
  362. package/dist/chunk-kekrjeem.js +402 -0
  363. package/dist/chunk-kez5r0zz.js +280 -0
  364. package/dist/chunk-kfsvcs5t.js +75 -0
  365. package/dist/chunk-khtvffc4.js +285 -0
  366. package/dist/chunk-kkz4w1tv.js +64 -0
  367. package/dist/chunk-kmywng0j.js +272 -0
  368. package/dist/chunk-kq6vcpdr.js +224 -0
  369. package/dist/chunk-kqzdszcc.js +37 -0
  370. package/dist/chunk-ktxpp02w.js +435 -0
  371. package/dist/chunk-kwcvhbtz.js +26 -0
  372. package/dist/chunk-kx0cm9qr.js +128 -0
  373. package/dist/chunk-kxcmqz10.js +120 -0
  374. package/dist/chunk-kxwava1g.js +14 -0
  375. package/dist/chunk-kywtr3jg.js +825 -0
  376. package/dist/chunk-kzwg923p.js +8 -0
  377. package/dist/chunk-m1eq3sgv.js +255 -0
  378. package/dist/chunk-m21h5zb4.js +119 -0
  379. package/dist/chunk-m2c3bjv1.js +111 -0
  380. package/dist/chunk-m41e19ms.js +42 -0
  381. package/dist/chunk-m7ka36ex.js +97 -0
  382. package/dist/chunk-m81w8tbm.js +259 -0
  383. package/dist/chunk-m95ggkax.js +281 -0
  384. package/dist/chunk-manx26xa.js +145 -0
  385. package/dist/chunk-mdxh3pk2.js +298 -0
  386. package/dist/chunk-mhbfkcja.js +311 -0
  387. package/dist/chunk-mjnr5erm.js +173 -0
  388. package/dist/chunk-mngvnmwp.js +135 -0
  389. package/dist/chunk-mvfqanv5.js +63 -0
  390. package/dist/chunk-mw1nesq1.js +140 -0
  391. package/dist/chunk-mx168925.js +661 -0
  392. package/dist/chunk-mxwvj18g.js +795 -0
  393. package/dist/chunk-my7r5mba.js +257 -0
  394. package/dist/chunk-myaa1kkf.js +17 -0
  395. package/dist/chunk-myypc3tn.js +46 -0
  396. package/dist/chunk-mzcnmnpq.js +3379 -0
  397. package/dist/chunk-mznav6d1.js +194 -0
  398. package/dist/chunk-n0qxskpr.js +24 -0
  399. package/dist/chunk-n6a6hgtp.js +394 -0
  400. package/dist/chunk-n6d5fgx0.js +254 -0
  401. package/dist/chunk-n6ym3n03.js +120 -0
  402. package/dist/chunk-n9g24mwe.js +104 -0
  403. package/dist/chunk-naamqdf9.js +185 -0
  404. package/dist/chunk-nb2jk7zj.js +15 -0
  405. package/dist/chunk-nbkbq9en.js +67 -0
  406. package/dist/chunk-ndttd6es.js +38 -0
  407. package/dist/chunk-nfygaaxg.js +133 -0
  408. package/dist/chunk-ngdzpszd.js +454 -0
  409. package/dist/chunk-nmfwksa4.js +1297 -0
  410. package/dist/chunk-nt837qt9.js +21 -0
  411. package/dist/chunk-nwc3v0vp.js +691 -0
  412. package/dist/chunk-nz8ha95p.js +3610 -0
  413. package/dist/chunk-nzxfj0gq.js +2007 -0
  414. package/dist/chunk-p0r8887g.js +6932 -0
  415. package/dist/chunk-p1seyqdm.js +120 -0
  416. package/dist/chunk-p425zbgw.js +726 -0
  417. package/dist/chunk-p7hamd2c.js +146 -0
  418. package/dist/chunk-pdvg91cg.js +32 -0
  419. package/dist/chunk-pecy49yr.js +14649 -0
  420. package/dist/chunk-pfxrg89f.js +547 -0
  421. package/dist/chunk-pfyw3155.js +2750 -0
  422. package/dist/chunk-pr8m11pm.js +1192 -0
  423. package/dist/chunk-ptxteaeh.js +1591 -0
  424. package/dist/chunk-pv164mac.js +394 -0
  425. package/dist/chunk-pxxhtxf5.js +10154 -0
  426. package/dist/chunk-q0e485mg.js +61 -0
  427. package/dist/chunk-q1vrhh0q.js +458 -0
  428. package/dist/chunk-q2h79ncs.js +370 -0
  429. package/dist/chunk-q3b4n194.js +56 -0
  430. package/dist/chunk-q44zc68f.js +4301 -0
  431. package/dist/chunk-q8gknbdx.js +352 -0
  432. package/dist/chunk-q8xk3kdj.js +11 -0
  433. package/dist/chunk-qak46xtp.js +119 -0
  434. package/dist/chunk-qfq7absv.js +95 -0
  435. package/dist/chunk-qfsn720k.js +151 -0
  436. package/dist/chunk-qg4811f6.js +228 -0
  437. package/dist/chunk-qgzn3qps.js +90 -0
  438. package/dist/chunk-qhaggqkt.js +113 -0
  439. package/dist/chunk-qjjp27z8.js +195 -0
  440. package/dist/chunk-qxp0nye6.js +34 -0
  441. package/dist/chunk-qy3nagaq.js +4957 -0
  442. package/dist/chunk-qz2meav1.js +1452 -0
  443. package/dist/chunk-r50hne7m.js +63 -0
  444. package/dist/chunk-r6m0vgnv.js +80 -0
  445. package/dist/chunk-r7yw38vf.js +22864 -0
  446. package/dist/chunk-r8xc618w.js +42 -0
  447. package/dist/chunk-r961r5kj.js +87 -0
  448. package/dist/chunk-r9b5xrh0.js +66 -0
  449. package/dist/chunk-rcn2pd6q.js +477 -0
  450. package/dist/chunk-rdeh8p3y.js +148 -0
  451. package/dist/chunk-rg9x1742.js +542 -0
  452. package/dist/chunk-rgyzsbs3.js +39 -0
  453. package/dist/chunk-rk2fsxtz.js +16 -0
  454. package/dist/chunk-rkchkwv9.js +40 -0
  455. package/dist/chunk-rp8whpb3.js +478 -0
  456. package/dist/chunk-rpkxdtgr.js +68 -0
  457. package/dist/chunk-rpmntgyh.js +394 -0
  458. package/dist/chunk-rpshz4dy.js +614 -0
  459. package/dist/chunk-rqd60ay5.js +133 -0
  460. package/dist/chunk-rrsjf2ea.js +229 -0
  461. package/dist/chunk-rtjk8c8e.js +173 -0
  462. package/dist/chunk-rw0y2wdf.js +1017 -0
  463. package/dist/chunk-rx5w7ess.js +663 -0
  464. package/dist/chunk-rx8t9d35.js +1947 -0
  465. package/dist/chunk-rxcazxgf.js +195 -0
  466. package/dist/chunk-rxg6q3bp.js +1413 -0
  467. package/dist/chunk-rxrb7xnd.js +71 -0
  468. package/dist/chunk-rxrzxff3.js +118 -0
  469. package/dist/chunk-ryqjc943.js +71 -0
  470. package/dist/chunk-rzk9k2rf.js +81 -0
  471. package/dist/chunk-s2qv0nht.js +119 -0
  472. package/dist/chunk-s3hafnk3.js +2285 -0
  473. package/dist/chunk-s4a496tt.js +226 -0
  474. package/dist/chunk-s4d1h3ka.js +35 -0
  475. package/dist/chunk-sm3k3ze4.js +16525 -0
  476. package/dist/chunk-sn0bja82.js +385 -0
  477. package/dist/chunk-sngjggw1.js +4227 -0
  478. package/dist/chunk-sq047n34.js +364 -0
  479. package/dist/chunk-sttwe2tw.js +8584 -0
  480. package/dist/chunk-sw8qx1r0.js +86 -0
  481. package/dist/chunk-swstah6a.js +240 -0
  482. package/dist/chunk-syrkr0mf.js +63 -0
  483. package/dist/chunk-sz206bd9.js +26 -0
  484. package/dist/chunk-t09669cj.js +333 -0
  485. package/dist/chunk-t5f8e30k.js +602 -0
  486. package/dist/chunk-t5m78mc8.js +432 -0
  487. package/dist/chunk-t5x1dqwn.js +143 -0
  488. package/dist/chunk-t877ea0w.js +168 -0
  489. package/dist/chunk-t91hb71c.js +17 -0
  490. package/dist/chunk-tb636bcf.js +942 -0
  491. package/dist/chunk-tb8sykbr.js +426 -0
  492. package/dist/chunk-tbdkekz3.js +125 -0
  493. package/dist/chunk-td2gsz7s.js +225 -0
  494. package/dist/chunk-tenvxbyh.js +20 -0
  495. package/dist/chunk-texg4qqt.js +317 -0
  496. package/dist/chunk-teymzz80.js +266 -0
  497. package/dist/chunk-tj26qpf7.js +153 -0
  498. package/dist/chunk-tk85ec4p.js +395 -0
  499. package/dist/chunk-tq205h01.js +164 -0
  500. package/dist/chunk-tqzddjzg.js +61 -0
  501. package/dist/chunk-trqrj23e.js +134 -0
  502. package/dist/chunk-tw1hfsxv.js +2477 -0
  503. package/dist/chunk-txxdfq83.js +122 -0
  504. package/dist/chunk-v0yhe582.js +31 -0
  505. package/dist/chunk-v14184xm.js +15 -0
  506. package/dist/chunk-v1h9z4hw.js +138 -0
  507. package/dist/chunk-v3ey5j7f.js +329 -0
  508. package/dist/chunk-v3nh1sfn.js +208 -0
  509. package/dist/chunk-v3x8tcc0.js +45 -0
  510. package/dist/chunk-v4nqnvqq.js +3984 -0
  511. package/dist/chunk-v4ypszbb.js +15 -0
  512. package/dist/chunk-v7wbqcx9.js +63 -0
  513. package/dist/chunk-v8r5fev3.js +341 -0
  514. package/dist/chunk-v9zg5kzx.js +2810 -0
  515. package/dist/chunk-va1wh5ss.js +24 -0
  516. package/dist/chunk-vbfswhht.js +42 -0
  517. package/dist/chunk-ve7x2tfq.js +124 -0
  518. package/dist/chunk-vfz8k89y.js +485 -0
  519. package/dist/chunk-vgm5k14x.js +35678 -0
  520. package/dist/chunk-vh9pej3c.js +247 -0
  521. package/dist/chunk-vjxqyt6f.js +3820 -0
  522. package/dist/chunk-vpb1xstn.js +178 -0
  523. package/dist/chunk-vqt79tj8.js +110 -0
  524. package/dist/chunk-vr0n9pv9.js +152 -0
  525. package/dist/chunk-vrejmja5.js +90 -0
  526. package/dist/chunk-vrxasmdw.js +449 -0
  527. package/dist/chunk-vrxb946v.js +125 -0
  528. package/dist/chunk-vv4kj0q8.js +98 -0
  529. package/dist/chunk-vvpfng7w.js +8 -0
  530. package/dist/chunk-vw6ybyew.js +2007 -0
  531. package/dist/chunk-vwenx8ke.js +17 -0
  532. package/dist/chunk-vwfa0s5a.js +155 -0
  533. package/dist/chunk-vx71j8xe.js +63 -0
  534. package/dist/chunk-vxbjzggp.js +43 -0
  535. package/dist/chunk-vxjxtz8w.js +440 -0
  536. package/dist/chunk-vy0c1bwp.js +9 -0
  537. package/dist/chunk-w3zczyse.js +14 -0
  538. package/dist/chunk-w4p5t920.js +655 -0
  539. package/dist/chunk-w68wc625.js +287 -0
  540. package/dist/chunk-w9ddp3yf.js +96 -0
  541. package/dist/chunk-wcggm5ja.js +125 -0
  542. package/dist/chunk-wgnyph3q.js +1306 -0
  543. package/dist/chunk-wjm5pc1e.js +134 -0
  544. package/dist/chunk-wnve0drm.js +131 -0
  545. package/dist/chunk-wp27ev2k.js +135 -0
  546. package/dist/chunk-wyvy8a4x.js +131 -0
  547. package/dist/chunk-x671y4dk.js +129 -0
  548. package/dist/chunk-xbj5keyy.js +22 -0
  549. package/dist/chunk-xf4fzms8.js +39 -0
  550. package/dist/chunk-xf59k3zg.js +65 -0
  551. package/dist/chunk-xgzc4w49.js +204 -0
  552. package/dist/chunk-xhj7g13b.js +2149 -0
  553. package/dist/chunk-xjp0cd00.js +56 -0
  554. package/dist/chunk-xkhnmhqs.js +74 -0
  555. package/dist/chunk-xkrkqx61.js +55 -0
  556. package/dist/chunk-xmpgmeb8.js +114 -0
  557. package/dist/chunk-xrw80zgd.js +4249 -0
  558. package/dist/chunk-xrzc96g0.js +202 -0
  559. package/dist/chunk-xt76sm44.js +318 -0
  560. package/dist/chunk-xwet3awb.js +20 -0
  561. package/dist/chunk-xyg1sk2w.js +78 -0
  562. package/dist/chunk-y0jpkqb0.js +180 -0
  563. package/dist/chunk-y1q7rt9n.js +102 -0
  564. package/dist/chunk-y67ntyek.js +258 -0
  565. package/dist/chunk-ybk37qp9.js +37 -0
  566. package/dist/chunk-yc1stfve.js +5386 -0
  567. package/dist/chunk-ychjpjef.js +62 -0
  568. package/dist/chunk-yez8fa9g.js +276 -0
  569. package/dist/chunk-ygm7xszr.js +90 -0
  570. package/dist/chunk-ym11azkj.js +37 -0
  571. package/dist/chunk-ympz2h15.js +578 -0
  572. package/dist/chunk-yqx3az3n.js +129 -0
  573. package/dist/chunk-yt3nfhcc.js +152 -0
  574. package/dist/chunk-yy8q0n8s.js +120 -0
  575. package/dist/chunk-yzb92zxv.js +8 -0
  576. package/dist/chunk-yzet6xyr.js +119 -0
  577. package/dist/chunk-yzm97qp1.js +226 -0
  578. package/dist/chunk-z0jgeax8.js +35 -0
  579. package/dist/chunk-z1r3z6w6.js +29 -0
  580. package/dist/chunk-z2dp53wn.js +17 -0
  581. package/dist/chunk-z79355gz.js +308 -0
  582. package/dist/chunk-z7e94hxz.js +251 -0
  583. package/dist/chunk-z8cqdcec.js +173 -0
  584. package/dist/chunk-z99tbg45.js +148 -0
  585. package/dist/chunk-z9nsjcht.js +37 -0
  586. package/dist/chunk-za3k6h2h.js +470 -0
  587. package/dist/chunk-zacynq5p.js +265 -0
  588. package/dist/chunk-zb0x40az.js +1785 -0
  589. package/dist/chunk-zbxtzycc.js +274 -0
  590. package/dist/chunk-zga50181.js +342 -0
  591. package/dist/chunk-zhb2pns1.js +44 -0
  592. package/dist/chunk-zkch6trx.js +231 -0
  593. package/dist/chunk-znf3z4qt.js +954 -0
  594. package/dist/chunk-zp8zwdgq.js +72 -0
  595. package/dist/chunk-ztjd8pyf.js +120 -0
  596. package/dist/chunk-ztmb7geg.js +173 -0
  597. package/dist/chunk-zvr4snzv.js +887 -0
  598. package/dist/chunk-zw62m6n3.js +34858 -0
  599. package/dist/chunk-zwwdebd0.js +65 -0
  600. package/dist/chunk-zxc6x9w8.js +340 -0
  601. package/dist/chunk-zy2e7sz0.js +8 -0
  602. package/dist/chunk-zzf074w3.js +196 -0
  603. package/dist/chunk-zzz0nwb5.js +310 -0
  604. package/dist/cli-bun.js +2 -0
  605. package/dist/cli-node.js +2 -0
  606. package/dist/cli.js +218 -0
  607. package/dist/vendor/audio-capture/arm64-darwin/audio-capture.node +0 -0
  608. package/dist/vendor/audio-capture/arm64-linux/audio-capture.node +0 -0
  609. package/dist/vendor/audio-capture/arm64-win32/audio-capture.node +0 -0
  610. package/dist/vendor/audio-capture/x64-darwin/audio-capture.node +0 -0
  611. package/dist/vendor/audio-capture/x64-linux/audio-capture.node +0 -0
  612. package/dist/vendor/audio-capture/x64-win32/audio-capture.node +0 -0
  613. package/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
  614. package/package.json +243 -0
  615. package/scripts/chrome-mcp-bridge-resolver.mjs +43 -0
  616. package/scripts/chrome-mcp-env.mjs +19 -0
  617. package/scripts/postinstall.cjs +339 -0
  618. package/scripts/run-parallel.mjs +10 -0
  619. package/scripts/setup-chrome-mcp.mjs +69 -0
@@ -0,0 +1,2477 @@
1
+ // @bun
2
+ import {
3
+ createCapacityWake
4
+ } from "./chunk-ae76ded0.js";
5
+ import {
6
+ getPollIntervalConfig
7
+ } from "./chunk-syrkr0mf.js";
8
+ import {
9
+ buildCCRv2SdkUrl,
10
+ buildSdkUrl,
11
+ decodeWorkSecret,
12
+ registerWorker,
13
+ sameSessionId
14
+ } from "./chunk-cwc33j40.js";
15
+ import {
16
+ createTokenRefreshScheduler
17
+ } from "./chunk-yt3nfhcc.js";
18
+ import {
19
+ getBootstrapArgs,
20
+ getScriptPath,
21
+ init_cliLaunch
22
+ } from "./chunk-4kqt1pm1.js";
23
+ import {
24
+ $toString,
25
+ init_server
26
+ } from "./chunk-xrw80zgd.js";
27
+ import {
28
+ BridgeFatalError,
29
+ FAILED_FOOTER_TEXT,
30
+ TOOL_DISPLAY_EXPIRY_MS,
31
+ buildActiveFooterText,
32
+ buildBridgeConnectUrl,
33
+ buildBridgeSessionUrl,
34
+ buildIdleFooterText,
35
+ createAgentWorktree,
36
+ createBridgeApiClient,
37
+ getRemoteSessionUrl,
38
+ init_bridgeApi,
39
+ init_bridgeStatusUtil,
40
+ init_product,
41
+ init_worktree,
42
+ isExpiredErrorType,
43
+ isSuppressible403,
44
+ removeAgentWorktree,
45
+ timestamp,
46
+ validateBridgeId,
47
+ wrapWithOsc8Link
48
+ } from "./chunk-gmdy2w3z.js";
49
+ import {
50
+ init_rcDebugLog,
51
+ rcLog
52
+ } from "./chunk-nzxfj0gq.js";
53
+ import {
54
+ getTrustedDeviceToken,
55
+ init_trustedDevice
56
+ } from "./chunk-vr0n9pv9.js";
57
+ import {
58
+ BRIDGE_LOGIN_ERROR,
59
+ DEFAULT_SESSION_TIMEOUT_MS,
60
+ init_types
61
+ } from "./chunk-71sdcaq6.js";
62
+ import {
63
+ debugTruncate,
64
+ describeAxiosError,
65
+ init_debugUtils,
66
+ init_sessionIdCompat,
67
+ toCompatSessionId,
68
+ toInfraSessionId
69
+ } from "./chunk-tbdkekz3.js";
70
+ import {
71
+ getBridgeSessionIngressUrl,
72
+ init_bridgeEnv,
73
+ isBridgeCcrV2OverrideEnabled
74
+ } from "./chunk-2p369q9z.js";
75
+ import {
76
+ init_datadog,
77
+ shutdownDatadog
78
+ } from "./chunk-7nvday0n.js";
79
+ import {
80
+ BRIDGE_FAILED_INDICATOR,
81
+ BRIDGE_READY_INDICATOR,
82
+ BRIDGE_SPINNER_FRAMES,
83
+ checkGate_CACHED_OR_BLOCKING,
84
+ init_figures,
85
+ init_firstPartyEventLogger,
86
+ init_growthbook,
87
+ shutdown1PEventLogging
88
+ } from "./chunk-eemjb825.js";
89
+ import {
90
+ init_sleep,
91
+ sleep
92
+ } from "./chunk-jmv7k0jn.js";
93
+ import {
94
+ formatDuration,
95
+ init_format,
96
+ truncateToWidth
97
+ } from "./chunk-q1vrhh0q.js";
98
+ import {
99
+ init_source,
100
+ init_src,
101
+ source_default,
102
+ stringWidth
103
+ } from "./chunk-2g0ytd9d.js";
104
+ import {
105
+ init_analytics,
106
+ logEvent,
107
+ logEventAsync
108
+ } from "./chunk-j1mep9ck.js";
109
+ import {
110
+ init_diagLogs,
111
+ logForDiagnosticsNoPII
112
+ } from "./chunk-10k5jfc5.js";
113
+ import {
114
+ errorMessage,
115
+ init_debug,
116
+ init_envUtils,
117
+ init_errors,
118
+ init_log,
119
+ init_slowOperations,
120
+ isInProtectedNamespace,
121
+ jsonParse,
122
+ jsonStringify,
123
+ logError,
124
+ logForDebugging
125
+ } from "./chunk-s3hafnk3.js";
126
+ import {
127
+ __require
128
+ } from "./chunk-hhsxm2yr.js";
129
+
130
+ // src/bridge/bridgeMain.ts
131
+ init_product();
132
+ init_datadog();
133
+ init_firstPartyEventLogger();
134
+ init_growthbook();
135
+ init_analytics();
136
+ init_cliLaunch();
137
+ init_debug();
138
+ init_rcDebugLog();
139
+ init_diagLogs();
140
+ init_envUtils();
141
+ init_errors();
142
+ init_format();
143
+ init_log();
144
+ init_sleep();
145
+ init_worktree();
146
+ init_bridgeApi();
147
+ init_bridgeStatusUtil();
148
+ import { randomUUID } from "crypto";
149
+ import { hostname, tmpdir as tmpdir2 } from "os";
150
+ import { basename, join as join2, resolve } from "path";
151
+
152
+ // src/bridge/bridgeUI.ts
153
+ init_source();
154
+ init_server();
155
+ init_figures();
156
+ init_src();
157
+ init_debug();
158
+ init_bridgeStatusUtil();
159
+ var QR_OPTIONS = {
160
+ type: "utf8",
161
+ errorCorrectionLevel: "L",
162
+ small: true
163
+ };
164
+ async function generateQr(url) {
165
+ const qr = await $toString(url, QR_OPTIONS);
166
+ return qr.split(`
167
+ `).filter((line) => line.length > 0);
168
+ }
169
+ function createBridgeLogger(options) {
170
+ const write = options.write ?? ((s) => process.stdout.write(s));
171
+ const verbose = options.verbose;
172
+ let statusLineCount = 0;
173
+ let currentState = "idle";
174
+ let currentStateText = "Ready";
175
+ let repoName = "";
176
+ let branch = "";
177
+ let debugLogPath = "";
178
+ let connectUrl = "";
179
+ let cachedIngressUrl = "";
180
+ let cachedEnvironmentId = "";
181
+ let activeSessionUrl = null;
182
+ let qrLines = [];
183
+ let qrVisible = false;
184
+ let lastToolSummary = null;
185
+ let lastToolTime = 0;
186
+ let sessionActive = 0;
187
+ let sessionMax = 1;
188
+ let spawnModeDisplay = null;
189
+ let spawnMode = "single-session";
190
+ const sessionDisplayInfo = new Map;
191
+ let connectingTimer = null;
192
+ let connectingTick = 0;
193
+ function countVisualLines(text) {
194
+ const cols = process.stdout.columns || 80;
195
+ let count = 0;
196
+ for (const logical of text.split(`
197
+ `)) {
198
+ if (logical.length === 0) {
199
+ count++;
200
+ continue;
201
+ }
202
+ const width = stringWidth(logical);
203
+ count += Math.max(1, Math.ceil(width / cols));
204
+ }
205
+ if (text.endsWith(`
206
+ `)) {
207
+ count--;
208
+ }
209
+ return count;
210
+ }
211
+ function writeStatus(text) {
212
+ write(text);
213
+ statusLineCount += countVisualLines(text);
214
+ }
215
+ function clearStatusLines() {
216
+ if (statusLineCount <= 0)
217
+ return;
218
+ logForDebugging(`[bridge:ui] clearStatusLines count=${statusLineCount}`);
219
+ write(`\x1B[${statusLineCount}A`);
220
+ write("\x1B[J");
221
+ statusLineCount = 0;
222
+ }
223
+ function printLog(line) {
224
+ clearStatusLines();
225
+ write(line);
226
+ }
227
+ function regenerateQr(url) {
228
+ generateQr(url).then((lines) => {
229
+ qrLines = lines;
230
+ renderStatusLine();
231
+ }).catch((e) => {
232
+ logForDebugging(`QR code generation failed: ${e}`, { level: "error" });
233
+ });
234
+ }
235
+ function renderConnectingLine() {
236
+ clearStatusLines();
237
+ const frame = BRIDGE_SPINNER_FRAMES[connectingTick % BRIDGE_SPINNER_FRAMES.length];
238
+ let suffix = "";
239
+ if (repoName) {
240
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(repoName);
241
+ }
242
+ if (branch) {
243
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(branch);
244
+ }
245
+ writeStatus(`${source_default.yellow(frame)} ${source_default.yellow("Connecting")}${suffix}
246
+ `);
247
+ }
248
+ function startConnecting() {
249
+ stopConnecting();
250
+ renderConnectingLine();
251
+ connectingTimer = setInterval(() => {
252
+ connectingTick++;
253
+ renderConnectingLine();
254
+ }, 150);
255
+ }
256
+ function stopConnecting() {
257
+ if (connectingTimer) {
258
+ clearInterval(connectingTimer);
259
+ connectingTimer = null;
260
+ }
261
+ }
262
+ function renderStatusLine() {
263
+ if (currentState === "reconnecting" || currentState === "failed") {
264
+ return;
265
+ }
266
+ clearStatusLines();
267
+ const isIdle = currentState === "idle";
268
+ if (qrVisible) {
269
+ for (const line of qrLines) {
270
+ writeStatus(`${source_default.dim(line)}
271
+ `);
272
+ }
273
+ }
274
+ const indicator = BRIDGE_READY_INDICATOR;
275
+ const indicatorColor = isIdle ? source_default.green : source_default.cyan;
276
+ const baseColor = isIdle ? source_default.green : source_default.cyan;
277
+ const stateText = baseColor(currentStateText);
278
+ let suffix = "";
279
+ if (repoName) {
280
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(repoName);
281
+ }
282
+ if (branch && spawnMode !== "worktree") {
283
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(branch);
284
+ }
285
+ if (process.env.USER_TYPE === "ant" && debugLogPath) {
286
+ writeStatus(`${source_default.yellow("[ANT-ONLY] Logs:")} ${source_default.dim(debugLogPath)}
287
+ `);
288
+ }
289
+ writeStatus(`${indicatorColor(indicator)} ${stateText}${suffix}
290
+ `);
291
+ if (sessionMax > 1) {
292
+ const modeHint = spawnMode === "worktree" ? "New sessions will be created in an isolated worktree" : "New sessions will be created in the current directory";
293
+ writeStatus(` ${source_default.dim(`Capacity: ${sessionActive}/${sessionMax} \xB7 ${modeHint}`)}
294
+ `);
295
+ for (const [, info] of sessionDisplayInfo) {
296
+ const titleText = info.title ? truncateToWidth(info.title, 35) : source_default.dim("Attached");
297
+ const titleLinked = wrapWithOsc8Link(titleText, info.url);
298
+ const act = info.activity;
299
+ const showAct = act && act.type !== "result" && act.type !== "error";
300
+ const actText = showAct ? source_default.dim(` ${truncateToWidth(act.summary, 40)}`) : "";
301
+ writeStatus(` ${titleLinked}${actText}
302
+ `);
303
+ }
304
+ }
305
+ if (sessionMax === 1) {
306
+ const modeText = spawnMode === "single-session" ? "Single session \xB7 exits when complete" : spawnMode === "worktree" ? `Capacity: ${sessionActive}/1 \xB7 New sessions will be created in an isolated worktree` : `Capacity: ${sessionActive}/1 \xB7 New sessions will be created in the current directory`;
307
+ writeStatus(` ${source_default.dim(modeText)}
308
+ `);
309
+ }
310
+ if (sessionMax === 1 && !isIdle && lastToolSummary && Date.now() - lastToolTime < TOOL_DISPLAY_EXPIRY_MS) {
311
+ writeStatus(` ${source_default.dim(truncateToWidth(lastToolSummary, 60))}
312
+ `);
313
+ }
314
+ const url = activeSessionUrl ?? connectUrl;
315
+ if (url) {
316
+ writeStatus(`
317
+ `);
318
+ const footerText = isIdle ? buildIdleFooterText(url) : buildActiveFooterText(url);
319
+ const qrHint = qrVisible ? source_default.dim.italic("space to hide QR code") : source_default.dim.italic("space to show QR code");
320
+ const toggleHint = spawnModeDisplay ? source_default.dim.italic(" \xB7 w to toggle spawn mode") : "";
321
+ writeStatus(`${source_default.dim(footerText)}
322
+ `);
323
+ writeStatus(`${qrHint}${toggleHint}
324
+ `);
325
+ }
326
+ }
327
+ return {
328
+ printBanner(config, environmentId) {
329
+ cachedIngressUrl = config.sessionIngressUrl;
330
+ cachedEnvironmentId = environmentId;
331
+ connectUrl = buildBridgeConnectUrl(environmentId, cachedIngressUrl);
332
+ regenerateQr(connectUrl);
333
+ if (verbose) {
334
+ write(source_default.dim(`Remote Control`) + ` v${"1.0.0"}
335
+ `);
336
+ }
337
+ if (verbose) {
338
+ if (config.spawnMode !== "single-session") {
339
+ write(source_default.dim(`Spawn mode: `) + `${config.spawnMode}
340
+ `);
341
+ write(source_default.dim(`Max concurrent sessions: `) + `${config.maxSessions}
342
+ `);
343
+ }
344
+ write(source_default.dim(`Environment ID: `) + `${environmentId}
345
+ `);
346
+ }
347
+ if (config.sandbox) {
348
+ write(source_default.dim(`Sandbox: `) + `${source_default.green("Enabled")}
349
+ `);
350
+ }
351
+ write(`
352
+ `);
353
+ startConnecting();
354
+ },
355
+ logSessionStart(sessionId, prompt) {
356
+ if (verbose) {
357
+ const short = truncateToWidth(prompt, 80);
358
+ printLog(source_default.dim(`[${timestamp()}]`) + ` Session started: ${source_default.white(`"${short}"`)} (${source_default.dim(sessionId)})
359
+ `);
360
+ }
361
+ },
362
+ logSessionComplete(sessionId, durationMs) {
363
+ printLog(source_default.dim(`[${timestamp()}]`) + ` Session ${source_default.green("completed")} (${formatDuration(durationMs)}) ${source_default.dim(sessionId)}
364
+ `);
365
+ },
366
+ logSessionFailed(sessionId, error) {
367
+ printLog(source_default.dim(`[${timestamp()}]`) + ` Session ${source_default.red("failed")}: ${error} ${source_default.dim(sessionId)}
368
+ `);
369
+ },
370
+ logStatus(message) {
371
+ printLog(source_default.dim(`[${timestamp()}]`) + ` ${message}
372
+ `);
373
+ },
374
+ logVerbose(message) {
375
+ if (verbose) {
376
+ printLog(source_default.dim(`[${timestamp()}] ${message}`) + `
377
+ `);
378
+ }
379
+ },
380
+ logError(message) {
381
+ printLog(source_default.red(`[${timestamp()}] Error: ${message}`) + `
382
+ `);
383
+ },
384
+ logReconnected(disconnectedMs) {
385
+ printLog(source_default.dim(`[${timestamp()}]`) + ` ${source_default.green("Reconnected")} after ${formatDuration(disconnectedMs)}
386
+ `);
387
+ },
388
+ setRepoInfo(repo, branchName) {
389
+ repoName = repo;
390
+ branch = branchName;
391
+ },
392
+ setDebugLogPath(path) {
393
+ debugLogPath = path;
394
+ },
395
+ updateIdleStatus() {
396
+ stopConnecting();
397
+ currentState = "idle";
398
+ currentStateText = "Ready";
399
+ lastToolSummary = null;
400
+ lastToolTime = 0;
401
+ activeSessionUrl = null;
402
+ regenerateQr(connectUrl);
403
+ renderStatusLine();
404
+ },
405
+ setAttached(sessionId) {
406
+ stopConnecting();
407
+ currentState = "attached";
408
+ currentStateText = "Connected";
409
+ lastToolSummary = null;
410
+ lastToolTime = 0;
411
+ if (sessionMax <= 1) {
412
+ activeSessionUrl = buildBridgeSessionUrl(sessionId, cachedEnvironmentId, cachedIngressUrl);
413
+ regenerateQr(activeSessionUrl);
414
+ }
415
+ renderStatusLine();
416
+ },
417
+ updateReconnectingStatus(delayStr, elapsedStr) {
418
+ stopConnecting();
419
+ clearStatusLines();
420
+ currentState = "reconnecting";
421
+ if (qrVisible) {
422
+ for (const line of qrLines) {
423
+ writeStatus(`${source_default.dim(line)}
424
+ `);
425
+ }
426
+ }
427
+ const frame = BRIDGE_SPINNER_FRAMES[connectingTick % BRIDGE_SPINNER_FRAMES.length];
428
+ connectingTick++;
429
+ writeStatus(`${source_default.yellow(frame)} ${source_default.yellow("Reconnecting")} ${source_default.dim("\xB7")} ${source_default.dim(`retrying in ${delayStr}`)} ${source_default.dim("\xB7")} ${source_default.dim(`disconnected ${elapsedStr}`)}
430
+ `);
431
+ },
432
+ updateFailedStatus(error) {
433
+ stopConnecting();
434
+ clearStatusLines();
435
+ currentState = "failed";
436
+ let suffix = "";
437
+ if (repoName) {
438
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(repoName);
439
+ }
440
+ if (branch) {
441
+ suffix += source_default.dim(" \xB7 ") + source_default.dim(branch);
442
+ }
443
+ writeStatus(`${source_default.red(BRIDGE_FAILED_INDICATOR)} ${source_default.red("Remote Control Failed")}${suffix}
444
+ `);
445
+ writeStatus(`${source_default.dim(FAILED_FOOTER_TEXT)}
446
+ `);
447
+ if (error) {
448
+ writeStatus(`${source_default.red(error)}
449
+ `);
450
+ }
451
+ },
452
+ updateSessionStatus(_sessionId, _elapsed, activity, _trail) {
453
+ if (activity.type === "tool_start") {
454
+ lastToolSummary = activity.summary;
455
+ lastToolTime = Date.now();
456
+ }
457
+ renderStatusLine();
458
+ },
459
+ clearStatus() {
460
+ stopConnecting();
461
+ clearStatusLines();
462
+ },
463
+ toggleQr() {
464
+ qrVisible = !qrVisible;
465
+ renderStatusLine();
466
+ },
467
+ updateSessionCount(active, max, mode) {
468
+ if (sessionActive === active && sessionMax === max && spawnMode === mode)
469
+ return;
470
+ sessionActive = active;
471
+ sessionMax = max;
472
+ spawnMode = mode;
473
+ },
474
+ setSpawnModeDisplay(mode) {
475
+ if (spawnModeDisplay === mode)
476
+ return;
477
+ spawnModeDisplay = mode;
478
+ if (mode)
479
+ spawnMode = mode;
480
+ },
481
+ addSession(sessionId, url) {
482
+ sessionDisplayInfo.set(sessionId, { url });
483
+ },
484
+ updateSessionActivity(sessionId, activity) {
485
+ const info = sessionDisplayInfo.get(sessionId);
486
+ if (!info)
487
+ return;
488
+ info.activity = activity;
489
+ },
490
+ setSessionTitle(sessionId, title) {
491
+ const info = sessionDisplayInfo.get(sessionId);
492
+ if (!info)
493
+ return;
494
+ info.title = title;
495
+ if (currentState === "reconnecting" || currentState === "failed")
496
+ return;
497
+ if (sessionMax === 1) {
498
+ currentState = "titled";
499
+ currentStateText = truncateToWidth(title, 40);
500
+ }
501
+ renderStatusLine();
502
+ },
503
+ removeSession(sessionId) {
504
+ sessionDisplayInfo.delete(sessionId);
505
+ },
506
+ refreshDisplay() {
507
+ if (currentState === "reconnecting" || currentState === "failed")
508
+ return;
509
+ renderStatusLine();
510
+ }
511
+ };
512
+ }
513
+
514
+ // src/bridge/bridgeMain.ts
515
+ init_bridgeEnv();
516
+ init_debugUtils();
517
+ init_sessionIdCompat();
518
+
519
+ // src/bridge/sessionRunner.ts
520
+ init_slowOperations();
521
+ init_debugUtils();
522
+ import { spawn } from "child_process";
523
+ import { createWriteStream } from "fs";
524
+ import { tmpdir } from "os";
525
+ import { dirname, join } from "path";
526
+ import { createInterface } from "readline";
527
+ var MAX_ACTIVITIES = 10;
528
+ var MAX_STDERR_LINES = 10;
529
+ function safeFilenameId(id) {
530
+ return id.replace(/[^a-zA-Z0-9_-]/g, "_");
531
+ }
532
+ var TOOL_VERBS = {
533
+ Read: "Reading",
534
+ Write: "Writing",
535
+ Edit: "Editing",
536
+ MultiEdit: "Editing",
537
+ Bash: "Running",
538
+ Glob: "Searching",
539
+ Grep: "Searching",
540
+ WebFetch: "Fetching",
541
+ WebSearch: "Searching",
542
+ Task: "Running task",
543
+ FileReadTool: "Reading",
544
+ FileWriteTool: "Writing",
545
+ FileEditTool: "Editing",
546
+ GlobTool: "Searching",
547
+ GrepTool: "Searching",
548
+ BashTool: "Running",
549
+ NotebookEditTool: "Editing notebook",
550
+ LSP: "LSP"
551
+ };
552
+ function toolSummary(name, input) {
553
+ const verb = TOOL_VERBS[name] ?? name;
554
+ const target = input.file_path ?? input.filePath ?? input.pattern ?? input.command?.slice(0, 60) ?? input.url ?? input.query ?? "";
555
+ if (target) {
556
+ return `${verb} ${target}`;
557
+ }
558
+ return verb;
559
+ }
560
+ function extractActivities(line, sessionId, onDebug) {
561
+ let parsed;
562
+ try {
563
+ parsed = jsonParse(line);
564
+ } catch {
565
+ return [];
566
+ }
567
+ if (!parsed || typeof parsed !== "object") {
568
+ return [];
569
+ }
570
+ const msg = parsed;
571
+ const activities = [];
572
+ const now = Date.now();
573
+ switch (msg.type) {
574
+ case "assistant": {
575
+ const message = msg.message;
576
+ if (!message)
577
+ break;
578
+ const content = message.content;
579
+ if (!Array.isArray(content))
580
+ break;
581
+ for (const block of content) {
582
+ if (!block || typeof block !== "object")
583
+ continue;
584
+ const b = block;
585
+ if (b.type === "tool_use") {
586
+ const name = b.name ?? "Tool";
587
+ const input = b.input ?? {};
588
+ const summary = toolSummary(name, input);
589
+ activities.push({
590
+ type: "tool_start",
591
+ summary,
592
+ timestamp: now
593
+ });
594
+ onDebug(`[bridge:activity] sessionId=${sessionId} tool_use name=${name} ${inputPreview(input)}`);
595
+ } else if (b.type === "text") {
596
+ const text = b.text ?? "";
597
+ if (text.length > 0) {
598
+ activities.push({
599
+ type: "text",
600
+ summary: text.slice(0, 80),
601
+ timestamp: now
602
+ });
603
+ onDebug(`[bridge:activity] sessionId=${sessionId} text "${text.slice(0, 100)}"`);
604
+ }
605
+ }
606
+ }
607
+ break;
608
+ }
609
+ case "result": {
610
+ const subtype = msg.subtype;
611
+ if (subtype === "success") {
612
+ activities.push({
613
+ type: "result",
614
+ summary: "Session completed",
615
+ timestamp: now
616
+ });
617
+ onDebug(`[bridge:activity] sessionId=${sessionId} result subtype=success`);
618
+ } else if (subtype) {
619
+ const errors = msg.errors;
620
+ const errorSummary = errors?.[0] ?? `Error: ${subtype}`;
621
+ activities.push({
622
+ type: "error",
623
+ summary: errorSummary,
624
+ timestamp: now
625
+ });
626
+ onDebug(`[bridge:activity] sessionId=${sessionId} result subtype=${subtype} error="${errorSummary}"`);
627
+ } else {
628
+ onDebug(`[bridge:activity] sessionId=${sessionId} result subtype=undefined`);
629
+ }
630
+ break;
631
+ }
632
+ default:
633
+ break;
634
+ }
635
+ return activities;
636
+ }
637
+ function extractUserMessageText(msg) {
638
+ if (msg.parent_tool_use_id != null || msg.isSynthetic || msg.isReplay)
639
+ return;
640
+ const message = msg.message;
641
+ const content = message?.content;
642
+ let text;
643
+ if (typeof content === "string") {
644
+ text = content;
645
+ } else if (Array.isArray(content)) {
646
+ for (const block of content) {
647
+ if (block && typeof block === "object" && block.type === "text") {
648
+ text = block.text;
649
+ break;
650
+ }
651
+ }
652
+ }
653
+ text = text?.trim();
654
+ return text ? text : undefined;
655
+ }
656
+ function inputPreview(input) {
657
+ const parts = [];
658
+ for (const [key, val] of Object.entries(input)) {
659
+ if (typeof val === "string") {
660
+ parts.push(`${key}="${val.slice(0, 100)}"`);
661
+ }
662
+ if (parts.length >= 3)
663
+ break;
664
+ }
665
+ return parts.join(" ");
666
+ }
667
+ function createSessionSpawner(deps) {
668
+ return {
669
+ spawn(opts, dir) {
670
+ const safeId = safeFilenameId(opts.sessionId);
671
+ let debugFile;
672
+ if (deps.debugFile) {
673
+ const ext = deps.debugFile.lastIndexOf(".");
674
+ if (ext > 0) {
675
+ debugFile = `${deps.debugFile.slice(0, ext)}-${safeId}${deps.debugFile.slice(ext)}`;
676
+ } else {
677
+ debugFile = `${deps.debugFile}-${safeId}`;
678
+ }
679
+ } else if (deps.verbose || process.env.USER_TYPE === "ant") {
680
+ debugFile = join(tmpdir(), "claude", `bridge-session-${safeId}.log`);
681
+ }
682
+ let transcriptStream = null;
683
+ let transcriptPath;
684
+ if (deps.debugFile) {
685
+ transcriptPath = join(dirname(deps.debugFile), `bridge-transcript-${safeId}.jsonl`);
686
+ transcriptStream = createWriteStream(transcriptPath, { flags: "a" });
687
+ transcriptStream.on("error", (err) => {
688
+ deps.onDebug(`[bridge:session] Transcript write error: ${err.message}`);
689
+ transcriptStream = null;
690
+ });
691
+ deps.onDebug(`[bridge:session] Transcript log: ${transcriptPath}`);
692
+ }
693
+ const args = [
694
+ ...deps.scriptArgs,
695
+ "--print",
696
+ "--sdk-url",
697
+ opts.sdkUrl,
698
+ "--session-id",
699
+ opts.sessionId,
700
+ "--input-format",
701
+ "stream-json",
702
+ "--output-format",
703
+ "stream-json",
704
+ "--replay-user-messages",
705
+ ...deps.verbose ? ["--verbose"] : [],
706
+ ...debugFile ? ["--debug-file", debugFile] : [],
707
+ ...deps.permissionMode ? ["--permission-mode", deps.permissionMode] : []
708
+ ];
709
+ const env = {
710
+ ...deps.env,
711
+ CLAUDE_CODE_OAUTH_TOKEN: undefined,
712
+ CLAUDE_CODE_ENVIRONMENT_KIND: "bridge",
713
+ ...deps.sandbox && { CLAUDE_CODE_FORCE_SANDBOX: "1" },
714
+ CLAUDE_CODE_SESSION_ACCESS_TOKEN: opts.accessToken,
715
+ CLAUDE_CODE_POST_FOR_SESSION_INGRESS_V2: "1",
716
+ ...opts.useCcrV2 && {
717
+ CLAUDE_CODE_USE_CCR_V2: "1",
718
+ CLAUDE_CODE_WORKER_EPOCH: String(opts.workerEpoch)
719
+ }
720
+ };
721
+ deps.onDebug(`[bridge:session] Spawning sessionId=${opts.sessionId} sdkUrl=${opts.sdkUrl} accessToken=${opts.accessToken ? "present" : "MISSING"}`);
722
+ deps.onDebug(`[bridge:session] Child args: ${args.join(" ")}`);
723
+ if (debugFile) {
724
+ deps.onDebug(`[bridge:session] Debug log: ${debugFile}`);
725
+ }
726
+ const child = spawn(deps.execPath, args, {
727
+ cwd: dir,
728
+ stdio: ["pipe", "pipe", "pipe"],
729
+ env,
730
+ windowsHide: true
731
+ });
732
+ deps.onDebug(`[bridge:session] sessionId=${opts.sessionId} pid=${child.pid}`);
733
+ const activities = [];
734
+ let currentActivity = null;
735
+ const lastStderr = [];
736
+ let sigkillSent = false;
737
+ let firstUserMessageSeen = false;
738
+ if (child.stderr) {
739
+ const stderrRl = createInterface({ input: child.stderr });
740
+ stderrRl.on("line", (line) => {
741
+ if (deps.verbose) {
742
+ process.stderr.write(line + `
743
+ `);
744
+ }
745
+ if (lastStderr.length >= MAX_STDERR_LINES) {
746
+ lastStderr.shift();
747
+ }
748
+ lastStderr.push(line);
749
+ });
750
+ }
751
+ if (child.stdout) {
752
+ const rl = createInterface({ input: child.stdout });
753
+ rl.on("line", (line) => {
754
+ if (transcriptStream) {
755
+ transcriptStream.write(line + `
756
+ `);
757
+ }
758
+ deps.onDebug(`[bridge:ws] sessionId=${opts.sessionId} <<< ${debugTruncate(line)}`);
759
+ if (deps.verbose) {
760
+ process.stderr.write(line + `
761
+ `);
762
+ }
763
+ const extracted = extractActivities(line, opts.sessionId, deps.onDebug);
764
+ for (const activity of extracted) {
765
+ if (activities.length >= MAX_ACTIVITIES) {
766
+ activities.shift();
767
+ }
768
+ activities.push(activity);
769
+ currentActivity = activity;
770
+ deps.onActivity?.(opts.sessionId, activity);
771
+ }
772
+ {
773
+ let parsed;
774
+ try {
775
+ parsed = jsonParse(line);
776
+ } catch {}
777
+ if (parsed && typeof parsed === "object") {
778
+ const msg = parsed;
779
+ if (msg.type === "control_request") {
780
+ const request = msg.request;
781
+ if (request?.subtype === "can_use_tool" && deps.onPermissionRequest) {
782
+ deps.onPermissionRequest(opts.sessionId, parsed, opts.accessToken);
783
+ }
784
+ } else if (msg.type === "user" && !firstUserMessageSeen && opts.onFirstUserMessage) {
785
+ const text = extractUserMessageText(msg);
786
+ if (text) {
787
+ firstUserMessageSeen = true;
788
+ opts.onFirstUserMessage(text);
789
+ }
790
+ }
791
+ }
792
+ }
793
+ });
794
+ }
795
+ const done = new Promise((resolve) => {
796
+ child.on("close", (code, signal) => {
797
+ if (transcriptStream) {
798
+ transcriptStream.end();
799
+ transcriptStream = null;
800
+ }
801
+ if (signal === "SIGTERM" || signal === "SIGINT") {
802
+ deps.onDebug(`[bridge:session] sessionId=${opts.sessionId} interrupted signal=${signal} pid=${child.pid}`);
803
+ resolve("interrupted");
804
+ } else if (code === 0) {
805
+ deps.onDebug(`[bridge:session] sessionId=${opts.sessionId} completed exit_code=0 pid=${child.pid}`);
806
+ resolve("completed");
807
+ } else {
808
+ deps.onDebug(`[bridge:session] sessionId=${opts.sessionId} failed exit_code=${code} pid=${child.pid}`);
809
+ resolve("failed");
810
+ }
811
+ });
812
+ child.on("error", (err) => {
813
+ deps.onDebug(`[bridge:session] sessionId=${opts.sessionId} spawn error: ${err.message}`);
814
+ resolve("failed");
815
+ });
816
+ });
817
+ const handle = {
818
+ sessionId: opts.sessionId,
819
+ done,
820
+ activities,
821
+ accessToken: opts.accessToken,
822
+ lastStderr,
823
+ get currentActivity() {
824
+ return currentActivity;
825
+ },
826
+ kill() {
827
+ if (!child.killed) {
828
+ deps.onDebug(`[bridge:session] Sending SIGTERM to sessionId=${opts.sessionId} pid=${child.pid}`);
829
+ if (process.platform === "win32") {
830
+ child.kill();
831
+ } else {
832
+ child.kill("SIGTERM");
833
+ }
834
+ }
835
+ },
836
+ forceKill() {
837
+ if (!sigkillSent && child.pid) {
838
+ sigkillSent = true;
839
+ deps.onDebug(`[bridge:session] Sending SIGKILL to sessionId=${opts.sessionId} pid=${child.pid}`);
840
+ if (process.platform === "win32") {
841
+ child.kill();
842
+ } else {
843
+ child.kill("SIGKILL");
844
+ }
845
+ }
846
+ },
847
+ writeStdin(data) {
848
+ if (child.stdin && !child.stdin.destroyed) {
849
+ deps.onDebug(`[bridge:ws] sessionId=${opts.sessionId} >>> ${debugTruncate(data)}`);
850
+ child.stdin.write(data);
851
+ }
852
+ },
853
+ updateAccessToken(token) {
854
+ handle.accessToken = token;
855
+ handle.writeStdin(jsonStringify({
856
+ type: "update_environment_variables",
857
+ variables: { CLAUDE_CODE_SESSION_ACCESS_TOKEN: token }
858
+ }) + `
859
+ `);
860
+ deps.onDebug(`[bridge:session] Sent token refresh via stdin for sessionId=${opts.sessionId}`);
861
+ }
862
+ };
863
+ return handle;
864
+ }
865
+ };
866
+ }
867
+
868
+ // src/bridge/bridgeMain.ts
869
+ init_trustedDevice();
870
+ init_types();
871
+ var DEFAULT_BACKOFF = {
872
+ connInitialMs: 2000,
873
+ connCapMs: 120000,
874
+ connGiveUpMs: 600000,
875
+ generalInitialMs: 500,
876
+ generalCapMs: 30000,
877
+ generalGiveUpMs: 600000
878
+ };
879
+ var STATUS_UPDATE_INTERVAL_MS = 1000;
880
+ var SPAWN_SESSIONS_DEFAULT = 32;
881
+ async function isMultiSessionSpawnEnabled() {
882
+ return checkGate_CACHED_OR_BLOCKING("tengu_ccr_bridge_multi_session");
883
+ }
884
+ function pollSleepDetectionThresholdMs(backoff) {
885
+ return backoff.connCapMs * 2;
886
+ }
887
+ function spawnScriptArgs() {
888
+ const bootstrap = [...getBootstrapArgs()];
889
+ const script = getScriptPath();
890
+ if (script)
891
+ bootstrap.push(script);
892
+ return bootstrap;
893
+ }
894
+ function safeSpawn(spawner, opts, dir) {
895
+ try {
896
+ return spawner.spawn(opts, dir);
897
+ } catch (err) {
898
+ const errMsg = errorMessage(err);
899
+ logError(new Error(`Session spawn failed: ${errMsg}`));
900
+ return errMsg;
901
+ }
902
+ }
903
+ async function runBridgeLoop(config, environmentId, environmentSecret, api, spawner, logger, signal, backoffConfig = DEFAULT_BACKOFF, initialSessionId, getAccessToken) {
904
+ const controller = new AbortController;
905
+ if (signal.aborted) {
906
+ controller.abort();
907
+ } else {
908
+ signal.addEventListener("abort", () => controller.abort(), { once: true });
909
+ }
910
+ const loopSignal = controller.signal;
911
+ const activeSessions = new Map;
912
+ const sessionStartTimes = new Map;
913
+ const sessionWorkIds = new Map;
914
+ const sessionCompatIds = new Map;
915
+ const sessionIngressTokens = new Map;
916
+ const sessionTimers = new Map;
917
+ const completedWorkIds = new Set;
918
+ const sessionWorktrees = new Map;
919
+ const timedOutSessions = new Set;
920
+ const titledSessions = new Set;
921
+ const capacityWake = createCapacityWake(loopSignal);
922
+ async function heartbeatActiveWorkItems() {
923
+ rcLog(`heartbeat: checking ${activeSessions.size} active session(s)`);
924
+ let anySuccess = false;
925
+ let anyFatal = false;
926
+ const authFailedSessions = [];
927
+ for (const [sessionId] of activeSessions) {
928
+ const workId = sessionWorkIds.get(sessionId);
929
+ const ingressToken = sessionIngressTokens.get(sessionId);
930
+ if (!workId || !ingressToken) {
931
+ continue;
932
+ }
933
+ try {
934
+ await api.heartbeatWork(environmentId, workId, ingressToken);
935
+ anySuccess = true;
936
+ } catch (err) {
937
+ logForDebugging(`[bridge:heartbeat] Failed for sessionId=${sessionId} workId=${workId}: ${errorMessage(err)}`);
938
+ if (err instanceof BridgeFatalError) {
939
+ logEvent("tengu_bridge_heartbeat_error", {
940
+ status: err.status,
941
+ error_type: err.status === 401 || err.status === 403 ? "auth_failed" : "fatal"
942
+ });
943
+ if (err.status === 401 || err.status === 403) {
944
+ authFailedSessions.push(sessionId);
945
+ } else {
946
+ anyFatal = true;
947
+ }
948
+ }
949
+ }
950
+ }
951
+ for (const sessionId of authFailedSessions) {
952
+ logger.logVerbose(`Session ${sessionId} token expired \u2014 re-queuing via bridge/reconnect`);
953
+ try {
954
+ await api.reconnectSession(environmentId, sessionId);
955
+ logForDebugging(`[bridge:heartbeat] Re-queued sessionId=${sessionId} via bridge/reconnect`);
956
+ } catch (err) {
957
+ logger.logError(`Failed to refresh session ${sessionId} token: ${errorMessage(err)}`);
958
+ logForDebugging(`[bridge:heartbeat] reconnectSession(${sessionId}) failed: ${errorMessage(err)}`, { level: "error" });
959
+ }
960
+ }
961
+ if (anyFatal) {
962
+ return "fatal";
963
+ }
964
+ if (authFailedSessions.length > 0) {
965
+ return "auth_failed";
966
+ }
967
+ return anySuccess ? "ok" : "failed";
968
+ }
969
+ const v2Sessions = new Set;
970
+ const tokenRefresh = getAccessToken ? createTokenRefreshScheduler({
971
+ getAccessToken,
972
+ onRefresh: (sessionId, oauthToken) => {
973
+ const handle = activeSessions.get(sessionId);
974
+ if (!handle) {
975
+ return;
976
+ }
977
+ if (v2Sessions.has(sessionId)) {
978
+ logger.logVerbose(`Refreshing session ${sessionId} token via bridge/reconnect`);
979
+ api.reconnectSession(environmentId, sessionId).catch((err) => {
980
+ logger.logError(`Failed to refresh session ${sessionId} token: ${errorMessage(err)}`);
981
+ logForDebugging(`[bridge:token] reconnectSession(${sessionId}) failed: ${errorMessage(err)}`, { level: "error" });
982
+ });
983
+ } else {
984
+ handle.updateAccessToken(oauthToken);
985
+ }
986
+ },
987
+ label: "bridge"
988
+ }) : null;
989
+ const loopStartTime = Date.now();
990
+ const pendingCleanups = new Set;
991
+ function trackCleanup(p) {
992
+ pendingCleanups.add(p);
993
+ p.finally(() => pendingCleanups.delete(p));
994
+ }
995
+ let connBackoff = 0;
996
+ let generalBackoff = 0;
997
+ let connErrorStart = null;
998
+ let generalErrorStart = null;
999
+ let lastPollErrorTime = null;
1000
+ let statusUpdateTimer = null;
1001
+ let fatalExit = false;
1002
+ logForDebugging(`[bridge:work] Starting poll loop spawnMode=${config.spawnMode} maxSessions=${config.maxSessions} environmentId=${environmentId}`);
1003
+ logForDiagnosticsNoPII("info", "bridge_loop_started", {
1004
+ max_sessions: config.maxSessions,
1005
+ spawn_mode: config.spawnMode
1006
+ });
1007
+ if (process.env.USER_TYPE === "ant") {
1008
+ let debugGlob;
1009
+ if (config.debugFile) {
1010
+ const ext = config.debugFile.lastIndexOf(".");
1011
+ debugGlob = ext > 0 ? `${config.debugFile.slice(0, ext)}-*${config.debugFile.slice(ext)}` : `${config.debugFile}-*`;
1012
+ } else {
1013
+ debugGlob = join2(tmpdir2(), "claude", "bridge-session-*.log");
1014
+ }
1015
+ logger.setDebugLogPath(debugGlob);
1016
+ }
1017
+ logger.printBanner(config, environmentId);
1018
+ logger.updateSessionCount(0, config.maxSessions, config.spawnMode);
1019
+ if (initialSessionId) {
1020
+ logger.setAttached(initialSessionId);
1021
+ }
1022
+ function updateStatusDisplay() {
1023
+ logger.updateSessionCount(activeSessions.size, config.maxSessions, config.spawnMode);
1024
+ for (const [sid, handle2] of activeSessions) {
1025
+ const act = handle2.currentActivity;
1026
+ if (act) {
1027
+ logger.updateSessionActivity(sessionCompatIds.get(sid) ?? sid, act);
1028
+ }
1029
+ }
1030
+ if (activeSessions.size === 0) {
1031
+ logger.updateIdleStatus();
1032
+ return;
1033
+ }
1034
+ const [sessionId, handle] = [...activeSessions.entries()].pop();
1035
+ const startTime = sessionStartTimes.get(sessionId);
1036
+ if (!startTime)
1037
+ return;
1038
+ const activity = handle.currentActivity;
1039
+ if (!activity || activity.type === "result" || activity.type === "error") {
1040
+ if (config.maxSessions > 1)
1041
+ logger.refreshDisplay();
1042
+ return;
1043
+ }
1044
+ const elapsed = formatDuration(Date.now() - startTime);
1045
+ const trail = handle.activities.filter((a) => a.type === "tool_start").slice(-5).map((a) => a.summary);
1046
+ logger.updateSessionStatus(sessionId, elapsed, activity, trail);
1047
+ }
1048
+ function startStatusUpdates() {
1049
+ stopStatusUpdates();
1050
+ updateStatusDisplay();
1051
+ statusUpdateTimer = setInterval(updateStatusDisplay, STATUS_UPDATE_INTERVAL_MS);
1052
+ }
1053
+ function stopStatusUpdates() {
1054
+ if (statusUpdateTimer) {
1055
+ clearInterval(statusUpdateTimer);
1056
+ statusUpdateTimer = null;
1057
+ }
1058
+ }
1059
+ function onSessionDone(sessionId, startTime, handle) {
1060
+ return (rawStatus) => {
1061
+ const workId = sessionWorkIds.get(sessionId);
1062
+ rcLog(`session done: sessionId=${sessionId} workId=${workId ?? "none"} status=${rawStatus}` + ` wasTimedOut=${timedOutSessions.has(sessionId)} duration=${Math.round((Date.now() - startTime) / 1000)}s` + ` stderr=${handle.lastStderr.length > 0 ? handle.lastStderr.join("\\n").slice(0, 500) : "(none)"}`);
1063
+ activeSessions.delete(sessionId);
1064
+ sessionStartTimes.delete(sessionId);
1065
+ sessionWorkIds.delete(sessionId);
1066
+ sessionIngressTokens.delete(sessionId);
1067
+ const compatId = sessionCompatIds.get(sessionId) ?? sessionId;
1068
+ sessionCompatIds.delete(sessionId);
1069
+ logger.removeSession(compatId);
1070
+ titledSessions.delete(compatId);
1071
+ v2Sessions.delete(sessionId);
1072
+ const timer = sessionTimers.get(sessionId);
1073
+ if (timer) {
1074
+ clearTimeout(timer);
1075
+ sessionTimers.delete(sessionId);
1076
+ }
1077
+ tokenRefresh?.cancel(sessionId);
1078
+ capacityWake.wake();
1079
+ const wasTimedOut = timedOutSessions.delete(sessionId);
1080
+ const status = wasTimedOut && rawStatus === "interrupted" ? "failed" : rawStatus;
1081
+ const durationMs = Date.now() - startTime;
1082
+ logForDebugging(`[bridge:session] sessionId=${sessionId} workId=${workId ?? "unknown"} exited status=${status} duration=${formatDuration(durationMs)}`);
1083
+ logEvent("tengu_bridge_session_done", {
1084
+ status,
1085
+ duration_ms: durationMs
1086
+ });
1087
+ logForDiagnosticsNoPII("info", "bridge_session_done", {
1088
+ status,
1089
+ duration_ms: durationMs
1090
+ });
1091
+ logger.clearStatus();
1092
+ stopStatusUpdates();
1093
+ const stderrSummary = handle.lastStderr.length > 0 ? handle.lastStderr.join(`
1094
+ `) : undefined;
1095
+ let failureMessage;
1096
+ switch (status) {
1097
+ case "completed":
1098
+ logger.logSessionComplete(sessionId, durationMs);
1099
+ break;
1100
+ case "failed":
1101
+ if (!wasTimedOut && !loopSignal.aborted) {
1102
+ failureMessage = stderrSummary ?? "Process exited with error";
1103
+ logger.logSessionFailed(sessionId, failureMessage);
1104
+ logError(new Error(`Bridge session failed: ${failureMessage}`));
1105
+ }
1106
+ break;
1107
+ case "interrupted":
1108
+ logger.logVerbose(`Session ${sessionId} interrupted`);
1109
+ break;
1110
+ }
1111
+ if (status !== "interrupted" && workId) {
1112
+ trackCleanup(stopWorkWithRetry(api, environmentId, workId, logger, backoffConfig.stopWorkBaseDelayMs));
1113
+ completedWorkIds.add(workId);
1114
+ }
1115
+ const wt = sessionWorktrees.get(sessionId);
1116
+ if (wt) {
1117
+ sessionWorktrees.delete(sessionId);
1118
+ trackCleanup(removeAgentWorktree(wt.worktreePath, wt.worktreeBranch, wt.gitRoot, wt.hookBased).catch((err) => logger.logVerbose(`Failed to remove worktree ${wt.worktreePath}: ${errorMessage(err)}`)));
1119
+ }
1120
+ if (status !== "interrupted" && !loopSignal.aborted) {
1121
+ if (config.spawnMode !== "single-session") {
1122
+ trackCleanup(api.archiveSession(compatId).catch((err) => logger.logVerbose(`Failed to archive session ${sessionId}: ${errorMessage(err)}`)));
1123
+ logForDebugging(`[bridge:session] Session ${status}, returning to idle (multi-session mode)`);
1124
+ } else {
1125
+ logForDebugging(`[bridge:session] Session ${status}, aborting poll loop to tear down environment`);
1126
+ controller.abort();
1127
+ return;
1128
+ }
1129
+ }
1130
+ if (!loopSignal.aborted) {
1131
+ startStatusUpdates();
1132
+ }
1133
+ };
1134
+ }
1135
+ if (!initialSessionId) {
1136
+ startStatusUpdates();
1137
+ }
1138
+ while (!loopSignal.aborted) {
1139
+ const pollConfig = getPollIntervalConfig();
1140
+ try {
1141
+ rcLog(`poll: envId=${environmentId} activeSessions=${activeSessions.size}`);
1142
+ const work = await api.pollForWork(environmentId, environmentSecret, loopSignal, pollConfig.reclaim_older_than_ms);
1143
+ const wasDisconnected = connErrorStart !== null || generalErrorStart !== null;
1144
+ if (wasDisconnected) {
1145
+ const disconnectedMs = Date.now() - (connErrorStart ?? generalErrorStart ?? Date.now());
1146
+ logger.logReconnected(disconnectedMs);
1147
+ logForDebugging(`[bridge:poll] Reconnected after ${formatDuration(disconnectedMs)}`);
1148
+ logEvent("tengu_bridge_reconnected", {
1149
+ disconnected_ms: disconnectedMs
1150
+ });
1151
+ }
1152
+ connBackoff = 0;
1153
+ generalBackoff = 0;
1154
+ connErrorStart = null;
1155
+ generalErrorStart = null;
1156
+ lastPollErrorTime = null;
1157
+ if (!work) {
1158
+ const atCap = activeSessions.size >= config.maxSessions;
1159
+ if (atCap) {
1160
+ const atCapMs = pollConfig.multisession_poll_interval_ms_at_capacity;
1161
+ if (pollConfig.non_exclusive_heartbeat_interval_ms > 0) {
1162
+ logEvent("tengu_bridge_heartbeat_mode_entered", {
1163
+ active_sessions: activeSessions.size,
1164
+ heartbeat_interval_ms: pollConfig.non_exclusive_heartbeat_interval_ms
1165
+ });
1166
+ const pollDeadline = atCapMs > 0 ? Date.now() + atCapMs : null;
1167
+ let hbResult = "ok";
1168
+ let hbCycles = 0;
1169
+ while (!loopSignal.aborted && activeSessions.size >= config.maxSessions && (pollDeadline === null || Date.now() < pollDeadline)) {
1170
+ const hbConfig = getPollIntervalConfig();
1171
+ if (hbConfig.non_exclusive_heartbeat_interval_ms <= 0)
1172
+ break;
1173
+ const cap = capacityWake.signal();
1174
+ hbResult = await heartbeatActiveWorkItems();
1175
+ if (hbResult === "auth_failed" || hbResult === "fatal") {
1176
+ cap.cleanup();
1177
+ break;
1178
+ }
1179
+ hbCycles++;
1180
+ await sleep(hbConfig.non_exclusive_heartbeat_interval_ms, cap.signal);
1181
+ cap.cleanup();
1182
+ }
1183
+ const exitReason = hbResult === "auth_failed" || hbResult === "fatal" ? hbResult : loopSignal.aborted ? "shutdown" : activeSessions.size < config.maxSessions ? "capacity_changed" : pollDeadline !== null && Date.now() >= pollDeadline ? "poll_due" : "config_disabled";
1184
+ logEvent("tengu_bridge_heartbeat_mode_exited", {
1185
+ reason: exitReason,
1186
+ heartbeat_cycles: hbCycles,
1187
+ active_sessions: activeSessions.size
1188
+ });
1189
+ if (exitReason === "poll_due") {
1190
+ logForDebugging(`[bridge:poll] Heartbeat poll_due after ${hbCycles} cycles \u2014 falling through to pollForWork`);
1191
+ }
1192
+ if (hbResult === "auth_failed" || hbResult === "fatal") {
1193
+ const cap = capacityWake.signal();
1194
+ await sleep(atCapMs > 0 ? atCapMs : pollConfig.non_exclusive_heartbeat_interval_ms, cap.signal);
1195
+ cap.cleanup();
1196
+ }
1197
+ } else if (atCapMs > 0) {
1198
+ const cap = capacityWake.signal();
1199
+ await sleep(atCapMs, cap.signal);
1200
+ cap.cleanup();
1201
+ }
1202
+ } else {
1203
+ const interval = activeSessions.size > 0 ? pollConfig.multisession_poll_interval_ms_partial_capacity : pollConfig.multisession_poll_interval_ms_not_at_capacity;
1204
+ await sleep(interval, loopSignal);
1205
+ }
1206
+ continue;
1207
+ }
1208
+ const atCapacityBeforeSwitch = activeSessions.size >= config.maxSessions;
1209
+ if (completedWorkIds.has(work.id)) {
1210
+ logForDebugging(`[bridge:work] Skipping already-completed workId=${work.id}`);
1211
+ if (atCapacityBeforeSwitch) {
1212
+ const cap = capacityWake.signal();
1213
+ if (pollConfig.non_exclusive_heartbeat_interval_ms > 0) {
1214
+ await heartbeatActiveWorkItems();
1215
+ await sleep(pollConfig.non_exclusive_heartbeat_interval_ms, cap.signal);
1216
+ } else if (pollConfig.multisession_poll_interval_ms_at_capacity > 0) {
1217
+ await sleep(pollConfig.multisession_poll_interval_ms_at_capacity, cap.signal);
1218
+ }
1219
+ cap.cleanup();
1220
+ } else {
1221
+ await sleep(1000, loopSignal);
1222
+ }
1223
+ continue;
1224
+ }
1225
+ let secret;
1226
+ try {
1227
+ secret = decodeWorkSecret(work.secret);
1228
+ } catch (err) {
1229
+ const errMsg = errorMessage(err);
1230
+ logger.logError(`Failed to decode work secret for workId=${work.id}: ${errMsg}`);
1231
+ logEvent("tengu_bridge_work_secret_failed", {});
1232
+ completedWorkIds.add(work.id);
1233
+ trackCleanup(stopWorkWithRetry(api, environmentId, work.id, logger, backoffConfig.stopWorkBaseDelayMs));
1234
+ if (atCapacityBeforeSwitch) {
1235
+ const cap = capacityWake.signal();
1236
+ if (pollConfig.non_exclusive_heartbeat_interval_ms > 0) {
1237
+ await heartbeatActiveWorkItems();
1238
+ await sleep(pollConfig.non_exclusive_heartbeat_interval_ms, cap.signal);
1239
+ } else if (pollConfig.multisession_poll_interval_ms_at_capacity > 0) {
1240
+ await sleep(pollConfig.multisession_poll_interval_ms_at_capacity, cap.signal);
1241
+ }
1242
+ cap.cleanup();
1243
+ }
1244
+ continue;
1245
+ }
1246
+ const ackWork = async () => {
1247
+ logForDebugging(`[bridge:work] Acknowledging workId=${work.id}`);
1248
+ try {
1249
+ await api.acknowledgeWork(environmentId, work.id, secret.session_ingress_token);
1250
+ } catch (err) {
1251
+ logForDebugging(`[bridge:work] Acknowledge failed workId=${work.id}: ${errorMessage(err)}`);
1252
+ }
1253
+ };
1254
+ const workType = work.data.type;
1255
+ switch (work.data.type) {
1256
+ case "healthcheck":
1257
+ await ackWork();
1258
+ logForDebugging("[bridge:work] Healthcheck received");
1259
+ logger.logVerbose("Healthcheck received");
1260
+ break;
1261
+ case "session": {
1262
+ const sessionId = work.data.id;
1263
+ rcLog(`work received: type=session sessionId=${sessionId} workId=${work.id}`);
1264
+ try {
1265
+ validateBridgeId(sessionId, "session_id");
1266
+ } catch {
1267
+ await ackWork();
1268
+ logger.logError(`Invalid session_id received: ${sessionId}`);
1269
+ break;
1270
+ }
1271
+ const existingHandle = activeSessions.get(sessionId);
1272
+ if (existingHandle) {
1273
+ existingHandle.updateAccessToken(secret.session_ingress_token);
1274
+ sessionIngressTokens.set(sessionId, secret.session_ingress_token);
1275
+ sessionWorkIds.set(sessionId, work.id);
1276
+ tokenRefresh?.schedule(sessionId, secret.session_ingress_token);
1277
+ logForDebugging(`[bridge:work] Updated access token for existing sessionId=${sessionId} workId=${work.id}`);
1278
+ await ackWork();
1279
+ break;
1280
+ }
1281
+ if (activeSessions.size >= config.maxSessions) {
1282
+ logForDebugging(`[bridge:work] At capacity (${activeSessions.size}/${config.maxSessions}), cannot spawn new session for workId=${work.id}`);
1283
+ break;
1284
+ }
1285
+ await ackWork();
1286
+ const spawnStartTime = Date.now();
1287
+ let sdkUrl;
1288
+ let useCcrV2 = false;
1289
+ let workerEpoch;
1290
+ if (secret.use_code_sessions === true || isBridgeCcrV2OverrideEnabled()) {
1291
+ sdkUrl = buildCCRv2SdkUrl(config.apiBaseUrl, sessionId);
1292
+ for (let attempt = 1;attempt <= 2; attempt++) {
1293
+ try {
1294
+ workerEpoch = await registerWorker(sdkUrl, secret.session_ingress_token);
1295
+ useCcrV2 = true;
1296
+ logForDebugging(`[bridge:session] CCR v2: registered worker sessionId=${sessionId} epoch=${workerEpoch} attempt=${attempt}`);
1297
+ break;
1298
+ } catch (err) {
1299
+ const errMsg = errorMessage(err);
1300
+ if (attempt < 2) {
1301
+ logForDebugging(`[bridge:session] CCR v2: registerWorker attempt ${attempt} failed, retrying: ${errMsg}`);
1302
+ await sleep(2000, loopSignal);
1303
+ if (loopSignal.aborted)
1304
+ break;
1305
+ continue;
1306
+ }
1307
+ logger.logError(`CCR v2 worker registration failed for session ${sessionId}: ${errMsg}`);
1308
+ logError(new Error(`registerWorker failed: ${errMsg}`));
1309
+ completedWorkIds.add(work.id);
1310
+ trackCleanup(stopWorkWithRetry(api, environmentId, work.id, logger, backoffConfig.stopWorkBaseDelayMs));
1311
+ }
1312
+ }
1313
+ if (!useCcrV2)
1314
+ break;
1315
+ } else {
1316
+ sdkUrl = buildSdkUrl(config.sessionIngressUrl, sessionId);
1317
+ }
1318
+ const spawnModeAtDecision = config.spawnMode;
1319
+ let sessionDir = config.dir;
1320
+ let worktreeCreateMs = 0;
1321
+ if (spawnModeAtDecision === "worktree" && (initialSessionId === undefined || !sameSessionId(sessionId, initialSessionId))) {
1322
+ const wtStart = Date.now();
1323
+ try {
1324
+ const wt = await createAgentWorktree(`bridge-${safeFilenameId(sessionId)}`);
1325
+ worktreeCreateMs = Date.now() - wtStart;
1326
+ sessionWorktrees.set(sessionId, {
1327
+ worktreePath: wt.worktreePath,
1328
+ worktreeBranch: wt.worktreeBranch,
1329
+ gitRoot: wt.gitRoot,
1330
+ hookBased: wt.hookBased
1331
+ });
1332
+ sessionDir = wt.worktreePath;
1333
+ logForDebugging(`[bridge:session] Created worktree for sessionId=${sessionId} at ${wt.worktreePath}`);
1334
+ } catch (err) {
1335
+ const errMsg = errorMessage(err);
1336
+ logger.logError(`Failed to create worktree for session ${sessionId}: ${errMsg}`);
1337
+ logError(new Error(`Worktree creation failed: ${errMsg}`));
1338
+ completedWorkIds.add(work.id);
1339
+ trackCleanup(stopWorkWithRetry(api, environmentId, work.id, logger, backoffConfig.stopWorkBaseDelayMs));
1340
+ break;
1341
+ }
1342
+ }
1343
+ logForDebugging(`[bridge:session] Spawning sessionId=${sessionId} sdkUrl=${sdkUrl}`);
1344
+ const compatSessionId = toCompatSessionId(sessionId);
1345
+ rcLog(`spawning session: sessionId=${sessionId} sdkUrl=${sdkUrl}` + ` useCcrV2=${useCcrV2} workerEpoch=${workerEpoch}` + ` dir=${sessionDir}` + ` accessToken=${secret.session_ingress_token ? secret.session_ingress_token.slice(0, 8) + "..." : "NONE"}`);
1346
+ const spawnResult = safeSpawn(spawner, {
1347
+ sessionId,
1348
+ sdkUrl,
1349
+ accessToken: secret.session_ingress_token,
1350
+ useCcrV2,
1351
+ workerEpoch,
1352
+ onFirstUserMessage: (text) => {
1353
+ if (titledSessions.has(compatSessionId))
1354
+ return;
1355
+ titledSessions.add(compatSessionId);
1356
+ const title = deriveSessionTitle(text);
1357
+ logger.setSessionTitle(compatSessionId, title);
1358
+ logForDebugging(`[bridge:title] derived title for ${compatSessionId}: ${title}`);
1359
+ import("./chunk-hnprkjgp.js").then(({ updateBridgeSessionTitle }) => updateBridgeSessionTitle(compatSessionId, title, {
1360
+ baseUrl: config.apiBaseUrl
1361
+ })).catch((err) => logForDebugging(`[bridge:title] failed to update title for ${compatSessionId}: ${err}`, { level: "error" }));
1362
+ }
1363
+ }, sessionDir);
1364
+ if (typeof spawnResult === "string") {
1365
+ logger.logError(`Failed to spawn session ${sessionId}: ${spawnResult}`);
1366
+ const wt = sessionWorktrees.get(sessionId);
1367
+ if (wt) {
1368
+ sessionWorktrees.delete(sessionId);
1369
+ trackCleanup(removeAgentWorktree(wt.worktreePath, wt.worktreeBranch, wt.gitRoot, wt.hookBased).catch((err) => logger.logVerbose(`Failed to remove worktree ${wt.worktreePath}: ${errorMessage(err)}`)));
1370
+ }
1371
+ completedWorkIds.add(work.id);
1372
+ trackCleanup(stopWorkWithRetry(api, environmentId, work.id, logger, backoffConfig.stopWorkBaseDelayMs));
1373
+ break;
1374
+ }
1375
+ const handle = spawnResult;
1376
+ const spawnDurationMs = Date.now() - spawnStartTime;
1377
+ logEvent("tengu_bridge_session_started", {
1378
+ active_sessions: activeSessions.size,
1379
+ spawn_mode: spawnModeAtDecision,
1380
+ in_worktree: sessionWorktrees.has(sessionId),
1381
+ spawn_duration_ms: spawnDurationMs,
1382
+ worktree_create_ms: worktreeCreateMs,
1383
+ inProtectedNamespace: isInProtectedNamespace()
1384
+ });
1385
+ logForDiagnosticsNoPII("info", "bridge_session_started", {
1386
+ spawn_mode: spawnModeAtDecision,
1387
+ in_worktree: sessionWorktrees.has(sessionId),
1388
+ spawn_duration_ms: spawnDurationMs,
1389
+ worktree_create_ms: worktreeCreateMs
1390
+ });
1391
+ activeSessions.set(sessionId, handle);
1392
+ sessionWorkIds.set(sessionId, work.id);
1393
+ sessionIngressTokens.set(sessionId, secret.session_ingress_token);
1394
+ sessionCompatIds.set(sessionId, compatSessionId);
1395
+ const startTime = Date.now();
1396
+ sessionStartTimes.set(sessionId, startTime);
1397
+ logger.logSessionStart(sessionId, `Session ${sessionId}`);
1398
+ const safeId = safeFilenameId(sessionId);
1399
+ let sessionDebugFile;
1400
+ if (config.debugFile) {
1401
+ const ext = config.debugFile.lastIndexOf(".");
1402
+ if (ext > 0) {
1403
+ sessionDebugFile = `${config.debugFile.slice(0, ext)}-${safeId}${config.debugFile.slice(ext)}`;
1404
+ } else {
1405
+ sessionDebugFile = `${config.debugFile}-${safeId}`;
1406
+ }
1407
+ } else if (config.verbose || process.env.USER_TYPE === "ant") {
1408
+ sessionDebugFile = join2(tmpdir2(), "claude", `bridge-session-${safeId}.log`);
1409
+ }
1410
+ if (sessionDebugFile) {
1411
+ logger.logVerbose(`Debug log: ${sessionDebugFile}`);
1412
+ }
1413
+ logger.addSession(compatSessionId, getRemoteSessionUrl(compatSessionId, config.sessionIngressUrl));
1414
+ startStatusUpdates();
1415
+ logger.setAttached(compatSessionId);
1416
+ fetchSessionTitle(compatSessionId, config.apiBaseUrl).then((title) => {
1417
+ if (title && activeSessions.has(sessionId)) {
1418
+ titledSessions.add(compatSessionId);
1419
+ logger.setSessionTitle(compatSessionId, title);
1420
+ logForDebugging(`[bridge:title] server title for ${compatSessionId}: ${title}`);
1421
+ }
1422
+ }).catch((err) => logForDebugging(`[bridge:title] failed to fetch title for ${compatSessionId}: ${err}`, { level: "error" }));
1423
+ const timeoutMs = config.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
1424
+ if (timeoutMs > 0) {
1425
+ const timer = setTimeout(onSessionTimeout, timeoutMs, sessionId, timeoutMs, logger, timedOutSessions, handle);
1426
+ sessionTimers.set(sessionId, timer);
1427
+ }
1428
+ if (useCcrV2) {
1429
+ v2Sessions.add(sessionId);
1430
+ }
1431
+ tokenRefresh?.schedule(sessionId, secret.session_ingress_token);
1432
+ handle.done.then(onSessionDone(sessionId, startTime, handle));
1433
+ break;
1434
+ }
1435
+ default:
1436
+ await ackWork();
1437
+ logForDebugging(`[bridge:work] Unknown work type: ${workType}, skipping`);
1438
+ break;
1439
+ }
1440
+ if (atCapacityBeforeSwitch) {
1441
+ const cap = capacityWake.signal();
1442
+ if (pollConfig.non_exclusive_heartbeat_interval_ms > 0) {
1443
+ await heartbeatActiveWorkItems();
1444
+ await sleep(pollConfig.non_exclusive_heartbeat_interval_ms, cap.signal);
1445
+ } else if (pollConfig.multisession_poll_interval_ms_at_capacity > 0) {
1446
+ await sleep(pollConfig.multisession_poll_interval_ms_at_capacity, cap.signal);
1447
+ }
1448
+ cap.cleanup();
1449
+ }
1450
+ } catch (err) {
1451
+ if (loopSignal.aborted) {
1452
+ break;
1453
+ }
1454
+ if (err instanceof BridgeFatalError) {
1455
+ fatalExit = true;
1456
+ if (isExpiredErrorType(err.errorType)) {
1457
+ logger.logStatus(err.message);
1458
+ } else if (isSuppressible403(err)) {
1459
+ logForDebugging(`[bridge:work] Suppressed 403 error: ${err.message}`);
1460
+ } else {
1461
+ logger.logError(err.message);
1462
+ logError(err);
1463
+ }
1464
+ logEvent("tengu_bridge_fatal_error", {
1465
+ status: err.status,
1466
+ error_type: err.errorType
1467
+ });
1468
+ logForDiagnosticsNoPII(isExpiredErrorType(err.errorType) ? "info" : "error", "bridge_fatal_error", { status: err.status, error_type: err.errorType });
1469
+ break;
1470
+ }
1471
+ const errMsg = describeAxiosError(err);
1472
+ rcLog(`poll error: ${errMsg}` + ` isConn=${isConnectionError(err)} isServer=${isServerError(err)}` + ` activeSessions=${activeSessions.size}`);
1473
+ if (isConnectionError(err) || isServerError(err)) {
1474
+ const now = Date.now();
1475
+ if (lastPollErrorTime !== null && now - lastPollErrorTime > pollSleepDetectionThresholdMs(backoffConfig)) {
1476
+ logForDebugging(`[bridge:work] Detected system sleep (${Math.round((now - lastPollErrorTime) / 1000)}s gap), resetting error budget`);
1477
+ logForDiagnosticsNoPII("info", "bridge_poll_sleep_detected", {
1478
+ gapMs: now - lastPollErrorTime
1479
+ });
1480
+ connErrorStart = null;
1481
+ connBackoff = 0;
1482
+ generalErrorStart = null;
1483
+ generalBackoff = 0;
1484
+ }
1485
+ lastPollErrorTime = now;
1486
+ if (!connErrorStart) {
1487
+ connErrorStart = now;
1488
+ }
1489
+ const elapsed = now - connErrorStart;
1490
+ if (elapsed >= backoffConfig.connGiveUpMs) {
1491
+ logger.logError(`Server unreachable for ${Math.round(elapsed / 60000)} minutes, giving up.`);
1492
+ logEvent("tengu_bridge_poll_give_up", {
1493
+ error_type: "connection",
1494
+ elapsed_ms: elapsed
1495
+ });
1496
+ logForDiagnosticsNoPII("error", "bridge_poll_give_up", {
1497
+ error_type: "connection",
1498
+ elapsed_ms: elapsed
1499
+ });
1500
+ fatalExit = true;
1501
+ break;
1502
+ }
1503
+ generalErrorStart = null;
1504
+ generalBackoff = 0;
1505
+ connBackoff = connBackoff ? Math.min(connBackoff * 2, backoffConfig.connCapMs) : backoffConfig.connInitialMs;
1506
+ const delay = addJitter(connBackoff);
1507
+ logger.logVerbose(`Connection error, retrying in ${formatDelay(delay)} (${Math.round(elapsed / 1000)}s elapsed): ${errMsg}`);
1508
+ logger.updateReconnectingStatus(formatDelay(delay), formatDuration(elapsed));
1509
+ if (getPollIntervalConfig().non_exclusive_heartbeat_interval_ms > 0) {
1510
+ await heartbeatActiveWorkItems();
1511
+ }
1512
+ await sleep(delay, loopSignal);
1513
+ } else {
1514
+ const now = Date.now();
1515
+ if (lastPollErrorTime !== null && now - lastPollErrorTime > pollSleepDetectionThresholdMs(backoffConfig)) {
1516
+ logForDebugging(`[bridge:work] Detected system sleep (${Math.round((now - lastPollErrorTime) / 1000)}s gap), resetting error budget`);
1517
+ logForDiagnosticsNoPII("info", "bridge_poll_sleep_detected", {
1518
+ gapMs: now - lastPollErrorTime
1519
+ });
1520
+ connErrorStart = null;
1521
+ connBackoff = 0;
1522
+ generalErrorStart = null;
1523
+ generalBackoff = 0;
1524
+ }
1525
+ lastPollErrorTime = now;
1526
+ if (!generalErrorStart) {
1527
+ generalErrorStart = now;
1528
+ }
1529
+ const elapsed = now - generalErrorStart;
1530
+ if (elapsed >= backoffConfig.generalGiveUpMs) {
1531
+ logger.logError(`Persistent errors for ${Math.round(elapsed / 60000)} minutes, giving up.`);
1532
+ logEvent("tengu_bridge_poll_give_up", {
1533
+ error_type: "general",
1534
+ elapsed_ms: elapsed
1535
+ });
1536
+ logForDiagnosticsNoPII("error", "bridge_poll_give_up", {
1537
+ error_type: "general",
1538
+ elapsed_ms: elapsed
1539
+ });
1540
+ fatalExit = true;
1541
+ break;
1542
+ }
1543
+ connErrorStart = null;
1544
+ connBackoff = 0;
1545
+ generalBackoff = generalBackoff ? Math.min(generalBackoff * 2, backoffConfig.generalCapMs) : backoffConfig.generalInitialMs;
1546
+ const delay = addJitter(generalBackoff);
1547
+ logger.logVerbose(`Poll failed, retrying in ${formatDelay(delay)} (${Math.round(elapsed / 1000)}s elapsed): ${errMsg}`);
1548
+ logger.updateReconnectingStatus(formatDelay(delay), formatDuration(elapsed));
1549
+ if (getPollIntervalConfig().non_exclusive_heartbeat_interval_ms > 0) {
1550
+ await heartbeatActiveWorkItems();
1551
+ }
1552
+ await sleep(delay, loopSignal);
1553
+ }
1554
+ }
1555
+ }
1556
+ stopStatusUpdates();
1557
+ logger.clearStatus();
1558
+ const loopDurationMs = Date.now() - loopStartTime;
1559
+ logEvent("tengu_bridge_shutdown", {
1560
+ active_sessions: activeSessions.size,
1561
+ loop_duration_ms: loopDurationMs
1562
+ });
1563
+ logForDiagnosticsNoPII("info", "bridge_shutdown", {
1564
+ active_sessions: activeSessions.size,
1565
+ loop_duration_ms: loopDurationMs
1566
+ });
1567
+ const sessionsToArchive = new Set(activeSessions.keys());
1568
+ if (initialSessionId) {
1569
+ sessionsToArchive.add(initialSessionId);
1570
+ }
1571
+ const compatIdSnapshot = new Map(sessionCompatIds);
1572
+ if (activeSessions.size > 0) {
1573
+ logForDebugging(`[bridge:shutdown] Shutting down ${activeSessions.size} active session(s)`);
1574
+ logger.logStatus(`Shutting down ${activeSessions.size} active session(s)\u2026`);
1575
+ const shutdownWorkIds = new Map(sessionWorkIds);
1576
+ for (const [sessionId, handle] of activeSessions.entries()) {
1577
+ logForDebugging(`[bridge:shutdown] Sending SIGTERM to sessionId=${sessionId}`);
1578
+ handle.kill();
1579
+ }
1580
+ const timeout = new AbortController;
1581
+ await Promise.race([
1582
+ Promise.allSettled([...activeSessions.values()].map((h) => h.done)),
1583
+ sleep(backoffConfig.shutdownGraceMs ?? 30000, timeout.signal)
1584
+ ]);
1585
+ timeout.abort();
1586
+ for (const [sid, handle] of activeSessions.entries()) {
1587
+ logForDebugging(`[bridge:shutdown] Force-killing stuck sessionId=${sid}`);
1588
+ handle.forceKill();
1589
+ }
1590
+ for (const timer of sessionTimers.values()) {
1591
+ clearTimeout(timer);
1592
+ }
1593
+ sessionTimers.clear();
1594
+ tokenRefresh?.cancelAll();
1595
+ if (sessionWorktrees.size > 0) {
1596
+ const remainingWorktrees = [...sessionWorktrees.values()];
1597
+ sessionWorktrees.clear();
1598
+ logForDebugging(`[bridge:shutdown] Cleaning up ${remainingWorktrees.length} worktree(s)`);
1599
+ await Promise.allSettled(remainingWorktrees.map((wt) => removeAgentWorktree(wt.worktreePath, wt.worktreeBranch, wt.gitRoot, wt.hookBased)));
1600
+ }
1601
+ await Promise.allSettled([...shutdownWorkIds.entries()].map(([sessionId, workId]) => {
1602
+ return api.stopWork(environmentId, workId, true).catch((err) => logger.logVerbose(`Failed to stop work ${workId} for session ${sessionId}: ${errorMessage(err)}`));
1603
+ }));
1604
+ }
1605
+ if (pendingCleanups.size > 0) {
1606
+ await Promise.allSettled([...pendingCleanups]);
1607
+ }
1608
+ if (config.spawnMode === "single-session" && initialSessionId && !fatalExit) {
1609
+ logger.logStatus(`Resume this session by running \`redscope remote-control --continue\``);
1610
+ logForDebugging(`[bridge:shutdown] Skipping archive+deregister to allow resume of session ${initialSessionId}`);
1611
+ return;
1612
+ }
1613
+ if (sessionsToArchive.size > 0) {
1614
+ logForDebugging(`[bridge:shutdown] Archiving ${sessionsToArchive.size} session(s)`);
1615
+ await Promise.allSettled([...sessionsToArchive].map((sessionId) => api.archiveSession(compatIdSnapshot.get(sessionId) ?? toCompatSessionId(sessionId)).catch((err) => logger.logVerbose(`Failed to archive session ${sessionId}: ${errorMessage(err)}`))));
1616
+ }
1617
+ try {
1618
+ await api.deregisterEnvironment(environmentId);
1619
+ logForDebugging(`[bridge:shutdown] Environment deregistered, bridge offline`);
1620
+ logger.logVerbose("Environment deregistered.");
1621
+ } catch (err) {
1622
+ logger.logVerbose(`Failed to deregister environment: ${errorMessage(err)}`);
1623
+ }
1624
+ const { clearBridgePointer } = await import("./chunk-1a5cep8h.js");
1625
+ await clearBridgePointer(config.dir);
1626
+ logger.logVerbose("Environment offline.");
1627
+ }
1628
+ var CONNECTION_ERROR_CODES = new Set([
1629
+ "ECONNREFUSED",
1630
+ "ECONNRESET",
1631
+ "ETIMEDOUT",
1632
+ "ENETUNREACH",
1633
+ "EHOSTUNREACH"
1634
+ ]);
1635
+ function isConnectionError(err) {
1636
+ if (err && typeof err === "object" && "code" in err && typeof err.code === "string" && CONNECTION_ERROR_CODES.has(err.code)) {
1637
+ return true;
1638
+ }
1639
+ return false;
1640
+ }
1641
+ function isServerError(err) {
1642
+ return !!err && typeof err === "object" && "code" in err && typeof err.code === "string" && err.code === "ERR_BAD_RESPONSE";
1643
+ }
1644
+ function addJitter(ms) {
1645
+ return Math.max(0, ms + ms * 0.25 * (2 * Math.random() - 1));
1646
+ }
1647
+ function formatDelay(ms) {
1648
+ return ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.round(ms)}ms`;
1649
+ }
1650
+ async function stopWorkWithRetry(api, environmentId, workId, logger, baseDelayMs = 1000) {
1651
+ const MAX_ATTEMPTS = 3;
1652
+ for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
1653
+ try {
1654
+ await api.stopWork(environmentId, workId, false);
1655
+ logForDebugging(`[bridge:work] stopWork succeeded for workId=${workId} on attempt ${attempt}/${MAX_ATTEMPTS}`);
1656
+ return;
1657
+ } catch (err) {
1658
+ if (err instanceof BridgeFatalError) {
1659
+ if (isSuppressible403(err)) {
1660
+ logForDebugging(`[bridge:work] Suppressed stopWork 403 for ${workId}: ${err.message}`);
1661
+ } else {
1662
+ logger.logError(`Failed to stop work ${workId}: ${err.message}`);
1663
+ }
1664
+ logForDiagnosticsNoPII("error", "bridge_stop_work_failed", {
1665
+ attempts: attempt,
1666
+ fatal: true
1667
+ });
1668
+ return;
1669
+ }
1670
+ const errMsg = errorMessage(err);
1671
+ if (attempt < MAX_ATTEMPTS) {
1672
+ const delay = addJitter(baseDelayMs * 2 ** (attempt - 1));
1673
+ logger.logVerbose(`Failed to stop work ${workId} (attempt ${attempt}/${MAX_ATTEMPTS}), retrying in ${formatDelay(delay)}: ${errMsg}`);
1674
+ await sleep(delay);
1675
+ } else {
1676
+ logger.logError(`Failed to stop work ${workId} after ${MAX_ATTEMPTS} attempts: ${errMsg}`);
1677
+ logForDiagnosticsNoPII("error", "bridge_stop_work_failed", {
1678
+ attempts: MAX_ATTEMPTS
1679
+ });
1680
+ }
1681
+ }
1682
+ }
1683
+ }
1684
+ function onSessionTimeout(sessionId, timeoutMs, logger, timedOutSessions, handle) {
1685
+ logForDebugging(`[bridge:session] sessionId=${sessionId} timed out after ${formatDuration(timeoutMs)}`);
1686
+ logEvent("tengu_bridge_session_timeout", {
1687
+ timeout_ms: timeoutMs
1688
+ });
1689
+ logger.logSessionFailed(sessionId, `Session timed out after ${formatDuration(timeoutMs)}`);
1690
+ timedOutSessions.add(sessionId);
1691
+ handle.kill();
1692
+ }
1693
+ var SPAWN_FLAG_VALUES = ["session", "same-dir", "worktree"];
1694
+ function parseSpawnValue(raw) {
1695
+ if (raw === "session")
1696
+ return "single-session";
1697
+ if (raw === "same-dir")
1698
+ return "same-dir";
1699
+ if (raw === "worktree")
1700
+ return "worktree";
1701
+ return `--spawn requires one of: ${SPAWN_FLAG_VALUES.join(", ")} (got: ${raw ?? "<missing>"})`;
1702
+ }
1703
+ function parseCapacityValue(raw) {
1704
+ const n = raw === undefined ? NaN : parseInt(raw, 10);
1705
+ if (isNaN(n) || n < 1) {
1706
+ return `--capacity requires a positive integer (got: ${raw ?? "<missing>"})`;
1707
+ }
1708
+ return n;
1709
+ }
1710
+ function parseArgs(args) {
1711
+ let verbose = false;
1712
+ let sandbox = false;
1713
+ let debugFile;
1714
+ let sessionTimeoutMs;
1715
+ let permissionMode;
1716
+ let name;
1717
+ let help = false;
1718
+ let spawnMode;
1719
+ let capacity;
1720
+ let createSessionInDir;
1721
+ let sessionId;
1722
+ let continueSession = false;
1723
+ for (let i = 0;i < args.length; i++) {
1724
+ const arg = args[i];
1725
+ if (arg === "--help" || arg === "-h") {
1726
+ help = true;
1727
+ } else if (arg === "--verbose" || arg === "-v") {
1728
+ verbose = true;
1729
+ } else if (arg === "--sandbox") {
1730
+ sandbox = true;
1731
+ } else if (arg === "--no-sandbox") {
1732
+ sandbox = false;
1733
+ } else if (arg === "--debug-file" && i + 1 < args.length) {
1734
+ debugFile = resolve(args[++i]);
1735
+ } else if (arg.startsWith("--debug-file=")) {
1736
+ debugFile = resolve(arg.slice("--debug-file=".length));
1737
+ } else if (arg === "--session-timeout" && i + 1 < args.length) {
1738
+ sessionTimeoutMs = parseInt(args[++i], 10) * 1000;
1739
+ } else if (arg.startsWith("--session-timeout=")) {
1740
+ sessionTimeoutMs = parseInt(arg.slice("--session-timeout=".length), 10) * 1000;
1741
+ } else if (arg === "--permission-mode" && i + 1 < args.length) {
1742
+ permissionMode = args[++i];
1743
+ } else if (arg.startsWith("--permission-mode=")) {
1744
+ permissionMode = arg.slice("--permission-mode=".length);
1745
+ } else if (arg === "--name" && i + 1 < args.length) {
1746
+ name = args[++i];
1747
+ } else if (arg.startsWith("--name=")) {
1748
+ name = arg.slice("--name=".length);
1749
+ } else if (arg === "--session-id" && i + 1 < args.length) {
1750
+ sessionId = args[++i];
1751
+ if (!sessionId) {
1752
+ return makeError("--session-id requires a value");
1753
+ }
1754
+ } else if (arg.startsWith("--session-id=")) {
1755
+ sessionId = arg.slice("--session-id=".length);
1756
+ if (!sessionId) {
1757
+ return makeError("--session-id requires a value");
1758
+ }
1759
+ } else if (arg === "--continue" || arg === "-c") {
1760
+ continueSession = true;
1761
+ } else if (arg === "--spawn" || arg.startsWith("--spawn=")) {
1762
+ if (spawnMode !== undefined) {
1763
+ return makeError("--spawn may only be specified once");
1764
+ }
1765
+ const raw = arg.startsWith("--spawn=") ? arg.slice("--spawn=".length) : args[++i];
1766
+ const v = parseSpawnValue(raw);
1767
+ if (v === "single-session" || v === "same-dir" || v === "worktree") {
1768
+ spawnMode = v;
1769
+ } else {
1770
+ return makeError(v);
1771
+ }
1772
+ } else if (arg === "--capacity" || arg.startsWith("--capacity=")) {
1773
+ if (capacity !== undefined) {
1774
+ return makeError("--capacity may only be specified once");
1775
+ }
1776
+ const raw = arg.startsWith("--capacity=") ? arg.slice("--capacity=".length) : args[++i];
1777
+ const v = parseCapacityValue(raw);
1778
+ if (typeof v === "number")
1779
+ capacity = v;
1780
+ else
1781
+ return makeError(v);
1782
+ } else if (arg === "--create-session-in-dir") {
1783
+ createSessionInDir = true;
1784
+ } else if (arg === "--no-create-session-in-dir") {
1785
+ createSessionInDir = false;
1786
+ } else {
1787
+ return makeError(`Unknown argument: ${arg}
1788
+ Run 'redscope remote-control --help' for usage.`);
1789
+ }
1790
+ }
1791
+ if (spawnMode === "single-session" && capacity !== undefined) {
1792
+ return makeError(`--capacity cannot be used with --spawn=session (single-session mode has fixed capacity 1).`);
1793
+ }
1794
+ if ((sessionId || continueSession) && (spawnMode !== undefined || capacity !== undefined || createSessionInDir !== undefined)) {
1795
+ return makeError(`--session-id and --continue cannot be used with --spawn, --capacity, or --create-session-in-dir.`);
1796
+ }
1797
+ if (sessionId && continueSession) {
1798
+ return makeError(`--session-id and --continue cannot be used together.`);
1799
+ }
1800
+ return {
1801
+ verbose,
1802
+ sandbox,
1803
+ debugFile,
1804
+ sessionTimeoutMs,
1805
+ permissionMode,
1806
+ name,
1807
+ spawnMode,
1808
+ capacity,
1809
+ createSessionInDir,
1810
+ sessionId,
1811
+ continueSession,
1812
+ help
1813
+ };
1814
+ function makeError(error) {
1815
+ return {
1816
+ verbose,
1817
+ sandbox,
1818
+ debugFile,
1819
+ sessionTimeoutMs,
1820
+ permissionMode,
1821
+ name,
1822
+ spawnMode,
1823
+ capacity,
1824
+ createSessionInDir,
1825
+ sessionId,
1826
+ continueSession,
1827
+ help,
1828
+ error
1829
+ };
1830
+ }
1831
+ }
1832
+ async function printHelp() {
1833
+ const { EXTERNAL_PERMISSION_MODES } = await import("./chunk-5v95pnq4.js");
1834
+ const modes = EXTERNAL_PERMISSION_MODES.join(", ");
1835
+ const showServer = await isMultiSessionSpawnEnabled();
1836
+ const serverOptions = showServer ? ` --spawn <mode> Spawn mode: same-dir, worktree, session
1837
+ (default: same-dir)
1838
+ --capacity <N> Max concurrent sessions in worktree or
1839
+ same-dir mode (default: ${SPAWN_SESSIONS_DEFAULT})
1840
+ --[no-]create-session-in-dir Pre-create a session in the current
1841
+ directory; in worktree mode this session
1842
+ stays in cwd while on-demand sessions get
1843
+ isolated worktrees (default: on)
1844
+ ` : "";
1845
+ const serverDescription = showServer ? `
1846
+ Remote Control runs as a persistent server that accepts multiple concurrent
1847
+ sessions in the current directory. One session is pre-created on start so
1848
+ you have somewhere to type immediately. Use --spawn=worktree to isolate
1849
+ each on-demand session in its own git worktree, or --spawn=session for
1850
+ the classic single-session mode (exits when that session ends). Press 'w'
1851
+ during runtime to toggle between same-dir and worktree.
1852
+ ` : "";
1853
+ const serverNote = showServer ? ` - Worktree mode requires a git repository or WorktreeCreate/WorktreeRemove hooks
1854
+ ` : "";
1855
+ const help = `
1856
+ Remote Control - Connect your local environment to claude.ai/code
1857
+
1858
+ USAGE
1859
+ redscope remote-control [options]
1860
+ OPTIONS
1861
+ --name <name> Name for the session (shown in claude.ai/code)
1862
+ -c, --continue Resume the last session in this directory
1863
+ --session-id <id> Resume a specific session by ID (cannot be
1864
+ used with spawn flags or --continue)
1865
+ --permission-mode <mode> Permission mode for spawned sessions
1866
+ (${modes})
1867
+ --debug-file <path> Write debug logs to file
1868
+ -v, --verbose Enable verbose output
1869
+ -h, --help Show this help
1870
+ ${serverOptions}
1871
+ DESCRIPTION
1872
+ Remote Control allows you to control sessions on your local device from
1873
+ claude.ai/code (https://claude.ai/code). Run this command in the
1874
+ directory you want to work in, then connect from the RedScope app or web.
1875
+ ${serverDescription}
1876
+ NOTES
1877
+ - You must be logged in with a RedScope account that has a subscription
1878
+ - Run \`redscope\` first in the directory to accept the workspace trust dialog
1879
+ ${serverNote}`;
1880
+ console.log(help);
1881
+ }
1882
+ var TITLE_MAX_LEN = 80;
1883
+ function deriveSessionTitle(text) {
1884
+ const flat = text.replace(/\s+/g, " ").trim();
1885
+ return truncateToWidth(flat, TITLE_MAX_LEN);
1886
+ }
1887
+ async function fetchSessionTitle(compatSessionId, baseUrl) {
1888
+ const { getBridgeSession } = await import("./chunk-hnprkjgp.js");
1889
+ const session = await getBridgeSession(compatSessionId, { baseUrl });
1890
+ return session?.title || undefined;
1891
+ }
1892
+ async function bridgeMain(args) {
1893
+ const parsed = parseArgs(args);
1894
+ if (parsed.help) {
1895
+ await printHelp();
1896
+ return;
1897
+ }
1898
+ if (parsed.error) {
1899
+ console.error(`Error: ${parsed.error}`);
1900
+ process.exit(1);
1901
+ }
1902
+ const {
1903
+ verbose,
1904
+ sandbox,
1905
+ debugFile,
1906
+ sessionTimeoutMs,
1907
+ permissionMode,
1908
+ name,
1909
+ spawnMode: parsedSpawnMode,
1910
+ capacity: parsedCapacity,
1911
+ createSessionInDir: parsedCreateSessionInDir,
1912
+ sessionId: parsedSessionId,
1913
+ continueSession
1914
+ } = parsed;
1915
+ let resumeSessionId = parsedSessionId;
1916
+ let resumePointerDir;
1917
+ const usedMultiSessionFeature = parsedSpawnMode !== undefined || parsedCapacity !== undefined || parsedCreateSessionInDir !== undefined;
1918
+ if (permissionMode !== undefined) {
1919
+ const { PERMISSION_MODES } = await import("./chunk-5v95pnq4.js");
1920
+ const valid = PERMISSION_MODES;
1921
+ if (!valid.includes(permissionMode)) {
1922
+ console.error(`Error: Invalid permission mode '${permissionMode}'. Valid modes: ${valid.join(", ")}`);
1923
+ process.exit(1);
1924
+ }
1925
+ }
1926
+ const dir = resolve(".");
1927
+ const { enableConfigs, checkHasTrustDialogAccepted } = await import("./chunk-bwb1vxnt.js");
1928
+ enableConfigs();
1929
+ const { initSinks } = await import("./chunk-fbtfp370.js");
1930
+ initSinks();
1931
+ const multiSessionEnabled = await isMultiSessionSpawnEnabled();
1932
+ if (usedMultiSessionFeature && !multiSessionEnabled) {
1933
+ await logEventAsync("tengu_bridge_multi_session_denied", {
1934
+ used_spawn: parsedSpawnMode !== undefined,
1935
+ used_capacity: parsedCapacity !== undefined,
1936
+ used_create_session_in_dir: parsedCreateSessionInDir !== undefined
1937
+ });
1938
+ await Promise.race([
1939
+ Promise.all([shutdown1PEventLogging(), shutdownDatadog()]),
1940
+ sleep(500, undefined, { unref: true })
1941
+ ]).catch(() => {});
1942
+ console.error("Error: Multi-session Remote Control is not enabled for your account yet.");
1943
+ process.exit(1);
1944
+ }
1945
+ const { setOriginalCwd, setCwdState } = await import("./chunk-hy566ev3.js");
1946
+ setOriginalCwd(dir);
1947
+ setCwdState(dir);
1948
+ if (!checkHasTrustDialogAccepted()) {
1949
+ console.error(`Error: Workspace not trusted. Please run \`claude\` in ${dir} first to review and accept the workspace trust dialog.`);
1950
+ process.exit(1);
1951
+ }
1952
+ const { clearOAuthTokenCache, checkAndRefreshOAuthTokenIfNeeded } = await import("./chunk-ayymxgn1.js");
1953
+ const { getBridgeAccessToken, getBridgeBaseUrl } = await import("./chunk-nbkbq9en.js");
1954
+ const bridgeToken = getBridgeAccessToken();
1955
+ if (!bridgeToken) {
1956
+ console.error(BRIDGE_LOGIN_ERROR);
1957
+ process.exit(1);
1958
+ }
1959
+ const {
1960
+ getGlobalConfig,
1961
+ saveGlobalConfig,
1962
+ getCurrentProjectConfig,
1963
+ saveCurrentProjectConfig
1964
+ } = await import("./chunk-bwb1vxnt.js");
1965
+ if (!getGlobalConfig().remoteDialogSeen) {
1966
+ const readline = await import("readline");
1967
+ const rl = readline.createInterface({
1968
+ input: process.stdin,
1969
+ output: process.stdout
1970
+ });
1971
+ console.log(`
1972
+ Remote Control lets you access this CLI session from the web (claude.ai/code)
1973
+ or the RedScope app, so you can pick up where you left off on any device.
1974
+
1975
+ You can disconnect remote access anytime by running /remote-control again.
1976
+ `);
1977
+ const answer = await new Promise((resolve2) => {
1978
+ rl.question("Enable Remote Control? (y/n) ", resolve2);
1979
+ });
1980
+ rl.close();
1981
+ saveGlobalConfig((current) => {
1982
+ if (current.remoteDialogSeen)
1983
+ return current;
1984
+ return { ...current, remoteDialogSeen: true };
1985
+ });
1986
+ if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
1987
+ process.exit(0);
1988
+ }
1989
+ }
1990
+ if (continueSession) {
1991
+ const { readBridgePointerAcrossWorktrees } = await import("./chunk-1a5cep8h.js");
1992
+ const found = await readBridgePointerAcrossWorktrees(dir);
1993
+ if (!found) {
1994
+ console.error(`Error: No recent session found in this directory or its worktrees. Run \`redscope remote-control\` to start a new one.`);
1995
+ process.exit(1);
1996
+ }
1997
+ const { pointer, dir: pointerDir } = found;
1998
+ const ageMin = Math.round(pointer.ageMs / 60000);
1999
+ const ageStr = ageMin < 60 ? `${ageMin}m` : `${Math.round(ageMin / 60)}h`;
2000
+ const fromWt = pointerDir !== dir ? ` from worktree ${pointerDir}` : "";
2001
+ console.error(`Resuming session ${pointer.sessionId} (${ageStr} ago)${fromWt}\u2026`);
2002
+ resumeSessionId = pointer.sessionId;
2003
+ resumePointerDir = pointerDir;
2004
+ }
2005
+ const baseUrl = getBridgeBaseUrl();
2006
+ if (baseUrl.startsWith("http://") && !baseUrl.includes("localhost") && !baseUrl.includes("127.0.0.1")) {
2007
+ console.error("Error: Remote Control base URL uses HTTP. Only HTTPS or localhost HTTP is allowed.");
2008
+ process.exit(1);
2009
+ }
2010
+ const sessionIngressUrl = getBridgeSessionIngressUrl(baseUrl);
2011
+ const { getBranch, getRemoteUrl, findGitRoot } = await import("./chunk-xkhnmhqs.js");
2012
+ const { hasWorktreeCreateHook } = await import("./chunk-rxcazxgf.js");
2013
+ const worktreeAvailable = hasWorktreeCreateHook() || findGitRoot(dir) !== null;
2014
+ let savedSpawnMode = multiSessionEnabled ? getCurrentProjectConfig().remoteControlSpawnMode : undefined;
2015
+ if (savedSpawnMode === "worktree" && !worktreeAvailable) {
2016
+ console.error("Warning: Saved spawn mode is worktree but this directory is not a git repository. Falling back to same-dir.");
2017
+ savedSpawnMode = undefined;
2018
+ saveCurrentProjectConfig((current) => {
2019
+ if (current.remoteControlSpawnMode === undefined)
2020
+ return current;
2021
+ return { ...current, remoteControlSpawnMode: undefined };
2022
+ });
2023
+ }
2024
+ if (multiSessionEnabled && !savedSpawnMode && worktreeAvailable && parsedSpawnMode === undefined && !resumeSessionId && process.stdin.isTTY) {
2025
+ const readline = await import("readline");
2026
+ const rl = readline.createInterface({
2027
+ input: process.stdin,
2028
+ output: process.stdout
2029
+ });
2030
+ console.log(`
2031
+ Claude Remote Control is launching in spawn mode which lets you create new sessions in this project from RedScope AI on Web or your Mobile app. Learn more here: https://code.claude.com/docs/en/remote-control
2032
+
2033
+ Spawn mode for this project:
2034
+ ` + ` [1] same-dir \u2014 sessions share the current directory (default)
2035
+ ` + ` [2] worktree \u2014 each session gets an isolated git worktree
2036
+
2037
+ ` + `This can be changed later or explicitly set with --spawn=same-dir or --spawn=worktree.
2038
+ `);
2039
+ const answer = await new Promise((resolve2) => {
2040
+ rl.question("Choose [1/2] (default: 1): ", resolve2);
2041
+ });
2042
+ rl.close();
2043
+ const chosen = answer.trim() === "2" ? "worktree" : "same-dir";
2044
+ savedSpawnMode = chosen;
2045
+ logEvent("tengu_bridge_spawn_mode_chosen", {
2046
+ spawn_mode: chosen
2047
+ });
2048
+ saveCurrentProjectConfig((current) => {
2049
+ if (current.remoteControlSpawnMode === chosen)
2050
+ return current;
2051
+ return { ...current, remoteControlSpawnMode: chosen };
2052
+ });
2053
+ }
2054
+ let spawnModeSource;
2055
+ let spawnMode;
2056
+ if (resumeSessionId) {
2057
+ spawnMode = "single-session";
2058
+ spawnModeSource = "resume";
2059
+ } else if (parsedSpawnMode !== undefined) {
2060
+ spawnMode = parsedSpawnMode;
2061
+ spawnModeSource = "flag";
2062
+ } else if (savedSpawnMode !== undefined) {
2063
+ spawnMode = savedSpawnMode;
2064
+ spawnModeSource = "saved";
2065
+ } else {
2066
+ spawnMode = multiSessionEnabled ? "same-dir" : "single-session";
2067
+ spawnModeSource = "gate_default";
2068
+ }
2069
+ const maxSessions = spawnMode === "single-session" ? 1 : parsedCapacity ?? SPAWN_SESSIONS_DEFAULT;
2070
+ const preCreateSession = parsedCreateSessionInDir ?? true;
2071
+ if (!resumeSessionId) {
2072
+ const { clearBridgePointer } = await import("./chunk-1a5cep8h.js");
2073
+ await clearBridgePointer(dir);
2074
+ }
2075
+ if (spawnMode === "worktree" && !worktreeAvailable) {
2076
+ console.error(`Error: Worktree mode requires a git repository or WorktreeCreate hooks configured. Use --spawn=session for single-session mode.`);
2077
+ process.exit(1);
2078
+ }
2079
+ const branch = await getBranch();
2080
+ const gitRepoUrl = await getRemoteUrl();
2081
+ const machineName = hostname();
2082
+ const bridgeId = randomUUID();
2083
+ const { handleOAuth401Error } = await import("./chunk-ayymxgn1.js");
2084
+ const api = createBridgeApiClient({
2085
+ baseUrl,
2086
+ getAccessToken: getBridgeAccessToken,
2087
+ runnerVersion: "1.0.0",
2088
+ onDebug: logForDebugging,
2089
+ onAuth401: handleOAuth401Error,
2090
+ getTrustedDeviceToken
2091
+ });
2092
+ let reuseEnvironmentId;
2093
+ if (resumeSessionId) {
2094
+ try {
2095
+ validateBridgeId(resumeSessionId, "sessionId");
2096
+ } catch {
2097
+ console.error(`Error: Invalid session ID "${resumeSessionId}". Session IDs must not contain unsafe characters.`);
2098
+ process.exit(1);
2099
+ }
2100
+ await checkAndRefreshOAuthTokenIfNeeded();
2101
+ clearOAuthTokenCache();
2102
+ const { getBridgeSession } = await import("./chunk-hnprkjgp.js");
2103
+ const session = await getBridgeSession(resumeSessionId, {
2104
+ baseUrl,
2105
+ getAccessToken: getBridgeAccessToken
2106
+ });
2107
+ if (!session) {
2108
+ if (resumePointerDir) {
2109
+ const { clearBridgePointer } = await import("./chunk-1a5cep8h.js");
2110
+ await clearBridgePointer(resumePointerDir);
2111
+ }
2112
+ console.error(`Error: Session ${resumeSessionId} not found. It may have been archived or expired, or your login may have lapsed (run \`claude /login\`).`);
2113
+ process.exit(1);
2114
+ }
2115
+ if (!session.environment_id) {
2116
+ if (resumePointerDir) {
2117
+ const { clearBridgePointer } = await import("./chunk-1a5cep8h.js");
2118
+ await clearBridgePointer(resumePointerDir);
2119
+ }
2120
+ console.error(`Error: Session ${resumeSessionId} has no environment_id. It may never have been attached to a bridge.`);
2121
+ process.exit(1);
2122
+ }
2123
+ reuseEnvironmentId = session.environment_id;
2124
+ logForDebugging(`[bridge:init] Resuming session ${resumeSessionId} on environment ${reuseEnvironmentId}`);
2125
+ }
2126
+ const config = {
2127
+ dir,
2128
+ machineName,
2129
+ branch,
2130
+ gitRepoUrl,
2131
+ maxSessions,
2132
+ spawnMode,
2133
+ verbose,
2134
+ sandbox,
2135
+ bridgeId,
2136
+ workerType: "claude_code",
2137
+ environmentId: randomUUID(),
2138
+ reuseEnvironmentId,
2139
+ apiBaseUrl: baseUrl,
2140
+ sessionIngressUrl,
2141
+ debugFile,
2142
+ sessionTimeoutMs
2143
+ };
2144
+ logForDebugging(`[bridge:init] bridgeId=${bridgeId}${reuseEnvironmentId ? ` reuseEnvironmentId=${reuseEnvironmentId}` : ""} dir=${dir} branch=${branch} gitRepoUrl=${gitRepoUrl} machine=${machineName}`);
2145
+ logForDebugging(`[bridge:init] apiBaseUrl=${baseUrl} sessionIngressUrl=${sessionIngressUrl}`);
2146
+ logForDebugging(`[bridge:init] sandbox=${sandbox}${debugFile ? ` debugFile=${debugFile}` : ""}`);
2147
+ let environmentId;
2148
+ let environmentSecret;
2149
+ try {
2150
+ const reg = await api.registerBridgeEnvironment(config);
2151
+ environmentId = reg.environment_id;
2152
+ environmentSecret = reg.environment_secret;
2153
+ } catch (err) {
2154
+ logEvent("tengu_bridge_registration_failed", {
2155
+ status: err instanceof BridgeFatalError ? err.status : undefined
2156
+ });
2157
+ console.error(err instanceof BridgeFatalError && err.status === 404 ? "Remote Control environments are not available for your account." : `Error: ${errorMessage(err)}`);
2158
+ process.exit(1);
2159
+ }
2160
+ let effectiveResumeSessionId;
2161
+ if (resumeSessionId) {
2162
+ if (reuseEnvironmentId && environmentId !== reuseEnvironmentId) {
2163
+ logError(new Error(`Bridge resume env mismatch: requested ${reuseEnvironmentId}, backend returned ${environmentId}. Falling back to fresh session.`));
2164
+ console.warn(`Warning: Could not resume session ${resumeSessionId} \u2014 its environment has expired. Creating a fresh session instead.`);
2165
+ } else {
2166
+ const infraResumeId = toInfraSessionId(resumeSessionId);
2167
+ const reconnectCandidates = infraResumeId === resumeSessionId ? [resumeSessionId] : [resumeSessionId, infraResumeId];
2168
+ let reconnected = false;
2169
+ let lastReconnectErr;
2170
+ for (const candidateId of reconnectCandidates) {
2171
+ try {
2172
+ await api.reconnectSession(environmentId, candidateId);
2173
+ logForDebugging(`[bridge:init] Session ${candidateId} re-queued via bridge/reconnect`);
2174
+ effectiveResumeSessionId = resumeSessionId;
2175
+ reconnected = true;
2176
+ break;
2177
+ } catch (err) {
2178
+ lastReconnectErr = err;
2179
+ logForDebugging(`[bridge:init] reconnectSession(${candidateId}) failed: ${errorMessage(err)}`);
2180
+ }
2181
+ }
2182
+ if (!reconnected) {
2183
+ const err = lastReconnectErr;
2184
+ const isFatal = err instanceof BridgeFatalError;
2185
+ if (resumePointerDir && isFatal) {
2186
+ const { clearBridgePointer } = await import("./chunk-1a5cep8h.js");
2187
+ await clearBridgePointer(resumePointerDir);
2188
+ }
2189
+ console.error(isFatal ? `Error: ${errorMessage(err)}` : `Error: Failed to reconnect session ${resumeSessionId}: ${errorMessage(err)}
2190
+ The session may still be resumable \u2014 try running the same command again.`);
2191
+ process.exit(1);
2192
+ }
2193
+ }
2194
+ }
2195
+ logForDebugging(`[bridge:init] Registered, server environmentId=${environmentId}`);
2196
+ const startupPollConfig = getPollIntervalConfig();
2197
+ logEvent("tengu_bridge_started", {
2198
+ max_sessions: config.maxSessions,
2199
+ has_debug_file: !!config.debugFile,
2200
+ sandbox: config.sandbox,
2201
+ verbose: config.verbose,
2202
+ heartbeat_interval_ms: startupPollConfig.non_exclusive_heartbeat_interval_ms,
2203
+ spawn_mode: config.spawnMode,
2204
+ spawn_mode_source: spawnModeSource,
2205
+ multi_session_gate: multiSessionEnabled,
2206
+ pre_create_session: preCreateSession,
2207
+ worktree_available: worktreeAvailable
2208
+ });
2209
+ logForDiagnosticsNoPII("info", "bridge_started", {
2210
+ max_sessions: config.maxSessions,
2211
+ sandbox: config.sandbox,
2212
+ spawn_mode: config.spawnMode
2213
+ });
2214
+ const spawner = createSessionSpawner({
2215
+ execPath: process.execPath,
2216
+ scriptArgs: spawnScriptArgs(),
2217
+ env: process.env,
2218
+ verbose,
2219
+ sandbox,
2220
+ debugFile,
2221
+ permissionMode,
2222
+ onDebug: logForDebugging,
2223
+ onActivity: (sessionId, activity) => {
2224
+ logForDebugging(`[bridge:activity] sessionId=${sessionId} ${activity.type} ${activity.summary}`);
2225
+ },
2226
+ onPermissionRequest: (sessionId, request, _accessToken) => {
2227
+ logForDebugging(`[bridge:perm] sessionId=${sessionId} tool=${request.request.tool_name} request_id=${request.request_id} (not auto-approving)`);
2228
+ }
2229
+ });
2230
+ const logger = createBridgeLogger({ verbose });
2231
+ const { parseGitHubRepository } = await import("./chunk-z9nsjcht.js");
2232
+ const ownerRepo = gitRepoUrl ? parseGitHubRepository(gitRepoUrl) : null;
2233
+ const repoName = ownerRepo ? ownerRepo.split("/").pop() : basename(dir);
2234
+ logger.setRepoInfo(repoName, branch);
2235
+ const toggleAvailable = spawnMode !== "single-session" && worktreeAvailable;
2236
+ if (toggleAvailable) {
2237
+ logger.setSpawnModeDisplay(spawnMode);
2238
+ }
2239
+ const onStdinData = (data) => {
2240
+ if (data[0] === 3 || data[0] === 4) {
2241
+ process.emit("SIGINT");
2242
+ return;
2243
+ }
2244
+ if (data[0] === 32) {
2245
+ logger.toggleQr();
2246
+ return;
2247
+ }
2248
+ if (data[0] === 119) {
2249
+ if (!toggleAvailable)
2250
+ return;
2251
+ const newMode = config.spawnMode === "same-dir" ? "worktree" : "same-dir";
2252
+ config.spawnMode = newMode;
2253
+ logEvent("tengu_bridge_spawn_mode_toggled", {
2254
+ spawn_mode: newMode
2255
+ });
2256
+ logger.logStatus(newMode === "worktree" ? "Spawn mode: worktree (new sessions get isolated git worktrees)" : "Spawn mode: same-dir (new sessions share the current directory)");
2257
+ logger.setSpawnModeDisplay(newMode);
2258
+ logger.refreshDisplay();
2259
+ saveCurrentProjectConfig((current) => {
2260
+ if (current.remoteControlSpawnMode === newMode)
2261
+ return current;
2262
+ return { ...current, remoteControlSpawnMode: newMode };
2263
+ });
2264
+ return;
2265
+ }
2266
+ };
2267
+ if (process.stdin.isTTY) {
2268
+ process.stdin.setRawMode(true);
2269
+ process.stdin.resume();
2270
+ process.stdin.on("data", onStdinData);
2271
+ }
2272
+ const controller = new AbortController;
2273
+ const onSigint = () => {
2274
+ logForDebugging("[bridge:shutdown] SIGINT received, shutting down");
2275
+ controller.abort();
2276
+ };
2277
+ const onSigterm = () => {
2278
+ logForDebugging("[bridge:shutdown] SIGTERM received, shutting down");
2279
+ controller.abort();
2280
+ };
2281
+ process.on("SIGINT", onSigint);
2282
+ process.on("SIGTERM", onSigterm);
2283
+ let initialSessionId = effectiveResumeSessionId ? effectiveResumeSessionId : null;
2284
+ if (preCreateSession && !effectiveResumeSessionId) {
2285
+ const { createBridgeSession } = await import("./chunk-hnprkjgp.js");
2286
+ try {
2287
+ initialSessionId = await createBridgeSession({
2288
+ environmentId,
2289
+ title: name,
2290
+ events: [],
2291
+ gitRepoUrl,
2292
+ branch,
2293
+ signal: controller.signal,
2294
+ baseUrl,
2295
+ getAccessToken: getBridgeAccessToken,
2296
+ permissionMode
2297
+ });
2298
+ if (initialSessionId) {
2299
+ logForDebugging(`[bridge:init] Created initial session ${initialSessionId}`);
2300
+ }
2301
+ } catch (err) {
2302
+ logForDebugging(`[bridge:init] Session creation failed (non-fatal): ${errorMessage(err)}`);
2303
+ }
2304
+ }
2305
+ let pointerRefreshTimer = null;
2306
+ if (initialSessionId && spawnMode === "single-session") {
2307
+ const { writeBridgePointer } = await import("./chunk-1a5cep8h.js");
2308
+ const pointerPayload = {
2309
+ sessionId: initialSessionId,
2310
+ environmentId,
2311
+ source: "standalone"
2312
+ };
2313
+ await writeBridgePointer(config.dir, pointerPayload);
2314
+ pointerRefreshTimer = setInterval(writeBridgePointer, 3600000, config.dir, pointerPayload);
2315
+ pointerRefreshTimer.unref?.();
2316
+ }
2317
+ try {
2318
+ await runBridgeLoop(config, environmentId, environmentSecret, api, spawner, logger, controller.signal, undefined, initialSessionId ?? undefined, async () => {
2319
+ clearOAuthTokenCache();
2320
+ await checkAndRefreshOAuthTokenIfNeeded();
2321
+ return getBridgeAccessToken();
2322
+ });
2323
+ } finally {
2324
+ if (pointerRefreshTimer !== null) {
2325
+ clearInterval(pointerRefreshTimer);
2326
+ }
2327
+ process.off("SIGINT", onSigint);
2328
+ process.off("SIGTERM", onSigterm);
2329
+ process.stdin.off("data", onStdinData);
2330
+ if (process.stdin.isTTY) {
2331
+ process.stdin.setRawMode(false);
2332
+ }
2333
+ process.stdin.pause();
2334
+ }
2335
+ process.exit(0);
2336
+ }
2337
+
2338
+ class BridgeHeadlessPermanentError extends Error {
2339
+ constructor(message) {
2340
+ super(message);
2341
+ this.name = "BridgeHeadlessPermanentError";
2342
+ }
2343
+ }
2344
+ async function runBridgeHeadless(opts, signal) {
2345
+ const { dir, log } = opts;
2346
+ process.chdir(dir);
2347
+ const { setOriginalCwd, setCwdState } = await import("./chunk-hy566ev3.js");
2348
+ setOriginalCwd(dir);
2349
+ setCwdState(dir);
2350
+ const { enableConfigs, checkHasTrustDialogAccepted } = await import("./chunk-bwb1vxnt.js");
2351
+ enableConfigs();
2352
+ const { initSinks } = await import("./chunk-fbtfp370.js");
2353
+ initSinks();
2354
+ if (!checkHasTrustDialogAccepted()) {
2355
+ throw new BridgeHeadlessPermanentError(`Workspace not trusted: ${dir}. Run \`claude\` in that directory first to accept the trust dialog.`);
2356
+ }
2357
+ if (!opts.getAccessToken()) {
2358
+ throw new Error(BRIDGE_LOGIN_ERROR);
2359
+ }
2360
+ const { getBridgeBaseUrl } = await import("./chunk-nbkbq9en.js");
2361
+ const baseUrl = getBridgeBaseUrl();
2362
+ if (baseUrl.startsWith("http://") && !baseUrl.includes("localhost") && !baseUrl.includes("127.0.0.1")) {
2363
+ throw new BridgeHeadlessPermanentError("Remote Control base URL uses HTTP. Only HTTPS or localhost HTTP is allowed.");
2364
+ }
2365
+ const sessionIngressUrl = getBridgeSessionIngressUrl(baseUrl);
2366
+ const { getBranch, getRemoteUrl, findGitRoot } = await import("./chunk-xkhnmhqs.js");
2367
+ const { hasWorktreeCreateHook } = await import("./chunk-rxcazxgf.js");
2368
+ if (opts.spawnMode === "worktree") {
2369
+ const worktreeAvailable = hasWorktreeCreateHook() || findGitRoot(dir) !== null;
2370
+ if (!worktreeAvailable) {
2371
+ throw new BridgeHeadlessPermanentError(`Worktree mode requires a git repository or WorktreeCreate hooks. Directory ${dir} has neither.`);
2372
+ }
2373
+ }
2374
+ const branch = await getBranch();
2375
+ const gitRepoUrl = await getRemoteUrl();
2376
+ const machineName = hostname();
2377
+ const bridgeId = randomUUID();
2378
+ const config = {
2379
+ dir,
2380
+ machineName,
2381
+ branch,
2382
+ gitRepoUrl,
2383
+ maxSessions: opts.capacity,
2384
+ spawnMode: opts.spawnMode,
2385
+ verbose: false,
2386
+ sandbox: opts.sandbox,
2387
+ bridgeId,
2388
+ workerType: "claude_code",
2389
+ environmentId: randomUUID(),
2390
+ apiBaseUrl: baseUrl,
2391
+ sessionIngressUrl,
2392
+ sessionTimeoutMs: opts.sessionTimeoutMs
2393
+ };
2394
+ const api = createBridgeApiClient({
2395
+ baseUrl,
2396
+ getAccessToken: opts.getAccessToken,
2397
+ runnerVersion: "1.0.0",
2398
+ onDebug: log,
2399
+ onAuth401: opts.onAuth401,
2400
+ getTrustedDeviceToken
2401
+ });
2402
+ let environmentId;
2403
+ let environmentSecret;
2404
+ try {
2405
+ const reg = await api.registerBridgeEnvironment(config);
2406
+ environmentId = reg.environment_id;
2407
+ environmentSecret = reg.environment_secret;
2408
+ } catch (err) {
2409
+ throw new Error(`Bridge registration failed: ${errorMessage(err)}`);
2410
+ }
2411
+ const spawner = createSessionSpawner({
2412
+ execPath: process.execPath,
2413
+ scriptArgs: spawnScriptArgs(),
2414
+ env: process.env,
2415
+ verbose: false,
2416
+ sandbox: opts.sandbox,
2417
+ permissionMode: opts.permissionMode,
2418
+ onDebug: log
2419
+ });
2420
+ const logger = createHeadlessBridgeLogger(log);
2421
+ logger.printBanner(config, environmentId);
2422
+ let initialSessionId;
2423
+ if (opts.createSessionOnStart) {
2424
+ const { createBridgeSession } = await import("./chunk-hnprkjgp.js");
2425
+ try {
2426
+ const sid = await createBridgeSession({
2427
+ environmentId,
2428
+ title: opts.name,
2429
+ events: [],
2430
+ gitRepoUrl,
2431
+ branch,
2432
+ signal,
2433
+ baseUrl,
2434
+ getAccessToken: opts.getAccessToken,
2435
+ permissionMode: opts.permissionMode
2436
+ });
2437
+ if (sid) {
2438
+ initialSessionId = sid;
2439
+ log(`created initial session ${sid}`);
2440
+ }
2441
+ } catch (err) {
2442
+ log(`session pre-creation failed (non-fatal): ${errorMessage(err)}`);
2443
+ }
2444
+ }
2445
+ await runBridgeLoop(config, environmentId, environmentSecret, api, spawner, logger, signal, undefined, initialSessionId, async () => opts.getAccessToken());
2446
+ }
2447
+ function createHeadlessBridgeLogger(log) {
2448
+ const noop = () => {};
2449
+ return {
2450
+ printBanner: (cfg, envId) => log(`registered environmentId=${envId} dir=${cfg.dir} spawnMode=${cfg.spawnMode} capacity=${cfg.maxSessions}`),
2451
+ logSessionStart: (id, _prompt) => log(`session start ${id}`),
2452
+ logSessionComplete: (id, ms) => log(`session complete ${id} (${ms}ms)`),
2453
+ logSessionFailed: (id, err) => log(`session failed ${id}: ${err}`),
2454
+ logStatus: log,
2455
+ logVerbose: log,
2456
+ logError: (s) => log(`error: ${s}`),
2457
+ logReconnected: (ms) => log(`reconnected after ${ms}ms`),
2458
+ addSession: (id, _url) => log(`session attached ${id}`),
2459
+ removeSession: (id) => log(`session detached ${id}`),
2460
+ updateIdleStatus: noop,
2461
+ updateReconnectingStatus: noop,
2462
+ updateSessionStatus: noop,
2463
+ updateSessionActivity: noop,
2464
+ updateSessionCount: noop,
2465
+ updateFailedStatus: noop,
2466
+ setSpawnModeDisplay: noop,
2467
+ setRepoInfo: noop,
2468
+ setDebugLogPath: noop,
2469
+ setAttached: noop,
2470
+ setSessionTitle: noop,
2471
+ clearStatus: noop,
2472
+ toggleQr: noop,
2473
+ refreshDisplay: noop
2474
+ };
2475
+ }
2476
+
2477
+ export { runBridgeLoop, isConnectionError, isServerError, parseArgs, bridgeMain, BridgeHeadlessPermanentError, runBridgeHeadless };