@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,246 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+
3
+ // Create hoisted mock functions
4
+ const { mockAccess, mockWriteFile, mockMkdir, mockReaddir, mockFindRunDir } = vi.hoisted(() => ({
5
+ mockAccess: vi.fn(),
6
+ mockWriteFile: vi.fn(),
7
+ mockMkdir: vi.fn(),
8
+ mockReaddir: vi.fn(),
9
+ mockFindRunDir: vi.fn(),
10
+ }));
11
+
12
+ // Mock path-resolver
13
+ vi.mock("@/lib/path-resolver", () => ({
14
+ findRunDir: mockFindRunDir,
15
+ }));
16
+
17
+ // Mock fs with a complete replacement that includes default export
18
+ vi.mock("fs", () => {
19
+ return {
20
+ default: {
21
+ promises: {
22
+ access: mockAccess,
23
+ writeFile: mockWriteFile,
24
+ mkdir: mockMkdir,
25
+ readdir: mockReaddir,
26
+ },
27
+ },
28
+ promises: {
29
+ access: mockAccess,
30
+ writeFile: mockWriteFile,
31
+ mkdir: mockMkdir,
32
+ readdir: mockReaddir,
33
+ },
34
+ };
35
+ });
36
+
37
+ import { approveBreakpoint } from "../approve-breakpoint";
38
+
39
+ const defaultSource = { path: "/projects", depth: 2, label: "test" };
40
+
41
+ describe("approveBreakpoint", () => {
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ // Default: journal dir has some existing entries
45
+ mockMkdir.mockResolvedValue(undefined);
46
+ mockReaddir.mockResolvedValue(["000001.01ABC.json", "000002.01DEF.json"]);
47
+ });
48
+
49
+ // -------------------------------------------------------------------------
50
+ // Input validation
51
+ // -------------------------------------------------------------------------
52
+
53
+ it("returns error when runId is empty", async () => {
54
+ const result = await approveBreakpoint("", "eff-001", "yes");
55
+ expect(result.success).toBe(false);
56
+ expect(result.error).toContain("Missing or invalid runId");
57
+ });
58
+
59
+ it("returns error when effectId is empty", async () => {
60
+ const result = await approveBreakpoint("run-001", "", "yes");
61
+ expect(result.success).toBe(false);
62
+ expect(result.error).toContain("Missing or invalid effectId");
63
+ });
64
+
65
+ it("returns error when answer is empty", async () => {
66
+ const result = await approveBreakpoint("run-001", "eff-001", "");
67
+ expect(result.success).toBe(false);
68
+ expect(result.error).toContain("Answer cannot be empty");
69
+ });
70
+
71
+ it("returns error when answer is only whitespace", async () => {
72
+ const result = await approveBreakpoint("run-001", "eff-001", " ");
73
+ expect(result.success).toBe(false);
74
+ expect(result.error).toContain("Answer cannot be empty");
75
+ });
76
+
77
+ it("returns error when runId contains path traversal characters", async () => {
78
+ const result = await approveBreakpoint("../etc", "eff-001", "yes");
79
+ expect(result.success).toBe(false);
80
+ expect(result.error).toContain("Invalid characters");
81
+ });
82
+
83
+ it("returns error when effectId contains path traversal characters", async () => {
84
+ const result = await approveBreakpoint("run-001", "../../etc", "yes");
85
+ expect(result.success).toBe(false);
86
+ expect(result.error).toContain("Invalid characters");
87
+ });
88
+
89
+ // -------------------------------------------------------------------------
90
+ // Run/task resolution
91
+ // -------------------------------------------------------------------------
92
+
93
+ it("returns error when run is not found", async () => {
94
+ mockFindRunDir.mockResolvedValue(null);
95
+
96
+ const result = await approveBreakpoint("run-999", "eff-001", "yes");
97
+ expect(result.success).toBe(false);
98
+ expect(result.error).toContain("Run not found");
99
+ });
100
+
101
+ it("returns error when task directory does not exist", async () => {
102
+ mockFindRunDir.mockResolvedValue({
103
+ runDir: "/projects/app/.a5c/runs/run-001",
104
+ source: defaultSource,
105
+ projectName: "app",
106
+ projectPath: "/projects/app",
107
+ });
108
+ mockAccess.mockRejectedValueOnce(new Error("ENOENT"));
109
+
110
+ const result = await approveBreakpoint("run-001", "eff-001", "yes");
111
+ expect(result.success).toBe(false);
112
+ expect(result.error).toContain("Task directory not found");
113
+ });
114
+
115
+ // -------------------------------------------------------------------------
116
+ // Success path
117
+ // -------------------------------------------------------------------------
118
+
119
+ it("writes result.json and journal entry on success", async () => {
120
+ const runDir = "/projects/app/.a5c/runs/run-001";
121
+ mockFindRunDir.mockResolvedValue({
122
+ runDir,
123
+ source: defaultSource,
124
+ projectName: "app",
125
+ projectPath: "/projects/app",
126
+ });
127
+ mockAccess.mockResolvedValue(undefined);
128
+ mockWriteFile.mockResolvedValue(undefined);
129
+
130
+ const result = await approveBreakpoint("run-001", "eff-001", "Deploy approved");
131
+ expect(result.success).toBe(true);
132
+
133
+ // Should write 2 files: result.json + journal entry
134
+ expect(mockWriteFile).toHaveBeenCalledTimes(2);
135
+
136
+ // First write: result.json
137
+ const [resultPath, resultContent] = mockWriteFile.mock.calls[0];
138
+ expect(resultPath).toContain("eff-001");
139
+ expect(resultPath).toContain("result.json");
140
+
141
+ const parsed = JSON.parse(resultContent as string);
142
+ expect(parsed.status).toBe("ok");
143
+ expect(parsed.value.answer).toBe("Deploy approved");
144
+ expect(parsed.value.approvedBy).toBe("observer-dashboard");
145
+ expect(parsed.value.approvedAt).toBeDefined();
146
+ expect(parsed.startedAt).toBeDefined();
147
+ expect(parsed.finishedAt).toBeDefined();
148
+
149
+ // Second write: journal entry
150
+ const [journalPath, journalContent] = mockWriteFile.mock.calls[1];
151
+ expect(journalPath).toContain("journal");
152
+ expect(journalPath).toMatch(/000003\./); // next seq after 000001, 000002
153
+
154
+ const journalParsed = JSON.parse(journalContent as string);
155
+ expect(journalParsed.type).toBe("EFFECT_RESOLVED");
156
+ expect(journalParsed.data.effectId).toBe("eff-001");
157
+ expect(journalParsed.data.status).toBe("ok");
158
+ expect(journalParsed.data.resultRef).toBe("tasks/eff-001/result.json");
159
+ expect(journalParsed.checksum).toBeDefined();
160
+ expect(typeof journalParsed.checksum).toBe("string");
161
+ expect(journalParsed.checksum.length).toBe(64); // SHA-256 hex
162
+ });
163
+
164
+ it("journal checksum is valid SHA-256 of payload without checksum", async () => {
165
+ const runDir = "/projects/app/.a5c/runs/run-001";
166
+ mockFindRunDir.mockResolvedValue({
167
+ runDir,
168
+ source: defaultSource,
169
+ projectName: "app",
170
+ projectPath: "/projects/app",
171
+ });
172
+ mockAccess.mockResolvedValue(undefined);
173
+ mockWriteFile.mockResolvedValue(undefined);
174
+
175
+ await approveBreakpoint("run-001", "eff-001", "yes");
176
+
177
+ const [, journalContent] = mockWriteFile.mock.calls[1];
178
+ const journalParsed = JSON.parse(journalContent as string);
179
+
180
+ // Recompute checksum: SHA-256 of JSON.stringify(payloadWithoutChecksum, null, 2) + "\n"
181
+ const { checksum: _checksum, ...payloadWithoutChecksum } = journalParsed;
182
+ const crypto = await import("crypto");
183
+ const expected = crypto.default
184
+ .createHash("sha256")
185
+ .update(JSON.stringify(payloadWithoutChecksum, null, 2) + "\n")
186
+ .digest("hex");
187
+ expect(journalParsed.checksum).toBe(expected);
188
+ });
189
+
190
+ it("uses seq 1 when journal dir is empty", async () => {
191
+ const runDir = "/projects/app/.a5c/runs/run-001";
192
+ mockFindRunDir.mockResolvedValue({
193
+ runDir,
194
+ source: defaultSource,
195
+ projectName: "app",
196
+ projectPath: "/projects/app",
197
+ });
198
+ mockAccess.mockResolvedValue(undefined);
199
+ mockWriteFile.mockResolvedValue(undefined);
200
+ mockReaddir.mockResolvedValue([]); // empty journal
201
+
202
+ await approveBreakpoint("run-001", "eff-001", "yes");
203
+
204
+ const [journalPath] = mockWriteFile.mock.calls[1];
205
+ expect(journalPath).toMatch(/000001\./);
206
+ });
207
+
208
+ it("trims whitespace from the answer", async () => {
209
+ const runDir = "/projects/app/.a5c/runs/run-001";
210
+ mockFindRunDir.mockResolvedValue({
211
+ runDir,
212
+ source: defaultSource,
213
+ projectName: "app",
214
+ projectPath: "/projects/app",
215
+ });
216
+ mockAccess.mockResolvedValue(undefined);
217
+ mockWriteFile.mockResolvedValue(undefined);
218
+
219
+ const result = await approveBreakpoint("run-001", "eff-001", " yes ");
220
+ expect(result.success).toBe(true);
221
+
222
+ const [, content] = mockWriteFile.mock.calls[0];
223
+ const parsed = JSON.parse(content as string);
224
+ expect(parsed.value.answer).toBe("yes");
225
+ });
226
+
227
+ // -------------------------------------------------------------------------
228
+ // Write failure
229
+ // -------------------------------------------------------------------------
230
+
231
+ it("returns error when file write fails", async () => {
232
+ const runDir = "/projects/app/.a5c/runs/run-001";
233
+ mockFindRunDir.mockResolvedValue({
234
+ runDir,
235
+ source: defaultSource,
236
+ projectName: "app",
237
+ projectPath: "/projects/app",
238
+ });
239
+ mockAccess.mockResolvedValue(undefined);
240
+ mockWriteFile.mockRejectedValue(new Error("EACCES: permission denied"));
241
+
242
+ const result = await approveBreakpoint("run-001", "eff-001", "yes");
243
+ expect(result.success).toBe(false);
244
+ expect(result.error).toContain("EACCES");
245
+ });
246
+ });
@@ -0,0 +1,145 @@
1
+ "use server";
2
+
3
+ import { promises as fs } from "fs";
4
+ import path from "path";
5
+ import crypto from "crypto";
6
+ import { monotonicFactory } from "ulid";
7
+ import { findRunDir } from "@/lib/path-resolver";
8
+
9
+ export interface ApproveBreakpointResult {
10
+ success: boolean;
11
+ error?: string;
12
+ }
13
+
14
+ const nextUlid = monotonicFactory();
15
+
16
+ /**
17
+ * Determine the next journal sequence number by scanning existing files.
18
+ */
19
+ async function getNextJournalSeq(journalDir: string): Promise<number> {
20
+ try {
21
+ const files = await fs.readdir(journalDir);
22
+ let max = 0;
23
+ for (const f of files) {
24
+ const seqStr = f.split(".")[0];
25
+ const seq = Number(seqStr);
26
+ if (Number.isFinite(seq) && seq > max) max = seq;
27
+ }
28
+ return max + 1;
29
+ } catch {
30
+ // Journal dir may not exist yet — seq 1
31
+ return 1;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Write an EFFECT_RESOLVED journal entry using the same format as the
37
+ * babysitter SDK: SHA-256 checksum of the JSON payload (without checksum)
38
+ * serialized as `JSON.stringify(payload, null, 2) + "\n"`.
39
+ */
40
+ async function appendJournalEntry(
41
+ runDir: string,
42
+ effectId: string,
43
+ now: string,
44
+ ): Promise<void> {
45
+ const journalDir = path.join(runDir, "journal");
46
+ await fs.mkdir(journalDir, { recursive: true });
47
+
48
+ const seq = await getNextJournalSeq(journalDir);
49
+ const ulid = nextUlid();
50
+ const filename = `${seq.toString().padStart(6, "0")}.${ulid}.json`;
51
+
52
+ const eventPayload = {
53
+ type: "EFFECT_RESOLVED",
54
+ recordedAt: now,
55
+ data: {
56
+ effectId,
57
+ status: "ok",
58
+ resultRef: `tasks/${effectId}/result.json`,
59
+ startedAt: now,
60
+ finishedAt: now,
61
+ },
62
+ };
63
+
64
+ const contents = JSON.stringify(eventPayload, null, 2) + "\n";
65
+ const checksum = crypto.createHash("sha256").update(contents).digest("hex");
66
+ const payloadWithChecksum = JSON.stringify({ ...eventPayload, checksum }, null, 2) + "\n";
67
+
68
+ await fs.writeFile(path.join(journalDir, filename), payloadWithChecksum, "utf-8");
69
+ }
70
+
71
+ /**
72
+ * Server Action: approve a breakpoint by writing both the result.json AND
73
+ * an EFFECT_RESOLVED journal entry. This ensures the SDK's state machine
74
+ * recognizes the resolution on the next `run:iterate` (the SDK auto-rebuilds
75
+ * its state cache when it detects journal head mismatch).
76
+ *
77
+ * Previous implementation only wrote result.json, leaving the journal
78
+ * untouched — the SDK never knew the breakpoint was resolved, causing runs
79
+ * to stay stuck in "Waiting" state permanently.
80
+ */
81
+ export async function approveBreakpoint(
82
+ runId: string,
83
+ effectId: string,
84
+ answer: string,
85
+ ): Promise<ApproveBreakpointResult> {
86
+ // --- Validate inputs ---
87
+ if (!runId || typeof runId !== "string") {
88
+ return { success: false, error: "Missing or invalid runId" };
89
+ }
90
+ if (!effectId || typeof effectId !== "string") {
91
+ return { success: false, error: "Missing or invalid effectId" };
92
+ }
93
+ if (!answer || typeof answer !== "string" || answer.trim().length === 0) {
94
+ return { success: false, error: "Answer cannot be empty" };
95
+ }
96
+
97
+ // Sanitize IDs to prevent path traversal
98
+ const idPattern = /^[a-zA-Z0-9_\-]+$/;
99
+ if (!idPattern.test(runId) || !idPattern.test(effectId)) {
100
+ return { success: false, error: "Invalid characters in runId or effectId" };
101
+ }
102
+
103
+ try {
104
+ // --- Resolve the run directory ---
105
+ const found = await findRunDir(runId);
106
+ if (!found) {
107
+ return { success: false, error: `Run not found: ${runId}` };
108
+ }
109
+ const runDir = found.runDir;
110
+
111
+ // --- Verify the task directory exists ---
112
+ const taskDir = path.join(runDir, "tasks", effectId);
113
+ try {
114
+ await fs.access(taskDir);
115
+ } catch {
116
+ return { success: false, error: `Task directory not found: ${effectId}` };
117
+ }
118
+
119
+ // --- Write result.json (SDK-compatible format) ---
120
+ const now = new Date().toISOString();
121
+ const resultPayload = {
122
+ status: "ok",
123
+ value: {
124
+ answer: answer.trim(),
125
+ approvedAt: now,
126
+ approvedBy: "observer-dashboard",
127
+ },
128
+ startedAt: now,
129
+ finishedAt: now,
130
+ };
131
+ const resultPath = path.join(taskDir, "result.json");
132
+ await fs.writeFile(resultPath, JSON.stringify(resultPayload, null, 2), "utf-8");
133
+
134
+ // --- Append EFFECT_RESOLVED journal entry ---
135
+ // This is the critical piece that was missing: without a journal entry,
136
+ // the SDK's state machine never knows the breakpoint was resolved and
137
+ // the run stays stuck in "Waiting" forever.
138
+ await appendJournalEntry(runDir, effectId, now);
139
+
140
+ return { success: true };
141
+ } catch (err: unknown) {
142
+ const msg = err instanceof Error ? err.message : String(err);
143
+ return { success: false, error: msg };
144
+ }
145
+ }
@@ -0,0 +1,137 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getConfig, invalidateConfigCache, writeConfig } from "@/lib/config-loader";
3
+ import { invalidateAll, discoverAndCacheAll } from "@/lib/run-cache";
4
+ import { normalizeError } from "@/lib/error-handler";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ export async function GET() {
9
+ try {
10
+ const config = await getConfig();
11
+ return NextResponse.json(config);
12
+ } catch (err) {
13
+ const normalized = normalizeError(err);
14
+ return NextResponse.json(
15
+ { error: normalized.message, code: normalized.code },
16
+ { status: normalized.status }
17
+ );
18
+ }
19
+ }
20
+
21
+ export async function POST(request: Request) {
22
+ try {
23
+ const body = await request.json();
24
+
25
+ // Validate sources
26
+ if (!Array.isArray(body.sources)) {
27
+ return NextResponse.json(
28
+ { error: "sources must be an array" },
29
+ { status: 400 }
30
+ );
31
+ }
32
+
33
+ for (let i = 0; i < body.sources.length; i++) {
34
+ const s = body.sources[i];
35
+ if (!s || typeof s.path !== "string" || !s.path.trim()) {
36
+ return NextResponse.json(
37
+ { error: `sources[${i}].path must be a non-empty string` },
38
+ { status: 400 }
39
+ );
40
+ }
41
+ if (typeof s.depth !== "number" || s.depth < 0 || s.depth > 10) {
42
+ return NextResponse.json(
43
+ { error: `sources[${i}].depth must be a number between 0 and 10` },
44
+ { status: 400 }
45
+ );
46
+ }
47
+ }
48
+
49
+ // Validate pollInterval
50
+ if (body.pollInterval !== undefined) {
51
+ if (typeof body.pollInterval !== "number" || body.pollInterval < 500) {
52
+ return NextResponse.json(
53
+ { error: "pollInterval must be a number >= 500" },
54
+ { status: 400 }
55
+ );
56
+ }
57
+ }
58
+
59
+ // Validate theme
60
+ if (body.theme !== undefined) {
61
+ if (body.theme !== "dark" && body.theme !== "light") {
62
+ return NextResponse.json(
63
+ { error: "theme must be 'dark' or 'light'" },
64
+ { status: 400 }
65
+ );
66
+ }
67
+ }
68
+
69
+ // Validate staleThresholdMs
70
+ if (body.staleThresholdMs !== undefined) {
71
+ if (typeof body.staleThresholdMs !== "number" || body.staleThresholdMs < 0) {
72
+ return NextResponse.json(
73
+ { error: "staleThresholdMs must be a non-negative number" },
74
+ { status: 400 }
75
+ );
76
+ }
77
+ }
78
+
79
+ // Validate retentionDays
80
+ if (body.retentionDays !== undefined) {
81
+ if (typeof body.retentionDays !== "number" || body.retentionDays < 1 || body.retentionDays > 365) {
82
+ return NextResponse.json(
83
+ { error: "retentionDays must be a number between 1 and 365" },
84
+ { status: 400 }
85
+ );
86
+ }
87
+ }
88
+
89
+ // Validate hiddenProjects
90
+ if (body.hiddenProjects !== undefined) {
91
+ if (!Array.isArray(body.hiddenProjects) || body.hiddenProjects.some((p: unknown) => typeof p !== "string")) {
92
+ return NextResponse.json(
93
+ { error: "hiddenProjects must be an array of strings" },
94
+ { status: 400 }
95
+ );
96
+ }
97
+ }
98
+
99
+ // Build config to save
100
+ const configToSave = {
101
+ sources: body.sources.map((s: { path: string; depth: number; label?: string }) => ({
102
+ path: s.path.trim(),
103
+ depth: s.depth,
104
+ ...(s.label ? { label: s.label.trim() } : {}),
105
+ })),
106
+ ...(body.pollInterval !== undefined ? { pollInterval: body.pollInterval } : {}),
107
+ ...(body.theme !== undefined ? { theme: body.theme } : {}),
108
+ ...(body.staleThresholdMs !== undefined ? { staleThresholdMs: body.staleThresholdMs } : {}),
109
+ ...(body.retentionDays !== undefined ? { retentionDays: body.retentionDays } : {}),
110
+ ...(body.hiddenProjects !== undefined ? { hiddenProjects: body.hiddenProjects } : {}),
111
+ };
112
+
113
+ // Write to disk
114
+ await writeConfig(configToSave);
115
+
116
+ // Invalidate caches so next request reads fresh
117
+ invalidateConfigCache();
118
+ invalidateAll(); // Clear run cache so re-discovery uses new sources
119
+
120
+ // Read back the full merged config
121
+ const savedConfig = await getConfig();
122
+
123
+ // Re-discover all runs with new sources (fire and forget)
124
+ discoverAndCacheAll().catch((err) =>
125
+ console.error("Failed to re-discover runs after config change:", err)
126
+ );
127
+
128
+ return NextResponse.json(savedConfig);
129
+ } catch (err) {
130
+ console.error("Failed to save config:", err);
131
+ const normalized = normalizeError(err);
132
+ return NextResponse.json(
133
+ { error: normalized.message, code: normalized.code },
134
+ { status: normalized.status }
135
+ );
136
+ }
137
+ }
@@ -0,0 +1,45 @@
1
+ import { NextResponse } from "next/server";
2
+ import { ensureInitialized } from "@/lib/server-init";
3
+ import { getAllCachedDigests, discoverAndCacheAll } from "@/lib/run-cache";
4
+ import { normalizeError } from "@/lib/error-handler";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ export async function GET() {
9
+ try {
10
+ try {
11
+ await ensureInitialized();
12
+ } catch (initError) {
13
+ console.error("Server initialization failed:", initError);
14
+ return NextResponse.json(
15
+ { error: "Server initialization failed. Check observer configuration and watch sources.", code: "INIT_FAILED" },
16
+ { status: 500 }
17
+ );
18
+ }
19
+
20
+ // Ensure cache is populated — discoverAndCacheAll() is debounced internally
21
+ // (10s) so repeated calls are cheap. This guarantees runs invalidated by the
22
+ // watcher are re-populated before we read the cache.
23
+ await discoverAndCacheAll();
24
+ const runs = getAllCachedDigests();
25
+
26
+ // Sort by updatedAt descending (most recent first), with runId tiebreaker
27
+ // to ensure stable ordering when multiple runs share the same timestamp.
28
+ runs.sort((a, b) => {
29
+ const cmp = (b.updatedAt || "").localeCompare(a.updatedAt || "");
30
+ if (cmp !== 0) return cmp;
31
+ return a.runId.localeCompare(b.runId);
32
+ });
33
+
34
+ return NextResponse.json({ runs }, {
35
+ headers: { "Cache-Control": "no-cache, no-store" },
36
+ });
37
+ } catch (error) {
38
+ console.error("Failed to read digest:", error);
39
+ const normalized = normalizeError(error);
40
+ return NextResponse.json(
41
+ { error: normalized.message, code: normalized.code },
42
+ { status: normalized.status }
43
+ );
44
+ }
45
+ }
@@ -0,0 +1,56 @@
1
+ import { NextResponse } from "next/server";
2
+ import path from "path";
3
+ import { findRunDir } from "@/lib/path-resolver";
4
+ import { parseJournalDir } from "@/lib/parser";
5
+ import { normalizeError } from "@/lib/error-handler";
6
+
7
+ export const dynamic = "force-dynamic";
8
+
9
+ function isValidId(id: string): boolean {
10
+ return /^[a-zA-Z0-9_\-]+$/.test(id);
11
+ }
12
+
13
+ export async function GET(
14
+ request: Request,
15
+ { params }: { params: { runId: string } }
16
+ ) {
17
+ try {
18
+ const { runId } = params;
19
+ if (!isValidId(runId)) {
20
+ return NextResponse.json({ error: "Invalid run ID" }, { status: 400 });
21
+ }
22
+
23
+ const found = await findRunDir(runId);
24
+ if (!found) {
25
+ return NextResponse.json({ error: "Run not found" }, { status: 404 });
26
+ }
27
+
28
+ const journalPath = path.join(found.runDir, "journal");
29
+
30
+ const url = new URL(request.url);
31
+ const limit = parseInt(url.searchParams.get("limit") || "50", 10);
32
+ const offset = parseInt(url.searchParams.get("offset") || "0", 10);
33
+
34
+ if (isNaN(limit) || isNaN(offset) || limit < 0 || offset < 0) {
35
+ return NextResponse.json(
36
+ { error: "Invalid pagination parameters", code: "INVALID_INPUT" },
37
+ { status: 400 }
38
+ );
39
+ }
40
+
41
+ const allEvents = await parseJournalDir(journalPath);
42
+ const total = allEvents.length;
43
+ const events = allEvents.slice(offset, offset + limit);
44
+
45
+ return NextResponse.json({ events, total }, {
46
+ headers: { "Cache-Control": "no-cache, no-store" },
47
+ });
48
+ } catch (error) {
49
+ console.error("Failed to read events:", error);
50
+ const normalized = normalizeError(error);
51
+ return NextResponse.json(
52
+ { error: normalized.message, code: normalized.code },
53
+ { status: normalized.status }
54
+ );
55
+ }
56
+ }