@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,345 @@
1
+ import React from 'react';
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { render, screen, setupUser } from '@/test/test-utils';
4
+ import { PipelineView } from '../pipeline-view';
5
+ import {
6
+ createMockRun,
7
+ createMockTaskEffect,
8
+ resetIdCounter,
9
+ } from '@/test/fixtures';
10
+
11
+ // Mock next/link so Link renders as a plain anchor
12
+ vi.mock('next/link', () => ({
13
+ default: ({ children, href, ...props }: any) =>
14
+ React.createElement('a', { href, ...props }, children),
15
+ }));
16
+
17
+ describe('PipelineView', () => {
18
+ const defaultProps = {
19
+ selectedEffectId: null,
20
+ onSelectEffect: vi.fn(),
21
+ };
22
+
23
+ beforeEach(() => {
24
+ resetIdCounter();
25
+ vi.clearAllMocks();
26
+ });
27
+
28
+ // -----------------------------------------------------------------------
29
+ // Basic rendering with a Run
30
+ // -----------------------------------------------------------------------
31
+
32
+ it('renders without crashing', () => {
33
+ const run = createMockRun();
34
+ render(<PipelineView {...defaultProps} run={run} />);
35
+ // Should render the breadcrumb "Projects" link
36
+ expect(screen.getByText('Projects')).toBeInTheDocument();
37
+ });
38
+
39
+ it('displays the project name in breadcrumb', () => {
40
+ const run = createMockRun({ projectName: 'my-cool-project' });
41
+ render(<PipelineView {...defaultProps} run={run} />);
42
+ expect(screen.getByText('my-cool-project')).toBeInTheDocument();
43
+ });
44
+
45
+ it('falls back to friendlyProcessName when projectName is empty', () => {
46
+ const run = createMockRun({ projectName: '', processId: 'data-pipeline/ingest' });
47
+ render(<PipelineView {...defaultProps} run={run} />);
48
+ // friendlyProcessName('data-pipeline/ingest') => 'Data Pipeline Ingest'
49
+ expect(screen.getByText('Data Pipeline Ingest')).toBeInTheDocument();
50
+ });
51
+
52
+ it('displays the run status badge', () => {
53
+ const run = createMockRun({ status: 'completed' });
54
+ render(<PipelineView {...defaultProps} run={run} />);
55
+ expect(screen.getByText('Completed')).toBeInTheDocument();
56
+ });
57
+
58
+ it('displays task count in the header', () => {
59
+ const run = createMockRun({ completedTasks: 5, totalTasks: 10 });
60
+ render(<PipelineView {...defaultProps} run={run} />);
61
+ expect(screen.getByText('5/10 tasks')).toBeInTheDocument();
62
+ });
63
+
64
+ it('displays formatted duration in the header', () => {
65
+ const run = createMockRun({ duration: 59000 });
66
+ render(<PipelineView {...defaultProps} run={run} />);
67
+ // formatDuration(59000) => "59s"
68
+ expect(screen.getByText('59s')).toBeInTheDocument();
69
+ });
70
+
71
+ it('displays progress percentage', () => {
72
+ const run = createMockRun({ completedTasks: 3, totalTasks: 4 });
73
+ render(<PipelineView {...defaultProps} run={run} />);
74
+ // Math.round((3/4)*100) = 75
75
+ expect(screen.getByText('75%')).toBeInTheDocument();
76
+ });
77
+
78
+ it('shows 0% progress when totalTasks is 0', () => {
79
+ const run = createMockRun({ totalTasks: 0, completedTasks: 0, tasks: [] });
80
+ render(<PipelineView {...defaultProps} run={run} />);
81
+ expect(screen.getByText('0%')).toBeInTheDocument();
82
+ });
83
+
84
+ // -----------------------------------------------------------------------
85
+ // Link back to Projects
86
+ // -----------------------------------------------------------------------
87
+
88
+ it('has a link back to projects page', () => {
89
+ const run = createMockRun();
90
+ render(<PipelineView {...defaultProps} run={run} />);
91
+ const link = screen.getByText('Projects');
92
+ expect(link.closest('a')).toHaveAttribute('href', '/');
93
+ });
94
+
95
+ // -----------------------------------------------------------------------
96
+ // Step list display
97
+ // -----------------------------------------------------------------------
98
+
99
+ it('renders step cards for each task', () => {
100
+ const tasks = [
101
+ createMockTaskEffect({ title: 'Task Alpha', status: 'resolved' }),
102
+ createMockTaskEffect({ title: 'Task Beta', status: 'resolved' }),
103
+ createMockTaskEffect({ title: 'Task Gamma', status: 'requested' }),
104
+ ];
105
+ const run = createMockRun({ tasks, totalTasks: 3, completedTasks: 2 });
106
+ render(<PipelineView {...defaultProps} run={run} />);
107
+ expect(screen.getByText('Task Alpha')).toBeInTheDocument();
108
+ expect(screen.getByText('Task Beta')).toBeInTheDocument();
109
+ expect(screen.getByText('Task Gamma')).toBeInTheDocument();
110
+ });
111
+
112
+ // -----------------------------------------------------------------------
113
+ // Empty tasks
114
+ // -----------------------------------------------------------------------
115
+
116
+ it('shows "No tasks yet" when run has no tasks', () => {
117
+ const run = createMockRun({ tasks: [], totalTasks: 0, completedTasks: 0 });
118
+ render(<PipelineView {...defaultProps} run={run} />);
119
+ expect(screen.getByText('No tasks yet')).toBeInTheDocument();
120
+ });
121
+
122
+ // -----------------------------------------------------------------------
123
+ // Parallel grouping
124
+ // -----------------------------------------------------------------------
125
+
126
+ it('groups tasks with same stepId prefix into a parallel group', () => {
127
+ const baseTime = new Date('2026-01-15T10:00:00.000Z');
128
+ const tasks = [
129
+ createMockTaskEffect({
130
+ title: 'Parallel A',
131
+ stepId: 'step1.a',
132
+ requestedAt: baseTime.toISOString(),
133
+ status: 'resolved',
134
+ }),
135
+ createMockTaskEffect({
136
+ title: 'Parallel B',
137
+ stepId: 'step1.b',
138
+ requestedAt: new Date(baseTime.getTime() + 10).toISOString(),
139
+ status: 'resolved',
140
+ }),
141
+ createMockTaskEffect({
142
+ title: 'Sequential C',
143
+ stepId: 'step2.a',
144
+ requestedAt: new Date(baseTime.getTime() + 5000).toISOString(),
145
+ status: 'resolved',
146
+ }),
147
+ ];
148
+ const run = createMockRun({ tasks, totalTasks: 3, completedTasks: 3 });
149
+ render(<PipelineView {...defaultProps} run={run} />);
150
+
151
+ // All tasks should render
152
+ expect(screen.getByText('Parallel A')).toBeInTheDocument();
153
+ expect(screen.getByText('Parallel B')).toBeInTheDocument();
154
+ expect(screen.getByText('Sequential C')).toBeInTheDocument();
155
+
156
+ // The parallel group label should appear
157
+ expect(screen.getByText('parallel')).toBeInTheDocument();
158
+ expect(screen.getByText(/2 tasks/)).toBeInTheDocument();
159
+ });
160
+
161
+ it('groups tasks within PARALLEL_THRESHOLD_MS into parallel group', () => {
162
+ const baseTime = new Date('2026-01-15T10:00:00.000Z');
163
+ const tasks = [
164
+ createMockTaskEffect({
165
+ title: 'Close A',
166
+ stepId: 'stepA.1',
167
+ requestedAt: baseTime.toISOString(),
168
+ status: 'resolved',
169
+ }),
170
+ createMockTaskEffect({
171
+ title: 'Close B',
172
+ stepId: 'stepB.1',
173
+ requestedAt: new Date(baseTime.getTime() + 50).toISOString(),
174
+ status: 'resolved',
175
+ }),
176
+ ];
177
+ const run = createMockRun({ tasks, totalTasks: 2, completedTasks: 2 });
178
+ render(<PipelineView {...defaultProps} run={run} />);
179
+ // Both within 100ms threshold -> parallel group
180
+ expect(screen.getByText('parallel')).toBeInTheDocument();
181
+ // The header shows "2/2 tasks" and the parallel group label shows "· 2 tasks"
182
+ // Use getAllByText to confirm at least one match for the parallel group count
183
+ const matches = screen.getAllByText(/2 tasks/);
184
+ expect(matches.length).toBeGreaterThanOrEqual(1);
185
+ });
186
+
187
+ it('does not group tasks far apart in time with different step prefixes', () => {
188
+ const baseTime = new Date('2026-01-15T10:00:00.000Z');
189
+ const tasks = [
190
+ createMockTaskEffect({
191
+ title: 'Solo A',
192
+ stepId: 'stepA.1',
193
+ requestedAt: baseTime.toISOString(),
194
+ status: 'resolved',
195
+ }),
196
+ createMockTaskEffect({
197
+ title: 'Solo B',
198
+ stepId: 'stepB.1',
199
+ requestedAt: new Date(baseTime.getTime() + 5000).toISOString(),
200
+ status: 'resolved',
201
+ }),
202
+ ];
203
+ const run = createMockRun({ tasks, totalTasks: 2, completedTasks: 2 });
204
+ render(<PipelineView {...defaultProps} run={run} />);
205
+ expect(screen.getByText('Solo A')).toBeInTheDocument();
206
+ expect(screen.getByText('Solo B')).toBeInTheDocument();
207
+ // No parallel group should be rendered
208
+ expect(screen.queryByText('parallel')).not.toBeInTheDocument();
209
+ });
210
+
211
+ // -----------------------------------------------------------------------
212
+ // runStatus override
213
+ // -----------------------------------------------------------------------
214
+
215
+ it('uses runStatus prop over run.status when provided', () => {
216
+ const run = createMockRun({ status: 'completed' });
217
+ render(
218
+ <PipelineView
219
+ {...defaultProps}
220
+ run={run}
221
+ runStatus="waiting"
222
+ />,
223
+ );
224
+ // The StatusBadge still shows run.status (not runStatus) — run.status is in the badge
225
+ // But the effectiveStatus drives isReviewMode and isRunning behavior
226
+ // The status badge still displays run.status from the breadcrumb
227
+ expect(screen.getByText('Completed')).toBeInTheDocument();
228
+ });
229
+
230
+ // -----------------------------------------------------------------------
231
+ // Selected effect
232
+ // -----------------------------------------------------------------------
233
+
234
+ it('passes isSelected=true to the correct StepCard', () => {
235
+ const tasks = [
236
+ createMockTaskEffect({ effectId: 'eff-1', title: 'First' }),
237
+ createMockTaskEffect({ effectId: 'eff-2', title: 'Second' }),
238
+ ];
239
+ const run = createMockRun({ tasks, totalTasks: 2 });
240
+ render(
241
+ <PipelineView
242
+ {...defaultProps}
243
+ run={run}
244
+ selectedEffectId="eff-2"
245
+ />,
246
+ );
247
+ // Both tasks should render
248
+ expect(screen.getByText('First')).toBeInTheDocument();
249
+ expect(screen.getByText('Second')).toBeInTheDocument();
250
+ });
251
+
252
+ // -----------------------------------------------------------------------
253
+ // Show all tasks (pagination)
254
+ // -----------------------------------------------------------------------
255
+
256
+ it('shows "Show all" button when more than 20 pipeline entries exist', () => {
257
+ const tasks = Array.from({ length: 25 }, (_, i) =>
258
+ createMockTaskEffect({
259
+ title: `Task ${i + 1}`,
260
+ stepId: `step-${i}.0`,
261
+ requestedAt: new Date(Date.now() + i * 1000).toISOString(),
262
+ status: 'resolved',
263
+ }),
264
+ );
265
+ const run = createMockRun({ tasks, totalTasks: 25, completedTasks: 25 });
266
+ render(<PipelineView {...defaultProps} run={run} />);
267
+ expect(screen.getByText(/Show all 25 tasks/)).toBeInTheDocument();
268
+ });
269
+
270
+ it('reveals all tasks when "Show all" button is clicked', async () => {
271
+ const user = setupUser();
272
+ const tasks = Array.from({ length: 25 }, (_, i) =>
273
+ createMockTaskEffect({
274
+ title: `Task ${i + 1}`,
275
+ stepId: `step-${i}.0`,
276
+ requestedAt: new Date(Date.now() + i * 1000).toISOString(),
277
+ status: 'resolved',
278
+ }),
279
+ );
280
+ const run = createMockRun({ tasks, totalTasks: 25, completedTasks: 25 });
281
+ render(<PipelineView {...defaultProps} run={run} />);
282
+
283
+ // Task 25 should not be visible initially (only first 20 entries shown)
284
+ expect(screen.queryByText('Task 25')).not.toBeInTheDocument();
285
+
286
+ // Click "Show all"
287
+ await user.click(screen.getByText(/Show all 25 tasks/));
288
+
289
+ // Now all tasks should be visible
290
+ expect(screen.getByText('Task 25')).toBeInTheDocument();
291
+ // The "Show all" button should be gone
292
+ expect(screen.queryByText(/Show all/)).not.toBeInTheDocument();
293
+ });
294
+
295
+ it('does not show "Show all" button when 20 or fewer entries exist', () => {
296
+ const tasks = Array.from({ length: 5 }, (_, i) =>
297
+ createMockTaskEffect({
298
+ title: `SmallTask ${i + 1}`,
299
+ stepId: `step-${i}.0`,
300
+ requestedAt: new Date(Date.now() + i * 1000).toISOString(),
301
+ status: 'resolved',
302
+ }),
303
+ );
304
+ const run = createMockRun({ tasks, totalTasks: 5, completedTasks: 5 });
305
+ render(<PipelineView {...defaultProps} run={run} />);
306
+ expect(screen.queryByText(/Show all/)).not.toBeInTheDocument();
307
+ });
308
+
309
+ // -----------------------------------------------------------------------
310
+ // onSelectEffect callback
311
+ // -----------------------------------------------------------------------
312
+
313
+ it('calls onSelectEffect when a step card is clicked', async () => {
314
+ const user = setupUser();
315
+ const onSelectEffect = vi.fn();
316
+ const tasks = [
317
+ createMockTaskEffect({ effectId: 'eff-click-me', title: 'Click Me Task' }),
318
+ ];
319
+ const run = createMockRun({ tasks, totalTasks: 1 });
320
+ render(
321
+ <PipelineView
322
+ {...defaultProps}
323
+ run={run}
324
+ onSelectEffect={onSelectEffect}
325
+ />,
326
+ );
327
+ // Click the task title area (inside the main button)
328
+ await user.click(screen.getByText('Click Me Task'));
329
+ expect(onSelectEffect).toHaveBeenCalledWith('eff-click-me');
330
+ });
331
+
332
+ // -----------------------------------------------------------------------
333
+ // Session pill
334
+ // -----------------------------------------------------------------------
335
+
336
+ it('renders session pill with session ID', () => {
337
+ const run = createMockRun({ sessionId: 'session-abc-123' });
338
+ render(<PipelineView {...defaultProps} run={run} />);
339
+ // SessionPill uses formatShortId which shows "...3456" format
340
+ // For "session-abc-123", it shows last 4 chars: "...c-123" -> actually "...-123"
341
+ // Just check the component renders (it uses formatShortId internally)
342
+ // The component is present in the DOM
343
+ expect(screen.getByText('Projects')).toBeInTheDocument();
344
+ });
345
+ });
@@ -0,0 +1,330 @@
1
+ import React from 'react';
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { render, screen, setupUser } from '@/test/test-utils';
4
+ import { StepCard } from '../step-card';
5
+ import {
6
+ createMockTaskEffect,
7
+ resetIdCounter,
8
+ } from '@/test/fixtures';
9
+
10
+ // Mock next/link
11
+ vi.mock('next/link', () => ({
12
+ default: ({ children, href, ...props }: any) =>
13
+ React.createElement('a', { href, ...props }, children),
14
+ }));
15
+
16
+ describe('StepCard', () => {
17
+ const defaultProps = {
18
+ runId: 'run-001',
19
+ onSelect: vi.fn(),
20
+ isSelected: false,
21
+ defaultExpanded: false,
22
+ stepNumber: 1,
23
+ };
24
+
25
+ beforeEach(() => {
26
+ resetIdCounter();
27
+ vi.clearAllMocks();
28
+ });
29
+
30
+ // -----------------------------------------------------------------------
31
+ // Basic rendering
32
+ // -----------------------------------------------------------------------
33
+
34
+ it('renders the task title', () => {
35
+ const task = createMockTaskEffect({ title: 'Fetch user data' });
36
+ render(<StepCard {...defaultProps} task={task} />);
37
+ expect(screen.getByText('Fetch user data')).toBeInTheDocument();
38
+ });
39
+
40
+ it('renders status badge for resolved task', () => {
41
+ const task = createMockTaskEffect({ status: 'resolved' });
42
+ render(<StepCard {...defaultProps} task={task} />);
43
+ // StatusBadge maps "resolved" -> "Done"
44
+ expect(screen.getByText('Done')).toBeInTheDocument();
45
+ });
46
+
47
+ it('renders status badge for error task', () => {
48
+ const task = createMockTaskEffect({ status: 'error' });
49
+ render(<StepCard {...defaultProps} task={task} />);
50
+ expect(screen.getByText('Error')).toBeInTheDocument();
51
+ });
52
+
53
+ it('renders status badge for requested (running) task', () => {
54
+ const task = createMockTaskEffect({ status: 'requested' });
55
+ render(<StepCard {...defaultProps} task={task} />);
56
+ expect(screen.getByText('Running')).toBeInTheDocument();
57
+ });
58
+
59
+ // -----------------------------------------------------------------------
60
+ // Step number display
61
+ // -----------------------------------------------------------------------
62
+
63
+ it('displays step number when provided', () => {
64
+ const task = createMockTaskEffect();
65
+ render(<StepCard {...defaultProps} task={task} stepNumber={3} />);
66
+ expect(screen.getByText('3')).toBeInTheDocument();
67
+ });
68
+
69
+ it('does not render step number badge when stepNumber is undefined', () => {
70
+ const task = createMockTaskEffect();
71
+ const { container } = render(
72
+ <StepCard {...defaultProps} task={task} stepNumber={undefined} />,
73
+ );
74
+ // Step number badge has specific classes
75
+ const stepBadges = container.querySelectorAll('.w-5.h-5.rounded-full');
76
+ expect(stepBadges.length).toBe(0);
77
+ });
78
+
79
+ // -----------------------------------------------------------------------
80
+ // Kind badge
81
+ // -----------------------------------------------------------------------
82
+
83
+ it('renders KindBadge for the task kind', () => {
84
+ const task = createMockTaskEffect({ kind: 'shell' });
85
+ render(<StepCard {...defaultProps} task={task} />);
86
+ expect(screen.getByText('shell')).toBeInTheDocument();
87
+ });
88
+
89
+ it('renders KindBadge for agent kind', () => {
90
+ const task = createMockTaskEffect({ kind: 'agent' });
91
+ render(<StepCard {...defaultProps} task={task} />);
92
+ expect(screen.getByText('agent')).toBeInTheDocument();
93
+ });
94
+
95
+ // -----------------------------------------------------------------------
96
+ // Running state (animation pulse dot)
97
+ // -----------------------------------------------------------------------
98
+
99
+ it('shows an animated pulse dot when task is running', () => {
100
+ const task = createMockTaskEffect({ status: 'requested', kind: 'node' });
101
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
102
+ const pulseDot = container.querySelector('.animate-pulse-dot');
103
+ expect(pulseDot).toBeInTheDocument();
104
+ });
105
+
106
+ it('shows running text with elapsed time for requested task', () => {
107
+ const task = createMockTaskEffect({
108
+ status: 'requested',
109
+ kind: 'node',
110
+ requestedAt: new Date(Date.now() - 5000).toISOString(),
111
+ });
112
+ render(<StepCard {...defaultProps} task={task} />);
113
+ expect(screen.getByText(/running/)).toBeInTheDocument();
114
+ });
115
+
116
+ it('does not show pulse dot for resolved task', () => {
117
+ const task = createMockTaskEffect({ status: 'resolved', kind: 'node' });
118
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
119
+ const pulseDots = container.querySelectorAll('.bg-info.animate-pulse-dot');
120
+ expect(pulseDots.length).toBe(0);
121
+ });
122
+
123
+ // -----------------------------------------------------------------------
124
+ // Duration display
125
+ // -----------------------------------------------------------------------
126
+
127
+ it('shows formatted duration for completed task', () => {
128
+ const task = createMockTaskEffect({ status: 'resolved', duration: 4000 });
129
+ render(<StepCard {...defaultProps} task={task} />);
130
+ // Duration appears in the card body (may also appear in expanded details)
131
+ expect(screen.getAllByText('4s').length).toBeGreaterThanOrEqual(1);
132
+ });
133
+
134
+ it('does not show duration row in card body when duration is absent and task is not running', () => {
135
+ // Create a task and override duration to undefined (falsy) directly
136
+ const task = createMockTaskEffect({ status: 'resolved' });
137
+ const taskNoDuration = { ...task, duration: undefined };
138
+ const { container } = render(<StepCard {...defaultProps} task={taskNoDuration} defaultExpanded={false} />);
139
+ // The main card button should not contain a Clock icon for the duration row
140
+ const mainButton = container.querySelector('button.w-full.text-left.p-3');
141
+ const clockInBody = mainButton?.querySelector('[data-lucide="Clock"]');
142
+ expect(clockInBody).toBeNull();
143
+ });
144
+
145
+ // -----------------------------------------------------------------------
146
+ // Click handler
147
+ // -----------------------------------------------------------------------
148
+
149
+ it('calls onSelect with effectId when card button is clicked', async () => {
150
+ const user = setupUser();
151
+ const onSelect = vi.fn();
152
+ const task = createMockTaskEffect({ effectId: 'eff-click-test' });
153
+ render(<StepCard {...defaultProps} task={task} onSelect={onSelect} />);
154
+ // Click the main button (first button is the main card button)
155
+ const buttons = screen.getAllByRole('button');
156
+ await user.click(buttons[0]);
157
+ expect(onSelect).toHaveBeenCalledWith('eff-click-test');
158
+ });
159
+
160
+ it('does not call onSelect when expand toggle is clicked', async () => {
161
+ const user = setupUser();
162
+ const onSelect = vi.fn();
163
+ const task = createMockTaskEffect();
164
+ render(<StepCard {...defaultProps} task={task} onSelect={onSelect} />);
165
+ // The expand/collapse button has an aria-label
166
+ const expandBtn = screen.getByLabelText('Expand details');
167
+ await user.click(expandBtn);
168
+ expect(onSelect).not.toHaveBeenCalled();
169
+ });
170
+
171
+ // -----------------------------------------------------------------------
172
+ // Expanded details
173
+ // -----------------------------------------------------------------------
174
+
175
+ it('shows expand button with "Expand details" label when collapsed', () => {
176
+ const task = createMockTaskEffect();
177
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={false} />);
178
+ expect(screen.getByLabelText('Expand details')).toBeInTheDocument();
179
+ });
180
+
181
+ it('shows "Collapse details" label when defaultExpanded is true', () => {
182
+ const task = createMockTaskEffect();
183
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
184
+ expect(screen.getByLabelText('Collapse details')).toBeInTheDocument();
185
+ });
186
+
187
+ it('toggles expanded state when expand button is clicked', async () => {
188
+ const user = setupUser();
189
+ const task = createMockTaskEffect();
190
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={false} />);
191
+ // Initially collapsed
192
+ expect(screen.getByLabelText('Expand details')).toBeInTheDocument();
193
+ // Click to expand
194
+ await user.click(screen.getByLabelText('Expand details'));
195
+ expect(screen.getByLabelText('Collapse details')).toBeInTheDocument();
196
+ // Click to collapse
197
+ await user.click(screen.getByLabelText('Collapse details'));
198
+ expect(screen.getByLabelText('Expand details')).toBeInTheDocument();
199
+ });
200
+
201
+ it('shows step ID in expanded details', () => {
202
+ const task = createMockTaskEffect({ stepId: 'step-abc-123' });
203
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
204
+ expect(screen.getByText('Step:')).toBeInTheDocument();
205
+ });
206
+
207
+ it('shows duration in expanded details when present', () => {
208
+ const task = createMockTaskEffect({ duration: 12000 });
209
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
210
+ expect(screen.getByText('Duration:')).toBeInTheDocument();
211
+ // Duration appears in both the card body and expanded details
212
+ expect(screen.getAllByText('12s').length).toBeGreaterThanOrEqual(2);
213
+ });
214
+
215
+ it('shows requestedAt in expanded details', () => {
216
+ const task = createMockTaskEffect({
217
+ requestedAt: '2026-01-15T10:30:00.000Z',
218
+ });
219
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
220
+ expect(screen.getByText('Requested:')).toBeInTheDocument();
221
+ });
222
+
223
+ it('shows resolvedAt in expanded details when present', () => {
224
+ const task = createMockTaskEffect({
225
+ resolvedAt: '2026-01-15T10:30:05.000Z',
226
+ });
227
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
228
+ expect(screen.getByText('Resolved:')).toBeInTheDocument();
229
+ });
230
+
231
+ it('shows error details in expanded view when task has error', () => {
232
+ const task = createMockTaskEffect({
233
+ status: 'error',
234
+ error: { name: 'TimeoutError', message: 'Task timed out after 30s' },
235
+ });
236
+ render(<StepCard {...defaultProps} task={task} defaultExpanded={true} />);
237
+ expect(screen.getByText('TimeoutError:')).toBeInTheDocument();
238
+ expect(screen.getByText(/Task timed out after 30s/)).toBeInTheDocument();
239
+ });
240
+
241
+ // -----------------------------------------------------------------------
242
+ // Breakpoint waiting state
243
+ // -----------------------------------------------------------------------
244
+
245
+ it('shows breakpoint waiting indicator for breakpoint kind with requested status', () => {
246
+ const task = createMockTaskEffect({
247
+ kind: 'breakpoint',
248
+ status: 'requested',
249
+ });
250
+ render(<StepCard {...defaultProps} task={task} />);
251
+ expect(screen.getByText('Your approval is needed')).toBeInTheDocument();
252
+ });
253
+
254
+ it('shows Hand icon for breakpoint waiting state', () => {
255
+ const task = createMockTaskEffect({
256
+ kind: 'breakpoint',
257
+ status: 'requested',
258
+ });
259
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
260
+ const handIcons = container.querySelectorAll('[data-lucide="Hand"]');
261
+ expect(handIcons.length).toBeGreaterThan(0);
262
+ });
263
+
264
+ it('applies breakpoint glow animation class for breakpoint waiting state', () => {
265
+ const task = createMockTaskEffect({
266
+ kind: 'breakpoint',
267
+ status: 'requested',
268
+ });
269
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
270
+ const cardDiv = container.firstChild as HTMLElement;
271
+ expect(cardDiv.className).toContain('animate-breakpoint-glow');
272
+ });
273
+
274
+ it('does not show breakpoint indicators for resolved breakpoint', () => {
275
+ const task = createMockTaskEffect({
276
+ kind: 'breakpoint',
277
+ status: 'resolved',
278
+ });
279
+ render(<StepCard {...defaultProps} task={task} />);
280
+ expect(screen.queryByText('Your approval is needed')).not.toBeInTheDocument();
281
+ });
282
+
283
+ // -----------------------------------------------------------------------
284
+ // Selected state
285
+ // -----------------------------------------------------------------------
286
+
287
+ it('applies selected styling when isSelected is true', () => {
288
+ const task = createMockTaskEffect();
289
+ const { container } = render(
290
+ <StepCard {...defaultProps} task={task} isSelected={true} />,
291
+ );
292
+ const cardDiv = container.firstChild as HTMLElement;
293
+ expect(cardDiv.className).toContain('border-l-primary');
294
+ });
295
+
296
+ // -----------------------------------------------------------------------
297
+ // Status-based border colors
298
+ // -----------------------------------------------------------------------
299
+
300
+ it('applies success border for resolved task', () => {
301
+ const task = createMockTaskEffect({ status: 'resolved' });
302
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
303
+ const cardDiv = container.firstChild as HTMLElement;
304
+ expect(cardDiv.className).toContain('border-l-success');
305
+ });
306
+
307
+ it('applies error border for error task', () => {
308
+ const task = createMockTaskEffect({ status: 'error' });
309
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
310
+ const cardDiv = container.firstChild as HTMLElement;
311
+ expect(cardDiv.className).toContain('border-l-error');
312
+ });
313
+
314
+ it('applies info border for running task (non-breakpoint)', () => {
315
+ const task = createMockTaskEffect({ status: 'requested', kind: 'node' });
316
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
317
+ const cardDiv = container.firstChild as HTMLElement;
318
+ expect(cardDiv.className).toContain('border-l-info');
319
+ });
320
+
321
+ it('applies warning border for breakpoint waiting task', () => {
322
+ const task = createMockTaskEffect({
323
+ status: 'requested',
324
+ kind: 'breakpoint',
325
+ });
326
+ const { container } = render(<StepCard {...defaultProps} task={task} />);
327
+ const cardDiv = container.firstChild as HTMLElement;
328
+ expect(cardDiv.className).toContain('border-l-warning');
329
+ });
330
+ });