@a5c-ai/babysitter-observer-dashboard 5.0.1-staging.7a8768ec

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 (513) hide show
  1. package/.next/BUILD_ID +1 -0
  2. package/.next/app-path-routes-manifest.json +16 -0
  3. package/.next/build-manifest.json +23 -0
  4. package/.next/export-marker.json +6 -0
  5. package/.next/fallback-build-manifest.json +13 -0
  6. package/.next/images-manifest.json +68 -0
  7. package/.next/next-minimal-server.js.nft.json +1 -0
  8. package/.next/next-server.js.nft.json +1 -0
  9. package/.next/package.json +1 -0
  10. package/.next/prerender-manifest.json +114 -0
  11. package/.next/required-server-files.json +334 -0
  12. package/.next/routes-manifest.json +139 -0
  13. package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  14. package/.next/server/app/_global-error/page/build-manifest.json +19 -0
  15. package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  16. package/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
  17. package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  18. package/.next/server/app/_global-error/page.js +9 -0
  19. package/.next/server/app/_global-error/page.js.map +5 -0
  20. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  21. package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
  22. package/.next/server/app/_global-error.html +1 -0
  23. package/.next/server/app/_global-error.meta +15 -0
  24. package/.next/server/app/_global-error.rsc +14 -0
  25. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
  26. package/.next/server/app/_global-error.segments/_full.segment.rsc +14 -0
  27. package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
  28. package/.next/server/app/_global-error.segments/_index.segment.rsc +5 -0
  29. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  30. package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  31. package/.next/server/app/_not-found/page/build-manifest.json +19 -0
  32. package/.next/server/app/_not-found/page/next-font-manifest.json +6 -0
  33. package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  34. package/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
  35. package/.next/server/app/_not-found/page.js +13 -0
  36. package/.next/server/app/_not-found/page.js.map +5 -0
  37. package/.next/server/app/_not-found/page.js.nft.json +1 -0
  38. package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -0
  39. package/.next/server/app/_not-found.html +1 -0
  40. package/.next/server/app/_not-found.meta +16 -0
  41. package/.next/server/app/_not-found.rsc +19 -0
  42. package/.next/server/app/_not-found.segments/_full.segment.rsc +19 -0
  43. package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
  44. package/.next/server/app/_not-found.segments/_index.segment.rsc +8 -0
  45. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +6 -0
  46. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +5 -0
  47. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
  48. package/.next/server/app/api/config/route/app-paths-manifest.json +3 -0
  49. package/.next/server/app/api/config/route/build-manifest.json +9 -0
  50. package/.next/server/app/api/config/route/server-reference-manifest.json +4 -0
  51. package/.next/server/app/api/config/route.js +8 -0
  52. package/.next/server/app/api/config/route.js.map +5 -0
  53. package/.next/server/app/api/config/route.js.nft.json +1 -0
  54. package/.next/server/app/api/config/route_client-reference-manifest.js +3 -0
  55. package/.next/server/app/api/digest/route/app-paths-manifest.json +3 -0
  56. package/.next/server/app/api/digest/route/build-manifest.json +9 -0
  57. package/.next/server/app/api/digest/route/server-reference-manifest.json +4 -0
  58. package/.next/server/app/api/digest/route.js +9 -0
  59. package/.next/server/app/api/digest/route.js.map +5 -0
  60. package/.next/server/app/api/digest/route.js.nft.json +1 -0
  61. package/.next/server/app/api/digest/route_client-reference-manifest.js +3 -0
  62. package/.next/server/app/api/runs/[runId]/events/route/app-paths-manifest.json +3 -0
  63. package/.next/server/app/api/runs/[runId]/events/route/build-manifest.json +9 -0
  64. package/.next/server/app/api/runs/[runId]/events/route/server-reference-manifest.json +4 -0
  65. package/.next/server/app/api/runs/[runId]/events/route.js +8 -0
  66. package/.next/server/app/api/runs/[runId]/events/route.js.map +5 -0
  67. package/.next/server/app/api/runs/[runId]/events/route.js.nft.json +1 -0
  68. package/.next/server/app/api/runs/[runId]/events/route_client-reference-manifest.js +3 -0
  69. package/.next/server/app/api/runs/[runId]/route/app-paths-manifest.json +3 -0
  70. package/.next/server/app/api/runs/[runId]/route/build-manifest.json +9 -0
  71. package/.next/server/app/api/runs/[runId]/route/server-reference-manifest.json +4 -0
  72. package/.next/server/app/api/runs/[runId]/route.js +9 -0
  73. package/.next/server/app/api/runs/[runId]/route.js.map +5 -0
  74. package/.next/server/app/api/runs/[runId]/route.js.nft.json +1 -0
  75. package/.next/server/app/api/runs/[runId]/route_client-reference-manifest.js +3 -0
  76. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/app-paths-manifest.json +3 -0
  77. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/build-manifest.json +9 -0
  78. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route/server-reference-manifest.json +4 -0
  79. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js +8 -0
  80. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js.map +5 -0
  81. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route.js.nft.json +1 -0
  82. package/.next/server/app/api/runs/[runId]/tasks/[effectId]/route_client-reference-manifest.js +3 -0
  83. package/.next/server/app/api/runs/route/app-paths-manifest.json +3 -0
  84. package/.next/server/app/api/runs/route/build-manifest.json +9 -0
  85. package/.next/server/app/api/runs/route/server-reference-manifest.json +4 -0
  86. package/.next/server/app/api/runs/route.js +9 -0
  87. package/.next/server/app/api/runs/route.js.map +5 -0
  88. package/.next/server/app/api/runs/route.js.nft.json +1 -0
  89. package/.next/server/app/api/runs/route_client-reference-manifest.js +3 -0
  90. package/.next/server/app/api/stream/route/app-paths-manifest.json +3 -0
  91. package/.next/server/app/api/stream/route/build-manifest.json +9 -0
  92. package/.next/server/app/api/stream/route/server-reference-manifest.json +4 -0
  93. package/.next/server/app/api/stream/route.js +8 -0
  94. package/.next/server/app/api/stream/route.js.map +5 -0
  95. package/.next/server/app/api/stream/route.js.nft.json +1 -0
  96. package/.next/server/app/api/stream/route_client-reference-manifest.js +3 -0
  97. package/.next/server/app/api/test/route/app-paths-manifest.json +3 -0
  98. package/.next/server/app/api/test/route/build-manifest.json +9 -0
  99. package/.next/server/app/api/test/route/server-reference-manifest.json +4 -0
  100. package/.next/server/app/api/test/route.js +6 -0
  101. package/.next/server/app/api/test/route.js.map +5 -0
  102. package/.next/server/app/api/test/route.js.nft.json +1 -0
  103. package/.next/server/app/api/test/route_client-reference-manifest.js +3 -0
  104. package/.next/server/app/api/version/route/app-paths-manifest.json +3 -0
  105. package/.next/server/app/api/version/route/build-manifest.json +9 -0
  106. package/.next/server/app/api/version/route/server-reference-manifest.json +4 -0
  107. package/.next/server/app/api/version/route.js +7 -0
  108. package/.next/server/app/api/version/route.js.map +5 -0
  109. package/.next/server/app/api/version/route.js.nft.json +1 -0
  110. package/.next/server/app/api/version/route_client-reference-manifest.js +3 -0
  111. package/.next/server/app/icon.svg/route/app-paths-manifest.json +3 -0
  112. package/.next/server/app/icon.svg/route/build-manifest.json +9 -0
  113. package/.next/server/app/icon.svg/route.js +7 -0
  114. package/.next/server/app/icon.svg/route.js.map +5 -0
  115. package/.next/server/app/icon.svg/route.js.nft.json +1 -0
  116. package/.next/server/app/icon.svg.body +20 -0
  117. package/.next/server/app/icon.svg.meta +1 -0
  118. package/.next/server/app/index.html +1 -0
  119. package/.next/server/app/index.meta +14 -0
  120. package/.next/server/app/index.rsc +21 -0
  121. package/.next/server/app/index.segments/__PAGE__.segment.rsc +9 -0
  122. package/.next/server/app/index.segments/_full.segment.rsc +21 -0
  123. package/.next/server/app/index.segments/_head.segment.rsc +6 -0
  124. package/.next/server/app/index.segments/_index.segment.rsc +8 -0
  125. package/.next/server/app/index.segments/_tree.segment.rsc +2 -0
  126. package/.next/server/app/page/app-paths-manifest.json +3 -0
  127. package/.next/server/app/page/build-manifest.json +19 -0
  128. package/.next/server/app/page/next-font-manifest.json +6 -0
  129. package/.next/server/app/page/react-loadable-manifest.json +1 -0
  130. package/.next/server/app/page/server-reference-manifest.json +17 -0
  131. package/.next/server/app/page.js +15 -0
  132. package/.next/server/app/page.js.map +5 -0
  133. package/.next/server/app/page.js.nft.json +1 -0
  134. package/.next/server/app/page_client-reference-manifest.js +3 -0
  135. package/.next/server/app/runs/[runId]/page/app-paths-manifest.json +3 -0
  136. package/.next/server/app/runs/[runId]/page/build-manifest.json +19 -0
  137. package/.next/server/app/runs/[runId]/page/next-font-manifest.json +6 -0
  138. package/.next/server/app/runs/[runId]/page/react-loadable-manifest.json +22 -0
  139. package/.next/server/app/runs/[runId]/page/server-reference-manifest.json +17 -0
  140. package/.next/server/app/runs/[runId]/page.js +15 -0
  141. package/.next/server/app/runs/[runId]/page.js.map +5 -0
  142. package/.next/server/app/runs/[runId]/page.js.nft.json +1 -0
  143. package/.next/server/app/runs/[runId]/page_client-reference-manifest.js +3 -0
  144. package/.next/server/app-paths-manifest.json +16 -0
  145. package/.next/server/chunks/01oi_server_app_api_runs_[runId]_tasks_[effectId]_route_actions_0r72yai.js +3 -0
  146. package/.next/server/chunks/01oi_server_app_api_runs_[runId]_tasks_[effectId]_route_actions_0r72yai.js.map +1 -0
  147. package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_events_route_actions_0~msldk.js +3 -0
  148. package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_events_route_actions_0~msldk.js.map +1 -0
  149. package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_route_actions_09iz0n6.js +3 -0
  150. package/.next/server/chunks/0h.v__next-internal_server_app_api_runs_[runId]_route_actions_09iz0n6.js.map +1 -0
  151. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_config_route_actions_0~eypoa.js +3 -0
  152. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_config_route_actions_0~eypoa.js.map +1 -0
  153. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_digest_route_actions_04jj5zs.js +3 -0
  154. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_digest_route_actions_04jj5zs.js.map +1 -0
  155. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_runs_route_actions_0~-t-o4.js +3 -0
  156. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_runs_route_actions_0~-t-o4.js.map +1 -0
  157. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_stream_route_actions_0fkmv2_.js +3 -0
  158. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_stream_route_actions_0fkmv2_.js.map +1 -0
  159. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_test_route_actions_00ugava.js +3 -0
  160. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_test_route_actions_00ugava.js.map +1 -0
  161. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_version_route_actions_0~v3ojm.js +3 -0
  162. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_api_version_route_actions_0~v3ojm.js.map +1 -0
  163. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_icon_svg_route_actions_0yypxkm.js +3 -0
  164. package/.next/server/chunks/0juq_observer-dashboard__next-internal_server_app_icon_svg_route_actions_0yypxkm.js.map +1 -0
  165. package/.next/server/chunks/[root-of-the-server]__0.6bt.6._.js +3 -0
  166. package/.next/server/chunks/[root-of-the-server]__0.6bt.6._.js.map +1 -0
  167. package/.next/server/chunks/[root-of-the-server]__08kwev1._.js +3 -0
  168. package/.next/server/chunks/[root-of-the-server]__08kwev1._.js.map +1 -0
  169. package/.next/server/chunks/[root-of-the-server]__096el.d._.js +3 -0
  170. package/.next/server/chunks/[root-of-the-server]__096el.d._.js.map +1 -0
  171. package/.next/server/chunks/[root-of-the-server]__0_bmt4z._.js +3 -0
  172. package/.next/server/chunks/[root-of-the-server]__0_bmt4z._.js.map +1 -0
  173. package/.next/server/chunks/[root-of-the-server]__0_ln2d2._.js +3 -0
  174. package/.next/server/chunks/[root-of-the-server]__0_ln2d2._.js.map +1 -0
  175. package/.next/server/chunks/[root-of-the-server]__0al3v65._.js +3 -0
  176. package/.next/server/chunks/[root-of-the-server]__0al3v65._.js.map +1 -0
  177. package/.next/server/chunks/[root-of-the-server]__0gf516b._.js +3 -0
  178. package/.next/server/chunks/[root-of-the-server]__0gf516b._.js.map +1 -0
  179. package/.next/server/chunks/[root-of-the-server]__0kdfw4x._.js +3 -0
  180. package/.next/server/chunks/[root-of-the-server]__0kdfw4x._.js.map +1 -0
  181. package/.next/server/chunks/[root-of-the-server]__0pxt00h._.js +3 -0
  182. package/.next/server/chunks/[root-of-the-server]__0pxt00h._.js.map +1 -0
  183. package/.next/server/chunks/[root-of-the-server]__0rubnza._.js +3 -0
  184. package/.next/server/chunks/[root-of-the-server]__0rubnza._.js.map +1 -0
  185. package/.next/server/chunks/[root-of-the-server]__0tn9iud._.js +3 -0
  186. package/.next/server/chunks/[root-of-the-server]__0tn9iud._.js.map +1 -0
  187. package/.next/server/chunks/[root-of-the-server]__0ws5o6i._.js +3 -0
  188. package/.next/server/chunks/[root-of-the-server]__0ws5o6i._.js.map +1 -0
  189. package/.next/server/chunks/[turbopack]_runtime.js +903 -0
  190. package/.next/server/chunks/[turbopack]_runtime.js.map +11 -0
  191. package/.next/server/chunks/node_modules_next_04~_e52._.js +13 -0
  192. package/.next/server/chunks/node_modules_next_04~_e52._.js.map +1 -0
  193. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0nyyph-.js +9 -0
  194. package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_0nyyph-.js.map +1 -0
  195. package/.next/server/chunks/packages_observer-dashboard_src_lib_02.vvb.._.js +3 -0
  196. package/.next/server/chunks/packages_observer-dashboard_src_lib_02.vvb.._.js.map +1 -0
  197. package/.next/server/chunks/packages_observer-dashboard_src_lib_0rqgpk0._.js +3 -0
  198. package/.next/server/chunks/packages_observer-dashboard_src_lib_0rqgpk0._.js.map +1 -0
  199. package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__global-error_page_actions_0ekoxmy.js +3 -0
  200. package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__global-error_page_actions_0ekoxmy.js.map +1 -0
  201. package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__not-found_page_actions_09b3ti3.js +3 -0
  202. package/.next/server/chunks/ssr/0juq_observer-dashboard__next-internal_server_app__not-found_page_actions_09b3ti3.js.map +1 -0
  203. package/.next/server/chunks/ssr/[root-of-the-server]__006f7~t._.js +4 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__006f7~t._.js.map +1 -0
  205. package/.next/server/chunks/ssr/[root-of-the-server]__02jgvbi._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__02jgvbi._.js.map +1 -0
  207. package/.next/server/chunks/ssr/[root-of-the-server]__04j8t~1._.js +3 -0
  208. package/.next/server/chunks/ssr/[root-of-the-server]__04j8t~1._.js.map +1 -0
  209. package/.next/server/chunks/ssr/[root-of-the-server]__09c~s.0._.js +33 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__09c~s.0._.js.map +1 -0
  211. package/.next/server/chunks/ssr/[root-of-the-server]__0cpy61n._.js +3 -0
  212. package/.next/server/chunks/ssr/[root-of-the-server]__0cpy61n._.js.map +1 -0
  213. package/.next/server/chunks/ssr/[root-of-the-server]__0cwa32j._.js +3 -0
  214. package/.next/server/chunks/ssr/[root-of-the-server]__0cwa32j._.js.map +1 -0
  215. package/.next/server/chunks/ssr/[root-of-the-server]__0fk_g0j._.js +19 -0
  216. package/.next/server/chunks/ssr/[root-of-the-server]__0fk_g0j._.js.map +1 -0
  217. package/.next/server/chunks/ssr/[root-of-the-server]__0pddpic._.js +3 -0
  218. package/.next/server/chunks/ssr/[root-of-the-server]__0pddpic._.js.map +1 -0
  219. package/.next/server/chunks/ssr/[root-of-the-server]__0pvtneq._.js +3 -0
  220. package/.next/server/chunks/ssr/[root-of-the-server]__0pvtneq._.js.map +1 -0
  221. package/.next/server/chunks/ssr/[root-of-the-server]__0xc-2vm._.js +3 -0
  222. package/.next/server/chunks/ssr/[root-of-the-server]__0xc-2vm._.js.map +1 -0
  223. package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js +33 -0
  224. package/.next/server/chunks/ssr/[root-of-the-server]__10xgshr._.js.map +1 -0
  225. package/.next/server/chunks/ssr/[turbopack]_runtime.js +903 -0
  226. package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +11 -0
  227. package/.next/server/chunks/ssr/_00yo1im._.js +3 -0
  228. package/.next/server/chunks/ssr/_00yo1im._.js.map +1 -0
  229. package/.next/server/chunks/ssr/_03sbc.o._.js +3 -0
  230. package/.next/server/chunks/ssr/_03sbc.o._.js.map +1 -0
  231. package/.next/server/chunks/ssr/_04z5ea0._.js +3 -0
  232. package/.next/server/chunks/ssr/_04z5ea0._.js.map +1 -0
  233. package/.next/server/chunks/ssr/_0gmb3g_._.js +3 -0
  234. package/.next/server/chunks/ssr/_0gmb3g_._.js.map +1 -0
  235. package/.next/server/chunks/ssr/_0okz9j8._.js +6 -0
  236. package/.next/server/chunks/ssr/_0okz9j8._.js.map +1 -0
  237. package/.next/server/chunks/ssr/_0wrbwro._.js +6 -0
  238. package/.next/server/chunks/ssr/_0wrbwro._.js.map +1 -0
  239. package/.next/server/chunks/ssr/node_modules_09w7yel._.js +33 -0
  240. package/.next/server/chunks/ssr/node_modules_09w7yel._.js.map +1 -0
  241. package/.next/server/chunks/ssr/node_modules_next_dist_0avqw4q._.js +3 -0
  242. package/.next/server/chunks/ssr/node_modules_next_dist_0avqw4q._.js.map +1 -0
  243. package/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js +6 -0
  244. package/.next/server/chunks/ssr/node_modules_next_dist_0h9llsw._.js.map +1 -0
  245. package/.next/server/chunks/ssr/node_modules_next_dist_0i_._k3._.js +3 -0
  246. package/.next/server/chunks/ssr/node_modules_next_dist_0i_._k3._.js.map +1 -0
  247. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0ee1czk._.js +3 -0
  248. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0ee1czk._.js.map +1 -0
  249. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js +3 -0
  250. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0lgvd_..js.map +1 -0
  251. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js +3 -0
  252. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0cjv-23.js.map +1 -0
  253. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0amzg6z.js +4 -0
  254. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0amzg6z.js.map +1 -0
  255. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dw1x0d.js +4 -0
  256. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0dw1x0d.js.map +1 -0
  257. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js +4 -0
  258. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0rc3ul_.js.map +1 -0
  259. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10iomok.js +4 -0
  260. package/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_10iomok.js.map +1 -0
  261. package/.next/server/chunks/ssr/packages_observer-dashboard_0~a2tmu._.js +3 -0
  262. package/.next/server/chunks/ssr/packages_observer-dashboard_0~a2tmu._.js.map +1 -0
  263. package/.next/server/chunks/ssr/packages_observer-dashboard_src_0f.ozc-._.js +3 -0
  264. package/.next/server/chunks/ssr/packages_observer-dashboard_src_0f.ozc-._.js.map +1 -0
  265. package/.next/server/chunks/ssr/packages_observer-dashboard_src_components_providers_tsx_03_vrrn._.js +7 -0
  266. package/.next/server/chunks/ssr/packages_observer-dashboard_src_components_providers_tsx_03_vrrn._.js.map +1 -0
  267. package/.next/server/functions-config-manifest.json +4 -0
  268. package/.next/server/interception-route-rewrite-manifest.js +1 -0
  269. package/.next/server/middleware-build-manifest.js +23 -0
  270. package/.next/server/middleware-manifest.json +6 -0
  271. package/.next/server/next-font-manifest.js +1 -0
  272. package/.next/server/next-font-manifest.json +6 -0
  273. package/.next/server/pages/404.html +1 -0
  274. package/.next/server/pages/500.html +1 -0
  275. package/.next/server/pages-manifest.json +4 -0
  276. package/.next/server/prefetch-hints.json +1 -0
  277. package/.next/server/server-reference-manifest.js +1 -0
  278. package/.next/server/server-reference-manifest.json +24 -0
  279. package/.next/static/MvfPly4ZXHqaveDVOG1qq/_buildManifest.js +11 -0
  280. package/.next/static/MvfPly4ZXHqaveDVOG1qq/_clientMiddlewareManifest.js +1 -0
  281. package/.next/static/MvfPly4ZXHqaveDVOG1qq/_ssgManifest.js +1 -0
  282. package/.next/static/chunks/00c87uqn~kk2z.js +1 -0
  283. package/.next/static/chunks/01xlw8hd842-c.js +1 -0
  284. package/.next/static/chunks/02p9dpa.0oxiz.js +1 -0
  285. package/.next/static/chunks/034i63v_muq~d.js +1 -0
  286. package/.next/static/chunks/03mo-6~4pxdio.js +1 -0
  287. package/.next/static/chunks/03~yq9q893hmn.js +1 -0
  288. package/.next/static/chunks/04dm5qn77.fc2.js +1 -0
  289. package/.next/static/chunks/07uz2g0_38qia.js +4 -0
  290. package/.next/static/chunks/08nqnwvixoxnk.js +2 -0
  291. package/.next/static/chunks/0d3shmwh5_nmn.js +1 -0
  292. package/.next/static/chunks/0e_wyjw3nx.a..js +1 -0
  293. package/.next/static/chunks/0mstyq17cbf8-.js +1 -0
  294. package/.next/static/chunks/0ntuxw9.how-q.js +1 -0
  295. package/.next/static/chunks/0t3uzajv1qzmo.js +1 -0
  296. package/.next/static/chunks/0u~_nwr5-v.xp.js +1 -0
  297. package/.next/static/chunks/0wxcxh6eyzams.js +1 -0
  298. package/.next/static/chunks/0x6y7yt4kiddp.css +1 -0
  299. package/.next/static/chunks/0z6-vonyxr0dn.js +4 -0
  300. package/.next/static/chunks/0ze4gu236oq96.js +31 -0
  301. package/.next/static/chunks/0zwozael9msy1.js +1 -0
  302. package/.next/static/chunks/10qd__0r7a~.l.js +1 -0
  303. package/.next/static/chunks/11jh_u1ynmatg.js +1 -0
  304. package/.next/static/chunks/13xer3cb9shu-.js +5 -0
  305. package/.next/static/chunks/142zlnch_xmgd.js +1 -0
  306. package/.next/static/chunks/144kcri75qczu.js +1 -0
  307. package/.next/static/chunks/turbopack-0-ww6fe7b37qt.js +1 -0
  308. package/.next/static/media/icon.08ljfy7xai2x_.svg +20 -0
  309. package/LICENSE +21 -0
  310. package/README.md +490 -0
  311. package/next.config.mjs +25 -0
  312. package/package.json +104 -0
  313. package/postcss.config.mjs +8 -0
  314. package/src/app/actions/__tests__/approve-breakpoint.test.ts +246 -0
  315. package/src/app/actions/approve-breakpoint.ts +145 -0
  316. package/src/app/api/config/route.ts +137 -0
  317. package/src/app/api/digest/route.ts +45 -0
  318. package/src/app/api/runs/[runId]/events/route.ts +56 -0
  319. package/src/app/api/runs/[runId]/route.ts +84 -0
  320. package/src/app/api/runs/[runId]/tasks/[effectId]/route.ts +44 -0
  321. package/src/app/api/runs/route.ts +48 -0
  322. package/src/app/api/stream/route.ts +136 -0
  323. package/src/app/api/test/route.ts +1 -0
  324. package/src/app/api/version/route.ts +57 -0
  325. package/src/app/globals.css +555 -0
  326. package/src/app/icon.svg +20 -0
  327. package/src/app/layout.tsx +39 -0
  328. package/src/app/not-found.tsx +16 -0
  329. package/src/app/page.tsx +120 -0
  330. package/src/app/runs/[runId]/page.tsx +279 -0
  331. package/src/cli.ts +271 -0
  332. package/src/components/breakpoint/__tests__/breakpoint-approval.test.tsx +212 -0
  333. package/src/components/breakpoint/__tests__/breakpoint-panel.test.tsx +130 -0
  334. package/src/components/breakpoint/__tests__/file-preview.test.tsx +313 -0
  335. package/src/components/breakpoint/breakpoint-approval.tsx +138 -0
  336. package/src/components/breakpoint/breakpoint-panel.tsx +95 -0
  337. package/src/components/breakpoint/file-preview.tsx +215 -0
  338. package/src/components/dashboard/.gitkeep +0 -0
  339. package/src/components/dashboard/__tests__/breakpoint-banner.test.tsx +177 -0
  340. package/src/components/dashboard/__tests__/catch-up-banner.test.tsx +141 -0
  341. package/src/components/dashboard/__tests__/executive-summary-banner.test.tsx +164 -0
  342. package/src/components/dashboard/__tests__/kpi-grid.test.tsx +101 -0
  343. package/src/components/dashboard/__tests__/pagination-controls.test.tsx +125 -0
  344. package/src/components/dashboard/__tests__/project-accordion.test.tsx +97 -0
  345. package/src/components/dashboard/__tests__/project-list-view.test.tsx +174 -0
  346. package/src/components/dashboard/__tests__/project-search-input.test.tsx +110 -0
  347. package/src/components/dashboard/__tests__/project-section-header.test.tsx +91 -0
  348. package/src/components/dashboard/__tests__/project-section.test.tsx +151 -0
  349. package/src/components/dashboard/__tests__/run-card.test.tsx +164 -0
  350. package/src/components/dashboard/__tests__/run-filter-bar.test.tsx +109 -0
  351. package/src/components/dashboard/__tests__/run-list.test.tsx +123 -0
  352. package/src/components/dashboard/__tests__/search-filter.test.tsx +150 -0
  353. package/src/components/dashboard/__tests__/virtualized-run-list.test.tsx +179 -0
  354. package/src/components/dashboard/breakpoint-banner.tsx +301 -0
  355. package/src/components/dashboard/catch-up-banner.tsx +88 -0
  356. package/src/components/dashboard/executive-summary-banner.tsx +174 -0
  357. package/src/components/dashboard/global-search.tsx +323 -0
  358. package/src/components/dashboard/kpi-grid.tsx +140 -0
  359. package/src/components/dashboard/pagination-controls.tsx +100 -0
  360. package/src/components/dashboard/project-accordion.tsx +72 -0
  361. package/src/components/dashboard/project-health-card.tsx +536 -0
  362. package/src/components/dashboard/project-list-view.tsx +246 -0
  363. package/src/components/dashboard/project-search-input.tsx +41 -0
  364. package/src/components/dashboard/project-section-header.tsx +73 -0
  365. package/src/components/dashboard/project-section.tsx +89 -0
  366. package/src/components/dashboard/run-card.tsx +218 -0
  367. package/src/components/dashboard/run-filter-bar.tsx +100 -0
  368. package/src/components/dashboard/run-list.tsx +77 -0
  369. package/src/components/dashboard/search-filter.tsx +69 -0
  370. package/src/components/dashboard/virtualized-run-list.tsx +130 -0
  371. package/src/components/details/.gitkeep +0 -0
  372. package/src/components/details/__tests__/agent-panel.test.tsx +236 -0
  373. package/src/components/details/__tests__/json-tree.test.tsx +347 -0
  374. package/src/components/details/__tests__/log-viewer.test.tsx +168 -0
  375. package/src/components/details/__tests__/task-detail.test.tsx +212 -0
  376. package/src/components/details/__tests__/timing-panel.test.tsx +271 -0
  377. package/src/components/details/agent-panel.tsx +234 -0
  378. package/src/components/details/json-tree/categorize.ts +131 -0
  379. package/src/components/details/json-tree/index.tsx +120 -0
  380. package/src/components/details/json-tree/json-node.tsx +223 -0
  381. package/src/components/details/json-tree/smart-summary.tsx +596 -0
  382. package/src/components/details/json-tree/tree-controls.tsx +47 -0
  383. package/src/components/details/json-tree.tsx +9 -0
  384. package/src/components/details/log-viewer.tsx +140 -0
  385. package/src/components/details/task-detail.tsx +114 -0
  386. package/src/components/details/timing-panel.tsx +247 -0
  387. package/src/components/events/.gitkeep +0 -0
  388. package/src/components/events/__tests__/event-item.test.tsx +211 -0
  389. package/src/components/events/__tests__/event-stream.test.tsx +225 -0
  390. package/src/components/events/event-item.tsx +121 -0
  391. package/src/components/events/event-stream.tsx +260 -0
  392. package/src/components/notifications/.gitkeep +0 -0
  393. package/src/components/notifications/__tests__/notification-panel.test.tsx +287 -0
  394. package/src/components/notifications/__tests__/notification-provider.test.tsx +585 -0
  395. package/src/components/notifications/__tests__/toast-stack.test.tsx +217 -0
  396. package/src/components/notifications/notification-panel.tsx +124 -0
  397. package/src/components/notifications/notification-provider.tsx +175 -0
  398. package/src/components/notifications/toast-stack.tsx +75 -0
  399. package/src/components/pipeline/.gitkeep +0 -0
  400. package/src/components/pipeline/__tests__/parallel-group.test.tsx +88 -0
  401. package/src/components/pipeline/__tests__/pipeline-view.test.tsx +345 -0
  402. package/src/components/pipeline/__tests__/step-card.test.tsx +330 -0
  403. package/src/components/pipeline/parallel-group.tsx +39 -0
  404. package/src/components/pipeline/pipeline-view.tsx +197 -0
  405. package/src/components/pipeline/step-card.tsx +166 -0
  406. package/src/components/providers/event-stream-provider.tsx +29 -0
  407. package/src/components/providers.tsx +24 -0
  408. package/src/components/shared/.gitkeep +0 -0
  409. package/src/components/shared/__tests__/empty-state.test.tsx +49 -0
  410. package/src/components/shared/__tests__/friendly-id.test.tsx +47 -0
  411. package/src/components/shared/__tests__/kbd.test.tsx +45 -0
  412. package/src/components/shared/__tests__/kind-badge.test.tsx +71 -0
  413. package/src/components/shared/__tests__/metrics-row.test.tsx +74 -0
  414. package/src/components/shared/__tests__/outcome-banner.test.tsx +71 -0
  415. package/src/components/shared/__tests__/progress-bar.test.tsx +89 -0
  416. package/src/components/shared/__tests__/session-pill.test.tsx +62 -0
  417. package/src/components/shared/__tests__/settings-modal.test.tsx +201 -0
  418. package/src/components/shared/__tests__/shortcuts-help.test.tsx +103 -0
  419. package/src/components/shared/__tests__/status-badge.test.tsx +98 -0
  420. package/src/components/shared/__tests__/theme-provider.test.tsx +100 -0
  421. package/src/components/shared/__tests__/truncated-id.test.tsx +53 -0
  422. package/src/components/shared/app-footer.tsx +80 -0
  423. package/src/components/shared/app-header.tsx +160 -0
  424. package/src/components/shared/empty-state.tsx +18 -0
  425. package/src/components/shared/error-boundary.tsx +81 -0
  426. package/src/components/shared/friendly-id.tsx +48 -0
  427. package/src/components/shared/kbd.tsx +15 -0
  428. package/src/components/shared/kind-badge.tsx +51 -0
  429. package/src/components/shared/metrics-row.tsx +106 -0
  430. package/src/components/shared/outcome-banner.tsx +56 -0
  431. package/src/components/shared/progress-bar.tsx +42 -0
  432. package/src/components/shared/session-pill.tsx +69 -0
  433. package/src/components/shared/settings-modal.tsx +509 -0
  434. package/src/components/shared/shortcuts-help.tsx +113 -0
  435. package/src/components/shared/status-badge.tsx +110 -0
  436. package/src/components/shared/theme-provider.tsx +46 -0
  437. package/src/components/shared/truncated-id.tsx +51 -0
  438. package/src/components/ui/.gitkeep +0 -0
  439. package/src/components/ui/__tests__/accordion.test.tsx +96 -0
  440. package/src/components/ui/__tests__/badge.test.tsx +69 -0
  441. package/src/components/ui/__tests__/button.test.tsx +113 -0
  442. package/src/components/ui/__tests__/tabs.test.tsx +75 -0
  443. package/src/components/ui/__tests__/tooltip.test.tsx +90 -0
  444. package/src/components/ui/accordion.tsx +61 -0
  445. package/src/components/ui/badge.tsx +25 -0
  446. package/src/components/ui/button.tsx +40 -0
  447. package/src/components/ui/card.tsx +21 -0
  448. package/src/components/ui/scroll-area.tsx +35 -0
  449. package/src/components/ui/separator.tsx +24 -0
  450. package/src/components/ui/tabs.tsx +64 -0
  451. package/src/components/ui/tooltip.tsx +37 -0
  452. package/src/hooks/.gitkeep +0 -0
  453. package/src/hooks/__tests__/use-animated-number.test.ts +184 -0
  454. package/src/hooks/__tests__/use-batched-updates.test.ts +315 -0
  455. package/src/hooks/__tests__/use-event-stream.test.ts +243 -0
  456. package/src/hooks/__tests__/use-keyboard.test.ts +217 -0
  457. package/src/hooks/__tests__/use-notifications.test.ts +230 -0
  458. package/src/hooks/__tests__/use-polling.test.ts +274 -0
  459. package/src/hooks/__tests__/use-project-runs.test.ts +163 -0
  460. package/src/hooks/__tests__/use-projects.test.ts +248 -0
  461. package/src/hooks/__tests__/use-run-dashboard.test.ts +168 -0
  462. package/src/hooks/__tests__/use-run-detail.test.ts +273 -0
  463. package/src/hooks/__tests__/use-smart-polling.test.ts +305 -0
  464. package/src/hooks/use-animated-number.ts +87 -0
  465. package/src/hooks/use-batched-updates.ts +150 -0
  466. package/src/hooks/use-event-stream.ts +150 -0
  467. package/src/hooks/use-keyboard.ts +45 -0
  468. package/src/hooks/use-notifications.ts +82 -0
  469. package/src/hooks/use-persisted-state.ts +60 -0
  470. package/src/hooks/use-polling.ts +60 -0
  471. package/src/hooks/use-project-runs.ts +51 -0
  472. package/src/hooks/use-projects.ts +26 -0
  473. package/src/hooks/use-run-dashboard.ts +207 -0
  474. package/src/hooks/use-run-detail.ts +77 -0
  475. package/src/hooks/use-smart-polling.ts +144 -0
  476. package/src/lib/.gitkeep +0 -0
  477. package/src/lib/__tests__/cn.test.ts +69 -0
  478. package/src/lib/__tests__/config-loader.test.ts +210 -0
  479. package/src/lib/__tests__/config.test.ts +561 -0
  480. package/src/lib/__tests__/error-handler.test.ts +143 -0
  481. package/src/lib/__tests__/fetcher.test.ts +517 -0
  482. package/src/lib/__tests__/global-registry.test.ts +214 -0
  483. package/src/lib/__tests__/parser.test.ts +1532 -0
  484. package/src/lib/__tests__/path-resolver.test.ts +112 -0
  485. package/src/lib/__tests__/run-cache.test.ts +591 -0
  486. package/src/lib/__tests__/server-init.test.ts +512 -0
  487. package/src/lib/__tests__/source-discovery.test.ts +246 -0
  488. package/src/lib/__tests__/utils.test.ts +160 -0
  489. package/src/lib/__tests__/watcher.test.ts +227 -0
  490. package/src/lib/cn.ts +6 -0
  491. package/src/lib/config-loader.ts +195 -0
  492. package/src/lib/config.ts +20 -0
  493. package/src/lib/error-handler.ts +76 -0
  494. package/src/lib/fetcher.ts +394 -0
  495. package/src/lib/global-registry.ts +117 -0
  496. package/src/lib/parser.ts +794 -0
  497. package/src/lib/path-resolver.ts +16 -0
  498. package/src/lib/run-cache.ts +404 -0
  499. package/src/lib/server-init.ts +226 -0
  500. package/src/lib/services/__tests__/run-query-service.test.ts +819 -0
  501. package/src/lib/services/run-query-service.ts +286 -0
  502. package/src/lib/source-discovery.ts +216 -0
  503. package/src/lib/utils.ts +103 -0
  504. package/src/lib/watcher.ts +265 -0
  505. package/src/test/fixtures.ts +269 -0
  506. package/src/test/mocks/handlers.ts +110 -0
  507. package/src/test/mocks/server.ts +17 -0
  508. package/src/test/setup.ts +200 -0
  509. package/src/test/test-utils.tsx +36 -0
  510. package/src/types/.gitkeep +0 -0
  511. package/src/types/breakpoint.ts +17 -0
  512. package/src/types/index.ts +214 -0
  513. package/tsconfig.json +50 -0
