thursday-agent 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +5 -5
  5. package/.next/routes-manifest.json +24 -6
  6. package/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +2 -2
  11. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page.js +2 -2
  15. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/api/artifact/route.js +3 -3
  23. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
  25. package/.next/server/app/api/bot/memory/files/route.js +10 -0
  26. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
  27. package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
  28. package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/memory/route.js +14 -0
  30. package/.next/server/app/api/bot/{notes → memory}/route.js.nft.json +1 -1
  31. package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/route.js +6 -6
  33. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  34. package/.next/server/app/api/bot/task/[id]/route.js +8 -8
  35. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
  36. package/.next/server/app/api/bot/task/route.js +8 -8
  37. package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
  38. package/.next/server/app/api/config/route.js +5 -5
  39. package/.next/server/app/api/config/route.js.nft.json +1 -1
  40. package/.next/server/app/api/events/route.js +4 -5
  41. package/.next/server/app/api/events/route.js.nft.json +1 -1
  42. package/.next/server/app/api/file/[...path]/route.js +3 -3
  43. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/catalog/route.js +9 -8
  45. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
  47. package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
  48. package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
  49. package/.next/server/app/api/llm-model/credits/route.js +16 -0
  50. package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
  51. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
  52. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
  53. package/.next/server/app/api/llm-model/route.js +10 -8
  54. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  55. package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
  56. package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
  57. package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
  58. package/.next/server/app/api/llm-model/subscription/route.js +15 -0
  59. package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
  60. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
  61. package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
  62. package/.next/server/app/api/mcp/[name]/route.js +4 -4
  63. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
  65. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  66. package/.next/server/app/api/mcp/route.js +4 -4
  67. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  68. package/.next/server/app/api/mcp/tools/route.js +4 -4
  69. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  70. package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
  71. package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
  72. package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
  73. package/.next/server/app/api/memory/edit/route.js +24 -0
  74. package/.next/server/app/api/memory/edit/route.js.map +5 -0
  75. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
  76. package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/memory/route.js +6 -7
  78. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  79. package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
  80. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  81. package/.next/server/app/api/skills/route.js +3 -3
  82. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  83. package/.next/server/app/api/thursday/call/route.js +9 -7
  84. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  85. package/.next/server/app/api/thursday/skills/route.js +9 -7
  86. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  87. package/.next/server/app/api/thursday/tool-call/route.js +17 -15
  88. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  89. package/.next/server/app/api/workspace/route.js +4 -5
  90. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  91. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  92. package/.next/server/app/artifact/[...path]/page.js +5 -6
  93. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  94. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  95. package/.next/server/app/favicon.ico/route.js +3 -4
  96. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  97. package/.next/server/app/favicon.ico.body +0 -0
  98. package/.next/server/app/page/server-reference-manifest.json +57 -90
  99. package/.next/server/app/page.js +10 -10
  100. package/.next/server/app/page.js.nft.json +1 -1
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app-paths-manifest.json +5 -2
  103. package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
  104. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +1 -1
  106. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
  107. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
  108. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
  109. package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
  110. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
  111. package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
  112. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
  113. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
  114. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
  115. package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
  116. package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
  117. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
  118. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
  119. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
  120. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
  121. package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
  122. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
  123. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
  124. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
  125. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +5 -5
  126. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
  127. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
  128. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
  129. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
  131. package/.next/server/chunks/_0-73of8._.js +5 -5
  132. package/.next/server/chunks/_0-fjql4._.js +26 -0
  133. package/.next/server/chunks/_00xh_q0._.js +27 -0
  134. package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +163 -36
  135. package/.next/server/chunks/_051qh8u._.js +3 -0
  136. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  137. package/.next/server/chunks/_05h2cii._.js +1 -1
  138. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  139. package/.next/server/chunks/_0fzqt2y._.js +130 -0
  140. package/.next/server/chunks/{_0vnutv9._.js → _0ioz3nd._.js} +1 -1
  141. package/.next/server/chunks/_0iwfby5._.js +3 -0
  142. package/.next/server/chunks/_0mecv0f._.js +26 -0
  143. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  144. package/.next/server/chunks/_0n74zsf._.js +4 -4
  145. package/.next/server/chunks/_0obojvv._.js +3 -0
  146. package/.next/server/chunks/_0recufk._.js +49 -0
  147. package/.next/server/chunks/_0rnf-6n._.js +4 -4
  148. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  149. package/.next/server/chunks/_0u10wmw._.js +5 -5
  150. package/.next/server/chunks/_0u4aiy2._.js +3 -0
  151. package/.next/server/chunks/_0wp4le3._.js +1 -1
  152. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  153. package/.next/server/chunks/_1230wbx._.js +10 -0
  154. package/.next/server/chunks/_12nheja._.js +3 -0
  155. package/.next/server/chunks/_13510xh._.js +3 -0
  156. package/.next/server/chunks/_15hq89o._.js +1 -1
  157. package/.next/server/chunks/_17l5ygt._.js +49 -0
  158. package/.next/server/chunks/_18-1wcc._.js +5 -5
  159. package/.next/server/chunks/_1_5mnq4._.js +4 -4
  160. package/.next/server/chunks/_1_9mjx-._.js +3 -0
  161. package/.next/server/chunks/_1d0j961._.js +6 -0
  162. package/.next/server/chunks/_1d5zmy8._.js +1 -1
  163. package/.next/server/chunks/_1drgfx4._.js +4 -4
  164. package/.next/server/chunks/_1f46eie._.js +3 -0
  165. package/.next/server/chunks/_1h5_8sk._.js +3 -0
  166. package/.next/server/chunks/_1hdnxb7._.js +3 -0
  167. package/.next/server/chunks/_1j8k_j5._.js +3 -0
  168. package/.next/server/chunks/_1krd9rf._.js +3 -0
  169. package/.next/server/chunks/_1nc0eui._.js +11 -0
  170. package/.next/server/chunks/_1nula3v._.js +3 -0
  171. package/.next/server/chunks/_1pf4qe-._.js +3 -0
  172. package/.next/server/chunks/_1php4eq._.js +1 -1
  173. package/.next/server/chunks/_1qxheoa._.js +3 -0
  174. package/.next/server/chunks/_1x6kd1r._.js +3 -0
  175. package/.next/server/chunks/_1yuv4vp._.js +1 -1
  176. package/.next/server/chunks/_1zjrdag._.js +3 -0
  177. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
  178. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
  179. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
  180. package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
  181. package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
  182. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  183. package/.next/server/chunks/features_0rpfxbk._.js +3 -0
  184. package/.next/server/chunks/features_1qf3cei._.js +3 -0
  185. package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
  186. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +3 -0
  187. package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
  188. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0a1rd09._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
  189. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_06067w6._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
  190. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_096ais_._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
  191. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_02s3hjt._.js → node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js} +1 -1
  192. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
  193. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tvkfgh._.js → node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js} +1 -1
  194. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  195. package/.next/server/chunks/ssr/{[root-of-the-server]__1qfqvmg._.js → [root-of-the-server]__0_69wqr._.js} +2 -2
  196. package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
  198. package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  201. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
  205. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  207. package/.next/server/chunks/ssr/{[root-of-the-server]__0m1b5ky._.js → [root-of-the-server]__1cyjywu._.js} +1 -1
  208. package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
  209. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  211. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
  212. package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
  213. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  214. package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
  215. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  216. package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
  217. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  218. package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
  219. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  220. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  221. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  222. package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
  223. package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
  224. package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
  225. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  226. package/.next/server/chunks/ssr/{_040sk32._.js → _0u2jv_x._.js} +76 -82
  227. package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
  228. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  229. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  230. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  231. package/.next/server/chunks/ssr/{_1lip4th._.js → _13z3f85._.js} +2 -2
  232. package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
  233. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  234. package/.next/server/chunks/ssr/{_09ja_w1._.js → _1eoqg_g._.js} +2 -2
  235. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  236. package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
  237. package/.next/server/chunks/ssr/{_0x_nu5e._.js → _1vi_uo7._.js} +2 -2
  238. package/.next/server/chunks/ssr/_1vyd1ji._.js +1 -1
  239. package/.next/server/chunks/ssr/{_1m3bsfr._.js → _1xvgn77._.js} +2 -2
  240. package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
  241. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  242. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  243. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  244. package/.next/server/chunks/ssr/lib_date-like_ts_02is0pw._.js +3 -0
  245. package/.next/server/chunks/ssr/{node_modules_18_dk7_._.js → node_modules_063xwpp._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_01qnv-a._.js → node_modules_0bvraul._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_0n1kj4p._.js → node_modules_0eu1va6._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0kl7-tn._.js → node_modules_0h50b8n._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0_n241r._.js → node_modules_0h5hnr1._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_0lrjk5t._.js → node_modules_0h7u60n._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0ndvxub._.js → node_modules_0lm7_vm._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_13r44jq._.js → node_modules_0mwym0g._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_17lrt3y._.js → node_modules_0rjg6t1._.js} +1 -1
  254. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  255. package/.next/server/chunks/ssr/{node_modules_004qlr4._.js → node_modules_0y_cded._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_0kxz4gt._.js → node_modules_0z5tsu8._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_0iz1rzd._.js → node_modules_0zp9r92._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_19dp7ko._.js → node_modules_1-hc6uv._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_1q0p85z._.js → node_modules_113tz0l._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1toafc-._.js → node_modules_124bue5._.js} +1 -1
  261. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  262. package/.next/server/chunks/ssr/{node_modules_08d8bke._.js → node_modules_1_n3ztw._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1dwguw_._.js → node_modules_1bc7gu8._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_20yebtj._.js → node_modules_1bgb6-f._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1n5ygqe._.js → node_modules_1h4a4pp._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_04n7mjs._.js → node_modules_1i7u1ia._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_1hn8z1f._.js → node_modules_1juq3hs._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_1xyd7ov._.js → node_modules_1l0qtdu._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_0m93zeg._.js → node_modules_1t9cyee._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_09xhur7._.js → node_modules_1uuj9x1._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_1hd-5tv._.js → node_modules_1vqb6po._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_1zu988w._.js → node_modules_1xx28h1._.js} +1 -1
  273. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0m9a4y0._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
  274. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_13w_wy9._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
  275. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
  276. package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  277. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
  278. package/.next/server/instrumentation.js +1 -1
  279. package/.next/server/middleware-build-manifest.js +3 -3
  280. package/.next/server/pages/404.html +1 -1
  281. package/.next/server/pages/500.html +1 -1
  282. package/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/server/server-reference-manifest.json +58 -91
  284. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  285. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  286. package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
  287. package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
  288. package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
  289. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  290. package/.next/static/chunks/14hgtsjg-kael.css +1 -0
  291. package/.next/static/chunks/17donp69y4do7.js +40 -0
  292. package/.next/static/chunks/{3_h9txt3tq8t8.js → 1dkjg87pxk0n9.js} +1 -1
  293. package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
  294. package/.next/static/chunks/{3ard_noqapnw1.js → 1grhjo7a5a0_-.js} +1 -1
  295. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  296. package/.next/static/chunks/1okqiww3pnwka.js +1 -0
  297. package/.next/static/chunks/26-pr2c9ro222.js +1 -0
  298. package/.next/static/chunks/{18vhba44l1fc9.js → 280t0_e99i276.js} +1 -1
  299. package/.next/static/chunks/28cizcdaabd4h.js +1 -0
  300. package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
  301. package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
  302. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  303. package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
  304. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  305. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  306. package/.next/static/chunks/3111pj5wnjgos.js +1 -0
  307. package/.next/static/chunks/{07kl352c-lvcz.js → 3agpgkwaa321p.js} +1 -1
  308. package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
  309. package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
  310. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  311. package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
  312. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  313. package/README.md +6 -4
  314. package/app/api/bot/memory/files/route.ts +14 -0
  315. package/app/api/bot/memory/route.ts +5 -0
  316. package/app/api/events/app-event.ts +3 -5
  317. package/app/api/llm-model/credits/route.ts +11 -0
  318. package/app/api/llm-model/route.ts +6 -1
  319. package/app/api/llm-model/subscription/route.ts +11 -0
  320. package/app/api/memory/edit/route.ts +7 -0
  321. package/app/api/memory/route.ts +21 -0
  322. package/app/api/query-key.ts +19 -4
  323. package/bin/thursday.mjs +3 -0
  324. package/components/ui/shiny-text.tsx +48 -134
  325. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/migration.sql +24 -34
  326. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/snapshot.json +71 -145
  327. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  328. package/database/migrations/{20260909063821_bitter_tenebrous → 20260911030320_opposite_jack_power}/snapshot.json +57 -184
  329. package/features/ai/chatgpt.ts +617 -0
  330. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  331. package/features/ai/components/model-picker.tsx +17 -1
  332. package/features/ai/components/provider-icon.tsx +1 -0
  333. package/features/ai/load-tools.ts +58 -42
  334. package/features/ai/model.schema.ts +232 -34
  335. package/features/ai/model.ts +169 -24
  336. package/features/ai/prompts/bot.prompt.ts +156 -65
  337. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  338. package/features/ai/prompts/prompt-helper.ts +45 -26
  339. package/features/ai/prompts/thursday.prompt.ts +40 -17
  340. package/features/ai/tools/bot.tool.ts +35 -52
  341. package/features/ai/tools/connected.ts +17 -4
  342. package/features/ai/tools/memory.tool.ts +133 -72
  343. package/features/ai/tools/search.tool.ts +136 -47
  344. package/features/ai/tools/tool-name.ts +2 -5
  345. package/features/ai/tools/workspace.tool.ts +2 -1
  346. package/features/bot/bot.action.ts +8 -18
  347. package/features/bot/bot.memory.ts +89 -0
  348. package/features/bot/bot.query.ts +37 -57
  349. package/features/bot/bot.run.ts +507 -241
  350. package/features/bot/bot.runner.ts +410 -114
  351. package/features/bot/bot.schema.ts +79 -19
  352. package/features/bot/bot.seed.ts +89 -16
  353. package/features/bot/components/bot-mark.tsx +122 -20
  354. package/features/bot/components/bot-room.tsx +159 -130
  355. package/features/bot/components/bot-setting.tsx +790 -402
  356. package/features/bot/components/bot-tool.tsx +2 -6
  357. package/features/bot/components/mark-palette.tsx +54 -0
  358. package/features/bot/components/path-chips.tsx +1 -1
  359. package/features/bot/components/task-badge.tsx +26 -6
  360. package/features/bot/components/task-reply.tsx +22 -33
  361. package/features/bot/components/task-setting.tsx +20 -17
  362. package/features/bot/task.query.ts +215 -28
  363. package/features/bot/task.store.ts +53 -9
  364. package/features/config/components/config-setting.tsx +265 -34
  365. package/features/config/components/models-badge.tsx +42 -0
  366. package/features/config/config.action.ts +12 -0
  367. package/features/config/config.const.ts +38 -2
  368. package/features/connectors/mcp.manager.ts +10 -2
  369. package/features/intro/components/intro.tsx +47 -46
  370. package/features/memory/components/memory-edit.tsx +338 -0
  371. package/features/memory/components/memory-setting.tsx +75 -77
  372. package/features/memory/memory.action.ts +3 -43
  373. package/features/memory/memory.edit.ts +87 -0
  374. package/features/memory/memory.query.ts +24 -42
  375. package/features/memory/memory.schema.ts +29 -106
  376. package/features/settings/components/settings.tsx +2 -0
  377. package/features/settings/settings.alert.ts +3 -1
  378. package/features/thursday/components/ascii-orb.tsx +106 -90
  379. package/features/thursday/components/boot.tsx +7 -0
  380. package/features/thursday/components/call-log.tsx +219 -92
  381. package/features/thursday/components/face.tsx +6 -4
  382. package/features/thursday/components/tab-state.tsx +97 -0
  383. package/features/thursday/components/thursday-mark.tsx +4 -1
  384. package/features/thursday/components/thursday-setting.tsx +17 -47
  385. package/features/thursday/components/thursday.tsx +208 -95
  386. package/features/thursday/thursday.action.ts +12 -17
  387. package/features/thursday/thursday.query.ts +61 -70
  388. package/features/thursday/thursday.schema.ts +20 -7
  389. package/features/thursday/tool-line.ts +85 -11
  390. package/features/thursday/use-thursday.ts +86 -59
  391. package/features/workspace/components/file-view.tsx +4 -2
  392. package/features/workspace/workspace.ts +110 -26
  393. package/lib/limits.ts +1 -1
  394. package/lib/oauth-page.ts +27 -0
  395. package/lib/realtime/openai.ts +2 -2
  396. package/lib/realtime/realtime.protocol.ts +1 -1
  397. package/lib/realtime/realtime.tap.ts +122 -0
  398. package/lib/sandbox.ts +59 -36
  399. package/package.json +1 -1
  400. package/skills/browser/SKILL.md +55 -34
  401. package/.next/server/app/api/bot/notes/route/app-paths-manifest.json +0 -3
  402. package/.next/server/app/api/bot/notes/route.js +0 -14
  403. package/.next/server/app/api/bot/notes/route_client-reference-manifest.js +0 -3
  404. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  405. package/.next/server/app/api/memory/tidy/route.js +0 -22
  406. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  407. package/.next/server/chunks/0d-b_next_dist_server_app-render_after-task-async-storage_external_0-exn7p.js +0 -3
  408. package/.next/server/chunks/[root-of-the-server]__0-npkh_._.js +0 -3
  409. package/.next/server/chunks/[root-of-the-server]__005var5._.js +0 -3
  410. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  411. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  412. package/.next/server/chunks/[root-of-the-server]__04_8spk._.js +0 -3
  413. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  414. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  415. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  416. package/.next/server/chunks/[root-of-the-server]__0cro2dz._.js +0 -5
  417. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  418. package/.next/server/chunks/[root-of-the-server]__0emr6go._.js +0 -3
  419. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  420. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  421. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  422. package/.next/server/chunks/[root-of-the-server]__0p32jfz._.js +0 -12
  423. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  424. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  425. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  426. package/.next/server/chunks/[root-of-the-server]__11j52t0._.js +0 -5
  427. package/.next/server/chunks/[root-of-the-server]__1692zrv._.js +0 -3
  428. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  429. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  430. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  431. package/.next/server/chunks/[root-of-the-server]__1bn73ih._.js +0 -10
  432. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  433. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  434. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  435. package/.next/server/chunks/[root-of-the-server]__1fboj2j._.js +0 -3
  436. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  437. package/.next/server/chunks/[root-of-the-server]__1oli73c._.js +0 -3
  438. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  439. package/.next/server/chunks/[root-of-the-server]__1untqv8._.js +0 -5
  440. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  441. package/.next/server/chunks/_00_584r._.js +0 -293
  442. package/.next/server/chunks/_012yhfm._.js +0 -39
  443. package/.next/server/chunks/_06mxlgn._.js +0 -3
  444. package/.next/server/chunks/_07rtlxv._.js +0 -3
  445. package/.next/server/chunks/_0a351g7._.js +0 -6
  446. package/.next/server/chunks/_0kjjmag._.js +0 -3
  447. package/.next/server/chunks/_0nn99o2._.js +0 -3
  448. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  449. package/.next/server/chunks/_106co2o._.js +0 -3
  450. package/.next/server/chunks/_12bbv5i._.js +0 -100
  451. package/.next/server/chunks/_15q1pig._.js +0 -3
  452. package/.next/server/chunks/_19wg5yn._.js +0 -138
  453. package/.next/server/chunks/_1bt95p9._.js +0 -55
  454. package/.next/server/chunks/_1cbk7ms._.js +0 -26
  455. package/.next/server/chunks/_1drv2et._.js +0 -40
  456. package/.next/server/chunks/_1ic3bew._.js +0 -5
  457. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  458. package/.next/server/chunks/_1rysr-r._.js +0 -10
  459. package/.next/server/chunks/_1u3rwbr._.js +0 -3
  460. package/.next/server/chunks/_1x7p319._.js +0 -6
  461. package/.next/server/chunks/_next-internal_server_app_api_bot_notes_route_actions_0qcsyu7.js +0 -3
  462. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  463. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  464. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js +0 -3
  465. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  466. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1tpvamf._.js +0 -3
  467. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  468. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y9-wcr._.js +0 -3
  469. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  470. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  471. package/.next/server/chunks/ssr/[root-of-the-server]__0un-erv._.js +0 -4
  472. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -92
  473. package/.next/server/chunks/ssr/[root-of-the-server]__1bww500._.js +0 -3
  474. package/.next/server/chunks/ssr/[root-of-the-server]__1vcdast._.js +0 -3
  475. package/.next/server/chunks/ssr/[root-of-the-server]__1xwnu-h._.js +0 -3
  476. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  477. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  478. package/.next/server/chunks/ssr/_03webdr._.js +0 -3
  479. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  480. package/.next/server/chunks/ssr/_0f_b_9s._.js +0 -3
  481. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  482. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  483. package/.next/server/chunks/ssr/_0su6_08._.js +0 -3
  484. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  485. package/.next/server/chunks/ssr/_0w5bgak._.js +0 -3
  486. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  487. package/.next/server/chunks/ssr/_1ciyoo3._.js +0 -3
  488. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  489. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  490. package/.next/server/chunks/ssr/_1g6l4uj._.js +0 -3
  491. package/.next/server/chunks/ssr/_1ruzehw._.js +0 -3
  492. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  493. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  494. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  495. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  496. package/.next/static/chunks/05b6nx_o3_f_n.js +0 -1
  497. package/.next/static/chunks/0dmns-gi0raa4.js +0 -1
  498. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  499. package/.next/static/chunks/0oc4_xoia77dg.css +0 -1
  500. package/.next/static/chunks/0pheo8m3a-rzi.js +0 -1
  501. package/.next/static/chunks/19i8h2t-5evjx.js +0 -1
  502. package/.next/static/chunks/1c5fcj473025q.js +0 -1
  503. package/.next/static/chunks/1pi_hbmjw-f-z.js +0 -1
  504. package/.next/static/chunks/1twt6k09vg4np.js +0 -1
  505. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  506. package/.next/static/chunks/28gotuisldmom.js +0 -1
  507. package/.next/static/chunks/2998p0y7k1c8z.js +0 -3
  508. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  509. package/.next/static/chunks/2l233xfycjpd8.js +0 -1
  510. package/.next/static/chunks/2p5n7pa3c40t-.js +0 -2
  511. package/.next/static/chunks/2ru1q132af7h7.js +0 -1
  512. package/.next/static/chunks/2t8wqycwg3y04.js +0 -2
  513. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  514. package/.next/static/chunks/32z_ypgtchw48.js +0 -1
  515. package/.next/static/chunks/33pyjb3xd1iez.js +0 -1
  516. package/.next/static/chunks/3omud5xunrk1f.js +0 -1
  517. package/.next/static/chunks/42dnrkbph9e-1.js +0 -1
  518. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  519. package/database/migrations/20260909063821_bitter_tenebrous/migration.sql +0 -1
  520. package/features/ai/prompts/memory-tidy.prompt.ts +0 -129
  521. package/features/ai/tools/tidy.tool.ts +0 -22
  522. package/features/bot/bot.notes.ts +0 -120
  523. package/features/memory/components/memory-tidy.tsx +0 -395
  524. package/features/memory/memory.tidy.ts +0 -332
  525. package/features/memory/tidy.query.ts +0 -135
  526. package/features/thursday/use-call-title.ts +0 -31
  527. /package/.next/server/app/api/bot/{notes → memory/files}/route/build-manifest.json +0 -0
  528. /package/.next/server/app/api/bot/{notes → memory/files}/route/server-reference-manifest.json +0 -0
  529. /package/.next/server/app/api/bot/{notes → memory/files}/route.js.map +0 -0
  530. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/build-manifest.json +0 -0
  531. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/server-reference-manifest.json +0 -0
  532. /package/.next/server/app/api/{memory/tidy → bot/memory}/route.js.map +0 -0
  533. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
  534. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
  535. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
