vibepulse 0.1.12 → 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 (547) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -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 +56 -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/app-paths-manifest.json +3 -0
  32. package/.next/server/app/api/node/events/route/build-manifest.json +11 -0
  33. package/.next/server/app/api/node/events/route/server-reference-manifest.json +4 -0
  34. package/.next/server/app/api/node/events/route.js +7 -0
  35. package/.next/server/app/api/node/events/route.js.map +5 -0
  36. package/.next/server/app/api/node/events/route.js.nft.json +1 -0
  37. package/.next/server/app/api/node/events/route_client-reference-manifest.js +2 -0
  38. package/.next/server/app/api/node/health/route/app-paths-manifest.json +3 -0
  39. package/.next/server/app/api/node/health/route/build-manifest.json +11 -0
  40. package/.next/server/app/api/node/health/route/server-reference-manifest.json +4 -0
  41. package/.next/server/app/api/node/health/route.js +6 -0
  42. package/.next/server/app/api/node/health/route.js.map +5 -0
  43. package/.next/server/app/api/node/health/route.js.nft.json +1 -0
  44. package/.next/server/app/api/node/health/route_client-reference-manifest.js +2 -0
  45. package/.next/server/app/api/node/sessions/[id]/archive/route/app-paths-manifest.json +3 -0
  46. package/.next/server/app/api/node/sessions/[id]/archive/route/build-manifest.json +11 -0
  47. package/.next/server/app/api/node/sessions/[id]/archive/route/server-reference-manifest.json +4 -0
  48. package/.next/server/app/api/node/sessions/[id]/archive/route.js +6 -0
  49. package/.next/server/app/api/node/sessions/[id]/archive/route.js.map +5 -0
  50. package/.next/server/app/api/node/sessions/[id]/archive/route.js.nft.json +1 -0
  51. package/.next/server/app/api/node/sessions/[id]/archive/route_client-reference-manifest.js +2 -0
  52. package/.next/server/app/api/node/sessions/[id]/delete/route/app-paths-manifest.json +3 -0
  53. package/.next/server/app/api/node/sessions/[id]/delete/route/build-manifest.json +11 -0
  54. package/.next/server/app/api/node/sessions/[id]/delete/route/server-reference-manifest.json +4 -0
  55. package/.next/server/app/api/node/sessions/[id]/delete/route.js +7 -0
  56. package/.next/server/app/api/node/sessions/[id]/delete/route.js.map +5 -0
  57. package/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -0
  58. package/.next/server/app/api/node/sessions/[id]/delete/route_client-reference-manifest.js +2 -0
  59. package/.next/server/app/api/node/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  60. package/.next/server/app/api/node/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  61. package/.next/server/app/api/node/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  62. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js +7 -0
  63. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js.map +5 -0
  64. package/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -0
  65. package/.next/server/app/api/node/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  66. package/.next/server/app/api/node/sessions/route/app-paths-manifest.json +3 -0
  67. package/.next/server/app/api/node/sessions/route/build-manifest.json +11 -0
  68. package/.next/server/app/api/node/sessions/route/server-reference-manifest.json +4 -0
  69. package/.next/server/app/api/node/sessions/route.js +9 -0
  70. package/.next/server/app/api/node/sessions/route.js.map +5 -0
  71. package/.next/server/app/api/node/sessions/route.js.nft.json +1 -0
  72. package/.next/server/app/api/node/sessions/route_client-reference-manifest.js +2 -0
  73. package/.next/server/app/api/nodes/route/app-paths-manifest.json +3 -0
  74. package/.next/server/app/api/nodes/route/build-manifest.json +11 -0
  75. package/.next/server/app/api/nodes/route/server-reference-manifest.json +4 -0
  76. package/.next/server/app/api/nodes/route.js +8 -0
  77. package/.next/server/app/api/nodes/route.js.map +5 -0
  78. package/.next/server/app/api/nodes/route.js.nft.json +1 -0
  79. package/.next/server/app/api/nodes/route_client-reference-manifest.js +2 -0
  80. package/.next/server/app/api/opencode-config/route.js +1 -1
  81. package/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
  82. package/.next/server/app/api/opencode-config/status/route.js +1 -1
  83. package/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
  84. package/.next/server/app/api/opencode-events/route.js +4 -2
  85. package/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
  86. package/.next/server/app/api/profiles/[id]/apply/route.js +1 -1
  87. package/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
  88. package/.next/server/app/api/profiles/[id]/export/route.js +2 -2
  89. package/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
  90. package/.next/server/app/api/profiles/[id]/route.js +2 -2
  91. package/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
  92. package/.next/server/app/api/profiles/import/route.js +2 -2
  93. package/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
  94. package/.next/server/app/api/profiles/route.js +2 -2
  95. package/.next/server/app/api/profiles/route.js.nft.json +1 -1
  96. package/.next/server/app/api/sessions/[id]/archive/route.js +2 -1
  97. package/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  98. package/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  99. package/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  100. package/.next/server/app/api/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  101. package/.next/server/app/api/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  102. package/.next/server/app/api/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  103. package/.next/server/app/api/sessions/[id]/open-editor/route.js +7 -0
  104. package/.next/server/app/api/sessions/[id]/open-editor/route.js.map +5 -0
  105. package/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -0
  106. package/.next/server/app/api/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  107. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  108. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  109. package/.next/server/app/api/sessions/route.js +3 -3
  110. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  111. package/.next/server/app/favicon.ico/route.js +1 -1
  112. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  113. package/.next/server/app/index.html +1 -1
  114. package/.next/server/app/index.rsc +3 -3
  115. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  116. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  117. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  118. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  119. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  120. package/.next/server/app/page.js +1 -1
  121. package/.next/server/app/page.js.nft.json +1 -1
  122. package/.next/server/app/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app-paths-manifest.json +8 -0
  124. package/.next/server/chunks/{[root-of-the-server]__172a07b6._.js → [externals]_next_dist_84e7390b._.js} +2 -2
  125. package/.next/server/chunks/[root-of-the-server]__1211da38._.js +3 -0
  126. package/.next/server/chunks/[root-of-the-server]__1211da38._.js.map +1 -0
  127. package/.next/server/chunks/[root-of-the-server]__192ed2f4._.js +3 -0
  128. package/.next/server/chunks/[root-of-the-server]__192ed2f4._.js.map +1 -0
  129. package/.next/server/chunks/[root-of-the-server]__1b87ec42._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1b87ec42._.js.map +1 -0
  131. package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +3 -0
  132. package/.next/server/chunks/[root-of-the-server]__2b526e7a._.js.map +1 -0
  133. package/.next/server/chunks/[root-of-the-server]__2f981540._.js +3 -0
  134. package/.next/server/chunks/[root-of-the-server]__2f981540._.js.map +1 -0
  135. package/.next/server/chunks/[root-of-the-server]__3745b314._.js +3 -0
  136. package/.next/server/chunks/[root-of-the-server]__3745b314._.js.map +1 -0
  137. package/.next/server/chunks/[root-of-the-server]__56690af0._.js +3 -0
  138. package/.next/server/chunks/[root-of-the-server]__56690af0._.js.map +1 -0
  139. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js +3 -0
  140. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js.map +1 -0
  141. package/.next/server/chunks/[root-of-the-server]__59175de4._.js +3 -0
  142. package/.next/server/chunks/[root-of-the-server]__59175de4._.js.map +1 -0
  143. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js +3 -0
  144. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js.map +1 -0
  145. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js +3 -0
  146. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js.map +1 -0
  147. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js +3 -0
  148. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js.map +1 -0
  149. package/.next/server/chunks/[root-of-the-server]__7e757f50._.js +3 -0
  150. package/.next/server/chunks/[root-of-the-server]__7e757f50._.js.map +1 -0
  151. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +3 -0
  152. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js.map +1 -0
  153. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +3 -0
  154. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js.map +1 -0
  155. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js +3 -0
  156. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js.map +1 -0
  157. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +3 -0
  158. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js.map +1 -0
  159. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js +3 -0
  160. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js.map +1 -0
  161. package/.next/server/chunks/[root-of-the-server]__db285678._.js +3 -0
  162. package/.next/server/chunks/[root-of-the-server]__db285678._.js.map +1 -0
  163. package/.next/server/chunks/[root-of-the-server]__e00a9200._.js +5 -0
  164. package/.next/server/chunks/[root-of-the-server]__e00a9200._.js.map +1 -0
  165. package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +3 -0
  166. package/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js.map +1 -0
  167. package/.next/server/chunks/_next-internal_server_app_api_node_events_route_actions_f1abd32d.js +3 -0
  168. package/.next/server/chunks/_next-internal_server_app_api_node_events_route_actions_f1abd32d.js.map +1 -0
  169. package/.next/server/chunks/_next-internal_server_app_api_node_health_route_actions_c4c4c077.js +3 -0
  170. package/.next/server/chunks/_next-internal_server_app_api_node_health_route_actions_c4c4c077.js.map +1 -0
  171. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js +3 -0
  172. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js.map +1 -0
  173. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js +3 -0
  174. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js.map +1 -0
  175. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_route_actions_6b564c5a.js +3 -0
  176. package/.next/server/chunks/_next-internal_server_app_api_node_sessions_route_actions_6b564c5a.js.map +1 -0
  177. package/.next/server/chunks/_next-internal_server_app_api_nodes_route_actions_3e496ee8.js +3 -0
  178. package/.next/server/chunks/_next-internal_server_app_api_nodes_route_actions_3e496ee8.js.map +1 -0
  179. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js +3 -0
  180. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js.map +1 -0
  181. package/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js +3 -0
  182. package/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js.map +1 -0
  183. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
  184. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js.map +1 -1
  185. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +3 -0
  186. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js.map +1 -0
  187. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  188. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js.map +1 -1
  189. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +5 -0
  190. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js.map +1 -0
  191. package/.next/{standalone/.next/server/chunks/ssr/[root-of-the-server]__39eef6a5._.js → server/chunks/ssr/[root-of-the-server]__631e12d0._.js} +2 -2
  192. package/.next/{standalone/.next/server/chunks/ssr/[root-of-the-server]__535a2208._.js → server/chunks/ssr/[root-of-the-server]__a8cd3911._.js} +2 -2
  193. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
  194. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js.map +1 -1
  195. package/.next/server/pages/404.html +1 -1
  196. package/.next/server/pages/500.html +2 -2
  197. package/.next/server/server-reference-manifest.js +1 -1
  198. package/.next/server/server-reference-manifest.json +1 -1
  199. package/.next/standalone/.next/BUILD_ID +1 -1
  200. package/.next/standalone/.next/app-path-routes-manifest.json +8 -0
  201. package/.next/standalone/.next/build-manifest.json +2 -2
  202. package/.next/standalone/.next/prerender-manifest.json +3 -3
  203. package/.next/standalone/.next/routes-manifest.json +56 -0
  204. package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
  205. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  206. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  207. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  208. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  209. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  210. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  211. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  212. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  213. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  214. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  215. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  216. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  217. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  218. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  219. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  220. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  221. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  222. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  223. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  224. package/.next/standalone/.next/server/app/api/node/events/route/app-paths-manifest.json +3 -0
  225. package/.next/standalone/.next/server/app/api/node/events/route/build-manifest.json +11 -0
  226. package/.next/standalone/.next/server/app/api/node/events/route/server-reference-manifest.json +4 -0
  227. package/.next/standalone/.next/server/app/api/node/events/route.js +7 -0
  228. package/.next/standalone/.next/server/app/api/node/events/route.js.map +5 -0
  229. package/.next/standalone/.next/server/app/api/node/events/route.js.nft.json +1 -0
  230. package/.next/standalone/.next/server/app/api/node/events/route_client-reference-manifest.js +2 -0
  231. package/.next/standalone/.next/server/app/api/node/health/route/app-paths-manifest.json +3 -0
  232. package/.next/standalone/.next/server/app/api/node/health/route/build-manifest.json +11 -0
  233. package/.next/standalone/.next/server/app/api/node/health/route/server-reference-manifest.json +4 -0
  234. package/.next/standalone/.next/server/app/api/node/health/route.js +6 -0
  235. package/.next/standalone/.next/server/app/api/node/health/route.js.map +5 -0
  236. package/.next/standalone/.next/server/app/api/node/health/route.js.nft.json +1 -0
  237. package/.next/standalone/.next/server/app/api/node/health/route_client-reference-manifest.js +2 -0
  238. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/app-paths-manifest.json +3 -0
  239. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/build-manifest.json +11 -0
  240. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route/server-reference-manifest.json +4 -0
  241. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js +6 -0
  242. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js.map +5 -0
  243. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route.js.nft.json +1 -0
  244. package/.next/standalone/.next/server/app/api/node/sessions/[id]/archive/route_client-reference-manifest.js +2 -0
  245. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/app-paths-manifest.json +3 -0
  246. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/build-manifest.json +11 -0
  247. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route/server-reference-manifest.json +4 -0
  248. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js +7 -0
  249. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js.map +5 -0
  250. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route.js.nft.json +1 -0
  251. package/.next/standalone/.next/server/app/api/node/sessions/[id]/delete/route_client-reference-manifest.js +2 -0
  252. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  253. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  254. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  255. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js +7 -0
  256. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.map +5 -0
  257. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -0
  258. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  259. package/.next/standalone/.next/server/app/api/node/sessions/route/app-paths-manifest.json +3 -0
  260. package/.next/standalone/.next/server/app/api/node/sessions/route/build-manifest.json +11 -0
  261. package/.next/standalone/.next/server/app/api/node/sessions/route/server-reference-manifest.json +4 -0
  262. package/.next/standalone/.next/server/app/api/node/sessions/route.js +9 -0
  263. package/.next/standalone/.next/server/app/api/node/sessions/route.js.map +5 -0
  264. package/.next/standalone/.next/server/app/api/node/sessions/route.js.nft.json +1 -0
  265. package/.next/standalone/.next/server/app/api/node/sessions/route_client-reference-manifest.js +2 -0
  266. package/.next/standalone/.next/server/app/api/nodes/route/app-paths-manifest.json +3 -0
  267. package/.next/standalone/.next/server/app/api/nodes/route/build-manifest.json +11 -0
  268. package/.next/standalone/.next/server/app/api/nodes/route/server-reference-manifest.json +4 -0
  269. package/.next/standalone/.next/server/app/api/nodes/route.js +8 -0
  270. package/.next/standalone/.next/server/app/api/nodes/route.js.map +5 -0
  271. package/.next/standalone/.next/server/app/api/nodes/route.js.nft.json +1 -0
  272. package/.next/standalone/.next/server/app/api/nodes/route_client-reference-manifest.js +2 -0
  273. package/.next/standalone/.next/server/app/api/opencode-config/route.js +1 -1
  274. package/.next/standalone/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
  275. package/.next/standalone/.next/server/app/api/opencode-config/status/route.js +1 -1
  276. package/.next/standalone/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
  277. package/.next/standalone/.next/server/app/api/opencode-events/route.js +4 -2
  278. package/.next/standalone/.next/server/app/api/opencode-events/route.js.nft.json +1 -1
  279. package/.next/standalone/.next/server/app/api/profiles/[id]/apply/route.js +1 -1
  280. package/.next/standalone/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
  281. package/.next/standalone/.next/server/app/api/profiles/[id]/export/route.js +2 -2
  282. package/.next/standalone/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
  283. package/.next/standalone/.next/server/app/api/profiles/[id]/route.js +2 -2
  284. package/.next/standalone/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
  285. package/.next/standalone/.next/server/app/api/profiles/import/route.js +2 -2
  286. package/.next/standalone/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
  287. package/.next/standalone/.next/server/app/api/profiles/route.js +2 -2
  288. package/.next/standalone/.next/server/app/api/profiles/route.js.nft.json +1 -1
  289. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js +2 -1
  290. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  291. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  292. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  293. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/app-paths-manifest.json +3 -0
  294. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/build-manifest.json +11 -0
  295. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route/server-reference-manifest.json +4 -0
  296. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js +7 -0
  297. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.map +5 -0
  298. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -0
  299. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route_client-reference-manifest.js +2 -0
  300. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js +1 -1
  301. package/.next/standalone/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  302. package/.next/standalone/.next/server/app/api/sessions/route.js +3 -3
  303. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  304. package/.next/standalone/.next/server/app/favicon.ico/route.js +1 -1
  305. package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  306. package/.next/standalone/.next/server/app/index.html +1 -1
  307. package/.next/standalone/.next/server/app/index.rsc +3 -3
  308. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  309. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  310. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  311. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  312. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  313. package/.next/standalone/.next/server/app/page.js +1 -1
  314. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  315. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  316. package/.next/standalone/.next/server/app-paths-manifest.json +8 -0
  317. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__172a07b6._.js → [externals]_next_dist_84e7390b._.js} +2 -2
  318. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1211da38._.js +3 -0
  319. package/.next/standalone/.next/server/chunks/[root-of-the-server]__192ed2f4._.js +3 -0
  320. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b87ec42._.js +3 -0
  321. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2b526e7a._.js +3 -0
  322. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f981540._.js +3 -0
  323. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3745b314._.js +3 -0
  324. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56690af0._.js +3 -0
  325. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56f5f249._.js +3 -0
  326. package/.next/standalone/.next/server/chunks/[root-of-the-server]__59175de4._.js +3 -0
  327. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64fffc02._.js +3 -0
  328. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c428a24._.js +3 -0
  329. package/.next/standalone/.next/server/chunks/[root-of-the-server]__73a00b88._.js +3 -0
  330. package/.next/standalone/.next/server/chunks/[root-of-the-server]__7e757f50._.js +3 -0
  331. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +3 -0
  332. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +3 -0
  333. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b796d06c._.js +3 -0
  334. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +3 -0
  335. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8e61048._.js +3 -0
  336. package/.next/standalone/.next/server/chunks/[root-of-the-server]__db285678._.js +3 -0
  337. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e00a9200._.js +5 -0
  338. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e5df5e5f._.js +3 -0
  339. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_events_route_actions_f1abd32d.js +3 -0
  340. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_health_route_actions_c4c4c077.js +3 -0
  341. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_archive_route_actions_237255a5.js +3 -0
  342. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_sessions_[id]_delete_route_actions_e5d426f6.js +3 -0
  343. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_node_sessions_route_actions_6b564c5a.js +3 -0
  344. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_nodes_route_actions_3e496ee8.js +3 -0
  345. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_open-editor_route_actions_eaebf476.js +3 -0
  346. package/.next/standalone/.next/server/chunks/ce889_server_app_api_node_sessions_[id]_open-editor_route_actions_791cdf5b.js +3 -0
  347. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7e181e75.js +1 -1
  348. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +3 -0
  349. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  350. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_fa835ac3.js +5 -0
  351. package/.next/{server/chunks/ssr/[root-of-the-server]__39eef6a5._.js → standalone/.next/server/chunks/ssr/[root-of-the-server]__631e12d0._.js} +2 -2
  352. package/.next/{server/chunks/ssr/[root-of-the-server]__535a2208._.js → standalone/.next/server/chunks/ssr/[root-of-the-server]__a8cd3911._.js} +2 -2
  353. package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +3 -3
  354. package/.next/standalone/.next/server/pages/404.html +1 -1
  355. package/.next/standalone/.next/server/pages/500.html +2 -2
  356. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  357. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  358. package/.next/standalone/.next/static/chunks/7ac19aaef01f4a03.js +13 -0
  359. package/.next/standalone/.next/static/chunks/f42202943f6742e5.css +3 -0
  360. package/.next/standalone/AGENTS.md +85 -0
  361. package/.next/standalone/README.md +76 -0
  362. package/.next/standalone/__mocks__/child_process.ts +4 -0
  363. package/.next/standalone/bin/dev-runtime.js +58 -0
  364. package/.next/standalone/bin/vibepulse.js +87 -0
  365. package/.next/standalone/check-hsql.mjs +71 -0
  366. package/.next/standalone/docs/session-status-detection.md +258 -0
  367. package/.next/standalone/eslint.config.mjs +31 -0
  368. package/.next/standalone/next.config.ts +8 -0
  369. package/.next/standalone/package-lock.json +10312 -0
  370. package/.next/standalone/package.json +4 -2
  371. package/.next/standalone/postcss.config.mjs +7 -0
  372. package/.next/standalone/public/readme-cover.png +0 -0
  373. package/.next/standalone/src/AGENTS.md +41 -0
  374. package/.next/standalone/src/app/api/AGENTS.md +40 -0
  375. package/.next/standalone/src/app/api/node/events/route.test.ts +196 -0
  376. package/.next/standalone/src/app/api/node/events/route.ts +259 -0
  377. package/.next/standalone/src/app/api/node/health/route.test.ts +190 -0
  378. package/.next/standalone/src/app/api/node/health/route.ts +48 -0
  379. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.test.ts +128 -0
  380. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.ts +97 -0
  381. package/.next/standalone/src/app/api/node/sessions/[id]/delete/route.test.ts +113 -0
  382. package/.next/standalone/src/app/api/node/sessions/[id]/delete/route.ts +81 -0
  383. package/.next/standalone/src/app/api/node/sessions/[id]/open-editor/route.test.ts +206 -0
  384. package/.next/standalone/src/app/api/node/sessions/[id]/open-editor/route.ts +123 -0
  385. package/.next/standalone/src/app/api/node/sessions/route.test.ts +408 -0
  386. package/.next/standalone/src/app/api/node/sessions/route.ts +1094 -0
  387. package/.next/standalone/src/app/api/nodes/route.test.ts +237 -0
  388. package/.next/standalone/src/app/api/nodes/route.ts +176 -0
  389. package/.next/standalone/src/app/api/opencode-config/route.test.ts +86 -0
  390. package/.next/standalone/src/app/api/opencode-config/route.ts +376 -0
  391. package/.next/standalone/src/app/api/opencode-config/status/route.ts +31 -0
  392. package/.next/standalone/src/app/api/opencode-events/route.test.ts +624 -0
  393. package/.next/standalone/src/app/api/opencode-events/route.ts +508 -0
  394. package/.next/standalone/src/app/api/opencode-models/route.test.ts +167 -0
  395. package/.next/standalone/src/app/api/opencode-models/route.ts +76 -0
  396. package/.next/standalone/src/app/api/profiles/[id]/apply/route.ts +49 -0
  397. package/.next/standalone/src/app/api/profiles/[id]/export/route.ts +31 -0
  398. package/.next/standalone/src/app/api/profiles/[id]/route.ts +160 -0
  399. package/.next/standalone/src/app/api/profiles/import/route.test.js +107 -0
  400. package/.next/standalone/src/app/api/profiles/import/route.ts +65 -0
  401. package/.next/standalone/src/app/api/profiles/route.ts +107 -0
  402. package/.next/standalone/src/app/api/sessions/[id]/archive/route.test.ts +136 -0
  403. package/.next/standalone/src/app/api/sessions/[id]/archive/route.ts +170 -0
  404. package/.next/standalone/src/app/api/sessions/[id]/delete/route.test.ts +113 -0
  405. package/.next/standalone/src/app/api/sessions/[id]/delete/route.ts +137 -0
  406. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.test.ts +218 -0
  407. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.ts +85 -0
  408. package/.next/standalone/src/app/api/sessions/[id]/route.test.ts +531 -0
  409. package/.next/standalone/src/app/api/sessions/[id]/route.ts +75 -0
  410. package/.next/standalone/src/app/api/sessions/route.test.ts +1298 -0
  411. package/.next/standalone/src/app/api/sessions/route.ts +1695 -0
  412. package/.next/standalone/src/app/favicon.ico +0 -0
  413. package/.next/standalone/src/app/globals.css +66 -0
  414. package/.next/standalone/src/app/layout.tsx +37 -0
  415. package/.next/standalone/src/app/page.test.tsx +134 -0
  416. package/.next/standalone/src/app/page.tsx +358 -0
  417. package/.next/standalone/src/components/AGENTS.md +42 -0
  418. package/.next/standalone/src/components/ErrorBoundary.tsx +72 -0
  419. package/.next/standalone/src/components/KanbanBoard.test.tsx +704 -0
  420. package/.next/standalone/src/components/KanbanBoard.tsx +852 -0
  421. package/.next/standalone/src/components/LoadingState.tsx +37 -0
  422. package/.next/standalone/src/components/ProjectCard.test.tsx +773 -0
  423. package/.next/standalone/src/components/ProjectCard.tsx +595 -0
  424. package/.next/standalone/src/components/QueryProvider.tsx +25 -0
  425. package/.next/standalone/src/components/SessionCard.test.tsx +566 -0
  426. package/.next/standalone/src/components/SessionCard.tsx +434 -0
  427. package/.next/standalone/src/components/SessionList.tsx +60 -0
  428. package/.next/standalone/src/components/host-config/HostManagerDialog.test.tsx +252 -0
  429. package/.next/standalone/src/components/host-config/HostManagerDialog.tsx +476 -0
  430. package/.next/standalone/src/components/opencode-config/AgentConfigForm.test.tsx +72 -0
  431. package/.next/standalone/src/components/opencode-config/AgentConfigForm.tsx +483 -0
  432. package/.next/standalone/src/components/opencode-config/AgentModelSelector.tsx +284 -0
  433. package/.next/standalone/src/components/opencode-config/AgentsConfigPanel.tsx +162 -0
  434. package/.next/standalone/src/components/opencode-config/ConfigButton.tsx +43 -0
  435. package/.next/standalone/src/components/opencode-config/ConfigPanel.tsx +91 -0
  436. package/.next/standalone/src/components/opencode-config/FullscreenConfigPanel.tsx +435 -0
  437. package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.test.tsx +91 -0
  438. package/.next/standalone/src/components/opencode-config/GeneralSettingsForm.tsx +288 -0
  439. package/.next/standalone/src/components/opencode-config/categories/CategoriesList.tsx +382 -0
  440. package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.test.tsx +111 -0
  441. package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.tsx +174 -0
  442. package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.tsx +453 -0
  443. package/.next/standalone/src/components/opencode-config/profiles/ProfileCard.tsx +140 -0
  444. package/.next/standalone/src/components/opencode-config/profiles/ProfileEditor.tsx +446 -0
  445. package/.next/standalone/src/components/opencode-config/profiles/ProfileList.tsx +446 -0
  446. package/.next/standalone/src/components/opencode-config/profiles/ProfileManager.test.tsx +225 -0
  447. package/.next/standalone/src/components/opencode-config/profiles/ProfileManager.tsx +405 -0
  448. package/.next/standalone/src/components/ui/Tabs.tsx +59 -0
  449. package/.next/standalone/src/hooks/useHostSources.test.ts +509 -0
  450. package/.next/standalone/src/hooks/useHostSources.ts +299 -0
  451. package/.next/standalone/src/hooks/useOpencodeSync.test.ts +387 -0
  452. package/.next/standalone/src/hooks/useOpencodeSync.ts +571 -0
  453. package/.next/standalone/src/index.ts +2 -0
  454. package/.next/standalone/src/lib/editorLauncher.server.ts +36 -0
  455. package/.next/standalone/src/lib/editorLauncher.test.ts +35 -0
  456. package/.next/standalone/src/lib/editorLauncher.ts +25 -0
  457. package/.next/standalone/src/lib/hostAccent.test.ts +58 -0
  458. package/.next/standalone/src/lib/hostAccent.ts +46 -0
  459. package/.next/standalone/src/lib/hostIdentity.test.ts +187 -0
  460. package/.next/standalone/src/lib/hostIdentity.ts +122 -0
  461. package/.next/standalone/src/lib/hostSourcesStorage.test.ts +141 -0
  462. package/.next/standalone/src/lib/hostSourcesStorage.ts +72 -0
  463. package/.next/standalone/src/lib/nodeProtocol.test.ts +159 -0
  464. package/.next/standalone/src/lib/nodeProtocol.ts +142 -0
  465. package/.next/standalone/src/lib/nodeRegistry.test.ts +173 -0
  466. package/.next/standalone/src/lib/nodeRegistry.ts +398 -0
  467. package/.next/standalone/src/lib/notificationSound.ts +292 -0
  468. package/.next/standalone/src/lib/opencodeConfig.test.ts +100 -0
  469. package/.next/standalone/src/lib/opencodeConfig.ts +76 -0
  470. package/.next/standalone/src/lib/opencodeDiscovery.ts +275 -0
  471. package/.next/standalone/src/lib/profiles/share.test.ts +91 -0
  472. package/.next/standalone/src/lib/profiles/share.ts +93 -0
  473. package/.next/standalone/src/lib/profiles/storage.test.ts +108 -0
  474. package/.next/standalone/src/lib/profiles/storage.ts +370 -0
  475. package/.next/standalone/src/lib/runtimeMode.test.ts +29 -0
  476. package/.next/standalone/src/lib/runtimeMode.ts +29 -0
  477. package/.next/standalone/src/lib/sessionActionErrors.ts +37 -0
  478. package/.next/standalone/src/lib/sessionArchiveOverrides.test.ts +43 -0
  479. package/.next/standalone/src/lib/sessionArchiveOverrides.ts +116 -0
  480. package/.next/standalone/src/lib/transform.test.ts +121 -0
  481. package/.next/standalone/src/lib/transform.ts +193 -0
  482. package/.next/standalone/src/test/setup.ts +8 -0
  483. package/.next/standalone/src/types/index.ts +152 -0
  484. package/.next/standalone/src/types/opencodeConfig.ts +149 -0
  485. package/.next/standalone/tsconfig.json +34 -0
  486. package/.next/standalone/tsconfig.lib.json +17 -0
  487. package/.next/standalone/vitest.config.ts +16 -0
  488. package/.next/static/chunks/7ac19aaef01f4a03.js +13 -0
  489. package/.next/static/chunks/f42202943f6742e5.css +3 -0
  490. package/.next/trace +1 -1
  491. package/.next/trace-build +1 -1
  492. package/.next/types/routes.d.ts +9 -1
  493. package/.next/types/validator.ts +72 -0
  494. package/README.md +28 -11
  495. package/bin/dev-runtime.js +58 -0
  496. package/bin/vibepulse.js +72 -39
  497. package/package.json +4 -2
  498. package/public/readme-cover.png +0 -0
  499. package/.next/server/chunks/[externals]_next_dist_16542d6b._.js +0 -3
  500. package/.next/server/chunks/[root-of-the-server]__07488412._.js +0 -3
  501. package/.next/server/chunks/[root-of-the-server]__07488412._.js.map +0 -1
  502. package/.next/server/chunks/[root-of-the-server]__07649a30._.js +0 -3
  503. package/.next/server/chunks/[root-of-the-server]__07649a30._.js.map +0 -1
  504. package/.next/server/chunks/[root-of-the-server]__172a07b6._.js.map +0 -1
  505. package/.next/server/chunks/[root-of-the-server]__1bf88ae0._.js +0 -3
  506. package/.next/server/chunks/[root-of-the-server]__1bf88ae0._.js.map +0 -1
  507. package/.next/server/chunks/[root-of-the-server]__2c3e3de2._.js +0 -3
  508. package/.next/server/chunks/[root-of-the-server]__2c3e3de2._.js.map +0 -1
  509. package/.next/server/chunks/[root-of-the-server]__560e7c61._.js +0 -3
  510. package/.next/server/chunks/[root-of-the-server]__560e7c61._.js.map +0 -1
  511. package/.next/server/chunks/[root-of-the-server]__9f034d03._.js +0 -5
  512. package/.next/server/chunks/[root-of-the-server]__9f034d03._.js.map +0 -1
  513. package/.next/server/chunks/[root-of-the-server]__a84faf4b._.js +0 -3
  514. package/.next/server/chunks/[root-of-the-server]__a84faf4b._.js.map +0 -1
  515. package/.next/server/chunks/[root-of-the-server]__b92251ea._.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__b92251ea._.js.map +0 -1
  517. package/.next/server/chunks/[root-of-the-server]__e7a766a0._.js +0 -3
  518. package/.next/server/chunks/[root-of-the-server]__e7a766a0._.js.map +0 -1
  519. package/.next/server/chunks/[root-of-the-server]__f234882e._.js +0 -3
  520. package/.next/server/chunks/[root-of-the-server]__f234882e._.js.map +0 -1
  521. package/.next/server/chunks/[root-of-the-server]__f85221b8._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__f85221b8._.js.map +0 -1
  523. package/.next/standalone/.next/server/chunks/[externals]_next_dist_16542d6b._.js +0 -3
  524. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07488412._.js +0 -3
  525. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07649a30._.js +0 -3
  526. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1bf88ae0._.js +0 -3
  527. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2c3e3de2._.js +0 -3
  528. package/.next/standalone/.next/server/chunks/[root-of-the-server]__560e7c61._.js +0 -3
  529. package/.next/standalone/.next/server/chunks/[root-of-the-server]__9f034d03._.js +0 -5
  530. package/.next/standalone/.next/server/chunks/[root-of-the-server]__a84faf4b._.js +0 -3
  531. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b92251ea._.js +0 -3
  532. package/.next/standalone/.next/server/chunks/[root-of-the-server]__e7a766a0._.js +0 -3
  533. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f234882e._.js +0 -3
  534. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f85221b8._.js +0 -3
  535. package/.next/standalone/.next/static/chunks/ca49cb2092c277d2.js +0 -13
  536. package/.next/standalone/.next/static/chunks/dc07499869593595.css +0 -3
  537. package/.next/static/chunks/ca49cb2092c277d2.js +0 -13
  538. package/.next/static/chunks/dc07499869593595.css +0 -3
  539. /package/.next/server/chunks/{[externals]_next_dist_16542d6b._.js.map → [externals]_next_dist_84e7390b._.js.map} +0 -0
  540. /package/.next/server/chunks/ssr/{[root-of-the-server]__39eef6a5._.js.map → [root-of-the-server]__631e12d0._.js.map} +0 -0
  541. /package/.next/server/chunks/ssr/{[root-of-the-server]__535a2208._.js.map → [root-of-the-server]__a8cd3911._.js.map} +0 -0
  542. /package/.next/standalone/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_buildManifest.js +0 -0
  543. /package/.next/standalone/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_clientMiddlewareManifest.json +0 -0
  544. /package/.next/standalone/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_ssgManifest.js +0 -0
  545. /package/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_buildManifest.js +0 -0
  546. /package/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_clientMiddlewareManifest.json +0 -0
  547. /package/.next/static/{78EwnRx2m70qyfCL0X4sH → Fw2R3y-fHX4B2SWxNy_4X}/_ssgManifest.js +0 -0
