vibepulse 0.2.1 → 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +1 -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 +8 -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/sessions/[id]/open-editor/route.js.nft.json +1 -1
  32. package/.next/server/app/api/node/sessions/route.js +5 -3
  33. package/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
  34. package/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
  35. package/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
  36. package/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
  37. package/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
  38. package/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
  39. package/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
  40. package/.next/server/app/api/profiles/route.js.nft.json +1 -1
  41. package/.next/server/app/api/sessions/[id]/archive/route.js +3 -2
  42. package/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  43. package/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  44. package/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  45. package/.next/server/app/api/sessions/[id]/open-editor/route.js +1 -1
  46. package/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -1
  47. package/.next/server/app/api/sessions/[id]/restore/route/app-paths-manifest.json +3 -0
  48. package/.next/server/app/api/sessions/[id]/restore/route/build-manifest.json +11 -0
  49. package/.next/server/app/api/sessions/[id]/restore/route/server-reference-manifest.json +4 -0
  50. package/.next/server/app/api/sessions/[id]/restore/route.js +8 -0
  51. package/.next/server/app/api/sessions/[id]/restore/route.js.map +5 -0
  52. package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -0
  53. package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +2 -0
  54. package/.next/server/app/api/sessions/route.js +5 -3
  55. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  56. package/.next/server/app/index.html +1 -1
  57. package/.next/server/app/index.rsc +3 -3
  58. package/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  59. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  60. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  61. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  62. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/page_client-reference-manifest.js +1 -1
  64. package/.next/server/app-paths-manifest.json +1 -0
  65. package/.next/server/chunks/[root-of-the-server]__31d19c5c._.js +3 -0
  66. package/.next/server/chunks/[root-of-the-server]__31d19c5c._.js.map +1 -0
  67. package/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
  68. package/.next/server/chunks/[root-of-the-server]__56690af0._.js.map +1 -1
  69. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
  70. package/.next/server/chunks/[root-of-the-server]__56f5f249._.js.map +1 -1
  71. package/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
  72. package/.next/server/chunks/[root-of-the-server]__59175de4._.js.map +1 -1
  73. package/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js +3 -0
  74. package/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js.map +1 -0
  75. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
  76. package/.next/server/chunks/[root-of-the-server]__64fffc02._.js.map +1 -1
  77. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
  78. package/.next/server/chunks/[root-of-the-server]__89c5eeab._.js.map +1 -1
  79. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
  80. package/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js.map +1 -1
  81. package/.next/server/chunks/[root-of-the-server]__98073dd6._.js +3 -0
  82. package/.next/server/chunks/[root-of-the-server]__98073dd6._.js.map +1 -0
  83. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
  84. package/.next/server/chunks/[root-of-the-server]__b796d06c._.js.map +1 -1
  85. package/.next/server/chunks/[root-of-the-server]__b7b717eb._.js +3 -0
  86. package/.next/server/chunks/[root-of-the-server]__b7b717eb._.js.map +1 -0
  87. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
  88. package/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js.map +1 -1
  89. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js +1 -1
  90. package/.next/server/chunks/[root-of-the-server]__d8e61048._.js.map +1 -1
  91. package/.next/server/chunks/[root-of-the-server]__f441109e._.js +3 -0
  92. package/.next/server/chunks/[root-of-the-server]__f441109e._.js.map +1 -0
  93. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js +3 -0
  94. package/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js.map +1 -0
  95. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_2edc9589.js +3 -0
  96. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_2edc9589.js.map +1 -0
  97. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js +3 -0
  98. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js.map +1 -0
  99. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +1 -1
  100. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js.map +1 -1
  101. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  102. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js.map +1 -1
  103. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d0c0f338.js +3 -0
  104. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d0c0f338.js.map +1 -0
  105. package/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js +3 -0
  106. package/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js.map +1 -0
  107. package/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js → [root-of-the-server]__c91a8380._.js} +2 -2
  108. package/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js.map → [root-of-the-server]__c91a8380._.js.map} +1 -1
  109. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +4 -4
  110. package/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js.map +1 -1
  111. package/.next/server/pages/404.html +1 -1
  112. package/.next/server/pages/500.html +2 -2
  113. package/.next/server/server-reference-manifest.js +1 -1
  114. package/.next/server/server-reference-manifest.json +1 -1
  115. package/.next/standalone/.next/BUILD_ID +1 -1
  116. package/.next/standalone/.next/app-path-routes-manifest.json +1 -0
  117. package/.next/standalone/.next/build-manifest.json +2 -2
  118. package/.next/standalone/.next/prerender-manifest.json +3 -3
  119. package/.next/standalone/.next/routes-manifest.json +8 -0
  120. package/.next/standalone/.next/server/app/_global-error/page.js +1 -1
  121. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/_global-error.html +2 -2
  123. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  124. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  125. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  126. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  127. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  128. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  129. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  130. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  131. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  132. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  133. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  134. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  135. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  136. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  137. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  138. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  139. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  140. package/.next/standalone/.next/server/app/api/node/sessions/[id]/open-editor/route.js.nft.json +1 -1
  141. package/.next/standalone/.next/server/app/api/node/sessions/route.js +5 -3
  142. package/.next/standalone/.next/server/app/api/node/sessions/route.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/api/opencode-config/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/opencode-config/status/route.js.nft.json +1 -1
  145. package/.next/standalone/.next/server/app/api/profiles/[id]/apply/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/api/profiles/[id]/export/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/api/profiles/[id]/route.js.nft.json +1 -1
  148. package/.next/standalone/.next/server/app/api/profiles/import/route.js.nft.json +1 -1
  149. package/.next/standalone/.next/server/app/api/profiles/route.js.nft.json +1 -1
  150. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js +3 -2
  151. package/.next/standalone/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
  152. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js +3 -2
  153. package/.next/standalone/.next/server/app/api/sessions/[id]/delete/route.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js +1 -1
  155. package/.next/standalone/.next/server/app/api/sessions/[id]/open-editor/route.js.nft.json +1 -1
  156. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/app-paths-manifest.json +3 -0
  157. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/build-manifest.json +11 -0
  158. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route/server-reference-manifest.json +4 -0
  159. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js +8 -0
  160. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js.map +5 -0
  161. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -0
  162. package/.next/standalone/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +2 -0
  163. package/.next/standalone/.next/server/app/api/sessions/route.js +5 -3
  164. package/.next/standalone/.next/server/app/api/sessions/route.js.nft.json +1 -1
  165. package/.next/standalone/.next/server/app/index.html +1 -1
  166. package/.next/standalone/.next/server/app/index.rsc +3 -3
  167. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  168. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  169. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  170. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  171. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  172. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  173. package/.next/standalone/.next/server/app-paths-manifest.json +1 -0
  174. package/.next/standalone/.next/server/chunks/[root-of-the-server]__31d19c5c._.js +3 -0
  175. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56690af0._.js +1 -1
  176. package/.next/standalone/.next/server/chunks/[root-of-the-server]__56f5f249._.js +1 -1
  177. package/.next/standalone/.next/server/chunks/[root-of-the-server]__59175de4._.js +1 -1
  178. package/.next/standalone/.next/server/chunks/[root-of-the-server]__5e0a0e38._.js +3 -0
  179. package/.next/standalone/.next/server/chunks/[root-of-the-server]__64fffc02._.js +1 -1
  180. package/.next/standalone/.next/server/chunks/[root-of-the-server]__89c5eeab._.js +1 -1
  181. package/.next/standalone/.next/server/chunks/[root-of-the-server]__8da6c5a8._.js +1 -1
  182. package/.next/standalone/.next/server/chunks/[root-of-the-server]__98073dd6._.js +3 -0
  183. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b796d06c._.js +1 -1
  184. package/.next/standalone/.next/server/chunks/[root-of-the-server]__b7b717eb._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/[root-of-the-server]__c2ce5c0f._.js +1 -1
  186. package/.next/standalone/.next/server/chunks/[root-of-the-server]__d8e61048._.js +1 -1
  187. package/.next/standalone/.next/server/chunks/[root-of-the-server]__f441109e._.js +3 -0
  188. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_sessions_[id]_restore_route_actions_af7d6b6c.js +3 -0
  189. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_2edc9589.js +3 -0
  190. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_7f178d4a.js +3 -0
  191. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_aca45402.js +1 -1
  192. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_b054aff3.js +1 -1
  193. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_d0c0f338.js +3 -0
  194. package/.next/standalone/.next/server/chunks/src_lib_session-providers_claudeCode_ts_0f9590ed._.js +3 -0
  195. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__631e12d0._.js → [root-of-the-server]__c91a8380._.js} +2 -2
  196. package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_a7111f3e._.js +4 -4
  197. package/.next/standalone/.next/server/pages/404.html +1 -1
  198. package/.next/standalone/.next/server/pages/500.html +2 -2
  199. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  200. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  201. package/.next/standalone/.next/static/chunks/b3bc362202331708.css +3 -0
  202. package/.next/standalone/.next/static/chunks/c1294e057d8d4681.js +13 -0
  203. package/.next/standalone/AGENTS.md +2 -2
  204. package/.next/standalone/README.md +30 -7
  205. package/.next/standalone/docs/session-status-detection.md +36 -0
  206. package/.next/standalone/docs/superpowers/plans/2026-04-05-oh-my-openagent-migration.md +57 -0
  207. package/.next/standalone/docs/superpowers/specs/2026-04-09-claude-capability-alignment-design.md +39 -0
  208. package/.next/standalone/package-lock.json +2 -2
  209. package/.next/standalone/package.json +1 -1
  210. package/.next/standalone/src/app/api/AGENTS.md +2 -2
  211. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.test.ts +60 -1
  212. package/.next/standalone/src/app/api/node/sessions/[id]/archive/route.ts +77 -22
  213. package/.next/standalone/src/app/api/node/sessions/route.test.ts +282 -0
  214. package/.next/standalone/src/app/api/node/sessions/route.ts +141 -17
  215. package/.next/standalone/src/app/api/opencode-config/status/route.ts +6 -7
  216. package/.next/standalone/src/app/api/opencode-events/route.test.ts +3 -1
  217. package/.next/standalone/src/app/api/sessions/[id]/archive/route.test.ts +101 -0
  218. package/.next/standalone/src/app/api/sessions/[id]/archive/route.ts +47 -12
  219. package/.next/standalone/src/app/api/sessions/[id]/delete/route.test.ts +92 -0
  220. package/.next/standalone/src/app/api/sessions/[id]/delete/route.ts +45 -10
  221. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.test.ts +74 -0
  222. package/.next/standalone/src/app/api/sessions/[id]/open-editor/route.ts +22 -2
  223. package/.next/standalone/src/app/api/sessions/[id]/restore/route.test.ts +186 -0
  224. package/.next/standalone/src/app/api/sessions/[id]/restore/route.ts +184 -0
  225. package/.next/standalone/src/app/api/sessions/route.test.ts +1889 -107
  226. package/.next/standalone/src/app/api/sessions/route.ts +365 -981
  227. package/.next/standalone/src/components/AGENTS.md +2 -2
  228. package/.next/standalone/src/components/KanbanBoard.test.tsx +307 -1
  229. package/.next/standalone/src/components/KanbanBoard.tsx +105 -18
  230. package/.next/standalone/src/components/ProjectCard.test.tsx +416 -2
  231. package/.next/standalone/src/components/ProjectCard.tsx +238 -86
  232. package/.next/standalone/src/components/SessionCard.test.tsx +253 -2
  233. package/.next/standalone/src/components/SessionCard.tsx +182 -76
  234. package/.next/standalone/src/components/opencode-config/AgentConfigForm.test.tsx +28 -0
  235. package/.next/standalone/src/components/opencode-config/AgentConfigForm.tsx +9 -9
  236. package/.next/standalone/src/components/opencode-config/ConfigButton.tsx +4 -4
  237. package/.next/standalone/src/components/opencode-config/categories/CategoriesList.tsx +10 -8
  238. package/.next/standalone/src/components/opencode-config/categories/CategoriesManager.test.tsx +29 -1
  239. package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.test.tsx +49 -0
  240. package/.next/standalone/src/components/opencode-config/categories/CategoryConfigForm.tsx +6 -6
  241. package/.next/standalone/src/hooks/useOpencodeSync.test.ts +321 -1
  242. package/.next/standalone/src/hooks/useOpencodeSync.ts +16 -12
  243. package/.next/standalone/src/index.ts +1 -1
  244. package/.next/standalone/src/lib/claudeSessionOverrides.test.ts +75 -0
  245. package/.next/standalone/src/lib/claudeSessionOverrides.ts +169 -0
  246. package/.next/standalone/src/lib/opencodeConfig.test.ts +53 -4
  247. package/.next/standalone/src/lib/opencodeConfig.ts +24 -12
  248. package/.next/standalone/src/lib/profiles/storage.test.ts +38 -1
  249. package/.next/standalone/src/lib/profiles/storage.ts +17 -17
  250. package/.next/standalone/src/lib/session-providers/claudeCode.test.ts +2288 -0
  251. package/.next/standalone/src/lib/session-providers/claudeCode.ts +1083 -0
  252. package/.next/standalone/src/lib/session-providers/localAggregator.test.ts +322 -0
  253. package/.next/standalone/src/lib/session-providers/localAggregator.ts +302 -0
  254. package/.next/standalone/src/lib/session-providers/opencodeProvider.ts +723 -0
  255. package/.next/standalone/src/lib/session-providers/providerIds.test.ts +337 -0
  256. package/.next/standalone/src/lib/session-providers/providerIds.ts +176 -0
  257. package/.next/standalone/src/lib/session-providers/types.ts +131 -0
  258. package/.next/standalone/src/lib/transform.test.ts +253 -0
  259. package/.next/standalone/src/lib/transform.ts +96 -37
  260. package/.next/standalone/src/types/index.ts +23 -17
  261. package/.next/standalone/src/types/opencodeConfig.ts +1 -9
  262. package/.next/static/chunks/b3bc362202331708.css +3 -0
  263. package/.next/static/chunks/c1294e057d8d4681.js +13 -0
  264. package/.next/trace +1 -1
  265. package/.next/trace-build +1 -1
  266. package/.next/types/routes.d.ts +2 -1
  267. package/.next/types/validator.ts +9 -0
  268. package/README.md +30 -7
  269. package/package.json +1 -1
  270. package/.next/server/chunks/[root-of-the-server]__2f981540._.js +0 -3
  271. package/.next/server/chunks/[root-of-the-server]__2f981540._.js.map +0 -1
  272. package/.next/server/chunks/[root-of-the-server]__3745b314._.js +0 -3
  273. package/.next/server/chunks/[root-of-the-server]__3745b314._.js.map +0 -1
  274. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js +0 -3
  275. package/.next/server/chunks/[root-of-the-server]__6c428a24._.js.map +0 -1
  276. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js +0 -3
  277. package/.next/server/chunks/[root-of-the-server]__73a00b88._.js.map +0 -1
  278. package/.next/server/chunks/[root-of-the-server]__db285678._.js +0 -3
  279. package/.next/server/chunks/[root-of-the-server]__db285678._.js.map +0 -1
  280. package/.next/standalone/.next/server/chunks/[root-of-the-server]__2f981540._.js +0 -3
  281. package/.next/standalone/.next/server/chunks/[root-of-the-server]__3745b314._.js +0 -3
  282. package/.next/standalone/.next/server/chunks/[root-of-the-server]__6c428a24._.js +0 -3
  283. package/.next/standalone/.next/server/chunks/[root-of-the-server]__73a00b88._.js +0 -3
  284. package/.next/standalone/.next/server/chunks/[root-of-the-server]__db285678._.js +0 -3
  285. package/.next/standalone/.next/static/chunks/7ac19aaef01f4a03.js +0 -13
  286. package/.next/standalone/.next/static/chunks/f42202943f6742e5.css +0 -3
  287. package/.next/static/chunks/7ac19aaef01f4a03.js +0 -13
  288. package/.next/static/chunks/f42202943f6742e5.css +0 -3
  289. /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_buildManifest.js +0 -0
  290. /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_clientMiddlewareManifest.json +0 -0
  291. /package/.next/standalone/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_ssgManifest.js +0 -0
  292. /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_buildManifest.js +0 -0
  293. /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_clientMiddlewareManifest.json +0 -0
  294. /package/.next/static/{Fw2R3y-fHX4B2SWxNy_4X → bsWNvgDS7Zp38Yt9q0DUg}/_ssgManifest.js +0 -0
