vibepulse 0.2.0 → 0.2.1

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 (420) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +4 -0
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/cache/.previewinfo +1 -1
  5. package/.next/cache/.rscinfo +1 -1
  6. package/.next/cache/.tsbuildinfo +1 -1
  7. package/.next/cache/config.json +3 -3
  8. package/.next/fallback-build-manifest.json +2 -2
  9. package/.next/prerender-manifest.json +3 -3
  10. package/.next/routes-manifest.json +32 -0
  11. package/.next/server/app/_global-error/page.js +1 -1
  12. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  13. package/.next/server/app/_global-error.html +2 -2
  14. package/.next/server/app/_global-error.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  18. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/.next/server/app/_not-found/page.js +1 -1
  21. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/_not-found.html +1 -1
  24. package/.next/server/app/_not-found.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  26. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  27. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  28. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  29. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  30. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/api/node/events/route.js +1 -1
  32. package/.next/server/app/api/node/events/route.js.nft.json +1 -1
  33. package/.next/server/app/api/node/health/route.js +1 -1
  34. package/.next/server/app/api/node/health/route.js.nft.json +1 -1
  35. package/.next/server/app/api/node/sessions/[id]/archive/route/app-paths-manifest.json +3 -0
  36. package/.next/server/app/api/node/sessions/[id]/archive/route/build-manifest.json +11 -0
  37. package/.next/server/app/api/node/sessions/[id]/archive/route/server-reference-manifest.json +4 -0
  38. package/.next/server/app/api/node/sessions/[id]/archive/route.js +6 -0
  39. package/.next/server/app/api/node/sessions/[id]/archive/route.js.map +5 -0
  40. package/.next/server/app/api/node/sessions/[id]/archive/route.js.nft.json +1 -0
  41. package/.next/server/app/api/node/sessions/[id]/archive/route_client-reference-manifest.js +2 -0
  42. package/.next/server/app/api/node/sessions/[id]/delete/route/app-paths-manifest.json +3 -0
  43. package/.next/server/app/api/node/sessions/[id]/delete/route/build-manifest.json +11 -0
  44. package/.next/server/app/api/node/sessions/[id]/delete/route/server-reference-manifest.json +4 -0
  45. package/.next/server/app/api/node/sessions/[id]/delete/route.js +7 -0
  46. package/.next/server/app/api/node/sessions/[id]/delete/route.js.map +5 -0
  47. package/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -0
  48. package/.next/server/app/api/node/sessions/[id]/delete/route_client-reference-manifest.js +2 -0
  49. package/.next/server/app/api/node/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  50. package/.next/server/app/api/node/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  51. package/.next/server/app/api/node/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  52. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js +7 -0
  53. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js.map +5 -0
  54. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -0
  55. package/.next/server/app/api/node/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  56. package/.next/server/app/api/node/sessions/route.js +1 -1
  57. package/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
  58. package/.next/server/app/api/opencode-events/route.js +1 -1
  59. package/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
  60. package/.next/server/app/api/sessions/[id]/archive/route.js +2 -1
  61. package/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  62. package/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  63. package/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  64. package/.next/server/app/api/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  65. package/.next/server/app/api/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  66. package/.next/server/app/api/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  67. package/.next/server/app/api/sessions/[id]/open-editor/route.js +7 -0
  68. package/.next/server/app/api/sessions/[id]/open-editor/route.js.map +5 -0
  69. package/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -0
  70. package/.next/server/app/api/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  71. package/.next/server/app/api/sessions/route.js +1 -1
  72. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  73. package/.next/server/app/index.html +1 -1
  74. package/.next/server/app/index.rsc +3 -3
  75. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  76. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  77. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  78. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  79. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  80. package/.next/server/app/page.js +1 -1
  81. package/.next/server/app/page.js.nft.json +1 -1
  82. package/.next/server/app/page_client-reference-manifest.js +1 -1
  83. package/.next/server/app-paths-manifest.json +4 -0
  84. package/.next/server/chunks/[root-of-the-server]__1211da38._.js +3 -0
  85. package/.next/server/chunks/[root-of-the-server]__1211da38._.js.map +1 -0
  86. package/.next/{standalone/.next/server/chunks/[root-of-the-server]__b698889b._.js → server/chunks/[root-of-the-server]__1b87ec42._.js} +2 -2
  87. package/.next/server/chunks/[root-of-the-server]__1b87ec42._.js.map +1 -0
  88. package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +3 -0
  89. package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js.map +1 -0
  90. package/.next/server/chunks/[root-of-the-server]__2f981540._.js +3 -0
  91. package/.next/server/chunks/[root-of-the-server]__2f981540._.js.map +1 -0
  92. package/.next/server/chunks/[root-of-the-server]__3745b314._.js +3 -0
  93. package/.next/server/chunks/[root-of-the-server]__3745b314._.js.map +1 -0
  94. package/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
  95. package/.next/server/chunks/[root-of-the-server]__56690af0._.js.map +1 -1
  96. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
  97. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js.map +1 -1
  98. package/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
  99. package/.next/server/chunks/[root-of-the-server]__59175de4._.js.map +1 -1
  100. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
  101. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js.map +1 -1
  102. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js +3 -0
  103. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js.map +1 -0
  104. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js.map +1 -0
  106. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
  107. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js.map +1 -1
  108. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
  109. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js.map +1 -1
  110. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
  111. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js.map +1 -1
  112. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
  113. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js.map +1 -1
  114. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js +3 -0
  115. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js.map +1 -0
  116. package/.next/server/chunks/[root-of-the-server]__db285678._.js +3 -0
  117. package/.next/server/chunks/[root-of-the-server]__db285678._.js.map +1 -0
  118. package/.next/{standalone/.next/server/chunks/[root-of-the-server]__16a9eb0a._.js → server/chunks/[root-of-the-server]__e00a9200._.js} +2 -2
  119. package/.next/server/chunks/{[root-of-the-server]__16a9eb0a._.js.map → [root-of-the-server]__e00a9200._.js.map} +1 -1
  120. package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +3 -0
  121. package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js.map +1 -0
  122. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js +3 -0
  123. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js.map +1 -0
  124. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js +3 -0
  125. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js.map +1 -0
  126. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js +3 -0
  127. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js.map +1 -0
  128. package/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js +3 -0
  129. package/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js.map +1 -0
  130. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
  131. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js.map +1 -1
  132. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  133. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js.map +1 -1
  134. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +2 -2
  135. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js.map +1 -1
  136. package/.next/server/chunks/ssr/{[root-of-the-server]__efc52f08._.js → [root-of-the-server]__631e12d0._.js} +2 -2
  137. package/.next/server/chunks/ssr/[root-of-the-server]__a8cd3911._.js +3 -0
  138. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
  139. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js.map +1 -1
  140. package/.next/server/pages/404.html +1 -1
  141. package/.next/server/pages/500.html +2 -2
  142. package/.next/server/server-reference-manifest.js +1 -1
  143. package/.next/server/server-reference-manifest.json +1 -1
  144. package/.next/standalone/.next/BUILD_ID +1 -1
  145. package/.next/standalone/.next/app-path-routes-manifest.json +4 -0
  146. package/.next/standalone/.next/build-manifest.json +2 -2
  147. package/.next/standalone/.next/prerender-manifest.json +3 -3
  148. package/.next/standalone/.next/routes-manifest.json +32 -0
  149. package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
  150. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  151. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  152. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  153. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  154. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  155. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  156. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  157. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  158. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  159. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  160. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  161. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  162. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  163. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  164. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  165. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  166. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  167. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  168. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  169. package/.next/standalone/.next/server/app/api/node/events/route.js +1 -1
  170. package/.next/standalone/.next/server/app/api/node/events/route.js.nft.json +1 -1
  171. package/.next/standalone/.next/server/app/api/node/health/route.js +1 -1
  172. package/.next/standalone/.next/server/app/api/node/health/route.js.nft.json +1 -1
  173. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/app-paths-manifest.json +3 -0
  174. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/build-manifest.json +11 -0
  175. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/server-reference-manifest.json +4 -0
  176. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js +6 -0
  177. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js.map +5 -0
  178. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js.nft.json +1 -0
  179. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route_client-reference-manifest.js +2 -0
  180. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/app-paths-manifest.json +3 -0
  181. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/build-manifest.json +11 -0
  182. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/server-reference-manifest.json +4 -0
  183. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js +7 -0
  184. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js.map +5 -0
  185. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -0
  186. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route_client-reference-manifest.js +2 -0
  187. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  188. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  189. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  190. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js +7 -0
  191. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.map +5 -0
  192. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -0
  193. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  194. package/.next/standalone/.next/server/app/api/node/sessions/route.js +1 -1
  195. package/.next/standalone/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
  196. package/.next/standalone/.next/server/app/api/opencode-events/route.js +1 -1
  197. package/.next/standalone/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
  198. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js +2 -1
  199. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  200. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  201. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  202. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  203. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  204. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  205. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js +7 -0
  206. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.map +5 -0
  207. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -0
  208. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  209. package/.next/standalone/.next/server/app/api/sessions/route.js +1 -1
  210. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  211. package/.next/standalone/.next/server/app/index.html +1 -1
  212. package/.next/standalone/.next/server/app/index.rsc +3 -3
  213. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  214. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  215. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  216. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  217. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  218. package/.next/standalone/.next/server/app/page.js +1 -1
  219. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  220. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  221. package/.next/standalone/.next/server/app-paths-manifest.json +4 -0
  222. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1211da38._.js +3 -0
  223. package/.next/{server/chunks/[root-of-the-server]__b698889b._.js → standalone/.next/server/chunks/[root-of-the-server]__1b87ec42._.js} +2 -2
  224. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +3 -0
  225. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f981540._.js +3 -0
  226. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3745b314._.js +3 -0
  227. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
  228. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
  229. package/.next/standalone/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
  230. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
  231. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c428a24._.js +3 -0
  232. package/.next/standalone/.next/server/chunks/[root-of-the-server]__73a00b88._.js +3 -0
  233. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
  234. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
  235. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
  236. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
  237. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8e61048._.js +3 -0
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__db285678._.js +3 -0
  239. package/.next/{server/chunks/[root-of-the-server]__16a9eb0a._.js → standalone/.next/server/chunks/[root-of-the-server]__e00a9200._.js} +2 -2
  240. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +3 -0
  241. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js +3 -0
  242. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js +3 -0
  243. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js +3 -0
  244. package/.next/standalone/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js +3 -0
  245. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
  246. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  247. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +2 -2
  248. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__efc52f08._.js → [root-of-the-server]__631e12d0._.js} +2 -2
  249. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__a8cd3911._.js +3 -0
  250. package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
  251. package/.next/standalone/.next/server/pages/404.html +1 -1
  252. package/.next/standalone/.next/server/pages/500.html +2 -2
  253. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  254. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  255. package/.next/standalone/.next/static/chunks/7ac19aaef01f4a03.js +13 -0
  256. package/.next/standalone/.next/static/chunks/f42202943f6742e5.css +3 -0
  257. package/.next/standalone/AGENTS.md +85 -0
  258. package/.next/standalone/README.md +76 -0
  259. package/.next/standalone/__mocks__/child_process.ts +4 -0
  260. package/.next/standalone/bin/dev-runtime.js +58 -0
  261. package/.next/standalone/bin/vibepulse.js +87 -0
  262. package/.next/standalone/check-hsql.mjs +71 -0
  263. package/.next/standalone/docs/session-status-detection.md +258 -0
  264. package/.next/standalone/eslint.config.mjs +31 -0
  265. package/.next/standalone/next.config.ts +8 -0
  266. package/.next/standalone/package-lock.json +10312 -0
  267. package/.next/standalone/package.json +1 -1
  268. package/.next/standalone/postcss.config.mjs +7 -0
  269. package/.next/standalone/src/AGENTS.md +41 -0
  270. package/.next/standalone/src/app/api/AGENTS.md +40 -0
  271. package/.next/standalone/src/app/api/node/events/route.test.ts +196 -0
  272. package/.next/standalone/src/app/api/node/events/route.ts +259 -0
  273. package/.next/standalone/src/app/api/node/health/route.test.ts +190 -0
  274. package/.next/standalone/src/app/api/node/health/route.ts +48 -0
  275. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.test.ts +128 -0
  276. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.ts +97 -0
  277. package/.next/standalone/src/app/api/node/sessions/[id]/delete/route.test.ts +113 -0
  278. package/.next/standalone/src/app/api/node/sessions/[id]/delete/route.ts +81 -0
  279. package/.next/standalone/src/app/api/node/sessions/[id]/open-editor/route.test.ts +206 -0
  280. package/.next/standalone/src/app/api/node/sessions/[id]/open-editor/route.ts +123 -0
  281. package/.next/standalone/src/app/api/node/sessions/route.test.ts +408 -0
  282. package/.next/standalone/src/app/api/node/sessions/route.ts +1094 -0
  283. package/.next/standalone/src/app/api/nodes/route.test.ts +237 -0
  284. package/.next/standalone/src/app/api/nodes/route.ts +176 -0
  285. package/.next/standalone/src/app/api/opencode-config/route.test.ts +86 -0
  286. package/.next/standalone/src/app/api/opencode-config/route.ts +376 -0
  287. package/.next/standalone/src/app/api/opencode-config/status/route.ts +31 -0
  288. package/.next/standalone/src/app/api/opencode-events/route.test.ts +624 -0
  289. package/.next/standalone/src/app/api/opencode-events/route.ts +508 -0
  290. package/.next/standalone/src/app/api/opencode-models/route.test.ts +167 -0
  291. package/.next/standalone/src/app/api/opencode-models/route.ts +76 -0
  292. package/.next/standalone/src/app/api/profiles/[id]/apply/route.ts +49 -0
  293. package/.next/standalone/src/app/api/profiles/[id]/export/route.ts +31 -0
  294. package/.next/standalone/src/app/api/profiles/[id]/route.ts +160 -0
  295. package/.next/standalone/src/app/api/profiles/import/route.test.js +107 -0
  296. package/.next/standalone/src/app/api/profiles/import/route.ts +65 -0
  297. package/.next/standalone/src/app/api/profiles/route.ts +107 -0
  298. package/.next/standalone/src/app/api/sessions/[id]/archive/route.test.ts +136 -0
  299. package/.next/standalone/src/app/api/sessions/[id]/archive/route.ts +170 -0
  300. package/.next/standalone/src/app/api/sessions/[id]/delete/route.test.ts +113 -0
  301. package/.next/standalone/src/app/api/sessions/[id]/delete/route.ts +137 -0
  302. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.test.ts +218 -0
  303. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.ts +85 -0
  304. package/.next/standalone/src/app/api/sessions/[id]/route.test.ts +531 -0
  305. package/.next/standalone/src/app/api/sessions/[id]/route.ts +75 -0
  306. package/.next/standalone/src/app/api/sessions/route.test.ts +1298 -0
  307. package/.next/standalone/src/app/api/sessions/route.ts +1695 -0
  308. package/.next/standalone/src/app/favicon.ico +0 -0
  309. package/.next/standalone/src/app/globals.css +66 -0
  310. package/.next/standalone/src/app/layout.tsx +37 -0
  311. package/.next/standalone/src/app/page.test.tsx +134 -0
  312. package/.next/standalone/src/app/page.tsx +358 -0
  313. package/.next/standalone/src/components/AGENTS.md +42 -0
  314. package/.next/standalone/src/components/ErrorBoundary.tsx +72 -0
  315. package/.next/standalone/src/components/KanbanBoard.test.tsx +704 -0
  316. package/.next/standalone/src/components/KanbanBoard.tsx +852 -0
  317. package/.next/standalone/src/components/LoadingState.tsx +37 -0
  318. package/.next/standalone/src/components/ProjectCard.test.tsx +773 -0
  319. package/.next/standalone/src/components/ProjectCard.tsx +595 -0
  320. package/.next/standalone/src/components/QueryProvider.tsx +25 -0
  321. package/.next/standalone/src/components/SessionCard.test.tsx +566 -0
  322. package/.next/standalone/src/components/SessionCard.tsx +434 -0
  323. package/.next/standalone/src/components/SessionList.tsx +60 -0
  324. package/.next/standalone/src/components/host-config/HostManagerDialog.test.tsx +252 -0
  325. package/.next/standalone/src/components/host-config/HostManagerDialog.tsx +476 -0
  326. package/.next/standalone/src/components/opencode-config/AgentConfigForm.test.tsx +72 -0
  327. package/.next/standalone/src/components/opencode-config/AgentConfigForm.tsx +483 -0
  328. package/.next/standalone/src/components/opencode-config/AgentModelSelector.tsx +284 -0
  329. package/.next/standalone/src/components/opencode-config/AgentsConfigPanel.tsx +162 -0
  330. package/.next/standalone/src/components/opencode-config/ConfigButton.tsx +43 -0
  331. package/.next/standalone/src/components/opencode-config/ConfigPanel.tsx +91 -0
  332. package/.next/standalone/src/components/opencode-config/FullscreenConfigPanel.tsx +435 -0
  333. package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.test.tsx +91 -0
  334. package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.tsx +288 -0
  335. package/.next/standalone/src/components/opencode-config/categories/CategoriesList.tsx +382 -0
  336. package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.test.tsx +111 -0
  337. package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.tsx +174 -0
  338. package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.tsx +453 -0
  339. package/.next/standalone/src/components/opencode-config/profiles/ProfileCard.tsx +140 -0
  340. package/.next/standalone/src/components/opencode-config/profiles/ProfileEditor.tsx +446 -0
  341. package/.next/standalone/src/components/opencode-config/profiles/ProfileList.tsx +446 -0
  342. package/.next/standalone/src/components/opencode-config/profiles/ProfileManager.test.tsx +225 -0
  343. package/.next/standalone/src/components/opencode-config/profiles/ProfileManager.tsx +405 -0
  344. package/.next/standalone/src/components/ui/Tabs.tsx +59 -0
  345. package/.next/standalone/src/hooks/useHostSources.test.ts +509 -0
  346. package/.next/standalone/src/hooks/useHostSources.ts +299 -0
  347. package/.next/standalone/src/hooks/useOpencodeSync.test.ts +387 -0
  348. package/.next/standalone/src/hooks/useOpencodeSync.ts +571 -0
  349. package/.next/standalone/src/index.ts +2 -0
  350. package/.next/standalone/src/lib/editorLauncher.server.ts +36 -0
  351. package/.next/standalone/src/lib/editorLauncher.test.ts +35 -0
  352. package/.next/standalone/src/lib/editorLauncher.ts +25 -0
  353. package/.next/standalone/src/lib/hostAccent.test.ts +58 -0
  354. package/.next/standalone/src/lib/hostAccent.ts +46 -0
  355. package/.next/standalone/src/lib/hostIdentity.test.ts +187 -0
  356. package/.next/standalone/src/lib/hostIdentity.ts +122 -0
  357. package/.next/standalone/src/lib/hostSourcesStorage.test.ts +141 -0
  358. package/.next/standalone/src/lib/hostSourcesStorage.ts +72 -0
  359. package/.next/standalone/src/lib/nodeProtocol.test.ts +159 -0
  360. package/.next/standalone/src/lib/nodeProtocol.ts +142 -0
  361. package/.next/standalone/src/lib/nodeRegistry.test.ts +173 -0
  362. package/.next/standalone/src/lib/nodeRegistry.ts +398 -0
  363. package/.next/standalone/src/lib/notificationSound.ts +292 -0
  364. package/.next/standalone/src/lib/opencodeConfig.test.ts +100 -0
  365. package/.next/standalone/src/lib/opencodeConfig.ts +76 -0
  366. package/.next/standalone/src/lib/opencodeDiscovery.ts +275 -0
  367. package/.next/standalone/src/lib/profiles/share.test.ts +91 -0
  368. package/.next/standalone/src/lib/profiles/share.ts +93 -0
  369. package/.next/standalone/src/lib/profiles/storage.test.ts +108 -0
  370. package/.next/standalone/src/lib/profiles/storage.ts +370 -0
  371. package/.next/standalone/src/lib/runtimeMode.test.ts +29 -0
  372. package/.next/standalone/src/lib/runtimeMode.ts +29 -0
  373. package/.next/standalone/src/lib/sessionActionErrors.ts +37 -0
  374. package/.next/standalone/src/lib/sessionArchiveOverrides.test.ts +43 -0
  375. package/.next/standalone/src/lib/sessionArchiveOverrides.ts +116 -0
  376. package/.next/standalone/src/lib/transform.test.ts +121 -0
  377. package/.next/standalone/src/lib/transform.ts +193 -0
  378. package/.next/standalone/src/test/setup.ts +8 -0
  379. package/.next/standalone/src/types/index.ts +152 -0
  380. package/.next/standalone/src/types/opencodeConfig.ts +149 -0
  381. package/.next/standalone/tsconfig.json +34 -0
  382. package/.next/standalone/tsconfig.lib.json +17 -0
  383. package/.next/standalone/vitest.config.ts +16 -0
  384. package/.next/static/chunks/7ac19aaef01f4a03.js +13 -0
  385. package/.next/static/chunks/f42202943f6742e5.css +3 -0
  386. package/.next/trace +1 -1
  387. package/.next/trace-build +1 -1
  388. package/.next/types/routes.d.ts +5 -1
  389. package/.next/types/validator.ts +36 -0
  390. package/package.json +1 -1
  391. package/.next/server/chunks/[root-of-the-server]__0b017945._.js +0 -3
  392. package/.next/server/chunks/[root-of-the-server]__0b017945._.js.map +0 -1
  393. package/.next/server/chunks/[root-of-the-server]__1e118bd3._.js +0 -3
  394. package/.next/server/chunks/[root-of-the-server]__1e118bd3._.js.map +0 -1
  395. package/.next/server/chunks/[root-of-the-server]__6979e732._.js +0 -3
  396. package/.next/server/chunks/[root-of-the-server]__6979e732._.js.map +0 -1
  397. package/.next/server/chunks/[root-of-the-server]__a7b4d79d._.js +0 -3
  398. package/.next/server/chunks/[root-of-the-server]__a7b4d79d._.js.map +0 -1
  399. package/.next/server/chunks/[root-of-the-server]__b698889b._.js.map +0 -1
  400. package/.next/server/chunks/[root-of-the-server]__ddc251b7._.js +0 -3
  401. package/.next/server/chunks/[root-of-the-server]__ddc251b7._.js.map +0 -1
  402. package/.next/server/chunks/ssr/[root-of-the-server]__b0788643._.js +0 -3
  403. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b017945._.js +0 -3
  404. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1e118bd3._.js +0 -3
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6979e732._.js +0 -3
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a7b4d79d._.js +0 -3
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__ddc251b7._.js +0 -3
  408. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__b0788643._.js +0 -3
  409. package/.next/standalone/.next/static/chunks/9f8c22002e7395e8.js +0 -13
  410. package/.next/standalone/.next/static/chunks/f1b55db60e7ed6f3.css +0 -3
  411. package/.next/static/chunks/9f8c22002e7395e8.js +0 -13
  412. package/.next/static/chunks/f1b55db60e7ed6f3.css +0 -3
  413. /package/.next/server/chunks/ssr/{[root-of-the-server]__efc52f08._.js.map → [root-of-the-server]__631e12d0._.js.map} +0 -0
  414. /package/.next/server/chunks/ssr/{[root-of-the-server]__b0788643._.js.map → [root-of-the-server]__a8cd3911._.js.map} +0 -0
  415. /package/.next/standalone/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_buildManifest.js +0 -0
  416. /package/.next/standalone/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_clientMiddlewareManifest.json +0 -0
  417. /package/.next/standalone/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_ssgManifest.js +0 -0
  418. /package/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_buildManifest.js +0 -0
  419. /package/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_clientMiddlewareManifest.json +0 -0
  420. /package/.next/static/{L_tmqf71LaeMzApO4SiU- → Fw2R3y-fHX4B2SWxNy_4X}/_ssgManifest.js +0 -0
