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,446 @@
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import { Search, Plus, Users, AlertTriangle, X, Check, Download, Upload } from 'lucide-react';
5
+ import { Profile } from '../../../types/opencodeConfig';
6
+
7
+ interface ProfileListProps {
8
+ /** Array of profiles to display */
9
+ profiles: Profile[];
10
+ /** ID of the currently active profile */
11
+ activeProfileId: string | null;
12
+ /** ID of the profile currently being applied */
13
+ appliedProfileId: string | null;
14
+ /** Callback when Apply button is clicked */
15
+ onApply: (profileId: string) => void;
16
+ /** Callback when Edit button is clicked */
17
+ onEdit: (profile: Profile) => void;
18
+ /** Callback when Delete button is clicked */
19
+ onDelete: (profileId: string) => void;
20
+ onExport: (profile: Profile) => void;
21
+ onImport: (file: File) => void;
22
+ /** Callback when Create New button is clicked */
23
+ onCreateNew: () => void;
24
+ }
25
+
26
+ /**
27
+ * ProfileList component - displays all profiles with search/filter
28
+ *
29
+ * Design: Refined industrial data-table aesthetic
30
+ * - Dark charcoal palette with teal accents
31
+ * - Monospace numeric indicators for technical precision
32
+ * - Subtle borders that evoke control panel interfaces
33
+ */
34
+ export function ProfileList({
35
+ profiles,
36
+ activeProfileId,
37
+ appliedProfileId,
38
+ onApply,
39
+ onEdit,
40
+ onDelete,
41
+ onExport,
42
+ onImport,
43
+ onCreateNew,
44
+ }: ProfileListProps) {
45
+ const [searchQuery, setSearchQuery] = React.useState('');
46
+ const [confirmingProfile, setConfirmingProfile] = React.useState<Profile | null>(null);
47
+ const fileInputRef = React.useRef<HTMLInputElement | null>(null);
48
+
49
+ const handleApplyWithConfirm = (profile: Profile, isApplied: boolean) => {
50
+ if (isApplied) {
51
+ setConfirmingProfile(profile);
52
+ } else {
53
+ onApply(profile.id);
54
+ }
55
+ };
56
+
57
+ const handleConfirmReset = () => {
58
+ if (confirmingProfile) {
59
+ onApply(confirmingProfile.id);
60
+ setConfirmingProfile(null);
61
+ }
62
+ };
63
+
64
+ const handleCancelConfirm = () => {
65
+ setConfirmingProfile(null);
66
+ };
67
+
68
+ const handleImportClick = () => {
69
+ fileInputRef.current?.click();
70
+ };
71
+
72
+ const handleImportChange = (event: React.ChangeEvent<HTMLInputElement>) => {
73
+ const file = event.target.files?.[0];
74
+ if (file) {
75
+ onImport(file);
76
+ }
77
+
78
+ event.target.value = '';
79
+ };
80
+
81
+ // Filter profiles based on search query (name or description)
82
+ const filteredProfiles = React.useMemo(() => {
83
+ if (!searchQuery.trim()) return profiles;
84
+
85
+ const query = searchQuery.toLowerCase();
86
+ return profiles.filter(
87
+ (profile) =>
88
+ profile.name.toLowerCase().includes(query) ||
89
+ (profile.description?.toLowerCase() || '').includes(query)
90
+ );
91
+ }, [profiles, searchQuery]);
92
+
93
+ // Separate active, built-in, and custom profiles for grouping
94
+ const { active, builtIn, custom } = React.useMemo(() => {
95
+ const active: Profile[] = [];
96
+ const builtIn: Profile[] = [];
97
+ const custom: Profile[] = [];
98
+
99
+ filteredProfiles.forEach((profile) => {
100
+ if (profile.id === activeProfileId) {
101
+ active.push(profile);
102
+ } else if (profile.isBuiltIn) {
103
+ builtIn.push(profile);
104
+ } else {
105
+ custom.push(profile);
106
+ }
107
+ });
108
+
109
+ return { active, builtIn, custom };
110
+ }, [filteredProfiles, activeProfileId]);
111
+
112
+ const totalCount = profiles.length;
113
+ const filteredCount = filteredProfiles.length;
114
+ const isFiltering = searchQuery.trim().length > 0;
115
+
116
+ return (
117
+ <div className="space-y-4">
118
+ {/* Header with search and count */}
119
+ <div className="flex items-center gap-3">
120
+ <div className="relative flex-1">
121
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-zinc-400" />
122
+ <input
123
+ type="text"
124
+ placeholder="Search profiles..."
125
+ value={searchQuery}
126
+ onChange={(e) => setSearchQuery(e.target.value)}
127
+ className="w-full pl-9 pr-3 py-2 text-sm bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg
128
+ placeholder:text-zinc-400
129
+ focus:outline-none focus:ring-2 focus:ring-teal-500/20 focus:border-teal-500
130
+ transition-all duration-200"
131
+ />
132
+ </div>
133
+ <div className="flex items-center gap-1.5 text-xs text-zinc-500 dark:text-zinc-400 tabular-nums">
134
+ <Users className="h-3.5 w-3.5" />
135
+ <span>
136
+ {isFiltering ? `${filteredCount} of ${totalCount}` : `${totalCount}`} profiles
137
+ </span>
138
+ </div>
139
+ <input
140
+ ref={fileInputRef}
141
+ type="file"
142
+ accept="application/json,.json"
143
+ className="sr-only"
144
+ onChange={handleImportChange}
145
+ aria-label="Import profile file"
146
+ />
147
+ <button
148
+ type="button"
149
+ onClick={handleImportClick}
150
+ className="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2 text-sm font-medium text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800 transition-colors"
151
+ >
152
+ <Upload className="h-4 w-4" />
153
+ Import File
154
+ </button>
155
+ </div>
156
+
157
+ {/* Empty state */}
158
+ {filteredProfiles.length === 0 && (
159
+ <div className="text-center py-12 px-4">
160
+ <div className="inline-flex items-center justify-center w-12 h-12 rounded-full bg-zinc-100 dark:bg-zinc-800 mb-3">
161
+ <Users className="h-5 w-5 text-zinc-400 dark:text-zinc-500" />
162
+ </div>
163
+ <p className="text-sm font-medium text-zinc-900 dark:text-zinc-100">
164
+ {isFiltering ? 'No profiles match your search' : 'No profiles yet'}
165
+ </p>
166
+ <p className="text-xs text-zinc-500 dark:text-zinc-400 mt-1">
167
+ {isFiltering
168
+ ? 'Try a different search term'
169
+ : 'Create your first profile to get started'}
170
+ </p>
171
+ </div>
172
+ )}
173
+
174
+ {/* Profile groups */}
175
+ {filteredProfiles.length > 0 && (
176
+ <div className="space-y-4">
177
+ {/* Active Profile */}
178
+ {active.length > 0 && (
179
+ <section>
180
+ <div className="flex items-center gap-2 mb-2">
181
+ <span className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-[10px] font-semibold bg-teal-100 text-teal-700 dark:bg-teal-900/40 dark:text-teal-300 uppercase tracking-wider">
182
+ <span className="w-1.5 h-1.5 rounded-full bg-teal-500 animate-pulse" />
183
+ Active
184
+ </span>
185
+ <span className="text-[10px] text-zinc-400 dark:text-zinc-500 tabular-nums">
186
+ {active.length}
187
+ </span>
188
+ </div>
189
+ <div className="space-y-2">
190
+ {active.map((profile) => (
191
+ <ProfileCard
192
+ key={profile.id}
193
+ profile={profile}
194
+ isActive={true}
195
+ isApplied={profile.id === appliedProfileId}
196
+ onApply={() => handleApplyWithConfirm(profile, profile.id === appliedProfileId)}
197
+ onEdit={() => onEdit(profile)}
198
+ onDelete={() => onDelete(profile.id)}
199
+ onExport={() => onExport(profile)}
200
+ />
201
+ ))}
202
+ </div>
203
+ </section>
204
+ )}
205
+
206
+ {/* Built-in Profiles */}
207
+ {builtIn.length > 0 && (
208
+ <section>
209
+ <div className="flex items-center gap-2 mb-2">
210
+ <span className="text-[10px] font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
211
+ Built-in
212
+ </span>
213
+ <span className="text-[10px] text-zinc-400 dark:text-zinc-500 tabular-nums">
214
+ {builtIn.length}
215
+ </span>
216
+ </div>
217
+ <div className="space-y-2">
218
+ {builtIn.map((profile) => (
219
+ <ProfileCard
220
+ key={profile.id}
221
+ profile={profile}
222
+ isActive={false}
223
+ isApplied={profile.id === appliedProfileId}
224
+ onApply={() => handleApplyWithConfirm(profile, profile.id === appliedProfileId)}
225
+ onEdit={() => onEdit(profile)}
226
+ onDelete={() => onDelete(profile.id)}
227
+ onExport={() => onExport(profile)}
228
+ />
229
+ ))}
230
+ </div>
231
+ </section>
232
+ )}
233
+
234
+ {/* Custom Profiles */}
235
+ {custom.length > 0 && (
236
+ <section>
237
+ <div className="flex items-center gap-2 mb-2">
238
+ <span className="text-[10px] font-semibold text-zinc-500 dark:text-zinc-400 uppercase tracking-wider">
239
+ Custom
240
+ </span>
241
+ <span className="text-[10px] text-zinc-400 dark:text-zinc-500 tabular-nums">
242
+ {custom.length}
243
+ </span>
244
+ </div>
245
+ <div className="space-y-2">
246
+ {custom.map((profile) => (
247
+ <ProfileCard
248
+ key={profile.id}
249
+ profile={profile}
250
+ isActive={false}
251
+ isApplied={profile.id === appliedProfileId}
252
+ onApply={() => handleApplyWithConfirm(profile, profile.id === appliedProfileId)}
253
+ onEdit={() => onEdit(profile)}
254
+ onDelete={() => onDelete(profile.id)}
255
+ onExport={() => onExport(profile)}
256
+ />
257
+ ))}
258
+ </div>
259
+ </section>
260
+ )}
261
+ </div>
262
+ )}
263
+
264
+ {/* Reset Confirmation Dialog */}
265
+ {confirmingProfile && (
266
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm">
267
+ <div className="w-full max-w-md mx-4 bg-white dark:bg-zinc-900 rounded-xl border border-zinc-200 dark:border-zinc-700 shadow-2xl">
268
+ <div className="p-6">
269
+ <div className="flex items-start gap-4">
270
+ <div className="flex-shrink-0 w-12 h-12 rounded-full bg-amber-100 dark:bg-amber-900/30 flex items-center justify-center">
271
+ <AlertTriangle className="h-6 w-6 text-amber-600 dark:text-amber-400" />
272
+ </div>
273
+ <div className="flex-1">
274
+ <h3 className="text-lg font-semibold text-zinc-900 dark:text-zinc-100">
275
+ Reset Profile Configuration
276
+ </h3>
277
+ <p className="mt-2 text-sm text-zinc-600 dark:text-zinc-400">
278
+ This will reset all agent and category configurations back to the <strong>{confirmingProfile.name}</strong> profile values. Any changes made after applying this profile will be lost.
279
+ </p>
280
+ </div>
281
+ </div>
282
+
283
+ <div className="mt-6 flex items-center justify-end gap-3">
284
+ <button
285
+ type="button"
286
+ onClick={handleCancelConfirm}
287
+ className="inline-flex items-center gap-2 px-4 py-2 rounded-lg border border-zinc-200 dark:border-zinc-700 bg-white dark:bg-zinc-800 text-sm font-medium text-zinc-700 dark:text-zinc-300 hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors"
288
+ >
289
+ <X className="h-4 w-4" />
290
+ Cancel
291
+ </button>
292
+ <button
293
+ type="button"
294
+ onClick={handleConfirmReset}
295
+ className="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-amber-600 text-sm font-medium text-white hover:bg-amber-700 transition-colors"
296
+ >
297
+ <Check className="h-4 w-4" />
298
+ Reset to {confirmingProfile.name}
299
+ </button>
300
+ </div>
301
+ </div>
302
+ </div>
303
+ </div>
304
+ )}
305
+
306
+ {/* Create New button */}
307
+ <button
308
+ type="button"
309
+ onClick={onCreateNew}
310
+ className="w-full flex items-center justify-center gap-2 py-3 px-4 rounded-lg border border-dashed border-zinc-300 dark:border-zinc-700
311
+ text-sm font-medium text-zinc-600 dark:text-zinc-400
312
+ hover:border-teal-400 hover:text-teal-600 dark:hover:border-teal-500 dark:hover:text-teal-400
313
+ hover:bg-teal-50/50 dark:hover:bg-teal-900/10
314
+ transition-all duration-200"
315
+ >
316
+ <Plus className="h-4 w-4" />
317
+ Create New Profile
318
+ </button>
319
+ </div>
320
+ );
321
+ }
322
+
323
+ // ProfileCard interface - assume external component exists
324
+ interface ProfileCardProps {
325
+ profile: Profile;
326
+ isActive: boolean;
327
+ isApplied: boolean;
328
+ onApply: () => void;
329
+ onEdit: () => void;
330
+ onDelete: () => void;
331
+ onExport: () => void;
332
+ }
333
+
334
+ // Inline ProfileCard implementation for completeness
335
+ function ProfileCard({
336
+ profile,
337
+ isActive,
338
+ isApplied,
339
+ onApply,
340
+ onEdit,
341
+ onDelete,
342
+ onExport,
343
+ }: ProfileCardProps) {
344
+ return (
345
+ <div
346
+ className={`
347
+ group relative flex items-center justify-between p-3 rounded-lg border
348
+ transition-all duration-200
349
+ ${
350
+ isActive
351
+ ? 'bg-teal-50/50 border-teal-200 dark:bg-teal-900/20 dark:border-teal-700/50'
352
+ : 'bg-white border-zinc-200 dark:bg-zinc-900 dark:border-zinc-700 hover:border-zinc-300 dark:hover:border-zinc-600'
353
+ }
354
+ `}
355
+ >
356
+ <div className="flex items-center gap-3 flex-1 min-w-0">
357
+ <span className="text-xl" role="img" aria-label={`${profile.name} icon`}>
358
+ {profile.emoji}
359
+ </span>
360
+ <div className="flex-1 min-w-0">
361
+ <div className="flex items-center gap-2">
362
+ <h4 className="text-sm font-medium text-zinc-900 dark:text-zinc-100 truncate">
363
+ {profile.name}
364
+ </h4>
365
+ {profile.isDefault && (
366
+ <span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300">
367
+ Default
368
+ </span>
369
+ )}
370
+ {profile.isBuiltIn && (
371
+ <span className="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300">
372
+ Built-in
373
+ </span>
374
+ )}
375
+ </div>
376
+ {profile.description && (
377
+ <p className="mt-0.5 text-xs text-zinc-500 dark:text-zinc-400 truncate">
378
+ {profile.description}
379
+ </p>
380
+ )}
381
+ </div>
382
+ </div>
383
+
384
+ <div className="flex items-center gap-1 ml-3">
385
+ <button
386
+ type="button"
387
+ onClick={onApply}
388
+ disabled={isActive && !isApplied}
389
+ title={isApplied ? 'Reset config to this profile' : isActive ? 'Currently active' : 'Apply this profile'}
390
+ className={`
391
+ px-2.5 py-1 rounded-md text-xs font-medium
392
+ transition-all duration-200
393
+ ${
394
+ isApplied
395
+ ? 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/40 dark:text-amber-300 dark:hover:bg-amber-900/60'
396
+ : isActive
397
+ ? 'bg-teal-100 text-teal-700 dark:bg-teal-900/40 dark:text-teal-300 cursor-default'
398
+ : 'bg-zinc-100 text-zinc-700 hover:bg-teal-100 hover:text-teal-700 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-teal-900/30 dark:hover:text-teal-300'
399
+ }
400
+ `}
401
+ >
402
+ {isApplied ? 'Reset' : isActive ? 'Active' : 'Apply'}
403
+ </button>
404
+ <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
405
+ <button
406
+ type="button"
407
+ onClick={onExport}
408
+ className="p-1.5 rounded-md text-zinc-400 hover:text-teal-600 hover:bg-teal-50 dark:text-zinc-500 dark:hover:text-teal-300 dark:hover:bg-teal-900/20 transition-colors"
409
+ aria-label={`Export ${profile.name}`}
410
+ title={`Export ${profile.name}`}
411
+ >
412
+ <Download className="h-3.5 w-3.5" aria-hidden="true" />
413
+ </button>
414
+ <button
415
+ type="button"
416
+ onClick={onEdit}
417
+ className="p-1.5 rounded-md text-zinc-400 hover:text-zinc-700 hover:bg-zinc-100 dark:text-zinc-500 dark:hover:text-zinc-200 dark:hover:bg-zinc-800 transition-colors"
418
+ aria-label={`Edit ${profile.name}`}
419
+ title={`Edit ${profile.name}`}
420
+ >
421
+ <svg className="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2} role="img">
422
+ <title>Edit</title>
423
+ <path strokeLinecap="round" strokeLinejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
424
+ </svg>
425
+ </button>
426
+ {!profile.isBuiltIn && !profile.isDefault && (
427
+ <button
428
+ type="button"
429
+ onClick={onDelete}
430
+ className="p-1.5 rounded-md text-zinc-400 hover:text-red-600 hover:bg-red-50 dark:text-zinc-500 dark:hover:text-red-400 dark:hover:bg-red-900/20 transition-colors"
431
+ aria-label={`Delete ${profile.name}`}
432
+ title={`Delete ${profile.name}`}
433
+ >
434
+ <svg className="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2} role="img">
435
+ <title>Delete</title>
436
+ <path strokeLinecap="round" strokeLinejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
437
+ </svg>
438
+ </button>
439
+ )}
440
+ </div>
441
+ </div>
442
+ </div>
443
+ );
444
+ }
445
+
446
+ export default ProfileList;
@@ -0,0 +1,225 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { render, screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { ProfileManager } from './ProfileManager';
5
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
+
7
+ const mockFetch = vi.fn<typeof fetch>();
8
+ global.fetch = mockFetch;
9
+
10
+ function jsonResponse(data: unknown): Response {
11
+ return {
12
+ ok: true,
13
+ status: 200,
14
+ json: async () => data,
15
+ } as Response;
16
+ }
17
+
18
+ function blobResponse(data: Blob): Response {
19
+ return {
20
+ ok: true,
21
+ status: 200,
22
+ blob: async () => data,
23
+ } as Response;
24
+ }
25
+
26
+ describe('ProfileManager', () => {
27
+ let queryClient: QueryClient;
28
+
29
+ beforeEach(() => {
30
+ queryClient = new QueryClient({
31
+ defaultOptions: {
32
+ queries: { staleTime: 0 },
33
+ },
34
+ });
35
+ vi.clearAllMocks();
36
+ });
37
+
38
+ it('should load and display profile list correctly', async () => {
39
+ mockFetch.mockResolvedValueOnce(
40
+ jsonResponse({
41
+ profiles: [
42
+ { id: 'coding', name: 'Coding Mode', emoji: '🚀', isBuiltIn: true },
43
+ { id: 'custom1', name: 'Custom Profile', emoji: '⚙️' },
44
+ ],
45
+ activeProfileId: null,
46
+ })
47
+ );
48
+
49
+ render(
50
+ <QueryClientProvider client={queryClient}>
51
+ <ProfileManager />
52
+ </QueryClientProvider>
53
+ );
54
+
55
+ await waitFor(() => {
56
+ expect(screen.getByText('Coding Mode')).toBeInTheDocument();
57
+ });
58
+ });
59
+
60
+ it('should call API correctly when applying profile', async () => {
61
+ const user = userEvent.setup();
62
+
63
+ mockFetch
64
+ .mockResolvedValueOnce(
65
+ jsonResponse({
66
+ profiles: [{ id: 'coding', name: 'Coding', emoji: '🚀', isBuiltIn: true }],
67
+ activeProfileId: null,
68
+ })
69
+ )
70
+ .mockResolvedValueOnce(jsonResponse({ message: 'Profile applied successfully' }));
71
+
72
+ render(
73
+ <QueryClientProvider client={queryClient}>
74
+ <ProfileManager />
75
+ </QueryClientProvider>
76
+ );
77
+
78
+ await waitFor(() => {
79
+ expect(screen.getByText('Coding')).toBeInTheDocument();
80
+ });
81
+
82
+ const applyButtons = screen.getAllByRole('button', { name: /apply/i });
83
+ await user.click(applyButtons[0]);
84
+
85
+ await waitFor(() => {
86
+ expect(mockFetch).toHaveBeenCalledWith(
87
+ '/api/profiles/coding/apply',
88
+ expect.objectContaining({ method: 'POST' })
89
+ );
90
+ });
91
+ });
92
+
93
+ it('should invalidate profiles and opencode-config query cache when applying profile', async () => {
94
+ const user = userEvent.setup();
95
+ const invalidateQueriesSpy = vi.spyOn(queryClient, 'invalidateQueries');
96
+
97
+ await queryClient.prefetchQuery({
98
+ queryKey: ['opencode-config'],
99
+ queryFn: async () => ({ config: 'test' }),
100
+ });
101
+
102
+ mockFetch
103
+ .mockResolvedValueOnce(
104
+ jsonResponse({
105
+ profiles: [{ id: 'coding', name: 'Coding', emoji: '🚀', isBuiltIn: true }],
106
+ activeProfileId: null,
107
+ })
108
+ )
109
+ .mockResolvedValueOnce(jsonResponse({ message: 'Profile applied successfully' }));
110
+
111
+ render(
112
+ <QueryClientProvider client={queryClient}>
113
+ <ProfileManager />
114
+ </QueryClientProvider>
115
+ );
116
+
117
+ await waitFor(() => {
118
+ expect(screen.getByText('Coding')).toBeInTheDocument();
119
+ });
120
+
121
+ const applyButtons = screen.getAllByRole('button', { name: /apply/i });
122
+ await user.click(applyButtons[0]);
123
+
124
+ await waitFor(() => {
125
+ expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['profiles'] });
126
+ expect(invalidateQueriesSpy).toHaveBeenCalledWith({ queryKey: ['opencode-config'] });
127
+ });
128
+ });
129
+
130
+ it('should call export API when exporting a profile', async () => {
131
+ const user = userEvent.setup();
132
+
133
+ mockFetch
134
+ .mockResolvedValueOnce(
135
+ jsonResponse({
136
+ profiles: [{ id: 'coding', name: 'Coding', emoji: '🚀', isBuiltIn: true }],
137
+ activeProfileId: null,
138
+ })
139
+ )
140
+ .mockResolvedValueOnce(blobResponse(new Blob(['{}'], { type: 'application/json' })));
141
+
142
+ render(
143
+ <QueryClientProvider client={queryClient}>
144
+ <ProfileManager />
145
+ </QueryClientProvider>
146
+ );
147
+
148
+ await waitFor(() => {
149
+ expect(screen.getByText('Coding')).toBeInTheDocument();
150
+ });
151
+
152
+ await user.click(screen.getByRole('button', { name: /export coding/i }));
153
+
154
+ await waitFor(() => {
155
+ expect(mockFetch).toHaveBeenCalledWith('/api/profiles/coding/export');
156
+ });
157
+ });
158
+
159
+ it('should call import API when uploading a profile file', async () => {
160
+ const user = userEvent.setup();
161
+
162
+ mockFetch
163
+ .mockResolvedValueOnce(
164
+ jsonResponse({
165
+ profiles: [{ id: 'coding', name: 'Coding', emoji: '🚀', isBuiltIn: true }],
166
+ activeProfileId: null,
167
+ })
168
+ )
169
+ .mockResolvedValueOnce(
170
+ jsonResponse({
171
+ profile: { id: 'shared', name: 'Shared Team', emoji: '🤝' },
172
+ })
173
+ )
174
+ .mockResolvedValueOnce(
175
+ jsonResponse({
176
+ profiles: [
177
+ { id: 'coding', name: 'Coding', emoji: '🚀', isBuiltIn: true },
178
+ { id: 'shared', name: 'Shared Team', emoji: '🤝' },
179
+ ],
180
+ activeProfileId: null,
181
+ })
182
+ );
183
+
184
+ render(
185
+ <QueryClientProvider client={queryClient}>
186
+ <ProfileManager />
187
+ </QueryClientProvider>
188
+ );
189
+
190
+ await waitFor(() => {
191
+ expect(screen.getByText('Coding')).toBeInTheDocument();
192
+ });
193
+
194
+ const file = new File(
195
+ [
196
+ JSON.stringify({
197
+ profile: { id: 'shared', name: 'Shared Team', emoji: '🤝' },
198
+ config: { agents: {} },
199
+ }),
200
+ ],
201
+ 'shared-profile.json',
202
+ { type: 'application/json' }
203
+ );
204
+ Object.defineProperty(file, 'text', {
205
+ value: vi.fn().mockResolvedValue(
206
+ JSON.stringify({
207
+ profile: { id: 'shared', name: 'Shared Team', emoji: '🤝' },
208
+ config: { agents: {} },
209
+ })
210
+ ),
211
+ });
212
+
213
+ await user.upload(screen.getByLabelText(/import profile file/i), file);
214
+
215
+ await waitFor(() => {
216
+ expect(mockFetch).toHaveBeenCalledWith(
217
+ '/api/profiles/import',
218
+ expect.objectContaining({
219
+ method: 'POST',
220
+ headers: { 'Content-Type': 'application/json' },
221
+ })
222
+ );
223
+ });
224
+ });
225
+ });