@vibedeckx/linux-x64 0.1.10

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 (579) hide show
  1. package/dist/agent-provider.d.ts +92 -0
  2. package/dist/agent-provider.js +8 -0
  3. package/dist/agent-session-manager.d.ts +165 -0
  4. package/dist/agent-session-manager.js +985 -0
  5. package/dist/agent-types.d.ts +148 -0
  6. package/dist/agent-types.js +4 -0
  7. package/dist/bin.d.ts +2 -0
  8. package/dist/bin.js +4 -0
  9. package/dist/browser-manager.d.ts +46 -0
  10. package/dist/browser-manager.js +182 -0
  11. package/dist/chat-session-manager.d.ts +101 -0
  12. package/dist/chat-session-manager.js +1425 -0
  13. package/dist/command.d.ts +1 -0
  14. package/dist/command.js +163 -0
  15. package/dist/constants.d.ts +3 -0
  16. package/dist/constants.js +5 -0
  17. package/dist/conversation-patch.d.ts +103 -0
  18. package/dist/conversation-patch.js +69 -0
  19. package/dist/dialog.d.ts +1 -0
  20. package/dist/dialog.js +41 -0
  21. package/dist/entry-index-provider.d.ts +74 -0
  22. package/dist/entry-index-provider.js +105 -0
  23. package/dist/event-bus.d.ts +47 -0
  24. package/dist/event-bus.js +16 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.js +2 -0
  27. package/dist/plugins/shared-services.d.ts +8 -0
  28. package/dist/plugins/shared-services.js +65 -0
  29. package/dist/process-manager.d.ts +146 -0
  30. package/dist/process-manager.js +779 -0
  31. package/dist/providers/claude-code-provider.d.ts +13 -0
  32. package/dist/providers/claude-code-provider.js +127 -0
  33. package/dist/providers/codex-provider.d.ts +41 -0
  34. package/dist/providers/codex-provider.js +354 -0
  35. package/dist/providers/index.d.ts +5 -0
  36. package/dist/providers/index.js +19 -0
  37. package/dist/remote-patch-cache.d.ts +67 -0
  38. package/dist/remote-patch-cache.js +190 -0
  39. package/dist/reverse-connect-client.d.ts +27 -0
  40. package/dist/reverse-connect-client.js +255 -0
  41. package/dist/reverse-connect-manager.d.ts +31 -0
  42. package/dist/reverse-connect-manager.js +287 -0
  43. package/dist/reverse-connect-types.d.ts +55 -0
  44. package/dist/reverse-connect-types.js +7 -0
  45. package/dist/routes/agent-session-routes.d.ts +4 -0
  46. package/dist/routes/agent-session-routes.js +442 -0
  47. package/dist/routes/browser-proxy-routes.d.ts +25 -0
  48. package/dist/routes/browser-proxy-routes.js +421 -0
  49. package/dist/routes/browser-routes.d.ts +4 -0
  50. package/dist/routes/browser-routes.js +73 -0
  51. package/dist/routes/chat-session-routes.d.ts +7 -0
  52. package/dist/routes/chat-session-routes.js +69 -0
  53. package/dist/routes/diff-routes.d.ts +4 -0
  54. package/dist/routes/diff-routes.js +208 -0
  55. package/dist/routes/event-routes.d.ts +4 -0
  56. package/dist/routes/event-routes.js +52 -0
  57. package/dist/routes/executor-group-routes.d.ts +4 -0
  58. package/dist/routes/executor-group-routes.js +76 -0
  59. package/dist/routes/executor-routes.d.ts +4 -0
  60. package/dist/routes/executor-routes.js +106 -0
  61. package/dist/routes/file-routes.d.ts +4 -0
  62. package/dist/routes/file-routes.js +331 -0
  63. package/dist/routes/process-routes.d.ts +4 -0
  64. package/dist/routes/process-routes.js +183 -0
  65. package/dist/routes/project-remote-routes.d.ts +4 -0
  66. package/dist/routes/project-remote-routes.js +82 -0
  67. package/dist/routes/project-routes.d.ts +4 -0
  68. package/dist/routes/project-routes.js +286 -0
  69. package/dist/routes/remote-routes.d.ts +4 -0
  70. package/dist/routes/remote-routes.js +59 -0
  71. package/dist/routes/remote-server-routes.d.ts +4 -0
  72. package/dist/routes/remote-server-routes.js +157 -0
  73. package/dist/routes/reverse-connect-routes.d.ts +4 -0
  74. package/dist/routes/reverse-connect-routes.js +33 -0
  75. package/dist/routes/settings-routes.d.ts +4 -0
  76. package/dist/routes/settings-routes.js +129 -0
  77. package/dist/routes/task-routes.d.ts +4 -0
  78. package/dist/routes/task-routes.js +107 -0
  79. package/dist/routes/terminal-routes.d.ts +4 -0
  80. package/dist/routes/terminal-routes.js +187 -0
  81. package/dist/routes/translate-routes.d.ts +4 -0
  82. package/dist/routes/translate-routes.js +38 -0
  83. package/dist/routes/websocket-routes.d.ts +4 -0
  84. package/dist/routes/websocket-routes.js +604 -0
  85. package/dist/routes/worktree-routes.d.ts +4 -0
  86. package/dist/routes/worktree-routes.js +511 -0
  87. package/dist/server-types.d.ts +41 -0
  88. package/dist/server-types.js +1 -0
  89. package/dist/server.d.ts +23 -0
  90. package/dist/server.js +238 -0
  91. package/dist/storage/sqlite.d.ts +2 -0
  92. package/dist/storage/sqlite.js +1073 -0
  93. package/dist/storage/types.d.ts +281 -0
  94. package/dist/storage/types.js +1 -0
  95. package/dist/ui/404/index.html +1 -0
  96. package/dist/ui/404.html +1 -0
  97. package/dist/ui/__next.__PAGE__.txt +10 -0
  98. package/dist/ui/__next._full.txt +25 -0
  99. package/dist/ui/__next._head.txt +6 -0
  100. package/dist/ui/__next._index.txt +9 -0
  101. package/dist/ui/__next._tree.txt +6 -0
  102. package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_buildManifest.js +11 -0
  103. package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_clientMiddlewareManifest.json +1 -0
  104. package/dist/ui/_next/static/7vIIuOQPJu8rdb6uAhwtg/_ssgManifest.js +1 -0
  105. package/dist/ui/_next/static/chunks/002f5a047b8d07d4.js +1 -0
  106. package/dist/ui/_next/static/chunks/01178e167ba3e5b4.js +1 -0
  107. package/dist/ui/_next/static/chunks/020d675d21be28d4.js +1 -0
  108. package/dist/ui/_next/static/chunks/024926197424b4a5.js +1 -0
  109. package/dist/ui/_next/static/chunks/02c93f6ca211a65d.js +1 -0
  110. package/dist/ui/_next/static/chunks/0364437dee56dc96.js +1 -0
  111. package/dist/ui/_next/static/chunks/03fc6b527b16efdc.js +1 -0
  112. package/dist/ui/_next/static/chunks/04f9a7932751cf2d.js +1 -0
  113. package/dist/ui/_next/static/chunks/0624b8204e5ae457.js +136 -0
  114. package/dist/ui/_next/static/chunks/067d8978cf41b901.js +1 -0
  115. package/dist/ui/_next/static/chunks/06d96238e85cdbb3.js +1 -0
  116. package/dist/ui/_next/static/chunks/071b9575dbdf1dcb.js +1 -0
  117. package/dist/ui/_next/static/chunks/073d5b9dc87ceab0.js +1 -0
  118. package/dist/ui/_next/static/chunks/0876a7111934d6f7.js +1 -0
  119. package/dist/ui/_next/static/chunks/08ffc3bf406c665d.js +1 -0
  120. package/dist/ui/_next/static/chunks/0969e8274c92c2d8.js +1 -0
  121. package/dist/ui/_next/static/chunks/0a3f62f00d7bec78.js +1 -0
  122. package/dist/ui/_next/static/chunks/0b80166023d89049.js +5 -0
  123. package/dist/ui/_next/static/chunks/0c2a941e61c395b6.js +1 -0
  124. package/dist/ui/_next/static/chunks/0c5eac8493334420.js +1 -0
  125. package/dist/ui/_next/static/chunks/0cc61d37b2333469.js +1 -0
  126. package/dist/ui/_next/static/chunks/0d440843348b2871.js +1 -0
  127. package/dist/ui/_next/static/chunks/0da3d15845f17208.js +1 -0
  128. package/dist/ui/_next/static/chunks/0e1982b1a6cbd127.js +53 -0
  129. package/dist/ui/_next/static/chunks/0e81d5bc1c725b75.js +1 -0
  130. package/dist/ui/_next/static/chunks/0e862e51b01e904b.js +63 -0
  131. package/dist/ui/_next/static/chunks/0ed7b6d86744b723.js +1 -0
  132. package/dist/ui/_next/static/chunks/0f0b3025f4e268b1.js +1 -0
  133. package/dist/ui/_next/static/chunks/10a30eb52825da36.js +1 -0
  134. package/dist/ui/_next/static/chunks/10c48da576fd8eef.js +1 -0
  135. package/dist/ui/_next/static/chunks/133e9f1435ca5f45.js +29 -0
  136. package/dist/ui/_next/static/chunks/16f4db3a54f167fd.js +1 -0
  137. package/dist/ui/_next/static/chunks/1988e3ecf5ad06d3.js +1 -0
  138. package/dist/ui/_next/static/chunks/1acfae010fd77014.js +152 -0
  139. package/dist/ui/_next/static/chunks/1ae53c2f1fff8cc2.js +1 -0
  140. package/dist/ui/_next/static/chunks/1af4fbc6c1256fae.js +1 -0
  141. package/dist/ui/_next/static/chunks/1b758c732032b236.js +1 -0
  142. package/dist/ui/_next/static/chunks/1ba26455a9f70c08.js +1 -0
  143. package/dist/ui/_next/static/chunks/1d22644cb4049d6b.css +1 -0
  144. package/dist/ui/_next/static/chunks/1d241f3b57c14cf7.js +1 -0
  145. package/dist/ui/_next/static/chunks/1d640bbe1c2c7869.js +1 -0
  146. package/dist/ui/_next/static/chunks/1da6354c9cb6f0de.js +1 -0
  147. package/dist/ui/_next/static/chunks/1dcd49914412f67b.js +1 -0
  148. package/dist/ui/_next/static/chunks/1e3b3771294825a4.js +1 -0
  149. package/dist/ui/_next/static/chunks/1eaa8ad7eca7f957.js +1 -0
  150. package/dist/ui/_next/static/chunks/1ebc88f60cadb128.js +1 -0
  151. package/dist/ui/_next/static/chunks/1ecb57b258088259.js +1 -0
  152. package/dist/ui/_next/static/chunks/1f5ba6b80fe19200.js +1 -0
  153. package/dist/ui/_next/static/chunks/20a5531534828366.js +1 -0
  154. package/dist/ui/_next/static/chunks/20b511fc299dfe9a.js +1 -0
  155. package/dist/ui/_next/static/chunks/20bff4eb9a0a6872.css +1 -0
  156. package/dist/ui/_next/static/chunks/219b7d9e437c6bd8.js +15 -0
  157. package/dist/ui/_next/static/chunks/21b32f530e0df2c5.js +1 -0
  158. package/dist/ui/_next/static/chunks/21fc6dc60e7647b1.js +1 -0
  159. package/dist/ui/_next/static/chunks/221a27e65aa5fbfd.js +1 -0
  160. package/dist/ui/_next/static/chunks/23a1e247c32bcc61.js +93 -0
  161. package/dist/ui/_next/static/chunks/2473c16c0c2f6b5f.css +2 -0
  162. package/dist/ui/_next/static/chunks/2615c71c0f8fe9bd.js +1 -0
  163. package/dist/ui/_next/static/chunks/263327288d5e2703.js +1 -0
  164. package/dist/ui/_next/static/chunks/2663fbaf43239e38.js +1 -0
  165. package/dist/ui/_next/static/chunks/27332c590d59f4e5.js +1 -0
  166. package/dist/ui/_next/static/chunks/27ca4a4e8191093f.js +1 -0
  167. package/dist/ui/_next/static/chunks/29b7618dcaa8edba.js +1 -0
  168. package/dist/ui/_next/static/chunks/2ba1d2b55b82f4da.js +21 -0
  169. package/dist/ui/_next/static/chunks/2cb23686e72468c8.js +1 -0
  170. package/dist/ui/_next/static/chunks/2d46f05dcbf1cbc2.js +1 -0
  171. package/dist/ui/_next/static/chunks/2d4c0fd06ca34510.js +2 -0
  172. package/dist/ui/_next/static/chunks/2f3d1d07474b8f79.js +1 -0
  173. package/dist/ui/_next/static/chunks/2f85c2849249a0dd.js +1 -0
  174. package/dist/ui/_next/static/chunks/3001d378f166eec9.js +1 -0
  175. package/dist/ui/_next/static/chunks/3018714f3827e360.js +1 -0
  176. package/dist/ui/_next/static/chunks/301cc25e0d489351.js +1 -0
  177. package/dist/ui/_next/static/chunks/305242b22ba8b49b.js +1 -0
  178. package/dist/ui/_next/static/chunks/3067c6e369066bd6.js +1 -0
  179. package/dist/ui/_next/static/chunks/311a77c9d5cb9de9.js +1 -0
  180. package/dist/ui/_next/static/chunks/320c001380e81470.js +1 -0
  181. package/dist/ui/_next/static/chunks/329db6c551df0faf.js +1 -0
  182. package/dist/ui/_next/static/chunks/33da178724072b3d.js +1 -0
  183. package/dist/ui/_next/static/chunks/33e8248c9296537a.js +1 -0
  184. package/dist/ui/_next/static/chunks/35a9992a8958f93b.js +1 -0
  185. package/dist/ui/_next/static/chunks/35bb90cf09892b72.js +1 -0
  186. package/dist/ui/_next/static/chunks/379f91b92366dc15.js +1 -0
  187. package/dist/ui/_next/static/chunks/391f22359769763f.js +1 -0
  188. package/dist/ui/_next/static/chunks/39231cb1044f7823.js +1 -0
  189. package/dist/ui/_next/static/chunks/394e8b7a1c2c58c6.js +1 -0
  190. package/dist/ui/_next/static/chunks/3a2cfdeb5f76ebd2.js +1 -0
  191. package/dist/ui/_next/static/chunks/3a3bd015fd042386.js +1 -0
  192. package/dist/ui/_next/static/chunks/3ad1bee238af9b5a.js +1 -0
  193. package/dist/ui/_next/static/chunks/3b2b2f7a9b7b130d.js +1 -0
  194. package/dist/ui/_next/static/chunks/3b586f80547e3a22.js +1 -0
  195. package/dist/ui/_next/static/chunks/3ca412e72bd3707a.js +1 -0
  196. package/dist/ui/_next/static/chunks/3cbb3bdceb4230af.js +1 -0
  197. package/dist/ui/_next/static/chunks/3ed1465109fecc2d.js +1 -0
  198. package/dist/ui/_next/static/chunks/3fd0801238b3b099.js +1 -0
  199. package/dist/ui/_next/static/chunks/401df66bd5da2115.js +15 -0
  200. package/dist/ui/_next/static/chunks/4211f4efe510f7ac.js +1 -0
  201. package/dist/ui/_next/static/chunks/43085364d0a41d1d.js +1 -0
  202. package/dist/ui/_next/static/chunks/4310c821dbee7a16.js +1 -0
  203. package/dist/ui/_next/static/chunks/46382f31f63e59cf.js +1 -0
  204. package/dist/ui/_next/static/chunks/468836b90ddf24d6.js +1 -0
  205. package/dist/ui/_next/static/chunks/470d091143104517.js +1 -0
  206. package/dist/ui/_next/static/chunks/4712e4f7e6b6ddc1.js +1 -0
  207. package/dist/ui/_next/static/chunks/4899f1e3f21c077e.js +1 -0
  208. package/dist/ui/_next/static/chunks/492ce6930bf61811.js +1 -0
  209. package/dist/ui/_next/static/chunks/494485a20952ffa3.js +1 -0
  210. package/dist/ui/_next/static/chunks/49535db309898f43.js +1 -0
  211. package/dist/ui/_next/static/chunks/4b8d2612d69e2013.js +1 -0
  212. package/dist/ui/_next/static/chunks/4c4a0f67891826a3.js +1 -0
  213. package/dist/ui/_next/static/chunks/4cc11ce32f4453b0.js +1 -0
  214. package/dist/ui/_next/static/chunks/4d03a0bc963fc3d4.js +1 -0
  215. package/dist/ui/_next/static/chunks/4d603a66c067134e.js +1 -0
  216. package/dist/ui/_next/static/chunks/4d8d7e62c2743f71.js +15 -0
  217. package/dist/ui/_next/static/chunks/4da42f10a5460b36.js +1 -0
  218. package/dist/ui/_next/static/chunks/4e832ffb65e75807.js +1 -0
  219. package/dist/ui/_next/static/chunks/4e954e1cec89a9ea.js +1 -0
  220. package/dist/ui/_next/static/chunks/4f2bc7a7a6b05a8b.js +55 -0
  221. package/dist/ui/_next/static/chunks/4f9c934abf34ceb9.js +1 -0
  222. package/dist/ui/_next/static/chunks/4fa248b0d2586928.js +1 -0
  223. package/dist/ui/_next/static/chunks/4fafbac2156844ca.js +1 -0
  224. package/dist/ui/_next/static/chunks/502039e483cc5e48.js +1 -0
  225. package/dist/ui/_next/static/chunks/509c91c38224448a.js +1 -0
  226. package/dist/ui/_next/static/chunks/5159d6f8d4307f36.js +1 -0
  227. package/dist/ui/_next/static/chunks/5179ab56aaaed42d.js +1 -0
  228. package/dist/ui/_next/static/chunks/5269ea07faff562d.js +1 -0
  229. package/dist/ui/_next/static/chunks/529f3f0f7d42444a.js +1 -0
  230. package/dist/ui/_next/static/chunks/5317db6783ee8dc9.js +1 -0
  231. package/dist/ui/_next/static/chunks/53a7b7c0ab020902.js +1 -0
  232. package/dist/ui/_next/static/chunks/544869c670c1dd8e.js +1 -0
  233. package/dist/ui/_next/static/chunks/547c0db6a433370e.js +1 -0
  234. package/dist/ui/_next/static/chunks/54d5670f5fa2abbe.css +1 -0
  235. package/dist/ui/_next/static/chunks/55761e35a8946a1d.js +15 -0
  236. package/dist/ui/_next/static/chunks/558f73c16b7ff14f.js +1 -0
  237. package/dist/ui/_next/static/chunks/55c76f605958d671.js +1 -0
  238. package/dist/ui/_next/static/chunks/55dc6750fb117bf9.js +1 -0
  239. package/dist/ui/_next/static/chunks/584bad9cf2498405.js +1 -0
  240. package/dist/ui/_next/static/chunks/593b85b9abea3ea6.js +1 -0
  241. package/dist/ui/_next/static/chunks/5a79af73c96155d4.js +1 -0
  242. package/dist/ui/_next/static/chunks/5ee54b9b6b400134.js +1 -0
  243. package/dist/ui/_next/static/chunks/5f27ee48dc820109.js +1 -0
  244. package/dist/ui/_next/static/chunks/5ffd50a08d82e2f3.js +1 -0
  245. package/dist/ui/_next/static/chunks/61d65fe807f69413.js +62 -0
  246. package/dist/ui/_next/static/chunks/626a650bcaaecdb8.js +1 -0
  247. package/dist/ui/_next/static/chunks/62baecafed4dbced.js +1 -0
  248. package/dist/ui/_next/static/chunks/634a4b5b6a38ccab.js +1 -0
  249. package/dist/ui/_next/static/chunks/643c359cf3f7364e.js +1 -0
  250. package/dist/ui/_next/static/chunks/649e65f4820a772b.js +1 -0
  251. package/dist/ui/_next/static/chunks/65028938188a230c.js +1 -0
  252. package/dist/ui/_next/static/chunks/65b3658348e8d4fd.js +1 -0
  253. package/dist/ui/_next/static/chunks/65eed220466cbdbc.js +1 -0
  254. package/dist/ui/_next/static/chunks/66714687cfd91953.js +1 -0
  255. package/dist/ui/_next/static/chunks/66ccaa3e69ed7a69.js +1 -0
  256. package/dist/ui/_next/static/chunks/6754600af0c6b3a8.js +1 -0
  257. package/dist/ui/_next/static/chunks/67a1d37727697340.js +1 -0
  258. package/dist/ui/_next/static/chunks/67e965a7f9531cee.js +1 -0
  259. package/dist/ui/_next/static/chunks/6816bf02e4c22a55.js +1 -0
  260. package/dist/ui/_next/static/chunks/68621b90909ec4e6.js +1 -0
  261. package/dist/ui/_next/static/chunks/6929ceb718c6e4c6.js +1 -0
  262. package/dist/ui/_next/static/chunks/69362fff2240a17b.js +1 -0
  263. package/dist/ui/_next/static/chunks/69dab47a307b1a37.js +1 -0
  264. package/dist/ui/_next/static/chunks/6afa71c8b3358dd5.js +1 -0
  265. package/dist/ui/_next/static/chunks/6bf54dc328e667f7.js +1 -0
  266. package/dist/ui/_next/static/chunks/6c44508faf13f6f0.js +1 -0
  267. package/dist/ui/_next/static/chunks/6c9c2b61c905a2de.js +1 -0
  268. package/dist/ui/_next/static/chunks/6cc2e3d7873522b9.js +1 -0
  269. package/dist/ui/_next/static/chunks/6d01e8902e85bfe0.js +1 -0
  270. package/dist/ui/_next/static/chunks/6dc69e4a91f7a353.js +1 -0
  271. package/dist/ui/_next/static/chunks/6e832e016b60ae19.js +1 -0
  272. package/dist/ui/_next/static/chunks/6eab0d8815c18a6d.js +1 -0
  273. package/dist/ui/_next/static/chunks/6f862eb588fa3b7e.js +1 -0
  274. package/dist/ui/_next/static/chunks/6ff7b0a8653036b2.js +1 -0
  275. package/dist/ui/_next/static/chunks/710ce144a9645f3c.js +1 -0
  276. package/dist/ui/_next/static/chunks/71293e300c639b6b.js +1 -0
  277. package/dist/ui/_next/static/chunks/7186d7cce354a012.js +1 -0
  278. package/dist/ui/_next/static/chunks/7215d586009e8158.js +1 -0
  279. package/dist/ui/_next/static/chunks/726fdeaff53a89ac.js +1 -0
  280. package/dist/ui/_next/static/chunks/7322a00d61e7ffad.js +1 -0
  281. package/dist/ui/_next/static/chunks/73c60ee9f233051d.js +1 -0
  282. package/dist/ui/_next/static/chunks/740f5627b5c57baa.js +1 -0
  283. package/dist/ui/_next/static/chunks/74438794a8e9ba80.js +1 -0
  284. package/dist/ui/_next/static/chunks/74ffcd7d13b3fea0.js +1 -0
  285. package/dist/ui/_next/static/chunks/7510496048ab1ad4.js +1 -0
  286. package/dist/ui/_next/static/chunks/7636f89f38cbc3e3.js +1 -0
  287. package/dist/ui/_next/static/chunks/782a93ec4348b666.js +1 -0
  288. package/dist/ui/_next/static/chunks/7850bbac1925646c.js +1 -0
  289. package/dist/ui/_next/static/chunks/790dcc1e825d2504.js +1 -0
  290. package/dist/ui/_next/static/chunks/798597a1c1248d29.js +1 -0
  291. package/dist/ui/_next/static/chunks/7a70641f70a5c72d.js +60 -0
  292. package/dist/ui/_next/static/chunks/7c62789391c35dce.js +1 -0
  293. package/dist/ui/_next/static/chunks/7d533d3f2ab624f2.js +1 -0
  294. package/dist/ui/_next/static/chunks/7d6087c3fabf9ded.js +1 -0
  295. package/dist/ui/_next/static/chunks/7d84c9cb810e6902.js +1 -0
  296. package/dist/ui/_next/static/chunks/7dc4f5ba8c25c409.js +1 -0
  297. package/dist/ui/_next/static/chunks/7e10c0644fbb99d1.js +1 -0
  298. package/dist/ui/_next/static/chunks/7e7aaacf104c17f4.js +1 -0
  299. package/dist/ui/_next/static/chunks/7e92979509de57ed.js +1 -0
  300. package/dist/ui/_next/static/chunks/7f9a52e36f9f001e.js +1 -0
  301. package/dist/ui/_next/static/chunks/7fc4ae2e7cf2e37e.js +1 -0
  302. package/dist/ui/_next/static/chunks/801232fdde8ce252.js +1 -0
  303. package/dist/ui/_next/static/chunks/808ed0f189237446.js +1 -0
  304. package/dist/ui/_next/static/chunks/8199e6b3fa54b2ff.js +1 -0
  305. package/dist/ui/_next/static/chunks/81fa0fa05a94eb02.js +1 -0
  306. package/dist/ui/_next/static/chunks/821b5389566b82d2.js +1 -0
  307. package/dist/ui/_next/static/chunks/82b9e04f88e657df.js +1 -0
  308. package/dist/ui/_next/static/chunks/830c79cc12f2c5a4.js +1 -0
  309. package/dist/ui/_next/static/chunks/8388ae863590404b.js +4 -0
  310. package/dist/ui/_next/static/chunks/83ab70f11a82a8c6.js +1 -0
  311. package/dist/ui/_next/static/chunks/83faf7904ac18d7f.js +1 -0
  312. package/dist/ui/_next/static/chunks/850d850bd879606f.js +1 -0
  313. package/dist/ui/_next/static/chunks/864d4b5cf4ae2226.js +1 -0
  314. package/dist/ui/_next/static/chunks/86d8962196053f53.js +139 -0
  315. package/dist/ui/_next/static/chunks/8723d7000b263475.js +1 -0
  316. package/dist/ui/_next/static/chunks/87e5597a4336e2c1.js +1 -0
  317. package/dist/ui/_next/static/chunks/899fe56c4c707c65.js +1 -0
  318. package/dist/ui/_next/static/chunks/8bda52f55493ae9b.js +1 -0
  319. package/dist/ui/_next/static/chunks/8ce5668c3da0679a.js +1 -0
  320. package/dist/ui/_next/static/chunks/8d1c22aafb4783c5.js +1 -0
  321. package/dist/ui/_next/static/chunks/8deda0adfe811d18.js +1 -0
  322. package/dist/ui/_next/static/chunks/8eed597098a27801.js +1 -0
  323. package/dist/ui/_next/static/chunks/8ff7a1947b8d114b.js +1 -0
  324. package/dist/ui/_next/static/chunks/90367a2ee1e720b2.js +1 -0
  325. package/dist/ui/_next/static/chunks/9097640e1931c0de.js +1 -0
  326. package/dist/ui/_next/static/chunks/912457473a4c91c3.js +1 -0
  327. package/dist/ui/_next/static/chunks/91f7dd388c6b88c6.js +1 -0
  328. package/dist/ui/_next/static/chunks/932d4334e5f98b7c.js +1 -0
  329. package/dist/ui/_next/static/chunks/94b1efc14d44707b.js +1 -0
  330. package/dist/ui/_next/static/chunks/956107bc3ba52911.js +1 -0
  331. package/dist/ui/_next/static/chunks/962e5cad8ea716fc.js +36 -0
  332. package/dist/ui/_next/static/chunks/96acf903dff8ecf7.js +1 -0
  333. package/dist/ui/_next/static/chunks/96b274c82c194b4f.js +1 -0
  334. package/dist/ui/_next/static/chunks/96b3c1b1afe3201d.js +1 -0
  335. package/dist/ui/_next/static/chunks/9880c26551206d33.js +1 -0
  336. package/dist/ui/_next/static/chunks/98ea228d01556617.js +1 -0
  337. package/dist/ui/_next/static/chunks/9951c25a8b05148f.js +1 -0
  338. package/dist/ui/_next/static/chunks/9b10895d33be5f6e.js +1 -0
  339. package/dist/ui/_next/static/chunks/9b50a76ddbe4934d.js +1 -0
  340. package/dist/ui/_next/static/chunks/9bbb1c0146042008.js +1 -0
  341. package/dist/ui/_next/static/chunks/9ccab70823e99451.js +1 -0
  342. package/dist/ui/_next/static/chunks/9cd7bcb29e0b3418.js +24 -0
  343. package/dist/ui/_next/static/chunks/9d06bd5d701ace73.js +1 -0
  344. package/dist/ui/_next/static/chunks/9e5d9fc30c12fbdd.js +1 -0
  345. package/dist/ui/_next/static/chunks/9ec3bc5544bcc15a.js +1 -0
  346. package/dist/ui/_next/static/chunks/9f47133184a7455a.js +1 -0
  347. package/dist/ui/_next/static/chunks/a002d3850b7c7c59.js +1 -0
  348. package/dist/ui/_next/static/chunks/a0bc5573cadd1377.js +1 -0
  349. package/dist/ui/_next/static/chunks/a1d3de9e7615662e.js +160 -0
  350. package/dist/ui/_next/static/chunks/a2ce60768a8373e7.js +1 -0
  351. package/dist/ui/_next/static/chunks/a305087b1a55b367.js +1 -0
  352. package/dist/ui/_next/static/chunks/a41df0d443f66c68.js +1 -0
  353. package/dist/ui/_next/static/chunks/a49d2e9f31886b5e.js +1 -0
  354. package/dist/ui/_next/static/chunks/a50922e0883f65cd.js +1 -0
  355. package/dist/ui/_next/static/chunks/a60e84ee8b6c5ffc.js +43 -0
  356. package/dist/ui/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  357. package/dist/ui/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  358. package/dist/ui/_next/static/chunks/a7c40c289b5e2384.js +1 -0
  359. package/dist/ui/_next/static/chunks/a7fdfeea5fd894c1.js +59 -0
  360. package/dist/ui/_next/static/chunks/a81381241f4f484c.js +1 -0
  361. package/dist/ui/_next/static/chunks/a8a3989305bcc136.js +215 -0
  362. package/dist/ui/_next/static/chunks/a8cf26088e63128c.js +1 -0
  363. package/dist/ui/_next/static/chunks/aac4ca816d9ccdb6.js +1 -0
  364. package/dist/ui/_next/static/chunks/ab432bc28a971c8f.js +1 -0
  365. package/dist/ui/_next/static/chunks/abccff1b09b6effa.js +1 -0
  366. package/dist/ui/_next/static/chunks/ac8a8986f09ec520.js +1 -0
  367. package/dist/ui/_next/static/chunks/accbf306b5ddb732.js +1 -0
  368. package/dist/ui/_next/static/chunks/af7b09aba1d477ff.js +1 -0
  369. package/dist/ui/_next/static/chunks/af8114430894d79e.js +1 -0
  370. package/dist/ui/_next/static/chunks/afe2ff5d0727a240.js +1 -0
  371. package/dist/ui/_next/static/chunks/b096fa008120f0ae.js +1 -0
  372. package/dist/ui/_next/static/chunks/b0bc568eaff56dad.js +1 -0
  373. package/dist/ui/_next/static/chunks/b225dddc0852f85c.js +215 -0
  374. package/dist/ui/_next/static/chunks/b2342c5099957971.js +1 -0
  375. package/dist/ui/_next/static/chunks/b2d8c64d7d6a06b7.js +1 -0
  376. package/dist/ui/_next/static/chunks/b331c855cfc8fd57.js +1 -0
  377. package/dist/ui/_next/static/chunks/b356ee8615740392.js +1 -0
  378. package/dist/ui/_next/static/chunks/b3beaac9b7957d3f.js +1 -0
  379. package/dist/ui/_next/static/chunks/b4e7d4a109c4c080.js +1 -0
  380. package/dist/ui/_next/static/chunks/b5010f2ea9df9d00.js +77 -0
  381. package/dist/ui/_next/static/chunks/b5f9d21bd1b51a48.js +1 -0
  382. package/dist/ui/_next/static/chunks/b6a16eb77c5c9831.js +1 -0
  383. package/dist/ui/_next/static/chunks/b6a8e7c2216683ca.js +262 -0
  384. package/dist/ui/_next/static/chunks/b873c4d327a450e0.js +1 -0
  385. package/dist/ui/_next/static/chunks/b8aec8caed569fd2.js +24 -0
  386. package/dist/ui/_next/static/chunks/b8e7601e2379fd74.js +1 -0
  387. package/dist/ui/_next/static/chunks/ba3d03bf2f33f2a3.js +1 -0
  388. package/dist/ui/_next/static/chunks/ba698805336b2cb2.js +1 -0
  389. package/dist/ui/_next/static/chunks/bc48735eee7d1345.js +1 -0
  390. package/dist/ui/_next/static/chunks/bcb48aab1bdae96a.js +1 -0
  391. package/dist/ui/_next/static/chunks/bde2ca9d150d96ff.js +1 -0
  392. package/dist/ui/_next/static/chunks/be4af851547fc916.js +1 -0
  393. package/dist/ui/_next/static/chunks/be70ba8c4ba5cdb6.js +1 -0
  394. package/dist/ui/_next/static/chunks/be87578ee895734b.js +1 -0
  395. package/dist/ui/_next/static/chunks/c0aeb40fcca7d006.js +1 -0
  396. package/dist/ui/_next/static/chunks/c32156843c32ebca.js +1 -0
  397. package/dist/ui/_next/static/chunks/c57a3e045f3722c1.js +1 -0
  398. package/dist/ui/_next/static/chunks/c5add23cde4a234a.js +1 -0
  399. package/dist/ui/_next/static/chunks/c60897f3554a9388.js +1 -0
  400. package/dist/ui/_next/static/chunks/c648a36722afd12a.js +1 -0
  401. package/dist/ui/_next/static/chunks/c652f05e0a0d7b81.js +1 -0
  402. package/dist/ui/_next/static/chunks/c678d9303ed453b4.js +1 -0
  403. package/dist/ui/_next/static/chunks/c681430c24597d06.js +1 -0
  404. package/dist/ui/_next/static/chunks/c890870fb65940bc.js +1 -0
  405. package/dist/ui/_next/static/chunks/c94c394aeec71e21.js +1 -0
  406. package/dist/ui/_next/static/chunks/ca1eb1e2978389e4.js +1 -0
  407. package/dist/ui/_next/static/chunks/ca3512025a981c82.js +1 -0
  408. package/dist/ui/_next/static/chunks/ca6db0d999bad46b.js +1 -0
  409. package/dist/ui/_next/static/chunks/ca926babdf75597c.js +1 -0
  410. package/dist/ui/_next/static/chunks/cb0877764d4a31f2.js +1 -0
  411. package/dist/ui/_next/static/chunks/cb15e0c2ff49cf52.js +1 -0
  412. package/dist/ui/_next/static/chunks/cb1ae84204260ecd.js +1 -0
  413. package/dist/ui/_next/static/chunks/cb2ef733c53d80f7.js +1 -0
  414. package/dist/ui/_next/static/chunks/cbaa87ba8930fb75.js +1 -0
  415. package/dist/ui/_next/static/chunks/cbd29ba61906e19f.js +1 -0
  416. package/dist/ui/_next/static/chunks/ccf1e618faea3d02.js +148 -0
  417. package/dist/ui/_next/static/chunks/cd91712ea04f43ba.js +13 -0
  418. package/dist/ui/_next/static/chunks/cdd85dc039d450f3.js +1 -0
  419. package/dist/ui/_next/static/chunks/ce663833f73b1ec5.js +1 -0
  420. package/dist/ui/_next/static/chunks/ceda8fcac21d8e70.js +1 -0
  421. package/dist/ui/_next/static/chunks/cf565875b66f8cad.js +1 -0
  422. package/dist/ui/_next/static/chunks/d127ded39a594c84.js +1 -0
  423. package/dist/ui/_next/static/chunks/d34124988f5b8f6d.js +1 -0
  424. package/dist/ui/_next/static/chunks/d36807add3e11d59.js +60 -0
  425. package/dist/ui/_next/static/chunks/d3f2e4603faebed8.js +1 -0
  426. package/dist/ui/_next/static/chunks/d414302c23047b9b.js +1 -0
  427. package/dist/ui/_next/static/chunks/d42adc0237103e65.js +1 -0
  428. package/dist/ui/_next/static/chunks/d4a06b205f0a641b.js +1 -0
  429. package/dist/ui/_next/static/chunks/d4e5289ace3acef0.js +1 -0
  430. package/dist/ui/_next/static/chunks/d53b4725d3328076.js +1 -0
  431. package/dist/ui/_next/static/chunks/d5bd04634f922925.js +1 -0
  432. package/dist/ui/_next/static/chunks/d642c9229900dc48.js +1 -0
  433. package/dist/ui/_next/static/chunks/d6651bb78c09d144.js +5 -0
  434. package/dist/ui/_next/static/chunks/d7276c56aa62ceed.js +1 -0
  435. package/dist/ui/_next/static/chunks/d85cd9cda46f2d1b.js +1 -0
  436. package/dist/ui/_next/static/chunks/d8978f4b468bbad4.js +1 -0
  437. package/dist/ui/_next/static/chunks/d8fb9668a83c0603.js +1 -0
  438. package/dist/ui/_next/static/chunks/d95c62472fc41baf.js +1 -0
  439. package/dist/ui/_next/static/chunks/da13170b983f7ebf.js +1 -0
  440. package/dist/ui/_next/static/chunks/dae86e12c7741e6c.js +19 -0
  441. package/dist/ui/_next/static/chunks/db44023a744297d1.js +1 -0
  442. package/dist/ui/_next/static/chunks/dbe7840308be36b8.js +1 -0
  443. package/dist/ui/_next/static/chunks/dc0a4df8f7080b29.js +1 -0
  444. package/dist/ui/_next/static/chunks/dc4a6f59be156511.js +1 -0
  445. package/dist/ui/_next/static/chunks/dcda5e7b57ed88e0.js +1 -0
  446. package/dist/ui/_next/static/chunks/de9ff8c97f75b947.js +1 -0
  447. package/dist/ui/_next/static/chunks/df6abcdb3eb0b236.js +1 -0
  448. package/dist/ui/_next/static/chunks/df8a0933ca385a63.js +1 -0
  449. package/dist/ui/_next/static/chunks/dff6434c44c2dfaa.js +1 -0
  450. package/dist/ui/_next/static/chunks/e037ec5e62b2bdc3.js +1 -0
  451. package/dist/ui/_next/static/chunks/e212cf1f5a503899.js +1 -0
  452. package/dist/ui/_next/static/chunks/e2bfdac0a2305cc1.js +1 -0
  453. package/dist/ui/_next/static/chunks/e2dce648399ad4d4.js +1 -0
  454. package/dist/ui/_next/static/chunks/e318291bb8d74aee.js +1 -0
  455. package/dist/ui/_next/static/chunks/e33e40c2e7ab7629.js +1 -0
  456. package/dist/ui/_next/static/chunks/e410dfbcccddc478.js +1 -0
  457. package/dist/ui/_next/static/chunks/e411d58b52ab342b.js +1 -0
  458. package/dist/ui/_next/static/chunks/e57f7ffd0803a922.js +117 -0
  459. package/dist/ui/_next/static/chunks/e6b56ceb762e84c4.js +1 -0
  460. package/dist/ui/_next/static/chunks/e6d9a6ca68017eef.js +1 -0
  461. package/dist/ui/_next/static/chunks/e6ec2663605cf5a7.js +29 -0
  462. package/dist/ui/_next/static/chunks/e834330589be0639.js +1 -0
  463. package/dist/ui/_next/static/chunks/e8f662ba8bc76802.js +1 -0
  464. package/dist/ui/_next/static/chunks/e9e8e72d7ff45812.js +1 -0
  465. package/dist/ui/_next/static/chunks/eadd25eb66104a63.js +1 -0
  466. package/dist/ui/_next/static/chunks/ec3a7a7f48a8aca9.js +1 -0
  467. package/dist/ui/_next/static/chunks/ed62e349fb1ce14c.js +1 -0
  468. package/dist/ui/_next/static/chunks/ed6caa113f5769a5.js +1 -0
  469. package/dist/ui/_next/static/chunks/f02ac565bb5bc450.js +1 -0
  470. package/dist/ui/_next/static/chunks/f1a7a173e3da4ff4.js +1 -0
  471. package/dist/ui/_next/static/chunks/f268093817d3b260.js +1 -0
  472. package/dist/ui/_next/static/chunks/f6f811ccfe79e963.js +1 -0
  473. package/dist/ui/_next/static/chunks/f8955634331fd956.js +1 -0
  474. package/dist/ui/_next/static/chunks/f8c965a996875e30.js +56 -0
  475. package/dist/ui/_next/static/chunks/f9bb8411d37b06d7.js +1 -0
  476. package/dist/ui/_next/static/chunks/f9d4f77d8c130497.js +1 -0
  477. package/dist/ui/_next/static/chunks/fba113a516eb485f.js +1 -0
  478. package/dist/ui/_next/static/chunks/fc069e49a569d83c.js +1 -0
  479. package/dist/ui/_next/static/chunks/fc245016ffebdde3.js +1 -0
  480. package/dist/ui/_next/static/chunks/fc2d01d74dcf3921.js +1 -0
  481. package/dist/ui/_next/static/chunks/fe2ad0e00041a87d.js +1 -0
  482. package/dist/ui/_next/static/chunks/fe571740188dea3a.js +1 -0
  483. package/dist/ui/_next/static/chunks/turbopack-a5ce95b200d58f7a.js +4 -0
  484. package/dist/ui/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  485. package/dist/ui/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  486. package/dist/ui/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  487. package/dist/ui/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  488. package/dist/ui/_next/static/media/KaTeX_AMS-Regular.892f691b.ttf +0 -0
  489. package/dist/ui/_next/static/media/KaTeX_AMS-Regular.c30af439.woff2 +0 -0
  490. package/dist/ui/_next/static/media/KaTeX_AMS-Regular.e6a3cada.woff +0 -0
  491. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.2f97783e.woff +0 -0
  492. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.a36b8125.ttf +0 -0
  493. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Bold.db991531.woff2 +0 -0
  494. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.2b13f013.woff +0 -0
  495. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.7c50032c.ttf +0 -0
  496. package/dist/ui/_next/static/media/KaTeX_Caligraphic-Regular.c20eee08.woff2 +0 -0
  497. package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.5fa2f5e4.woff +0 -0
  498. package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.d514bd28.woff2 +0 -0
  499. package/dist/ui/_next/static/media/KaTeX_Fraktur-Bold.e311399d.ttf +0 -0
  500. package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.18139813.woff +0 -0
  501. package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.2a73476d.ttf +0 -0
  502. package/dist/ui/_next/static/media/KaTeX_Fraktur-Regular.5d62e468.woff2 +0 -0
  503. package/dist/ui/_next/static/media/KaTeX_Main-Bold.6d137c77.ttf +0 -0
  504. package/dist/ui/_next/static/media/KaTeX_Main-Bold.c24b5ba7.woff +0 -0
  505. package/dist/ui/_next/static/media/KaTeX_Main-Bold.f4e2828d.woff2 +0 -0
  506. package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.079b33ae.woff +0 -0
  507. package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.c003d3ec.ttf +0 -0
  508. package/dist/ui/_next/static/media/KaTeX_Main-BoldItalic.f1884480.woff2 +0 -0
  509. package/dist/ui/_next/static/media/KaTeX_Main-Italic.26a3619b.woff +0 -0
  510. package/dist/ui/_next/static/media/KaTeX_Main-Italic.61da3e93.ttf +0 -0
  511. package/dist/ui/_next/static/media/KaTeX_Main-Italic.a3746929.woff2 +0 -0
  512. package/dist/ui/_next/static/media/KaTeX_Main-Regular.12644167.woff2 +0 -0
  513. package/dist/ui/_next/static/media/KaTeX_Main-Regular.876b86ad.ttf +0 -0
  514. package/dist/ui/_next/static/media/KaTeX_Main-Regular.d511f158.woff +0 -0
  515. package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.5c6a6a93.woff2 +0 -0
  516. package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.ad4dffd5.woff +0 -0
  517. package/dist/ui/_next/static/media/KaTeX_Math-BoldItalic.e73b3bf0.ttf +0 -0
  518. package/dist/ui/_next/static/media/KaTeX_Math-Italic.03974bc4.ttf +0 -0
  519. package/dist/ui/_next/static/media/KaTeX_Math-Italic.1cd2c488.woff +0 -0
  520. package/dist/ui/_next/static/media/KaTeX_Math-Italic.d8564edb.woff2 +0 -0
  521. package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.a03f9428.woff2 +0 -0
  522. package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.d4608ed5.ttf +0 -0
  523. package/dist/ui/_next/static/media/KaTeX_SansSerif-Bold.ff51ef5c.woff +0 -0
  524. package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.8ed740d6.woff +0 -0
  525. package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.9245afda.woff2 +0 -0
  526. package/dist/ui/_next/static/media/KaTeX_SansSerif-Italic.c0b22b1e.ttf +0 -0
  527. package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.128c9bc2.woff2 +0 -0
  528. package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.156dbd4e.ttf +0 -0
  529. package/dist/ui/_next/static/media/KaTeX_SansSerif-Regular.ee7b0a16.woff +0 -0
  530. package/dist/ui/_next/static/media/KaTeX_Script-Regular.00d9a561.ttf +0 -0
  531. package/dist/ui/_next/static/media/KaTeX_Script-Regular.186c7155.woff2 +0 -0
  532. package/dist/ui/_next/static/media/KaTeX_Script-Regular.afc2fd5a.woff +0 -0
  533. package/dist/ui/_next/static/media/KaTeX_Size1-Regular.4450ef36.woff2 +0 -0
  534. package/dist/ui/_next/static/media/KaTeX_Size1-Regular.9aaff96b.ttf +0 -0
  535. package/dist/ui/_next/static/media/KaTeX_Size1-Regular.e5bf4c74.woff +0 -0
  536. package/dist/ui/_next/static/media/KaTeX_Size2-Regular.6a97527b.woff2 +0 -0
  537. package/dist/ui/_next/static/media/KaTeX_Size2-Regular.8fbd32af.woff +0 -0
  538. package/dist/ui/_next/static/media/KaTeX_Size2-Regular.f11810ed.ttf +0 -0
  539. package/dist/ui/_next/static/media/KaTeX_Size3-Regular.45ae8eba.woff +0 -0
  540. package/dist/ui/_next/static/media/KaTeX_Size3-Regular.54b7ce9d.woff2 +0 -0
  541. package/dist/ui/_next/static/media/KaTeX_Size3-Regular.9812ade2.ttf +0 -0
  542. package/dist/ui/_next/static/media/KaTeX_Size4-Regular.44a4d487.ttf +0 -0
  543. package/dist/ui/_next/static/media/KaTeX_Size4-Regular.927fc5b9.woff2 +0 -0
  544. package/dist/ui/_next/static/media/KaTeX_Size4-Regular.b211e3d3.woff +0 -0
  545. package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.68b6c3a9.woff +0 -0
  546. package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.a1a7ff52.ttf +0 -0
  547. package/dist/ui/_next/static/media/KaTeX_Typewriter-Regular.ff99d643.woff2 +0 -0
  548. package/dist/ui/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  549. package/dist/ui/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  550. package/dist/ui/_next/static/media/favicon.0b3bf435.ico +0 -0
  551. package/dist/ui/_not-found/__next._full.txt +18 -0
  552. package/dist/ui/_not-found/__next._head.txt +6 -0
  553. package/dist/ui/_not-found/__next._index.txt +9 -0
  554. package/dist/ui/_not-found/__next._not-found.__PAGE__.txt +5 -0
  555. package/dist/ui/_not-found/__next._not-found.txt +4 -0
  556. package/dist/ui/_not-found/__next._tree.txt +3 -0
  557. package/dist/ui/_not-found/index.html +1 -0
  558. package/dist/ui/_not-found/index.txt +18 -0
  559. package/dist/ui/favicon.ico +0 -0
  560. package/dist/ui/file.svg +1 -0
  561. package/dist/ui/globe.svg +1 -0
  562. package/dist/ui/index.html +1 -0
  563. package/dist/ui/index.txt +25 -0
  564. package/dist/ui/next.svg +1 -0
  565. package/dist/ui/vercel.svg +1 -0
  566. package/dist/ui/window.svg +1 -0
  567. package/dist/utils/chat-model.d.ts +11 -0
  568. package/dist/utils/chat-model.js +37 -0
  569. package/dist/utils/diff-parser.d.ts +20 -0
  570. package/dist/utils/diff-parser.js +100 -0
  571. package/dist/utils/proxy-manager.d.ts +18 -0
  572. package/dist/utils/proxy-manager.js +42 -0
  573. package/dist/utils/remote-proxy.d.ts +40 -0
  574. package/dist/utils/remote-proxy.js +145 -0
  575. package/dist/utils/worktree-paths.d.ts +13 -0
  576. package/dist/utils/worktree-paths.js +64 -0
  577. package/dist/virtual-ws-adapter.d.ts +26 -0
  578. package/dist/virtual-ws-adapter.js +54 -0
  579. package/package.json +19 -0