@@ -13,6 +13,12 @@ vi.mock('@/lib/opencodeConfig', () => ({
13
13
  readConfig: vi.fn(),
14
14
  }));
15
15
 
16
+ vi.mock('@/lib/session-providers/claudeCode', () => ({
17
+ claudeCodeLocalSessionProvider: {
18
+ getSessionsResult: vi.fn(),
19
+ },
20
+ }));
21
+
16
22
  vi.mock('child_process', async () => {
17
23
  const execSync = vi.fn();
18
24
  return {
@@ -39,6 +45,7 @@ import {
39
45
  discoverOpencodeProcessCwdsWithoutPortWithMeta,
40
46
  } from '@/lib/opencodeDiscovery';
41
47
  import { readConfig } from '@/lib/opencodeConfig';
48
+ import { claudeCodeLocalSessionProvider } from '@/lib/session-providers/claudeCode';
42
49
  import { createNodeRequestHeaders } from '@/lib/nodeProtocol';
43
50
 
44
51
  import { GET } from './route';
@@ -50,6 +57,7 @@ const mockCreateOpencodeClient: any = createOpencodeClient;
50
57
  const mockDiscoverPortsWithMeta: any = discoverOpencodePortsWithMeta;
51
58
  const mockDiscoverProcessCwdsWithoutPortWithMeta: any = discoverOpencodeProcessCwdsWithoutPortWithMeta;
52
59
  const mockReadConfig: any = readConfig;
60
+ const mockClaudeLocalProviderGetSessionsResult: any = claudeCodeLocalSessionProvider.getSessionsResult;
53
61
  const mockExecSync: any = execSync;
54
62
 
55
63
  function resetDefaultClientMock(): void {
@@ -82,6 +90,13 @@ function createNeverResolvingPromise<T>(signal?: AbortSignal): Promise<T> {
82
90
 
83
91
  function setupLocalSessionsMocks(): void {
84
92
  resetDefaultClientMock();
93
+ mockClaudeLocalProviderGetSessionsResult.mockResolvedValue({
94
+ payload: {
95
+ sessions: [],
96
+ processHints: [],
97
+ },
98
+ sourceMeta: { online: false },
99
+ });
85
100
 
86
101
  mockReadConfig.mockResolvedValue({
87
102
  vibepulse: {
@@ -225,9 +240,276 @@ describe('/api/node/sessions', () => {
225
240
  waitingForUser: true,
226
241
  });
227
242
  expect(JSON.stringify(data).includes('baseUrl')).toBe(false);
243
+ expect(data.sessions.every((session: any) => session.hostId === 'local')).toBe(true);
244
+ expect(data.sessions.every((session: any) => !session.baseUrl)).toBe(true);
228
245
  expect(mockCreateOpencodeClient.mock.calls).toEqual([[{ baseUrl: 'http://localhost:7777' }]]);
229
246
  });
230
247
 
248
+ it('carries nested Claude child topology in node polling payloads with provider-aware local ids', async () => {
249
+ mockClaudeLocalProviderGetSessionsResult.mockResolvedValue({
250
+ payload: {
251
+ sessions: [
252
+ {
253
+ id: 'claude~550e8400-e29b-41d4-a716-446655440000',
254
+ slug: '550e8400-e29b-41d4-a716-446655440000',
255
+ title: 'Claude Parent',
256
+ directory: '/repo/project-one',
257
+ projectName: 'project-one',
258
+ branch: 'main',
259
+ provider: 'claude-code',
260
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
261
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
262
+ topology: { childSessions: 'authoritative' },
263
+ readOnly: true,
264
+ realTimeStatus: 'busy',
265
+ waitingForUser: false,
266
+ children: [
267
+ {
268
+ id: '660e8400-e29b-41d4-a716-446655440000',
269
+ parentID: '550e8400-e29b-41d4-a716-446655440000',
270
+ rawSessionId: '660e8400-e29b-41d4-a716-446655440000',
271
+ providerRawId: '660e8400-e29b-41d4-a716-446655440000',
272
+ title: 'Claude Child',
273
+ directory: '/repo/project-one',
274
+ realTimeStatus: 'busy',
275
+ waitingForUser: false,
276
+ readOnly: true,
277
+ topology: { childSessions: 'authoritative' },
278
+ time: { created: 2_100, updated: Date.now() - 900 },
279
+ },
280
+ ],
281
+ time: { created: 2_000, updated: Date.now() - 1_000 },
282
+ },
283
+ ],
284
+ processHints: [],
285
+ },
286
+ sourceMeta: { online: true },
287
+ });
288
+
289
+ const response = await GET(
290
+ new Request('http://localhost/api/node/sessions', {
291
+ headers: createNodeRequestHeaders('shared-secret'),
292
+ })
293
+ );
294
+ const data = await response.json();
295
+
296
+ expect(response.status).toBe(200);
297
+ expect(data.sessions).toEqual(
298
+ expect.arrayContaining([
299
+ expect.objectContaining({ id: 'local:parent-1' }),
300
+ expect.objectContaining({
301
+ id: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
302
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
303
+ sourceSessionKey: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
304
+ provider: 'claude-code',
305
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
306
+ readOnly: true,
307
+ topology: { childSessions: 'authoritative' },
308
+ children: [
309
+ expect.objectContaining({
310
+ id: 'local:claude~660e8400-e29b-41d4-a716-446655440000',
311
+ rawSessionId: '660e8400-e29b-41d4-a716-446655440000',
312
+ sourceSessionKey: 'local:claude~660e8400-e29b-41d4-a716-446655440000',
313
+ parentID: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
314
+ provider: 'claude-code',
315
+ providerRawId: '660e8400-e29b-41d4-a716-446655440000',
316
+ hostId: 'local',
317
+ hostLabel: 'Local',
318
+ hostKind: 'local',
319
+ readOnly: true,
320
+ topology: { childSessions: 'authoritative' },
321
+ }),
322
+ ],
323
+ }),
324
+ ])
325
+ );
326
+ });
327
+
328
+ it('keeps flat Claude polling payloads backward-compatible when provider metadata is sparse', async () => {
329
+ mockClaudeLocalProviderGetSessionsResult.mockResolvedValue({
330
+ payload: {
331
+ sessions: [
332
+ {
333
+ id: 'claude~550e8400-e29b-41d4-a716-446655440000',
334
+ slug: '550e8400-e29b-41d4-a716-446655440000',
335
+ title: 'Claude Flat Session',
336
+ directory: '/repo/project-one',
337
+ projectName: 'project-one',
338
+ branch: 'main',
339
+ realTimeStatus: 'idle',
340
+ waitingForUser: false,
341
+ readOnly: true,
342
+ children: [],
343
+ time: { created: 3_000, updated: Date.now() - 1_500 },
344
+ },
345
+ ],
346
+ processHints: [],
347
+ },
348
+ sourceMeta: { online: true },
349
+ });
350
+
351
+ const response = await GET(
352
+ new Request('http://localhost/api/node/sessions', {
353
+ headers: createNodeRequestHeaders('shared-secret'),
354
+ })
355
+ );
356
+ const data = await response.json();
357
+
358
+ expect(response.status).toBe(200);
359
+ expect(data.sessions).toEqual(
360
+ expect.arrayContaining([
361
+ expect.objectContaining({
362
+ id: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
363
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
364
+ sourceSessionKey: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
365
+ provider: 'claude-code',
366
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
367
+ readOnly: true,
368
+ children: [],
369
+ }),
370
+ ])
371
+ );
372
+ });
373
+
374
+ it('returns Claude polling sessions when OpenCode ports are absent but Claude provider is available', async () => {
375
+ mockDiscoverProcessCwdsWithoutPortWithMeta.mockReturnValue({
376
+ processes: [],
377
+ timedOut: false,
378
+ });
379
+ mockDiscoverPortsWithMeta.mockReturnValue({
380
+ ports: [],
381
+ timedOut: false,
382
+ });
383
+ mockClaudeLocalProviderGetSessionsResult.mockResolvedValue({
384
+ payload: {
385
+ sessions: [
386
+ {
387
+ id: 'claude~550e8400-e29b-41d4-a716-446655440000',
388
+ slug: '550e8400-e29b-41d4-a716-446655440000',
389
+ title: 'Claude Only Session',
390
+ directory: '/repo/claude-only-project',
391
+ projectName: 'claude-only-project',
392
+ branch: 'main',
393
+ provider: 'claude-code',
394
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
395
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
396
+ readOnly: true,
397
+ topology: { childSessions: 'flat' },
398
+ realTimeStatus: 'busy',
399
+ waitingForUser: false,
400
+ children: [],
401
+ time: { created: 4_000, updated: Date.now() - 1_000 },
402
+ },
403
+ ],
404
+ processHints: [],
405
+ },
406
+ sourceMeta: { online: true },
407
+ });
408
+
409
+ const response = await GET(
410
+ new Request('http://localhost/api/node/sessions', {
411
+ headers: createNodeRequestHeaders('shared-secret'),
412
+ })
413
+ );
414
+ const data = await response.json();
415
+
416
+ expect(response.status).toBe(200);
417
+ expect(data).toMatchObject({
418
+ ok: true,
419
+ role: 'node',
420
+ protocolVersion: '1',
421
+ source: { hostId: 'local', hostLabel: 'Local', hostKind: 'local' },
422
+ upstream: { kind: 'opencode', reachable: true },
423
+ processHints: [],
424
+ hosts: [{ hostId: 'local', hostLabel: 'Local', hostKind: 'local', online: true }],
425
+ hostStatuses: [{ hostId: 'local', hostLabel: 'Local', hostKind: 'local', online: true }],
426
+ });
427
+ expect(data.sessions).toEqual([
428
+ expect.objectContaining({
429
+ id: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
430
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
431
+ sourceSessionKey: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
432
+ provider: 'claude-code',
433
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
434
+ hostId: 'local',
435
+ hostLabel: 'Local',
436
+ hostKind: 'local',
437
+ readOnly: true,
438
+ topology: { childSessions: 'flat' },
439
+ children: [],
440
+ }),
441
+ ]);
442
+ expect(mockCreateOpencodeClient).not.toHaveBeenCalled();
443
+ });
444
+
445
+ it('returns degraded Claude fallback sessions when all discovered OpenCode ports fail', async () => {
446
+ setupLocalSessionsMocks();
447
+ mockDiscoverPortsWithMeta.mockReturnValue({
448
+ ports: [7777, 7778],
449
+ timedOut: false,
450
+ });
451
+ mockSessionList.mockRejectedValue(new Error('ECONNREFUSED'));
452
+ mockClaudeLocalProviderGetSessionsResult.mockResolvedValue({
453
+ payload: {
454
+ sessions: [
455
+ {
456
+ id: 'claude~550e8400-e29b-41d4-a716-446655440000',
457
+ slug: '550e8400-e29b-41d4-a716-446655440000',
458
+ title: 'Claude Fallback Session',
459
+ directory: '/repo/claude-fallback',
460
+ projectName: 'claude-fallback',
461
+ branch: 'main',
462
+ provider: 'claude-code',
463
+ providerRawId: '550e8400-e29b-41d4-a716-446655440000',
464
+ rawSessionId: '550e8400-e29b-41d4-a716-446655440000',
465
+ readOnly: true,
466
+ topology: { childSessions: 'flat' },
467
+ realTimeStatus: 'busy',
468
+ waitingForUser: false,
469
+ children: [],
470
+ time: { created: 5_000, updated: Date.now() - 1_000 },
471
+ },
472
+ ],
473
+ processHints: [],
474
+ },
475
+ sourceMeta: { online: true },
476
+ });
477
+
478
+ const response = await GET(
479
+ new Request('http://localhost/api/node/sessions', {
480
+ headers: createNodeRequestHeaders('shared-secret'),
481
+ })
482
+ );
483
+ const data = await response.json();
484
+
485
+ expect(response.status).toBe(200);
486
+ expect(data.degraded).toBe(true);
487
+ expect(data.failedPorts).toEqual([
488
+ expect.objectContaining({ port: 7777 }),
489
+ expect.objectContaining({ port: 7778 }),
490
+ ]);
491
+ expect(data.sessions).toEqual(
492
+ expect.arrayContaining([
493
+ expect.objectContaining({
494
+ id: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
495
+ provider: 'claude-code',
496
+ sourceSessionKey: 'local:claude~550e8400-e29b-41d4-a716-446655440000',
497
+ }),
498
+ ])
499
+ );
500
+ expect(data.hostStatuses).toEqual([
501
+ expect.objectContaining({
502
+ hostId: 'local',
503
+ online: true,
504
+ degraded: true,
505
+ }),
506
+ ]);
507
+ expect(mockCreateOpencodeClient.mock.calls).toEqual([
508
+ [{ baseUrl: 'http://localhost:7777' }],
509
+ [{ baseUrl: 'http://localhost:7778' }],
510
+ ]);
511
+ });
512
+
231
513
  it('rejects unauthenticated requests before running discovery', async () => {
232
514
  const response = await GET(
233
515
  new Request('http://localhost/api/node/sessions', {
@@ -6,7 +6,12 @@ import {
6
6
  discoverOpencodeProcessCwdsWithoutPortWithMeta,
7
7
  } from '@/lib/opencodeDiscovery';
8
8
  import { readConfig } from '@/lib/opencodeConfig';
9
- import { composeSourceKey } from '@/lib/hostIdentity';
9
+ import { claudeCodeLocalSessionProvider } from '@/lib/session-providers/claudeCode';
10
+ import {
11
+ composeProviderSourceKey,
12
+ detectProviderFromRawId,
13
+ extractProviderRawId,
14
+ } from '@/lib/session-providers/providerIds';
10
15
  import {
11
16
  NODE_PROTOCOL_VERSION,
12
17
  createNodeFailureResponse,
@@ -73,9 +78,20 @@ type HostAwareFields = {
73
78
  hostId?: typeof LOCAL_SOURCE.hostId;
74
79
  hostLabel?: typeof LOCAL_SOURCE.hostLabel;
75
80
  hostKind?: typeof LOCAL_SOURCE.hostKind;
81
+ provider?: 'opencode' | 'claude-code';
82
+ providerRawId?: string;
76
83
  rawSessionId?: string;
77
84
  sourceSessionKey?: string;
78
85
  readOnly?: boolean;
86
+ capabilities?: {
87
+ openProject: boolean;
88
+ openEditor: boolean;
89
+ archive: boolean;
90
+ delete: boolean;
91
+ };
92
+ topology?: {
93
+ childSessions: 'flat' | 'authoritative';
94
+ };
79
95
  };
80
96
 
81
97
  type ChildEntry = HostAwareFields & {
@@ -557,38 +573,112 @@ function sortChildEntries(children: ChildEntry[]): void {
557
573
  });
558
574
  }
559
575
 
560
- function addLocalHostMetadataToChildEntry(child: ChildEntry): ChildEntry {
561
- const rawSessionId = child.rawSessionId ?? child.id;
562
- const sourceSessionKey = composeSourceKey(LOCAL_SOURCE.hostId, rawSessionId);
576
+ function readSupplementalProviderPayload(payload: unknown): Pick<LocalSessionsSuccessPayload, 'sessions' | 'processHints'> {
577
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
578
+ return { sessions: [], processHints: [] };
579
+ }
580
+
581
+ const record = payload as Record<string, unknown>;
582
+
583
+ return {
584
+ sessions: Array.isArray(record['sessions']) ? (record['sessions'] as EnrichedSession[]) : [],
585
+ processHints: Array.isArray(record['processHints']) ? (record['processHints'] as ProcessHint[]) : [],
586
+ };
587
+ }
588
+
589
+ async function getSupplementalClaudePayload(stickyBusyDelayMs: number): Promise<
590
+ Pick<LocalSessionsSuccessPayload, 'sessions' | 'processHints'>
591
+ > {
592
+ try {
593
+ const result = await claudeCodeLocalSessionProvider.getSessionsResult({ stickyBusyDelayMs });
594
+ return readSupplementalProviderPayload(result.payload);
595
+ } catch {
596
+ return { sessions: [], processHints: [] };
597
+ }
598
+ }
599
+
600
+ function composeLocalProviderSourceKey(
601
+ rawSessionId: string,
602
+ fields: Pick<HostAwareFields, 'provider' | 'readOnly' | 'capabilities' | 'topology'>
603
+ ) {
604
+ return composeProviderSourceKey(LOCAL_SOURCE.hostId, rawSessionId, {
605
+ ...(fields.provider ? { provider: fields.provider } : {}),
606
+ ...(fields.readOnly !== undefined ? { readOnly: fields.readOnly } : {}),
607
+ ...(fields.capabilities ? { capabilities: fields.capabilities } : {}),
608
+ ...(fields.topology ? { topology: fields.topology } : {}),
609
+ });
610
+ }
611
+
612
+ function addLocalHostMetadataToChildEntry(
613
+ child: ChildEntry,
614
+ parentSourceSessionKey?: string,
615
+ parentProvider?: HostAwareFields['provider']
616
+ ): ChildEntry {
617
+ const rawSessionId = child.rawSessionId ?? extractProviderRawId(child.id);
618
+ const inferredProvider = child.provider ?? detectProviderFromRawId(child.id);
619
+ const provider = inferredProvider === 'claude-code' ? inferredProvider : (parentProvider ?? inferredProvider);
620
+ const sourceKey = composeLocalProviderSourceKey(rawSessionId, {
621
+ provider,
622
+ readOnly: child.readOnly,
623
+ capabilities: child.capabilities,
624
+ topology: child.topology,
625
+ });
626
+ const rawParentId = child.parentID ? extractProviderRawId(child.parentID) : undefined;
627
+ const sourceParentKey = parentSourceSessionKey
628
+ ?? (rawParentId
629
+ ? composeLocalProviderSourceKey(rawParentId, {
630
+ provider,
631
+ }).sourceKey
632
+ : child.parentID);
563
633
 
564
634
  return {
565
635
  ...child,
566
- id: sourceSessionKey,
567
- parentID: child.parentID ? composeSourceKey(LOCAL_SOURCE.hostId, child.parentID) : child.parentID,
636
+ id: sourceKey.sourceKey,
637
+ parentID: sourceParentKey,
568
638
  hostId: LOCAL_SOURCE.hostId,
569
639
  hostLabel: LOCAL_SOURCE.hostLabel,
570
640
  hostKind: LOCAL_SOURCE.hostKind,
571
641
  rawSessionId,
572
- sourceSessionKey,
573
- readOnly: false,
642
+ sourceSessionKey: sourceKey.sourceKey,
643
+ provider,
644
+ providerRawId: child.providerRawId ?? sourceKey.providerRawId,
645
+ readOnly: child.readOnly ?? sourceKey.readOnly,
646
+ capabilities: child.capabilities ?? sourceKey.capabilities,
647
+ topology: child.topology ?? sourceKey.topology,
574
648
  };
575
649
  }
576
650
 
577
651
  function addLocalHostMetadataToSession(session: EnrichedSession): EnrichedSession {
578
- const rawSessionId = session.rawSessionId ?? session.id;
579
- const sourceSessionKey = composeSourceKey(LOCAL_SOURCE.hostId, rawSessionId);
652
+ const rawSessionId = session.rawSessionId ?? extractProviderRawId(session.id);
653
+ const provider = session.provider ?? detectProviderFromRawId(session.id);
654
+ const sourceKey = composeLocalProviderSourceKey(rawSessionId, {
655
+ provider,
656
+ readOnly: session.readOnly,
657
+ capabilities: session.capabilities,
658
+ topology: session.topology,
659
+ });
660
+ const rawParentId = session.parentID ? extractProviderRawId(session.parentID) : undefined;
661
+ const sourceParentKey = rawParentId
662
+ ? composeLocalProviderSourceKey(rawParentId, {
663
+ provider,
664
+ }).sourceKey
665
+ : session.parentID;
580
666
 
581
667
  return {
582
668
  ...session,
583
- id: sourceSessionKey,
584
- parentID: session.parentID ? composeSourceKey(LOCAL_SOURCE.hostId, session.parentID) : session.parentID,
669
+ id: sourceKey.sourceKey,
670
+ parentID: sourceParentKey,
585
671
  hostId: LOCAL_SOURCE.hostId,
586
672
  hostLabel: LOCAL_SOURCE.hostLabel,
587
673
  hostKind: LOCAL_SOURCE.hostKind,
588
674
  rawSessionId,
589
- sourceSessionKey,
590
- readOnly: false,
591
- children: session.children.map((child) => addLocalHostMetadataToChildEntry(child)),
675
+ sourceSessionKey: sourceKey.sourceKey,
676
+ provider,
677
+ providerRawId: session.providerRawId ?? sourceKey.providerRawId,
678
+ readOnly: session.readOnly ?? sourceKey.readOnly,
679
+ capabilities: session.capabilities ?? sourceKey.capabilities,
680
+ topology: session.topology ?? sourceKey.topology,
681
+ children: session.children.map((child) => addLocalHostMetadataToChildEntry(child, sourceKey.sourceKey, provider)),
592
682
  };
593
683
  }
594
684
 
@@ -686,6 +776,20 @@ async function getLocalSessionsResult(stickyBusyDelayMs: number): Promise<LocalS
686
776
  return createLocalFailureResult('upstream_timeout', processHints);
687
777
  }
688
778
 
779
+ const supplementalClaudePayload = await getSupplementalClaudePayload(stickyBusyDelayMs);
780
+ if (supplementalClaudePayload.sessions.length > 0 || supplementalClaudePayload.processHints.length > 0) {
781
+ return {
782
+ ok: true,
783
+ payload: {
784
+ sessions: supplementalClaudePayload.sessions,
785
+ processHints: [...processHints, ...supplementalClaudePayload.processHints],
786
+ },
787
+ meta: {
788
+ online: true,
789
+ },
790
+ };
791
+ }
792
+
689
793
  return createLocalFailureResult('upstream_unreachable', processHints);
690
794
  }
691
795
 
@@ -771,6 +875,24 @@ async function getLocalSessionsResult(stickyBusyDelayMs: number): Promise<LocalS
771
875
  }
772
876
 
773
877
  if (results.length > 0 && failedPorts.length === results.length) {
878
+ const supplementalClaudePayload = await getSupplementalClaudePayload(stickyBusyDelayMs);
879
+ if (supplementalClaudePayload.sessions.length > 0 || supplementalClaudePayload.processHints.length > 0) {
880
+ return {
881
+ ok: true,
882
+ payload: {
883
+ sessions: supplementalClaudePayload.sessions,
884
+ processHints: [...processHints, ...supplementalClaudePayload.processHints],
885
+ failedPorts,
886
+ degraded: true,
887
+ },
888
+ meta: {
889
+ online: true,
890
+ degraded: true,
891
+ reason: resolveFailureReasonFromMessages(failedPorts.map((entry) => entry.reason)),
892
+ },
893
+ };
894
+ }
895
+
774
896
  pruneStickyState(Date.now(), new Set<string>());
775
897
  return createLocalFailureResult(resolveFailureReasonFromMessages(failedPorts.map((entry) => entry.reason)), processHints, {
776
898
  failedPorts,
@@ -1069,11 +1191,13 @@ async function getLocalSessionsResult(stickyBusyDelayMs: number): Promise<LocalS
1069
1191
 
1070
1192
  const filteredProcessHints = processHints.filter((hint) => !knownDirectories.has(hint.directory));
1071
1193
 
1194
+ const supplementalClaudePayload = await getSupplementalClaudePayload(stickyBusyDelayMs);
1195
+
1072
1196
  return {
1073
1197
  ok: true,
1074
1198
  payload: {
1075
- sessions: enrichedSessions,
1076
- processHints: filteredProcessHints,
1199
+ sessions: [...enrichedSessions, ...supplementalClaudePayload.sessions],
1200
+ processHints: [...filteredProcessHints, ...supplementalClaudePayload.processHints],
1077
1201
  ...(failedPorts.length > 0 ? { failedPorts, degraded: true } : {}),
1078
1202
  },
1079
1203
  meta: {
@@ -1,12 +1,11 @@
1
- import { detectConfig, CONFIG_PATH } from '@/lib/opencodeConfig';
1
+ import { detectConfig, resolveConfigPath } from '@/lib/opencodeConfig';
2
2
  import { exec } from 'child_process';
3
3
  import { promisify } from 'util';
4
4
 
5
5
  const execAsync = promisify(exec);
6
6
 
7
- async function detectPlugin(): Promise<boolean> {
7
+ async function detectOpenCodeCli(): Promise<boolean> {
8
8
  try {
9
- // Check if oh-my-opencode CLI is available
10
9
  await execAsync('opencode --version');
11
10
  return true;
12
11
  } catch {
@@ -16,15 +15,15 @@ async function detectPlugin(): Promise<boolean> {
16
15
 
17
16
  export async function GET() {
18
17
  const hasConfig = detectConfig();
19
- const hasPlugin = await detectPlugin();
18
+ const hasOpenCodeCli = await detectOpenCodeCli();
20
19
 
21
- const response: { hasConfig: boolean; hasPlugin: boolean; path?: string } = {
20
+ const response: { hasConfig: boolean; hasOpenCodeCli: boolean; path?: string } = {
22
21
  hasConfig,
23
- hasPlugin,
22
+ hasOpenCodeCli,
24
23
  };
25
24
 
26
25
  if (hasConfig) {
27
- response.path = CONFIG_PATH;
26
+ response.path = resolveConfigPath();
28
27
  }
29
28
 
30
29
  return Response.json(response);
@@ -493,7 +493,7 @@ describe('/api/opencode-events', () => {
493
493
  const reader = response.body?.getReader();
494
494
  expect(reader).toBeTruthy();
495
495
 
496
- const first = await readPayload(reader!);
496
+ const first = (await readPayload(reader!)) as any;
497
497
  expect(first).toEqual({
498
498
  type: 'session.status',
499
499
  properties: {
@@ -502,6 +502,8 @@ describe('/api/opencode-events', () => {
502
502
  },
503
503
  timestamp: 100,
504
504
  });
505
+ expect(first.source).toBeUndefined();
506
+ expect(first.event).toBeUndefined();
505
507
 
506
508
  await reader!.cancel();
507
509
  });