thursday-agent 0.4.0 → 0.6.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 (657) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +3 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.json +8 -1
  6. package/.next/routes-manifest.json +18 -6
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +13 -13
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/server/app/api/artifact/route.js +10 -6
  21. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js +6 -5
  23. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/route.js +8 -8
  25. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  26. package/.next/server/app/api/bot/route.js +8 -8
  27. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  28. package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
  30. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
  31. package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
  33. package/.next/server/app/api/bot/thread/route.js +15 -0
  34. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
  35. package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
  36. package/.next/server/app/api/config/route.js +7 -7
  37. package/.next/server/app/api/config/route.js.nft.json +1 -1
  38. package/.next/server/app/api/events/route.js +3 -3
  39. package/.next/server/app/api/events/route.js.nft.json +1 -1
  40. package/.next/server/app/api/file/[...path]/route.js +5 -5
  41. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  42. package/.next/server/app/api/llm-model/catalog/route.js +8 -8
  43. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/credits/route.js +8 -8
  45. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/route.js +8 -8
  47. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/subscription/route.js +8 -8
  49. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  50. package/.next/server/app/api/mcp/[name]/route.js +6 -6
  51. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
  53. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  54. package/.next/server/app/api/mcp/route.js +6 -6
  55. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  56. package/.next/server/app/api/mcp/tools/route.js +6 -6
  57. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  58. package/.next/server/app/api/memory/edit/route.js +13 -13
  59. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  60. package/.next/server/app/api/memory/route.js +7 -6
  61. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  62. package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
  63. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/skills/route.js +6 -6
  65. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  66. package/.next/server/app/api/thursday/call/route.js +10 -11
  67. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  68. package/.next/server/app/api/thursday/skills/route.js +10 -11
  69. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  70. package/.next/server/app/api/thursday/tool-call/route.js +15 -15
  71. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  72. package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/workspace/missing/route.js +12 -0
  76. package/.next/server/app/api/workspace/missing/route.js.map +5 -0
  77. package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
  78. package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
  79. package/.next/server/app/api/workspace/route.js +5 -4
  80. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  81. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  82. package/.next/server/app/artifact/[...path]/page.js +4 -3
  83. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  84. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  86. package/.next/server/app/page/server-reference-manifest.json +67 -45
  87. package/.next/server/app/page.js +10 -9
  88. package/.next/server/app/page.js.nft.json +1 -1
  89. package/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app-paths-manifest.json +3 -2
  91. package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
  92. package/.next/server/chunks/[root-of-the-server]__049f521._.js +3 -0
  93. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
  94. package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
  95. package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
  96. package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
  97. package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
  98. package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
  99. package/.next/server/chunks/[root-of-the-server]__0g-ueei._.js +8 -0
  100. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
  101. package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
  102. package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
  103. package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
  104. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__0ye3da2._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
  107. package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
  109. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
  110. package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
  111. package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
  112. package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
  113. package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
  114. package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
  115. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
  116. package/.next/server/chunks/_02szwk8._.js +5 -0
  117. package/.next/server/chunks/_05h2cii._.js +1 -1
  118. package/.next/server/chunks/_06c9kie._.js +216 -0
  119. package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
  120. package/.next/server/chunks/_0a43a-0._.js +3 -0
  121. package/.next/server/chunks/_0bujjey._.js +5 -0
  122. package/.next/server/chunks/_0c9j6rb._.js +1 -1
  123. package/.next/server/chunks/_0dkd549._.js +3 -0
  124. package/.next/server/chunks/_0ej1kvv._.js +3 -0
  125. package/.next/server/chunks/_0f6ts7z._.js +3 -0
  126. package/.next/server/chunks/_0gm9hyv._.js +55 -0
  127. package/.next/server/chunks/_0i55en5._.js +25 -0
  128. package/.next/server/chunks/_0k50n27._.js +18 -0
  129. package/.next/server/chunks/_0khihjk._.js +3 -3
  130. package/.next/server/chunks/_0n74zsf._.js +5 -5
  131. package/.next/server/chunks/_0nvm9ef._.js +3 -0
  132. package/.next/server/chunks/_0p56fn0._.js +3 -0
  133. package/.next/server/chunks/_0recufk._.js +1 -1
  134. package/.next/server/chunks/_0xbkz10._.js +3 -0
  135. package/.next/server/chunks/_10tkr26._.js +3 -0
  136. package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
  137. package/.next/server/chunks/_11ujpya._.js +3 -0
  138. package/.next/server/chunks/_127nx_p._.js +5 -0
  139. package/.next/server/chunks/_17l5ygt._.js +1 -1
  140. package/.next/server/chunks/_19uauj6._.js +3 -0
  141. package/.next/server/chunks/_1_5mnq4._.js +5 -5
  142. package/.next/server/chunks/_1abl6t9._.js +55 -0
  143. package/.next/server/chunks/_1d0j961._.js +3 -3
  144. package/.next/server/chunks/_1dbixxz._.js +3 -0
  145. package/.next/server/chunks/_1dc_d1q._.js +98 -0
  146. package/.next/server/chunks/_1drgfx4._.js +5 -5
  147. package/.next/server/chunks/_1e48czp._.js +3 -3
  148. package/.next/server/chunks/_1f31u5x._.js +5 -0
  149. package/.next/server/chunks/_1kg70wc._.js +3 -3
  150. package/.next/server/chunks/_1klbcft._.js +5 -0
  151. package/.next/server/chunks/_1krd9rf._.js +4 -1
  152. package/.next/server/chunks/_1kwmzab._.js +3 -0
  153. package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
  154. package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
  155. package/.next/server/chunks/_1qgix-j._.js +3 -0
  156. package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
  157. package/.next/server/chunks/_1vsej-s._.js +5 -0
  158. package/.next/server/chunks/_1yx0p_s._.js +5 -0
  159. package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
  160. package/.next/server/chunks/_2128hkj._.js +5 -0
  161. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
  162. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
  163. package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
  164. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  165. package/.next/server/chunks/features_0-cnt0l._.js +4 -0
  166. package/.next/server/chunks/features_0hdaci0._.js +4 -0
  167. package/.next/server/chunks/features_1e39j7-._.js +8 -0
  168. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  169. package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
  170. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
  171. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
  173. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
  174. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
  175. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
  176. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1kipdeo._.js +3 -0
  177. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
  178. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
  179. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
  180. package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
  181. package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
  182. package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
  183. package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
  184. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  185. package/.next/server/chunks/ssr/[root-of-the-server]__0bxsfyn._.js +101 -0
  186. package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
  187. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  188. package/.next/server/chunks/ssr/[root-of-the-server]__172cq4x._.js +3 -0
  189. package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
  190. package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
  191. package/.next/server/chunks/ssr/[root-of-the-server]__1fll8dc._.js +3 -0
  192. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  193. package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +100 -0
  196. package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
  197. package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -89
  198. package/.next/server/chunks/ssr/_03_928f._.js +3 -0
  199. package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
  200. package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
  201. package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
  202. package/.next/server/chunks/ssr/_0c9e5w6._.js +9 -0
  203. package/.next/server/chunks/ssr/{_0s99bgb._.js → _0dh2e1j._.js} +9 -3
  204. package/.next/server/chunks/ssr/_0dr-ddg._.js +3 -0
  205. package/.next/server/chunks/ssr/_0eaog6_._.js +3 -0
  206. package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
  207. package/.next/server/chunks/ssr/_0g_rlog._.js +3 -0
  208. package/.next/server/chunks/ssr/_0geg212._.js +3 -0
  209. package/.next/server/chunks/ssr/{_1gd8q8l._.js → _0hxt2ul._.js} +2 -2
  210. package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
  211. package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
  212. package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
  213. package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
  214. package/.next/server/chunks/ssr/_123ttsf._.js +3 -0
  215. package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
  216. package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
  217. package/.next/server/chunks/ssr/_161kqav._.js +3 -0
  218. package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
  219. package/.next/server/chunks/ssr/_18opah7._.js +3 -0
  220. package/.next/server/chunks/ssr/_18xqmny._.js +3 -0
  221. package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
  222. package/.next/server/chunks/ssr/{_1-_etts._.js → _1anqots._.js} +2 -2
  223. package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
  224. package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
  225. package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
  226. package/.next/server/chunks/ssr/{_0n3toaw._.js → _1k0spz7._.js} +2 -2
  227. package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
  228. package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
  229. package/.next/server/chunks/ssr/{_1fojd41._.js → _1x9pskj._.js} +3 -3
  230. package/.next/server/chunks/ssr/_1y6b5mr._.js +101 -0
  231. package/.next/server/chunks/ssr/_1ztk7p6._.js +7 -0
  232. package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
  233. package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
  234. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  235. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  236. package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
  237. package/.next/server/chunks/ssr/{node_modules_0cxaxk9._.js → node_modules_00_51_v._.js} +1 -1
  238. package/.next/server/chunks/ssr/{node_modules_04jf_m8._.js → node_modules_022sipm._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_0g7fzk3._.js → node_modules_0332gw4._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_1cx_ql6._.js → node_modules_04vxchl._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_1vh5ntv._.js → node_modules_0746rzi._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_0yugy6m._.js → node_modules_0d5uzof._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_09q35v_._.js → node_modules_0exkwcm._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_08dhkiq._.js → node_modules_0fr-ml8._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_14q6g4n._.js → node_modules_0mxvg8h._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_0arus10._.js → node_modules_0qapgjr._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_1eg7m6c._.js → node_modules_0qbfyjh._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_1cz2hle._.js → node_modules_0t-9nup._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
  250. package/.next/server/chunks/ssr/{node_modules_1efrqxi._.js → node_modules_0vsxbzp._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0_-_a--._.js → node_modules_0vv0-fg._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_1gdh31p._.js → node_modules_0wsvp00._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_1hpopmo._.js → node_modules_1-urho9._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_1_pc9kq._.js → node_modules_16pi_dd._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_00etblx._.js → node_modules_1d53yiq._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_1aaxuef._.js → node_modules_1g1eihe._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_198nmll._.js → node_modules_1gpednh._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_0pvd7q-._.js → node_modules_1gu1pph._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_0b__sgl._.js → node_modules_1he1w8_._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1qpjvy5._.js → node_modules_1lnjapm._.js} +1 -1
  261. package/.next/server/chunks/ssr/{node_modules_0940ns5._.js → node_modules_1lynj9m._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
  263. package/.next/server/chunks/ssr/{node_modules_14om4ar._.js → node_modules_1u6w1pb._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_0had7xd._.js → node_modules_1xn6saw._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b748ic._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_067_exa._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1z4hm5e._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0nrrdaq._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_06mk8id._.js → node_modules_@vercel_oidc_dist_21a5haa._.js} +1 -1
  268. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
  269. package/.next/server/middleware-build-manifest.js +3 -3
  270. package/.next/server/pages/404.html +1 -1
  271. package/.next/server/pages/500.html +1 -1
  272. package/.next/server/server-reference-manifest.js +1 -1
  273. package/.next/server/server-reference-manifest.json +68 -46
  274. package/.next/static/chunks/0dr16v67vj4n7.js +2 -0
  275. package/.next/static/chunks/0g4b348l0pve7.js +1 -0
  276. package/.next/static/chunks/0joan-69kbspd.js +1 -0
  277. package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
  278. package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
  279. package/.next/static/chunks/10k2xvap03z20.css +1 -0
  280. package/.next/static/chunks/18mkhstgiqcbt.js +1 -0
  281. package/.next/static/chunks/{15m575979un5f.js → 1i-u2wzub_to1.js} +2 -2
  282. package/.next/static/chunks/1kp5nfp06nj9h.js +5 -0
  283. package/.next/static/chunks/1ohslk4568tm3.js +1 -0
  284. package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
  285. package/.next/static/chunks/1t9qms5pwwa3n.js +1 -0
  286. package/.next/static/chunks/1vj_5bnbxx84e.js +1 -0
  287. package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
  288. package/.next/static/chunks/{3akmqm77muj4-.js → 1wlo979mx-y3w.js} +1 -1
  289. package/.next/static/chunks/26ql4y-43xwhp.js +1 -0
  290. package/.next/static/chunks/{0fl3gwe4-l6tz.js → 2_pnccjp6j1ca.js} +1 -1
  291. package/.next/static/chunks/2a51-ywz9b2a3.js +1 -0
  292. package/.next/static/chunks/2fvdgxih7x7hr.js +1 -0
  293. package/.next/static/chunks/2jlz8zp4jax_m.js +18 -0
  294. package/.next/static/chunks/2nvepds1fu2ux.js +1 -0
  295. package/.next/static/chunks/3addj3i4-izma.js +1 -0
  296. package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
  297. package/.next/static/chunks/3gfh7nxwusbt0.js +1 -0
  298. package/.next/static/chunks/3gwa44cvz4qoi.js +1 -0
  299. package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
  300. package/.next/static/chunks/3zk6q3-3f9swq.js +99 -0
  301. package/.next/static/chunks/3zkg5iup3v4a2.js +12 -0
  302. package/.next/static/chunks/405m0bqtoihev.js +1 -0
  303. package/.next/static/chunks/42wcg3wfg_m_p.js +1 -0
  304. package/README.md +27 -216
  305. package/app/api/events/app-event.ts +6 -4
  306. package/app/api/query-key.ts +25 -16
  307. package/bin/database.mjs +37 -0
  308. package/bin/thursday.mjs +44 -28
  309. package/components/ui/custom-icon.tsx +0 -60
  310. package/components/ui/radio-group.tsx +37 -0
  311. package/components/ui/shiny-text.tsx +33 -6
  312. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
  313. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
  314. package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
  315. package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
  316. package/docs/how-it-works.md +39 -36
  317. package/docs/images/keeps-going.png +0 -0
  318. package/docs/images/two-minds.png +0 -0
  319. package/docs/live-calls.md +231 -0
  320. package/docs/thread-rooms.md +71 -0
  321. package/features/ai/chatgpt.ts +1 -2
  322. package/features/ai/live.schema.ts +128 -0
  323. package/features/ai/load-tools.ts +148 -77
  324. package/features/ai/model.schema.ts +2 -120
  325. package/features/ai/model.ts +52 -88
  326. package/features/ai/prompts/bot.prompt.ts +91 -214
  327. package/features/ai/prompts/live.prompt.ts +265 -0
  328. package/features/ai/prompts/prompt-helper.ts +91 -32
  329. package/features/ai/prompts/thursday.prompt.ts +125 -172
  330. package/features/ai/tools/bot.tool.ts +38 -145
  331. package/features/ai/tools/call.tool.ts +1 -1
  332. package/features/ai/tools/connected.ts +5 -3
  333. package/features/ai/tools/mcp.tool.ts +7 -4
  334. package/features/ai/tools/memory.tool.ts +35 -31
  335. package/features/ai/tools/skills.tool.ts +36 -14
  336. package/features/ai/tools/studio.tool.ts +26 -21
  337. package/features/ai/tools/tool-name.ts +2 -5
  338. package/features/ai/tools/workspace.tool.ts +33 -10
  339. package/features/artifact/artifact.action.ts +2 -2
  340. package/features/artifact/artifact.query.ts +112 -61
  341. package/features/artifact/artifact.schema.ts +8 -6
  342. package/features/artifact/components/artifact-setting.tsx +83 -33
  343. package/features/bot/bot.action.ts +43 -36
  344. package/features/bot/bot.memory.ts +137 -20
  345. package/features/bot/bot.query.ts +28 -11
  346. package/features/bot/bot.run.ts +299 -636
  347. package/features/bot/bot.runner.ts +468 -844
  348. package/features/bot/bot.schema.ts +93 -82
  349. package/features/bot/bot.seed.ts +141 -64
  350. package/features/bot/components/bot-mark.tsx +324 -232
  351. package/features/bot/components/bot-room.tsx +1613 -697
  352. package/features/bot/components/bot-roster.tsx +8 -13
  353. package/features/bot/components/bot-setting.tsx +58 -42
  354. package/features/bot/components/bot-tool.tsx +55 -87
  355. package/features/bot/components/mark-palette.tsx +35 -32
  356. package/features/bot/components/path-chips.tsx +33 -3
  357. package/features/bot/components/thread-badge.tsx +34 -0
  358. package/features/bot/components/thread-reply.tsx +639 -0
  359. package/features/bot/components/thread-setting.tsx +674 -0
  360. package/features/bot/mark.const.ts +79 -31
  361. package/features/bot/room.query.ts +889 -0
  362. package/features/bot/room.schema.ts +64 -0
  363. package/features/bot/seed-bots.ts +2 -1
  364. package/features/bot/thread.query.ts +971 -0
  365. package/features/bot/thread.store.ts +587 -0
  366. package/features/config/components/voice-key.tsx +113 -88
  367. package/features/config/config.const.ts +5 -9
  368. package/features/connectors/mcp.schema.ts +0 -2
  369. package/features/intro/components/intro.tsx +169 -139
  370. package/features/memory/components/memory-setting.tsx +2 -7
  371. package/features/memory/memory.schema.ts +14 -23
  372. package/features/settings/components/setting-ui.tsx +0 -44
  373. package/features/settings/components/settings.tsx +12 -12
  374. package/features/settings/settings.alert.ts +3 -3
  375. package/features/settings/settings.store.ts +1 -1
  376. package/features/skills/skills.schema.ts +0 -2
  377. package/features/thursday/components/ascii-field.tsx +24 -44
  378. package/features/thursday/components/ascii-orb.tsx +359 -358
  379. package/features/thursday/components/call-log.tsx +46 -44
  380. package/features/thursday/components/face.tsx +35 -10
  381. package/features/thursday/components/tab-state.tsx +3 -3
  382. package/features/thursday/components/thursday-mark.tsx +1 -0
  383. package/features/thursday/components/thursday-setting.tsx +631 -332
  384. package/features/thursday/components/thursday.tsx +106 -41
  385. package/features/thursday/components/voice-picker.tsx +255 -0
  386. package/features/thursday/thursday.action.ts +94 -68
  387. package/features/thursday/thursday.query.ts +49 -30
  388. package/features/thursday/thursday.schema.ts +27 -30
  389. package/features/thursday/thursday.store.ts +11 -7
  390. package/features/thursday/tool-call.ts +3 -3
  391. package/features/thursday/tool-line.ts +5 -3
  392. package/features/thursday/use-thursday.ts +725 -450
  393. package/features/workspace/workspace.query.ts +17 -0
  394. package/features/workspace/workspace.ts +103 -50
  395. package/lib/live/live.schema.ts +47 -0
  396. package/lib/live/live.server.ts +155 -0
  397. package/lib/live/live.session.ts +574 -0
  398. package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
  399. package/lib/live/live.transport.ts +152 -0
  400. package/lib/protocol/use-server-pages.ts +9 -5
  401. package/lib/utils.ts +21 -20
  402. package/package.json +2 -2
  403. package/public/voices/alloy.ogg +0 -0
  404. package/public/voices/ash.ogg +0 -0
  405. package/public/voices/ballad.ogg +0 -0
  406. package/public/voices/beacon.ogg +0 -0
  407. package/public/voices/bossa.ogg +0 -0
  408. package/public/voices/cedar.ogg +0 -0
  409. package/public/voices/cinder.ogg +0 -0
  410. package/public/voices/coral.ogg +0 -0
  411. package/public/voices/delta.ogg +0 -0
  412. package/public/voices/echo.ogg +0 -0
  413. package/public/voices/gleam.ogg +0 -0
  414. package/public/voices/marin.ogg +0 -0
  415. package/public/voices/meridian.ogg +0 -0
  416. package/public/voices/quartz.ogg +0 -0
  417. package/public/voices/ripple.ogg +0 -0
  418. package/public/voices/sage.ogg +0 -0
  419. package/public/voices/shimmer.ogg +0 -0
  420. package/public/voices/stone.ogg +0 -0
  421. package/public/voices/tempo.ogg +0 -0
  422. package/public/voices/verse.ogg +0 -0
  423. package/public/voices/vesper.ogg +0 -0
  424. package/public/voices/willow.ogg +0 -0
  425. package/scripts/artifact-paths.test.mts +25 -0
  426. package/scripts/bot-context.test.mts +1408 -0
  427. package/scripts/live-history.test.mts +115 -0
  428. package/scripts/live-session.test.mts +948 -0
  429. package/server.js +1 -1
  430. package/skills/browser/SKILL.md +17 -6
  431. package/skills/computer/SKILL.md +1 -1
  432. package/skills/find-skills/SKILL.md +3 -8
  433. package/skills/interactive-page/SKILL.md +12 -7
  434. package/skills/interactive-page/references/diagram.md +89 -0
  435. package/skills/interactive-page/scripts/archify/LICENSE +22 -0
  436. package/skills/interactive-page/scripts/archify/README.md +25 -0
  437. package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
  438. package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
  439. package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
  440. package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
  441. package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
  442. package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
  443. package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
  444. package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
  445. package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
  446. package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
  447. package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
  448. package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
  449. package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
  450. package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
  451. package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
  452. package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
  453. package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
  454. package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
  455. package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
  456. package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
  457. package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
  458. package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
  459. package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
  460. package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
  461. package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
  462. package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
  463. package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
  464. package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
  465. package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  466. package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
  467. package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  468. package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
  469. package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
  470. package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
  471. package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
  472. package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
  473. package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
  474. package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
  475. package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
  476. package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
  477. package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
  478. package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
  479. package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
  480. package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
  481. package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
  482. package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
  483. package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
  484. package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
  485. package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
  486. package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
  487. package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
  488. package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
  489. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  490. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  491. package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
  492. package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
  493. package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
  494. package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
  495. package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
  496. package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
  497. package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
  498. package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
  499. package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
  500. package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
  501. package/skills/skill-creator/SKILL.md +4 -5
  502. package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
  503. package/.next/server/app/api/bot/task/[id]/route.js +0 -16
  504. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
  505. package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
  506. package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
  507. package/.next/server/app/api/bot/task/route.js +0 -16
  508. package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
  509. package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
  510. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +0 -3
  511. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
  512. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +0 -3
  513. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +0 -8
  514. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +0 -3
  515. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +0 -8
  517. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +0 -8
  518. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
  519. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
  520. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
  521. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +0 -8
  523. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +0 -8
  524. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
  525. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
  526. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +0 -10
  527. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
  528. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
  529. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
  530. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +0 -8
  531. package/.next/server/chunks/_0-73of8._.js +0 -55
  532. package/.next/server/chunks/_0-fjql4._.js +0 -26
  533. package/.next/server/chunks/_00xh_q0._.js +0 -25
  534. package/.next/server/chunks/_03a0897._.js +0 -3
  535. package/.next/server/chunks/_051qh8u._.js +0 -3
  536. package/.next/server/chunks/_05sovvj._.js +0 -3
  537. package/.next/server/chunks/_0fzqt2y._.js +0 -134
  538. package/.next/server/chunks/_0mecv0f._.js +0 -26
  539. package/.next/server/chunks/_0mh8j4m._.js +0 -3
  540. package/.next/server/chunks/_0obojvv._.js +0 -3
  541. package/.next/server/chunks/_0sb7tlz._.js +0 -3
  542. package/.next/server/chunks/_0sbynis._.js +0 -3
  543. package/.next/server/chunks/_0u10wmw._.js +0 -55
  544. package/.next/server/chunks/_0u4aiy2._.js +0 -3
  545. package/.next/server/chunks/_0wp4le3._.js +0 -3
  546. package/.next/server/chunks/_0y5fg-x._.js +0 -3
  547. package/.next/server/chunks/_1230wbx._.js +0 -10
  548. package/.next/server/chunks/_12nheja._.js +0 -3
  549. package/.next/server/chunks/_13510xh._.js +0 -3
  550. package/.next/server/chunks/_15hq89o._.js +0 -3
  551. package/.next/server/chunks/_18-1wcc._.js +0 -55
  552. package/.next/server/chunks/_1_9mjx-._.js +0 -3
  553. package/.next/server/chunks/_1c78vw5._.js +0 -229
  554. package/.next/server/chunks/_1h5_8sk._.js +0 -3
  555. package/.next/server/chunks/_1hdnxb7._.js +0 -3
  556. package/.next/server/chunks/_1j8k_j5._.js +0 -3
  557. package/.next/server/chunks/_1nula3v._.js +0 -3
  558. package/.next/server/chunks/_1php4eq._.js +0 -3
  559. package/.next/server/chunks/_1yuv4vp._.js +0 -3
  560. package/.next/server/chunks/_1zjrdag._.js +0 -3
  561. package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
  562. package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
  563. package/.next/server/chunks/features_0rpfxbk._.js +0 -3
  564. package/.next/server/chunks/features_1qf3cei._.js +0 -3
  565. package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
  566. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +0 -3
  567. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
  568. package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
  569. package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
  570. package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
  571. package/.next/server/chunks/ssr/[root-of-the-server]__0s9l2sv._.js +0 -3
  572. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
  573. package/.next/server/chunks/ssr/[root-of-the-server]__0xsog8n._.js +0 -3
  574. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
  575. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +0 -43
  576. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +0 -4
  577. package/.next/server/chunks/ssr/[root-of-the-server]__202p40z._.js +0 -3
  578. package/.next/server/chunks/ssr/_001_ms1._.js +0 -28
  579. package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
  580. package/.next/server/chunks/ssr/_0fz4mf_._.js +0 -3
  581. package/.next/server/chunks/ssr/_0gb4gmf._.js +0 -3
  582. package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
  583. package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
  584. package/.next/server/chunks/ssr/_0ilna52._.js +0 -42
  585. package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
  586. package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
  587. package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
  588. package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
  589. package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
  590. package/.next/server/chunks/ssr/_1b2mjwr._.js +0 -3
  591. package/.next/server/chunks/ssr/_1f-dg-6._.js +0 -3
  592. package/.next/server/chunks/ssr/_1h0rw11._.js +0 -3
  593. package/.next/server/chunks/ssr/_1jhd09t._.js +0 -3
  594. package/.next/server/chunks/ssr/_1nnsk7z._.js +0 -3
  595. package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
  596. package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
  597. package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
  598. package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
  599. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  600. package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
  601. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  602. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
  603. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
  604. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
  605. package/.next/static/chunks/00rd4-v8r7axp.js +0 -1
  606. package/.next/static/chunks/08qe4as2q428z.js +0 -3
  607. package/.next/static/chunks/0gnqdjn2lvdad.js +0 -2
  608. package/.next/static/chunks/0hwap1-p0m5sa.js +0 -1
  609. package/.next/static/chunks/0r5qcctujhxli.js +0 -1
  610. package/.next/static/chunks/0w52rrrmuj9r9.js +0 -1
  611. package/.next/static/chunks/0wcprt5ot5she.js +0 -1
  612. package/.next/static/chunks/10teww7wt-f6h.js +0 -1
  613. package/.next/static/chunks/17p6tk6k88dq6.js +0 -1
  614. package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
  615. package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
  616. package/.next/static/chunks/1jd09sxcjddu1.js +0 -1
  617. package/.next/static/chunks/1w73ece_6bheu.js +0 -18
  618. package/.next/static/chunks/214ya3n5gxeih.js +0 -1
  619. package/.next/static/chunks/22_zkas21rpna.js +0 -1
  620. package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
  621. package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
  622. package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
  623. package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
  624. package/.next/static/chunks/2u7xt6mxg44lf.js +0 -1
  625. package/.next/static/chunks/3786h5vayt80-.js +0 -28
  626. package/.next/static/chunks/39j0fvpybzabl.js +0 -40
  627. package/.next/static/chunks/3cq5g494yuke8.css +0 -1
  628. package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
  629. package/.next/static/chunks/3woj-xd7ki5_i.js +0 -1
  630. package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
  631. package/.next/static/chunks/3zmcsnuo25zvq.js +0 -1
  632. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
  633. package/docs/images/task-thread.png +0 -0
  634. package/features/bot/components/task-badge.tsx +0 -42
  635. package/features/bot/components/task-reply.tsx +0 -328
  636. package/features/bot/components/task-setting.tsx +0 -524
  637. package/features/bot/task.query.ts +0 -976
  638. package/features/bot/task.store.ts +0 -489
  639. package/lib/realtime/client-secret.ts +0 -86
  640. package/lib/realtime/open-session.ts +0 -31
  641. package/lib/realtime/openai.ts +0 -35
  642. package/lib/realtime/realtime.audio.ts +0 -196
  643. package/lib/realtime/realtime.driver.ts +0 -489
  644. package/lib/realtime/realtime.protocol.ts +0 -393
  645. package/lib/realtime/realtime.schema.ts +0 -37
  646. package/lib/realtime/realtime.session.ts +0 -106
  647. package/lib/realtime/realtime.transport.ts +0 -384
  648. package/lib/realtime/xai.ts +0 -39
  649. /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
  650. /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
  651. /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
  652. /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
  653. /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
  654. /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
  655. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_buildManifest.js +0 -0
  656. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_clientMiddlewareManifest.js +0 -0
  657. /package/.next/static/{kaTO0UHqF1bMnWgCDik2f → 0qzGoKn2wTERVZtblX1tp}/_ssgManifest.js +0 -0
@@ -1,8 +1,14 @@
1
1
  "use client";
2
2
 
3
3
  import { useEffect, useId, useMemo, useRef } from "react";
4
- import { createVoiceFollower } from "@/lib/realtime/realtime.tap";
5
- import { MARK_BANDS, type MarkShape } from "../mark.const";
4
+ import { createVoiceFollower, SPECTRUM_BANDS } from "@/lib/live/live.tap";
5
+ import {
6
+ MARK_PAINTS,
7
+ type MarkPaint,
8
+ type MarkPaintLook,
9
+ type MarkPaintSpec,
10
+ type MarkShape,
11
+ } from "../mark.const";
6
12
 
7
13
  // Procedural bot avatar: a generated silhouette with two eyes, animated per frame from refs.
8
14
 
@@ -121,6 +127,22 @@ function polyOutline(sides: number, cornerRatio: number, rotDeg: number): Pt[] {
121
127
  return out;
122
128
  }
123
129
 
130
+ /** The classic heart curve, a little taller than wide. */
131
+ function heartOutline(): Pt[] {
132
+ const out: Pt[] = [];
133
+ for (let i = 0; i < 400; i++) {
134
+ const t = (i / 400) * TAU;
135
+ const x = 16 * Math.sin(t) ** 3;
136
+ const y =
137
+ 13 * Math.cos(t) -
138
+ 5 * Math.cos(2 * t) -
139
+ 2 * Math.cos(3 * t) -
140
+ Math.cos(4 * t);
141
+ out.push([CENTER + x * 6.6, CENTER - (y + 2.2) * 7.26]);
142
+ }
143
+ return out;
144
+ }
145
+
124
146
  function sub(a: Pt, b: Pt): Pt {
125
147
  return [a[0] - b[0], a[1] - b[1]];
126
148
  }
@@ -266,38 +288,23 @@ export type MarkOptions = {
266
288
  stretch: number;
267
289
  idle: boolean;
268
290
  liveliness: number;
269
- glance: number;
270
291
  float: number;
271
292
  breathe: number;
272
293
  speed: number;
273
294
  blink: boolean;
274
295
 
275
- /** Peak opacity of the soft shadow that swells under the mark while thinking, percent. 0 disables. */
276
- shadow: number;
277
- /** Soft halo around the silhouette, cut out of the head; blur radius in view-box units. 0 disables. */
278
- glow: number;
279
- /** Aura color. null follows the mark color. */
280
- glowColor: string | null;
281
- /** Aura opacity, percent. */
282
- glowStrength: number;
283
- /** Border around the silhouette so it still reads on a same-colored background. 0 disables. */
284
- rim: number;
285
- /** Defaults to the theme text color, the one color guaranteed to differ from the background. */
286
- rimColor: string;
287
-
288
296
  notify: boolean;
289
297
  notifyAngle: number;
290
298
  notifyDist: number;
291
299
  notifyR: number;
292
300
  notifyRing: number;
293
- notifyColor: string;
294
301
  };
295
302
 
296
303
  const MARK_DEFAULTS: MarkOptions = {
297
304
  shape: "blob",
298
305
  sides: 3,
299
306
  corner: 0.74,
300
- rotation: -180,
307
+ rotation: 0,
301
308
  squircle: 4.6,
302
309
  wobble: 0.2,
303
310
  seed: 113,
@@ -328,53 +335,18 @@ const MARK_DEFAULTS: MarkOptions = {
328
335
  stretch: 15,
329
336
  idle: true,
330
337
  liveliness: 55,
331
- glance: 22,
332
338
  float: 7,
333
339
  breathe: 3.7,
334
340
  speed: 1.7,
335
341
  blink: true,
336
342
 
337
- shadow: 16,
338
- glow: 0,
339
- glowColor: null,
340
- glowStrength: 55,
341
- rim: 0,
342
- rimColor: "currentColor",
343
-
344
343
  notify: false,
345
344
  notifyAngle: 41,
346
345
  notifyDist: 109,
347
346
  notifyR: 25,
348
347
  notifyRing: 11,
349
- notifyColor: "#FF3B30",
350
348
  };
351
349
 
352
- /* Per-instance variation: shape and color stay, only the values inside the shape roll
353
- * from a seed the caller picks (task id for one face per task, bot name for one per bot). */
354
- const VARY = {
355
- /** Blob depth. The seed already changes the whole silhouette, so keep this slight. */
356
- wobble: [0.8, 1.35],
357
- /** Poly. Below 0.45 it rounds into a circle. */
358
- corner: [0.45, 0.77],
359
- rotation: [-180, 180],
360
- /** Squircle. 4 is nearly square, 12 nearly round. */
361
- squircle: [4, 12],
362
- } as const satisfies Record<string, readonly [number, number]>;
363
-
364
- /** Roll order defines what a seed means; reordering changes every bot's face. */
365
- function varyOptions(cfg: MarkOptions, seed: number): MarkOptions {
366
- if (!seed) return cfg;
367
- const rnd = mulberry32(seed);
368
- const pick = ([lo, hi]: readonly [number, number]) => lo + rnd() * (hi - lo);
369
- return {
370
- ...cfg,
371
- wobble: cfg.wobble * pick(VARY.wobble),
372
- corner: pick(VARY.corner),
373
- rotation: pick(VARY.rotation),
374
- squircle: pick(VARY.squircle),
375
- };
376
- }
377
-
378
350
  /** Silhouettes are scaled to the area of the circle of radius R so they read the same size,
379
351
  * capped so sharp corners stay inside the view box. */
380
352
  const FIT_LIMIT = 130;
@@ -400,7 +372,7 @@ function fitRadii(radii: number[]): number[] {
400
372
  const WARP = 0.035;
401
373
 
402
374
  /** Bends a ruled outline by a few slow waves. Blob outlines already wobble and are left alone. */
403
- function warpRadii(radii: number[], seed: number): number[] {
375
+ function warpRadii(radii: number[], seed: number, depth = WARP): number[] {
404
376
  const rnd = mulberry32(seed ^ 0x2f6b);
405
377
  const waves = [2, 3, 5].map((k) => ({
406
378
  k,
@@ -414,7 +386,33 @@ function warpRadii(radii: number[], seed: number): number[] {
414
386
  return d;
415
387
  });
416
388
  const peak = Math.max(...offsets.map(Math.abs)) || 1;
417
- return radii.map((r, i) => r * (1 + (WARP * offsets[i]) / peak));
389
+ return radii.map((r, i) => r * (1 + (depth * offsets[i]) / peak));
390
+ }
391
+
392
+ /**
393
+ * A true heart has the only sharp tip and deep notch of any mark. Averaging the
394
+ * radii blunts both, then it bends and leans by the seed like poly and squircle
395
+ * do, a little more.
396
+ */
397
+ function softenHeart(radii: number[], seed: number): number[] {
398
+ let soft = radii;
399
+ for (let pass = 0; pass < 2; pass++) {
400
+ const prev = soft;
401
+ soft = prev.map((_, i) => {
402
+ let sum = 0;
403
+ for (let k = -3; k <= 3; k++) sum += prev[(i + k + RES) % RES];
404
+ return sum / 7;
405
+ });
406
+ }
407
+ const mean = soft.reduce((sum, r) => sum + r, 0) / RES;
408
+ const bent = warpRadii(
409
+ soft.map((r) => r * 0.95 + mean * 0.05),
410
+ seed,
411
+ 0.05,
412
+ );
413
+ // A few degrees of lean, one sample at a time.
414
+ const lean = Math.round((mulberry32(seed ^ 0x51f1)() * 2 - 1) * 3);
415
+ return lean ? bent.map((_, i) => bent[(i - lean + RES * 2) % RES]) : bent;
418
416
  }
419
417
 
420
418
  const radiiCache = new Map<string, number[]>();
@@ -426,12 +424,19 @@ function radiiFor(cfg: MarkOptions, shape: MarkShape, seed: number): number[] {
426
424
  ? `poly|${cfg.sides}|${cfg.corner}|${cfg.rotation}|${seed}`
427
425
  : shape === "squircle"
428
426
  ? `squircle|${cfg.squircle}|${seed}`
429
- : `blob|${cfg.wobble}|${seed}`
427
+ : shape === "heart"
428
+ ? `heart|${seed}`
429
+ : `blob|${cfg.wobble}|${seed}`
430
430
  }|${cfg.autofit}`;
431
431
  const hit = radiiCache.get(key);
432
432
  if (hit) return hit;
433
433
  const traced = toRadii(outlineFor(cfg, shape, seed));
434
- const raw = shape === "blob" ? traced : warpRadii(traced, seed);
434
+ const raw =
435
+ shape === "blob"
436
+ ? traced
437
+ : shape === "heart"
438
+ ? softenHeart(traced, seed)
439
+ : warpRadii(traced, seed);
435
440
  const radii = cfg.autofit ? fitRadii(raw) : raw;
436
441
  if (radiiCache.size > 400) radiiCache.clear();
437
442
  radiiCache.set(key, radii);
@@ -441,9 +446,82 @@ function radiiFor(cfg: MarkOptions, shape: MarkShape, seed: number): number[] {
441
446
  function outlineFor(cfg: MarkOptions, shape: MarkShape, seed: number): Pt[] {
442
447
  if (shape === "squircle") return squircleOutline(cfg.squircle);
443
448
  if (shape === "poly") return polyOutline(cfg.sides, cfg.corner, cfg.rotation);
449
+ if (shape === "heart") return heartOutline();
444
450
  return blobOutline(seed, cfg.wobble);
445
451
  }
446
452
 
453
+ /**
454
+ * Where a mark sits between the smallest the app draws (14px, 0) and the bot
455
+ * page's 112px (1). The SVG scales evenly, but a small face has fewer pixels for
456
+ * each band, so paints and a crossed-out X are drawn denser as this falls.
457
+ */
458
+ const growOf = (size: number) => clamp((size - 14) / 98, 0, 1);
459
+
460
+ /** One run of the sliding rainbow: shorter on small marks, so more of its colours fit. */
461
+ const spanOf = (grow: number) => 345 * (0.7 + 0.3 * grow);
462
+
463
+ /** Where each look's gradient runs, in the 240-unit box. */
464
+ function paintAxis(
465
+ look: MarkPaintLook,
466
+ grow: number,
467
+ ): Pick<
468
+ React.SVGProps<SVGLinearGradientElement>,
469
+ "gradientUnits" | "x1" | "y1" | "x2" | "y2" | "spreadMethod"
470
+ > {
471
+ if (look === "flow") {
472
+ return {
473
+ gradientUnits: "userSpaceOnUse",
474
+ x1: 0,
475
+ y1: 0,
476
+ x2: spanOf(grow),
477
+ y2: 0,
478
+ spreadMethod: "repeat",
479
+ };
480
+ }
481
+ // In box units like the rest, so the wider blurred layer wears the same ramp as the head.
482
+ return {
483
+ gradientUnits: "userSpaceOnUse",
484
+ x1: 0,
485
+ y1: 0,
486
+ x2: look === "duo" ? BOX : 0,
487
+ y2: BOX,
488
+ };
489
+ }
490
+
491
+ /** A paint's stops. Aurora's gradient is only its night. */
492
+ function paintStops({
493
+ look,
494
+ colors,
495
+ }: MarkPaintSpec): { offset: number; color: string }[] {
496
+ const used = look === "aurora" ? colors.slice(0, 2) : colors;
497
+ return used.map((color, i) => ({ offset: i / (used.length - 1), color }));
498
+ }
499
+
500
+ /** Aurora's curtains: where each hangs, how far it sways and how long one sway takes (s). */
501
+ const CURTAINS = [
502
+ { cx: 42, sway: 40, period: 5 },
503
+ { cx: 134, sway: -35, period: 6.5 },
504
+ { cx: 209, sway: 29, period: 4.5 },
505
+ ];
506
+ const CURTAIN_Y = 91;
507
+ /** Curtains grow broader and softer on small marks, so they read as a glow, not a stripe. */
508
+ const curtainRxOf = (grow: number) => 60 - 29 * grow;
509
+ const curtainBlurOf = (grow: number) => 34 - 12 * grow;
510
+
511
+ /** Below this relative luminance a body sinks into a dark page. */
512
+ const DARK_BODY = 0.06;
513
+
514
+ /** Relative luminance of a #rrggbb colour; null for anything else (currentColor follows the theme). */
515
+ function luminance(color: string): number | null {
516
+ const hex = /^#([0-9a-f]{6})$/i.exec(color);
517
+ if (!hex) return null;
518
+ const channel = (at: number) => {
519
+ const c = Number.parseInt(hex[1].slice(at, at + 2), 16) / 255;
520
+ return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
521
+ };
522
+ return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4);
523
+ }
524
+
447
525
  /* Idle beats: small unrelated motions picked at random, weighted by state. Each returns
448
526
  * per-frame channel offsets for progress p in 0..1 and a direction. `eyeLen`/`eyeWid`
449
527
  * scale along the eye's own axis, so they still mean shorter/wider when the eye is tilted. */
@@ -762,8 +840,6 @@ type StateShape = {
762
840
  /** Constant gaze offset, box units, on top of pointer tracking and drift. */
763
841
  gazeX: number;
764
842
  gazeY: number;
765
- /** 1 lets the shadow through, 0 blocks it; eased like the other channels. */
766
- shadow: number;
767
843
  };
768
844
 
769
845
  /** Resting-pose targets per state. */
@@ -777,7 +853,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
777
853
  breathe: 1,
778
854
  float: 1,
779
855
  blink: 1,
780
- shadow: 0,
781
856
  lean: 0,
782
857
  aspect: 1,
783
858
  gazeX: 0,
@@ -792,7 +867,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
792
867
  breathe: 2.2,
793
868
  float: 0.6,
794
869
  blink: 0.6,
795
- shadow: 0,
796
870
  lean: 0,
797
871
  aspect: 1.03,
798
872
  gazeX: 0,
@@ -807,7 +881,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
807
881
  breathe: 0.45,
808
882
  float: 0.35,
809
883
  blink: 1.8,
810
- shadow: 0,
811
884
  lean: 0,
812
885
  aspect: 0.97,
813
886
  gazeX: 0,
@@ -822,7 +895,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
822
895
  breathe: 1.3,
823
896
  float: 1.4,
824
897
  blink: 0.8,
825
- shadow: 1,
826
898
  lean: 7,
827
899
  aspect: 1.04,
828
900
  gazeX: -9,
@@ -837,7 +909,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
837
909
  breathe: 0.6,
838
910
  float: 0.5,
839
911
  blink: 1.3,
840
- shadow: 0,
841
912
  lean: -6,
842
913
  aspect: 1,
843
914
  gazeX: 15,
@@ -854,7 +925,6 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
854
925
  breathe: 0.4,
855
926
  float: 0.5,
856
927
  blink: 1.2,
857
- shadow: 0,
858
928
  lean: 0,
859
929
  aspect: 1,
860
930
  gazeX: 0,
@@ -863,7 +933,7 @@ const STATE_SHAPE: Record<MarkState, StateShape> = {
863
933
  };
864
934
 
865
935
  /** What the follower reads while the mark is not speaking. */
866
- const SILENT: number[] = new Array<number>(MARK_BANDS).fill(0);
936
+ const SILENT: number[] = new Array<number>(SPECTRUM_BANDS).fill(0);
867
937
 
868
938
  /**
869
939
  * Milliseconds to the next blink, irregular the way a person's are: mostly a
@@ -902,23 +972,19 @@ export type BotMarkProps = {
902
972
  seed?: number | string;
903
973
  color?: string;
904
974
  shape?: MarkShape;
905
- /**
906
- * Nudges this instance's silhouette (VARY) while keeping shape and color. A value is
907
- * the seed (task id or bot name); `true` uses useId so server and client agree.
908
- */
909
- vary?: boolean | number | string;
910
975
  /** Stroke instead of fill; same as `options.fill: false`. */
911
976
  outline?: boolean;
977
+ /** A paint (MARK_PAINTS) worn in place of `color`. */
978
+ paint?: MarkPaint;
912
979
  notify?: boolean;
980
+ /** Eyes crossed out: a stopped thread, or a call that failed. */
981
+ crossed?: boolean;
913
982
  state?: MarkState;
914
- /** Read once per animation frame. Use this for live audio instead of React state. */
915
- getLevel?: () => number;
916
- /** MARK_BANDS values in 0..1, low frequencies first, read once per frame. Where the energy sits sets the shape, how much sets the size. */
983
+ /** SPECTRUM_BANDS values in 0..1, low frequencies first, read once per frame. Where the energy sits sets the shape, how much sets the size. */
917
984
  getSpectrum?: () => ArrayLike<number>;
918
985
  /** Per-instance overrides; omitted keys fall back to MARK_DEFAULTS. Pass a stable object, a new literal each render re-derives the silhouette. */
919
986
  options?: Partial<MarkOptions>;
920
987
  className?: string;
921
- svgRef?: React.RefObject<SVGSVGElement | null>;
922
988
  };
923
989
 
924
990
  /** Cheap string hash so a name or id can seed the mark. */
@@ -936,62 +1002,56 @@ export function BotMark({
936
1002
  seed,
937
1003
  color,
938
1004
  shape,
939
- vary,
940
1005
  outline,
1006
+ paint,
941
1007
  notify,
1008
+ crossed,
942
1009
  state = "idle",
943
- getLevel,
944
1010
  getSpectrum,
945
1011
  options,
946
1012
  className,
947
- svgRef,
948
1013
  }: BotMarkProps) {
949
1014
  const clipId = useId();
950
- // 0 means no variation. `true` falls back to useId, the only per-instance value
951
- // server and client agree on.
952
- const varySeed = useMemo(() => {
953
- if (vary === undefined || vary === false) return 0;
954
- return hashSeed(vary === true ? clipId : vary) || 1;
955
- }, [vary, clipId]);
956
1015
  const cfg = useMemo(
957
1016
  () =>
958
- varyOptions(
959
- {
960
- ...MARK_DEFAULTS,
961
- ...options,
962
- ...(outline === undefined ? {} : { fill: !outline }),
963
- } as MarkOptions,
964
- varySeed,
965
- ),
966
- [options, outline, varySeed],
1017
+ ({
1018
+ ...MARK_DEFAULTS,
1019
+ ...options,
1020
+ ...(outline === undefined ? {} : { fill: !outline }),
1021
+ }) as MarkOptions,
1022
+ [options, outline],
967
1023
  );
968
- const glowId = `${clipId}-glow`;
969
- const haloId = `${clipId}-halo`;
970
1024
  const maskId = `${clipId}-mask`;
971
- const shadowId = `${clipId}-shadow`;
1025
+ const paintId = `${clipId}-paint`;
1026
+ const curtainId = `${clipId}-curtain`;
972
1027
  const lifeRef = useRef<SVGGElement>(null);
973
1028
  const eyesRef = useRef<SVGGElement>(null);
974
1029
  const headRef = useRef<SVGPathElement>(null);
975
1030
  const clipRef = useRef<SVGPathElement>(null);
976
1031
  const eyeLRef = useRef<SVGGElement>(null);
977
1032
  const eyeRRef = useRef<SVGGElement>(null);
978
- const glowRef = useRef<SVGPathElement>(null);
979
- const haloHeadRef = useRef<SVGPathElement>(null);
980
- const shadowRef = useRef<SVGPathElement>(null);
981
1033
  const maskHeadRef = useRef<SVGPathElement>(null);
982
- const rimRef = useRef<SVGPathElement>(null);
983
- const localSvg = useRef<SVGSVGElement>(null);
984
- const svg = svgRef ?? localSvg;
985
-
986
- const theSeed = seed === undefined ? cfg.seed : hashSeed(seed);
987
- // Blob silhouettes come from the seed, so variation goes through the seed too; the
988
- // idle phase splits here so neighboring marks do not breathe in sync.
989
- const shapeSeed = varySeed
990
- ? ((theSeed ^ Math.imul(varySeed, 0x9e3779b1)) >>> 0) % 10000
991
- : theSeed;
1034
+ const paintRef = useRef<SVGLinearGradientElement>(null);
1035
+ const curtainRefs = useRef<(SVGEllipseElement | null)[]>([]);
1036
+ const inkEyesRef = useRef<SVGGElement>(null);
1037
+ const inkEyeLRef = useRef<SVGGElement>(null);
1038
+ const inkEyeRRef = useRef<SVGGElement>(null);
1039
+ const svgRef = useRef<SVGSVGElement>(null);
1040
+
1041
+ const shapeSeed = seed === undefined ? cfg.seed : hashSeed(seed);
992
1042
  const theShape = shape ?? cfg.shape;
993
1043
  const theFg = color ?? cfg.color;
994
1044
  const notifying = notify ?? cfg.notify;
1045
+ const spec = paint ? MARK_PAINTS[paint] : null;
1046
+ const grow = growOf(size);
1047
+ // A dark body draws its eyes: as holes they show the dark page it sinks into.
1048
+ const edge = spec
1049
+ ? "edge" in spec
1050
+ ? spec.edge
1051
+ : null
1052
+ : (luminance(theFg) ?? 1) < DARK_BODY
1053
+ ? "dark"
1054
+ : null;
995
1055
 
996
1056
  // While deforming, the head is redrawn per frame; memo only seeds the initial `d`.
997
1057
  const radii = useMemo(
@@ -1031,8 +1091,28 @@ export function BotMark({
1031
1091
  // the tree at 60 fps. `radii` and `shapeSeed` go through the ref rather than the
1032
1092
  // effect deps: the loop mounts once, and restarting it on a seed change (the create
1033
1093
  // form retypes the name) would snap the eyes and reset the blink and breath phase.
1034
- const live = useRef({ cfg, state, getLevel, getSpectrum, radii, shapeSeed });
1035
- live.current = { cfg, state, getLevel, getSpectrum, radii, shapeSeed };
1094
+ const look = spec?.look ?? null;
1095
+ const eyesOut = Boolean(crossed);
1096
+ const live = useRef({
1097
+ cfg,
1098
+ state,
1099
+ getSpectrum,
1100
+ radii,
1101
+ shapeSeed,
1102
+ look,
1103
+ crossed: eyesOut,
1104
+ grow,
1105
+ });
1106
+ live.current = {
1107
+ cfg,
1108
+ state,
1109
+ getSpectrum,
1110
+ radii,
1111
+ shapeSeed,
1112
+ look,
1113
+ crossed: eyesOut,
1114
+ grow,
1115
+ };
1036
1116
 
1037
1117
  useEffect(() => {
1038
1118
  bindPointer();
@@ -1050,20 +1130,18 @@ export function BotMark({
1050
1130
  // STATE_SHAPE values are targets, eased over about 0.6 s.
1051
1131
  const shape = { ...STATE_SHAPE.idle };
1052
1132
  const SHAPE_KEYS = Object.keys(shape) as (keyof StateShape)[];
1053
- // Three time scales: ~50 ms to catch a syllable, ~300 ms to know one just happened,
1054
- // ~1 s to know speech is ongoing.
1133
+ // Two time scales: ~50 ms to catch a syllable, ~1 s to know speech is ongoing.
1055
1134
  let fastLvl = 0;
1056
- let midLvl = 0;
1057
1135
  let lvl = 0;
1058
1136
  let bright = 0.5;
1059
1137
  // Syllable-kicked spring; its own frequency caps how fast the mark can move.
1060
1138
  let bob = 0;
1061
1139
  let bobVel = 0;
1062
1140
  let lastOnset = 0;
1063
- const band = new Array<number>(MARK_BANDS).fill(0);
1141
+ const band = new Array<number>(SPECTRUM_BANDS).fill(0);
1064
1142
  // Each harmonic rotates at its own speed, alternating direction, so the deformation
1065
1143
  // never settles into a standing wave.
1066
- const bandPhase = Array.from({ length: MARK_BANDS }, (_, k) => k * 1.7);
1144
+ const bandPhase = Array.from({ length: SPECTRUM_BANDS }, (_, k) => k * 1.7);
1067
1145
  // Integrated, never `time * speed`: `churnSpeed` eases between states, and
1068
1146
  // phase = elapsed * speed would sweep the whole elapsed time on every speed change.
1069
1147
  let churnPhase = 0;
@@ -1097,7 +1175,7 @@ export function BotMark({
1097
1175
  // still; each band inside its own recent range moves with the words.
1098
1176
  const heard = voice.read(spec ?? SILENT, dt);
1099
1177
  let specSum = 0;
1100
- for (let k = 0; k < MARK_BANDS; k++) {
1178
+ for (let k = 0; k < SPECTRUM_BANDS; k++) {
1101
1179
  const target = heard.bands[k];
1102
1180
  // Bands set the shape, so smooth hard; faster and small marks shimmer.
1103
1181
  band[k] += (target - band[k]) * c.bandEase;
@@ -1105,21 +1183,14 @@ export function BotMark({
1105
1183
  specSum += target;
1106
1184
  }
1107
1185
 
1108
- const given = live.current.getLevel?.();
1109
- const want = st === "speaking" ? clamp(given ?? heard.level, 0, 1) : 0;
1186
+ const want = st === "speaking" ? clamp(heard.level, 0, 1) : 0;
1110
1187
 
1111
1188
  fastLvl += (want - fastLvl) * 0.3;
1112
- midLvl += (want - midLvl) * 0.055;
1113
1189
  lvl += (want - lvl) * 0.016;
1114
1190
 
1115
- // A syllable is a rise over the recent average: the follower's for a
1116
- // spectrum, this one's for a bare level. The gap must exceed the spring
1191
+ // A syllable is the follower's onset. The gap must exceed the spring
1117
1192
  // period or kicks pile up into a tremble.
1118
- const syllable =
1119
- given === undefined
1120
- ? heard.onset > 0
1121
- : fastLvl > midLvl * 1.25 + 0.03 && fastLvl > 0.09;
1122
- if (syllable && now - lastOnset > 340) {
1193
+ if (heard.onset > 0 && now - lastOnset > 340) {
1123
1194
  lastOnset = now;
1124
1195
  // Slower springs integrate each impulse longer, so scale the kick with stiffness.
1125
1196
  bobVel -= c.punch * Math.min(1, fastLvl * 1.6) * c.bobRate;
@@ -1133,8 +1204,8 @@ export function BotMark({
1133
1204
  // that changes per phoneme reads as flicker.
1134
1205
  if (specSum > 0.04) {
1135
1206
  let weighted = 0;
1136
- for (let k = 0; k < MARK_BANDS; k++) weighted += band[k] * k;
1137
- bright += (weighted / specSum / (MARK_BANDS - 1) - bright) * 0.04;
1207
+ for (let k = 0; k < SPECTRUM_BANDS; k++) weighted += band[k] * k;
1208
+ bright += (weighted / specSum / (SPECTRUM_BANDS - 1) - bright) * 0.04;
1138
1209
  } else {
1139
1210
  bright += (0.5 - bright) * 0.03;
1140
1211
  }
@@ -1172,14 +1243,6 @@ export function BotMark({
1172
1243
  }
1173
1244
  }
1174
1245
 
1175
- if (shadowRef.current) {
1176
- const swell = 0.5 - 0.5 * Math.cos(t * 0.55);
1177
- shadowRef.current.setAttribute(
1178
- "opacity",
1179
- f((shape.shadow * swell * c.shadow) / 100).toString(),
1180
- );
1181
- }
1182
-
1183
1246
  if (lifeRef.current) {
1184
1247
  const amp = (c.breathe * shape.breathe) / 100;
1185
1248
  const swell = (lvl * c.pulse) / 300 - bob * 0.05;
@@ -1208,6 +1271,28 @@ export function BotMark({
1208
1271
  );
1209
1272
  }
1210
1273
 
1274
+ // Paints run on plain seconds, not `c.speed`: they are surface, not mood.
1275
+ const paintLook = live.current.look;
1276
+ if (paintLook) {
1277
+ const secs = now / 1000;
1278
+ const grow = live.current.grow;
1279
+ if (paintLook === "flow") {
1280
+ // Slanted and sliding one run every 3.6 s, so the colours meet at no point.
1281
+ paintRef.current?.setAttribute(
1282
+ "gradientTransform",
1283
+ `rotate(-35 ${CENTER} ${CENTER}) translate(${f(-((secs / 3.6) % 1) * spanOf(grow))} 0)`,
1284
+ );
1285
+ } else if (paintLook === "aurora") {
1286
+ for (const [i, curtain] of CURTAINS.entries()) {
1287
+ const e = 0.5 - 0.5 * Math.cos((secs / curtain.period) * TAU);
1288
+ curtainRefs.current[i]?.setAttribute(
1289
+ "transform",
1290
+ `translate(${f(curtain.sway * e)} 0) translate(${curtain.cx} ${CURTAIN_Y}) skewX(${f(20 * e - 10)}) scale(1 ${f(1 + 0.18 * e)}) translate(${-curtain.cx} ${-CURTAIN_Y})`,
1291
+ );
1292
+ }
1293
+ }
1294
+ }
1295
+
1211
1296
  // Eight bands folded into three, driving harmonics 2..4 only; higher harmonics on
1212
1297
  // an already bumpy silhouette read as noise.
1213
1298
  const lowE = (band[0] + band[1] + band[2]) / 3;
@@ -1241,18 +1326,14 @@ export function BotMark({
1241
1326
  const d = radiiToPath(next);
1242
1327
  headRef.current.setAttribute("d", d);
1243
1328
  clipRef.current?.setAttribute("d", d);
1244
- glowRef.current?.setAttribute("d", d);
1245
- haloHeadRef.current?.setAttribute("d", d);
1246
- shadowRef.current?.setAttribute("d", d);
1247
- rimRef.current?.setAttribute("d", d);
1248
1329
  maskHeadRef.current?.setAttribute("d", d);
1249
1330
  }
1250
1331
 
1251
1332
  if (eyesRef.current) {
1252
1333
  let tgx = 0;
1253
1334
  let tgy = 0;
1254
- if (c.follow && pointer.live && svg.current) {
1255
- const r = svg.current.getBoundingClientRect();
1335
+ if (c.follow && pointer.live && svgRef.current) {
1336
+ const r = svgRef.current.getBoundingClientRect();
1256
1337
  if (r.width > 0) {
1257
1338
  tgx =
1258
1339
  clamp(
@@ -1278,7 +1359,8 @@ export function BotMark({
1278
1359
  0.38 * Math.sin(t * 0.47 + phase * 2.1));
1279
1360
 
1280
1361
  let sy = 1;
1281
- if (blinkStart === 0) {
1362
+ // Crossed-out eyes do not blink.
1363
+ if (blinkStart === 0 && !live.current.crossed) {
1282
1364
  if (queuedBlink > 0 && now >= queuedBlink) {
1283
1365
  blinkStart = now;
1284
1366
  queuedBlink = 0;
@@ -1297,10 +1379,9 @@ export function BotMark({
1297
1379
  sy = 1 - Math.sin(Math.PI * p) * 0.94;
1298
1380
  }
1299
1381
  }
1300
- eyesRef.current.setAttribute(
1301
- "transform",
1302
- `translate(${f(gx + act.eyeX + shape.gazeX)} ${f(gy + drift + act.eyeY + shape.gazeY)}) translate(${CENTER} ${c.eyeY}) scale(1 ${sy.toFixed(3)}) translate(${-CENTER} ${-c.eyeY})`,
1303
- );
1382
+ const eyesAt = `translate(${f(gx + act.eyeX + shape.gazeX)} ${f(gy + drift + act.eyeY + shape.gazeY)}) translate(${CENTER} ${c.eyeY}) scale(1 ${sy.toFixed(3)}) translate(${-CENTER} ${-c.eyeY})`;
1383
+ eyesRef.current.setAttribute("transform", eyesAt);
1384
+ inkEyesRef.current?.setAttribute("transform", eyesAt);
1304
1385
 
1305
1386
  // Each eye scales about its own center; scaling both together widens the gap instead.
1306
1387
  const eyeWid = act.eyeWid * (1 - lvl * 0.13) * shape.eyes;
@@ -1315,9 +1396,11 @@ export function BotMark({
1315
1396
  const tilt = i === 0 ? c.eyeTilt : c.eyeTilt + c.eyeSkew;
1316
1397
  const len = eyeLen.toFixed(3);
1317
1398
  const wid = eyeWid.toFixed(3);
1318
- ref.current.setAttribute(
1399
+ const eyeAt = `translate(${f(cx)} ${c.eyeY}) rotate(${f(tilt)}) scale(${len} ${wid}) rotate(${f(-tilt)}) translate(${f(-cx)} ${-c.eyeY})`;
1400
+ ref.current.setAttribute("transform", eyeAt);
1401
+ (i === 0 ? inkEyeLRef : inkEyeRRef).current?.setAttribute(
1319
1402
  "transform",
1320
- `translate(${f(cx)} ${c.eyeY}) rotate(${f(tilt)}) scale(${len} ${wid}) rotate(${f(-tilt)}) translate(${f(-cx)} ${-c.eyeY})`,
1403
+ eyeAt,
1321
1404
  );
1322
1405
  }
1323
1406
  }
@@ -1325,13 +1408,29 @@ export function BotMark({
1325
1408
 
1326
1409
  raf = requestAnimationFrame(tick);
1327
1410
  return () => cancelAnimationFrame(raf);
1328
- }, [svg]);
1411
+ }, []);
1329
1412
 
1330
1413
  const nAngle = (cfg.notifyAngle * Math.PI) / 180;
1414
+ const ink = spec ? `url(#${paintId})` : "var(--fg)";
1415
+ // Smaller marks get a thicker, wider X: at 18px the 112px stroke is under a pixel.
1416
+ const xHalf = f(18 - 3 * grow);
1417
+ const xStroke = f(22 - 9 * grow);
1418
+ const eye = (d: string, cx: number, color: string) =>
1419
+ eyesOut ? (
1420
+ <path
1421
+ d={`M${cx - xHalf} ${cfg.eyeY - xHalf}L${cx + xHalf} ${cfg.eyeY + xHalf}M${cx + xHalf} ${cfg.eyeY - xHalf}L${cx - xHalf} ${cfg.eyeY + xHalf}`}
1422
+ fill="none"
1423
+ stroke={color}
1424
+ strokeWidth={xStroke}
1425
+ strokeLinecap="round"
1426
+ />
1427
+ ) : (
1428
+ <path d={d} fill={color} />
1429
+ );
1331
1430
 
1332
1431
  return (
1333
1432
  <svg
1334
- ref={svg}
1433
+ ref={svgRef}
1335
1434
  data-slot="bot-mark"
1336
1435
  aria-hidden="true"
1337
1436
  className={className}
@@ -1352,10 +1451,10 @@ export function BotMark({
1352
1451
  <g clipPath={`url(#${clipId})`}>
1353
1452
  <g ref={eyesRef}>
1354
1453
  <g ref={eyeLRef}>
1355
- <path d={eyeL} fill="#000" />
1454
+ {eye(eyeL, CENTER - cfg.eyeGap / 2, "#000")}
1356
1455
  </g>
1357
1456
  <g ref={eyeRRef}>
1358
- <path d={eyeR} fill="#000" />
1457
+ {eye(eyeR, CENTER + cfg.eyeGap / 2, "#000")}
1359
1458
  </g>
1360
1459
  </g>
1361
1460
  </g>
@@ -1369,114 +1468,107 @@ export function BotMark({
1369
1468
  )}
1370
1469
  </mask>
1371
1470
  )}
1372
- {cfg.shadow > 0 && (
1373
- <filter
1374
- id={shadowId}
1375
- x="-60%"
1376
- y="-60%"
1377
- width="220%"
1378
- height="220%"
1379
- colorInterpolationFilters="sRGB"
1471
+ {spec && (
1472
+ <linearGradient
1473
+ ref={paintRef}
1474
+ id={paintId}
1475
+ {...paintAxis(spec.look, grow)}
1380
1476
  >
1381
- <feGaussianBlur stdDeviation={9} />
1382
- </filter>
1477
+ {paintStops(spec).map((stop) => (
1478
+ <stop
1479
+ key={`${stop.offset}-${stop.color}`}
1480
+ offset={stop.offset}
1481
+ stopColor={stop.color}
1482
+ />
1483
+ ))}
1484
+ </linearGradient>
1383
1485
  )}
1384
- {/* The aura is a halo around the silhouette, never a light behind it: the
1385
- eyes are holes cut out of the head, so anything drawn under it shines
1386
- straight through them and the face reads as hollow. */}
1387
- {cfg.glow > 0 && (
1388
- <mask
1389
- id={haloId}
1390
- maskUnits="userSpaceOnUse"
1391
- // The default region is the view box; the blur reaches past it.
1486
+ {spec?.look === "aurora" && (
1487
+ <filter
1488
+ id={curtainId}
1489
+ filterUnits="userSpaceOnUse"
1392
1490
  x={-PAD * 4}
1393
1491
  y={-PAD * 4}
1394
1492
  width={BOX + PAD * 8}
1395
1493
  height={BOX + PAD * 8}
1396
- >
1397
- <rect
1398
- x={-PAD * 4}
1399
- y={-PAD * 4}
1400
- width={BOX + PAD * 8}
1401
- height={BOX + PAD * 8}
1402
- fill="#fff"
1403
- />
1404
- <path ref={haloHeadRef} d={headPath} fill="#000" />
1405
- </mask>
1406
- )}
1407
- {cfg.glow > 0 && (
1408
- <filter
1409
- id={glowId}
1410
- x="-60%"
1411
- y="-60%"
1412
- width="220%"
1413
- height="220%"
1414
1494
  colorInterpolationFilters="sRGB"
1415
1495
  >
1416
- <feGaussianBlur stdDeviation={cfg.glow} />
1496
+ <feGaussianBlur stdDeviation={f(curtainBlurOf(grow))} />
1417
1497
  </filter>
1418
1498
  )}
1419
1499
  </defs>
1420
1500
  <g ref={lifeRef}>
1421
- {cfg.shadow > 0 && (
1422
- <path
1423
- ref={shadowRef}
1424
- d={headPath}
1425
- fill="var(--fg)"
1426
- filter={`url(#${shadowId})`}
1427
- transform={`translate(0 ${12})`}
1428
- opacity={0}
1429
- />
1430
- )}
1431
- {cfg.glow > 0 && (
1432
- <path
1433
- ref={glowRef}
1434
- d={headPath}
1435
- fill={cfg.glowColor ?? "var(--fg)"}
1436
- filter={`url(#${glowId})`}
1437
- mask={`url(#${haloId})`}
1438
- opacity={cfg.glowStrength / 100}
1439
- />
1440
- )}
1441
- {/* Under the fill, stroked at double width so only the outer half shows. */}
1442
- {cfg.rim > 0 && (
1501
+ {cfg.fill ? (
1502
+ // Everything the body wears shares its one mask, so a paint's layers keep the eyes cut.
1503
+ <g mask={`url(#${maskId})`}>
1504
+ <path ref={headRef} d={headPath} fill={ink} />
1505
+ {spec?.look === "aurora" && (
1506
+ // Blurred on a layer wider than the face, so the curtains melt into the night
1507
+ // while the mask keeps the outline and the eyes sharp.
1508
+ <g filter={`url(#${curtainId})`}>
1509
+ <rect
1510
+ x={-PAD * 4}
1511
+ y={-PAD * 4}
1512
+ width={BOX + PAD * 8}
1513
+ height={BOX + PAD * 8}
1514
+ fill={ink}
1515
+ />
1516
+ {CURTAINS.map((curtain, i) => (
1517
+ <ellipse
1518
+ key={curtain.cx}
1519
+ ref={(node) => {
1520
+ curtainRefs.current[i] = node;
1521
+ }}
1522
+ cx={curtain.cx}
1523
+ cy={CURTAIN_Y}
1524
+ rx={f(curtainRxOf(grow))}
1525
+ ry={138}
1526
+ fill={spec.colors[2 + i]}
1527
+ style={{ mixBlendMode: "screen" }}
1528
+ />
1529
+ ))}
1530
+ </g>
1531
+ )}
1532
+ </g>
1533
+ ) : (
1443
1534
  <path
1444
- ref={rimRef}
1535
+ ref={headRef}
1445
1536
  d={headPath}
1446
1537
  fill="none"
1447
- stroke={cfg.rimColor}
1448
- strokeWidth={cfg.rim * 2}
1538
+ stroke={ink}
1539
+ strokeWidth={cfg.strokeWidth}
1449
1540
  strokeLinejoin="round"
1450
1541
  />
1451
1542
  )}
1452
- <path
1453
- ref={headRef}
1454
- d={headPath}
1455
- fill={cfg.fill ? "var(--fg)" : "none"}
1456
- stroke={cfg.fill ? "none" : "var(--fg)"}
1457
- strokeWidth={cfg.fill ? 0 : cfg.strokeWidth}
1458
- strokeLinejoin="round"
1459
- mask={cfg.fill ? `url(#${maskId})` : undefined}
1460
- />
1543
+ {cfg.fill && edge === "dark" && (
1544
+ // Eye holes show the page, and a dark body on a dark page swallows them.
1545
+ <g clipPath={`url(#${clipId})`} opacity={0.92}>
1546
+ <g ref={inkEyesRef}>
1547
+ <g ref={inkEyeLRef}>
1548
+ {eye(eyeL, CENTER - cfg.eyeGap / 2, "#fff")}
1549
+ </g>
1550
+ <g ref={inkEyeRRef}>
1551
+ {eye(eyeR, CENTER + cfg.eyeGap / 2, "#fff")}
1552
+ </g>
1553
+ </g>
1554
+ </g>
1555
+ )}
1461
1556
  {/* Outlined marks have no silhouette to cut into, so the eyes are drawn. */}
1462
1557
  {!cfg.fill && (
1463
1558
  <g clipPath={`url(#${clipId})`}>
1464
1559
  <g ref={eyesRef}>
1465
- <g ref={eyeLRef}>
1466
- <path d={eyeL} fill="var(--fg)" />
1467
- </g>
1468
- <g ref={eyeRRef}>
1469
- <path d={eyeR} fill="var(--fg)" />
1470
- </g>
1560
+ <g ref={eyeLRef}>{eye(eyeL, CENTER - cfg.eyeGap / 2, ink)}</g>
1561
+ <g ref={eyeRRef}>{eye(eyeR, CENTER + cfg.eyeGap / 2, ink)}</g>
1471
1562
  </g>
1472
1563
  </g>
1473
1564
  )}
1474
1565
  {notifying && (
1566
+ // The dot waits on the user, so it wears amber in NavBadge's shades.
1475
1567
  <circle
1476
1568
  cx={f(CENTER + Math.cos(nAngle) * cfg.notifyDist)}
1477
1569
  cy={f(CENTER + Math.sin(nAngle) * cfg.notifyDist)}
1478
1570
  r={cfg.notifyR}
1479
- fill={cfg.notifyColor}
1571
+ className="fill-amber-600 dark:fill-amber-400"
1480
1572
  />
1481
1573
  )}
1482
1574
  </g>