@@ -0,0 +1,852 @@
1
+ 'use client';
2
+
3
+ import { useQuery } from '@tanstack/react-query';
4
+ import { KanbanColumn, KanbanCard, OpencodeSession } from '@/types';
5
+ import { ProjectCard } from './ProjectCard';
6
+ import { transformSessions } from '@/lib/transform';
7
+ import { LoadingState } from './LoadingState';
8
+ import { playCompleteSound } from '@/lib/notificationSound';
9
+ import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react';
10
+ import { getSseStatusSnapshot } from '@/hooks/useOpencodeSync';
11
+ import { useHostSources } from '@/hooks/useHostSources';
12
+ import { composeSourceKey } from '@/lib/hostIdentity';
13
+ import { getHostAccentTextClass } from '@/lib/hostAccent';
14
+
15
+ const WAITING_STORAGE_KEY = 'vibepulse:waiting-sessions:v2';
16
+ const SNAPSHOT_STORAGE_KEY = 'vibepulse:last-sessions-snapshot:v2';
17
+ const START_COMMAND_TEMPLATE = 'opencode --port <PORT>';
18
+ const CARD_ANIMATION_DURATION_MS = 250;
19
+ const SESSIONS_ERROR_DISPLAY_THRESHOLD = 3;
20
+ const DEGRADED_MERGE_MAX_SNAPSHOT_AGE_MS = 10 * 60 * 1000;
21
+ const WAITING_PERSIST_MAX_AGE_MS = 10 * 60 * 1000;
22
+
23
+ const LOCAL_SOURCE = {
24
+ hostId: 'local',
25
+ hostLabel: 'Local',
26
+ hostKind: 'local',
27
+ } as const;
28
+
29
+ const COLUMNS: { id: KanbanColumn; title: string }[] = [
30
+ { id: 'idle', title: 'Idle' },
31
+ { id: 'busy', title: 'Busy' },
32
+ { id: 'review', title: 'Needs Attention' },
33
+ { id: 'done', title: 'Archived' },
34
+ ];
35
+
36
+ interface KanbanBoardProps {
37
+ filterDays: number;
38
+ onProcessHintsChange?: (hints: ProcessHint[]) => void;
39
+ hostSources: ReturnType<typeof useHostSources>;
40
+ isNodeMode?: boolean;
41
+ showHostFilter?: boolean;
42
+ onHostStatusesChange?: (statuses: SessionHostStatus[]) => void;
43
+ }
44
+
45
+ type SessionsFetchError = Error & {
46
+ kind?: 'opencode_unavailable' | 'request_failed';
47
+ hint?: string;
48
+ status?: number;
49
+ };
50
+
51
+ type ProcessHint = {
52
+ pid: number;
53
+ directory: string;
54
+ projectName: string;
55
+ reason: 'process_without_api_port';
56
+ };
57
+
58
+ type SessionSnapshot = {
59
+ savedAt: number;
60
+ sessions: OpencodeSession[];
61
+ processHints: ProcessHint[];
62
+ hostStatuses?: SessionHostStatus[];
63
+ };
64
+
65
+ export type SessionHostStatus = {
66
+ hostId: string;
67
+ hostLabel: string;
68
+ hostKind: 'local' | 'remote';
69
+ online: boolean;
70
+ degraded?: boolean;
71
+ reason?: string;
72
+ baseUrl?: string;
73
+ };
74
+
75
+ type SessionsResponse = {
76
+ sessions: OpencodeSession[];
77
+ processHints?: ProcessHint[];
78
+ failedPorts?: Array<{ port: number; reason: string }>;
79
+ degraded?: boolean;
80
+ hostStatuses?: SessionHostStatus[];
81
+ };
82
+
83
+ type SessionsErrorPayload = {
84
+ error?: string;
85
+ hint?: string;
86
+ degraded?: boolean;
87
+ sessions?: unknown;
88
+ };
89
+
90
+ function areHostStatusesEqual(
91
+ previous: SessionHostStatus[] | null,
92
+ next: SessionHostStatus[]
93
+ ): boolean {
94
+ if (!previous) {
95
+ return false;
96
+ }
97
+
98
+ if (previous.length !== next.length) {
99
+ return false;
100
+ }
101
+
102
+ for (let index = 0; index < previous.length; index += 1) {
103
+ const left = previous[index];
104
+ const right = next[index];
105
+ if (
106
+ left.hostId !== right.hostId ||
107
+ left.hostLabel !== right.hostLabel ||
108
+ left.hostKind !== right.hostKind ||
109
+ left.online !== right.online ||
110
+ left.degraded !== right.degraded ||
111
+ left.reason !== right.reason
112
+ ) {
113
+ return false;
114
+ }
115
+ }
116
+
117
+ return true;
118
+ }
119
+
120
+ function getLocalWaitingPersistenceKey(
121
+ session: Pick<OpencodeSession, 'id' | 'sourceSessionKey' | 'hostId' | 'hostKind'>
122
+ ): string | null {
123
+ const sourceKey = session.sourceSessionKey || session.id;
124
+ if (session.hostKind === 'local' || session.hostId === 'local' || sourceKey.startsWith('local:')) {
125
+ return sourceKey;
126
+ }
127
+
128
+ return null;
129
+ }
130
+
131
+ function getCanonicalSessionIdentity(
132
+ session: Pick<OpencodeSession, 'id' | 'hostId' | 'rawSessionId' | 'sourceSessionKey'>
133
+ ): string {
134
+ if (session.sourceSessionKey) {
135
+ return session.sourceSessionKey;
136
+ }
137
+
138
+ if (session.hostId && session.rawSessionId) {
139
+ return composeSourceKey(session.hostId, session.rawSessionId);
140
+ }
141
+
142
+ if (session.hostId && !session.id.includes(':')) {
143
+ return composeSourceKey(session.hostId, session.id);
144
+ }
145
+
146
+ if (!session.id.includes(':')) {
147
+ return composeSourceKey('local', session.id);
148
+ }
149
+
150
+ return session.id;
151
+ }
152
+
153
+ export function KanbanBoard({
154
+ filterDays,
155
+ onProcessHintsChange,
156
+ hostSources,
157
+ isNodeMode = false,
158
+ showHostFilter = true,
159
+ onHostStatusesChange,
160
+ }: KanbanBoardProps) {
161
+ const cardStatusStateRef = useRef<Record<string, KanbanColumn>>({});
162
+ const cardStatusInitRef = useRef(false);
163
+ const [copyFeedback, setCopyFeedback] = useState<'idle' | 'copied' | 'failed'>('idle');
164
+ const [staleSnapshot, setStaleSnapshot] = useState<SessionSnapshot | null>(null);
165
+ const { enabledSources, activeFilter, setActiveFilter, filteredHostIds } = hostSources;
166
+ const requestSources = useMemo(() => {
167
+ if (!isNodeMode) {
168
+ return enabledSources;
169
+ }
170
+
171
+ const localSources = enabledSources.filter(
172
+ (source) => source.hostKind === 'local' && source.hostId === 'local'
173
+ );
174
+ return localSources.length > 0 ? localSources : [LOCAL_SOURCE];
175
+ }, [enabledSources, isNodeMode]);
176
+
177
+ const { data: config } = useQuery({
178
+ queryKey: ['opencode-config'],
179
+ queryFn: async () => {
180
+ const res = await fetch('/api/opencode-config');
181
+ if (!res.ok) throw new Error('Failed to fetch config');
182
+ return res.json();
183
+ }
184
+ });
185
+
186
+ const configuredRefreshIntervalMs = config?.vibepulse?.sessionsRefreshIntervalMs;
187
+ const refreshIntervalMs =
188
+ typeof configuredRefreshIntervalMs === 'number' && Number.isFinite(configuredRefreshIntervalMs) && configuredRefreshIntervalMs > 0
189
+ ? configuredRefreshIntervalMs
190
+ : 5000;
191
+
192
+ const { data, isLoading, error, dataUpdatedAt, refetch, isFetching, failureCount } = useQuery<SessionsResponse>({
193
+ queryKey: ['sessions', requestSources, isNodeMode],
194
+ queryFn: async ({ signal }: { signal: AbortSignal }) => {
195
+ try {
196
+ const res = await fetch('/api/sessions', {
197
+ method: 'POST',
198
+ headers: { 'Content-Type': 'application/json' },
199
+ body: JSON.stringify({ sources: requestSources }),
200
+ signal
201
+ });
202
+ if (!res.ok) {
203
+ let payload: SessionsErrorPayload | null = null;
204
+ try {
205
+ payload = await res.json() as SessionsErrorPayload;
206
+ } catch {
207
+ payload = null;
208
+ }
209
+
210
+ const isDegradedPayload =
211
+ !!payload &&
212
+ payload.degraded === true &&
213
+ Array.isArray(payload.sessions);
214
+
215
+ if (isDegradedPayload) {
216
+ return payload as SessionsResponse;
217
+ }
218
+
219
+ const isUnavailable =
220
+ res.status === 503 && payload?.error === 'OpenCode server not found';
221
+ const fetchError = new Error(
222
+ isUnavailable
223
+ ? payload?.error || 'OpenCode server not found'
224
+ : payload?.error || `Failed to load sessions (${res.status})`
225
+ ) as SessionsFetchError;
226
+
227
+ fetchError.kind = isUnavailable ? 'opencode_unavailable' : 'request_failed';
228
+ fetchError.hint = payload?.hint;
229
+ fetchError.status = res.status;
230
+ throw fetchError;
231
+ }
232
+
233
+ return res.json();
234
+ } catch (error) {
235
+ if (error instanceof Error && error.name === 'AbortError') {
236
+ throw error;
237
+ }
238
+
239
+ if (error instanceof Error && (error as SessionsFetchError).kind) {
240
+ throw error;
241
+ }
242
+
243
+ const fetchError = new Error('Unable to connect to session service') as SessionsFetchError;
244
+ fetchError.kind = 'request_failed';
245
+ throw fetchError;
246
+ }
247
+ },
248
+ refetchInterval: (query) => query.state.fetchStatus === 'fetching' ? false : refreshIntervalMs,
249
+ refetchIntervalInBackground: true,
250
+ refetchOnReconnect: true,
251
+ retry: false,
252
+ });
253
+
254
+ const activeError = error as SessionsFetchError | null;
255
+ const hasSessionsResponse = data !== undefined;
256
+
257
+ useEffect(() => {
258
+ if (typeof window === 'undefined') return;
259
+ try {
260
+ const raw = localStorage.getItem(SNAPSHOT_STORAGE_KEY);
261
+ if (!raw) return;
262
+ const parsed = JSON.parse(raw) as SessionSnapshot;
263
+ if (!parsed || !Array.isArray(parsed.sessions) || typeof parsed.savedAt !== 'number') {
264
+ return;
265
+ }
266
+ if (!Array.isArray(parsed.processHints)) {
267
+ parsed.processHints = [];
268
+ }
269
+ if (!Array.isArray(parsed.hostStatuses)) {
270
+ parsed.hostStatuses = [];
271
+ }
272
+ if (parsed.sessions.length === 0) return;
273
+ setStaleSnapshot(parsed);
274
+ } catch {
275
+ setStaleSnapshot(null);
276
+ }
277
+ }, []);
278
+
279
+ useEffect(() => {
280
+ if (typeof window === 'undefined') return;
281
+ if (!data?.sessions || data.sessions.length === 0) return;
282
+
283
+ if (data.degraded && staleSnapshot?.sessions?.length) {
284
+ return;
285
+ }
286
+
287
+ const snapshot: SessionSnapshot = {
288
+ savedAt: Date.now(),
289
+ sessions: data.sessions,
290
+ processHints: data.processHints ?? [],
291
+ hostStatuses: data.hostStatuses ?? [],
292
+ };
293
+
294
+ try {
295
+ localStorage.setItem(SNAPSHOT_STORAGE_KEY, JSON.stringify(snapshot));
296
+ setStaleSnapshot(snapshot);
297
+ } catch {
298
+ setStaleSnapshot(snapshot);
299
+ }
300
+ }, [data?.degraded, data?.processHints, data?.sessions, data?.hostStatuses, staleSnapshot?.sessions?.length]);
301
+
302
+ const handleCopyStartCommand = async () => {
303
+ try {
304
+ await navigator.clipboard.writeText(START_COMMAND_TEMPLATE);
305
+ setCopyFeedback('copied');
306
+ setTimeout(() => setCopyFeedback('idle'), 1500);
307
+ } catch {
308
+ setCopyFeedback('failed');
309
+ setTimeout(() => setCopyFeedback('idle'), 2000);
310
+ }
311
+ };
312
+
313
+ const sourceSessions = useMemo(() => {
314
+ if (data?.sessions) {
315
+ if (data.degraded && staleSnapshot?.sessions?.length) {
316
+ const snapshotAgeMs = Date.now() - staleSnapshot.savedAt;
317
+ if (snapshotAgeMs <= DEGRADED_MERGE_MAX_SNAPSHOT_AGE_MS) {
318
+ const merged = [...data.sessions];
319
+ const seen = new Set(merged.map((session) => getCanonicalSessionIdentity(session)));
320
+ for (const session of staleSnapshot.sessions) {
321
+ const canonicalIdentity = getCanonicalSessionIdentity(session);
322
+ if (seen.has(canonicalIdentity)) continue;
323
+ merged.push(session);
324
+ seen.add(canonicalIdentity);
325
+ }
326
+ return merged;
327
+ }
328
+ }
329
+ return data.sessions;
330
+ }
331
+ if (activeError && staleSnapshot?.sessions?.length) {
332
+ return staleSnapshot.sessions;
333
+ }
334
+ return [];
335
+ }, [activeError, data?.degraded, data?.sessions, staleSnapshot?.savedAt, staleSnapshot?.sessions]);
336
+
337
+ const isShowingStaleData = !!activeError && !data?.sessions && !!staleSnapshot?.sessions?.length;
338
+
339
+ const currentHostStatuses = useMemo(() => {
340
+ if (data?.hostStatuses?.length) {
341
+ return data.hostStatuses;
342
+ }
343
+ if (isShowingStaleData && staleSnapshot?.hostStatuses?.length) {
344
+ return staleSnapshot.hostStatuses;
345
+ }
346
+
347
+ if (
348
+ data &&
349
+ !activeError &&
350
+ requestSources.length === 1 &&
351
+ requestSources[0].hostId === 'local' &&
352
+ requestSources[0].hostKind === 'local'
353
+ ) {
354
+ return [{
355
+ hostId: 'local',
356
+ hostLabel: 'Local',
357
+ hostKind: 'local' as const,
358
+ online: true,
359
+ }];
360
+ }
361
+
362
+ return [];
363
+ }, [activeError, data, data?.hostStatuses, requestSources, isShowingStaleData, staleSnapshot?.hostStatuses]);
364
+
365
+ const previousHostStatusesRef = useRef<SessionHostStatus[] | null>(null);
366
+
367
+ useEffect(() => {
368
+ if (!onHostStatusesChange) {
369
+ return;
370
+ }
371
+
372
+ if (areHostStatusesEqual(previousHostStatusesRef.current, currentHostStatuses)) {
373
+ return;
374
+ }
375
+
376
+ previousHostStatusesRef.current = currentHostStatuses.map((status) => ({ ...status }));
377
+ onHostStatusesChange(currentHostStatuses);
378
+ }, [currentHostStatuses, onHostStatusesChange]);
379
+
380
+ const shouldShowHardError =
381
+ !!activeError &&
382
+ !isShowingStaleData &&
383
+ !hasSessionsResponse &&
384
+ failureCount >= SESSIONS_ERROR_DISPLAY_THRESHOLD;
385
+ const shouldShowTransientRecovery =
386
+ !!activeError &&
387
+ !isShowingStaleData &&
388
+ !hasSessionsResponse &&
389
+ failureCount > 0 &&
390
+ failureCount < SESSIONS_ERROR_DISPLAY_THRESHOLD;
391
+
392
+ const processHints = useMemo(() => {
393
+ if (data?.processHints) {
394
+ return data.processHints;
395
+ }
396
+ if (isShowingStaleData && staleSnapshot?.processHints) {
397
+ return staleSnapshot.processHints;
398
+ }
399
+ return [];
400
+ }, [data?.processHints, isShowingStaleData, staleSnapshot?.processHints]);
401
+
402
+ useEffect(() => {
403
+ onProcessHintsChange?.(processHints);
404
+ }, [onProcessHintsChange, processHints]);
405
+
406
+ const enrichedSessions = useMemo(() => {
407
+ if (!sourceSessions.length) return [];
408
+
409
+ let persistedWaiting: Record<string, boolean> = {};
410
+ if (typeof window !== 'undefined') {
411
+ try {
412
+ persistedWaiting = JSON.parse(localStorage.getItem(WAITING_STORAGE_KEY) || '{}');
413
+ } catch {
414
+ persistedWaiting = {};
415
+ }
416
+ }
417
+
418
+ const sseSnapshot = getSseStatusSnapshot();
419
+ const now = Date.now();
420
+ const isPersistedWaitingStillValid = (
421
+ status: string | undefined,
422
+ updatedAt: number,
423
+ persisted: boolean
424
+ ) => {
425
+ if (!persisted) return false;
426
+ if (status !== 'busy' && status !== 'retry') return false;
427
+ if (!updatedAt) return false;
428
+ return now - updatedAt <= WAITING_PERSIST_MAX_AGE_MS;
429
+ };
430
+
431
+ return sourceSessions.map((s) => {
432
+ const waitingPersistenceKey = getLocalWaitingPersistenceKey(s);
433
+ const persisted = waitingPersistenceKey ? !!persistedWaiting[waitingPersistenceKey] : false;
434
+ const updatedAt = s.time?.updated || s.time?.created || 0;
435
+ const keepWaitingFromPersistence = waitingPersistenceKey
436
+ ? isPersistedWaitingStillValid(s.realTimeStatus, updatedAt, persisted)
437
+ : false;
438
+
439
+ const sseEntry = waitingPersistenceKey ? sseSnapshot.get(waitingPersistenceKey) : undefined;
440
+ const sessionStatus = sseEntry ? sseEntry.status : s.realTimeStatus;
441
+
442
+ const children = (s.children || []).map((child) => {
443
+ const childWaitingPersistenceKey = getLocalWaitingPersistenceKey(child);
444
+ const childPersisted = childWaitingPersistenceKey ? !!persistedWaiting[childWaitingPersistenceKey] : false;
445
+ const childUpdatedAt = child.time?.updated || child.time?.created || 0;
446
+ const childSseEntry = childWaitingPersistenceKey ? sseSnapshot.get(childWaitingPersistenceKey) : undefined;
447
+ const childStatus = childSseEntry ? childSseEntry.status : child.realTimeStatus;
448
+ const keepChildWaitingFromPersistence = childWaitingPersistenceKey
449
+ ? isPersistedWaitingStillValid(
450
+ childStatus,
451
+ childUpdatedAt,
452
+ childPersisted
453
+ )
454
+ : false;
455
+
456
+ return {
457
+ ...child,
458
+ realTimeStatus: childStatus,
459
+ waitingForUser: !!child.waitingForUser || keepChildWaitingFromPersistence,
460
+ };
461
+ });
462
+
463
+ return {
464
+ ...s,
465
+ realTimeStatus: sessionStatus,
466
+ waitingForUser: !!s.waitingForUser || keepWaitingFromPersistence,
467
+ children,
468
+ };
469
+ });
470
+ }, [sourceSessions]);
471
+
472
+ useEffect(() => {
473
+ if (typeof window === 'undefined') return;
474
+ const nextPersistedWaiting: Record<string, boolean> = {};
475
+ for (const session of enrichedSessions as Array<{ id: string; waitingForUser?: boolean; children?: Array<{ id: string; waitingForUser?: boolean }> }>) {
476
+ const sessionKey = getLocalWaitingPersistenceKey(session);
477
+ if (session.waitingForUser && sessionKey) {
478
+ nextPersistedWaiting[sessionKey] = true;
479
+ }
480
+
481
+ for (const child of session.children || []) {
482
+ const childKey = getLocalWaitingPersistenceKey(child);
483
+ if (child.waitingForUser && childKey) {
484
+ nextPersistedWaiting[childKey] = true;
485
+ }
486
+ }
487
+ }
488
+ localStorage.setItem(WAITING_STORAGE_KEY, JSON.stringify(nextPersistedWaiting));
489
+ }, [enrichedSessions]);
490
+
491
+ const cards: KanbanCard[] = useMemo(() => {
492
+ const allCards = transformSessions(enrichedSessions);
493
+ let filtered = allCards;
494
+ if (filteredHostIds) {
495
+ filtered = filtered.filter(card => {
496
+ const cardHostId = card.hostId || 'local';
497
+ return filteredHostIds.has(cardHostId);
498
+ });
499
+ }
500
+
501
+ if (filterDays === 0) {
502
+ return filtered;
503
+ }
504
+ const cutoff = dataUpdatedAt - filterDays * 24 * 60 * 60 * 1000;
505
+
506
+ return filtered.filter((card) => {
507
+ if (card.status === 'busy' || card.status === 'review') {
508
+ return true;
509
+ }
510
+
511
+ const lastActivityAt = Math.max(
512
+ card.updatedAt || 0,
513
+ card.createdAt || 0,
514
+ card.archivedAt || 0
515
+ );
516
+ return lastActivityAt >= cutoff;
517
+ });
518
+ }, [dataUpdatedAt, enrichedSessions, filterDays, filteredHostIds]);
519
+
520
+ useEffect(() => {
521
+ const nextCardStatus: Record<string, KanbanColumn> = {};
522
+ for (const card of cards) {
523
+ nextCardStatus[card.id] = card.status;
524
+ }
525
+
526
+ if (!cardStatusInitRef.current) {
527
+ cardStatusInitRef.current = true;
528
+ cardStatusStateRef.current = nextCardStatus;
529
+ return;
530
+ }
531
+
532
+ const shouldPlayComplete = Object.entries(nextCardStatus).some(([id, currentStatus]) => {
533
+ const previousStatus = cardStatusStateRef.current[id];
534
+ return !!previousStatus && previousStatus !== 'idle' && currentStatus === 'idle';
535
+ });
536
+
537
+ cardStatusStateRef.current = nextCardStatus;
538
+
539
+ if (shouldPlayComplete && !isShowingStaleData) {
540
+ setTimeout(() => playCompleteSound(), CARD_ANIMATION_DURATION_MS);
541
+ }
542
+ }, [cards, isShowingStaleData]);
543
+
544
+
545
+ const renderHostFilter = () => (
546
+ <div className="shrink-0 flex items-center justify-end px-4 py-2 bg-zinc-50 dark:bg-black border-b border-gray-200 dark:border-zinc-800">
547
+ <div className="flex items-center gap-1 bg-gray-100 dark:bg-zinc-800 rounded-lg p-0.5" data-testid="host-filter">
548
+ <button
549
+ type="button"
550
+ onClick={() => setActiveFilter('all')}
551
+ className={`px-3 py-1 text-xs font-medium rounded-md transition-all duration-150 ${
552
+ activeFilter === 'all'
553
+ ? 'bg-white dark:bg-zinc-600 text-gray-900 dark:text-white shadow-sm'
554
+ : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200'
555
+ }`}
556
+ data-testid="host-filter-option-all"
557
+ >
558
+ All Hosts
559
+ </button>
560
+ {enabledSources.map(source => {
561
+ const status = currentHostStatuses.find((s: SessionHostStatus) => s.hostId === source.hostId);
562
+ const isOnline = status?.online ?? false;
563
+ const hostAccentClass = getHostAccentTextClass(source.hostId, source.hostLabel);
564
+
565
+ return (
566
+ <button
567
+ key={source.hostId}
568
+ type="button"
569
+ onClick={() => setActiveFilter(source.hostId)}
570
+ className={`flex items-center gap-1.5 px-3 py-1 text-xs font-medium rounded-md transition-all duration-150 ${
571
+ activeFilter === source.hostId
572
+ ? 'bg-white dark:bg-zinc-600 text-gray-900 dark:text-white shadow-sm'
573
+ : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200'
574
+ }`}
575
+ data-testid={`host-filter-option-${source.hostId}`}
576
+ >
577
+ <span className={`inline-flex items-center justify-center flex-shrink-0 ${hostAccentClass}`} data-testid={`host-identity-${source.hostId}`} title={`Host identity: ${source.hostLabel}`}>
578
+ <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
579
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
580
+ </svg>
581
+ </span>
582
+ <span className="truncate">{source.hostLabel}</span>
583
+ <span className="ml-auto inline-flex items-center pl-1.5" data-testid={`host-indicators-${source.hostId}`}>
584
+ <span
585
+ className={`w-2 h-2 rounded-full ${isOnline ? 'bg-emerald-500' : 'bg-gray-400'}`}
586
+ data-testid={`host-status-${source.hostId}`}
587
+ title={isOnline ? 'Online' : 'Offline'}
588
+ />
589
+ </span>
590
+ </button>
591
+ );
592
+ })}
593
+ </div>
594
+ </div>
595
+ );
596
+
597
+ const hostFilterNode: ReactNode = showHostFilter ? renderHostFilter() : null;
598
+
599
+ if (isLoading) {
600
+ return (
601
+ <div className="flex flex-col flex-1 h-full min-h-0">
602
+ {hostFilterNode}
603
+ <LoadingState />
604
+ </div>
605
+ );
606
+ }
607
+
608
+ if (shouldShowHardError) {
609
+ const isOpencodeUnavailable = activeError?.kind === 'opencode_unavailable';
610
+ const title = isOpencodeUnavailable ? 'OpenCode is not running' : 'Failed to load sessions';
611
+ const description = isOpencodeUnavailable
612
+ ? activeError?.hint || 'Run OpenCode with an exposed API port, for example `opencode --port <PORT>`.'
613
+ : activeError?.message || 'An error occurred while loading sessions';
614
+
615
+ return (
616
+ <div className="flex flex-col flex-1 h-full min-h-0">
617
+ {hostFilterNode}
618
+ <div className="flex-1 flex items-center justify-center p-8">
619
+ <div className="max-w-md w-full text-center">
620
+ <div className="flex items-center justify-center w-12 h-12 mx-auto mb-4 bg-red-100 dark:bg-red-900/30 rounded-full">
621
+ <svg
622
+ className="w-6 h-6 text-red-600 dark:text-red-400"
623
+ fill="none"
624
+ stroke="currentColor"
625
+ viewBox="0 0 24 24"
626
+ aria-hidden="true"
627
+ >
628
+ <path
629
+ strokeLinecap="round"
630
+ strokeLinejoin="round"
631
+ strokeWidth={2}
632
+ d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
633
+ />
634
+ </svg>
635
+ </div>
636
+ <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
637
+ {title}
638
+ </h2>
639
+ <p className="text-gray-600 dark:text-gray-400 mb-4">
640
+ {description}
641
+ </p>
642
+ <div className="flex items-center justify-center gap-2">
643
+ <button
644
+ type="button"
645
+ onClick={() => refetch()}
646
+ className="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
647
+ disabled={isFetching}
648
+ >
649
+ {isFetching ? 'Retrying...' : 'Retry'}
650
+ </button>
651
+ {isOpencodeUnavailable ? (
652
+ <button
653
+ type="button"
654
+ onClick={handleCopyStartCommand}
655
+ className="px-3 py-1.5 bg-gray-100 hover:bg-gray-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 text-gray-700 dark:text-gray-300 text-sm font-medium rounded-md transition-colors"
656
+ >
657
+ {copyFeedback === 'copied'
658
+ ? 'Copied'
659
+ : copyFeedback === 'failed'
660
+ ? 'Copy Failed'
661
+ : 'Copy Start Command'}
662
+ </button>
663
+ ) : null}
664
+ </div>
665
+ </div>
666
+ </div>
667
+ </div>
668
+ );
669
+ }
670
+
671
+ if (shouldShowTransientRecovery) {
672
+ return (
673
+ <div className="flex flex-col flex-1 h-full min-h-0">
674
+ {hostFilterNode}
675
+ <div className="flex-1 flex items-center justify-center p-8">
676
+ <div className="max-w-md w-full text-center">
677
+ <div className="flex items-center justify-center w-12 h-12 mx-auto mb-4 bg-amber-100 dark:bg-amber-900/30 rounded-full">
678
+ <svg
679
+ className="w-6 h-6 text-amber-600 dark:text-amber-400"
680
+ fill="none"
681
+ stroke="currentColor"
682
+ viewBox="0 0 24 24"
683
+ aria-hidden="true"
684
+ >
685
+ <path
686
+ strokeLinecap="round"
687
+ strokeLinejoin="round"
688
+ strokeWidth={2}
689
+ d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
690
+ />
691
+ </svg>
692
+ </div>
693
+ <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
694
+ Reconnecting to session service...
695
+ </h2>
696
+ <p className="text-gray-600 dark:text-gray-400 mb-4">
697
+ Temporary fetch failure ({failureCount}/{SESSIONS_ERROR_DISPLAY_THRESHOLD}). Retrying automatically.
698
+ </p>
699
+ <button
700
+ type="button"
701
+ onClick={() => refetch()}
702
+ className="px-3 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-md transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
703
+ disabled={isFetching}
704
+ >
705
+ {isFetching ? 'Retrying...' : 'Retry now'}
706
+ </button>
707
+ </div>
708
+ </div>
709
+ </div>
710
+ );
711
+ }
712
+
713
+ if (!cards || cards.length === 0) {
714
+ return (
715
+ <div className="flex flex-col flex-1 h-full min-h-0">
716
+ {hostFilterNode}
717
+ <div className="flex-1 flex items-center justify-center p-8">
718
+ <div className="max-w-md w-full text-center">
719
+ <div className="flex items-center justify-center w-12 h-12 mx-auto mb-4 bg-gray-100 dark:bg-zinc-800 rounded-full">
720
+ <svg
721
+ className="w-6 h-6 text-gray-500 dark:text-gray-400"
722
+ fill="none"
723
+ stroke="currentColor"
724
+ viewBox="0 0 24 24"
725
+ aria-hidden="true"
726
+ >
727
+ <path
728
+ strokeLinecap="round"
729
+ strokeLinejoin="round"
730
+ strokeWidth={2}
731
+ d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
732
+ />
733
+ </svg>
734
+ </div>
735
+ <h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
736
+ No sessions yet
737
+ </h2>
738
+ <p className="text-gray-600 dark:text-gray-400 mb-4">
739
+ OpenCode is running, but no sessions are available.
740
+ </p>
741
+ <p className="text-sm text-gray-500 dark:text-gray-500">
742
+ Start a conversation in OpenCode and this board will update automatically.
743
+ </p>
744
+ </div>
745
+ </div>
746
+ </div>
747
+ );
748
+ }
749
+
750
+ // Group cards by project
751
+ const groupByProject = (columnCards: KanbanCard[]) => {
752
+ const groups = new Map<string, {
753
+ projectName: string;
754
+ branch?: string;
755
+ hostLabel?: string;
756
+ readOnly: boolean;
757
+ cards: KanbanCard[];
758
+ }>();
759
+
760
+ for (const card of columnCards) {
761
+ const projectName = card.projectName || 'Unknown Project';
762
+ const hostId = card.hostId || 'local';
763
+ const key = `${hostId}::${projectName}`;
764
+
765
+ if (!groups.has(key)) {
766
+ groups.set(key, {
767
+ projectName,
768
+ branch: card.branch,
769
+ hostLabel: card.hostLabel,
770
+ readOnly: !!card.readOnly,
771
+ cards: [],
772
+ });
773
+ }
774
+
775
+ const group = groups.get(key)!;
776
+ group.cards.push(card);
777
+ group.readOnly = group.readOnly || !!card.readOnly;
778
+
779
+ if (!group.branch && card.branch) {
780
+ group.branch = card.branch;
781
+ }
782
+
783
+ if (!group.hostLabel && card.hostLabel) {
784
+ group.hostLabel = card.hostLabel;
785
+ }
786
+ }
787
+
788
+ return groups;
789
+ };
790
+
791
+ return (
792
+ <div className="flex flex-col flex-1 h-full min-h-0">
793
+ {hostFilterNode}
794
+ <div className="flex-1 overflow-x-auto scrollbar-thin scroll-smooth relative">
795
+ {isShowingStaleData ? (
796
+ <div className="px-4 pt-4 pb-0">
797
+ <div className="rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-amber-800 dark:border-amber-900/40 dark:bg-amber-900/20 dark:text-amber-200">
798
+ <div className="flex items-center gap-2 text-xs font-medium">
799
+ <span className="inline-flex items-center rounded-full bg-amber-100 px-2 py-0.5 text-[10px] uppercase tracking-wide dark:bg-amber-900/40">
800
+ Stale Data
801
+ </span>
802
+ <span>
803
+ Last seen at {staleSnapshot ? new Date(staleSnapshot.savedAt).toLocaleString() : '--'}
804
+ </span>
805
+ <span className="text-amber-700/80 dark:text-amber-300/80">Read-only snapshot while OpenCode is unreachable.</span>
806
+ </div>
807
+ </div>
808
+ </div>
809
+ ) : null}
810
+ <div className="flex gap-6 h-full min-w-max p-4">
811
+ {COLUMNS.map((column) => {
812
+ const columnCards = cards
813
+ .filter((c) => c.status === column.id)
814
+ .sort((a, b) => a.sortOrder - b.sortOrder);
815
+ const projectGroups = groupByProject(columnCards);
816
+
817
+ return (
818
+ <div
819
+ key={column.id}
820
+ className="flex-shrink-0 w-80 bg-gray-100 dark:bg-zinc-800/80 rounded-xl p-4 flex flex-col shadow-sm"
821
+ >
822
+ <div className="flex items-center justify-between mb-4 pb-3 border-b border-gray-200 dark:border-zinc-700">
823
+ <h2 className="font-semibold text-gray-700 dark:text-gray-300">
824
+ {column.title}
825
+ </h2>
826
+ <span className="px-2.5 py-0.5 bg-gray-200 dark:bg-zinc-700 text-gray-600 dark:text-gray-400 text-xs font-medium rounded-full">
827
+ {columnCards.length}
828
+ </span>
829
+ </div>
830
+ <div className="flex-1 overflow-y-auto scrollbar-thin pr-1">
831
+ <div className="space-y-3">
832
+ {Array.from(projectGroups.entries()).map(([groupKey, group]) => (
833
+ <ProjectCard
834
+ key={groupKey}
835
+ projectName={group.projectName}
836
+ branch={group.branch}
837
+ cards={group.cards}
838
+ readOnly={isShowingStaleData || group.readOnly}
839
+ hostLabel={group.hostLabel}
840
+ multipleHostsEnabled={requestSources.length > 1}
841
+ />
842
+ ))}
843
+ </div>
844
+ </div>
845
+ </div>
846
+ );
847
+ })}
848
+ </div>
849
+ </div>
850
+ </div>
851
+ );
852
+ }