tmux-ide 1.3.1 → 2.1.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 (603) hide show
  1. package/bin/cli.js +4 -216
  2. package/bin/cli.ts +536 -0
  3. package/dashboard/out/404/index.html +1 -0
  4. package/dashboard/out/404.html +1 -0
  5. package/dashboard/out/__next.__PAGE__.txt +9 -0
  6. package/dashboard/out/__next._full.txt +21 -0
  7. package/dashboard/out/__next._head.txt +5 -0
  8. package/dashboard/out/__next._index.txt +7 -0
  9. package/dashboard/out/__next._tree.txt +4 -0
  10. package/dashboard/out/_next/static/WTHSCKfFb30xXXhXuq66f/_buildManifest.js +11 -0
  11. package/dashboard/out/_next/static/WTHSCKfFb30xXXhXuq66f/_clientMiddlewareManifest.json +1 -0
  12. package/dashboard/out/_next/static/WTHSCKfFb30xXXhXuq66f/_ssgManifest.js +1 -0
  13. package/dashboard/out/_next/static/chunks/048e2449530877e2.js +1 -0
  14. package/dashboard/out/_next/static/chunks/053c57bda6abb959.js +1 -0
  15. package/dashboard/out/_next/static/chunks/056760c6c2dd9172.js +1 -0
  16. package/dashboard/out/_next/static/chunks/06ab47357b6d3e35.js +1 -0
  17. package/dashboard/out/_next/static/chunks/0921cbe5dfd6738e.js +1 -0
  18. package/dashboard/out/_next/static/chunks/0b2599bf468cf5ea.js +1 -0
  19. package/dashboard/out/_next/static/chunks/0c012eac08ef2c4f.js +1 -0
  20. package/dashboard/out/_next/static/chunks/0c29e87fcdcffac3.js +1 -0
  21. package/dashboard/out/_next/static/chunks/0e1e98854430c693.js +1 -0
  22. package/dashboard/out/_next/static/chunks/0e24498976a88976.js +1 -0
  23. package/dashboard/out/_next/static/chunks/0e5bf11ff0b9ab90.js +1 -0
  24. package/dashboard/out/_next/static/chunks/0eae0a45ab8416c8.js +1 -0
  25. package/dashboard/out/_next/static/chunks/104797400d9d38ad.js +1 -0
  26. package/dashboard/out/_next/static/chunks/10cfcfce475f9d2d.js +1 -0
  27. package/dashboard/out/_next/static/chunks/11bac38e7cfb4ecc.js +1 -0
  28. package/dashboard/out/_next/static/chunks/120c5f6501ec3529.js +1 -0
  29. package/dashboard/out/_next/static/chunks/121fceb2b1dcd79f.js +1 -0
  30. package/dashboard/out/_next/static/chunks/13726b63e1be6b98.js +1 -0
  31. package/dashboard/out/_next/static/chunks/140c6ce631514660.js +1 -0
  32. package/dashboard/out/_next/static/chunks/1435ee3a51174c97.js +1 -0
  33. package/dashboard/out/_next/static/chunks/14dc927d2e2cca91.js +1 -0
  34. package/dashboard/out/_next/static/chunks/179c3031b292d98e.js +1 -0
  35. package/dashboard/out/_next/static/chunks/181e88957c47e5c1.js +1 -0
  36. package/dashboard/out/_next/static/chunks/18f70ba23873c432.js +1 -0
  37. package/dashboard/out/_next/static/chunks/1b58303b027fd135.js +1 -0
  38. package/dashboard/out/_next/static/chunks/1b5f49a358dcc71e.js +1 -0
  39. package/dashboard/out/_next/static/chunks/1bba44b81585099a.js +1 -0
  40. package/dashboard/out/_next/static/chunks/1bea8dee19a3e9ae.js +1 -0
  41. package/dashboard/out/_next/static/chunks/1cfad21646fc250e.js +1 -0
  42. package/dashboard/out/_next/static/chunks/1d053dc9e1e428ef.js +1 -0
  43. package/dashboard/out/_next/static/chunks/1e7d7639c6f0ee5e.js +1 -0
  44. package/dashboard/out/_next/static/chunks/1f42504ca81463f1.js +1 -0
  45. package/dashboard/out/_next/static/chunks/20c92047399305b4.js +1 -0
  46. package/dashboard/out/_next/static/chunks/214560e9514a9a4d.js +1 -0
  47. package/dashboard/out/_next/static/chunks/21d4ef106914e997.js +1 -0
  48. package/dashboard/out/_next/static/chunks/2586e83fc3dc2588.js +1 -0
  49. package/dashboard/out/_next/static/chunks/267136a09e94f5c2.js +1 -0
  50. package/dashboard/out/_next/static/chunks/271c50b329917c10.js +1 -0
  51. package/dashboard/out/_next/static/chunks/27fccecefffd88b5.js +1 -0
  52. package/dashboard/out/_next/static/chunks/28f058ed331315b6.js +1 -0
  53. package/dashboard/out/_next/static/chunks/28f704f2cc5713eb.js +1 -0
  54. package/dashboard/out/_next/static/chunks/290f67a6cd150a98.js +1 -0
  55. package/dashboard/out/_next/static/chunks/2ad12f4dcc30d30a.js +1 -0
  56. package/dashboard/out/_next/static/chunks/2b650b172078ab92.js +1 -0
  57. package/dashboard/out/_next/static/chunks/2bd91076019a6453.js +1 -0
  58. package/dashboard/out/_next/static/chunks/2e1278563a8e26be.js +1 -0
  59. package/dashboard/out/_next/static/chunks/309eb70780a3d67d.js +1 -0
  60. package/dashboard/out/_next/static/chunks/30f71950992e2307.js +1 -0
  61. package/dashboard/out/_next/static/chunks/31191873c2075784.js +1 -0
  62. package/dashboard/out/_next/static/chunks/31a790921a0c035e.js +1 -0
  63. package/dashboard/out/_next/static/chunks/34f8d7a5a06e8e32.js +1 -0
  64. package/dashboard/out/_next/static/chunks/36b3716436d9bc9d.js +1 -0
  65. package/dashboard/out/_next/static/chunks/3770b7d0ff004de3.js +1 -0
  66. package/dashboard/out/_next/static/chunks/381ab3bd4cffbf4d.js +1 -0
  67. package/dashboard/out/_next/static/chunks/38aa4eada5dcd1a4.js +1 -0
  68. package/dashboard/out/_next/static/chunks/39723132b78cb77e.js +1 -0
  69. package/dashboard/out/_next/static/chunks/399efdcc3fe56e09.js +1 -0
  70. package/dashboard/out/_next/static/chunks/3a8431a9221b0706.js +1 -0
  71. package/dashboard/out/_next/static/chunks/3a9b40810ce88cbf.js +1 -0
  72. package/dashboard/out/_next/static/chunks/3b322e3e9476ecdf.js +1 -0
  73. package/dashboard/out/_next/static/chunks/3bb14befeeb08c28.js +1 -0
  74. package/dashboard/out/_next/static/chunks/3c99637ebd462b20.js +1 -0
  75. package/dashboard/out/_next/static/chunks/3cbb9217d56459d8.js +1 -0
  76. package/dashboard/out/_next/static/chunks/3d438e0929a762f7.js +1 -0
  77. package/dashboard/out/_next/static/chunks/3e6d4834e0752f76.js +2 -0
  78. package/dashboard/out/_next/static/chunks/3e6f8cedaad4e89b.js +1 -0
  79. package/dashboard/out/_next/static/chunks/3e701259ce1b53e3.js +1 -0
  80. package/dashboard/out/_next/static/chunks/41562f7ab7c033eb.js +1 -0
  81. package/dashboard/out/_next/static/chunks/418fadd8a94e2fd7.js +1 -0
  82. package/dashboard/out/_next/static/chunks/42345437bb922e9c.js +1 -0
  83. package/dashboard/out/_next/static/chunks/434b6bd78c97b668.js +1 -0
  84. package/dashboard/out/_next/static/chunks/434febe897d33e2d.js +1 -0
  85. package/dashboard/out/_next/static/chunks/45d28707dd8ce1c1.js +1 -0
  86. package/dashboard/out/_next/static/chunks/4620a640e88cb1b7.js +1 -0
  87. package/dashboard/out/_next/static/chunks/468f8eb604502ea4.js +1 -0
  88. package/dashboard/out/_next/static/chunks/495f5cedf8afe823.js +1 -0
  89. package/dashboard/out/_next/static/chunks/49a89d1704d27740.js +1 -0
  90. package/dashboard/out/_next/static/chunks/49e5c37d15f63def.js +1 -0
  91. package/dashboard/out/_next/static/chunks/4a46ad186a8587ee.css +2 -0
  92. package/dashboard/out/_next/static/chunks/4a5c728574935d50.js +1 -0
  93. package/dashboard/out/_next/static/chunks/4b27ebd4d9304d8f.js +1 -0
  94. package/dashboard/out/_next/static/chunks/4b965aa320a9b358.js +1 -0
  95. package/dashboard/out/_next/static/chunks/4bb2da90bbe5794f.js +1 -0
  96. package/dashboard/out/_next/static/chunks/4d2f1c6f631e4b85.js +1 -0
  97. package/dashboard/out/_next/static/chunks/4d696d5a64dab42e.js +1 -0
  98. package/dashboard/out/_next/static/chunks/4f660dadb3f1e9e2.js +1 -0
  99. package/dashboard/out/_next/static/chunks/507b50d47f949333.js +1 -0
  100. package/dashboard/out/_next/static/chunks/50b1b7063bb044e2.js +1 -0
  101. package/dashboard/out/_next/static/chunks/50c0c2e3c4f02508.js +1 -0
  102. package/dashboard/out/_next/static/chunks/50d7ba9803e65b02.js +1 -0
  103. package/dashboard/out/_next/static/chunks/51535a6d4c98c7a4.js +1 -0
  104. package/dashboard/out/_next/static/chunks/526de6cc16c7dd2f.js +1 -0
  105. package/dashboard/out/_next/static/chunks/5307604f8632b3fd.js +1 -0
  106. package/dashboard/out/_next/static/chunks/5480bd722260f231.js +1 -0
  107. package/dashboard/out/_next/static/chunks/54c61c82e5f1dca5.js +1 -0
  108. package/dashboard/out/_next/static/chunks/555de6ac6bb9034c.js +1 -0
  109. package/dashboard/out/_next/static/chunks/562b89ee76a4b90c.js +1 -0
  110. package/dashboard/out/_next/static/chunks/5747f9a32edff429.js +1 -0
  111. package/dashboard/out/_next/static/chunks/57ee141430b4c05c.js +1 -0
  112. package/dashboard/out/_next/static/chunks/584c066a0837dd9a.js +1 -0
  113. package/dashboard/out/_next/static/chunks/5856aed4670a6253.js +1 -0
  114. package/dashboard/out/_next/static/chunks/58fe563414726511.js +1 -0
  115. package/dashboard/out/_next/static/chunks/5948196b2729b18c.js +1 -0
  116. package/dashboard/out/_next/static/chunks/5ab77c69e7306f97.js +1 -0
  117. package/dashboard/out/_next/static/chunks/5b3fa4c99d61611c.js +1 -0
  118. package/dashboard/out/_next/static/chunks/5cc87abaef616661.js +1 -0
  119. package/dashboard/out/_next/static/chunks/5dfa7913f99bb966.js +1 -0
  120. package/dashboard/out/_next/static/chunks/5e49b008432770f1.js +1 -0
  121. package/dashboard/out/_next/static/chunks/5e5a33dd81c45c47.js +1 -0
  122. package/dashboard/out/_next/static/chunks/5ee61bed638eb8a8.js +1 -0
  123. package/dashboard/out/_next/static/chunks/5eed557b9f45ae4a.js +1 -0
  124. package/dashboard/out/_next/static/chunks/60446823a7d30c1b.js +1 -0
  125. package/dashboard/out/_next/static/chunks/605150c490861442.js +1 -0
  126. package/dashboard/out/_next/static/chunks/609056d51c0bf332.js +1 -0
  127. package/dashboard/out/_next/static/chunks/60ec91dfeb50071b.js +1 -0
  128. package/dashboard/out/_next/static/chunks/61bc7be0bba6a33f.js +1 -0
  129. package/dashboard/out/_next/static/chunks/61f4a5c9ce23e55e.js +1 -0
  130. package/dashboard/out/_next/static/chunks/63aae3585be04e65.js +1 -0
  131. package/dashboard/out/_next/static/chunks/64e0e1ee7ef4f01b.js +1 -0
  132. package/dashboard/out/_next/static/chunks/66e9b4c26ff1aaaf.js +1 -0
  133. package/dashboard/out/_next/static/chunks/67068847aa1b5e98.js +1 -0
  134. package/dashboard/out/_next/static/chunks/68d7de1f2e202c26.js +1 -0
  135. package/dashboard/out/_next/static/chunks/698ca3ea1937ba4f.js +1 -0
  136. package/dashboard/out/_next/static/chunks/69eb97c24b5b6b9d.js +1 -0
  137. package/dashboard/out/_next/static/chunks/6b1ac098c228a479.js +1 -0
  138. package/dashboard/out/_next/static/chunks/6bb8020cb796bcc1.js +1 -0
  139. package/dashboard/out/_next/static/chunks/6cb5c58418022991.js +193 -0
  140. package/dashboard/out/_next/static/chunks/6cf8b1db17f2a155.js +1 -0
  141. package/dashboard/out/_next/static/chunks/6e7613643906ea88.js +1 -0
  142. package/dashboard/out/_next/static/chunks/6ea27ceb2e6feae5.js +1 -0
  143. package/dashboard/out/_next/static/chunks/6f95a8dbcf23dded.js +1 -0
  144. package/dashboard/out/_next/static/chunks/6fd44e759d82f64e.js +1 -0
  145. package/dashboard/out/_next/static/chunks/716ec29c268c38f6.js +1 -0
  146. package/dashboard/out/_next/static/chunks/717b399dfcf7c02c.js +1 -0
  147. package/dashboard/out/_next/static/chunks/72badd90e1c91348.js +1 -0
  148. package/dashboard/out/_next/static/chunks/72f9296dbb7ae3c4.js +1 -0
  149. package/dashboard/out/_next/static/chunks/73aa31e1144d8191.js +1 -0
  150. package/dashboard/out/_next/static/chunks/73f98ded8fe2e879.js +1 -0
  151. package/dashboard/out/_next/static/chunks/740a2e8ace15e13b.js +1 -0
  152. package/dashboard/out/_next/static/chunks/74e57c16e7304b6b.js +1 -0
  153. package/dashboard/out/_next/static/chunks/7628dead4d113df2.js +1 -0
  154. package/dashboard/out/_next/static/chunks/7717c88c07ed96e6.js +1 -0
  155. package/dashboard/out/_next/static/chunks/775581f7956d9a27.js +1 -0
  156. package/dashboard/out/_next/static/chunks/77d3b6661befdb98.js +1 -0
  157. package/dashboard/out/_next/static/chunks/78435c0e1c77fea7.js +1 -0
  158. package/dashboard/out/_next/static/chunks/791336748b9c9393.js +1 -0
  159. package/dashboard/out/_next/static/chunks/79ea68dfae65ef2f.js +1 -0
  160. package/dashboard/out/_next/static/chunks/7bae777a472eb13c.js +1 -0
  161. package/dashboard/out/_next/static/chunks/7fd847f47237a35c.js +1 -0
  162. package/dashboard/out/_next/static/chunks/804d718be0370058.css +1 -0
  163. package/dashboard/out/_next/static/chunks/807cb3c1923995ab.js +1 -0
  164. package/dashboard/out/_next/static/chunks/8286b39407d94447.js +1 -0
  165. package/dashboard/out/_next/static/chunks/84e4305b8dc830ed.js +1 -0
  166. package/dashboard/out/_next/static/chunks/850f99dbfabb53e0.js +1 -0
  167. package/dashboard/out/_next/static/chunks/85594127e66b6b7f.js +1 -0
  168. package/dashboard/out/_next/static/chunks/858c11169c183c9c.js +1 -0
  169. package/dashboard/out/_next/static/chunks/85e27005dfe4c3e3.js +1 -0
  170. package/dashboard/out/_next/static/chunks/8707bd3d8ddc1f1c.js +1 -0
  171. package/dashboard/out/_next/static/chunks/8851e5d7ef894973.js +1 -0
  172. package/dashboard/out/_next/static/chunks/88ba3782cc614989.js +1 -0
  173. package/dashboard/out/_next/static/chunks/8a0c9a181784c2ef.js +1 -0
  174. package/dashboard/out/_next/static/chunks/8ad01ae355a6e7f6.js +1 -0
  175. package/dashboard/out/_next/static/chunks/8d2ed93b0d0a4b4f.js +1 -0
  176. package/dashboard/out/_next/static/chunks/8dc352ebd5310d3c.js +1 -0
  177. package/dashboard/out/_next/static/chunks/8dd1d722c8c1a22c.js +1 -0
  178. package/dashboard/out/_next/static/chunks/8e60fe307e3e4986.js +1 -0
  179. package/dashboard/out/_next/static/chunks/8eea4dd71e25f32a.js +1 -0
  180. package/dashboard/out/_next/static/chunks/8f468a65bac34eaa.js +1 -0
  181. package/dashboard/out/_next/static/chunks/9057e5382d6a5059.js +1 -0
  182. package/dashboard/out/_next/static/chunks/931d056437805ecb.js +1 -0
  183. package/dashboard/out/_next/static/chunks/954eb11648dd8cff.js +1 -0
  184. package/dashboard/out/_next/static/chunks/955034d876d14bb3.js +1 -0
  185. package/dashboard/out/_next/static/chunks/966c4895773249f6.js +1 -0
  186. package/dashboard/out/_next/static/chunks/96aff410a6ab106c.js +1 -0
  187. package/dashboard/out/_next/static/chunks/99b396c821c1dd2d.js +1 -0
  188. package/dashboard/out/_next/static/chunks/9a255fd2cf4922ae.js +1 -0
  189. package/dashboard/out/_next/static/chunks/9b1f6aa73bc864b2.js +1 -0
  190. package/dashboard/out/_next/static/chunks/9b9ce582c533aa79.js +1 -0
  191. package/dashboard/out/_next/static/chunks/9c19bd3c773c6611.js +1 -0
  192. package/dashboard/out/_next/static/chunks/9ceeaa847eb15ca2.js +1 -0
  193. package/dashboard/out/_next/static/chunks/9d2e6e7b8b65f845.js +1 -0
  194. package/dashboard/out/_next/static/chunks/9de23802066128ff.js +1 -0
  195. package/dashboard/out/_next/static/chunks/9e327f94b3701170.js +1 -0
  196. package/dashboard/out/_next/static/chunks/9e7818421c2d455a.js +1 -0
  197. package/dashboard/out/_next/static/chunks/9e935acbcf2fb519.js +1 -0
  198. package/dashboard/out/_next/static/chunks/9ed9f68340343b51.js +1 -0
  199. package/dashboard/out/_next/static/chunks/9f94a0242455fc20.js +1 -0
  200. package/dashboard/out/_next/static/chunks/9fff46b5aaecf47e.js +1 -0
  201. package/dashboard/out/_next/static/chunks/a06d267a5c557657.js +1 -0
  202. package/dashboard/out/_next/static/chunks/a0eb8c81c54722fe.js +1 -0
  203. package/dashboard/out/_next/static/chunks/a16808e83106427d.js +1 -0
  204. package/dashboard/out/_next/static/chunks/a2215e2bc72739ef.js +1 -0
  205. package/dashboard/out/_next/static/chunks/a2de9e6696eb9c17.js +1 -0
  206. package/dashboard/out/_next/static/chunks/a33420b8c14090d6.js +1 -0
  207. package/dashboard/out/_next/static/chunks/a360bffef39d818b.js +1 -0
  208. package/dashboard/out/_next/static/chunks/a42852fdf5287cf5.js +1 -0
  209. package/dashboard/out/_next/static/chunks/a4efc88488322b67.js +1 -0
  210. package/dashboard/out/_next/static/chunks/a696a91d14101bdb.js +1 -0
  211. package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  212. package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  213. package/dashboard/out/_next/static/chunks/a705c7261712bd8e.js +1 -0
  214. package/dashboard/out/_next/static/chunks/a7d1e4b067ace180.js +1 -0
  215. package/dashboard/out/_next/static/chunks/a8590c121a7efaa5.js +1 -0
  216. package/dashboard/out/_next/static/chunks/a95953a83a6df6cf.js +1 -0
  217. package/dashboard/out/_next/static/chunks/a9d0a757d3b4afed.js +1 -0
  218. package/dashboard/out/_next/static/chunks/a9dc35514619c872.js +1 -0
  219. package/dashboard/out/_next/static/chunks/ab1821552066a74d.js +1 -0
  220. package/dashboard/out/_next/static/chunks/ac96bc0eccebe15a.js +1 -0
  221. package/dashboard/out/_next/static/chunks/acc03cfaaf6bb30f.js +1 -0
  222. package/dashboard/out/_next/static/chunks/acc298ae059b9fe4.js +1 -0
  223. package/dashboard/out/_next/static/chunks/ad076b6e996d250c.js +1 -0
  224. package/dashboard/out/_next/static/chunks/ae53b64af7ba16d5.js +1 -0
  225. package/dashboard/out/_next/static/chunks/ae5da7fa4bc5fa95.js +1 -0
  226. package/dashboard/out/_next/static/chunks/aefcf0eb033a155e.js +1 -0
  227. package/dashboard/out/_next/static/chunks/b12d43100ee10526.js +1 -0
  228. package/dashboard/out/_next/static/chunks/b137952dd5566a41.js +1 -0
  229. package/dashboard/out/_next/static/chunks/b2832d8a2d332a47.js +1 -0
  230. package/dashboard/out/_next/static/chunks/b417aa09c15f63c6.js +1 -0
  231. package/dashboard/out/_next/static/chunks/b48e152ba7bf6caf.js +1 -0
  232. package/dashboard/out/_next/static/chunks/b4cbef8e4714bf92.js +1 -0
  233. package/dashboard/out/_next/static/chunks/b568ff8383a37f53.js +1 -0
  234. package/dashboard/out/_next/static/chunks/b6e1495dd89a39e3.js +1 -0
  235. package/dashboard/out/_next/static/chunks/b73a21bd67528440.js +1 -0
  236. package/dashboard/out/_next/static/chunks/b77ee62bc71dcec7.js +1 -0
  237. package/dashboard/out/_next/static/chunks/b7f454615c11d4eb.js +1 -0
  238. package/dashboard/out/_next/static/chunks/b818ea32a839590f.js +1 -0
  239. package/dashboard/out/_next/static/chunks/b901ce78c1c65d66.js +1 -0
  240. package/dashboard/out/_next/static/chunks/b93d647b803be9fa.js +1 -0
  241. package/dashboard/out/_next/static/chunks/b960b09ff1ecd6bb.js +1 -0
  242. package/dashboard/out/_next/static/chunks/ba717c7779a778fc.js +1 -0
  243. package/dashboard/out/_next/static/chunks/bacb0ae7458d18b6.js +1 -0
  244. package/dashboard/out/_next/static/chunks/bb51f68b27346852.js +1 -0
  245. package/dashboard/out/_next/static/chunks/bb67f22e1ab632ae.js +1 -0
  246. package/dashboard/out/_next/static/chunks/bbae97ec58d1bb9d.js +1 -0
  247. package/dashboard/out/_next/static/chunks/bbaf38ee90307765.js +1 -0
  248. package/dashboard/out/_next/static/chunks/be01598fe1fce5db.js +1 -0
  249. package/dashboard/out/_next/static/chunks/bf4cbbc095987fec.js +1 -0
  250. package/dashboard/out/_next/static/chunks/c18f823797d57446.js +1 -0
  251. package/dashboard/out/_next/static/chunks/c1bcece34ec5b295.js +1 -0
  252. package/dashboard/out/_next/static/chunks/c1ccbc3a51adaf0a.js +1 -0
  253. package/dashboard/out/_next/static/chunks/c1f54a628f27791c.js +1 -0
  254. package/dashboard/out/_next/static/chunks/c21916bf5d232151.js +1 -0
  255. package/dashboard/out/_next/static/chunks/c27e570f0fc2f78b.js +1 -0
  256. package/dashboard/out/_next/static/chunks/c322b8005eebc0d8.js +1 -0
  257. package/dashboard/out/_next/static/chunks/c3900ac2b009b764.js +1 -0
  258. package/dashboard/out/_next/static/chunks/c3c597c8eb77ad6b.js +1 -0
  259. package/dashboard/out/_next/static/chunks/c58d45c1d88e208c.js +1 -0
  260. package/dashboard/out/_next/static/chunks/c63875998d7a655f.js +1 -0
  261. package/dashboard/out/_next/static/chunks/c6eaa7c8e7209c8e.js +1 -0
  262. package/dashboard/out/_next/static/chunks/c6f820f71162a59a.js +1 -0
  263. package/dashboard/out/_next/static/chunks/c7ce0941d1dfe7ed.js +1 -0
  264. package/dashboard/out/_next/static/chunks/c877259f784ec8e5.js +1 -0
  265. package/dashboard/out/_next/static/chunks/cb8057e86aaa1c68.js +1 -0
  266. package/dashboard/out/_next/static/chunks/ccb4e306ee4859b1.js +1 -0
  267. package/dashboard/out/_next/static/chunks/ccde62b0fa8112eb.js +1 -0
  268. package/dashboard/out/_next/static/chunks/cd421f0971c63c31.js +1 -0
  269. package/dashboard/out/_next/static/chunks/cde0317494d4adb7.js +1 -0
  270. package/dashboard/out/_next/static/chunks/cfae64434b92b8b6.js +1 -0
  271. package/dashboard/out/_next/static/chunks/cfc0e19310ec0a36.js +1 -0
  272. package/dashboard/out/_next/static/chunks/d0f344c7d0bcb59a.js +1 -0
  273. package/dashboard/out/_next/static/chunks/d1871c73e74e1f50.js +1 -0
  274. package/dashboard/out/_next/static/chunks/d18f658850711061.js +1 -0
  275. package/dashboard/out/_next/static/chunks/d25d9c48880697f6.js +1 -0
  276. package/dashboard/out/_next/static/chunks/d3f0a72bbc3060b0.js +1 -0
  277. package/dashboard/out/_next/static/chunks/d5fca429bc89060b.js +1 -0
  278. package/dashboard/out/_next/static/chunks/d6a6c75c9a4bef49.js +1 -0
  279. package/dashboard/out/_next/static/chunks/d6a8f93aa8f1e345.js +1 -0
  280. package/dashboard/out/_next/static/chunks/d7deab676b19ba0e.js +1 -0
  281. package/dashboard/out/_next/static/chunks/d80030dde88cec85.js +1 -0
  282. package/dashboard/out/_next/static/chunks/da84f9774c076ff1.js +1 -0
  283. package/dashboard/out/_next/static/chunks/da98ecc6b9b0ceb2.js +1 -0
  284. package/dashboard/out/_next/static/chunks/db550aabce60b912.js +4 -0
  285. package/dashboard/out/_next/static/chunks/dc87f77fcc029482.js +1 -0
  286. package/dashboard/out/_next/static/chunks/dd05f30acdb63a53.js +1 -0
  287. package/dashboard/out/_next/static/chunks/dea150155499b903.js +1 -0
  288. package/dashboard/out/_next/static/chunks/df4358754ff1d5e8.js +1 -0
  289. package/dashboard/out/_next/static/chunks/df8b21ff12d23b0e.js +1 -0
  290. package/dashboard/out/_next/static/chunks/df8fc68d77debf2c.js +1 -0
  291. package/dashboard/out/_next/static/chunks/df9ed1ffec90589f.js +1 -0
  292. package/dashboard/out/_next/static/chunks/dfa65ece1598f934.js +1 -0
  293. package/dashboard/out/_next/static/chunks/dfaab5cdd41a20d9.js +1 -0
  294. package/dashboard/out/_next/static/chunks/e00c03c942b5ae3e.js +1 -0
  295. package/dashboard/out/_next/static/chunks/e02d27cf679bece1.js +1 -0
  296. package/dashboard/out/_next/static/chunks/e0b747585f78513a.js +1 -0
  297. package/dashboard/out/_next/static/chunks/e19b71ca23fd7df0.js +1 -0
  298. package/dashboard/out/_next/static/chunks/e21cbe89d0cda120.js +1 -0
  299. package/dashboard/out/_next/static/chunks/e2a0386930edd34f.js +1 -0
  300. package/dashboard/out/_next/static/chunks/e375de19a36e2f38.js +1 -0
  301. package/dashboard/out/_next/static/chunks/e5241b4a6496a9e0.js +1 -0
  302. package/dashboard/out/_next/static/chunks/e569dd07c96eb4dd.js +1 -0
  303. package/dashboard/out/_next/static/chunks/e61c3ea91233f948.js +1 -0
  304. package/dashboard/out/_next/static/chunks/e73b42c5d34c4c28.js +1 -0
  305. package/dashboard/out/_next/static/chunks/e7c5b2105f651e87.js +1 -0
  306. package/dashboard/out/_next/static/chunks/e878e58a69bb01b6.js +1 -0
  307. package/dashboard/out/_next/static/chunks/e8f090a4dc571062.js +1 -0
  308. package/dashboard/out/_next/static/chunks/e98dc34dac91cdad.js +1 -0
  309. package/dashboard/out/_next/static/chunks/ea67cf7a0c5e7233.js +1 -0
  310. package/dashboard/out/_next/static/chunks/eacc98a1e3512fa9.js +1 -0
  311. package/dashboard/out/_next/static/chunks/eae9cd74d9bbed8b.js +1 -0
  312. package/dashboard/out/_next/static/chunks/eb187fd345852b34.js +1 -0
  313. package/dashboard/out/_next/static/chunks/ecea46df7a40b427.js +1 -0
  314. package/dashboard/out/_next/static/chunks/ecf48b83f4245d9c.js +1 -0
  315. package/dashboard/out/_next/static/chunks/eda41732bf966c6d.js +1 -0
  316. package/dashboard/out/_next/static/chunks/ee174a433049f43a.js +1 -0
  317. package/dashboard/out/_next/static/chunks/ee66b2d3b76de72e.js +1 -0
  318. package/dashboard/out/_next/static/chunks/ef058d3041c3d8ab.js +1 -0
  319. package/dashboard/out/_next/static/chunks/f3544b800b0d4969.js +1 -0
  320. package/dashboard/out/_next/static/chunks/f3b280e604b97509.js +1 -0
  321. package/dashboard/out/_next/static/chunks/f42e1d3693232993.js +1 -0
  322. package/dashboard/out/_next/static/chunks/f5a5fdd80166d304.js +1 -0
  323. package/dashboard/out/_next/static/chunks/f60adc5dd6169316.js +1 -0
  324. package/dashboard/out/_next/static/chunks/f6255bc2e6c68ce8.js +1 -0
  325. package/dashboard/out/_next/static/chunks/f6bb677d2d8840db.js +1 -0
  326. package/dashboard/out/_next/static/chunks/f6f3bf016239c33a.js +1 -0
  327. package/dashboard/out/_next/static/chunks/f6f57a46cd074bfe.js +1 -0
  328. package/dashboard/out/_next/static/chunks/f7feb9c1199e8cf6.js +1 -0
  329. package/dashboard/out/_next/static/chunks/f831087bf964cc3d.js +1 -0
  330. package/dashboard/out/_next/static/chunks/fa5a2f7244935aa2.js +1 -0
  331. package/dashboard/out/_next/static/chunks/fa73f36df4c38fa0.js +1 -0
  332. package/dashboard/out/_next/static/chunks/faa1461722d6a88d.js +1 -0
  333. package/dashboard/out/_next/static/chunks/fbf706b9a0edb7e6.js +1 -0
  334. package/dashboard/out/_next/static/chunks/fc2b8c8b7446bbc2.js +1 -0
  335. package/dashboard/out/_next/static/chunks/fd516f3930c128c1.js +1 -0
  336. package/dashboard/out/_next/static/chunks/fd663e7ff8de4887.js +1 -0
  337. package/dashboard/out/_next/static/chunks/fe5b656cc9bdd60e.js +1 -0
  338. package/dashboard/out/_next/static/chunks/turbopack-2f5dec4a537c0ee7.js +4 -0
  339. package/dashboard/out/_next/static/media/02263ebadd758ea4-s.8da66e7f.woff2 +0 -0
  340. package/dashboard/out/_next/static/media/2fe89d53234c61d4-s.cb53f04b.woff2 +0 -0
  341. package/dashboard/out/_next/static/media/59b15b4bcd7b1eb5-s.afa48be3.woff2 +0 -0
  342. package/dashboard/out/_next/static/media/5e05ae5b48faa55e-s.6b5ea6af.woff2 +0 -0
  343. package/dashboard/out/_next/static/media/68757d6cddeff913-s.e6cd1753.woff2 +0 -0
  344. package/dashboard/out/_next/static/media/99e609270109b47d-s.p.64b9304e.woff2 +0 -0
  345. package/dashboard/out/_next/static/media/a7afbb44bec2bb18-s.1dcddae6.woff2 +0 -0
  346. package/dashboard/out/_next/static/media/e390973e931a41c5-s.a82ecf4e.woff2 +0 -0
  347. package/dashboard/out/_next/static/media/e532fa1b9921e1cd-s.764b43eb.woff2 +0 -0
  348. package/dashboard/out/_next/static/media/effe91970fc4db64-s.p.19510058.woff2 +0 -0
  349. package/dashboard/out/_not-found/__next._full.txt +15 -0
  350. package/dashboard/out/_not-found/__next._head.txt +5 -0
  351. package/dashboard/out/_not-found/__next._index.txt +7 -0
  352. package/dashboard/out/_not-found/__next._not-found.__PAGE__.txt +5 -0
  353. package/dashboard/out/_not-found/__next._not-found.txt +4 -0
  354. package/dashboard/out/_not-found/__next._tree.txt +2 -0
  355. package/dashboard/out/_not-found/index.html +1 -0
  356. package/dashboard/out/_not-found/index.txt +15 -0
  357. package/dashboard/out/index.html +1 -0
  358. package/dashboard/out/index.txt +21 -0
  359. package/dashboard/out/project/__fallback/__next._full.txt +19 -0
  360. package/dashboard/out/project/__fallback/__next._head.txt +5 -0
  361. package/dashboard/out/project/__fallback/__next._index.txt +7 -0
  362. package/dashboard/out/project/__fallback/__next._tree.txt +5 -0
  363. package/dashboard/out/project/__fallback/__next.project.$d$name.__PAGE__.txt +7 -0
  364. package/dashboard/out/project/__fallback/__next.project.$d$name.txt +4 -0
  365. package/dashboard/out/project/__fallback/__next.project.txt +4 -0
  366. package/dashboard/out/project/__fallback/index.html +1 -0
  367. package/dashboard/out/project/__fallback/index.txt +19 -0
  368. package/package.json +31 -15
  369. package/src/__tests__/support.ts +186 -0
  370. package/src/attach.ts +20 -0
  371. package/src/cli.test.ts +314 -0
  372. package/src/command-center/discovery.test.ts +265 -0
  373. package/src/command-center/discovery.ts +296 -0
  374. package/src/command-center/index.ts +31 -0
  375. package/src/command-center/schemas.ts +57 -0
  376. package/src/command-center/server.test.ts +814 -0
  377. package/src/command-center/server.ts +1421 -0
  378. package/src/command-center/static.test.ts +105 -0
  379. package/src/command-center/static.ts +122 -0
  380. package/src/config-cli.test.ts +86 -0
  381. package/src/config.test.ts +205 -0
  382. package/src/config.ts +313 -0
  383. package/src/detect.test.ts +142 -0
  384. package/src/detect.ts +248 -0
  385. package/src/dispatch.ts +102 -0
  386. package/src/doctor.test.ts +119 -0
  387. package/src/doctor.ts +167 -0
  388. package/src/init.test.ts +101 -0
  389. package/src/init.ts +144 -0
  390. package/src/inspect.test.ts +67 -0
  391. package/src/inspect.ts +212 -0
  392. package/src/integration.test.ts.skip +276 -0
  393. package/src/js-yaml.d.ts +10 -0
  394. package/src/launch.test.ts +149 -0
  395. package/src/launch.ts +475 -0
  396. package/src/lib/auth/auth-service.test.ts +178 -0
  397. package/src/lib/auth/auth-service.ts +227 -0
  398. package/src/lib/auth/middleware.test.ts +119 -0
  399. package/src/lib/auth/middleware.ts +56 -0
  400. package/src/lib/auth/types.ts +13 -0
  401. package/src/lib/authorship.test.ts +242 -0
  402. package/src/lib/authorship.ts +280 -0
  403. package/src/lib/cast/recorder.test.ts +127 -0
  404. package/src/lib/cast/recorder.ts +148 -0
  405. package/src/lib/daemon-watchdog.ts +102 -0
  406. package/src/lib/daemon.ts +439 -0
  407. package/src/lib/dot-path.test.ts +66 -0
  408. package/src/lib/dot-path.ts +17 -0
  409. package/src/lib/errors.ts +44 -0
  410. package/src/lib/event-log.test.ts +189 -0
  411. package/src/lib/event-log.ts +237 -0
  412. package/src/lib/github-pr.ts +182 -0
  413. package/src/lib/hq/client.test.ts +154 -0
  414. package/src/lib/hq/client.ts +142 -0
  415. package/src/lib/hq/mdns.test.ts +54 -0
  416. package/src/lib/hq/mdns.ts +88 -0
  417. package/src/lib/hq/registry.test.ts +237 -0
  418. package/src/lib/hq/registry.ts +145 -0
  419. package/src/lib/hq/types.ts +44 -0
  420. package/src/lib/ipc/socket-protocol.test.ts +126 -0
  421. package/src/lib/ipc/socket-protocol.ts +324 -0
  422. package/src/lib/launch-plan.test.ts +119 -0
  423. package/src/lib/launch-plan.ts +90 -0
  424. package/src/lib/log.test.ts +39 -0
  425. package/src/lib/log.ts +71 -0
  426. package/src/lib/metrics.test.ts +213 -0
  427. package/src/lib/metrics.ts +345 -0
  428. package/src/lib/orchestrator.test.ts +2358 -0
  429. package/src/lib/orchestrator.ts +1790 -0
  430. package/src/lib/output.ts +76 -0
  431. package/src/lib/plan-store.test.ts +148 -0
  432. package/src/lib/plan-store.ts +131 -0
  433. package/src/lib/research.test.ts +208 -0
  434. package/src/lib/research.ts +475 -0
  435. package/src/lib/round-trip.test.ts +341 -0
  436. package/src/lib/session-monitor.test.ts +152 -0
  437. package/src/lib/session-monitor.ts +282 -0
  438. package/src/lib/session-options.test.ts +146 -0
  439. package/src/lib/session-options.ts +100 -0
  440. package/src/lib/shell.test.ts +20 -0
  441. package/src/lib/shell.ts +8 -0
  442. package/src/lib/sizes.test.ts +73 -0
  443. package/src/lib/sizes.ts +36 -0
  444. package/src/lib/skill-registry.test.ts +134 -0
  445. package/src/lib/skill-registry.ts +86 -0
  446. package/src/lib/slugify.test.ts +35 -0
  447. package/src/lib/slugify.ts +10 -0
  448. package/src/lib/task-store.ts +352 -0
  449. package/src/lib/tmux.test.ts +500 -0
  450. package/src/lib/tmux.ts +372 -0
  451. package/src/lib/token-tracker.test.ts +102 -0
  452. package/src/lib/token-tracker.ts +70 -0
  453. package/src/lib/tunnels/cloudflare.test.ts +73 -0
  454. package/src/lib/tunnels/cloudflare.ts +254 -0
  455. package/src/lib/tunnels/manager.test.ts +63 -0
  456. package/src/lib/tunnels/manager.ts +132 -0
  457. package/src/lib/tunnels/ngrok.test.ts +94 -0
  458. package/src/lib/tunnels/ngrok.ts +261 -0
  459. package/src/lib/tunnels/tailscale.test.ts +103 -0
  460. package/src/lib/tunnels/tailscale.ts +1048 -0
  461. package/src/lib/tunnels/types.ts +44 -0
  462. package/src/lib/validation.test.ts +289 -0
  463. package/src/lib/validation.ts +123 -0
  464. package/src/lib/webhook.ts +51 -0
  465. package/src/lib/workflow-store.ts +209 -0
  466. package/src/lib/ws-v3/protocol.test.ts +127 -0
  467. package/src/lib/ws-v3/protocol.ts +160 -0
  468. package/src/lib/yaml-io.test.ts +125 -0
  469. package/src/lib/yaml-io.ts +27 -0
  470. package/src/ls.test.ts +76 -0
  471. package/src/ls.ts +40 -0
  472. package/src/metrics-cli.ts +177 -0
  473. package/src/notify.ts +85 -0
  474. package/src/orchestrator-status.ts +228 -0
  475. package/src/plan.ts +117 -0
  476. package/src/postinstall.test.ts +79 -0
  477. package/src/remote.test.ts +115 -0
  478. package/src/remote.ts +148 -0
  479. package/src/restart.ts +24 -0
  480. package/src/schemas/domain.ts +422 -0
  481. package/src/schemas/ide-config.ts +148 -0
  482. package/src/schemas/index.ts +53 -0
  483. package/src/send.test.ts +70 -0
  484. package/src/send.ts +181 -0
  485. package/src/skill.test.ts +114 -0
  486. package/src/skill.ts +138 -0
  487. package/src/status.ts +66 -0
  488. package/src/stop.test.ts +151 -0
  489. package/src/stop.ts +28 -0
  490. package/src/task.test.ts +1466 -0
  491. package/src/task.ts +1143 -0
  492. package/src/tunnel.test.ts +80 -0
  493. package/src/tunnel.ts +133 -0
  494. package/src/types.ts +15 -0
  495. package/src/ui/index.ts +32 -0
  496. package/src/ui/terminal/index.ts +9 -0
  497. package/src/ui/types.ts +91 -0
  498. package/src/ui/web/base.css +80 -0
  499. package/src/ui/web/components/Box.tsx +59 -0
  500. package/src/ui/web/components/Input.tsx +32 -0
  501. package/src/ui/web/components/ScrollBox.tsx +60 -0
  502. package/src/ui/web/components/Text.tsx +28 -0
  503. package/src/ui/web/hooks.ts +106 -0
  504. package/src/ui/web/index.ts +27 -0
  505. package/src/ui/web/render.ts +77 -0
  506. package/src/ui/web/utils/color.test.ts +93 -0
  507. package/src/ui/web/utils/color.ts +27 -0
  508. package/src/validate.test.ts +385 -0
  509. package/src/validate.ts +217 -0
  510. package/src/widgets/changes/index.tsx +576 -0
  511. package/src/widgets/config/index.tsx +440 -0
  512. package/src/widgets/costs/index.tsx +216 -0
  513. package/src/widgets/explorer/breadcrumbs.tsx +77 -0
  514. package/src/widgets/explorer/footer.tsx +20 -0
  515. package/src/widgets/explorer/header.tsx +23 -0
  516. package/src/widgets/explorer/index.tsx +408 -0
  517. package/src/widgets/explorer/tree-model.test.ts +214 -0
  518. package/src/widgets/explorer/tree-model.ts +103 -0
  519. package/src/widgets/explorer/tree.tsx +156 -0
  520. package/src/widgets/lib/config-model.ts +116 -0
  521. package/src/widgets/lib/files.test.ts +103 -0
  522. package/src/widgets/lib/files.ts +88 -0
  523. package/src/widgets/lib/git.test.ts +151 -0
  524. package/src/widgets/lib/git.ts +88 -0
  525. package/src/widgets/lib/pane-comms.test.ts +178 -0
  526. package/src/widgets/lib/pane-comms.ts +207 -0
  527. package/src/widgets/lib/theme.ts +151 -0
  528. package/src/widgets/lib/watcher.ts +50 -0
  529. package/src/widgets/mission-control/activity-feed.tsx +59 -0
  530. package/src/widgets/mission-control/agent-panel.tsx +132 -0
  531. package/src/widgets/mission-control/command-bar.tsx +63 -0
  532. package/src/widgets/mission-control/index.tsx +751 -0
  533. package/src/widgets/mission-control/task-panel.tsx +238 -0
  534. package/src/widgets/preview/index.tsx +415 -0
  535. package/src/widgets/resolve.ts +40 -0
  536. package/src/widgets/setup/agent-naming.tsx +112 -0
  537. package/src/widgets/setup/config-tree.tsx +238 -0
  538. package/src/widgets/setup/detect-panel.tsx +72 -0
  539. package/src/widgets/setup/field-editor.tsx +265 -0
  540. package/src/widgets/setup/footer.tsx +107 -0
  541. package/src/widgets/setup/index.tsx +340 -0
  542. package/src/widgets/setup/layout-picker.tsx +96 -0
  543. package/src/widgets/setup/orchestrator-panel.tsx +200 -0
  544. package/src/widgets/setup/review-panel.tsx +140 -0
  545. package/src/widgets/setup/setup-model.test.ts +303 -0
  546. package/src/widgets/setup/setup-model.ts +188 -0
  547. package/src/widgets/tasks/index.tsx +129 -0
  548. package/src/widgets/tasks/task-detail.tsx +309 -0
  549. package/src/widgets/tasks/task-form.tsx +193 -0
  550. package/src/widgets/tasks/task-list.tsx +205 -0
  551. package/src/widgets/tasks/task-model.test.ts +473 -0
  552. package/src/widgets/tasks/task-model.ts +157 -0
  553. package/templates/AGENTS.md +20 -0
  554. package/templates/missions.yml +41 -0
  555. package/templates/skills/backend.md +30 -0
  556. package/templates/skills/frontend.md +30 -0
  557. package/templates/skills/general-worker.md +30 -0
  558. package/templates/skills/researcher.md +69 -0
  559. package/templates/skills/reviewer.md +30 -0
  560. package/dist/attach.d.ts +0 -3
  561. package/dist/attach.js +0 -14
  562. package/dist/config.d.ts +0 -5
  563. package/dist/config.js +0 -269
  564. package/dist/detect.d.ts +0 -15
  565. package/dist/detect.js +0 -228
  566. package/dist/doctor.d.ts +0 -3
  567. package/dist/doctor.js +0 -66
  568. package/dist/init.d.ts +0 -4
  569. package/dist/init.js +0 -67
  570. package/dist/inspect.d.ts +0 -54
  571. package/dist/inspect.js +0 -118
  572. package/dist/launch.d.ts +0 -22
  573. package/dist/launch.js +0 -174
  574. package/dist/lib/dot-path.d.ts +0 -2
  575. package/dist/lib/dot-path.js +0 -17
  576. package/dist/lib/errors.d.ts +0 -29
  577. package/dist/lib/errors.js +0 -37
  578. package/dist/lib/launch-plan.d.ts +0 -6
  579. package/dist/lib/launch-plan.js +0 -40
  580. package/dist/lib/output.d.ts +0 -9
  581. package/dist/lib/output.js +0 -65
  582. package/dist/lib/session-monitor.d.ts +0 -12
  583. package/dist/lib/session-monitor.js +0 -160
  584. package/dist/lib/session-options.d.ts +0 -13
  585. package/dist/lib/session-options.js +0 -85
  586. package/dist/lib/sizes.d.ts +0 -16
  587. package/dist/lib/sizes.js +0 -36
  588. package/dist/lib/tmux.d.ts +0 -42
  589. package/dist/lib/tmux.js +0 -225
  590. package/dist/lib/yaml-io.d.ts +0 -10
  591. package/dist/lib/yaml-io.js +0 -24
  592. package/dist/ls.d.ts +0 -3
  593. package/dist/ls.js +0 -35
  594. package/dist/restart.d.ts +0 -4
  595. package/dist/restart.js +0 -13
  596. package/dist/status.d.ts +0 -3
  597. package/dist/status.js +0 -29
  598. package/dist/stop.d.ts +0 -3
  599. package/dist/stop.js +0 -21
  600. package/dist/types.d.ts +0 -41
  601. package/dist/types.js +0 -1
  602. package/dist/validate.d.ts +0 -4
  603. package/dist/validate.js +0 -172