@@ -2,13 +2,12 @@ import { z } from "zod";
2
2
  import { type DateLike, DateLikeSchema, toDate } from "@/lib/date-like";
3
3
 
4
4
  /**
5
- * Who put a fact here. Memory is one note kept by four hands — the user typing
6
- * on the screen, the call as they talk, a bot that turned something up mid-job,
7
- * and the pass that reads calls back afterwards and they are not equally
8
- * close to the user. A reader that cannot tell them apart reads what a bot
9
- * inferred as something the user said.
5
+ * Who put a fact here. Memory is one note kept by three hands — the user typing
6
+ * on the screen, the call as they talk, and a bot that turned something up
7
+ * mid-job — and they are not equally close to the user. A reader that cannot
8
+ * tell them apart reads what a bot inferred as something the user said.
10
9
  */
11
- export const MemorySourceSchema = z.enum(["user", "call", "bot", "tidy"]);
10
+ export const MemorySourceSchema = z.enum(["user", "call", "bot"]);
12
11
 
13
12
  export type MemorySource = z.infer<typeof MemorySourceSchema>;
14
13
 
@@ -25,15 +24,13 @@ export const memorySourceLabel = (source: MemorySource | null | undefined) =>
25
24
  ? "on a call"
26
25
  : source === "bot"
