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
@@ -4,6 +4,7 @@ import {
4
4
  ChevronDown,
5
5
  ChevronUp,
6
6
  Flag,
7
+ Loader2,
7
8
  type LucideIcon,
8
9
  Mic,
9
10
  MicOff,
@@ -21,7 +22,7 @@ import {
21
22
  TooltipProvider,
22
23
  TooltipTrigger,
23
24
  } from "@/components/ui/tooltip";
24
- import { SPEACH_MODEL_PROVIDER_LIST } from "@/features/ai/model.schema";
25
+ import { LIVE_PROVIDER } from "@/features/ai/live.schema";
25
26
  import { type Bot, DEFAULT_BOT } from "@/features/bot/bot.schema";
26
27
  import { BotMark } from "@/features/bot/components/bot-mark";
27
28
  import { BotRoom } from "@/features/bot/components/bot-room";
@@ -45,7 +46,10 @@ import {
45
46
  type ThursdayFace,
46
47
  } from "@/features/thursday/thursday.schema";
47
48
  import { useThursdayStore } from "@/features/thursday/thursday.store";
48
- import { type ToolRun, useThursday } from "@/features/thursday/use-thursday";
49
+ import {
50
+ type ActivityLine,
51
+ useThursday,
52
+ } from "@/features/thursday/use-thursday";
49
53
  import { ArtifactView } from "@/features/workspace/components/artifact-view";
50
54
  import { useHotkeyLabel } from "@/hooks/use-hotkey";
51
55
  import { useServerRoute } from "@/lib/protocol/use-server-route";
@@ -63,9 +67,13 @@ export type { CaptionView };
63
67
 
64
68
  export type CallScreenProps = {
65
69
  status: CallStatus;
70
+ /** A call just failed to open or dropped; the face says so for a few seconds. */
71
+ failed?: boolean;
66
72
  /** Oldest first; the last one is the turn being spoken. */
67
73
  messages: CallMessage[];
68
- tool: ToolRun | null;
74
+ tool: ActivityLine | null;
75
+ /** When the backend picked the turn up (ms); null when it is not working. */
76
+ thinkingSince?: number | null;
69
77
  onTap: () => void;
70
78
  /** Wake phrase; null when the tap is the only entry point. */
71
79
  wakePhrase?: string | null;
@@ -75,8 +83,6 @@ export type CallScreenProps = {
75
83
  idleLeft?: number | null;
76
84
  /** When the line opened (ms). */
77
85
  since?: number | null;
78
- /** Mic muted (use-thursday micOff): a tool is running or a relay is being read. */
79
- micOff?: boolean;
80
86
  getSpectrum?: () => ArrayLike<number>;
81
87
  /** The user's own mic bands, for the listening meter. */
82
88
  getMicSpectrum?: () => ArrayLike<number>;
@@ -89,14 +95,15 @@ export type CallScreenProps = {
89
95
 
90
96
  export function CallScreen({
91
97
  status,
98
+ failed = false,
92
99
  messages,
93
100
  tool,
101
+ thinkingSince = null,
94
102
  onTap,
95
103
  wakePhrase = null,
96
104
  hotkeyLabel = null,
97
105
  idleLeft = null,
98
106
  since = null,
99
- micOff = false,
100
107
  getSpectrum,
101
108
  getMicSpectrum,
102
109
  captionView = "center",
@@ -106,8 +113,8 @@ export function CallScreen({
106
113
  // without a key the face opens the key prompt instead of a call
107
114
  const [asking, setAsking] = useState(false);
108
115
  const asleep = !callable && status === "idle";
109
- const busy = status === "connecting";
110
- const live = status !== "idle" && status !== "connecting";
116
+ const busy = status === "connecting" || status === "ending";
117
+ const live = status !== "idle" && !busy;
111
118
  // The caption box holds her words and nothing else, so the line she just
112
119
  // said stays put while she listens or works.
113
120
  const hers =
@@ -152,7 +159,9 @@ export function CallScreen({
152
159
  <Face
153
160
  look={face}
154
161
  status={status}
162
+ failed={failed}
155
163
  getSpectrum={getSpectrum}
164
+ getMicSpectrum={getMicSpectrum}
156
165
  className="w-full"
157
166
  />
158
167
  </button>
@@ -169,8 +178,8 @@ export function CallScreen({
169
178
  (use-thursday). */}
170
179
  <ActivityRow
171
180
  tool={tool}
172
- micOff={micOff}
173
- listening={status === "listening"}
181
+ thinkingSince={thinkingSince}
182
+ listening={status === "listening" && thinkingSince === null}
174
183
  getMicSpectrum={getMicSpectrum}
175
184
  />
176
185
 
@@ -180,6 +189,7 @@ export function CallScreen({
180
189
  text={sided || status === "idle" ? "" : hers}
181
190
  fixed
182
191
  paged
192
+ fadeIn
183
193
  className="w-full max-w-160 text-center text-base"
184
194
  />
185
195
 
@@ -213,7 +223,7 @@ export function CallScreen({
213
223
  </div>
214
224
  </div>
215
225
 
216
- {/* Documents a finished task produced; opens itself on the artifact event */}
226
+ {/* Documents a finished thread produced; opens itself on the artifact event */}
217
227
  <ArtifactView />
218
228
 
219
229
  <BotRoom />
@@ -223,7 +233,7 @@ export function CallScreen({
223
233
 
224
234
  /**
225
235
  * The corner is one group: three rooms as single buttons, everything else
226
- * behind the gear. Tasks is left out because the other corner is that room.
236
+ * behind the gear. Threads is left out because the other corner is that room.
227
237
  */
228
238
  const CORNER = ["thursday", "memory", "bot"] as const;
229
239
 
@@ -333,7 +343,7 @@ const CAPTION_PADS = ["px-4 py-3", "px-3.5 py-2.5", "px-3 py-2"];
333
343
  * page's own — the ascii field is boot and intro only — so an outline covers
334
344
  * nothing and ends up being the whole design.
335
345
  *
336
- * Yours is the surface `Bubble` already gives your words in the task thread
346
+ * Yours is the surface `Bubble` already gives your words in a thread
337
347
  * (primary, light ink); hers is the page's grey. Age recedes in the fill, not
338
348
  * in the block's opacity, which would take the ink down with it.
339
349
  */
@@ -368,6 +378,7 @@ function Flow({
368
378
  lines = CAPTION_LINES,
369
379
  fixed = false,
370
380
  paged = false,
381
+ fadeIn = false,
371
382
  className,
372
383
  }: {
373
384
  text: string;
@@ -378,6 +389,8 @@ function Flow({
378
389
  fixed?: boolean;
379
390
  /** Page overflow with chevrons; needs side margin. */
380
391
  paged?: boolean;
392
+ /** Each new character fades in as it arrives; what is already drawn stays put. */
393
+ fadeIn?: boolean;
381
394
  className?: string;
382
395
  }) {
383
396
  const box = useRef<HTMLParagraphElement>(null);
@@ -420,7 +433,17 @@ function Flow({
420
433
  className={cn("break-keep", paged && "transition-transform duration-200")}
421
434
  >
422
435
  {lead}
423
- {text}
436
+ {fadeIn
437
+ ? // char + index: a character already drawn keeps its key and never fades twice
438
+ Array.from(text).map((char, index) => (
439
+ <span
440
+ key={`${char}${index}`}
441
+ className="animate-in fade-in duration-300 motion-reduce:animate-none"
442
+ >
443
+ {char}
444
+ </span>
445
+ ))
446
+ : text}
424
447
  </p>
425
448
  );
426
449
 
@@ -626,7 +649,7 @@ function Ear({
626
649
  * which has no container either, so an outline under one of the two read as the
627
650
  * line changing shape rather than changing state.
628
651
  */
629
- function Activity({ tool, micOff }: { tool: ToolRun; micOff: boolean }) {
652
+ function Activity({ tool }: { tool: ActivityLine }) {
630
653
  // a relay from a bot is a flag, like the answer tool — unless it names the bot
631
654
  const relay = tool.kind === "relay";
632
655
  const Icon = relay ? Flag : toolIcon(tool.name);
@@ -662,17 +685,7 @@ function Activity({ tool, micOff }: { tool: ToolRun; micOff: boolean }) {
662
685
  {tool.done ? (
663
686
  <span className={cn(look, "text-muted-foreground")}>{text}</span>
664
687
  ) : (
665
- <ShinyText text={text} speed={2.4} className={look} />
666
- )}
667
- {/* The mic is closed because this is running, so it travels with the line.
668
- A chip, where the line has none: on the bare page a second glyph beside
669
- the tool's own shares strokes with it and reads as a smudge, and the
670
- plate is what says this is a state rather than more of the sentence. */}
671
- {micOff && (
672
- <span className="flex shrink-0 items-center gap-1 rounded-full bg-muted/60 py-0.5 pr-2 pl-1.5 font-mono text-[11px] leading-4 text-muted-foreground">
673
- <MicOff className="size-3 shrink-0" />
674
- mic off
675
- </span>
688
+ <ShinyText text={text} motion="pulse" className={look} />
676
689
  )}
677
690
  </span>
678
691
  );
@@ -691,7 +704,7 @@ function Mark({
691
704
  icon: Icon,
692
705
  running,
693
706
  }: {
694
- tool: ToolRun;
707
+ tool: ActivityLine;
695
708
  /** The row the name resolved to, when the roster has one; its look, not its identity. */
696
709
  bot: Bot | null;
697
710
  icon: LucideIcon;
@@ -703,10 +716,10 @@ function Mark({
703
716
  <BotMark
704
717
  size={16}
705
718
  seed={tool.bot}
706
- vary={tool.bot}
707
719
  color={bot?.icon?.color}
708
720
  shape={bot?.icon?.shape}
709
721
  outline={bot?.icon?.outline}
722
+ paint={bot?.icon?.paint}
710
723
  notify={false}
711
724
  />
712
725
  </span>
@@ -724,18 +737,19 @@ function Mark({
724
737
  }
725
738
 
726
739
  /**
727
- * The activity slot: 28px, one fact at a time, two faces. Both stay mounted and
740
+ * The activity slot: 28px, one fact at a time, three faces. All stay mounted and
728
741
  * cross-fade, so the line leaves wearing its last words instead of blinking
729
- * out, and the caption below never moves while they trade places.
742
+ * out, and the caption below never moves while they trade places. A tool wins
743
+ * over thinking: it is the same stretch of work, said more exactly.
730
744
  */
731
745
  function ActivityRow({
732
746
  tool,
733
- micOff,
747
+ thinkingSince,
734
748
  listening,
735
749
  getMicSpectrum,
736
750
  }: {
737
- tool: ToolRun | null;
738
- micOff: boolean;
751
+ tool: ActivityLine | null;
752
+ thinkingSince: number | null;
739
753
  listening: boolean;
740
754
  getMicSpectrum?: () => ArrayLike<number>;
741
755
  }) {
@@ -744,13 +758,26 @@ function ActivityRow({
744
758
  useEffect(() => {
745
759
  if (tool) setShown(tool);
746
760
  }, [tool]);
761
+ // and past the thinking, for the same reason
762
+ const [since, setSince] = useState(thinkingSince);
763
+ useEffect(() => {
764
+ if (thinkingSince !== null) setSince(thinkingSince);
765
+ }, [thinkingSince]);
747
766
 
748
767
  const hearing = listening && !tool;
749
768
  return (
750
769
  <div className="grid h-7 max-w-full items-center justify-items-center">
751
770
  {shown && (
752
771
  <Fade at="col-start-1 row-start-1 max-w-full" shown={tool !== null}>
753
- <Activity tool={shown} micOff={micOff} />
772
+ <Activity tool={shown} />
773
+ </Fade>
774
+ )}
775
+ {since !== null && (
776
+ <Fade
777
+ at="col-start-1 row-start-1"
778
+ shown={thinkingSince !== null && !tool}
779
+ >
780
+ <Thinking since={since} running={thinkingSince !== null && !tool} />
754
781
  </Fade>
755
782
  )}
756
783
  <Fade at="col-start-1 row-start-1" shown={hearing}>
@@ -802,7 +829,7 @@ function Hint({
802
829
  wakePhrase: string | null;
803
830
  hotkeyLabel: string | null;
804
831
  }) {
805
- const busy = status === "connecting";
832
+ const busy = status === "connecting" || status === "ending";
806
833
  const live = status !== "idle" && !busy;
807
834
 
808
835
  let body: React.ReactNode;
@@ -813,6 +840,7 @@ function Hint({
813
840
  body = (
814
841
  <ShinyText
815
842
  text={status === "connecting" ? "Connecting…" : "Ending…"}
843
+ motion="pulse"
816
844
  className="text-muted-foreground/70"
817
845
  />
818
846
  );
@@ -910,7 +938,6 @@ function NeedsKey({
910
938
  <BotMark
911
939
  size={24}
912
940
  seed={DEFAULT_BOT.name}
913
- vary={DEFAULT_BOT.name}
914
941
  color={DEFAULT_BOT.icon?.color}
915
942
  shape={DEFAULT_BOT.icon?.shape}
916
943
  outline={DEFAULT_BOT.icon?.outline}
@@ -928,6 +955,44 @@ function NeedsKey({
928
955
  );
929
956
  }
930
957
 
958
+ /**
959
+ * The backend has the turn: the activity line says so and counts, so the
960
+ * seconds before a tool and before her voice never read as a call that has
961
+ * stopped. A spinner fits here as it did not on a tool: there is no glyph yet
962
+ * for it to take off the screen. The seconds arrive after the first one, which
963
+ * is most answers.
964
+ */
965
+ function Thinking({ since, running }: { since: number; running: boolean }) {
966
+ const [now, setNow] = useState(() => Date.now());
967
+ // Stays mounted to fade out; the count stops with it rather than ticking unseen
968
+ useEffect(() => {
969
+ if (!running) return;
970
+ // back from a tool, the first reading is now rather than where it paused
971
+ const first = setTimeout(() => setNow(Date.now()), 0);
972
+ const tick = setInterval(() => setNow(Date.now()), 1000);
973
+ return () => {
974
+ clearTimeout(first);
975
+ clearInterval(tick);
976
+ };
977
+ }, [running]);
978
+ const seconds = Math.max(0, Math.floor((now - since) / 1000));
979
+ return (
980
+ <span className="flex max-w-full items-center gap-1.5 text-[13px] leading-5">
981
+ {/* the 18px slot a tool's glyph takes over when one starts */}
982
+ <span className="grid size-[18px] shrink-0 place-items-center">
983
+ <Loader2 className="size-3.5 animate-spin text-muted-foreground" />
984
+ </span>
985
+ <ShinyText text="Thinking…" motion="pulse" />
986
+ {seconds >= 1 && (
987
+ <>
988
+ <span className="text-muted-foreground/40">·</span>
989
+ <span className="text-muted-foreground tabular-nums">{seconds}s</span>
990
+ </>
991
+ )}
992
+ </span>
993
+ );
994
+ }
995
+
931
996
  /** Time since the line opened, mm:ss; only this span re-renders each second. */
932
997
  function Elapsed({ since }: { since: number | null }) {
933
998
  const [now, setNow] = useState(() => Date.now());
@@ -1095,11 +1160,12 @@ function SideCaptions({
1095
1160
  export function Thursday() {
1096
1161
  const {
1097
1162
  status,
1163
+ failed,
1098
1164
  messages,
1099
1165
  tool,
1166
+ thinkingSince,
1100
1167
  idleLeft,
1101
1168
  since,
1102
- micOff,
1103
1169
  call,
1104
1170
  getSpectrum,
1105
1171
  getMicSpectrum,
@@ -1117,9 +1183,7 @@ export function Thursday() {
1117
1183
  * can change during a call (NeedsKey). Unknown counts as not callable.
1118
1184
  */
1119
1185
  const { data: config } = useServerRoute<ConfigStatus[]>(queryKey.config);
1120
- const callable = SPEACH_MODEL_PROVIDER_LIST.some((provider) =>
1121
- isConfigSet(config, provider.apiKeyName),
1122
- );
1186
+ const callable = isConfigSet(config, LIVE_PROVIDER.apiKeyName);
1123
1187
 
1124
1188
  return (
1125
1189
  <>
@@ -1127,14 +1191,15 @@ export function Thursday() {
1127
1191
  <TabState live={status !== "idle"} />
1128
1192
  <CallScreen
1129
1193
  status={status}
1194
+ failed={failed}
1130
1195
  messages={messages}
1131
1196
  tool={tool}
1197
+ thinkingSince={thinkingSince}
1132
1198
  onTap={call}
1133
1199
  wakePhrase={wakePhrase}
1134
1200
  hotkeyLabel={hotkeyLabel}
1135
1201
  idleLeft={idleLeft}
1136
1202
  since={since}
1137
- micOff={micOff}
1138
1203
  getSpectrum={getSpectrum}
1139
1204
  getMicSpectrum={getMicSpectrum}
1140
1205
  face={face}
@@ -0,0 +1,255 @@
1
+ "use client";
2
+
3
+ import { Check, ChevronDown, X } from "lucide-react";
4
+ import { useCallback, useEffect, useRef, useState } from "react";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Input, inputClassName } from "@/components/ui/input";
7
+ import { ShinyText } from "@/components/ui/shiny-text";
8
+ import { toast } from "@/components/ui/toast";
9
+ import {
10
+ LIVE_VOICE_NOTE,
11
+ LIVE_VOICES,
12
+ voiceSamplePath,
13
+ } from "@/features/ai/live.schema";
14
+ import { Face } from "@/features/thursday/components/face";
15
+ import type { ThursdayFace } from "@/features/thursday/thursday.schema";
16
+ import { createClipTap, SPECTRUM_BANDS } from "@/lib/live/live.tap";
17
+ import { cn, errorToString } from "@/lib/utils";
18
+
19
+ /**
20
+ * Choosing a voice by ear. A name plays its recorded line and her own face
21
+ * speaks it — the same component and the same bands a call moves her with, so
22
+ * what you hear and see here is what the call will be. Only Save writes, so
23
+ * hearing eleven voices stores none of them.
24
+ */
25
+
26
+ const SILENT = new Array<number>(SPECTRUM_BANDS).fill(0);
27
+
28
+ export function VoicePicker({
29
+ voice,
30
+ face,
31
+ onChange,
32
+ }: {
33
+ /** The saved voice: what the next call opens with. */
34
+ voice: string;
35
+ face: ThursdayFace;
36
+ onChange: (voice: string) => void;
37
+ }) {
38
+ const [open, setOpen] = useState(false);
39
+ const [heard, setHeard] = useState(voice);
40
+ const [playing, setPlaying] = useState(false);
41
+ const [typed, setTyped] = useState("");
42
+
43
+ const clip = useRef<HTMLAudioElement>(null);
44
+ // A tap belongs to the element it routes, which exists only while the picker is open.
45
+ const tap = useRef<{
46
+ element: HTMLAudioElement;
47
+ clip: ReturnType<typeof createClipTap>;
48
+ } | null>(null);
49
+ // Each play and each stop takes the next number; a failure reported for an
50
+ // earlier one changes nothing.
51
+ const plays = useRef(0);
52
+ // The face reads the spectrum once per animation frame, so what it reads is a
53
+ // ref, not state: a stable function, and silence when nothing is playing.
54
+ const sounding = useRef(false);
55
+ const spectrum = useCallback(
56
+ () => (tap.current && sounding.current ? tap.current.clip.read() : SILENT),
57
+ [],
58
+ );
59
+ const showPlaying = (on: boolean) => {
60
+ sounding.current = on;
61
+ setPlaying(on);
62
+ };
63
+
64
+ // The element goes when the picker closes; its graph goes with it.
65
+ useEffect(() => {
66
+ if (!open) return;
67
+ return () => {
68
+ const held = tap.current;
69
+ tap.current = null;
70
+ if (!held) return;
71
+ held.element.pause();
72
+ void held.clip.close();
73
+ };
74
+ }, [open]);
75
+
76
+ const failed = (play: number, cause: unknown) => {
77
+ if (play !== plays.current) return;
78
+ plays.current++;
79
+ showPlaying(false);
80
+ toast.add({
81
+ type: "error",
82
+ title: "Voice sample did not play",
83
+ description: errorToString(cause),
84
+ });
85
+ };
86
+
87
+ const stop = () => {
88
+ plays.current++;
89
+ const audio = clip.current;
90
+ if (audio) {
91
+ audio.pause();
92
+ audio.currentTime = 0;
93
+ }
94
+ showPlaying(false);
95
+ };
96
+
97
+ const audition = (next: string) => {
98
+ const audio = clip.current;
99
+ if (!audio) return;
100
+ if (playing && next === heard) {
101
+ stop();
102
+ return;
103
+ }
104
+ setHeard(next);
105
+ setTyped("");
106
+ // The graph is built inside the gesture that plays: an AudioContext made
107
+ // before one is refused. An element is routed once, so it keeps its tap.
108
+ if (tap.current?.element !== audio) {
109
+ void tap.current?.clip.close();
110
+ tap.current = { element: audio, clip: createClipTap(audio) };
111
+ }
112
+ void tap.current.clip.resume();
113
+ const play = ++plays.current;
114
+ audio.src = voiceSamplePath(next);
115
+ showPlaying(true);
116
+ void audio.play().catch((cause: unknown) => {
117
+ // A later click or a stop cut this one short; that play owns the state.
118
+ if (cause instanceof DOMException && cause.name === "AbortError") return;
119
+ failed(play, cause);
120
+ });
121
+ };
122
+
123
+ const close = () => {
124
+ stop();
125
+ setOpen(false);
126
+ setTyped("");
127
+ setHeard(voice);
128
+ };
129
+
130
+ const save = () => {
131
+ const picked = typed.trim() || heard;
132
+ stop();
133
+ setOpen(false);
134
+ setTyped("");
135
+ setHeard(picked);
136
+ if (picked !== voice) onChange(picked);
137
+ };
138
+
139
+ if (!open) {
140
+ return (
141
+ <button
142
+ type="button"
143
+ onClick={() => setOpen(true)}
144
+ aria-label="Voice"
145
+ className={cn(
146
+ inputClassName,
147
+ "flex items-center gap-2 text-left font-mono text-sm hover:border-ring",
148
+ )}
149
+ >
150
+ <span className="shrink-0">{voice}</span>
151
+ <span className="min-w-0 truncate text-[11px] text-muted-foreground">
152
+ {LIVE_VOICE_NOTE[voice as keyof typeof LIVE_VOICE_NOTE]}
153
+ </span>
154
+ <ChevronDown className="ml-auto size-3.5 shrink-0 text-muted-foreground" />
155
+ </button>
156
+ );
157
+ }
158
+
159
+ return (
160
+ <div className="@container space-y-2">
161
+ {/* Nothing here plays through the page's own speakers but this element. */}
162
+ <audio
163
+ ref={clip}
164
+ onEnded={() => showPlaying(false)}
165
+ // A clip that breaks after it starts fails here, not in play()
166
+ onError={(event) => {
167
+ if (!sounding.current) return;
168
+ failed(
169
+ plays.current,
170
+ event.currentTarget.error?.message || "The clip could not be read.",
171
+ );
172
+ }}
173
+ >
174
+ <track kind="captions" />
175
+ </audio>
176
+
177
+ <div className="rounded-xl border border-border/60 p-3">
178
+ <div className="mb-2 flex items-center gap-2">
179
+ <span className="font-mono text-[11px] text-muted-foreground">
180
+ click a name to hear it
181
+ </span>
182
+ <Button
183
+ variant="ghost"
184
+ size="icon-xs"
185
+ className="ml-auto"
186
+ aria-label="Close"
187
+ onClick={close}
188
+ >
189
+ <X />
190
+ </Button>
191
+ </div>
192
+
193
+ <div className="grid gap-4 @md:grid-cols-[11rem_minmax(0,1fr)]">
194
+ <div className="flex flex-col items-center gap-2">
195
+ <Face
196
+ look={face}
197
+ status={playing ? "speaking" : "idle"}
198
+ getSpectrum={spectrum}
199
+ size={176}
200
+ className="w-44"
201
+ />
202
+ <span className="text-sm font-medium">
203
+ {playing ? <ShinyText text={heard} /> : heard}
204
+ </span>
205
+ <span className="h-4 font-mono text-[11px] text-muted-foreground">
206
+ {LIVE_VOICE_NOTE[heard as keyof typeof LIVE_VOICE_NOTE]}
207
+ </span>
208
+ </div>
209
+
210
+ <div className="max-h-56 min-w-0 overflow-y-auto">
211
+ {LIVE_VOICES.map((name) => (
212
+ <button
213
+ type="button"
214
+ key={name}
215
+ onClick={() => audition(name)}
216
+ className={cn(
217
+ "flex w-full items-center gap-2 rounded-md px-1.5 py-1.5 text-sm outline-none hover:bg-accent focus-visible:bg-accent",
218
+ name === heard && "bg-accent text-accent-foreground",
219
+ )}
220
+ >
221
+ <span className="flex-1 text-left">
222
+ {playing && name === heard ? <ShinyText text={name} /> : name}
223
+ </span>
224
+ <span className="shrink truncate font-mono text-[11px] text-muted-foreground">
225
+ {LIVE_VOICE_NOTE[name]}
226
+ </span>
227
+ <Check
228
+ className={cn(
229
+ "size-3.5 shrink-0",
230
+ name === voice ? "opacity-100" : "opacity-0",
231
+ )}
232
+ />
233
+ </button>
234
+ ))}
235
+ </div>
236
+ </div>
237
+ </div>
238
+
239
+ {/* A voice id that is not on the list still runs; it simply has no clip. */}
240
+ <div className="flex gap-2">
241
+ <Input
242
+ value={typed}
243
+ onChange={(event) => setTyped(event.target.value)}
244
+ placeholder="another voice id"
245
+ aria-label="Another voice id"
246
+ spellCheck={false}
247
+ className="font-mono text-sm"
248
+ />
249
+ <Button className="shrink-0" onClick={save}>
250
+ Save
251
+ </Button>
252
+ </div>
253
+ </div>
254
+ );
255
+ }