@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,98 @@
1
+ import React from 'react';
2
+ import { describe, it, expect } from 'vitest';
3
+ import { render, screen } from '@/test/test-utils';
4
+ import { StatusBadge } from '../status-badge';
5
+
6
+ describe('StatusBadge', () => {
7
+ it('renders without crashing', () => {
8
+ render(<StatusBadge status="completed" />);
9
+ expect(screen.getByText('Completed')).toBeInTheDocument();
10
+ });
11
+
12
+ it('renders "Completed" label for completed status', () => {
13
+ render(<StatusBadge status="completed" />);
14
+ expect(screen.getByText('Completed')).toBeInTheDocument();
15
+ });
16
+
17
+ it('renders "Done" label for resolved status', () => {
18
+ render(<StatusBadge status="resolved" />);
19
+ expect(screen.getByText('Done')).toBeInTheDocument();
20
+ });
21
+
22
+ it('renders "OK" label for ok status', () => {
23
+ render(<StatusBadge status="ok" />);
24
+ expect(screen.getByText('OK')).toBeInTheDocument();
25
+ });
26
+
27
+ it('renders "Failed" label for failed status', () => {
28
+ render(<StatusBadge status="failed" />);
29
+ expect(screen.getByText('Failed')).toBeInTheDocument();
30
+ });
31
+
32
+ it('renders "Error" label for error status', () => {
33
+ render(<StatusBadge status="error" />);
34
+ expect(screen.getByText('Error')).toBeInTheDocument();
35
+ });
36
+
37
+ it('renders "Waiting" label for waiting status', () => {
38
+ render(<StatusBadge status="waiting" />);
39
+ expect(screen.getByText('Waiting')).toBeInTheDocument();
40
+ });
41
+
42
+ it('renders "Needs Approval" label for breakpoint_awaiting status', () => {
43
+ render(<StatusBadge status="breakpoint_awaiting" />);
44
+ expect(screen.getByText('Needs Approval')).toBeInTheDocument();
45
+ });
46
+
47
+ it('renders "Running" label for requested status', () => {
48
+ render(<StatusBadge status="requested" />);
49
+ expect(screen.getByText('Running')).toBeInTheDocument();
50
+ });
51
+
52
+ it('renders "Pending" label for pending status', () => {
53
+ render(<StatusBadge status="pending" />);
54
+ expect(screen.getByText('Pending')).toBeInTheDocument();
55
+ });
56
+
57
+ it('falls back to pending config for unknown status', () => {
58
+ render(<StatusBadge status="unknown_status" />);
59
+ expect(screen.getByText('Pending')).toBeInTheDocument();
60
+ });
61
+
62
+ it('applies custom className', () => {
63
+ const { container } = render(<StatusBadge status="completed" className="my-custom" />);
64
+ const badge = container.firstChild as HTMLElement;
65
+ expect(badge.className).toContain('my-custom');
66
+ });
67
+
68
+ it('renders an icon alongside the label', () => {
69
+ const { container } = render(<StatusBadge status="completed" />);
70
+ // The Badge wrapper should contain both the SVG icon and the text
71
+ const svg = container.querySelector('svg');
72
+ expect(svg).toBeInTheDocument();
73
+ expect(screen.getByText('Completed')).toBeInTheDocument();
74
+ });
75
+
76
+ it('renders "Approval Needed" when status is waiting and waitingKind is breakpoint', () => {
77
+ render(<StatusBadge status="waiting" waitingKind="breakpoint" />);
78
+ expect(screen.getByText('Approval Needed')).toBeInTheDocument();
79
+ });
80
+
81
+ it('renders "Working" when status is waiting and waitingKind is task', () => {
82
+ render(<StatusBadge status="waiting" waitingKind="task" />);
83
+ expect(screen.getByText('Working')).toBeInTheDocument();
84
+ });
85
+
86
+ it('renders with stale styling when isStale is true', () => {
87
+ const { container } = render(<StatusBadge status="waiting" isStale={true} />);
88
+ const badge = container.firstChild as HTMLElement;
89
+ expect(badge.className).toContain('opacity-60');
90
+ });
91
+
92
+ it('renders normal waiting when waitingKind not provided', () => {
93
+ render(<StatusBadge status="waiting" />);
94
+ expect(screen.getByText('Waiting')).toBeInTheDocument();
95
+ expect(screen.queryByText('Approval Needed')).not.toBeInTheDocument();
96
+ expect(screen.queryByText('Working')).not.toBeInTheDocument();
97
+ });
98
+ });
@@ -0,0 +1,100 @@
1
+ import React from 'react';
2
+ import { describe, it, expect, beforeEach } from 'vitest';
3
+ import { render, screen, fireEvent } from '@/test/test-utils';
4
+ import { ThemeProvider, useTheme } from '../theme-provider';
5
+
6
+ function ThemeConsumer() {
7
+ const { theme, toggle } = useTheme();
8
+ return (
9
+ <div>
10
+ <span data-testid="theme-value">{theme}</span>
11
+ <button onClick={toggle}>Toggle</button>
12
+ </div>
13
+ );
14
+ }
15
+
16
+ describe('ThemeProvider', () => {
17
+ beforeEach(() => {
18
+ // Reset DOM state between tests since ThemeProvider reads from the DOM
19
+ document.documentElement.removeAttribute('data-theme');
20
+ document.documentElement.className = '';
21
+ localStorage.removeItem('observer-theme');
22
+ });
23
+
24
+ it('renders children', () => {
25
+ render(
26
+ <ThemeProvider>
27
+ <span>child content</span>
28
+ </ThemeProvider>,
29
+ );
30
+ expect(screen.getByText('child content')).toBeInTheDocument();
31
+ });
32
+
33
+ it('provides default dark theme', () => {
34
+ render(
35
+ <ThemeProvider>
36
+ <ThemeConsumer />
37
+ </ThemeProvider>,
38
+ );
39
+ expect(screen.getByTestId('theme-value').textContent).toBe('dark');
40
+ });
41
+
42
+ it('toggles from dark to light', () => {
43
+ render(
44
+ <ThemeProvider>
45
+ <ThemeConsumer />
46
+ </ThemeProvider>,
47
+ );
48
+ fireEvent.click(screen.getByText('Toggle'));
49
+ expect(screen.getByTestId('theme-value').textContent).toBe('light');
50
+ });
51
+
52
+ it('toggles from light back to dark', () => {
53
+ render(
54
+ <ThemeProvider>
55
+ <ThemeConsumer />
56
+ </ThemeProvider>,
57
+ );
58
+ fireEvent.click(screen.getByText('Toggle'));
59
+ expect(screen.getByTestId('theme-value').textContent).toBe('light');
60
+ fireEvent.click(screen.getByText('Toggle'));
61
+ expect(screen.getByTestId('theme-value').textContent).toBe('dark');
62
+ });
63
+
64
+ it('sets data-theme attribute on document element when toggling', () => {
65
+ render(
66
+ <ThemeProvider>
67
+ <ThemeConsumer />
68
+ </ThemeProvider>,
69
+ );
70
+ fireEvent.click(screen.getByText('Toggle'));
71
+ expect(document.documentElement.getAttribute('data-theme')).toBe('light');
72
+ });
73
+
74
+ it('sets className on document element when toggling', () => {
75
+ render(
76
+ <ThemeProvider>
77
+ <ThemeConsumer />
78
+ </ThemeProvider>,
79
+ );
80
+ fireEvent.click(screen.getByText('Toggle'));
81
+ expect(document.documentElement.className).toBe('light');
82
+ });
83
+
84
+ it('stores theme in localStorage when toggling', () => {
85
+ render(
86
+ <ThemeProvider>
87
+ <ThemeConsumer />
88
+ </ThemeProvider>,
89
+ );
90
+ fireEvent.click(screen.getByText('Toggle'));
91
+ expect(localStorage.getItem('observer-theme')).toBe('light');
92
+ });
93
+ });
94
+
95
+ describe('useTheme without provider', () => {
96
+ it('returns default values when used outside ThemeProvider', () => {
97
+ render(<ThemeConsumer />);
98
+ expect(screen.getByTestId('theme-value').textContent).toBe('dark');
99
+ });
100
+ });
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { describe, it, expect, vi } from 'vitest';
3
+ import { render, screen } from '@/test/test-utils';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { TruncatedId } from '../truncated-id';
6
+
7
+ describe('TruncatedId', () => {
8
+ it('renders without crashing', () => {
9
+ render(<TruncatedId id="abc123def456" />);
10
+ // formatShortId("abc123def456", 4) => "...f456"
11
+ expect(screen.getByText('...f456')).toBeInTheDocument();
12
+ });
13
+
14
+ it('renders truncated ID with default 4 chars', () => {
15
+ render(<TruncatedId id="long-id-string-xyz" />);
16
+ expect(screen.getByText('...-xyz')).toBeInTheDocument();
17
+ });
18
+
19
+ it('renders truncated ID with custom chars count', () => {
20
+ render(<TruncatedId id="abcdefghij" chars={6} />);
21
+ // formatShortId("abcdefghij", 6) => "...efghij"
22
+ expect(screen.getByText('...efghij')).toBeInTheDocument();
23
+ });
24
+
25
+ it('renders full ID when shorter than chars', () => {
26
+ render(<TruncatedId id="ab" chars={4} />);
27
+ expect(screen.getByText('ab')).toBeInTheDocument();
28
+ });
29
+
30
+ it('copies full ID to clipboard on click', async () => {
31
+ const user = userEvent.setup();
32
+ const writeTextSpy = vi.spyOn(navigator.clipboard, 'writeText');
33
+ render(<TruncatedId id="full-id-to-copy" />);
34
+ const el = screen.getByText('...copy');
35
+ await user.click(el);
36
+ expect(writeTextSpy).toHaveBeenCalledWith('full-id-to-copy');
37
+ });
38
+
39
+ it('applies copied class after click', async () => {
40
+ const user = userEvent.setup();
41
+ render(<TruncatedId id="some-test-id" />);
42
+ const el = screen.getByText('...t-id');
43
+ await user.click(el);
44
+ // After copying, the element gets 'text-primary' class to indicate copied state
45
+ expect(el.className).toContain('text-primary');
46
+ });
47
+
48
+ it('applies custom className', () => {
49
+ const { container } = render(<TruncatedId id="test-id" className="custom-class" />);
50
+ const span = container.querySelector('span');
51
+ expect(span?.className).toContain('custom-class');
52
+ });
53
+ });
@@ -0,0 +1,80 @@
1
+ "use client";
2
+ import { useState, useEffect } from "react";
3
+ import { Eye, Github, ExternalLink } from "lucide-react";
4
+
5
+ export function AppFooter() {
6
+ const [versions, setVersions] = useState({
7
+ app: process.env.NEXT_PUBLIC_APP_VERSION || "…",
8
+ babysitter: process.env.NEXT_PUBLIC_BABYSITTER_VERSION || "…",
9
+ });
10
+
11
+ useEffect(() => {
12
+ fetch("/api/version")
13
+ .then((r) => r.json())
14
+ .then((data) => {
15
+ if (data.app || data.babysitter) {
16
+ setVersions((prev) => ({
17
+ app: data.app || prev.app,
18
+ babysitter: data.babysitter || prev.babysitter,
19
+ }));
20
+ }
21
+ })
22
+ .catch(() => {
23
+ // Keep build-time fallback values
24
+ });
25
+ }, []);
26
+
27
+ return (
28
+ <footer className="border-t border-border bg-background/80 backdrop-blur-sm">
29
+ <div className="mx-auto max-w-[1600px] px-6 py-3 flex flex-wrap items-center justify-between gap-3 text-xs text-foreground-muted">
30
+ <div className="flex items-center gap-3 flex-wrap">
31
+ <Eye className="h-3.5 w-3.5 text-primary/40" />
32
+ <span className="font-medium">
33
+ Babysitter Observer{" "}
34
+ <span className="rounded-full bg-primary/10 border border-primary/20 px-1.5 py-px text-[10px] font-medium text-primary tabular-nums">
35
+ v{versions.app}
36
+ </span>
37
+ </span>
38
+
39
+ <span className="text-foreground-muted/30 select-none">&middot;</span>
40
+
41
+ <span className="text-xs font-normal text-foreground-muted">
42
+ Babysitter{" "}
43
+ <span className="rounded-full bg-muted/50 border border-border px-1.5 py-px text-[10px] font-normal text-foreground-muted tabular-nums">
44
+ v{versions.babysitter}
45
+ </span>
46
+ </span>
47
+ </div>
48
+ <div className="flex items-center gap-4">
49
+ <a
50
+ href="https://github.com/a5c-ai/babysitter/tree/main/packages/observer-dashboard#readme"
51
+ target="_blank"
52
+ rel="noopener noreferrer"
53
+ className="inline-flex items-center gap-1 hover:text-foreground-secondary transition-colors"
54
+ >
55
+ <Github className="h-3 w-3" />
56
+ Docs
57
+ </a>
58
+ <a
59
+ href="https://github.com/a5c-ai/babysitter"
60
+ target="_blank"
61
+ rel="noopener noreferrer"
62
+ className="inline-flex items-center gap-1 hover:text-foreground-secondary transition-colors"
63
+ >
64
+ <Github className="h-3 w-3" />
65
+ Babysitter
66
+ </a>
67
+ <a
68
+ href="https://www.a5c.ai/"
69
+ target="_blank"
70
+ rel="noopener noreferrer"
71
+ className="inline-flex items-center gap-1 hover:text-primary transition-colors"
72
+ >
73
+ a5c.ai
74
+ <ExternalLink className="h-3 w-3" />
75
+ </a>
76
+ </div>
77
+ </div>
78
+ </footer>
79
+ );
80
+ }
@@ -0,0 +1,160 @@
1
+ "use client";
2
+ import { useState, useCallback, useEffect } from "react";
3
+ import Link from "next/link";
4
+ import { useTheme } from "@/components/shared/theme-provider";
5
+ import { useEventStream } from "@/hooks/use-event-stream";
6
+ import { useNotificationContext } from "@/components/notifications/notification-provider";
7
+ import { useKeyboard } from "@/hooks/use-keyboard";
8
+ import { NotificationPanel } from "@/components/notifications/notification-panel";
9
+ import { SettingsModal } from "@/components/shared/settings-modal";
10
+ import { cn } from "@/lib/cn";
11
+ import {
12
+ Eye,
13
+ Sun,
14
+ Moon,
15
+ Settings,
16
+ Bell,
17
+ HelpCircle,
18
+ Wifi,
19
+ WifiOff,
20
+ Github,
21
+ } from "lucide-react";
22
+
23
+ export function AppHeader() {
24
+ const { theme, toggle: toggleTheme } = useTheme();
25
+ const { connected: sseConnected } = useEventStream();
26
+ const { notifications, dismiss } = useNotificationContext();
27
+ const [showNotificationPanel, setShowNotificationPanel] = useState(false);
28
+ const [showSettings, setShowSettings] = useState(false);
29
+
30
+ const toggleNotificationPanel = useCallback(() => {
31
+ setShowNotificationPanel((v) => !v);
32
+ }, []);
33
+
34
+ useKeyboard([
35
+ { key: "n", action: toggleNotificationPanel, description: "Toggle notifications" },
36
+ ]);
37
+
38
+ // Allow external components to open the settings modal via custom event
39
+ useEffect(() => {
40
+ const handler = () => setShowSettings(true);
41
+ window.addEventListener("open-settings", handler);
42
+ return () => window.removeEventListener("open-settings", handler);
43
+ }, []);
44
+
45
+
46
+ return (
47
+ <>
48
+ <a
49
+ href="#main-content"
50
+ className="sr-only focus:not-sr-only focus:absolute focus:top-2 focus:left-2 focus:z-[100] focus:px-4 focus:py-2 focus:bg-primary focus:text-primary-foreground focus:rounded-md"
51
+ >
52
+ Skip to main content
53
+ </a>
54
+ <header className="sticky top-0 z-30 border-b border-border bg-background/80 backdrop-blur-md">
55
+ <div className="mx-auto max-w-[1600px] px-6 py-3 flex items-center gap-3">
56
+ <Eye className="h-5 w-5 text-primary" />
57
+ <h1 className="text-base font-semibold">
58
+ <Link href="/" className="text-foreground hover:text-primary transition-colors">
59
+ Babysitter Observer
60
+ </Link>
61
+ </h1>
62
+ <a
63
+ href="https://www.a5c.ai/"
64
+ target="_blank"
65
+ rel="noopener noreferrer"
66
+ className="text-xs leading-tight font-medium text-primary/60 hover:text-primary transition-colors hidden sm:block"
67
+ >
68
+ a5c.ai
69
+ </a>
70
+ <a
71
+ href="https://github.com/a5c-ai/babysitter"
72
+ target="_blank"
73
+ rel="noopener noreferrer"
74
+ className="inline-flex items-center gap-1 text-xs text-foreground-muted hover:text-foreground-secondary transition-colors hidden sm:block"
75
+ title="Babysitter on GitHub"
76
+ >
77
+ <Github className="h-3.5 w-3.5" />
78
+ </a>
79
+ <span className="text-xs text-foreground-muted hidden md:block">
80
+ Real-time orchestration dashboard
81
+ </span>
82
+ <div className="ml-auto flex items-center gap-1.5">
83
+ {/* SSE connection status chip */}
84
+ <span
85
+ data-testid="sse-status"
86
+ role="status"
87
+ aria-live="polite"
88
+ className={cn(
89
+ "inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium mr-1 transition-all",
90
+ sseConnected
91
+ ? "bg-success/10 text-success border border-success/20"
92
+ : "bg-error/10 text-error border border-error/20"
93
+ )}
94
+ title={sseConnected ? "Live updates connected" : "Live updates disconnected"}
95
+ >
96
+ {sseConnected ? (
97
+ <Wifi className="h-3 w-3" />
98
+ ) : (
99
+ <WifiOff className="h-3 w-3" />
100
+ )}
101
+ <span className="hidden sm:inline">{sseConnected ? "Live" : "Offline"}</span>
102
+ </span>
103
+ {/* Notification bell */}
104
+ <button
105
+ data-testid="notification-bell"
106
+ onClick={toggleNotificationPanel}
107
+ className="relative rounded-md p-2 min-h-[44px] min-w-[44px] flex items-center justify-center text-foreground-muted hover:text-foreground-secondary hover:bg-background-secondary transition-colors"
108
+ title="Notifications"
109
+ aria-label={`Notifications${notifications.length > 0 ? ` (${notifications.length} unread)` : ""}`}
110
+ >
111
+ <Bell className="h-4 w-4" />
112
+ {notifications.length > 0 && (
113
+ <span data-testid="notification-badge" className="absolute -top-0.5 -right-0.5 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-primary-foreground tabular-nums">
114
+ {notifications.length > 9 ? "9+" : notifications.length}
115
+ </span>
116
+ )}
117
+ </button>
118
+ {/* Keyboard shortcuts help */}
119
+ <button
120
+ onClick={() => window.dispatchEvent(new CustomEvent("open-shortcuts-help"))}
121
+ className="rounded-md p-2 min-h-[44px] min-w-[44px] flex items-center justify-center text-foreground-muted hover:text-foreground-secondary hover:bg-background-secondary transition-colors"
122
+ title="Keyboard shortcuts"
123
+ aria-label="Keyboard shortcuts"
124
+ >
125
+ <HelpCircle className="h-4 w-4" />
126
+ </button>
127
+ <button
128
+ onClick={() => setShowSettings(true)}
129
+ className="rounded-md p-2 min-h-[44px] min-w-[44px] flex items-center justify-center text-foreground-muted hover:text-foreground-secondary hover:bg-background-secondary transition-colors"
130
+ title="Settings"
131
+ aria-label="Settings"
132
+ >
133
+ <Settings className="h-4 w-4" />
134
+ </button>
135
+ <button
136
+ data-testid="theme-toggle"
137
+ onClick={toggleTheme}
138
+ className="rounded-md p-2 min-h-[44px] min-w-[44px] flex items-center justify-center text-foreground-muted hover:text-foreground-secondary hover:bg-background-secondary transition-colors"
139
+ title={`Switch to ${theme === "dark" ? "light" : "dark"} theme`}
140
+ aria-label={`Switch to ${theme === "dark" ? "light" : "dark"} theme`}
141
+ >
142
+ {theme === "dark" ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
143
+ </button>
144
+ </div>
145
+ </div>
146
+ </header>
147
+
148
+ {/* Notification Panel */}
149
+ <NotificationPanel
150
+ open={showNotificationPanel}
151
+ notifications={notifications}
152
+ onDismiss={dismiss}
153
+ onClose={() => setShowNotificationPanel(false)}
154
+ />
155
+
156
+ {/* Settings Modal */}
157
+ <SettingsModal open={showSettings} onClose={() => setShowSettings(false)} />
158
+ </>
159
+ );
160
+ }
@@ -0,0 +1,18 @@
1
+ import { cn } from "@/lib/cn";
2
+ import { Inbox } from "lucide-react";
3
+
4
+ interface EmptyStateProps {
5
+ title?: string;
6
+ description?: string;
7
+ className?: string;
8
+ }
9
+
10
+ export function EmptyState({ title = "No runs found", description = "Start a babysitter run to see it here.", className }: EmptyStateProps) {
11
+ return (
12
+ <div className={cn("flex flex-col items-center justify-center py-16 text-center", className)}>
13
+ <Inbox className="h-12 w-12 text-foreground-muted/30 mb-4" />
14
+ <h3 className="text-sm font-medium text-foreground-secondary">{title}</h3>
15
+ <p className="mt-1 text-xs text-foreground-muted">{description}</p>
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,81 @@
1
+ "use client";
2
+ import React from "react";
3
+
4
+ interface ErrorBoundaryProps {
5
+ children: React.ReactNode;
6
+ /** When set, renders a compact inline fallback instead of the full-page error. */
7
+ section?: string;
8
+ }
9
+
10
+ interface ErrorBoundaryState {
11
+ hasError: boolean;
12
+ error: Error | null;
13
+ }
14
+
15
+ export class ErrorBoundary extends React.Component<
16
+ ErrorBoundaryProps,
17
+ ErrorBoundaryState
18
+ > {
19
+ constructor(props: ErrorBoundaryProps) {
20
+ super(props);
21
+ this.state = { hasError: false, error: null };
22
+ }
23
+
24
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
25
+ return { hasError: true, error };
26
+ }
27
+
28
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
29
+ console.error("ErrorBoundary caught an error:", error, errorInfo);
30
+ }
31
+
32
+ private handleRetry = () => {
33
+ this.setState({ hasError: false, error: null });
34
+ };
35
+
36
+ render() {
37
+ if (this.state.hasError) {
38
+ // Section-level: compact inline fallback that doesn't take over the page
39
+ if (this.props.section) {
40
+ return (
41
+ <div className="rounded-lg border border-error/20 bg-error-muted p-4 text-center">
42
+ <p className="text-sm font-medium text-error mb-1">
43
+ {this.props.section} failed to load
44
+ </p>
45
+ <p className="text-xs text-foreground-muted mb-2">
46
+ This section encountered an error. Other sections are unaffected.
47
+ </p>
48
+ <button
49
+ onClick={this.handleRetry}
50
+ className="rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-primary/90"
51
+ >
52
+ Retry
53
+ </button>
54
+ </div>
55
+ );
56
+ }
57
+
58
+ // Root-level: full-page fallback
59
+ return (
60
+ <div className="flex min-h-screen items-center justify-center bg-background p-6">
61
+ <div className="max-w-md text-center">
62
+ <h2 className="mb-2 text-lg font-semibold text-foreground">
63
+ Something went wrong
64
+ </h2>
65
+ <p className="mb-4 text-sm text-foreground-muted">
66
+ An unexpected error occurred. Please try again.
67
+ </p>
68
+ <button
69
+ onClick={() => window.location.reload()}
70
+ className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary/90"
71
+ >
72
+ Try Again
73
+ </button>
74
+ </div>
75
+ </div>
76
+ );
77
+ }
78
+
79
+ return this.props.children;
80
+ }
81
+ }
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import { useState } from "react";
3
+ import { formatShortId } from "@/lib/utils";
4
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
5
+ import { cn } from "@/lib/cn";
6
+
7
+ interface FriendlyIdProps {
8
+ id: string;
9
+ className?: string;
10
+ }
11
+
12
+ export function FriendlyId({ id, className }: FriendlyIdProps) {
13
+ const [copied, setCopied] = useState(false);
14
+
15
+ const handleCopy = async () => {
16
+ try {
17
+ await navigator.clipboard.writeText(id);
18
+ setCopied(true);
19
+ setTimeout(() => setCopied(false), 2000);
20
+ } catch (err) {
21
+ console.error('Failed to copy:', err);
22
+ }
23
+ };
24
+
25
+ return (
26
+ <TooltipProvider>
27
+ <Tooltip>
28
+ <TooltipTrigger asChild>
29
+ <button
30
+ onClick={handleCopy}
31
+ className={cn(
32
+ "inline-flex items-center rounded px-1.5 py-0.5 font-mono text-xs",
33
+ "bg-background-secondary text-info/80",
34
+ "hover:bg-background-tertiary hover:text-info transition-colors cursor-pointer",
35
+ copied && "text-primary",
36
+ className
37
+ )}
38
+ >
39
+ {formatShortId(id)}
40
+ </button>
41
+ </TooltipTrigger>
42
+ <TooltipContent>
43
+ <p className="font-mono text-xs">{copied ? <span className="text-primary font-semibold">Copied!</span> : id}</p>
44
+ </TooltipContent>
45
+ </Tooltip>
46
+ </TooltipProvider>
47
+ );
48
+ }
@@ -0,0 +1,15 @@
1
+ import { cn } from "@/lib/cn";
2
+
3
+ export function Kbd({ children, className }: { children: React.ReactNode; className?: string }) {
4
+ return (
5
+ <kbd className={cn(
6
+ "inline-flex h-5 min-w-[20px] items-center justify-center rounded",
7
+ "border border-[var(--kbd-border)] bg-background-secondary",
8
+ "px-1.5 font-mono text-xs leading-tight text-foreground-muted",
9
+ "shadow-kbd",
10
+ className
11
+ )}>
12
+ {children}
13
+ </kbd>
14
+ );
15
+ }