package/src/launch.ts ADDED
@@ -0,0 +1,475 @@
1
+ import { resolve, dirname, join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { execSync } from "node:child_process";
4
+ import { createHash } from "node:crypto";
5
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
6
+ import { readConfig, getSessionName } from "./lib/yaml-io.ts";
7
+ import { computeSizes, toSplitPercents } from "./lib/sizes.ts";
8
+ import { outputError } from "./lib/output.ts";
9
+ import { collectPaneStartupPlan } from "./lib/launch-plan.ts";
10
+ import { buildSessionOptions } from "./lib/session-options.ts";
11
+ import {
12
+ attachSession,
13
+ createDetachedSession,
14
+ getPaneCurrentCommand,
15
+ getSessionVariable,
16
+ hasSession,
17
+ runSessionCommand,
18
+ selectPane,
19
+ sendLiteral,
20
+ setPaneOption,
21
+ setPaneTitle,
22
+ setSessionEnvironment,
23
+ setSessionVariable,
24
+ splitPane,
25
+ startSessionMonitor,
26
+ } from "./lib/tmux.ts";
27
+ import { validateConfig } from "./validate.ts";
28
+ import { resolveWidgetCommand } from "./widgets/resolve.ts";
29
+ import { shellEscape } from "./lib/shell.ts";
30
+ import type { IdeConfig, Row, Pane } from "./types.ts";
31
+
32
+ const DEFAULT_COMMAND_CENTER_PORT = 6060;
33
+
34
+ function stripWidgetPanes(rows: Row[]): Row[] {
35
+ return rows
36
+ .map((row) => ({
37
+ ...row,
38
+ panes: row.panes.filter((p) => !p.type),
39
+ }))
40
+ .filter((row) => row.panes.length > 0);
41
+ }
42
+
43
+ interface SplitPaneArgs {
44
+ targetPane: string;
45
+ direction: "vertical" | "horizontal";
46
+ cwd: string;
47
+ percent: number;
48
+ }
49
+
50
+ function sleepMs(ms: number): void {
51
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
52
+ }
53
+
54
+ function configHash(config: IdeConfig): string {
55
+ return createHash("sha256").update(JSON.stringify(config)).digest("hex").slice(0, 12);
56
+ }
57
+
58
+ export function waitForPaneCommand(
59
+ targetPane: string,
60
+ expectedCommands: string[],
61
+ {
62
+ attempts = 20,
63
+ delayMs = 100,
64
+ getCurrentCommand = getPaneCurrentCommand,
65
+ sleep = sleepMs,
66
+ }: {
67
+ attempts?: number;
68
+ delayMs?: number;
69
+ getCurrentCommand?: (pane: string) => string;
70
+ sleep?: (ms: number) => void;
71
+ } = {},
72
+ ): boolean {
73
+ const allowed = new Set(expectedCommands.map((command) => command.toLowerCase()));
74
+
75
+ for (let attempt = 0; attempt < attempts; attempt++) {
76
+ try {
77
+ const current = getCurrentCommand(targetPane)?.trim().toLowerCase();
78
+ if (current && allowed.has(current)) return true;
79
+ } catch {
80
+ // Fall through to retry; tmux can briefly report transitional state.
81
+ }
82
+
83
+ if (attempt < attempts - 1) {
84
+ sleep(delayMs);
85
+ }
86
+ }
87
+
88
+ return false;
89
+ }
90
+
91
+ export function buildPaneMap(
92
+ rows: Row[],
93
+ dir: string,
94
+ rootPaneId: string,
95
+ splitPaneFn: (args: SplitPaneArgs) => string,
96
+ ): { paneMap: string[][]; firstPanesOfRows: Set<string> } {
97
+ const rowSizes = computeSizes(rows);
98
+ const rowSplitPercents = toSplitPercents(rowSizes);
99
+
100
+ // Create all rows vertically first so each row spans the full width.
101
+ const rowPaneIds = [rootPaneId];
102
+ for (let rowIdx = 1; rowIdx < rows.length; rowIdx++) {
103
+ const splitFrom = rowPaneIds[rowIdx - 1]!;
104
+ const newPaneId = splitPaneFn({
105
+ targetPane: splitFrom,
106
+ direction: "vertical",
107
+ cwd: dir,
108
+ percent: rowSplitPercents[rowIdx - 1]!,
109
+ });
110
+ rowPaneIds.push(newPaneId);
111
+ }
112
+
113
+ const paneMap: string[][] = [];
114
+ const firstPanesOfRows = new Set(rowPaneIds);
115
+
116
+ for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
117
+ const row = rows[rowIdx]!;
118
+ const panes = row.panes ?? [];
119
+ const rowPaneId = rowPaneIds[rowIdx]!;
120
+ const rowPanes = [rowPaneId];
121
+
122
+ const paneSizes = computeSizes(panes);
123
+ const paneSplitPercents = toSplitPercents(paneSizes);
124
+
125
+ for (let paneIdx = 1; paneIdx < panes.length; paneIdx++) {
126
+ const pane = panes[paneIdx]!;
127
+ const targetPane = rowPanes[paneIdx - 1]!;
128
+ const paneDir = pane.dir ? resolve(dir, pane.dir) : dir;
129
+ const newPaneId = splitPaneFn({
130
+ targetPane,
131
+ direction: "horizontal",
132
+ cwd: paneDir,
133
+ percent: paneSplitPercents[paneIdx - 1]!,
134
+ });
135
+ rowPanes.push(newPaneId);
136
+ }
137
+
138
+ paneMap.push(rowPanes);
139
+ }
140
+
141
+ return { paneMap, firstPanesOfRows };
142
+ }
143
+
144
+ function loadLaunchConfig(dir: string): IdeConfig {
145
+ let config;
146
+
147
+ try {
148
+ ({ config } = readConfig(dir));
149
+ } catch (error) {
150
+ if ((error as NodeJS.ErrnoException)?.code === "ENOENT") {
151
+ outputError(
152
+ `No ide.yml found in ${dir}. Run "tmux-ide init" or "tmux-ide detect --write" to create one.`,
153
+ "CONFIG_NOT_FOUND",
154
+ );
155
+ }
156
+
157
+ outputError(`Cannot read ide.yml: ${(error as Error).message}`, "READ_ERROR");
158
+ }
159
+
160
+ const errors = validateConfig(config);
161
+ if (errors.length > 0) {
162
+ outputError(
163
+ `Invalid ide.yml in ${dir}. Run "tmux-ide validate" for details.`,
164
+ "INVALID_CONFIG",
165
+ );
166
+ }
167
+
168
+ return config;
169
+ }
170
+
171
+ function runBeforeHook(command: string | undefined, dir: string): void {
172
+ if (!command) return;
173
+
174
+ console.log(`Running: ${command}`);
175
+
176
+ try {
177
+ execSync(command, { cwd: dir, stdio: "inherit", timeout: 60_000 });
178
+ } catch {
179
+ outputError(`The before hook failed: ${command}`, "BEFORE_HOOK_FAILED");
180
+ }
181
+ }
182
+
183
+ async function waitForDaemon(port: number, maxAttempts = 30, delayMs = 100): Promise<boolean> {
184
+ for (let i = 0; i < maxAttempts; i++) {
185
+ try {
186
+ const res = await fetch(`http://localhost:${port}/health`);
187
+ if (res.ok) return true;
188
+ } catch {
189
+ // Not ready yet
190
+ }
191
+ await new Promise((r) => setTimeout(r, delayMs));
192
+ }
193
+ return false;
194
+ }
195
+
196
+ async function isDaemonAlive(port: number): Promise<boolean> {
197
+ try {
198
+ const res = await fetch(`http://localhost:${port}/health`, {
199
+ signal: AbortSignal.timeout(1000),
200
+ });
201
+ return res.ok;
202
+ } catch {
203
+ return false;
204
+ }
205
+ }
206
+
207
+ export async function launch(
208
+ targetDir: string | undefined,
209
+ { json = false, attach = true }: { json?: boolean; attach?: boolean } = {},
210
+ ): Promise<void> {
211
+ const dir = resolve(targetDir ?? ".");
212
+ const config = loadLaunchConfig(dir);
213
+
214
+ const { name: fallbackName } = getSessionName(dir);
215
+ const session = config.name ?? fallbackName;
216
+ const headless = config.orchestrator?.widgets === false;
217
+ const rows = headless ? stripWidgetPanes(config.rows) : config.rows;
218
+ const theme = config.theme ?? {};
219
+ const team = config.team ?? null;
220
+
221
+ runBeforeHook(config.before, dir);
222
+
223
+ // If session already exists, check for config drift and attach
224
+ if (hasSession(session)) {
225
+ const currentHash = configHash(config);
226
+ const storedHash = getSessionVariable(session, "@config_hash");
227
+ const configChanged = Boolean(storedHash && currentHash !== storedHash);
228
+ const commandCenterPort =
229
+ config.orchestrator?.port ?? config.command_center?.port ?? DEFAULT_COMMAND_CENTER_PORT;
230
+ const commandCenterUrl = `http://localhost:${commandCenterPort}`;
231
+
232
+ // Verify daemon is alive, restart if dead
233
+ const daemonAlive = await isDaemonAlive(commandCenterPort);
234
+ if (!daemonAlive) {
235
+ console.log("Daemon not responding — restarting...");
236
+ const monitorScript = resolve(
237
+ dirname(fileURLToPath(import.meta.url)),
238
+ "lib",
239
+ "daemon-watchdog.ts",
240
+ );
241
+ startSessionMonitor(session, monitorScript, commandCenterPort);
242
+ await waitForDaemon(commandCenterPort);
243
+ }
244
+
245
+ if (json) {
246
+ console.log(JSON.stringify({ session, running: true, configChanged, commandCenterUrl }));
247
+ } else if (configChanged) {
248
+ console.log(`Session "${session}" is running but ide.yml has changed.`);
249
+ console.log(`Run "tmux-ide restart" to apply changes.`);
250
+ } else {
251
+ console.log(`Session "${session}" is already running. Attaching...`);
252
+ console.log(`Dashboard: ${commandCenterUrl}`);
253
+ }
254
+
255
+ if (attach) {
256
+ attachSession(session);
257
+ }
258
+ return;
259
+ }
260
+
261
+ // Get terminal dimensions
262
+ const cols = process.stdout.columns ?? 200;
263
+ const lines = process.stdout.rows ?? 50;
264
+
265
+ // Create session with first pane
266
+ const rootPaneId = createDetachedSession(session, dir, { cols, lines });
267
+
268
+ // Set agent teams env var if team config is present
269
+ if (team) {
270
+ setSessionEnvironment(session, "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS", "1");
271
+ }
272
+
273
+ const { paneMap, firstPanesOfRows } = buildPaneMap(
274
+ rows,
275
+ dir,
276
+ rootPaneId,
277
+ ({ targetPane, direction, cwd, percent }) => splitPane(targetPane, direction, cwd, percent),
278
+ );
279
+
280
+ const { focusPane, paneActions } = collectPaneStartupPlan(rows, paneMap, firstPanesOfRows, dir);
281
+
282
+ for (const action of paneActions) {
283
+ if (action.title) {
284
+ setPaneTitle(action.targetPane, action.title);
285
+ }
286
+
287
+ // Set pane identity options for discovery by orchestrator/widgets
288
+ setPaneOption(action.targetPane, "@ide_role", action.paneRole ?? "shell");
289
+ setPaneOption(action.targetPane, "@ide_name", action.title ?? "");
290
+ setPaneOption(action.targetPane, "@ide_type", action.paneType ?? "shell");
291
+
292
+ // Lock agent pane titles so Claude Code can't overwrite them
293
+ if (action.paneRole === "lead" || action.paneRole === "teammate") {
294
+ setPaneOption(action.targetPane, "allow-rename", "off");
295
+ }
296
+
297
+ if (action.chdir) {
298
+ sendLiteral(action.targetPane, `cd ${shellEscape(action.chdir)}`);
299
+ }
300
+
301
+ for (const exportCommand of action.exports) {
302
+ sendLiteral(action.targetPane, exportCommand);
303
+ }
304
+
305
+ if (action.widgetType) {
306
+ const widgetCmd = resolveWidgetCommand(action.widgetType, {
307
+ session,
308
+ dir,
309
+ target: action.widgetTarget ?? null,
310
+ theme: config.theme ?? null,
311
+ });
312
+ sendLiteral(action.targetPane, widgetCmd);
313
+ } else if (action.command) {
314
+ sendLiteral(action.targetPane, action.command);
315
+ }
316
+ }
317
+
318
+ for (const command of buildSessionOptions(session, { theme })) {
319
+ runSessionCommand(command);
320
+ }
321
+
322
+ // Store config hash for drift detection on re-launch
323
+ setSessionVariable(session, "@config_hash", configHash(config));
324
+
325
+ // Start background daemon watchdog (command center + session monitor)
326
+ const monitorScript = resolve(
327
+ dirname(fileURLToPath(import.meta.url)),
328
+ "lib",
329
+ "daemon-watchdog.ts",
330
+ );
331
+ const commandCenterPort =
332
+ config.orchestrator?.port ?? config.command_center?.port ?? DEFAULT_COMMAND_CENTER_PORT;
333
+ startSessionMonitor(session, monitorScript, commandCenterPort);
334
+
335
+ const daemonReady = await waitForDaemon(commandCenterPort);
336
+ if (!daemonReady) {
337
+ console.log("Warning: daemon did not respond to health check within 3s — continuing anyway");
338
+ }
339
+
340
+ // Inject master agent prompt and task docs if orchestrator is enabled
341
+ if (config.orchestrator?.enabled) {
342
+ ensureTaskDocs(dir);
343
+
344
+ const masterPaneTitle = config.orchestrator.master_pane;
345
+ if (masterPaneTitle) {
346
+ const masterAction = paneActions.find((a) => a.title === masterPaneTitle);
347
+ if (masterAction) {
348
+ const masterPrompt = buildMasterAgentPrompt(config);
349
+ setTimeout(() => {
350
+ sendLiteral(masterAction.targetPane, masterPrompt);
351
+ }, 5000);
352
+ }
353
+ }
354
+ }
355
+
356
+ // Focus the correct pane
357
+ selectPane(focusPane);
358
+
359
+ // Launch summary
360
+ const totalPanes = rows.reduce((sum, r) => sum + (r.panes?.length ?? 0), 0);
361
+ console.log(
362
+ `Starting "${session}" (${rows.length} row${rows.length === 1 ? "" : "s"}, ${totalPanes} pane${totalPanes === 1 ? "" : "s"})...`,
363
+ );
364
+ console.log(`Dashboard: http://localhost:${commandCenterPort}`);
365
+
366
+ // Attach
367
+ if (attach) {
368
+ attachSession(session);
369
+ }
370
+ }
371
+
372
+ export function buildMasterAgentPrompt(config: IdeConfig): string {
373
+ const teammatePanes = config.rows
374
+ .flatMap((r) => r.panes ?? [])
375
+ .filter((p: Pane) => p.role === "teammate" && p.command === "claude")
376
+ .map((p: Pane) => p.title)
377
+ .filter(Boolean);
378
+
379
+ return `You are the Master Agent for this tmux-ide session.
380
+
381
+ ## Your role
382
+ You coordinate a team of coding agents. The human gives you high-level goals, and you break them into structured tasks that your teammates execute.
383
+
384
+ ## Your teammates
385
+ ${teammatePanes.map((t) => `- ${t}`).join("\n")}
386
+
387
+ ## Task management commands
388
+ - tmux-ide mission set "title" --description "..."
389
+ - tmux-ide goal create "title" --priority N --acceptance "criteria"
390
+ - tmux-ide goal list --json
391
+ - tmux-ide task create "title" --goal NN --priority N
392
+ - tmux-ide task list --json
393
+ - tmux-ide task show NNN --json (shows full mission→goal→task context)
394
+ - tmux-ide task done NNN --proof "what was accomplished"
395
+ - tmux-ide goal done NN
396
+
397
+ ## How it works
398
+ 1. You create tasks with tmux-ide task create
399
+ 2. The orchestrator automatically assigns unassigned tasks to idle teammates
400
+ 3. Teammates work in the project directory
401
+ 4. When teammates finish, they run tmux-ide task done
402
+ 5. You get notified and review their work
403
+ 6. You report progress to the human
404
+
405
+ ## Important
406
+ - Focus on PLANNING and REVIEWING, not implementing
407
+ - Break work into small, clear tasks (one per teammate)
408
+ - Each task should be completable independently
409
+ - Set clear acceptance criteria in goals
410
+ - Check progress: tmux-ide task list --json`;
411
+ }
412
+
413
+ const TASK_DOCS_MARKER = "## Task Management";
414
+
415
+ const TASK_DOCS_SECTION = `
416
+ ## Task Management
417
+
418
+ tmux-ide provides structured task management for coordinated multi-agent work.
419
+
420
+ ### Mission & Goals
421
+
422
+ \`\`\`bash
423
+ tmux-ide mission set "title" --description "..." # Set the project mission
424
+ tmux-ide mission show # Show current mission
425
+ tmux-ide mission clear # Clear the mission
426
+
427
+ tmux-ide goal create "title" --priority N --acceptance "criteria"
428
+ tmux-ide goal list [--json] # List all goals
429
+ tmux-ide goal show <id> [--json] # Show goal with tasks
430
+ tmux-ide goal update <id> --status done
431
+ tmux-ide goal done <id> # Mark goal complete
432
+ tmux-ide goal delete <id>
433
+ \`\`\`
434
+
435
+ ### Tasks
436
+
437
+ \`\`\`bash
438
+ tmux-ide task create "title" --goal NN --priority N --assign "Agent" --tags "a,b" --depends "001,002"
439
+ tmux-ide task list [--status todo --goal NN] [--json]
440
+ tmux-ide task show <id> [--json] # Full mission→goal→task context
441
+ tmux-ide task update <id> --status review --proof '{"tests":{"passed":10,"total":10}}'
442
+ tmux-ide task claim <id> --assign "Agent Name" # Claim and start a task
443
+ tmux-ide task done <id> --proof "description" # Mark task complete with proof
444
+ tmux-ide task delete <id>
445
+ \`\`\`
446
+
447
+ ### Proof Format
448
+
449
+ The \`--proof\` flag accepts either a plain string (stored as \`notes\`) or a JSON object:
450
+
451
+ \`\`\`json
452
+ {
453
+ "tests": { "passed": 10, "total": 10 },
454
+ "pr": { "number": 42, "url": "https://...", "status": "merged" },
455
+ "ci": { "status": "passing", "url": "https://..." },
456
+ "notes": "Additional context"
457
+ }
458
+ \`\`\`
459
+
460
+ ### Task Dependencies
461
+
462
+ Use \`--depends "001,002"\` to declare that a task depends on other tasks. The orchestrator will not dispatch a task until all its dependencies are complete.
463
+ `;
464
+
465
+ export function ensureTaskDocs(dir: string): void {
466
+ const claudeMdPath = join(dir, "CLAUDE.md");
467
+
468
+ if (existsSync(claudeMdPath)) {
469
+ const content = readFileSync(claudeMdPath, "utf-8");
470
+ if (content.includes(TASK_DOCS_MARKER)) return;
471
+ writeFileSync(claudeMdPath, content + TASK_DOCS_SECTION);
472
+ } else {
473
+ writeFileSync(claudeMdPath, `# Project\n${TASK_DOCS_SECTION}`);
474
+ }
475
+ }
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "bun:test";
2
+ import * as crypto from "node:crypto";
3
+ import { AuthService } from "./auth-service.ts";
4
+
5
+ describe("AuthService", () => {
6
+ let auth: AuthService;
7
+ const SECRET = "test-secret-key-for-jwt";
8
+
9
+ beforeEach(() => {
10
+ auth = new AuthService(SECRET);
11
+ });
12
+
13
+ afterEach(() => {
14
+ auth.dispose();
15
+ });
16
+
17
+ // ---- JWT ----------------------------------------------------------------
18
+
19
+ describe("JWT sign/verify round-trip", () => {
20
+ it("generates and verifies a valid token", () => {
21
+ const token = auth.generateToken("alice");
22
+ const result = auth.verifyToken(token);
23
+ expect(result.valid).toBe(true);
24
+ expect(result.userId).toBe("alice");
25
+ });
26
+
27
+ it("works with different user IDs", () => {
28
+ const token = auth.generateToken("bob@example.com");
29
+ const result = auth.verifyToken(token);
30
+ expect(result.valid).toBe(true);
31
+ expect(result.userId).toBe("bob@example.com");
32
+ });
33
+ });
34
+
35
+ describe("expired token rejected", () => {
36
+ it("rejects a token with exp in the past", () => {
37
+ // Create a service with extremely short expiry by manipulating the token
38
+ // We'll manually craft a token with an expired timestamp
39
+ const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString(
40
+ "base64url",
41
+ );
42
+ const payload = Buffer.from(
43
+ JSON.stringify({
44
+ userId: "alice",
45
+ iat: Math.floor(Date.now() / 1000) - 7200,
46
+ exp: Math.floor(Date.now() / 1000) - 3600, // expired 1 hour ago
47
+ }),
48
+ ).toString("base64url");
49
+ const sigInput = header + "." + payload;
50
+ const sig = crypto.createHmac("sha256", SECRET).update(sigInput).digest("base64url");
51
+ const expiredToken = `${header}.${payload}.${sig}`;
52
+
53
+ const result = auth.verifyToken(expiredToken);
54
+ expect(result.valid).toBe(false);
55
+ });
56
+ });
57
+
58
+ describe("tampered token rejected", () => {
59
+ it("rejects a token with modified payload", () => {
60
+ const token = auth.generateToken("alice");
61
+ const parts = token.split(".");
62
+
63
+ // Tamper with payload — change userId
64
+ const payload = JSON.parse(Buffer.from(parts[1]!, "base64url").toString());
65
+ payload.userId = "eve";
66
+ parts[1] = Buffer.from(JSON.stringify(payload)).toString("base64url");
67
+ const tampered = parts.join(".");
68
+
69
+ const result = auth.verifyToken(tampered);
70
+ expect(result.valid).toBe(false);
71
+ });
72
+
73
+ it("rejects a token with modified signature", () => {
74
+ const token = auth.generateToken("alice");
75
+ const parts = token.split(".");
76
+ // Flip a character in the signature
77
+ const sig = parts[2]!;
78
+ parts[2] = sig[0] === "A" ? "B" + sig.slice(1) : "A" + sig.slice(1);
79
+ const tampered = parts.join(".");
80
+
81
+ const result = auth.verifyToken(tampered);
82
+ expect(result.valid).toBe(false);
83
+ });
84
+
85
+ it("rejects a token signed with a different secret", () => {
86
+ const other = new AuthService("different-secret");
87
+ const token = other.generateToken("alice");
88
+ other.dispose();
89
+
90
+ const result = auth.verifyToken(token);
91
+ expect(result.valid).toBe(false);
92
+ });
93
+
94
+ it("rejects garbage strings", () => {
95
+ expect(auth.verifyToken("not.a.jwt").valid).toBe(false);
96
+ expect(auth.verifyToken("").valid).toBe(false);
97
+ expect(auth.verifyToken("only-one-part").valid).toBe(false);
98
+ });
99
+ });
100
+
101
+ // ---- SSH challenge-response -------------------------------------------
102
+
103
+ describe("SSH challenge with test keypair", () => {
104
+ // Generate an Ed25519 keypair for testing
105
+ function makeTestKey() {
106
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
107
+
108
+ // Export raw 32-byte public key
109
+ const rawPub = publicKey.export({ type: "spki", format: "der" });
110
+ // Last 32 bytes of the DER encoding are the raw key
111
+ const raw32 = rawPub.subarray(rawPub.length - 32);
112
+
113
+ // Build SSH wire format: uint32(len) + "ssh-ed25519" + uint32(32) + raw32
114
+ const alg = Buffer.from("ssh-ed25519");
115
+ const algLenBuf = Buffer.alloc(4);
116
+ algLenBuf.writeUInt32BE(alg.length);
117
+ const keyLenBuf = Buffer.alloc(4);
118
+ keyLenBuf.writeUInt32BE(32);
119
+ const sshPubBuf = Buffer.concat([algLenBuf, alg, keyLenBuf, raw32]);
120
+ const sshPubStr = `ssh-ed25519 ${sshPubBuf.toString("base64")} test@test`;
121
+
122
+ return { publicKey, privateKey, sshPubStr };
123
+ }
124
+
125
+ it("creates a challenge and verifies a valid signature", async () => {
126
+ const { privateKey, sshPubStr } = makeTestKey();
127
+
128
+ // Create challenge
129
+ const { challengeId, challenge } = auth.createChallenge("testuser");
130
+ expect(challengeId).toBeTruthy();
131
+ expect(challenge).toBeTruthy();
132
+
133
+ // Sign the challenge
134
+ const challengeBuf = Buffer.from(challenge, "base64");
135
+ const signature = crypto.sign(null, challengeBuf, privateKey);
136
+
137
+ // authenticateWithSSHKey checks authorized_keys which won't exist in test,
138
+ // so we just verify the signature verification path works by checking
139
+ // that it gets past signature verification (fails at authorization)
140
+ const result = await auth.authenticateWithSSHKey({
141
+ publicKey: sshPubStr,
142
+ challengeId,
143
+ signature: signature.toString("base64"),
144
+ });
145
+
146
+ // Expect "not authorized" — which means signature verification passed
147
+ expect(result.success).toBe(false);
148
+ expect(result.error).toBe("SSH key not authorized for this user");
149
+ });
150
+
151
+ it("rejects an invalid signature", async () => {
152
+ const { sshPubStr } = makeTestKey();
153
+
154
+ const { challengeId } = auth.createChallenge("testuser");
155
+
156
+ // Send garbage signature (wrong length for ed25519 = 64 bytes)
157
+ const result = await auth.authenticateWithSSHKey({
158
+ publicKey: sshPubStr,
159
+ challengeId,
160
+ signature: Buffer.alloc(64).toString("base64"),
161
+ });
162
+
163
+ expect(result.success).toBe(false);
164
+ expect(result.error).toBe("Invalid SSH key signature");
165
+ });
166
+
167
+ it("rejects an expired/unknown challenge ID", async () => {
168
+ const result = await auth.authenticateWithSSHKey({
169
+ publicKey: "ssh-ed25519 AAAA test",
170
+ challengeId: "nonexistent-id",
171
+ signature: Buffer.alloc(64).toString("base64"),
172
+ });
173
+
174
+ expect(result.success).toBe(false);
175
+ expect(result.error).toBe("Invalid or expired challenge");
176
+ });
177
+ });
178
+ });