@@ -0,0 +1,508 @@
1
+ import { createOpencodeClient } from '@opencode-ai/sdk';
2
+ import { discoverOpencodePortsWithMeta } from '@/lib/opencodeDiscovery';
3
+ import { NODE_PROTOCOL_VERSION, createNodeRequestHeaders } from '@/lib/nodeProtocol';
4
+ import { listNodeRecords, type StoredNodeRecord } from '@/lib/nodeRegistry';
5
+ import { RUNTIME_ROLE_ENV_VAR } from '@/lib/runtimeMode';
6
+
7
+ const DEFAULT_EVENTS_PREFLIGHT_TIMEOUT_MS = 2500;
8
+
9
+ type ConnectedStream = {
10
+ key: string;
11
+ label: string;
12
+ stream: AsyncIterable<unknown>;
13
+ controller: AbortController;
14
+ };
15
+
16
+ type StreamSourceSpec = {
17
+ key: string;
18
+ label: string;
19
+ connect: (controller?: AbortController) => Promise<ConnectedStream>;
20
+ };
21
+
22
+ type RemoteEventSource = {
23
+ hostId: string;
24
+ hostLabel: string;
25
+ hostKind: 'remote';
26
+ hostBaseUrl: string;
27
+ };
28
+
29
+ function getPreflightTimeoutMs(): number {
30
+ const parsedTimeout = Number(process.env.OPENCODE_EVENTS_PREFLIGHT_TIMEOUT_MS);
31
+ return Number.isFinite(parsedTimeout) && parsedTimeout > 0
32
+ ? parsedTimeout
33
+ : DEFAULT_EVENTS_PREFLIGHT_TIMEOUT_MS;
34
+ }
35
+
36
+ function isRecord(value: unknown): value is Record<string, unknown> {
37
+ return typeof value === 'object' && value !== null;
38
+ }
39
+
40
+ function isAbortLikeError(error: unknown): boolean {
41
+ if (error instanceof Error && error.name === 'AbortError') {
42
+ return true;
43
+ }
44
+
45
+ if (!isRecord(error)) {
46
+ return false;
47
+ }
48
+
49
+ return error['name'] === 'AbortError' || error['code'] === 20;
50
+ }
51
+
52
+ function formatErrorForLog(error: unknown): string {
53
+ if (error instanceof Error) {
54
+ return error.message;
55
+ }
56
+
57
+ if (typeof error === 'string') {
58
+ return error;
59
+ }
60
+
61
+ try {
62
+ return JSON.stringify(error);
63
+ } catch {
64
+ return String(error);
65
+ }
66
+ }
67
+
68
+ function toRemoteEventSource(nodeRecord: StoredNodeRecord): RemoteEventSource {
69
+ return {
70
+ hostId: nodeRecord.nodeId,
71
+ hostLabel: nodeRecord.nodeLabel,
72
+ hostKind: 'remote',
73
+ hostBaseUrl: nodeRecord.baseUrl,
74
+ };
75
+ }
76
+
77
+ function parseRemoteNodeEventEnvelope(payload: unknown): { event: unknown } | null {
78
+ if (!isRecord(payload)) {
79
+ return null;
80
+ }
81
+
82
+ if (payload['role'] !== 'node' || payload['protocolVersion'] !== NODE_PROTOCOL_VERSION) {
83
+ return null;
84
+ }
85
+
86
+ const source = payload['source'];
87
+ if (
88
+ !isRecord(source) ||
89
+ source['hostId'] !== 'local' ||
90
+ source['hostLabel'] !== 'Local' ||
91
+ source['hostKind'] !== 'local'
92
+ ) {
93
+ return null;
94
+ }
95
+
96
+ if (!('event' in payload)) {
97
+ return null;
98
+ }
99
+
100
+ return { event: payload['event'] };
101
+ }
102
+
103
+ async function connectLocalEventStreamWithTimeout(
104
+ port: number,
105
+ timeoutMs: number,
106
+ controller?: AbortController
107
+ ): Promise<ConnectedStream> {
108
+ const connectionController = controller ?? new AbortController();
109
+ const client = createOpencodeClient({ baseUrl: `http://localhost:${port}` });
110
+
111
+ let timerId: ReturnType<typeof setTimeout> | null = null;
112
+ const timeoutPromise = new Promise<never>((_, reject) => {
113
+ timerId = setTimeout(() => {
114
+ connectionController.abort();
115
+ reject(new Error(`OpenCode event stream preflight timed out for port ${port} after ${timeoutMs}ms`));
116
+ }, timeoutMs);
117
+ });
118
+
119
+ try {
120
+ const connection = await Promise.race([
121
+ client.global.event({ signal: connectionController.signal }),
122
+ timeoutPromise,
123
+ ]);
124
+
125
+ return {
126
+ key: `local:${port}`,
127
+ label: `OpenCode port ${port}`,
128
+ stream: connection.stream as AsyncIterable<unknown>,
129
+ controller: connectionController,
130
+ };
131
+ } finally {
132
+ if (timerId) {
133
+ clearTimeout(timerId);
134
+ }
135
+ }
136
+ }
137
+
138
+ async function readNodeFailureReason(response: Response): Promise<string> {
139
+ try {
140
+ const body = await response.json();
141
+ if (isRecord(body) && typeof body.reason === 'string' && body.reason.trim()) {
142
+ return body.reason;
143
+ }
144
+ } catch {
145
+ }
146
+
147
+ return `node_request_failed_${response.status}`;
148
+ }
149
+
150
+ function normalizeSseChunk(chunk: string): string {
151
+ return chunk.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
152
+ }
153
+
154
+ function readSseDataBlock(block: string): string | null {
155
+ const dataLines = normalizeSseChunk(block)
156
+ .split('\n')
157
+ .filter((line) => line.startsWith('data:'))
158
+ .map((line) => line.slice(5).trimStart());
159
+
160
+ return dataLines.length > 0 ? dataLines.join('\n') : null;
161
+ }
162
+
163
+ async function* streamRemoteNodeEvents(
164
+ body: ReadableStream<Uint8Array>,
165
+ source: RemoteEventSource,
166
+ label: string
167
+ ): AsyncIterable<unknown> {
168
+ const reader = body.getReader();
169
+ const decoder = new TextDecoder();
170
+ let buffer = '';
171
+
172
+ try {
173
+ while (true) {
174
+ const { done, value } = await reader.read();
175
+ if (done) {
176
+ break;
177
+ }
178
+
179
+ buffer += normalizeSseChunk(decoder.decode(value, { stream: true }));
180
+
181
+ let boundaryIndex = buffer.indexOf('\n\n');
182
+ while (boundaryIndex !== -1) {
183
+ const block = buffer.slice(0, boundaryIndex);
184
+ buffer = buffer.slice(boundaryIndex + 2);
185
+
186
+ const data = readSseDataBlock(block);
187
+ if (data) {
188
+ try {
189
+ const payload = JSON.parse(data) as unknown;
190
+ const envelope = parseRemoteNodeEventEnvelope(payload);
191
+ if (!envelope) {
192
+ console.warn('Ignoring malformed remote node SSE event from', label, payload);
193
+ } else {
194
+ yield {
195
+ source,
196
+ event: envelope.event,
197
+ };
198
+ }
199
+ } catch (error) {
200
+ console.warn('Failed to parse remote node SSE event from', label, error);
201
+ }
202
+ }
203
+
204
+ boundaryIndex = buffer.indexOf('\n\n');
205
+ }
206
+ }
207
+
208
+ buffer += normalizeSseChunk(decoder.decode());
209
+ const data = readSseDataBlock(buffer);
210
+ if (data) {
211
+ try {
212
+ const payload = JSON.parse(data) as unknown;
213
+ const envelope = parseRemoteNodeEventEnvelope(payload);
214
+ if (envelope) {
215
+ yield {
216
+ source,
217
+ event: envelope.event,
218
+ };
219
+ }
220
+ } catch (error) {
221
+ console.warn('Failed to parse trailing remote node SSE event from', label, error);
222
+ }
223
+ }
224
+ } finally {
225
+ try {
226
+ await reader.cancel();
227
+ } catch {
228
+ }
229
+ reader.releaseLock();
230
+ }
231
+ }
232
+
233
+ async function connectRemoteNodeEventStreamWithTimeout(
234
+ nodeRecord: StoredNodeRecord,
235
+ timeoutMs: number,
236
+ controller?: AbortController
237
+ ): Promise<ConnectedStream> {
238
+ const connectionController = controller ?? new AbortController();
239
+ const endpoint = `${nodeRecord.baseUrl}/api/node/events`;
240
+ const label = `node ${nodeRecord.nodeId}`;
241
+
242
+ let timerId: ReturnType<typeof setTimeout> | null = null;
243
+ const timeoutPromise = new Promise<never>((_, reject) => {
244
+ timerId = setTimeout(() => {
245
+ connectionController.abort();
246
+ reject(new Error(`Remote node event stream preflight timed out for ${nodeRecord.nodeId} after ${timeoutMs}ms`));
247
+ }, timeoutMs);
248
+ });
249
+
250
+ try {
251
+ const response = await Promise.race([
252
+ fetch(endpoint, {
253
+ method: 'GET',
254
+ headers: createNodeRequestHeaders(nodeRecord.token),
255
+ signal: connectionController.signal,
256
+ }),
257
+ timeoutPromise,
258
+ ]);
259
+
260
+ if (!response.ok) {
261
+ throw new Error(`Remote node event stream request failed for ${nodeRecord.nodeId}: ${await readNodeFailureReason(response)}`);
262
+ }
263
+
264
+ if (!response.body) {
265
+ throw new Error(`Remote node event stream missing response body for ${nodeRecord.nodeId}`);
266
+ }
267
+
268
+ return {
269
+ key: `remote:${nodeRecord.nodeId}`,
270
+ label,
271
+ stream: streamRemoteNodeEvents(response.body, toRemoteEventSource(nodeRecord), label),
272
+ controller: connectionController,
273
+ };
274
+ } finally {
275
+ if (timerId) {
276
+ clearTimeout(timerId);
277
+ }
278
+ }
279
+ }
280
+
281
+ function createLocalUnavailableResponse(timedOut: boolean): Response {
282
+ if (timedOut) {
283
+ return Response.json(
284
+ {
285
+ error: 'OpenCode discovery timed out',
286
+ hint: 'Host process discovery exceeded timeout. Retry shortly, or increase OPENCODE_DISCOVERY_TIMEOUT_MS.',
287
+ },
288
+ { status: 503 }
289
+ );
290
+ }
291
+
292
+ return Response.json(
293
+ {
294
+ error: 'OpenCode server not found',
295
+ hint: 'Make sure OpenCode is running with an exposed API port. Example: opencode --port <PORT> (VibePulse auto-detects active ports).',
296
+ },
297
+ { status: 503 }
298
+ );
299
+ }
300
+
301
+ function createAllSourcesUnavailableResponse(): Response {
302
+ return Response.json(
303
+ {
304
+ error: 'Failed to connect to OpenCode event streams',
305
+ hint: 'Detected local and/or remote node event sources, but every streaming handshake failed. Ensure the hub can reach each source and retry.',
306
+ },
307
+ { status: 503 }
308
+ );
309
+ }
310
+
311
+ function buildStreamSourceSpecs(ports: number[], nodes: StoredNodeRecord[], timeoutMs: number): StreamSourceSpec[] {
312
+ const localSpecs = ports.map((port) => ({
313
+ key: `local:${port}`,
314
+ label: `OpenCode port ${port}`,
315
+ connect: (controller?: AbortController) => connectLocalEventStreamWithTimeout(port, timeoutMs, controller),
316
+ }));
317
+
318
+ const remoteSpecs = nodes
319
+ .filter((node) => node.enabled)
320
+ .map((node) => ({
321
+ key: `remote:${node.nodeId}`,
322
+ label: `node ${node.nodeId}`,
323
+ connect: (controller?: AbortController) => connectRemoteNodeEventStreamWithTimeout(node, timeoutMs, controller),
324
+ }));
325
+
326
+ return [...localSpecs, ...remoteSpecs];
327
+ }
328
+
329
+ export const dynamic = 'force-dynamic';
330
+
331
+ export async function GET(request: Request) {
332
+ const encoder = new TextEncoder();
333
+ const { ports, timedOut } = discoverOpencodePortsWithMeta();
334
+ const isNodeMode = process.env[RUNTIME_ROLE_ENV_VAR] === 'node';
335
+ const nodeRecords = isNodeMode ? [] : await listNodeRecords();
336
+ const preflightTimeoutMs = getPreflightTimeoutMs();
337
+ const sourceSpecs = buildStreamSourceSpecs(ports, nodeRecords, preflightTimeoutMs);
338
+
339
+ if (sourceSpecs.length === 0) {
340
+ return createLocalUnavailableResponse(timedOut);
341
+ }
342
+
343
+ try {
344
+ const preflightControllers = new Map<string, AbortController>();
345
+ const preflightAttempts = sourceSpecs.map((sourceSpec) => {
346
+ const controller = new AbortController();
347
+ preflightControllers.set(sourceSpec.key, controller);
348
+ return sourceSpec.connect(controller);
349
+ });
350
+
351
+ const firstConnectedStream = await Promise.any(preflightAttempts).catch(async () => {
352
+ const settled = await Promise.allSettled(preflightAttempts);
353
+ for (const result of settled) {
354
+ if (result.status === 'rejected') {
355
+ console.warn('Failed to connect to event source during preflight:', formatErrorForLog(result.reason));
356
+ }
357
+ }
358
+ return null;
359
+ });
360
+
361
+ if (!firstConnectedStream) {
362
+ if (ports.length === 0 && nodeRecords.filter((node) => node.enabled).length === 0) {
363
+ return createLocalUnavailableResponse(timedOut);
364
+ }
365
+
366
+ return createAllSourcesUnavailableResponse();
367
+ }
368
+
369
+ for (const [key, controller] of preflightControllers.entries()) {
370
+ if (key !== firstConnectedStream.key) {
371
+ controller.abort();
372
+ }
373
+ }
374
+
375
+ let teardown: (() => void) | null = null;
376
+ const stream = new ReadableStream({
377
+ async start(controller) {
378
+ let isClosed = false;
379
+ const activeControllers = new Set<AbortController>([firstConnectedStream.controller]);
380
+ const activeIterators = new Set<AsyncIterator<unknown>>();
381
+
382
+ const enqueueEvent = (event: unknown) => {
383
+ try {
384
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
385
+ return true;
386
+ } catch {
387
+ return false;
388
+ }
389
+ };
390
+
391
+ const closeControllerSafely = () => {
392
+ try {
393
+ controller.close();
394
+ } catch {
395
+ }
396
+ };
397
+
398
+ const onAbort = () => {
399
+ if (teardown) {
400
+ teardown();
401
+ return;
402
+ }
403
+
404
+ isClosed = true;
405
+ closeControllerSafely();
406
+ };
407
+
408
+ teardown = () => {
409
+ isClosed = true;
410
+ for (const activeController of activeControllers) {
411
+ activeController.abort();
412
+ }
413
+ void Promise.allSettled(Array.from(activeIterators).map((iterator) => iterator.return?.()));
414
+ request.signal.removeEventListener('abort', onAbort);
415
+ closeControllerSafely();
416
+ };
417
+
418
+ request.signal.addEventListener('abort', onAbort);
419
+
420
+ const streamEvents = async (connected: ConnectedStream) => {
421
+ const iterator = connected.stream[Symbol.asyncIterator]();
422
+ activeIterators.add(iterator);
423
+
424
+ try {
425
+ while (!isClosed) {
426
+ const next = await iterator.next();
427
+ if (next.done) {
428
+ break;
429
+ }
430
+ if (isClosed) {
431
+ break;
432
+ }
433
+ if (!enqueueEvent(next.value)) {
434
+ break;
435
+ }
436
+ }
437
+ } catch (error) {
438
+ if (!isClosed && !request.signal.aborted && !isAbortLikeError(error)) {
439
+ console.warn('Event stream failed for source:', connected.label, formatErrorForLog(error));
440
+ }
441
+ } finally {
442
+ activeIterators.delete(iterator);
443
+ activeControllers.delete(connected.controller);
444
+ }
445
+ };
446
+
447
+ try {
448
+ const primaryTask = streamEvents(firstConnectedStream);
449
+
450
+ const secondaryTasks = sourceSpecs
451
+ .filter((sourceSpec) => sourceSpec.key !== firstConnectedStream.key)
452
+ .map(async (sourceSpec) => {
453
+ if (isClosed) {
454
+ return;
455
+ }
456
+
457
+ try {
458
+ const connected = await sourceSpec.connect();
459
+ activeControllers.add(connected.controller);
460
+ if (isClosed) {
461
+ connected.controller.abort();
462
+ activeControllers.delete(connected.controller);
463
+ return;
464
+ }
465
+ await streamEvents(connected);
466
+ } catch (error) {
467
+ if (!isClosed && !request.signal.aborted && !isAbortLikeError(error)) {
468
+ console.warn('Failed to connect to secondary event source:', sourceSpec.label, formatErrorForLog(error));
469
+ }
470
+ }
471
+ });
472
+
473
+ await Promise.allSettled([primaryTask, ...secondaryTasks]);
474
+ } catch (error) {
475
+ console.error('Error in event stream:', error);
476
+ } finally {
477
+ isClosed = true;
478
+ teardown = null;
479
+ request.signal.removeEventListener('abort', onAbort);
480
+ closeControllerSafely();
481
+ }
482
+ },
483
+ cancel() {
484
+ if (teardown) {
485
+ teardown();
486
+ }
487
+ },
488
+ });
489
+
490
+ return new Response(stream, {
491
+ headers: {
492
+ 'Content-Type': 'text/event-stream',
493
+ 'Cache-Control': 'no-cache',
494
+ Connection: 'keep-alive',
495
+ },
496
+ });
497
+ } catch (error) {
498
+ console.error('Error creating event stream:', error);
499
+ return Response.json(
500
+ {
501
+ error: 'Failed to create event stream',
502
+ details: error instanceof Error ? error.message : String(error),
503
+ hint: 'Make sure OpenCode is running with an exposed API port. Example: opencode --port <PORT> (VibePulse auto-detects active ports).',
504
+ },
505
+ { status: 500 }
506
+ );
507
+ }
508
+ }
@@ -0,0 +1,167 @@
1
+ import { describe, it, expect, vi, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
2
+ import type { ExecException } from 'child_process';
3
+ import { handleExecResult, GET, setExecFn } from './route';
4
+
5
+ type ExecCallback = (error: ExecException | null, stdout: string, stderr: string) => void;
6
+
7
+ type MockExecFn = (cmd: string, opts: unknown, callback: ExecCallback) => void;
8
+
9
+ describe('/api/opencode-models', () => {
10
+ describe('handleExecResult', () => {
11
+ it('should return error when CLI does not exist', () => {
12
+ const error = new Error('spawn opencode ENOENT') as ExecException;
13
+ const result = handleExecResult(error, '', 'command not found');
14
+
15
+ expect(result.source).toBe('error');
16
+ expect(result.models).toEqual([]);
17
+ expect(result.error).toBeTruthy();
18
+ });
19
+
20
+ it('should return error on timeout', () => {
21
+ const error = new Error('timeout') as ExecException;
22
+ const result = handleExecResult(error, '', '');
23
+
24
+ expect(result.source).toBe('error');
25
+ expect(result.models).toEqual([]);
26
+ });
27
+
28
+ it('should return error on empty output', () => {
29
+ const result = handleExecResult(null, '', '');
30
+
31
+ expect(result.source).toBe('error');
32
+ expect(result.models).toEqual([]);
33
+ expect(result.error).toContain('No models found');
34
+ });
35
+
36
+ it('should return models when only stderr but stdout is valid', () => {
37
+ const result = handleExecResult(null, 'anthropic/claude\nopenai/gpt-4', 'some warning from CLI');
38
+
39
+ expect(result.source).toBe('opencode');
40
+ expect(result.models).toContain('anthropic/claude');
41
+ });
42
+
43
+ it('should return error when only stderr and stdout is empty', () => {
44
+ const result = handleExecResult(null, '', 'some error in stderr');
45
+
46
+ expect(result.source).toBe('error');
47
+ expect(result.models).toEqual([]);
48
+ });
49
+
50
+ it('should return CLI models in normal case', () => {
51
+ const result = handleExecResult(null, 'anthropic/claude\nopenai/gpt-4', '');
52
+
53
+ expect(result.source).toBe('opencode');
54
+ expect(result.models).toContain('anthropic/claude');
55
+ });
56
+ });
57
+
58
+ describe('GET API Integration Tests', () => {
59
+ const originalHome = process.env.HOME;
60
+ const originalPath = process.env.PATH;
61
+ const originalModelsTimeout = process.env.OPENCODE_MODELS_TIMEOUT_MS;
62
+
63
+ let mockExec: MockExecFn & {
64
+ mockImplementation: (impl: MockExecFn) => void;
65
+ mock: { calls: unknown[][] };
66
+ };
67
+
68
+ beforeAll(() => {
69
+ process.env.HOME = '/tmp';
70
+ process.env.PATH = '/usr/bin';
71
+ delete process.env.OPENCODE_MODELS_TIMEOUT_MS;
72
+ });
73
+
74
+ afterAll(() => {
75
+ process.env.HOME = originalHome;
76
+ process.env.PATH = originalPath;
77
+ if (originalModelsTimeout === undefined) {
78
+ delete process.env.OPENCODE_MODELS_TIMEOUT_MS;
79
+ } else {
80
+ process.env.OPENCODE_MODELS_TIMEOUT_MS = originalModelsTimeout;
81
+ }
82
+ });
83
+
84
+ beforeEach(() => {
85
+ mockExec = vi.fn() as unknown as MockExecFn & {
86
+ mockImplementation: (impl: MockExecFn) => void;
87
+ mock: { calls: unknown[][] };
88
+ };
89
+ setExecFn(mockExec as never);
90
+ });
91
+
92
+ afterEach(() => {
93
+ setExecFn(null);
94
+ });
95
+
96
+ it('should return source=opencode and real model list on successful GET', async () => {
97
+ mockExec.mockImplementation((_cmd: unknown, _opts: unknown, callback: ExecCallback) => {
98
+ callback(null, 'anthropic/claude-3.5-sonnet\nopenai/gpt-4o\ndeepseek/deepseek-chat\n', '');
99
+ });
100
+
101
+ const response = await GET();
102
+ const data = await response.json();
103
+ const call = mockExec.mock.calls[0] as [string, { timeout: number }, ExecCallback] | undefined;
104
+
105
+ expect(response.status).toBe(200);
106
+ expect(data.source).toBe('opencode');
107
+ expect(data.models).toContain('anthropic/claude-3.5-sonnet');
108
+ expect(call?.[0]).toBe('opencode models');
109
+ expect(call?.[1]?.timeout).toBe(15000);
110
+ expect(typeof call?.[2]).toBe('function');
111
+ });
112
+
113
+ it('should use OPENCODE_MODELS_TIMEOUT_MS when valid', async () => {
114
+ process.env.OPENCODE_MODELS_TIMEOUT_MS = '30000';
115
+ mockExec.mockImplementation((_cmd: unknown, _opts: unknown, callback: ExecCallback) => {
116
+ callback(null, 'anthropic/claude-3.5-sonnet\n', '');
117
+ });
118
+
119
+ const response = await GET();
120
+ const call = mockExec.mock.calls[0] as [string, { timeout: number }, ExecCallback] | undefined;
121
+ expect(response.status).toBe(200);
122
+ expect(call?.[0]).toBe('opencode models');
123
+ expect(call?.[1]?.timeout).toBe(30000);
124
+ expect(typeof call?.[2]).toBe('function');
125
+ delete process.env.OPENCODE_MODELS_TIMEOUT_MS;
126
+ });
127
+
128
+ it('should return source=opencode when CLI has stderr but stdout is valid', async () => {
129
+ mockExec.mockImplementation((_cmd: unknown, _opts: unknown, callback: ExecCallback) => {
130
+ callback(null, 'anthropic/claude-3.5-sonnet\n', 'Warning: newer version available');
131
+ });
132
+
133
+ const response = await GET();
134
+ const data = await response.json();
135
+
136
+ expect(response.status).toBe(200);
137
+ expect(data.source).toBe('opencode');
138
+ });
139
+
140
+ it('should return 503 with error payload when CLI fails', async () => {
141
+ mockExec.mockImplementation((_cmd: unknown, _opts: unknown, callback: ExecCallback) => {
142
+ callback(new Error('spawn opencode ENOENT') as ExecException, '', 'command not found');
143
+ });
144
+
145
+ const response = await GET();
146
+ const data = await response.json();
147
+
148
+ expect(response.status).toBe(503);
149
+ expect(data.source).toBe('error');
150
+ expect(data.models).toEqual([]);
151
+ expect(data.error).toBeTruthy();
152
+ });
153
+
154
+ it('should return 503 with error payload when GET returns empty models', async () => {
155
+ mockExec.mockImplementation((_cmd: unknown, _opts: unknown, callback: ExecCallback) => {
156
+ callback(null, '', '');
157
+ });
158
+
159
+ const response = await GET();
160
+ const data = await response.json();
161
+
162
+ expect(response.status).toBe(503);
163
+ expect(data.source).toBe('error');
164
+ expect(data.models).toEqual([]);
165
+ });
166
+ });
167
+ });