27
26
  ? "a bot"
28
- : source === "tidy"
29
- ? "read back"
30
- : "";
27
+ : "";
31
28
 
32
29
  // Storage is fact-based: one row per fact, history via isLatest.
33
30
  export const MemoryFactSchema = z.object({
34
31
  id: z.number(),
35
32
  text: z.string(),
36
- /** Loaded into every prompt without opening the note (ALWAYS_LOADED_MAX). */
33
+ /** Loaded into every prompt without opening the note (config MEMORY_LIMITS.carried). */
37
34
  alwaysLoad: z.boolean(),
38
35
  /** Null on rows written before the hand was recorded. */
39
36
  source: MemorySourceSchema.nullish(),
@@ -65,17 +62,16 @@ export type MemoryNote = z.infer<typeof MemoryNoteSchema>;
65
62
  export const MEMORY_PATHS = [
66
63
  {
67
64
  path: "profile",
68
- of: "The user themselves — who they are, what they do, where, how they live",
65
+ of: "The user themselves — their name, age, what they do, where they live, and whatever else says who they are",
69
66
  },
70
- { path: "preferences", of: "How they like things done, and said" },
67
+ { path: "preferences", of: "How they want things done, and said" },
68
+ { path: "people/", of: "Someone in their life, and what matters about them" },
71
69
  {
72
- path: "people/",
73
- of: "Who someone is to them, and what matters about them",
70
+ path: "projects/",
71
+ of: "Something with an end — a trip, a purchase, a deadline, a thing being built",
74
72
  },
75
- { path: "projects/", of: "Something they are building or running" },
76
- { path: "plans/", of: "A trip, an appointment, a purchase, a deadline" },
77
- { path: "topics/", of: "Anything else worth its own note" },
78
- { path: "inbox", of: "Nowhere obvious to go" },
73
+ { path: "topics/", of: "Something ongoing that keeps coming back" },
74
+ { path: "inbox", of: "Nowhere obvious yet" },
79
75
  ] as const;
80
76
 
81
77
  /** Where anything outside the convention lands. */
@@ -92,7 +88,6 @@ export const MEMORY_SECTIONS = MEMORY_PATHS.filter((entry) =>
92
88
  ).map((entry) => entry.path.slice(0, -1)) as (
93
89
  | "people"
94
90
  | "projects"
95
- | "plans"
96
91
  | "topics"
97
92
  )[];
98
93
 
@@ -108,11 +103,20 @@ export const MEMORY_ALWAYS_LISTED: string[] = ["profile", "preferences"];
108
103
  export const isAlwaysListed = (path: string) =>
109
104
  MEMORY_ALWAYS_LISTED.includes(path);
110
105
 
111
- /** Threshold, not a cap: a note above this is flagged for tidying but never truncated. */
112
- export const MANY_FACTS = 100;
106
+ /**
107
+ * Notes whose listing line the app writes rather than a model: the two root
108
+ * notes it keeps (memory.query ensureRootNotes) and the inbox, which is where
109
+ * a fact lands when its path is not one this listing can carry. A model's
110
+ * `description` for one of these is ignored, so the line cannot drift with
111
+ * whoever wrote last (ai/tools/memory.tool).
112
+ */
113
+ export const APP_NAMED_NOTES = [...MEMORY_ALWAYS_LISTED, MEMORY_INBOX];
114
+
115
+ export const isAppNamed = (path: string) => APP_NAMED_NOTES.includes(path);
113
116
 
114
- /** Max facts loaded into every session prompt; enforced by the write path, not the prompt. */
115
- export const ALWAYS_LOADED_MAX = 14;
117
+ /** The line the app writes for one of those. */
118
+ export const appNoteLine = (path: string) =>
119
+ MEMORY_PATHS.find((entry) => entry.path === path)?.of ?? null;
116
120
 
117
121
  export type MemorySection =
118
122
  | "you"
@@ -134,6 +138,8 @@ export type MemoryFactRef = {
134
138
  /** What `memory_forget` and `replaces` take. */
135
139
  id: number;
136
140
  text: string;
141
+ /** When the call it was said in started, when a call wrote it. Formatted by the tool, never sent as a Date. */
142
+ saidAt?: Date;
137
143
  };
138
144
 
139
145
  /** A fact carried at the top of the prompt, with its note path. */
@@ -209,86 +215,3 @@ export function isFading(
209
215
  ): boolean {
210
216
  return !isAlwaysListed(note.path) && recallScore(note) < 0.15;
211
217
  }
212
-
213
- // Reading calls back (memory.tidy): its settings and the run row the screen draws.
214
-
215
- /** Config keys (features/config config.query) the settings live under. */
216
- export const MEMORY_TIDY_KEYS = {
217
- /** "on" switches it on; anything else, unset included, is off. */
218
- on: "MEMORY_TIDY",
219
- /** `provider/model`; unset runs on the app default (ai/model resolveDefaultModel). */
220
- model: "MEMORY_TIDY_MODEL",
221
- } as const;
222
-
223
- /**
224
- * Off unless switched on. A read costs a whole context of a text model, so
225
- * nothing starts spending until the user asks for it — and a model must be
226
- * picked as well (memory.tidy startTidy).
227
- */
228
- export const isTidyOn = (value: string | undefined) => value?.trim() === "on";
229
-
230
- export const MEMORY_TIDY_STATUSES = [
231
- "running",
232
- "done",
233
- "stopped",
234
- "failed",
235
- ] as const;
236
- export type MemoryTidyStatus = (typeof MEMORY_TIDY_STATUSES)[number];
237
-
238
- /** One thing a read changed; the run row keeps them in order. */
239
- export const MemoryTidyChangeSchema = z.object({
240
- op: z.enum(["add", "replace", "forget", "carry", "uncarry"]),
241
- path: z.string(),
242
- text: z.string(),
243
- });
244
- export type MemoryTidyChange = z.infer<typeof MemoryTidyChangeSchema>;
245
-
246
- export const MemoryTidyRunSchema = z.object({
247
- id: z.string(),
248
- status: z.enum(MEMORY_TIDY_STATUSES),
249
- provider: z.string(),
250
- model: z.string(),
251
- /** The calls this read covered and stamped, oldest first. */
252
- callIds: z.string().array(),
253
- /** Turns it actually read. Fewer than were owed when older ones were dropped. */
254
- messages: z.number(),
255
- changes: MemoryTidyChangeSchema.array(),
256
- error: z.string().nullable(),
257
- inputTokens: z.number(),
258
- outputTokens: z.number(),
259
- startedAt: DateLikeSchema,
260
- endedAt: DateLikeSchema.nullable(),
261
- });
262
- export type MemoryTidyRun = z.infer<typeof MemoryTidyRunSchema>;
263
-
264
- /** What the setting reads (app/api/memory/tidy). */
265
- export type MemoryTidyStatusView = {
266
- on: boolean;
267
- /** The picked model as `provider/model`, or null for the app default. */
268
- model: string | null;
269
- /** Turns said since the last read, and how many it takes to run. */
270
- pending: number;
271
- every: number;
272
- /** The read in progress, if any. */
273
- current: MemoryTidyRun | null;
274
- /** The most recent finished read. */
275
- last: MemoryTidyRun | null;
276
- };
277
-
278
- /** Counts per op for one line on screen: "3 added, 1 revised". */
279
- export function tidyTally(changes: MemoryTidyChange[]): string {
280
- const count = (op: MemoryTidyChange["op"]) =>
281
- changes.filter((change) => change.op === op).length;
282
- const said = (
283
- [
284
- [count("add"), "added"],
285
- [count("replace"), "revised"],
286
- [count("forget"), "dropped"],
287
- [count("carry"), "carried"],
288
- [count("uncarry"), "uncarried"],
289
- ] as const
290
- )
291
- .filter(([n]) => n > 0)
292
- .map(([n, word]) => `${n} ${word}`);
293
- return said.length ? said.join(", ") : "nothing to change";
294
- }
@@ -29,6 +29,7 @@ import { BotBadge } from "@/features/bot/components/bot-badge";
29
29
  import { BotsMark } from "@/features/bot/components/bot-mark";
30
30
  import { TaskBadge } from "@/features/bot/components/task-badge";
31
31
  import { ConfigBadge } from "@/features/config/components/config-badge";
32
+ import { ModelsBadge } from "@/features/config/components/models-badge";
32
33
  import { McpBadge } from "@/features/connectors/components/mcp-badge";
33
34
  import { McpMark } from "@/features/connectors/components/mcp-mark";
34
35
  import { MemoryMark } from "@/features/memory/components/memory-mark";
@@ -203,6 +204,7 @@ export const SECTIONS: readonly {
203
204
  hint: "What bots draw, film, speak and transcribe with",
204
205
  icon: Aperture,
205
206
  Component: ModelsSetting,
207
+ Badge: ModelsBadge,
206
208
  },
207
209
  {
208
210
  id: "config",
@@ -3,6 +3,7 @@
3
3
  import { useBotAlert } from "@/features/bot/components/bot-badge";
4
4
  import { useTaskAlert } from "@/features/bot/components/task-badge";
5
5
  import { useConfigAlert } from "@/features/config/components/config-badge";
6
+ import { useModelsAlert } from "@/features/config/components/models-badge";
6
7
  import { useMcpAlert } from "@/features/connectors/components/mcp-badge";
7
8
  import type { SettingSectionId } from "./settings.store";
8
9
 
@@ -32,5 +33,6 @@ export function useSectionAlerts(): Partial<
32
33
  const tasks = useTaskAlert();
33
34
  const mcp = useMcpAlert();
34
35
  const config = useConfigAlert();
35
- return { bot, tasks, mcp, config };
36
+ const models = useModelsAlert();
37
+ return { bot, tasks, mcp, config, models };
36
38
  }
@@ -1,6 +1,11 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect, useRef } from "react";
4
+ import { ASCII_FACE } from "@/config";
5
+ import {
6
+ createVoiceFollower,
7
+ SPECTRUM_BANDS,
8
+ } from "@/lib/realtime/realtime.tap";
4
9
  import {
5
10
  ALPHA_TOP,
6
11
  CHAR_RATE,
@@ -132,44 +137,47 @@ const DESIGN = 680;
132
137
  /** Radius (reference units) within which cells exist. Must stay under DESIGN/2 or the canvas clips it. */
133
138
  const FIELD_R = 328;
134
139
 
135
- /** Gain on incoming band values: speech bands average 0.15-0.35, and the top is clamped anyway. */
136
- const VOICE_GAIN = 2.6;
137
-
138
140
  /** Speaking: reference-unit px the rim is pushed by each channel. */
139
- /** Swell at average loudness 1 */
140
- const SPEAK_SWELL = 58;
141
+ /** Where the rim sits while the voice is at the bottom of its range */
142
+ const SPEAK_BASE = 184;
143
+ /** Swell across a phrase at the top of the voice's range */
144
+ const SPEAK_SWELL = 40;
141
145
  /** Kick per syllable */
142
- const SPEAK_KICK = 58;
146
+ const SPEAK_KICK = 120;
143
147
  /** Rotating lobes, harmonics 2 and up (the first harmonic shifts the whole circle) */
144
148
  const SPEAK_LOBES = 4;
145
149
  /** Max depth of one lobe */
146
- const SPEAK_LOBE_R = 40;
150
+ const SPEAK_LOBE_R = 34;
147
151
  /**
148
- * Rim range. Max must stay inside FIELD_R or outgoing rings die at the edge;
149
- * min keeps a deep breath from collapsing to a dot.
152
+ * Rim range. Past SPEAK_KNEE the rim slows into SPEAK_MAX rather than stopping
153
+ * at it, so a loud syllable still reads as a push instead of a flat edge. Max
154
+ * stays inside FIELD_R or thrown crumbs die at the edge; min keeps a deep
155
+ * breath from collapsing to a dot.
150
156
  */
151
157
  const SPEAK_MIN = 130;
158
+ const SPEAK_KNEE = 244;
152
159
  const SPEAK_MAX = 278;
153
- /** Syllable ring speed (px/s) and lifetime (s) */
154
- const RING_SPEED = 100;
155
- const RING_LIFE = 0.55;
156
- /** Rings alive at once, so fast speech does not flood the field */
160
+ /** How far a rim cell sits in or out of the rim: the edge is crumbly, not drawn with a compass */
161
+ const SPEAK_ROUGH = 20;
162
+ /** Share of cells a syllable throws outward; the rest stay, so what leaves is crumbs, not a ring */
163
+ const SPECK_SHARE = 0.22;
164
+ /** Crumb speed (px/s) and lifetime (s) */
165
+ const RING_SPEED = 90;
166
+ const RING_LIFE = 0.7;
167
+ /** Syllables in flight at once, so fast speech does not flood the field */
157
168
  const MAX_RINGS = 5;
158
169
 
159
170
  /** Per-frame values derived from the voice; every cell reads the same ones. */
160
171
  type Voice = {
161
- /** Three time constants; fast/mid detect syllables, slow sets size */
162
- fast: number;
163
- mid: number;
164
- slow: number;
172
+ /** The voice inside its own range over about half a second (realtime.tap createVoiceFollower) */
173
+ phrase: number;
165
174
  /** Spring kicked by each syllable */
166
175
  bob: number;
167
176
  bobVel: number;
168
- lastOnset: number;
169
177
  /** Lobe strength and angle */
170
178
  amp: number[];
171
179
  phase: number[];
172
- /** One outgoing ring per syllable */
180
+ /** One throw of crumbs per syllable */
173
181
  rings: { born: number; power: number }[];
174
182
  };
175
183
 
@@ -228,6 +236,8 @@ type Cell = {
228
236
  death: number;
229
237
  /** Emoji slot in emoji mode */
230
238
  emoji: boolean;
239
+ /** Below SPECK_SHARE, a crumb a syllable throws outward */
240
+ speck: number;
231
241
  /** Index of the ERROR letter this cell belongs to, or -1 */
232
242
  letter: number;
233
243
  };
@@ -276,6 +286,13 @@ function idleValue(cell: Cell, t: number) {
276
286
  return (0.58 + w * 0.2 + breath) * body;
277
287
  }
278
288
 
289
+ /** The rim's radius for a raw push: as pushed up to SPEAK_KNEE, then easing into SPEAK_MAX. */
290
+ function rimAt(raw: number) {
291
+ if (raw <= SPEAK_KNEE) return Math.max(SPEAK_MIN, raw);
292
+ const room = SPEAK_MAX - SPEAK_KNEE;
293
+ return SPEAK_KNEE + room * Math.tanh((raw - SPEAK_KNEE) / room);
294
+ }
295
+
279
296
  /**
280
297
  * Brightness of one mode; mode transitions blend two of these.
281
298
  * @param e seconds since the mode started
@@ -305,12 +322,16 @@ function valueFor(m: AsciiOrbMode, cell: Cell, t: number, e: number, v: Voice) {
305
322
  * Speaking. Frequency is not mapped to angle: a voice's spectrum barely
306
323
  * moves within a sentence, so that freezes into a fixed star. The voice
307
324
  * gives size, syllables and lobe strength; rotation comes from time, each
308
- * lobe at its own speed in alternating directions.
325
+ * lobe at its own speed in alternating directions. No line in it is clean:
326
+ * the rim is crumbly, and a syllable throws crumbs rather than a ring.
309
327
  */
310
328
  case "speaking": {
311
329
  const grow = smoothstep(0, 1, Math.min(1, e / 0.8));
312
330
 
313
- let raw = IDLE_R + (SPEAK_SWELL * v.slow + SPEAK_KICK * v.bob) * grow;
331
+ let raw =
332
+ IDLE_R +
333
+ (SPEAK_BASE - IDLE_R + SPEAK_SWELL * v.phrase + SPEAK_KICK * v.bob) *
334
+ grow;
314
335
  for (let i = 0; i < SPEAK_LOBES; i++) {
315
336
  raw +=
316
337
  SPEAK_LOBE_R *
@@ -318,26 +339,41 @@ function valueFor(m: AsciiOrbMode, cell: Cell, t: number, e: number, v: Voice) {
318
339
  Math.sin((i + 2) * cell.angle + v.phase[i]) *
319
340
  grow;
320
341
  }
321
- const edge = Math.max(SPEAK_MIN, Math.min(SPEAK_MAX, raw));
322
-
323
- const d = cell.dist - edge;
324
- const rim = Math.exp(-(d * d) / 900);
325
- const core = Math.exp(-(cell.dist * cell.dist) / 6000) * 0.55;
326
- const inside = cell.dist < edge ? 0.3 * (1 - cell.dist / edge) ** 0.6 : 0;
327
-
328
- // one ring per syllable, born at the rim and moving outward
342
+ const edge = rimAt(raw);
343
+
344
+ // each cell sits a little in or out of the rim, and the offset drifts
345
+ const rough =
346
+ (cell.grain - 0.5) * SPEAK_ROUGH +
347
+ Math.sin(cell.angle * 5 + t * 0.9 + cell.seed * 6.283) *
348
+ SPEAK_ROUGH *
349
+ 0.3;
350
+ const d = cell.dist - (edge + rough);
351
+ const rim = Math.exp(-(d * d) / 800);
352
+ const core = Math.exp(-(cell.dist * cell.dist) / 6000) * 0.5;
353
+ // a soft fill toward the center, with the idle wave still moving through it
354
+ const inside =
355
+ cell.dist < edge
356
+ ? 0.3 *
357
+ (1 - cell.dist / edge) ** 0.6 *
358
+ (0.75 + 0.25 * Math.sin(cell.dist * 0.05 - t * 1.2))
359
+ : 0;
360
+
361
+ // crumbs: a sparse share of cells, each thrown past the rim at its own speed
329
362
  let out = 0;
330
- for (let i = 0; i < v.rings.length; i++) {
331
- const ring = v.rings[i];
332
- const age = t - ring.born;
333
- const dd = cell.dist - (edge + age * RING_SPEED);
334
- out +=
335
- Math.exp(-(dd * dd) / 2200) *
336
- ring.power *
337
- Math.max(0, 1 - age / RING_LIFE);
363
+ if (cell.speck < SPECK_SHARE) {
364
+ const speed = RING_SPEED * (0.6 + cell.grain * 0.9);
365
+ for (let i = 0; i < v.rings.length; i++) {
366
+ const ring = v.rings[i];
367
+ const age = t - ring.born;
368
+ const dd = cell.dist - (edge + 6 + age * speed);
369
+ out +=
370
+ Math.exp(-(dd * dd) / 500) *
371
+ ring.power *
372
+ Math.max(0, 1 - age / RING_LIFE);
373
+ }
338
374
  }
339
375
 
340
- return rim + core + inside + out * 0.8;
376
+ return rim + core + inside + out;
341
377
  }
342
378
 
343
379
  /**
@@ -387,10 +423,10 @@ function valueFor(m: AsciiOrbMode, cell: Cell, t: number, e: number, v: Voice) {
387
423
  export function AsciiOrb({
388
424
  className,
389
425
  mode = "idle",
390
- charset = "ascii",
426
+ charset = ASCII_FACE.charset,
391
427
  emotion = null,
392
- fontSize = 8,
393
- density = 1.4,
428
+ fontSize = ASCII_FACE.fontSize.default,
429
+ density = ASCII_FACE.density.default,
394
430
  size = DESIGN,
395
431
  color = DEFAULT_COLOR,
396
432
  getSpectrum,
@@ -432,12 +468,9 @@ export function AsciiOrb({
432
468
  specRef.current = getSpectrum;
433
469
 
434
470
  const voiceRef = useRef<Voice>({
435
- fast: 0,
436
- mid: 0,
437
- slow: 0,
471
+ phrase: 0,
438
472
  bob: 0,
439
473
  bobVel: 0,
440
- lastOnset: -Infinity,
441
474
  amp: new Array<number>(SPEAK_LOBES).fill(0),
442
475
  // distinct start phases, or the lobes overlap into one lump at first
443
476
  phase: Array.from({ length: SPEAK_LOBES }, (_, i) => i * 2.1),
@@ -502,6 +535,7 @@ export function AsciiOrb({
502
535
  birth: hash(c * 3.1 + 7, r * 5.7 + 2),
503
536
  death: hash(c * 9.4 + 3, r * 2.6 + 8),
504
537
  emoji: hash(c * 2.7 + 31, r * 5.9 + 17) < EMOJI_RATIO,
538
+ speck: hash(c * 4.1 + 23, r * 6.3 + 41),
505
539
  letter,
506
540
  });
507
541
  }
@@ -583,8 +617,8 @@ export function AsciiOrb({
583
617
  // animation loop
584
618
  useEffect(() => {
585
619
  let raf = 0;
586
- const BINS = 28;
587
- const spec = new Array<number>(BINS);
620
+ const follower = createVoiceFollower();
621
+ const murmur = new Array<number>(SPECTRUM_BANDS).fill(0);
588
622
 
589
623
  let lastT = performance.now() * 0.001;
590
624
 
@@ -604,49 +638,27 @@ export function AsciiOrb({
604
638
  bk.asciiN.fill(0);
605
639
  bk.emojiN.fill(0);
606
640
 
607
- // Live voice when available. Bands (usually 8) are fewer than BINS (28)
608
- // and the orb reads this array by angle, so interpolate to avoid steps
609
- const live = specRef.current?.();
610
- if (live && live.length > 1) {
611
- const last = live.length - 1;
612
- for (let i = 0; i < BINS; i++) {
613
- // fold the band index so it returns to the first band over one revolution; a plain stretch shows a seam at 0 degrees
614
- const fold = Math.abs((((i / BINS) * 2 + 1) % 2) - 1);
615
- const at = fold * last;
616
- const lo = Math.floor(at);
617
- const hi = Math.min(last, lo + 1);
618
- spec[i] = live[lo] + (live[hi] - live[lo]) * (at - lo);
619
- }
620
- } else {
621
- for (let i = 0; i < BINS; i++) {
641
+ // Live voice when available; without one a murmur keeps the orb alive (previews)
642
+ let live: ArrayLike<number> | undefined = specRef.current?.();
643
+ if (!live || live.length < 2) {
644
+ for (let k = 0; k < murmur.length; k++) {
622
645
  const a =
623
- Math.sin(t * 1.7 + i * 1.7) * 0.5 +
624
- Math.sin(t * 0.8 + i * 0.6) * 0.3 +
625
- Math.sin(t * 3.0 + i * 2.9) * 0.2;
626
- spec[i] = a * 0.5 + 0.5;
646
+ Math.sin(t * 1.7 + k * 1.7) * 0.5 +
647
+ Math.sin(t * 0.8 + k * 0.6) * 0.3 +
648
+ Math.sin(t * 3.0 + k * 2.9) * 0.2;
649
+ murmur[k] = a * 0.5 + 0.5;
627
650
  }
651
+ live = murmur;
628
652
  }
629
653
 
630
- // derive size, syllables and lobes from the voice (once per frame)
654
+ // size, syllables and lobes from the voice, once per frame; each band is
655
+ // read inside its own range, or a voice's narrow loud spectrum pins the rim
631
656
  const voice = voiceRef.current;
632
- let loud = 0;
633
- for (let i = 0; i < BINS; i++) loud += spec[i];
634
- loud = Math.min(1, (loud / BINS) * VOICE_GAIN);
635
-
636
- // three time constants: a syllable is a frame above the recent average, not a loud frame
637
- voice.fast += (loud - voice.fast) * 0.3;
638
- voice.mid += (loud - voice.mid) * 0.06;
639
- voice.slow += (loud - voice.slow) * 0.02;
640
-
641
- if (
642
- voice.fast > voice.mid * 1.25 + 0.02 &&
643
- voice.fast > 0.07 &&
644
- t - voice.lastOnset > 0.14
645
- ) {
646
- voice.lastOnset = t;
647
- const power = Math.min(1, voice.fast * 1.7);
648
- voice.bobVel += 0.05 * power;
649
- voice.rings.push({ born: t, power });
657
+ const heard = follower.read(live, dt);
658
+ voice.phrase = heard.phrase;
659
+ if (heard.onset > 0) {
660
+ voice.bobVel += 0.06 * heard.onset;
661
+ voice.rings.push({ born: t, power: heard.onset });
650
662
  if (voice.rings.length > MAX_RINGS) voice.rings.shift();
651
663
  }
652
664
  // a spring with a period of about 1s; kick it on syllables instead of driving position, or 60fps noise becomes jitter
@@ -654,15 +666,19 @@ export function AsciiOrb({
654
666
  voice.bob += voice.bobVel;
655
667
 
656
668
  for (let i = 0; i < SPEAK_LOBES; i++) {
657
- const from = ((i / SPEAK_LOBES) * BINS) | 0;
658
- const to = (((i + 1) / SPEAK_LOBES) * BINS) | 0;
669
+ // neighbouring bands per lobe, low lobes from low bands
670
+ const from = Math.floor((i * heard.bands.length) / SPEAK_LOBES);
671
+ const to = Math.max(
672
+ from + 1,
673
+ Math.floor(((i + 1) * heard.bands.length) / SPEAK_LOBES),
674
+ );
659
675
  let energy = 0;
660
- for (let j = from; j < to; j++) energy += spec[j];
661
- energy = Math.min(1, (energy / Math.max(1, to - from)) * VOICE_GAIN);
676
+ for (let j = from; j < to; j++) energy += heard.bands[j];
677
+ energy /= to - from;
662
678
  // a random factor that changes about once per second, so lobes keep moving through a held vowel
663
679
  const wander = 0.7 + hash(((t * 0.9) | 0) + i * 31, i) * 0.6;
664
680
  // different time constants per harmonic, or the star only scales
665
- voice.amp[i] += (energy * wander - voice.amp[i]) * (0.02 + i * 0.012);
681
+ voice.amp[i] += (energy * wander - voice.amp[i]) * (0.05 + i * 0.02);
666
682
  // own speed, alternating direction, so no standing wave forms
667
683
  voice.phase[i] += dt * (0.5 + i * 0.37) * (i % 2 ? -1 : 1);
668
684
  }
@@ -63,6 +63,13 @@ export function Boot({
63
63
  }}
64
64
  >
65
65
  <AsciiField boot rim={face.rim} centerY={face.centerY} onSettled={lift} />
66
+
67
+ {/* Nothing here can lift the curtain without the client, so a load that
68
+ never hydrates is a blank screen. Revealed by CSS alone (globals.css
69
+ `stalled`), well after any healthy start. */}
70
+ <p className="absolute inset-x-0 bottom-16 animate-stalled text-center text-[13px] text-muted-foreground opacity-0">
71
+ The page did not start. Reload it.
72
+ </p>
66
73
  </div>
67
74
  );
68
75
  }