@@ -0,0 +1,1425 @@
1
+ /**
2
+ * ChatSessionManager — lightweight AI chat session manager using Vercel AI SDK.
3
+ *
4
+ * No child processes, no tool tracking, no permission modes.
5
+ * Streams responses from DeepSeek via `streamText` and broadcasts
6
+ * JSON Patches over WebSocket (same architecture as AgentSessionManager).
7
+ */
8
+ import { randomUUID } from "crypto";
9
+ import { streamText, tool, stepCountIs } from "ai";
10
+ import { z } from "zod";
11
+ import { resolveChatModel } from "./utils/chat-model.js";
12
+ import WsWebSocket from "ws";
13
+ import { ConversationPatch } from "./conversation-patch.js";
14
+ import { resolveWorktreePath } from "./utils/worktree-paths.js";
15
+ import { proxyToRemote, proxyToRemoteAuto } from "./utils/remote-proxy.js";
16
+ import { VirtualWsAdapter } from "./virtual-ws-adapter.js";
17
+ // ============ Helpers ============
18
+ function stripAnsi(text) {
19
+ return text.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><~]/g, "");
20
+ }
21
+ function extractLogText(logs, tailLines) {
22
+ const textLogs = logs
23
+ .filter((l) => l.type !== "finished")
24
+ .map((l) => l.data);
25
+ const joined = textLogs.join("");
26
+ const lines = joined.split("\n");
27
+ return stripAnsi(lines.slice(-tailLines).join("\n"));
28
+ }
29
+ // ============ Manager ============
30
+ export class ChatSessionManager {
31
+ /** sessionId → ChatSession */
32
+ sessions = new Map();
33
+ /** projectId:branch → sessionId (one session per project+branch) */
34
+ sessionIndex = new Map();
35
+ /** terminalId → watcher state for active terminal output watchers */
36
+ terminalWatchers = new Map();
37
+ /** sessionId → queued messages waiting to be sent after current stream finishes */
38
+ messageQueue = new Map();
39
+ storage;
40
+ eventBus = null;
41
+ processManager;
42
+ agentSessionManager;
43
+ remoteSessionMap;
44
+ remoteExecutorMap;
45
+ remotePatchCache;
46
+ reverseConnectManager = null;
47
+ browserManager = null;
48
+ /** Pending browser commands waiting for iframe response: commandId → resolve */
49
+ pendingBrowserCommands = new Map();
50
+ constructor(storage, processManager, agentSessionManager, remoteSessionMap, remoteExecutorMap, remotePatchCache, reverseConnectManager, browserManager) {
51
+ this.storage = storage;
52
+ this.processManager = processManager;
53
+ this.agentSessionManager = agentSessionManager;
54
+ this.remoteSessionMap = remoteSessionMap;
55
+ this.remoteExecutorMap = remoteExecutorMap;
56
+ this.remotePatchCache = remotePatchCache;
57
+ this.reverseConnectManager = reverseConnectManager ?? null;
58
+ this.browserManager = browserManager ?? null;
59
+ }
60
+ setEventBus(eventBus) {
61
+ this.eventBus = eventBus;
62
+ this.setupEventListeners();
63
+ }
64
+ setEventListening(sessionId, enabled) {
65
+ const session = this.sessions.get(sessionId);
66
+ if (!session)
67
+ return false;
68
+ session.eventListeningEnabled = enabled;
69
+ return true;
70
+ }
71
+ getEventListening(sessionId) {
72
+ const session = this.sessions.get(sessionId);
73
+ return session?.eventListeningEnabled ?? false;
74
+ }
75
+ setupEventListeners() {
76
+ if (!this.eventBus)
77
+ return;
78
+ this.eventBus.subscribe((event) => {
79
+ if (event.type === "executor:stopped") {
80
+ this.handleExecutorFinished(event);
81
+ }
82
+ });
83
+ }
84
+ handleExecutorFinished(event) {
85
+ try {
86
+ // Look up executor metadata
87
+ const executor = this.storage.executors.getById(event.executorId);
88
+ if (!executor)
89
+ return;
90
+ // Look up group to get branch
91
+ const group = this.storage.executorGroups.getById(executor.group_id);
92
+ if (!group)
93
+ return;
94
+ const branch = group.branch || null;
95
+ // Find a chat session for this project+branch that has event listening enabled
96
+ const key = `${event.projectId}:${branch ?? ""}`;
97
+ const sessionId = this.sessionIndex.get(key);
98
+ if (!sessionId)
99
+ return;
100
+ const session = this.sessions.get(sessionId);
101
+ if (!session || !session.eventListeningEnabled)
102
+ return;
103
+ // Get tail output from process manager
104
+ const logs = this.processManager.getLogs(event.processId);
105
+ const outputLogs = logs.filter((l) => l.type === "pty" || l.type === "stdout" || l.type === "stderr");
106
+ const tail = outputLogs.slice(-100);
107
+ let raw = tail.map((l) => l.data).join("");
108
+ raw = raw.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
109
+ const tailOutput = raw.length > 10000 ? raw.slice(-10000) : raw;
110
+ const exitStatus = event.exitCode === 0 ? "success" : "failed";
111
+ const message = [
112
+ `[Executor Event: Process Finished]`,
113
+ `Executor: "${executor.name}"`,
114
+ `Command: ${executor.command}`,
115
+ `Exit Code: ${event.exitCode} (${exitStatus})`,
116
+ ``,
117
+ `Last output:`,
118
+ `---`,
119
+ tailOutput || "(no output captured)",
120
+ `---`,
121
+ ``,
122
+ `Summarize in 1-2 sentences.`,
123
+ ].join("\n");
124
+ // Send as a user message into the main chat — triggers DeepSeek AI response
125
+ this.enqueueOrSend(sessionId, message);
126
+ }
127
+ catch (error) {
128
+ console.error(`[ChatSession] handleExecutorFinished error:`, error);
129
+ }
130
+ }
131
+ handleBrowserError(sessionId, error) {
132
+ const typeLabels = {
133
+ js_error: "JS Error",
134
+ console_error: "Console Error",
135
+ network_error: "Network Error",
136
+ crash: "Browser Crash",
137
+ };
138
+ const label = typeLabels[error.type] ?? error.type;
139
+ const parts = [
140
+ `[Browser Event: ${label}]`,
141
+ error.url ? `URL: ${error.url}` : null,
142
+ `Error: ${error.message}`,
143
+ error.stack ? `Stack: ${error.stack}` : null,
144
+ ``,
145
+ `Summarize in 1-2 sentences.`,
146
+ ].filter(Boolean);
147
+ this.enqueueOrSend(sessionId, parts.join("\n"));
148
+ }
149
+ findRemoteSessionForProject(projectId, branch) {
150
+ // Session IDs use format: remote-{serverId}-{projectId}-{remoteSessionId}
151
+ // Match any session that contains the projectId segment
152
+ const projectSegment = `-${projectId}-`;
153
+ let fallback = null;
154
+ for (const [key, info] of this.remoteSessionMap) {
155
+ if (key.startsWith("remote-") && key.includes(projectSegment)) {
156
+ // Exact branch match
157
+ if (info.branch === (branch ?? null)) {
158
+ return { localSessionId: key, info };
159
+ }
160
+ // Keep first match as fallback in case no branch match
161
+ if (!fallback) {
162
+ fallback = { localSessionId: key, info };
163
+ }
164
+ }
165
+ }
166
+ if (fallback) {
167
+ console.log(`[ChatSession] findRemoteSessionForProject: no exact branch match for branch=${branch ?? "null"}, using fallback session=${fallback.localSessionId} (branch=${fallback.info.branch ?? "null"})`);
168
+ }
169
+ return fallback;
170
+ }
171
+ /**
172
+ * Extract AgentMessage[] from the local remotePatchCache for a given session.
173
+ * Parses cached WS messages and collects ENTRY patch values into an ordered array.
174
+ */
175
+ extractMessagesFromCache(sessionId) {
176
+ const cacheEntry = this.remotePatchCache.get(sessionId);
177
+ console.log(`[ChatSession] extractMessagesFromCache: sessionId=${sessionId}, cacheExists=${!!cacheEntry}, cachedMsgCount=${cacheEntry?.messages.length ?? 0}, patchCount=${cacheEntry?.patchCount ?? 0}, finished=${cacheEntry?.finished ?? "N/A"}, remoteWsState=${cacheEntry?.remoteWs?.readyState ?? "null"}, subscribers=${cacheEntry?.subscribers.size ?? 0}`);
178
+ if (!cacheEntry || cacheEntry.messages.length === 0)
179
+ return [];
180
+ const result = [];
181
+ // Track patch types for diagnostics
182
+ let entryCount = 0;
183
+ let statusCount = 0;
184
+ let readyCount = 0;
185
+ let finishedCount = 0;
186
+ let otherCount = 0;
187
+ let nonJsonPatchCount = 0;
188
+ let parseErrorCount = 0;
189
+ for (const raw of cacheEntry.messages) {
190
+ try {
191
+ const parsed = JSON.parse(raw);
192
+ if (!parsed.JsonPatch || !Array.isArray(parsed.JsonPatch)) {
193
+ nonJsonPatchCount++;
194
+ continue;
195
+ }
196
+ for (const op of parsed.JsonPatch) {
197
+ if ((op.op === "add" || op.op === "replace") && op.value?.type === "ENTRY" && op.value.content) {
198
+ const match = op.path?.match(/^\/entries\/(\d+)$/);
199
+ if (match) {
200
+ const index = parseInt(match[1], 10);
201
+ result[index] = op.value.content;
202
+ entryCount++;
203
+ }
204
+ }
205
+ else if (op.path === "/status") {
206
+ statusCount++;
207
+ }
208
+ else if (op.value?.type === "READY") {
209
+ readyCount++;
210
+ }
211
+ else if (op.value?.type === "FINISHED") {
212
+ finishedCount++;
213
+ }
214
+ else {
215
+ otherCount++;
216
+ }
217
+ }
218
+ }
219
+ catch {
220
+ parseErrorCount++;
221
+ }
222
+ }
223
+ const filtered = result.filter(Boolean);
224
+ console.log(`[ChatSession] extractMessagesFromCache: extracted ${filtered.length} messages from ${cacheEntry.messages.length} cached raw messages. Patch breakdown: entry=${entryCount}, status=${statusCount}, ready=${readyCount}, finished=${finishedCount}, other=${otherCount}, nonJsonPatch=${nonJsonPatchCount}, parseErrors=${parseErrorCount}`);
225
+ return filtered;
226
+ }
227
+ summarizeMessages(messages) {
228
+ return messages.map((msg) => {
229
+ switch (msg.type) {
230
+ case "user":
231
+ return { type: "user", content: msg.content };
232
+ case "assistant":
233
+ return { type: "assistant", content: msg.content };
234
+ case "tool_use": {
235
+ const inputStr = typeof msg.input === "string"
236
+ ? msg.input
237
+ : JSON.stringify(msg.input);
238
+ return {
239
+ type: "tool_use",
240
+ tool: msg.tool,
241
+ input: inputStr.length > 500 ? inputStr.substring(0, 500) + "..." : inputStr,
242
+ };
243
+ }
244
+ case "tool_result":
245
+ return {
246
+ type: "tool_result",
247
+ tool: msg.tool,
248
+ output: msg.output.length > 500 ? msg.output.substring(0, 500) + "..." : msg.output,
249
+ };
250
+ case "error":
251
+ return { type: "error", message: msg.message };
252
+ case "system":
253
+ return { type: "system", content: msg.content };
254
+ case "thinking":
255
+ return { type: "thinking", content: msg.content };
256
+ default:
257
+ return { type: msg.type };
258
+ }
259
+ });
260
+ }
261
+ // ---- Terminal watcher ----
262
+ startTerminalWatcher(sessionId, terminalId) {
263
+ // Clean up any existing watcher for this terminal
264
+ this.stopTerminalWatcher(terminalId);
265
+ const DEBOUNCE_MS = 3000;
266
+ const IDLE_TIMEOUT_MS = 60000;
267
+ const MAX_LINES = 100;
268
+ const MAX_BYTES = 8192;
269
+ // Mutable state shared between subscriber callback and flush — kept as a single
270
+ // object so the terminalWatchers map always has a live reference to current timers.
271
+ const state = {
272
+ debounceTimer: null,
273
+ idleTimer: setTimeout(() => this.stopTerminalWatcher(terminalId), IDLE_TIMEOUT_MS),
274
+ outputBuffer: "",
275
+ };
276
+ const flush = () => {
277
+ if (!state.outputBuffer.trim()) {
278
+ console.log(`[ChatSession] terminal watcher flush: empty buffer, skipping (terminal=${terminalId})`);
279
+ return;
280
+ }
281
+ console.log(`[ChatSession] terminal watcher flush: ${state.outputBuffer.length} bytes (terminal=${terminalId})`);
282
+ // Strip ANSI codes
283
+ let output = state.outputBuffer.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><~]/g, "");
284
+ // Cap at MAX_LINES / MAX_BYTES
285
+ const lines = output.split("\n");
286
+ if (lines.length > MAX_LINES) {
287
+ output = lines.slice(-MAX_LINES).join("\n");
288
+ }
289
+ if (output.length > MAX_BYTES) {
290
+ output = output.slice(-MAX_BYTES);
291
+ }
292
+ const message = [
293
+ `[Terminal Event: Output]`,
294
+ `Terminal: ${terminalId}`,
295
+ ``,
296
+ `Output:`,
297
+ `---`,
298
+ output,
299
+ `---`,
300
+ ``,
301
+ `Summarize what happened in 1-2 sentences.`,
302
+ ].join("\n");
303
+ // Clean up watcher before sending (prevents duplicate flushes)
304
+ this.stopTerminalWatcher(terminalId);
305
+ // Inject into chat session (queued if a stream is already active)
306
+ this.enqueueOrSend(sessionId, message);
307
+ };
308
+ const unsubscribe = this.processManager.subscribe(terminalId, (msg) => {
309
+ console.log(`[ChatSession] watcher subscriber fired: terminal=${terminalId} type=${msg.type} bufferLen=${state.outputBuffer.length}`);
310
+ if (msg.type === "finished") {
311
+ // Terminal exited — flush what we have
312
+ if (state.debounceTimer)
313
+ clearTimeout(state.debounceTimer);
314
+ state.debounceTimer = null;
315
+ flush();
316
+ return;
317
+ }
318
+ if (msg.type === "pty" || msg.type === "stdout" || msg.type === "stderr") {
319
+ state.outputBuffer += msg.data;
320
+ // Reset debounce timer
321
+ if (state.debounceTimer)
322
+ clearTimeout(state.debounceTimer);
323
+ state.debounceTimer = setTimeout(() => {
324
+ console.log(`[ChatSession] debounce timer fired for terminal=${terminalId}, bufferLen=${state.outputBuffer.length}`);
325
+ flush();
326
+ }, DEBOUNCE_MS);
327
+ // Reset idle timer
328
+ clearTimeout(state.idleTimer);
329
+ state.idleTimer = setTimeout(() => this.stopTerminalWatcher(terminalId), IDLE_TIMEOUT_MS);
330
+ }
331
+ });
332
+ if (!unsubscribe) {
333
+ console.log(`[ChatSession] Cannot watch terminal ${terminalId} — not found in processManager`);
334
+ clearTimeout(state.idleTimer);
335
+ return;
336
+ }
337
+ this.terminalWatchers.set(terminalId, {
338
+ unsubscribe,
339
+ state, // live reference — timer IDs stay current
340
+ sessionId,
341
+ });
342
+ console.log(`[ChatSession] Started terminal watcher for terminal=${terminalId} session=${sessionId}`);
343
+ }
344
+ stopTerminalWatcher(terminalId) {
345
+ const watcher = this.terminalWatchers.get(terminalId);
346
+ if (!watcher)
347
+ return;
348
+ watcher.unsubscribe();
349
+ if (watcher.state.debounceTimer)
350
+ clearTimeout(watcher.state.debounceTimer);
351
+ clearTimeout(watcher.state.idleTimer);
352
+ this.terminalWatchers.delete(terminalId);
353
+ console.log(`[ChatSession] Stopped terminal watcher for terminal=${terminalId}`);
354
+ }
355
+ /**
356
+ * Start a watcher for a remote terminal by opening a virtual channel over
357
+ * the existing reverse-connect WebSocket (or a direct WebSocket as fallback).
358
+ * Mirrors the local startTerminalWatcher() — accumulates output with
359
+ * debounce, flushes on "finished" or idle timeout, and feeds the result
360
+ * into enqueueOrSend().
361
+ */
362
+ startRemoteTerminalWatcher(sessionId, terminalId, remoteInfo) {
363
+ // Clean up any existing watcher for this terminal
364
+ this.stopTerminalWatcher(terminalId);
365
+ const DEBOUNCE_MS = 3000;
366
+ const IDLE_TIMEOUT_MS = 60000;
367
+ const MAX_LINES = 100;
368
+ const MAX_BYTES = 8192;
369
+ const state = {
370
+ debounceTimer: null,
371
+ idleTimer: setTimeout(() => this.stopTerminalWatcher(terminalId), IDLE_TIMEOUT_MS),
372
+ outputBuffer: "",
373
+ };
374
+ const flush = () => {
375
+ const buffered = state.outputBuffer;
376
+ state.outputBuffer = ""; // Clear immediately to prevent double-flush
377
+ if (!buffered.trim()) {
378
+ console.log(`[ChatSession] remote terminal watcher flush: empty buffer, skipping (terminal=${terminalId})`);
379
+ return;
380
+ }
381
+ console.log(`[ChatSession] remote terminal watcher flush: ${buffered.length} bytes (terminal=${terminalId})`);
382
+ // Strip ANSI codes
383
+ let output = buffered.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><~]/g, "");
384
+ const lines = output.split("\n");
385
+ if (lines.length > MAX_LINES) {
386
+ output = lines.slice(-MAX_LINES).join("\n");
387
+ }
388
+ if (output.length > MAX_BYTES) {
389
+ output = output.slice(-MAX_BYTES);
390
+ }
391
+ const message = [
392
+ `[Terminal Event: Output]`,
393
+ `Terminal: ${terminalId}`,
394
+ ``,
395
+ `Output:`,
396
+ `---`,
397
+ output,
398
+ `---`,
399
+ ``,
400
+ `Summarize what happened in 1-2 sentences.`,
401
+ ].join("\n");
402
+ // Clean up watcher before sending (prevents duplicate flushes)
403
+ this.stopTerminalWatcher(terminalId);
404
+ // Inject into chat session
405
+ this.enqueueOrSend(sessionId, message);
406
+ };
407
+ // Open a virtual channel over the existing reverse-connect WebSocket,
408
+ // or fall back to a direct WebSocket connection.
409
+ let remoteWs;
410
+ const useVirtual = this.reverseConnectManager?.isConnected(remoteInfo.remoteServerId);
411
+ if (useVirtual && this.reverseConnectManager) {
412
+ const channelId = randomUUID();
413
+ const wsPath = `/api/executor-processes/${remoteInfo.remoteProcessId}/logs`;
414
+ const wsQuery = `apiKey=${encodeURIComponent(remoteInfo.remoteApiKey)}`;
415
+ const adapter = new VirtualWsAdapter((data) => this.reverseConnectManager.sendChannelData(remoteInfo.remoteServerId, channelId, data), () => this.reverseConnectManager.closeChannel(remoteInfo.remoteServerId, channelId));
416
+ this.reverseConnectManager.setChannelAdapter(remoteInfo.remoteServerId, channelId, adapter);
417
+ this.reverseConnectManager.openVirtualChannel(remoteInfo.remoteServerId, channelId, wsPath, wsQuery);
418
+ remoteWs = adapter;
419
+ console.log(`[ChatSession] Remote terminal watcher: virtual channel opened for ${remoteInfo.remoteProcessId}`);
420
+ setTimeout(() => adapter.emit("open"), 0);
421
+ }
422
+ else {
423
+ const cleanRemoteUrl = remoteInfo.remoteUrl.replace(/\/+$/, "");
424
+ const wsProtocol = cleanRemoteUrl.startsWith("https") ? "wss" : "ws";
425
+ const wsUrl = cleanRemoteUrl.replace(/^https?/, wsProtocol);
426
+ const remoteWsUrl = `${wsUrl}/api/executor-processes/${remoteInfo.remoteProcessId}/logs?apiKey=${encodeURIComponent(remoteInfo.remoteApiKey)}`;
427
+ console.log(`[ChatSession] Remote terminal watcher: connecting to ${remoteWsUrl.replace(remoteInfo.remoteApiKey, "***")}`);
428
+ remoteWs = new WsWebSocket(remoteWsUrl);
429
+ }
430
+ const closeWs = () => {
431
+ try {
432
+ remoteWs.close();
433
+ }
434
+ catch {
435
+ // already closed
436
+ }
437
+ };
438
+ remoteWs.on("message", (data) => {
439
+ let msg;
440
+ try {
441
+ msg = JSON.parse(data.toString());
442
+ }
443
+ catch {
444
+ return;
445
+ }
446
+ // Skip non-log messages (init, error, etc.)
447
+ if (msg.type !== "pty" && msg.type !== "stdout" && msg.type !== "stderr" && msg.type !== "finished")
448
+ return;
449
+ if (msg.type === "finished") {
450
+ if (state.debounceTimer)
451
+ clearTimeout(state.debounceTimer);
452
+ state.debounceTimer = null;
453
+ flush();
454
+ closeWs();
455
+ return;
456
+ }
457
+ if (msg.type === "pty" || msg.type === "stdout" || msg.type === "stderr") {
458
+ state.outputBuffer += msg.data ?? "";
459
+ // Reset debounce timer
460
+ if (state.debounceTimer)
461
+ clearTimeout(state.debounceTimer);
462
+ state.debounceTimer = setTimeout(() => {
463
+ console.log(`[ChatSession] remote debounce timer fired for terminal=${terminalId}, bufferLen=${state.outputBuffer.length}`);
464
+ flush();
465
+ closeWs();
466
+ }, DEBOUNCE_MS);
467
+ // Reset idle timer
468
+ clearTimeout(state.idleTimer);
469
+ state.idleTimer = setTimeout(() => this.stopTerminalWatcher(terminalId), IDLE_TIMEOUT_MS);
470
+ }
471
+ });
472
+ remoteWs.on("close", () => {
473
+ console.log(`[ChatSession] Remote terminal watcher: connection closed for terminal=${terminalId}`);
474
+ // If we still have buffered output, flush it
475
+ if (state.outputBuffer.trim() && this.terminalWatchers.has(terminalId)) {
476
+ if (state.debounceTimer)
477
+ clearTimeout(state.debounceTimer);
478
+ state.debounceTimer = null;
479
+ flush();
480
+ }
481
+ });
482
+ remoteWs.on("error", (error) => {
483
+ console.error(`[ChatSession] Remote terminal watcher error for terminal=${terminalId}:`, error);
484
+ });
485
+ const unsubscribe = () => {
486
+ closeWs();
487
+ };
488
+ this.terminalWatchers.set(terminalId, {
489
+ unsubscribe,
490
+ state,
491
+ sessionId,
492
+ });
493
+ console.log(`[ChatSession] Started remote terminal watcher for terminal=${terminalId} session=${sessionId}`);
494
+ }
495
+ // ---- Session lifecycle ----
496
+ getOrCreateSession(projectId, branch) {
497
+ const key = `${projectId}:${branch ?? ""}`;
498
+ const existing = this.sessionIndex.get(key);
499
+ if (existing && this.sessions.has(existing)) {
500
+ return existing;
501
+ }
502
+ const id = randomUUID();
503
+ const session = {
504
+ id,
505
+ projectId,
506
+ branch,
507
+ store: { patches: [], entries: [], nextIndex: 0 },
508
+ subscribers: new Set(),
509
+ status: "stopped",
510
+ abortController: null,
511
+ eventListeningEnabled: false,
512
+ };
513
+ this.sessions.set(id, session);
514
+ this.sessionIndex.set(key, id);
515
+ console.log(`[ChatSession] Created session ${id} for project=${projectId} branch=${branch}`);
516
+ return id;
517
+ }
518
+ getSession(sessionId) {
519
+ return this.sessions.get(sessionId) ?? null;
520
+ }
521
+ getMessages(sessionId) {
522
+ return this.sessions.get(sessionId)?.store.entries ?? [];
523
+ }
524
+ // ---- WebSocket subscription ----
525
+ subscribe(sessionId, ws) {
526
+ const session = this.sessions.get(sessionId);
527
+ if (!session)
528
+ return null;
529
+ // Replay all historical patches
530
+ for (const patch of session.store.patches) {
531
+ const msg = { JsonPatch: patch };
532
+ try {
533
+ ws.send(JSON.stringify(msg));
534
+ }
535
+ catch {
536
+ // Client gone
537
+ }
538
+ }
539
+ // Send current status
540
+ const statusPatch = ConversationPatch.updateStatus(session.status);
541
+ try {
542
+ ws.send(JSON.stringify({ JsonPatch: statusPatch }));
543
+ }
544
+ catch {
545
+ // Client gone
546
+ }
547
+ // Signal replay complete
548
+ try {
549
+ ws.send(JSON.stringify({ Ready: true }));
550
+ }
551
+ catch {
552
+ // Client gone
553
+ }
554
+ session.subscribers.add(ws);
555
+ return () => {
556
+ session.subscribers.delete(ws);
557
+ };
558
+ }
559
+ // ---- Tools & system prompt ----
560
+ getSystemPrompt(projectId, branch) {
561
+ return [
562
+ "You are a helpful assistant for a software development workspace.",
563
+ "You can check the status of running executors (dev servers, build processes, etc.) using the getExecutorStatus tool.",
564
+ "You can start executors using the runExecutor tool and stop them using the stopExecutor tool.",
565
+ "When the user asks about running processes, errors, build status, or dev server status, use the getExecutorStatus tool.",
566
+ "When the user asks to start, run, or launch a process, use runExecutor. When they ask to stop or kill a process, use stopExecutor.",
567
+ "You can view the coding agent's conversation history using the getAgentConversation tool.",
568
+ "When the user asks about what the agent is doing, has done, or references agent activities, use this tool.",
569
+ "When you receive an [Executor Event] message, respond in 1-2 sentences only. State what finished, whether it succeeded or failed, and the key detail (e.g. error message) if it failed. Do not repeat the output logs.",
570
+ "You can list active terminal sessions using the listTerminals tool.",
571
+ "You can send commands to a terminal using the runInTerminal tool. The command runs visibly in the user's terminal and returns immediately.",
572
+ "After sending a command, terminal output will arrive as a [Terminal Event] message once the command finishes. Wait for it before commenting on results.",
573
+ "When the user asks to run a command, check something in the terminal, or interact with a shell, use these tools.",
574
+ "If no terminals are open, suggest the user open one in the Terminal tab first.",
575
+ "You can open web pages in the preview browser using the openPreview tool.",
576
+ "You can interact with pages: clickElement, fillInput, selectOption, pressKey.",
577
+ "You can inspect pages: screenshot (returns base64 image), getPageContent (returns text/HTML), waitForElement.",
578
+ "When you receive a [Browser Event] message, respond in 1-2 sentences. State what error occurred and suggest a fix if obvious.",
579
+ `Current workspace: project=${projectId}, branch=${branch ?? "default"}.`,
580
+ ].join("\n");
581
+ }
582
+ createTools(projectId, branch, sessionId) {
583
+ const storage = this.storage;
584
+ const processManager = this.processManager;
585
+ const agentSessionManager = this.agentSessionManager;
586
+ const remoteExecutorMap = this.remoteExecutorMap;
587
+ const reverseConnectManager = this.reverseConnectManager;
588
+ const browserManager = this.browserManager;
589
+ const onBrowserError = (error) => {
590
+ if (sessionId)
591
+ this.handleBrowserError(sessionId, error);
592
+ };
593
+ /** Try iframe command first, fall back to Playwright. Returns null if iframe handled it. */
594
+ const tryIframeCommand = sessionId
595
+ ? (cmd) => this.sendBrowserCommand(sessionId, cmd)
596
+ : () => Promise.resolve(null);
597
+ return {
598
+ getAgentConversation: tool({
599
+ description: "Get the conversation history of the coding agent in the current workspace. " +
600
+ "Use this when the user asks about what the coding agent is doing, what it has done, " +
601
+ "or needs context about the agent's work. Returns recent messages from the agent session.",
602
+ inputSchema: z.object({
603
+ tailMessages: z
604
+ .number()
605
+ .min(1)
606
+ .max(50)
607
+ .default(20)
608
+ .describe("Number of recent messages to return"),
609
+ }),
610
+ execute: async ({ tailMessages }) => {
611
+ // Collect local session
612
+ let localResult = null;
613
+ let agentSession = agentSessionManager.getSessionByBranch(projectId, branch);
614
+ if (!agentSession) {
615
+ const projectSessions = agentSessionManager.getSessionsByProject(projectId);
616
+ agentSession = projectSessions.find(s => s.status === "running")
617
+ ?? projectSessions[0]
618
+ ?? null;
619
+ }
620
+ if (agentSession) {
621
+ const allMessages = agentSessionManager.getMessages(agentSession.id);
622
+ const recent = allMessages.slice(-tailMessages);
623
+ localResult = {
624
+ sessionId: agentSession.id,
625
+ status: agentSession.status,
626
+ totalMessages: allMessages.length,
627
+ messages: this.summarizeMessages(recent),
628
+ };
629
+ }
630
+ // Collect remote session
631
+ let remoteResult = null;
632
+ const remote = this.findRemoteSessionForProject(projectId, branch);
633
+ console.log(`[ChatSession] getAgentConversation: projectId=${projectId}, branch=${branch ?? "null"}, remote=${remote ? remote.localSessionId : "null"}, remoteBranch=${remote?.info.branch ?? "null"}`);
634
+ if (remote) {
635
+ try {
636
+ const result = await proxyToRemote(remote.info.remoteUrl, remote.info.remoteApiKey, "GET", `/api/agent-sessions/${remote.info.remoteSessionId}`);
637
+ console.log(`[ChatSession] getAgentConversation: remote proxy result ok=${result.ok}, status=${result.status}`);
638
+ if (result.ok) {
639
+ const data = result.data;
640
+ let allMessages = data.messages ?? [];
641
+ console.log(`[ChatSession] getAgentConversation: remote returned ${allMessages.length} messages, session.status=${data.session?.status}`);
642
+ // Fallback: if remote returned no messages, extract from local cache
643
+ if (allMessages.length === 0) {
644
+ allMessages = this.extractMessagesFromCache(remote.localSessionId);
645
+ }
646
+ // If session is running but still no messages, poll cache briefly
647
+ // to allow time for ENTRY patches to arrive via WebSocket
648
+ if (allMessages.length === 0 && data.session?.status === "running") {
649
+ const cacheState = this.remotePatchCache.get(remote.localSessionId);
650
+ console.log(`[ChatSession] getAgentConversation: 0 messages for running session, starting retry. Cache state: wsState=${cacheState?.remoteWs?.readyState ?? "null"}, cachedMsgs=${cacheState?.messages.length ?? 0}, patchCount=${cacheState?.patchCount ?? 0}, finished=${cacheState?.finished ?? "N/A"}, reconnecting=${cacheState?.reconnecting ?? "N/A"}`);
651
+ for (let attempt = 0; attempt < 3; attempt++) {
652
+ await new Promise(resolve => setTimeout(resolve, 1000));
653
+ allMessages = this.extractMessagesFromCache(remote.localSessionId);
654
+ console.log(`[ChatSession] getAgentConversation: retry attempt ${attempt + 1}/3, extracted ${allMessages.length} messages`);
655
+ if (allMessages.length > 0)
656
+ break;
657
+ }
658
+ if (allMessages.length === 0) {
659
+ const finalCache = this.remotePatchCache.get(remote.localSessionId);
660
+ console.log(`[ChatSession] getAgentConversation: all retries exhausted, still 0 messages. Final cache: wsState=${finalCache?.remoteWs?.readyState ?? "null"}, cachedMsgs=${finalCache?.messages.length ?? 0}, patchCount=${finalCache?.patchCount ?? 0}`);
661
+ }
662
+ }
663
+ const recent = allMessages.slice(-tailMessages);
664
+ remoteResult = {
665
+ sessionId: remote.localSessionId,
666
+ status: data.session?.status ?? "unknown",
667
+ totalMessages: allMessages.length,
668
+ messages: this.summarizeMessages(recent),
669
+ ...(allMessages.length === 0 && data.session?.status === "running"
670
+ ? { note: "Session just started, agent is still initializing. Try again in a few seconds." }
671
+ : {}),
672
+ };
673
+ }
674
+ else {
675
+ console.error(`[ChatSession] getAgentConversation: remote proxy failed status=${result.status}`);
676
+ // Try local cache even if remote returned non-ok status
677
+ const cachedMessages = this.extractMessagesFromCache(remote.localSessionId);
678
+ if (cachedMessages.length > 0) {
679
+ remoteResult = {
680
+ sessionId: remote.localSessionId,
681
+ status: "running",
682
+ totalMessages: cachedMessages.length,
683
+ messages: this.summarizeMessages(cachedMessages.slice(-tailMessages)),
684
+ };
685
+ }
686
+ }
687
+ }
688
+ catch (err) {
689
+ console.error(`[ChatSession] getAgentConversation: remote proxy error:`, err);
690
+ // Try local cache even if remote is unreachable
691
+ const cachedMessages = this.extractMessagesFromCache(remote.localSessionId);
692
+ if (cachedMessages.length > 0) {
693
+ remoteResult = {
694
+ sessionId: remote.localSessionId,
695
+ status: "running",
696
+ totalMessages: cachedMessages.length,
697
+ messages: this.summarizeMessages(cachedMessages.slice(-tailMessages)),
698
+ };
699
+ }
700
+ }
701
+ }
702
+ if (!localResult && !remoteResult) {
703
+ return { local: null, remote: null, message: "No coding agent session found for this workspace." };
704
+ }
705
+ return { local: localResult, remote: remoteResult };
706
+ },
707
+ }),
708
+ getExecutorStatus: tool({
709
+ description: "Get the status of all executors (dev servers, build processes, etc.) in the current workspace. " +
710
+ "Use this when the user asks about running processes, errors, build output, or dev server status.",
711
+ inputSchema: z.object({
712
+ tailLines: z
713
+ .number()
714
+ .min(1)
715
+ .max(100)
716
+ .default(20)
717
+ .describe("Number of recent output lines to include per executor"),
718
+ }),
719
+ execute: async ({ tailLines }) => {
720
+ const group = branch
721
+ ? storage.executorGroups.getByBranch(projectId, branch)
722
+ : undefined;
723
+ if (!group) {
724
+ return { executors: [], message: "No executor group found for this workspace." };
725
+ }
726
+ const executors = storage.executors.getByGroupId(group.id);
727
+ const results = executors.map((executor) => {
728
+ const processes = processManager.getProcessesByExecutorId(executor.id);
729
+ const latestProcess = processes[processes.length - 1];
730
+ return {
731
+ name: executor.name,
732
+ command: executor.command,
733
+ isRunning: latestProcess?.isRunning ?? false,
734
+ recentOutput: latestProcess
735
+ ? extractLogText(latestProcess.logs, tailLines)
736
+ : "(no process history)",
737
+ };
738
+ });
739
+ return { executors: results };
740
+ },
741
+ }),
742
+ runExecutor: tool({
743
+ description: "Start an executor (dev server, build process, etc.) by name. " +
744
+ "Use this when the user asks to start, run, or launch a process.",
745
+ inputSchema: z.object({
746
+ executorName: z
747
+ .string()
748
+ .describe("Name of the executor to start (case-insensitive match)"),
749
+ }),
750
+ execute: async ({ executorName }) => {
751
+ const group = branch
752
+ ? storage.executorGroups.getByBranch(projectId, branch)
753
+ : undefined;
754
+ if (!group) {
755
+ return { success: false, message: "No executor group found for this workspace." };
756
+ }
757
+ const executors = storage.executors.getByGroupId(group.id);
758
+ const executor = executors.find((e) => e.name.toLowerCase() === executorName.toLowerCase());
759
+ if (!executor) {
760
+ const available = executors.map((e) => e.name).join(", ");
761
+ return {
762
+ success: false,
763
+ message: `Executor "${executorName}" not found. Available: ${available || "none"}`,
764
+ };
765
+ }
766
+ // Check if already running
767
+ const processes = processManager.getProcessesByExecutorId(executor.id);
768
+ const running = processes.find((p) => p.isRunning);
769
+ if (running) {
770
+ return {
771
+ success: false,
772
+ processId: running.processId,
773
+ executorName: executor.name,
774
+ message: `Executor "${executor.name}" is already running (processId=${running.processId}).`,
775
+ };
776
+ }
777
+ // Resolve project path
778
+ const project = storage.projects.getById(projectId);
779
+ if (!project?.path) {
780
+ return { success: false, message: "No project path configured." };
781
+ }
782
+ const basePath = resolveWorktreePath(project.path, branch);
783
+ try {
784
+ const processId = processManager.start(executor, basePath);
785
+ return {
786
+ success: true,
787
+ processId,
788
+ executorName: executor.name,
789
+ command: executor.command,
790
+ message: `Started "${executor.name}" (${executor.command}).`,
791
+ };
792
+ }
793
+ catch (err) {
794
+ const msg = err instanceof Error ? err.message : "Unknown error";
795
+ return { success: false, message: `Failed to start executor: ${msg}` };
796
+ }
797
+ },
798
+ }),
799
+ stopExecutor: tool({
800
+ description: "Stop a running executor (dev server, build process, etc.) by name. " +
801
+ "Use this when the user asks to stop, kill, or terminate a process.",
802
+ inputSchema: z.object({
803
+ executorName: z
804
+ .string()
805
+ .describe("Name of the executor to stop (case-insensitive match)"),
806
+ }),
807
+ execute: async ({ executorName }) => {
808
+ const group = branch
809
+ ? storage.executorGroups.getByBranch(projectId, branch)
810
+ : undefined;
811
+ if (!group) {
812
+ return { success: false, message: "No executor group found for this workspace." };
813
+ }
814
+ const executors = storage.executors.getByGroupId(group.id);
815
+ const executor = executors.find((e) => e.name.toLowerCase() === executorName.toLowerCase());
816
+ if (!executor) {
817
+ const available = executors.map((e) => e.name).join(", ");
818
+ return {
819
+ success: false,
820
+ message: `Executor "${executorName}" not found. Available: ${available || "none"}`,
821
+ };
822
+ }
823
+ const processes = processManager.getProcessesByExecutorId(executor.id);
824
+ const running = processes.find((p) => p.isRunning);
825
+ if (!running) {
826
+ return {
827
+ success: false,
828
+ executorName: executor.name,
829
+ message: `Executor "${executor.name}" is not running.`,
830
+ };
831
+ }
832
+ const stopped = processManager.stop(running.processId);
833
+ return {
834
+ success: stopped,
835
+ executorName: executor.name,
836
+ processId: running.processId,
837
+ message: stopped
838
+ ? `Stopped "${executor.name}" (processId=${running.processId}).`
839
+ : `Failed to stop "${executor.name}".`,
840
+ };
841
+ },
842
+ }),
843
+ listTerminals: tool({
844
+ description: "List all active terminal sessions in the current workspace. " +
845
+ "Use this to discover available terminals before running commands with runInTerminal.",
846
+ inputSchema: z.object({}),
847
+ execute: async () => {
848
+ // Local terminals
849
+ const localTerminals = processManager.getTerminals(projectId).map((t) => ({
850
+ id: t.id,
851
+ name: t.name,
852
+ cwd: t.cwd,
853
+ branch: t.branch,
854
+ location: "local",
855
+ }));
856
+ // Remote terminals from remoteExecutorMap
857
+ const remoteTerminals = [];
858
+ for (const [key, info] of remoteExecutorMap.entries()) {
859
+ if (!key.startsWith("remote-terminal-"))
860
+ continue;
861
+ if (info.projectId && info.projectId !== projectId)
862
+ continue;
863
+ remoteTerminals.push({
864
+ id: key,
865
+ name: key,
866
+ branch: info.branch,
867
+ location: "remote",
868
+ });
869
+ }
870
+ const terminals = [...localTerminals, ...remoteTerminals];
871
+ if (terminals.length === 0) {
872
+ return {
873
+ terminals: [],
874
+ message: "No active terminals. The user should open a terminal in the Terminal tab first.",
875
+ };
876
+ }
877
+ return { terminals };
878
+ },
879
+ }),
880
+ runInTerminal: tool({
881
+ description: "Send a shell command to an active terminal session. The command runs visibly in the user's terminal. " +
882
+ "Returns immediately — terminal output will arrive as a [Terminal Event] message once the command finishes. " +
883
+ "Use listTerminals first to get available terminal IDs. " +
884
+ "Use this when the user asks to run a command, check something, or interact with their shell.",
885
+ inputSchema: z.object({
886
+ terminalId: z.string().describe("ID of the terminal to run the command in (from listTerminals)"),
887
+ command: z.string().describe("The shell command to execute"),
888
+ }),
889
+ execute: async ({ terminalId, command }) => {
890
+ try {
891
+ // Remote terminal — proxy to remote server (fire-and-forget)
892
+ if (terminalId.startsWith("remote-terminal-")) {
893
+ const remoteInfo = remoteExecutorMap.get(terminalId);
894
+ console.log(`[runInTerminal] terminalId=${terminalId}, remoteProcessId=${remoteInfo?.remoteProcessId}, serverId=${remoteInfo?.remoteServerId}`);
895
+ if (!remoteInfo) {
896
+ return { sent: false, message: `Remote terminal ${terminalId} not found.` };
897
+ }
898
+ const result = await proxyToRemoteAuto(remoteInfo.remoteServerId, remoteInfo.remoteUrl, remoteInfo.remoteApiKey, "POST", `/api/path/terminals/${remoteInfo.remoteProcessId}/send`, { command }, { reverseConnectManager: reverseConnectManager ?? undefined });
899
+ if (!result.ok) {
900
+ return { sent: false, message: `Remote send failed: ${JSON.stringify(result.data)}` };
901
+ }
902
+ // Start a remote terminal watcher so output flows back as a [Terminal Event]
903
+ const sessionKey = `${projectId}:${branch ?? ""}`;
904
+ const chatSessionId = this.sessionIndex.get(sessionKey);
905
+ console.log(`[runInTerminal] remote: sessionKey=${sessionKey}, chatSessionId=${chatSessionId ?? "NOT FOUND"}`);
906
+ if (chatSessionId) {
907
+ this.startRemoteTerminalWatcher(chatSessionId, terminalId, remoteInfo);
908
+ }
909
+ else {
910
+ console.log(`[runInTerminal] WARNING: No chat session found — remote terminal watcher NOT started`);
911
+ }
912
+ return { sent: true, message: "Command sent to remote terminal. Output will arrive as a [Terminal Event]." };
913
+ }
914
+ // Local terminal — send command and start watcher
915
+ processManager.sendToTerminal(terminalId, command);
916
+ console.log(`[runInTerminal] Command sent to PTY for terminal=${terminalId}`);
917
+ // Find the chat session that called this tool so we can inject the [Terminal Event] later
918
+ const sessionKey = `${projectId}:${branch ?? ""}`;
919
+ const chatSessionId = this.sessionIndex.get(sessionKey);
920
+ console.log(`[runInTerminal] sessionKey=${sessionKey}, chatSessionId=${chatSessionId ?? "NOT FOUND"}`);
921
+ if (chatSessionId) {
922
+ this.startTerminalWatcher(chatSessionId, terminalId);
923
+ }
924
+ else {
925
+ console.log(`[runInTerminal] WARNING: No chat session found — terminal watcher NOT started`);
926
+ }
927
+ return { sent: true, message: "Command sent to terminal. Output will arrive as a [Terminal Event]." };
928
+ }
929
+ catch (err) {
930
+ const msg = err instanceof Error ? err.message : "Unknown error";
931
+ return { sent: false, message: msg };
932
+ }
933
+ },
934
+ }),
935
+ openPreview: tool({
936
+ description: "Open a URL in the preview browser. " +
937
+ "Use this when the user asks to open, preview, or navigate to a web page. " +
938
+ "This opens the page in the preview iframe (preferred) or falls back to server-side Playwright.",
939
+ inputSchema: z.object({
940
+ url: z.string().describe("The URL to open (e.g. https://remote-server:3000)"),
941
+ }),
942
+ execute: async ({ url }) => {
943
+ // Prefer iframe preview — send WS message to frontend
944
+ if (sessionId) {
945
+ const session = this.sessions.get(sessionId);
946
+ if (session && session.subscribers.size > 0) {
947
+ const raw = JSON.stringify({ openPreviewFrame: { projectId, url } });
948
+ for (const ws of session.subscribers) {
949
+ try {
950
+ ws.send(raw);
951
+ }
952
+ catch { /* ignore */ }
953
+ }
954
+ return { success: true, title: "Preview opened", url };
955
+ }
956
+ }
957
+ // Fallback to Playwright (no frontend connected)
958
+ if (!browserManager) {
959
+ return { success: false, message: "Browser preview not available." };
960
+ }
961
+ try {
962
+ let session = browserManager.getSession(projectId);
963
+ if (!session) {
964
+ session = await browserManager.startSession(projectId, branch, onBrowserError);
965
+ }
966
+ const result = await browserManager.navigate(projectId, url);
967
+ if (!result) {
968
+ return { success: false, message: "No browser session available." };
969
+ }
970
+ return { success: true, title: result.title, url: result.url };
971
+ }
972
+ catch (err) {
973
+ const msg = err instanceof Error ? err.message : "Failed to open URL";
974
+ return { success: false, error: msg };
975
+ }
976
+ },
977
+ }),
978
+ clickElement: tool({
979
+ description: "Click an element on the page in the preview browser. " +
980
+ "Accepts CSS selectors, text selectors (text=Submit), or role selectors (role=button[name='Submit']).",
981
+ inputSchema: z.object({
982
+ selector: z.string().describe("Selector for the element to click"),
983
+ }),
984
+ execute: async ({ selector }) => {
985
+ // Try iframe first (user sees it live)
986
+ const iframeResult = await tryIframeCommand({ action: "click", selector });
987
+ if (iframeResult)
988
+ return iframeResult;
989
+ // Fallback to Playwright
990
+ const page = browserManager?.getPage(projectId);
991
+ if (!page)
992
+ return { success: false, error: "No browser session. Use openPreview first." };
993
+ try {
994
+ await page.click(selector, { timeout: 5000 });
995
+ return { success: true };
996
+ }
997
+ catch (err) {
998
+ const msg = err instanceof Error ? err.message : "Click failed";
999
+ return { success: false, error: msg };
1000
+ }
1001
+ },
1002
+ }),
1003
+ fillInput: tool({
1004
+ description: "Fill an input or textarea on the page in the preview browser. " +
1005
+ "Clears existing value before typing. Accepts CSS, text, or role selectors.",
1006
+ inputSchema: z.object({
1007
+ selector: z.string().describe("Selector for the input element"),
1008
+ value: z.string().describe("Value to fill"),
1009
+ }),
1010
+ execute: async ({ selector, value }) => {
1011
+ // Try iframe first (user sees it live)
1012
+ const iframeResult = await tryIframeCommand({ action: "fill", selector, value });
1013
+ if (iframeResult)
1014
+ return iframeResult;
1015
+ // Fallback to Playwright
1016
+ const page = browserManager?.getPage(projectId);
1017
+ if (!page)
1018
+ return { success: false, error: "No browser session. Use openPreview first." };
1019
+ try {
1020
+ await page.fill(selector, value, { timeout: 5000 });
1021
+ return { success: true };
1022
+ }
1023
+ catch (err) {
1024
+ const msg = err instanceof Error ? err.message : "Fill failed";
1025
+ return { success: false, error: msg };
1026
+ }
1027
+ },
1028
+ }),
1029
+ selectOption: tool({
1030
+ description: "Select an option from a <select> dropdown in the preview browser.",
1031
+ inputSchema: z.object({
1032
+ selector: z.string().describe("Selector for the <select> element"),
1033
+ value: z.string().describe("Value or label of the option to select"),
1034
+ }),
1035
+ execute: async ({ selector, value }) => {
1036
+ // Try iframe first
1037
+ const iframeResult = await tryIframeCommand({ action: "select", selector, value });
1038
+ if (iframeResult)
1039
+ return iframeResult;
1040
+ // Fallback to Playwright
1041
+ const page = browserManager?.getPage(projectId);
1042
+ if (!page)
1043
+ return { success: false, error: "No browser session. Use openPreview first." };
1044
+ try {
1045
+ await page.selectOption(selector, value, { timeout: 5000 });
1046
+ return { success: true };
1047
+ }
1048
+ catch (err) {
1049
+ const msg = err instanceof Error ? err.message : "Select failed";
1050
+ return { success: false, error: msg };
1051
+ }
1052
+ },
1053
+ }),
1054
+ pressKey: tool({
1055
+ description: "Press a keyboard key in the preview browser (e.g. 'Enter', 'Tab', 'Escape', 'ArrowDown').",
1056
+ inputSchema: z.object({
1057
+ key: z.string().describe("Key to press (e.g. 'Enter', 'Tab', 'Escape')"),
1058
+ }),
1059
+ execute: async ({ key }) => {
1060
+ // Try iframe first
1061
+ const iframeResult = await tryIframeCommand({ action: "pressKey", key });
1062
+ if (iframeResult)
1063
+ return iframeResult;
1064
+ // Fallback to Playwright
1065
+ const page = browserManager?.getPage(projectId);
1066
+ if (!page)
1067
+ return { success: false, error: "No browser session. Use openPreview first." };
1068
+ try {
1069
+ await page.keyboard.press(key);
1070
+ return { success: true };
1071
+ }
1072
+ catch (err) {
1073
+ const msg = err instanceof Error ? err.message : "Key press failed";
1074
+ return { success: false, error: msg };
1075
+ }
1076
+ },
1077
+ }),
1078
+ screenshot: tool({
1079
+ description: "Take a screenshot of the current page in the preview browser. " +
1080
+ "Returns a base64 PNG image. Use this to see the current state of the page.",
1081
+ inputSchema: z.object({}),
1082
+ execute: async () => {
1083
+ const page = browserManager?.getPage(projectId);
1084
+ if (!page)
1085
+ return { success: false, error: "No browser session. Use openPreview first." };
1086
+ try {
1087
+ const buffer = await page.screenshot({ type: "png", fullPage: false });
1088
+ const base64 = buffer.toString("base64");
1089
+ return { success: true, image: base64 };
1090
+ }
1091
+ catch (err) {
1092
+ const msg = err instanceof Error ? err.message : "Screenshot failed";
1093
+ return { success: false, error: msg };
1094
+ }
1095
+ },
1096
+ }),
1097
+ getPageContent: tool({
1098
+ description: "Get the text content or HTML of the current page (or a specific element) in the preview browser. " +
1099
+ "If no selector is provided, returns the full page text content.",
1100
+ inputSchema: z.object({
1101
+ selector: z.string().optional().describe("Optional CSS selector to get content of a specific element"),
1102
+ }),
1103
+ execute: async ({ selector }) => {
1104
+ // Try iframe first (reads from the user's actual page)
1105
+ const iframeResult = await tryIframeCommand({ action: "getText", selector: selector ?? undefined });
1106
+ if (iframeResult) {
1107
+ if (iframeResult.success && iframeResult.content) {
1108
+ const capped = iframeResult.content.length > 10000
1109
+ ? iframeResult.content.slice(0, 10000) + "\n...(truncated)"
1110
+ : iframeResult.content;
1111
+ return { success: true, content: capped };
1112
+ }
1113
+ return iframeResult;
1114
+ }
1115
+ // Fallback to Playwright
1116
+ const page = browserManager?.getPage(projectId);
1117
+ if (!page)
1118
+ return { success: false, error: "No browser session. Use openPreview first." };
1119
+ try {
1120
+ if (selector) {
1121
+ const text = await page.textContent(selector, { timeout: 5000 });
1122
+ return { success: true, content: text ?? "" };
1123
+ }
1124
+ const text = await page.evaluate(() => document.body.innerText);
1125
+ const capped = text.length > 10000 ? text.slice(0, 10000) + "\n...(truncated)" : text;
1126
+ return { success: true, content: capped };
1127
+ }
1128
+ catch (err) {
1129
+ const msg = err instanceof Error ? err.message : "Failed to get page content";
1130
+ return { success: false, error: msg };
1131
+ }
1132
+ },
1133
+ }),
1134
+ waitForElement: tool({
1135
+ description: "Wait for an element to appear on the page in the preview browser.",
1136
+ inputSchema: z.object({
1137
+ selector: z.string().describe("Selector to wait for"),
1138
+ timeout: z.number().min(1000).max(30000).default(10000).describe("Timeout in milliseconds"),
1139
+ }),
1140
+ execute: async ({ selector, timeout }) => {
1141
+ const page = browserManager?.getPage(projectId);
1142
+ if (!page)
1143
+ return { success: false, error: "No browser session. Use openPreview first." };
1144
+ try {
1145
+ await page.waitForSelector(selector, { timeout });
1146
+ return { success: true };
1147
+ }
1148
+ catch (err) {
1149
+ const msg = err instanceof Error ? err.message : "Wait timed out";
1150
+ return { success: false, error: msg };
1151
+ }
1152
+ },
1153
+ }),
1154
+ };
1155
+ }
1156
+ // ---- Message queue (prevents concurrent streams on the same session) ----
1157
+ enqueueOrSend(sessionId, content) {
1158
+ const session = this.sessions.get(sessionId);
1159
+ if (!session) {
1160
+ console.log(`[ChatSession] enqueueOrSend: session ${sessionId} not found, dropping message`);
1161
+ return;
1162
+ }
1163
+ if (session.abortController) {
1164
+ // A stream is already active — queue the message
1165
+ let queue = this.messageQueue.get(sessionId);
1166
+ if (!queue) {
1167
+ queue = [];
1168
+ this.messageQueue.set(sessionId, queue);
1169
+ }
1170
+ queue.push(content);
1171
+ console.log(`[ChatSession] Queued message for session ${sessionId} (queue length: ${queue.length})`);
1172
+ return;
1173
+ }
1174
+ // No active stream — send immediately
1175
+ console.log(`[ChatSession] enqueueOrSend: sending immediately for session ${sessionId} (abortController=null)`);
1176
+ this.sendMessage(sessionId, content).catch((err) => {
1177
+ console.error(`[ChatSession] enqueueOrSend sendMessage error:`, err);
1178
+ });
1179
+ }
1180
+ drainQueue(sessionId) {
1181
+ const queue = this.messageQueue.get(sessionId);
1182
+ if (!queue || queue.length === 0) {
1183
+ this.messageQueue.delete(sessionId);
1184
+ return;
1185
+ }
1186
+ const next = queue.shift();
1187
+ if (queue.length === 0)
1188
+ this.messageQueue.delete(sessionId);
1189
+ console.log(`[ChatSession] Draining queued message for session ${sessionId}`);
1190
+ this.sendMessage(sessionId, next).catch((err) => {
1191
+ console.error(`[ChatSession] drainQueue sendMessage error:`, err);
1192
+ });
1193
+ }
1194
+ // ---- Send message & stream AI response ----
1195
+ async sendMessage(sessionId, content) {
1196
+ const session = this.sessions.get(sessionId);
1197
+ if (!session) {
1198
+ console.log(`[ChatSession] sendMessage: session ${sessionId} not found`);
1199
+ return false;
1200
+ }
1201
+ console.log(`[ChatSession] sendMessage called: session=${sessionId}, contentLen=${content.length}, isTerminalEvent=${content.includes("[Terminal Event]")}`);
1202
+ // 1. Push user message
1203
+ const userMsg = { type: "user", content, timestamp: Date.now() };
1204
+ this.pushEntry(session, userMsg);
1205
+ // 2. Update status to running
1206
+ session.status = "running";
1207
+ this.broadcastPatch(session, ConversationPatch.updateStatus("running"));
1208
+ // 3. Build messages array for AI SDK
1209
+ const messages = session.store.entries
1210
+ .filter((e) => e.type === "user" || e.type === "assistant")
1211
+ .map((e) => ({
1212
+ role: e.type,
1213
+ content: typeof e.content === "string" ? e.content : e.content.filter(p => p.type === "text").map(p => p.text).join("\n"),
1214
+ }));
1215
+ // 4. Stream response
1216
+ const abortController = new AbortController();
1217
+ session.abortController = abortController;
1218
+ let assistantIndex = null;
1219
+ let accumulatedText = "";
1220
+ try {
1221
+ const result = streamText({
1222
+ model: resolveChatModel(this.storage),
1223
+ system: this.getSystemPrompt(session.projectId, session.branch),
1224
+ messages,
1225
+ tools: this.createTools(session.projectId, session.branch, session.id),
1226
+ stopWhen: stepCountIs(3),
1227
+ abortSignal: abortController.signal,
1228
+ });
1229
+ for await (const part of result.fullStream) {
1230
+ if (abortController.signal.aborted)
1231
+ break;
1232
+ switch (part.type) {
1233
+ case "text-delta": {
1234
+ accumulatedText += part.text;
1235
+ if (assistantIndex === null) {
1236
+ // First chunk — create the assistant entry
1237
+ const assistantMsg = {
1238
+ type: "assistant",
1239
+ content: accumulatedText,
1240
+ partial: true,
1241
+ timestamp: Date.now(),
1242
+ };
1243
+ assistantIndex = session.store.nextIndex;
1244
+ session.store.nextIndex++;
1245
+ const patch = ConversationPatch.addEntry(assistantIndex, assistantMsg);
1246
+ session.store.patches.push(patch);
1247
+ session.store.entries[assistantIndex] = assistantMsg;
1248
+ this.broadcastPatch(session, patch);
1249
+ }
1250
+ else {
1251
+ // Subsequent chunks — replace entry
1252
+ const assistantMsg = {
1253
+ type: "assistant",
1254
+ content: accumulatedText,
1255
+ partial: true,
1256
+ timestamp: Date.now(),
1257
+ };
1258
+ const patch = ConversationPatch.replaceEntry(assistantIndex, assistantMsg);
1259
+ session.store.patches.push(patch);
1260
+ session.store.entries[assistantIndex] = assistantMsg;
1261
+ this.broadcastPatch(session, patch);
1262
+ }
1263
+ break;
1264
+ }
1265
+ case "tool-call": {
1266
+ // Finalize any partial assistant message before the tool call
1267
+ if (assistantIndex !== null && accumulatedText) {
1268
+ const finalMsg = {
1269
+ type: "assistant",
1270
+ content: accumulatedText,
1271
+ partial: false,
1272
+ timestamp: Date.now(),
1273
+ };
1274
+ const patch = ConversationPatch.replaceEntry(assistantIndex, finalMsg);
1275
+ session.store.patches.push(patch);
1276
+ session.store.entries[assistantIndex] = finalMsg;
1277
+ this.broadcastPatch(session, patch);
1278
+ }
1279
+ const toolUseMsg = {
1280
+ type: "tool_use",
1281
+ tool: part.toolName,
1282
+ input: part.input,
1283
+ toolUseId: part.toolCallId,
1284
+ timestamp: Date.now(),
1285
+ };
1286
+ this.pushEntry(session, toolUseMsg);
1287
+ // Reset so next text starts a new assistant message
1288
+ assistantIndex = null;
1289
+ accumulatedText = "";
1290
+ break;
1291
+ }
1292
+ case "tool-result": {
1293
+ const output = part.output;
1294
+ const toolResultMsg = {
1295
+ type: "tool_result",
1296
+ tool: part.toolName,
1297
+ output: typeof output === "string" ? output : JSON.stringify(output),
1298
+ toolUseId: part.toolCallId,
1299
+ timestamp: Date.now(),
1300
+ };
1301
+ this.pushEntry(session, toolResultMsg);
1302
+ break;
1303
+ }
1304
+ }
1305
+ }
1306
+ // 5. Finalize — mark as non-partial
1307
+ if (assistantIndex !== null) {
1308
+ const finalMsg = {
1309
+ type: "assistant",
1310
+ content: accumulatedText,
1311
+ partial: false,
1312
+ timestamp: Date.now(),
1313
+ };
1314
+ const patch = ConversationPatch.replaceEntry(assistantIndex, finalMsg);
1315
+ session.store.patches.push(patch);
1316
+ session.store.entries[assistantIndex] = finalMsg;
1317
+ this.broadcastPatch(session, patch);
1318
+ }
1319
+ }
1320
+ catch (err) {
1321
+ // Don't push error for intentional abort
1322
+ if (abortController.signal.aborted) {
1323
+ // Finalize partial message if we have one
1324
+ if (assistantIndex !== null && accumulatedText) {
1325
+ const finalMsg = {
1326
+ type: "assistant",
1327
+ content: accumulatedText,
1328
+ partial: false,
1329
+ timestamp: Date.now(),
1330
+ };
1331
+ const patch = ConversationPatch.replaceEntry(assistantIndex, finalMsg);
1332
+ session.store.patches.push(patch);
1333
+ session.store.entries[assistantIndex] = finalMsg;
1334
+ this.broadcastPatch(session, patch);
1335
+ }
1336
+ }
1337
+ else {
1338
+ const errorMessage = err instanceof Error ? err.message : "Unknown error";
1339
+ console.error(`[ChatSession] Stream error for ${sessionId}:`, errorMessage);
1340
+ const errorMsg = {
1341
+ type: "error",
1342
+ message: errorMessage,
1343
+ timestamp: Date.now(),
1344
+ };
1345
+ this.pushEntry(session, errorMsg);
1346
+ }
1347
+ }
1348
+ finally {
1349
+ session.abortController = null;
1350
+ session.status = "stopped";
1351
+ this.broadcastPatch(session, ConversationPatch.updateStatus("stopped"));
1352
+ // Process any queued messages (e.g. [Terminal Event] that arrived during this stream)
1353
+ this.drainQueue(sessionId);
1354
+ }
1355
+ return true;
1356
+ }
1357
+ // ---- Stop generation ----
1358
+ stopGeneration(sessionId) {
1359
+ const session = this.sessions.get(sessionId);
1360
+ if (!session || !session.abortController)
1361
+ return false;
1362
+ session.abortController.abort();
1363
+ return true;
1364
+ }
1365
+ // ---- Internal helpers ----
1366
+ pushEntry(session, entry) {
1367
+ const index = session.store.nextIndex;
1368
+ session.store.nextIndex++;
1369
+ const patch = ConversationPatch.addEntry(index, entry);
1370
+ session.store.patches.push(patch);
1371
+ session.store.entries[index] = entry;
1372
+ this.broadcastPatch(session, patch);
1373
+ }
1374
+ broadcastPatch(session, patch) {
1375
+ const raw = JSON.stringify({ JsonPatch: patch });
1376
+ for (const ws of session.subscribers) {
1377
+ try {
1378
+ ws.send(raw);
1379
+ }
1380
+ catch {
1381
+ // Client gone, will be cleaned up on close
1382
+ }
1383
+ }
1384
+ }
1385
+ // ---- Browser command via iframe ----
1386
+ /**
1387
+ * Send a browser command to the frontend via WebSocket.
1388
+ * The frontend forwards it to the iframe's injected script via postMessage.
1389
+ * Returns the result or null if no subscribers or timeout.
1390
+ */
1391
+ sendBrowserCommand(sessionId, command, timeoutMs = 5000) {
1392
+ const session = this.sessions.get(sessionId);
1393
+ if (!session || session.subscribers.size === 0) {
1394
+ return Promise.resolve(null); // No frontend connected
1395
+ }
1396
+ const id = `bcmd-${randomUUID()}`;
1397
+ const fullCommand = { id, ...command };
1398
+ return new Promise((resolve) => {
1399
+ const timer = setTimeout(() => {
1400
+ this.pendingBrowserCommands.delete(id);
1401
+ resolve(null); // Timeout — frontend didn't respond
1402
+ }, timeoutMs);
1403
+ this.pendingBrowserCommands.set(id, { resolve, timer });
1404
+ // Broadcast to all subscribers
1405
+ const raw = JSON.stringify({ browserCommand: fullCommand });
1406
+ for (const ws of session.subscribers) {
1407
+ try {
1408
+ ws.send(raw);
1409
+ }
1410
+ catch { /* client gone */ }
1411
+ }
1412
+ });
1413
+ }
1414
+ /**
1415
+ * Called when the frontend sends a browserResult message back over WebSocket.
1416
+ */
1417
+ handleBrowserResult(result) {
1418
+ const pending = this.pendingBrowserCommands.get(result.id);
1419
+ if (!pending)
1420
+ return; // Already timed out or duplicate
1421
+ clearTimeout(pending.timer);
1422
+ this.pendingBrowserCommands.delete(result.id);
1423
+ pending.resolve(result);
1424
+ }
1425
+ }