@@ -0,0 +1,138 @@
1
+ "use client";
2
+
3
+ import { useState, useTransition } from "react";
4
+ import { cn } from "@/lib/cn";
5
+ import { Button } from "@/components/ui/button";
6
+ import { CheckCircle2, Loader2, AlertCircle } from "lucide-react";
7
+ import { approveBreakpoint } from "@/app/actions/approve-breakpoint";
8
+ import type { TaskDetail } from "@/types";
9
+
10
+ interface BreakpointApprovalProps {
11
+ task: TaskDetail;
12
+ runId: string;
13
+ }
14
+
15
+ export function BreakpointApproval({ task, runId }: BreakpointApprovalProps) {
16
+ const [customAnswer, setCustomAnswer] = useState("");
17
+ const [isPending, startTransition] = useTransition();
18
+ const [result, setResult] = useState<{
19
+ success: boolean;
20
+ error?: string;
21
+ } | null>(null);
22
+
23
+ const options = task.breakpoint?.options || [];
24
+ const isWaiting = task.status === "requested";
25
+
26
+ // Don't render for non-waiting breakpoints
27
+ if (!isWaiting) return null;
28
+
29
+ function handleApprove(answer: string) {
30
+ if (!answer.trim()) return;
31
+
32
+ setResult(null);
33
+ startTransition(async () => {
34
+ const res = await approveBreakpoint(runId, task.effectId, answer);
35
+ setResult(res);
36
+ });
37
+ }
38
+
39
+ function handleCustomSubmit(e: React.FormEvent) {
40
+ e.preventDefault();
41
+ handleApprove(customAnswer);
42
+ }
43
+
44
+ return (
45
+ <div data-testid="breakpoint-approval" className="space-y-4">
46
+ {/* Option buttons */}
47
+ {options.length > 0 && (
48
+ <div data-testid="breakpoint-options" className="space-y-2">
49
+ <label className="text-xs font-medium text-foreground-muted uppercase tracking-wider">
50
+ Choose an option
51
+ </label>
52
+ <div className="flex flex-wrap gap-2">
53
+ {options.map((option) => (
54
+ <Button
55
+ key={option}
56
+ variant="neon"
57
+ size="sm"
58
+ disabled={isPending}
59
+ onClick={() => handleApprove(option)}
60
+ data-testid={`option-btn-${option}`}
61
+ >
62
+ {option}
63
+ </Button>
64
+ ))}
65
+ </div>
66
+ </div>
67
+ )}
68
+
69
+ {/* Free-text input */}
70
+ <form onSubmit={handleCustomSubmit} className="space-y-2">
71
+ <label
72
+ htmlFor="custom-answer"
73
+ className="text-xs font-medium text-foreground-muted uppercase tracking-wider"
74
+ >
75
+ {options.length > 0 ? "Or provide a custom answer" : "Provide an answer"}
76
+ </label>
77
+ <div className="flex gap-2">
78
+ <input
79
+ id="custom-answer"
80
+ data-testid="custom-answer-input"
81
+ type="text"
82
+ value={customAnswer}
83
+ onChange={(e) => setCustomAnswer(e.target.value)}
84
+ placeholder="Type your answer..."
85
+ disabled={isPending}
86
+ className={cn(
87
+ "flex-1 rounded-md border border-border bg-background px-3 py-2 text-sm",
88
+ "placeholder:text-foreground-muted/50",
89
+ "focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary/50",
90
+ "disabled:opacity-50 disabled:cursor-not-allowed"
91
+ )}
92
+ />
93
+ <Button
94
+ type="submit"
95
+ variant="default"
96
+ size="sm"
97
+ disabled={isPending || !customAnswer.trim()}
98
+ data-testid="approve-btn"
99
+ >
100
+ {isPending ? (
101
+ <>
102
+ <Loader2 className="h-3 w-3 animate-spin" />
103
+ Approving...
104
+ </>
105
+ ) : (
106
+ "Approve"
107
+ )}
108
+ </Button>
109
+ </div>
110
+ </form>
111
+
112
+ {/* Result feedback */}
113
+ {result && (
114
+ <div
115
+ data-testid="approval-result"
116
+ className={cn(
117
+ "rounded-lg border p-3 flex items-center gap-2 text-sm",
118
+ result.success
119
+ ? "border-success/30 bg-success-muted text-success"
120
+ : "border-error/30 bg-error-muted text-error"
121
+ )}
122
+ >
123
+ {result.success ? (
124
+ <>
125
+ <CheckCircle2 className="h-4 w-4 shrink-0" />
126
+ <span>Breakpoint approved successfully. The dashboard will update automatically.</span>
127
+ </>
128
+ ) : (
129
+ <>
130
+ <AlertCircle className="h-4 w-4 shrink-0" />
131
+ <span>{result.error || "An unknown error occurred"}</span>
132
+ </>
133
+ )}
134
+ </div>
135
+ )}
136
+ </div>
137
+ );
138
+ }
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ import { cn } from "@/lib/cn";
3
+ import { Badge } from "@/components/ui/badge";
4
+ import { FilePreview } from "./file-preview";
5
+ import { BreakpointApproval } from "./breakpoint-approval";
6
+ import { ScrollArea } from "@/components/ui/scroll-area";
7
+ import { Hand, CheckCircle2 } from "lucide-react";
8
+ import { TruncatedId } from "@/components/shared/truncated-id";
9
+ import type { TaskDetail } from "@/types";
10
+
11
+ interface BreakpointPanelProps {
12
+ task: TaskDetail;
13
+ runId: string;
14
+ }
15
+
16
+ export function BreakpointPanel({ task, runId }: BreakpointPanelProps) {
17
+ const breakpoint = task.breakpoint;
18
+ const question = breakpoint?.question || task.breakpointQuestion || "Approval required";
19
+ const title = breakpoint?.title || task.title || "Breakpoint";
20
+ const files = breakpoint?.context?.files || [];
21
+ const isWaiting = task.status === "requested";
22
+
23
+ return (
24
+ <ScrollArea className="h-full">
25
+ <div data-testid="breakpoint-panel" className="space-y-5 p-4">
26
+ {/* Header */}
27
+ <div className="space-y-2">
28
+ <div className="flex items-center gap-2">
29
+ <Hand className={cn("h-4 w-4 text-warning", isWaiting && "animate-pulse-dot")} />
30
+ <h3 className="text-sm font-semibold text-foreground">{title}</h3>
31
+ </div>
32
+ <div className="flex items-center gap-2">
33
+ <Badge variant="warning">Breakpoint</Badge>
34
+ {task.status === "resolved" && (
35
+ <Badge variant="success">Already Resolved</Badge>
36
+ )}
37
+ </div>
38
+ <TruncatedId id={task.effectId} chars={4} className="text-foreground-muted" />
39
+ </div>
40
+
41
+ {/* Question callout — sun yellow border with warm glow */}
42
+ <div
43
+ className={cn(
44
+ "rounded-lg border-2 p-5",
45
+ "bg-warning-muted border-warning/40",
46
+ isWaiting && "animate-breakpoint-glow"
47
+ )}
48
+ style={isWaiting ? { boxShadow: "var(--breakpoint-glow)" } : undefined}
49
+ >
50
+ <div className="flex items-start gap-3">
51
+ <Hand className="h-6 w-6 text-warning shrink-0 mt-0.5 animate-pulse-dot" />
52
+ <div className="min-w-0">
53
+ <h4 className={cn(
54
+ "text-xs leading-tight font-medium uppercase tracking-widest mb-2",
55
+ isWaiting ? "text-warning" : "text-success"
56
+ )}>
57
+ {isWaiting ? "Awaiting decision" : "Decision made"}
58
+ </h4>
59
+ <p data-testid="breakpoint-question" className="text-base text-foreground font-medium leading-relaxed whitespace-pre-wrap break-words">
60
+ {question}
61
+ </p>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ {/* Local approval form — only for pending breakpoints */}
67
+ {isWaiting && (
68
+ <BreakpointApproval task={task} runId={runId} />
69
+ )}
70
+
71
+ {/* Attached files */}
72
+ {files.length > 0 && (
73
+ <FilePreview files={files} runId={runId} effectId={task.effectId} />
74
+ )}
75
+
76
+ {/* Resolved state — neon green success glow */}
77
+ {task.status === "resolved" && (
78
+ <div className="rounded-lg bg-success-muted border border-success/30 p-4 flex items-center gap-3 shadow-glow-success">
79
+ <div className="flex items-center justify-center h-8 w-8 rounded-full bg-success/15">
80
+ <CheckCircle2 className="h-5 w-5 text-success" />
81
+ </div>
82
+ <div>
83
+ <span className="text-sm text-success font-semibold block">
84
+ Approved
85
+ </span>
86
+ <span className="text-xs leading-tight text-foreground-muted">
87
+ Breakpoint has been resolved
88
+ </span>
89
+ </div>
90
+ </div>
91
+ )}
92
+ </div>
93
+ </ScrollArea>
94
+ );
95
+ }
@@ -0,0 +1,215 @@
1
+ "use client";
2
+ import { useState, useMemo, useRef, useEffect } from "react";
3
+ import { cn } from "@/lib/cn";
4
+ import { resilientFetch } from "@/lib/fetcher";
5
+ import { Badge } from "@/components/ui/badge";
6
+ import {
7
+ Accordion,
8
+ AccordionItem,
9
+ AccordionTrigger,
10
+ AccordionContent,
11
+ } from "@/components/ui/accordion";
12
+ import { FileText, Code, FileJson, Loader2 } from "lucide-react";
13
+ import type { BreakpointFile } from "@/types";
14
+
15
+ interface FilePreviewProps {
16
+ files: BreakpointFile[];
17
+ runId: string;
18
+ effectId: string;
19
+ }
20
+
21
+ const formatIcon: Record<string, React.ReactNode> = {
22
+ markdown: <FileText className="h-3.5 w-3.5 text-info" />,
23
+ json: <FileJson className="h-3.5 w-3.5 text-warning" />,
24
+ code: <Code className="h-3.5 w-3.5 text-success" />,
25
+ };
26
+
27
+ function getIcon(format: string) {
28
+ return formatIcon[format] || <FileText className="h-3.5 w-3.5 text-foreground-muted" />;
29
+ }
30
+
31
+ function formatBadgeVariant(format: string): "info" | "warning" | "success" | "pending" {
32
+ switch (format) {
33
+ case "markdown":
34
+ return "info";
35
+ case "json":
36
+ return "warning";
37
+ case "code":
38
+ return "success";
39
+ default:
40
+ return "pending";
41
+ }
42
+ }
43
+
44
+ /** Try to pretty-print JSON content */
45
+ function formatJson(content: string): string {
46
+ try {
47
+ return JSON.stringify(JSON.parse(content), null, 2);
48
+ } catch {
49
+ return content;
50
+ }
51
+ }
52
+
53
+ /** Render content based on format — night-black background with subtle border */
54
+ function FileContent({ content, format }: { content: string; format: string }) {
55
+ const rendered = useMemo(() => {
56
+ if (format === "json") {
57
+ return formatJson(content);
58
+ }
59
+ return content;
60
+ }, [content, format]);
61
+
62
+ if (format === "markdown") {
63
+ return (
64
+ <div
65
+ className={cn(
66
+ "rounded-md bg-background border border-border/50 p-4",
67
+ "text-sm text-foreground-secondary leading-relaxed",
68
+ "overflow-x-auto max-h-80 overflow-y-auto",
69
+ "prose-sm prose-invert",
70
+ "[&_h1]:text-base [&_h1]:font-bold [&_h1]:mb-2 [&_h1]:text-foreground",
71
+ "[&_h2]:text-sm [&_h2]:font-semibold [&_h2]:mb-1.5 [&_h2]:text-foreground",
72
+ "[&_h3]:text-xs [&_h3]:font-medium [&_h3]:mb-1 [&_h3]:text-foreground",
73
+ "[&_code]:bg-background-secondary [&_code]:px-1 [&_code]:py-0.5 [&_code]:rounded [&_code]:text-xs [&_code]:font-mono",
74
+ "[&_pre]:bg-background-secondary [&_pre]:p-2 [&_pre]:rounded [&_pre]:text-xs [&_pre]:font-mono [&_pre]:overflow-x-auto",
75
+ "[&_ul]:list-disc [&_ul]:pl-4 [&_ol]:list-decimal [&_ol]:pl-4",
76
+ "[&_li]:mb-0.5",
77
+ "[&_strong]:font-semibold [&_strong]:text-foreground",
78
+ "[&_a]:text-primary [&_a]:underline"
79
+ )}
80
+ >
81
+ <pre className="whitespace-pre-wrap break-words font-sans">{content}</pre>
82
+ </div>
83
+ );
84
+ }
85
+
86
+ // Code and JSON: monospace with line numbers — night-black background
87
+ const lines = rendered.split("\n");
88
+ const gutterWidth = String(lines.length).length;
89
+
90
+ return (
91
+ <div
92
+ className={cn(
93
+ "rounded-md bg-background border border-border/50",
94
+ "text-xs font-mono overflow-x-auto max-h-80 overflow-y-auto"
95
+ )}
96
+ >
97
+ <table className="w-full border-collapse">
98
+ <tbody>
99
+ {lines.map((line, i) => (
100
+ <tr key={i} className="hover:bg-background-secondary/50">
101
+ <td
102
+ className="select-none text-right pr-3 pl-2 text-foreground-muted/40 border-r border-border/30 align-top font-mono"
103
+ style={{ width: `${gutterWidth + 2}ch` }}
104
+ >
105
+ {i + 1}
106
+ </td>
107
+ <td className="pl-3 pr-3 text-foreground-secondary whitespace-pre-wrap break-words">
108
+ {line || "\u00A0"}
109
+ </td>
110
+ </tr>
111
+ ))}
112
+ </tbody>
113
+ </table>
114
+ </div>
115
+ );
116
+ }
117
+
118
+ export function FilePreview({ files, runId, effectId }: FilePreviewProps) {
119
+ const [loadedContent, setLoadedContent] = useState<Record<string, string>>({});
120
+ const [loadingFiles, setLoadingFiles] = useState<Record<string, boolean>>({});
121
+ const abortRefs = useRef<Record<string, AbortController>>({});
122
+
123
+ // Abort all in-flight file requests on unmount
124
+ useEffect(() => {
125
+ const refs = abortRefs.current;
126
+ return () => {
127
+ for (const controller of Object.values(refs)) {
128
+ controller.abort();
129
+ }
130
+ };
131
+ }, []);
132
+
133
+ async function loadFileContent(filePath: string) {
134
+ if (loadedContent[filePath] || loadingFiles[filePath]) return;
135
+ setLoadingFiles((prev) => ({ ...prev, [filePath]: true }));
136
+
137
+ // Abort any previous in-flight request for this file
138
+ abortRefs.current[filePath]?.abort();
139
+ abortRefs.current[filePath] = new AbortController();
140
+
141
+ const result = await resilientFetch<{ content?: string }>(
142
+ `/api/runs/${runId}/tasks/${effectId}?file=${encodeURIComponent(filePath)}`,
143
+ { signal: abortRefs.current[filePath].signal }
144
+ );
145
+
146
+ if (!result.ok) {
147
+ if (result.error.isAborted) return;
148
+ setLoadedContent((prev) => ({
149
+ ...prev,
150
+ [filePath]: "// Failed to load file content",
151
+ }));
152
+ } else {
153
+ setLoadedContent((prev) => ({
154
+ ...prev,
155
+ [filePath]: result.data.content || "// No content available",
156
+ }));
157
+ }
158
+ setLoadingFiles((prev) => ({ ...prev, [filePath]: false }));
159
+ }
160
+
161
+ if (!files.length) return null;
162
+
163
+ return (
164
+ <div data-testid="file-preview" className="space-y-1">
165
+ <h4 className="text-xs font-medium text-foreground-muted uppercase tracking-wider mb-2 pl-2 border-l-2 border-primary">
166
+ Attached Files
167
+ </h4>
168
+ <Accordion
169
+ type="single"
170
+ collapsible
171
+ onValueChange={(value: string | string[]) => {
172
+ const v = typeof value === "string" ? value : value[0];
173
+ if (v) {
174
+ const file = files.find((f) => f.path === v);
175
+ if (file) loadFileContent(file.path);
176
+ }
177
+ }}
178
+ >
179
+ {files.map((file) => (
180
+ <AccordionItem key={file.path} value={file.path} className="border-border/50">
181
+ <AccordionTrigger className="py-2 text-xs">
182
+ <div className="flex items-center gap-2 min-w-0">
183
+ {getIcon(file.format)}
184
+ <span className="font-mono text-foreground-secondary truncate">
185
+ {file.path}
186
+ </span>
187
+ <Badge variant={formatBadgeVariant(file.format)} className="text-xs leading-tight px-1.5 py-0">
188
+ {file.format}
189
+ </Badge>
190
+ {file.language && (
191
+ <Badge variant="pending" className="text-xs leading-tight px-1.5 py-0">
192
+ {file.language}
193
+ </Badge>
194
+ )}
195
+ </div>
196
+ </AccordionTrigger>
197
+ <AccordionContent className="px-1">
198
+ {loadingFiles[file.path] ? (
199
+ <div className="flex items-center justify-center py-6">
200
+ <Loader2 className="h-4 w-4 animate-spin text-foreground-muted" />
201
+ </div>
202
+ ) : loadedContent[file.path] ? (
203
+ <FileContent content={loadedContent[file.path]} format={file.format} />
204
+ ) : (
205
+ <div className="py-4 text-xs text-foreground-muted text-center">
206
+ Expand to load content
207
+ </div>
208
+ )}
209
+ </AccordionContent>
210
+ </AccordionItem>
211
+ ))}
212
+ </Accordion>
213
+ </div>
214
+ );
215
+ }
File without changes
@@ -0,0 +1,177 @@
1
+ import { render, screen, act } from '@/test/test-utils';
2
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
3
+ import type { BreakpointRunInfo } from '@/types';
4
+ import { BreakpointBanner } from '../breakpoint-banner';
5
+
6
+ // Mock next/link to render a plain anchor (same pattern as run-card.test.tsx)
7
+ vi.mock('next/link', () => ({
8
+ __esModule: true,
9
+ default: ({ href, children, className }: { href: string; children: React.ReactNode; className?: string }) => (
10
+ <a href={href} className={className} data-testid="next-link">
11
+ {children}
12
+ </a>
13
+ ),
14
+ }));
15
+
16
+ function makeBp(overrides: Partial<BreakpointRunInfo> = {}): BreakpointRunInfo {
17
+ return {
18
+ runId: 'run-001',
19
+ projectName: 'my-project',
20
+ processId: 'data-pipeline',
21
+ breakpointQuestion: 'Approve deployment?',
22
+ ...overrides,
23
+ };
24
+ }
25
+
26
+ describe('BreakpointBanner', () => {
27
+ beforeEach(() => {
28
+ vi.useFakeTimers();
29
+ });
30
+
31
+ afterEach(() => {
32
+ vi.useRealTimers();
33
+ });
34
+
35
+ // --- Returns null when empty ---
36
+ it('returns null when no breakpoint runs and no resolved entries', () => {
37
+ const { container } = render(<BreakpointBanner breakpointRuns={[]} />);
38
+ expect(container.innerHTML).toBe('');
39
+ expect(screen.queryByTestId('breakpoint-banner')).not.toBeInTheDocument();
40
+ });
41
+
42
+ // --- Renders breakpoint entries ---
43
+ it('renders breakpoint entries with correct content', () => {
44
+ const bps = [
45
+ makeBp({ runId: 'run-001', projectName: 'proj-a', breakpointQuestion: 'Deploy to prod?' }),
46
+ makeBp({ runId: 'run-002', projectName: 'proj-b', breakpointQuestion: 'Run migrations?' }),
47
+ ];
48
+
49
+ render(<BreakpointBanner breakpointRuns={bps} />);
50
+
51
+ expect(screen.getByTestId('breakpoint-banner')).toBeInTheDocument();
52
+ expect(screen.getByText('Deploy to prod?')).toBeInTheDocument();
53
+ expect(screen.getByText('Run migrations?')).toBeInTheDocument();
54
+ expect(screen.getByText('proj-a')).toBeInTheDocument();
55
+ expect(screen.getByText('proj-b')).toBeInTheDocument();
56
+ });
57
+
58
+ it('renders "Approval Needed" label for each breakpoint', () => {
59
+ render(<BreakpointBanner breakpointRuns={[makeBp()]} />);
60
+ expect(screen.getByText('Approval Needed')).toBeInTheDocument();
61
+ });
62
+
63
+ it('renders truncated run ID', () => {
64
+ render(<BreakpointBanner breakpointRuns={[makeBp({ runId: 'run-abcdef-12345678' })]} />);
65
+ // runId.slice(0, 8) = "run-abcd"
66
+ expect(screen.getByText('run-abcd')).toBeInTheDocument();
67
+ });
68
+
69
+ it('shows summary count when multiple breakpoints are pending', () => {
70
+ const bps = [
71
+ makeBp({ runId: 'run-001' }),
72
+ makeBp({ runId: 'run-002' }),
73
+ makeBp({ runId: 'run-003' }),
74
+ ];
75
+ render(<BreakpointBanner breakpointRuns={bps} />);
76
+ expect(screen.getByText('3 approvals pending')).toBeInTheDocument();
77
+ });
78
+
79
+ it('does not show summary count for a single breakpoint', () => {
80
+ render(<BreakpointBanner breakpointRuns={[makeBp()]} />);
81
+ expect(screen.queryByText(/approvals pending/)).not.toBeInTheDocument();
82
+ });
83
+
84
+ // --- Staleness indicator ---
85
+ it('shows staleness indicator after STALENESS_THRESHOLD_MS (2 minutes)', () => {
86
+ const bp = makeBp({ runId: 'stale-run' });
87
+
88
+ const { rerender } = render(<BreakpointBanner breakpointRuns={[bp]} />);
89
+
90
+ // Initially no staleness indicator
91
+ expect(screen.queryByTestId('staleness-indicator')).not.toBeInTheDocument();
92
+
93
+ // Advance past the staleness threshold (120s) + a tick interval (10s)
94
+ act(() => {
95
+ vi.advanceTimersByTime(130000);
96
+ });
97
+
98
+ // Re-render with the same props to keep the breakpoint active
99
+ // (the staleness tick interval triggers state update internally)
100
+ rerender(<BreakpointBanner breakpointRuns={[bp]} />);
101
+
102
+ expect(screen.getByTestId('staleness-indicator')).toBeInTheDocument();
103
+ expect(screen.getByText('(checking...)')).toBeInTheDocument();
104
+ });
105
+
106
+ it('does not show staleness indicator before threshold', () => {
107
+ const bp = makeBp({ runId: 'fresh-run' });
108
+
109
+ const { rerender } = render(<BreakpointBanner breakpointRuns={[bp]} />);
110
+
111
+ // Advance only 60s (below 120s threshold)
112
+ act(() => {
113
+ vi.advanceTimersByTime(60000);
114
+ });
115
+
116
+ rerender(<BreakpointBanner breakpointRuns={[bp]} />);
117
+
118
+ expect(screen.queryByTestId('staleness-indicator')).not.toBeInTheDocument();
119
+ });
120
+
121
+ // --- Resolved entry detection ---
122
+ it('shows resolved entry when a breakpoint disappears from the list', () => {
123
+ const bp = makeBp({ runId: 'resolved-run', breakpointQuestion: 'Deploy?' });
124
+
125
+ // First render with the breakpoint active
126
+ const { rerender } = render(<BreakpointBanner breakpointRuns={[bp]} />);
127
+
128
+ expect(screen.getByText('Deploy?')).toBeInTheDocument();
129
+
130
+ // Re-render without the breakpoint (it was resolved)
131
+ act(() => {
132
+ rerender(<BreakpointBanner breakpointRuns={[]} />);
133
+ });
134
+
135
+ // Should show "Approved" label for the resolved entry
136
+ expect(screen.getByText('Approved')).toBeInTheDocument();
137
+ // The resolved entry should still display the breakpoint question
138
+ expect(screen.getByText('Deploy?')).toBeInTheDocument();
139
+ });
140
+
141
+ it('auto-removes resolved entries after RESOLVED_DISPLAY_MS (20s)', () => {
142
+ const bp = makeBp({ runId: 'auto-clear-run', breakpointQuestion: 'Deploy now?' });
143
+
144
+ const { rerender } = render(<BreakpointBanner breakpointRuns={[bp]} />);
145
+
146
+ // Remove the breakpoint to trigger resolved state
147
+ act(() => {
148
+ rerender(<BreakpointBanner breakpointRuns={[]} />);
149
+ });
150
+
151
+ expect(screen.getByText('Approved')).toBeInTheDocument();
152
+
153
+ // Advance past the RESOLVED_DISPLAY_MS (20s) + cleanup interval (1s)
154
+ act(() => {
155
+ vi.advanceTimersByTime(22000);
156
+ });
157
+
158
+ // The banner should now return null (no waiting and no resolved)
159
+ expect(screen.queryByText('Approved')).not.toBeInTheDocument();
160
+ expect(screen.queryByTestId('breakpoint-banner')).not.toBeInTheDocument();
161
+ });
162
+
163
+ // --- Accessibility ---
164
+ it('has role="alert" and aria-live="assertive"', () => {
165
+ render(<BreakpointBanner breakpointRuns={[makeBp()]} />);
166
+ const banner = screen.getByTestId('breakpoint-banner');
167
+ expect(banner).toHaveAttribute('role', 'alert');
168
+ expect(banner).toHaveAttribute('aria-live', 'assertive');
169
+ });
170
+
171
+ // --- Links ---
172
+ it('renders links to run detail pages', () => {
173
+ render(<BreakpointBanner breakpointRuns={[makeBp({ runId: 'link-run' })]} />);
174
+ const links = screen.getAllByTestId('next-link');
175
+ expect(links[0]).toHaveAttribute('href', '/runs/link-run');
176
+ });
177
+ });