thursday-agent 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -1
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +5 -5
  5. package/.next/routes-manifest.json +27 -3
  6. package/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js +2 -2
  14. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +1 -1
  17. package/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  20. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/api/artifact/route.js +3 -3
  22. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  23. package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
  24. package/.next/server/app/api/bot/memory/files/route.js +10 -0
  25. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
  26. package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
  27. package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
  28. package/.next/server/app/api/bot/memory/route/build-manifest.json +12 -0
  29. package/.next/server/app/api/bot/memory/route/server-reference-manifest.json +4 -0
  30. package/.next/server/app/api/bot/memory/route.js +14 -0
  31. package/.next/server/app/api/bot/memory/route.js.map +5 -0
  32. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -0
  33. package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
  34. package/.next/server/app/api/bot/route.js +7 -7
  35. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  36. package/.next/server/app/api/bot/task/[id]/route.js +9 -9
  37. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
  38. package/.next/server/app/api/bot/task/route.js +8 -8
  39. package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
  40. package/.next/server/app/api/config/route.js +6 -6
  41. package/.next/server/app/api/config/route.js.nft.json +1 -1
  42. package/.next/server/app/api/events/route.js +4 -5
  43. package/.next/server/app/api/events/route.js.nft.json +1 -1
  44. package/.next/server/app/api/file/[...path]/route.js +3 -3
  45. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/catalog/route.js +10 -9
  47. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
  49. package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
  50. package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
  51. package/.next/server/app/api/llm-model/credits/route.js +16 -0
  52. package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
  53. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
  54. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
  55. package/.next/server/app/api/llm-model/route.js +10 -8
  56. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  57. package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
  58. package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
  59. package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
  60. package/.next/server/app/api/llm-model/subscription/route.js +15 -0
  61. package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
  62. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
  63. package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
  64. package/.next/server/app/api/mcp/[name]/route.js +5 -5
  65. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  66. package/.next/server/app/api/mcp/oauth/callback/route.js +6 -6
  67. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  68. package/.next/server/app/api/mcp/route.js +5 -5
  69. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  70. package/.next/server/app/api/mcp/tools/route.js +5 -5
  71. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  72. package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/memory/edit/route.js +24 -0
  76. package/.next/server/app/api/memory/edit/route.js.map +5 -0
  77. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
  78. package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/memory/route.js +7 -8
  80. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  81. package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
  82. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  83. package/.next/server/app/api/skills/route.js +3 -3
  84. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  85. package/.next/server/app/api/thursday/call/route.js +9 -7
  86. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  87. package/.next/server/app/api/thursday/skills/route.js +9 -7
  88. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  89. package/.next/server/app/api/thursday/tool-call/route.js +16 -15
  90. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  91. package/.next/server/app/api/workspace/route.js +4 -5
  92. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  93. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  94. package/.next/server/app/artifact/[...path]/page.js +5 -6
  95. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  96. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  97. package/.next/server/app/favicon.ico/route.js +3 -4
  98. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  99. package/.next/server/app/favicon.ico.body +0 -0
  100. package/.next/server/app/page/server-reference-manifest.json +66 -77
  101. package/.next/server/app/page.js +11 -11
  102. package/.next/server/app/page.js.nft.json +1 -1
  103. package/.next/server/app/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app-paths-manifest.json +5 -1
  105. package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
  107. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
  109. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
  110. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
  111. package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
  112. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
  113. package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
  114. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
  115. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
  116. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
  117. package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
  118. package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
  119. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
  120. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
  121. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
  122. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
  123. package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
  124. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
  125. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
  126. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
  127. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +10 -0
  128. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
  129. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
  131. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
  132. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
  133. package/.next/server/chunks/{_1hzrsvg._.js → _0-73of8._.js} +6 -6
  134. package/.next/server/chunks/{_1cbk7ms._.js → _0-fjql4._.js} +10 -10
  135. package/.next/server/chunks/_00xh_q0._.js +27 -0
  136. package/.next/server/chunks/{_0y8is-s._.js → _03a0897._.js} +1 -1
  137. package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +166 -35
  138. package/.next/server/chunks/_051qh8u._.js +3 -0
  139. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  140. package/.next/server/chunks/_05h2cii._.js +1 -1
  141. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  142. package/.next/server/chunks/_0fzqt2y._.js +74 -44
  143. package/.next/server/chunks/{_0kl37zl._.js → _0ioz3nd._.js} +1 -1
  144. package/.next/server/chunks/_0iwfby5._.js +3 -0
  145. package/.next/server/chunks/{_0hin38_._.js → _0khihjk._.js} +5 -5
  146. package/.next/server/chunks/_0mecv0f._.js +26 -0
  147. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  148. package/.next/server/chunks/{_1icgbi8._.js → _0n74zsf._.js} +2 -2
  149. package/.next/server/chunks/_0obojvv._.js +3 -0
  150. package/.next/server/chunks/_0recufk._.js +49 -0
  151. package/.next/server/chunks/{_1t8fv7b._.js → _0rnf-6n._.js} +2 -2
  152. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  153. package/.next/server/chunks/{_0jgm3b8._.js → _0u10wmw._.js} +6 -6
  154. package/.next/server/chunks/{_12nr4xc._.js → _0u4aiy2._.js} +2 -2
  155. package/.next/server/chunks/_0wp4le3._.js +1 -1
  156. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  157. package/.next/server/chunks/_1230wbx._.js +10 -0
  158. package/.next/server/chunks/_12nheja._.js +3 -0
  159. package/.next/server/chunks/_13510xh._.js +3 -0
  160. package/.next/server/chunks/_15hq89o._.js +1 -1
  161. package/.next/server/chunks/_17l5ygt._.js +49 -0
  162. package/.next/server/chunks/{_0ks6_sg._.js → _18-1wcc._.js} +6 -6
  163. package/.next/server/chunks/_1_5mnq4._.js +18 -0
  164. package/.next/server/chunks/{_0tzfesa._.js → _1_9mjx-._.js} +1 -1
  165. package/.next/server/chunks/_1d0j961._.js +6 -0
  166. package/.next/server/chunks/_1d5zmy8._.js +1 -1
  167. package/.next/server/chunks/_1drgfx4._.js +18 -0
  168. package/.next/server/chunks/{_1skgy7b._.js → _1e48czp._.js} +5 -5
  169. package/.next/server/chunks/_1f46eie._.js +3 -0
  170. package/.next/server/chunks/_1h5_8sk._.js +3 -0
  171. package/.next/server/chunks/_1hdnxb7._.js +3 -0
  172. package/.next/server/chunks/_1j8k_j5._.js +3 -0
  173. package/.next/server/chunks/{_10qam6o._.js → _1kg70wc._.js} +5 -5
  174. package/.next/server/chunks/_1krd9rf._.js +3 -0
  175. package/.next/server/chunks/_1nc0eui._.js +11 -0
  176. package/.next/server/chunks/_1nula3v._.js +3 -0
  177. package/.next/server/chunks/_1pf4qe-._.js +3 -0
  178. package/.next/server/chunks/_1php4eq._.js +1 -1
  179. package/.next/server/chunks/_1qxheoa._.js +3 -0
  180. package/.next/server/chunks/_1x6kd1r._.js +3 -0
  181. package/.next/server/chunks/_1yuv4vp._.js +1 -1
  182. package/.next/server/chunks/_1zjrdag._.js +3 -0
  183. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
  184. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
  185. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
  186. package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
  187. package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
  188. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  189. package/.next/server/chunks/features_0rpfxbk._.js +3 -0
  190. package/.next/server/chunks/features_1qf3cei._.js +3 -0
  191. package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
  192. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  193. package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
  194. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tf290y._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
  195. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0228f43._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
  196. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0ir-vo2._.js → node_modules_consola_dist_chunks_prompt_mjs_0j61-ma._.js} +1 -1
  197. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0otw8ef._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
  198. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js +3 -0
  199. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_11zjo-1._.js +3 -0
  200. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1pycqsq._.js +3 -0
  201. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
  202. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js +3 -0
  203. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +3 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  205. package/.next/server/chunks/ssr/[root-of-the-server]__0_69wqr._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  207. package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
  208. package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
  209. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  211. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  212. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  213. package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
  214. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
  215. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  216. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  217. package/.next/server/chunks/ssr/[root-of-the-server]__1cyjywu._.js +3 -0
  218. package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
  219. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
  220. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  221. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
  222. package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
  223. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  224. package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
  225. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  226. package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
  227. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  228. package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
  229. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  230. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  231. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  232. package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
  233. package/.next/server/chunks/ssr/_0lu1n_x._.js +3 -0
  234. package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
  235. package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
  236. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  237. package/.next/server/chunks/ssr/{_0gd4vaa._.js → _0u2jv_x._.js} +94 -58
  238. package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
  239. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  240. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  241. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  242. package/.next/server/chunks/ssr/{_0q_2f2x._.js → _13z3f85._.js} +2 -2
  243. package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
  244. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  245. package/.next/server/chunks/ssr/{_0lc_7c8._.js → _1eoqg_g._.js} +2 -2
  246. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  247. package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
  248. package/.next/server/chunks/ssr/{_19_o9d-._.js → _1vi_uo7._.js} +2 -2
  249. package/.next/server/chunks/ssr/_1vyd1ji._.js +3 -0
  250. package/.next/server/chunks/ssr/_1xvgn77._.js +3 -0
  251. package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
  252. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  253. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  254. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  255. package/.next/server/chunks/ssr/lib_date-like_ts_02is0pw._.js +3 -0
  256. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +27 -0
  257. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +27 -0
  258. package/.next/server/chunks/ssr/{node_modules_1d-is1o._.js → node_modules_063xwpp._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_1ub40gk._.js → node_modules_0bvraul._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1nhw9qg._.js → node_modules_0eu1va6._.js} +1 -1
  261. package/.next/server/chunks/ssr/{node_modules_0xwx4u-._.js → node_modules_0h50b8n._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_043-236._.js → node_modules_0h5hnr1._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1t0y5jt._.js → node_modules_0h7u60n._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1k29j1j._.js → node_modules_0lm7_vm._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_16i4o_3._.js → node_modules_0mwym0g._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_1y8_3vg._.js → node_modules_0rjg6t1._.js} +1 -1
  267. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  268. package/.next/server/chunks/ssr/{node_modules_108wd2o._.js → node_modules_0y_cded._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_1jatz7w._.js → node_modules_0z5tsu8._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_0ls96je._.js → node_modules_0zp9r92._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_06kvvuo._.js → node_modules_1-hc6uv._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_1_588_4._.js → node_modules_113tz0l._.js} +1 -1
  273. package/.next/server/chunks/ssr/{node_modules_0ipn1ho._.js → node_modules_124bue5._.js} +1 -1
  274. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  275. package/.next/server/chunks/ssr/{node_modules_0_j7-g4._.js → node_modules_1_n3ztw._.js} +1 -1
  276. package/.next/server/chunks/ssr/{node_modules_20ynonm._.js → node_modules_1bc7gu8._.js} +1 -1
  277. package/.next/server/chunks/ssr/{node_modules_1hn_sd5._.js → node_modules_1bgb6-f._.js} +1 -1
  278. package/.next/server/chunks/ssr/{node_modules_0bue6gy._.js → node_modules_1h4a4pp._.js} +1 -1
  279. package/.next/server/chunks/ssr/{node_modules_0fbw5-u._.js → node_modules_1i7u1ia._.js} +1 -1
  280. package/.next/server/chunks/ssr/{node_modules_1ee8gav._.js → node_modules_1juq3hs._.js} +1 -1
  281. package/.next/server/chunks/ssr/{node_modules_0_fvxnt._.js → node_modules_1l0qtdu._.js} +1 -1
  282. package/.next/server/chunks/ssr/{node_modules_13f2md6._.js → node_modules_1t9cyee._.js} +1 -1
  283. package/.next/server/chunks/ssr/{node_modules_0y2-av4._.js → node_modules_1uuj9x1._.js} +1 -1
  284. package/.next/server/chunks/ssr/{node_modules_00d6675._.js → node_modules_1vqb6po._.js} +1 -1
  285. package/.next/server/chunks/ssr/{node_modules_1v0077l._.js → node_modules_1xx28h1._.js} +1 -1
  286. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_092s8nx._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
  287. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1nvexgu._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
  288. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
  289. package/.next/server/chunks/ssr/node_modules_consola_dist_chunks_prompt_mjs_05cwqv2._.js +47 -0
  290. package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  291. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
  292. package/.next/server/instrumentation.js +1 -1
  293. package/.next/server/middleware-build-manifest.js +3 -3
  294. package/.next/server/pages/404.html +1 -1
  295. package/.next/server/pages/500.html +1 -1
  296. package/.next/server/server-reference-manifest.js +1 -1
  297. package/.next/server/server-reference-manifest.json +67 -78
  298. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  299. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  300. package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
  301. package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
  302. package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
  303. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  304. package/.next/static/chunks/14hgtsjg-kael.css +1 -0
  305. package/.next/static/chunks/17donp69y4do7.js +40 -0
  306. package/.next/static/chunks/1dkjg87pxk0n9.js +28 -0
  307. package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
  308. package/.next/static/chunks/{1khakdu_iuedc.js → 1grhjo7a5a0_-.js} +1 -1
  309. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  310. package/.next/static/chunks/1okqiww3pnwka.js +1 -0
  311. package/.next/static/chunks/26-pr2c9ro222.js +1 -0
  312. package/.next/static/chunks/{2ihkf6l2jowo9.js → 280t0_e99i276.js} +3 -3
  313. package/.next/static/chunks/28cizcdaabd4h.js +1 -0
  314. package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
  315. package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
  316. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  317. package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
  318. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  319. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  320. package/.next/static/chunks/3111pj5wnjgos.js +1 -0
  321. package/.next/static/chunks/3786h5vayt80-.js +28 -0
  322. package/.next/static/chunks/{3aquirz5h71da.js → 3agpgkwaa321p.js} +1 -1
  323. package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
  324. package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
  325. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  326. package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
  327. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  328. package/README.md +6 -4
  329. package/app/api/bot/memory/files/route.ts +14 -0
  330. package/app/api/bot/memory/route.ts +5 -0
  331. package/app/api/events/app-event.client.ts +24 -0
  332. package/app/api/events/app-event.server.ts +45 -0
  333. package/app/api/events/app-event.ts +42 -0
  334. package/app/api/llm-model/catalog/route.ts +12 -0
  335. package/app/api/llm-model/credits/route.ts +11 -0
  336. package/app/api/llm-model/route.ts +26 -0
  337. package/app/api/llm-model/subscription/route.ts +11 -0
  338. package/app/api/memory/edit/route.ts +7 -0
  339. package/app/api/memory/route.ts +21 -0
  340. package/app/api/query-key.ts +159 -0
  341. package/app/api/thursday/tool-call/route.ts +67 -0
  342. package/bin/thursday.mjs +3 -0
  343. package/components/ui/button-group.tsx +45 -0
  344. package/components/ui/custom-icon.tsx +259 -0
  345. package/components/ui/dropdown-menu.tsx +271 -0
  346. package/components/ui/folded-text.tsx +68 -0
  347. package/components/ui/input-group.tsx +157 -0
  348. package/components/ui/json-view.tsx +240 -0
  349. package/components/ui/shiny-text.tsx +55 -0
  350. package/components/ui/text-type.tsx +213 -0
  351. package/components/ui/theme-sync.tsx +9 -0
  352. package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/migration.sql +30 -33
  353. package/database/migrations/{20260908030742_rainy_marvel_zombies → 20260910173049_numerous_spirit}/snapshot.json +124 -145
  354. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  355. package/database/migrations/20260911030320_opposite_jack_power/snapshot.json +1158 -0
  356. package/docs/how-it-works.md +59 -0
  357. package/docs/images/keeps-going.png +0 -0
  358. package/docs/images/task-thread.png +0 -0
  359. package/docs/images/two-minds.png +0 -0
  360. package/features/ai/chatgpt.ts +617 -0
  361. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  362. package/features/ai/components/model-picker.tsx +17 -1
  363. package/features/ai/components/provider-icon.tsx +1 -0
  364. package/features/ai/load-tools.ts +105 -39
  365. package/features/ai/model.schema.ts +232 -34
  366. package/features/ai/model.ts +169 -24
  367. package/features/ai/prompts/bot.prompt.ts +245 -59
  368. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  369. package/features/ai/prompts/prompt-helper.ts +75 -30
  370. package/features/ai/prompts/thursday.prompt.ts +42 -17
  371. package/features/ai/tools/bot.tool.ts +32 -30
  372. package/features/ai/tools/connected.ts +17 -4
  373. package/features/ai/tools/mcp.tool.ts +5 -5
  374. package/features/ai/tools/memory.tool.ts +142 -74
  375. package/features/ai/tools/search.tool.ts +136 -47
  376. package/features/ai/tools/studio.tool.ts +5 -5
  377. package/features/ai/tools/tool-name.ts +2 -3
  378. package/features/ai/tools/workspace.tool.ts +33 -4
  379. package/features/bot/bot.action.ts +24 -7
  380. package/features/bot/bot.memory.ts +89 -0
  381. package/features/bot/bot.query.ts +41 -6
  382. package/features/bot/bot.run.ts +516 -210
  383. package/features/bot/bot.runner.ts +463 -93
  384. package/features/bot/bot.schema.ts +84 -7
  385. package/features/bot/bot.seed.ts +89 -16
  386. package/features/bot/components/bot-mark.tsx +122 -20
  387. package/features/bot/components/bot-room.tsx +519 -391
  388. package/features/bot/components/bot-setting.tsx +832 -341
  389. package/features/bot/components/bot-tool.tsx +2 -6
  390. package/features/bot/components/mark-palette.tsx +54 -0
  391. package/features/bot/components/path-chips.tsx +1 -1
  392. package/features/bot/components/task-badge.tsx +26 -6
  393. package/features/bot/components/task-reply.tsx +22 -33
  394. package/features/bot/components/task-setting.tsx +20 -17
  395. package/features/bot/task.query.ts +233 -33
  396. package/features/bot/task.store.ts +53 -9
  397. package/features/config/components/config-setting.tsx +265 -34
  398. package/features/config/components/models-badge.tsx +42 -0
  399. package/features/config/config.action.ts +12 -0
  400. package/features/config/config.const.ts +38 -2
  401. package/features/connectors/mcp.manager.ts +10 -2
  402. package/features/intro/components/intro.tsx +47 -46
  403. package/features/memory/components/memory-edit.tsx +338 -0
  404. package/features/memory/components/memory-setting.tsx +86 -79
  405. package/features/memory/memory.action.ts +3 -43
  406. package/features/memory/memory.edit.ts +87 -0
  407. package/features/memory/memory.query.ts +33 -44
  408. package/features/memory/memory.schema.ts +50 -97
  409. package/features/settings/components/settings.tsx +2 -0
  410. package/features/settings/settings.alert.ts +3 -1
  411. package/features/skills/components/skills-setting.tsx +9 -1
  412. package/features/thursday/components/ascii-orb.tsx +106 -90
  413. package/features/thursday/components/boot.tsx +7 -0
  414. package/features/thursday/components/call-log.tsx +219 -92
  415. package/features/thursday/components/face.tsx +6 -4
  416. package/features/thursday/components/tab-state.tsx +97 -0
  417. package/features/thursday/components/thursday-mark.tsx +4 -1
  418. package/features/thursday/components/thursday-setting.tsx +17 -47
  419. package/features/thursday/components/thursday.tsx +208 -95
  420. package/features/thursday/thursday.action.ts +12 -17
  421. package/features/thursday/thursday.query.ts +61 -70
  422. package/features/thursday/thursday.schema.ts +20 -7
  423. package/features/thursday/tool-line.ts +85 -11
  424. package/features/thursday/use-thursday.ts +86 -59
  425. package/features/workspace/components/file-view.tsx +4 -2
  426. package/features/workspace/workspace.ts +230 -13
  427. package/hooks/use-draft.ts +37 -0
  428. package/hooks/use-hotkey.ts +105 -0
  429. package/hooks/use-object-state.ts +51 -0
  430. package/hooks/use-on-visible.ts +72 -0
  431. package/hooks/use-theme.ts +106 -0
  432. package/hooks/use-wake-word.ts +262 -0
  433. package/lib/limits.ts +1 -1
  434. package/lib/oauth-page.ts +27 -0
  435. package/lib/realtime/openai.ts +2 -2
  436. package/lib/realtime/realtime.driver.ts +34 -1
  437. package/lib/realtime/realtime.protocol.ts +7 -1
  438. package/lib/realtime/realtime.tap.ts +122 -0
  439. package/lib/sandbox.ts +60 -29
  440. package/lib/tokens.ts +19 -0
  441. package/package.json +1 -1
  442. package/skills/browser/SKILL.md +55 -34
  443. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  444. package/.next/server/app/api/memory/tidy/route.js +0 -23
  445. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  446. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  447. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  448. package/.next/server/chunks/[root-of-the-server]__02kt8yn._.js +0 -10
  449. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  450. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  451. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  452. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  453. package/.next/server/chunks/[root-of-the-server]__0h59di-._.js +0 -5
  454. package/.next/server/chunks/[root-of-the-server]__0j_n5l3._.js +0 -3
  455. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  456. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  457. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  458. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  459. package/.next/server/chunks/[root-of-the-server]__0qjqtwo._.js +0 -5
  460. package/.next/server/chunks/[root-of-the-server]__0t_dqaj._.js +0 -3
  461. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  462. package/.next/server/chunks/[root-of-the-server]__0yk6s3w._.js +0 -5
  463. package/.next/server/chunks/[root-of-the-server]__0z3gelv._.js +0 -3
  464. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  465. package/.next/server/chunks/[root-of-the-server]__113fqg5._.js +0 -12
  466. package/.next/server/chunks/[root-of-the-server]__11w_7_3._.js +0 -3
  467. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  468. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  469. package/.next/server/chunks/[root-of-the-server]__1_0q_9w._.js +0 -3
  470. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  471. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  472. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  473. package/.next/server/chunks/[root-of-the-server]__1dow0bz._.js +0 -3
  474. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  475. package/.next/server/chunks/[root-of-the-server]__1gmn1cs._.js +0 -10
  476. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  477. package/.next/server/chunks/[root-of-the-server]__1mzp_el._.js +0 -3
  478. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  479. package/.next/server/chunks/[root-of-the-server]__1u_qvc7._.js +0 -3
  480. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  481. package/.next/server/chunks/_012yhfm._.js +0 -39
  482. package/.next/server/chunks/_06mxlgn._.js +0 -3
  483. package/.next/server/chunks/_07rtlxv._.js +0 -3
  484. package/.next/server/chunks/_0a351g7._.js +0 -6
  485. package/.next/server/chunks/_0kjjmag._.js +0 -3
  486. package/.next/server/chunks/_0zmestz._.js +0 -55
  487. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  488. package/.next/server/chunks/_12bbv5i._.js +0 -96
  489. package/.next/server/chunks/_15q1pig._.js +0 -3
  490. package/.next/server/chunks/_1drv2et._.js +0 -36
  491. package/.next/server/chunks/_1ic3bew._.js +0 -5
  492. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  493. package/.next/server/chunks/_1uj4_io._.js +0 -10
  494. package/.next/server/chunks/_1x7p319._.js +0 -6
  495. package/.next/server/chunks/_1yldgo4._.js +0 -55
  496. package/.next/server/chunks/_2050gwn._.js +0 -255
  497. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  498. package/.next/server/chunks/features_0scmr4i._.js +0 -3
  499. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  500. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  501. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0ykklj0._.js +0 -3
  502. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1ryg3wh._.js +0 -3
  503. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  504. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vwbnq_._.js +0 -3
  505. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  506. package/.next/server/chunks/ssr/[root-of-the-server]__01id-v3._.js +0 -3
  507. package/.next/server/chunks/ssr/[root-of-the-server]__0b-0i32._.js +0 -3
  508. package/.next/server/chunks/ssr/[root-of-the-server]__0dfwvr4._.js +0 -4
  509. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  510. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -90
  511. package/.next/server/chunks/ssr/[root-of-the-server]__185grso._.js +0 -3
  512. package/.next/server/chunks/ssr/[root-of-the-server]__1minz8_._.js +0 -3
  513. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  514. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  515. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  516. package/.next/server/chunks/ssr/_0ay6b01._.js +0 -3
  517. package/.next/server/chunks/ssr/_0cvjbuz._.js +0 -3
  518. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  519. package/.next/server/chunks/ssr/_0j4v8of._.js +0 -3
  520. package/.next/server/chunks/ssr/_0l81bzy._.js +0 -3
  521. package/.next/server/chunks/ssr/_0nso8tp._.js +0 -3
  522. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  523. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  524. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  525. package/.next/server/chunks/ssr/_10uvw3l._.js +0 -3
  526. package/.next/server/chunks/ssr/_1dcxzqe._.js +0 -3
  527. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  528. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  529. package/.next/server/chunks/ssr/_1jbv7m1._.js +0 -3
  530. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  531. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  532. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  533. package/.next/server/chunks/ssr/lib_realtime_0aetuyp._.js +0 -24
  534. package/.next/server/chunks/ssr/lib_realtime_18k_aj-._.js +0 -24
  535. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_errors_05xv7vp.js +0 -3
  536. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  537. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  538. package/.next/static/chunks/0tydnn2kybibk.js +0 -1
  539. package/.next/static/chunks/0yysv1gzin17t.js +0 -1
  540. package/.next/static/chunks/1fr5m75pwtyic.js +0 -1
  541. package/.next/static/chunks/1gy3bbv7usnjo.js +0 -1
  542. package/.next/static/chunks/1keib_gt066gc.js +0 -1
  543. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  544. package/.next/static/chunks/21rk8w7bda-su.js +0 -1
  545. package/.next/static/chunks/247d-r95j8xs0.js +0 -1
  546. package/.next/static/chunks/28g42tw8tsvhd.js +0 -1
  547. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  548. package/.next/static/chunks/2cwjgkt_hoyhj.js +0 -22
  549. package/.next/static/chunks/2fq_86jvq9ymq.js +0 -2
  550. package/.next/static/chunks/2rbf1fpd8n80-.js +0 -22
  551. package/.next/static/chunks/2ukj8k69y89um.js +0 -1
  552. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  553. package/.next/static/chunks/2wngeetfnzxkp.js +0 -2
  554. package/.next/static/chunks/388-t2v72jh39.css +0 -1
  555. package/.next/static/chunks/3fqvc0cg-atq_.js +0 -1
  556. package/.next/static/chunks/3p4egvfjxpatb.js +0 -1
  557. package/.next/static/chunks/3qe1w1ei-huhl.js +0 -1
  558. package/.next/static/chunks/3xxa2j56-f3nm.js +0 -3
  559. package/.next/static/chunks/3y40riycdip-i.js +0 -1
  560. package/.next/static/chunks/45a6zbtkelph9.js +0 -1
  561. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  562. package/features/ai/prompts/memory-tidy.prompt.ts +0 -123
  563. package/features/ai/tools/tidy.tool.ts +0 -22
  564. package/features/memory/components/memory-tidy.tsx +0 -395
  565. package/features/memory/memory.tidy.ts +0 -332
  566. package/features/memory/tidy.query.ts +0 -135
  567. package/features/thursday/use-call-title.ts +0 -31
  568. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/build-manifest.json +0 -0
  569. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route/server-reference-manifest.json +0 -0
  570. /package/.next/server/app/api/{memory/tidy → bot/memory/files}/route.js.map +0 -0
  571. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
  572. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
  573. /package/.next/static/{X34BUd9bfdH27ripuwwBm → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
@@ -0,0 +1,262 @@
1
+ "use client";
2
+
3
+ import { useEffect, useRef } from "react";
4
+
5
+ /**
6
+ * Wake-word listener built on the browser's Web Speech API (no realtime socket
7
+ * while idle). It is a transcriber, not a KWS engine, so matching is fuzzy.
8
+ * Chrome streams idle audio to Google; Firefox has no recognizer (onError only).
9
+ */
10
+
11
+ /** lib.dom types the result objects but not the recognizer itself. */
12
+ type SpeechRecognitionLike = {
13
+ lang: string;
14
+ continuous: boolean;
15
+ interimResults: boolean;
16
+ maxAlternatives: number;
17
+ start(): void;
18
+ stop(): void;
19
+ abort(): void;
20
+ onresult:
21
+ | ((event: {
22
+ resultIndex: number;
23
+ results: SpeechRecognitionResultList;
24
+ }) => void)
25
+ | null;
26
+ onerror: ((event: { error: string }) => void) | null;
27
+ onend: (() => void) | null;
28
+ };
29
+
30
+ type SpeechRecognitionCtor = new () => SpeechRecognitionLike;
31
+
32
+ /**
33
+ * Default recognizer language. English keeps one spelling to compare against
34
+ * regardless of the speaker's accent; callers with a non-English name pass
35
+ * `lang` and `phrases` together.
36
+ */
37
+ export const WAKE_LANG = "en-US";
38
+
39
+ /**
40
+ * Allowed edit distance per word as a fraction of its length ("hey" = 1 edit,
41
+ * "thursday" = 3). Lower misses accents; higher lets ordinary speech wake.
42
+ */
43
+ const WAKE_TOLERANCE = 0.34;
44
+
45
+ /** Alternatives per result; the second-ranked guess is often the right one. */
46
+ const ALTERNATIVES = 3;
47
+
48
+ /** Delay before restarting after `onend`, so error loops do not spin. */
49
+ const RESTART_MS = 300;
50
+ /** Backoff cap while the recognition service is unreachable. */
51
+ const RESTART_MAX_MS = 10_000;
52
+
53
+ /** Errors a restart cannot fix. */
54
+ const FATAL: Record<string, string> = {
55
+ "not-allowed": "The microphone is not allowed",
56
+ "service-not-allowed": "The microphone is not allowed",
57
+ "audio-capture": "There is no microphone",
58
+ "language-not-supported": "This browser cannot listen in that language",
59
+ };
60
+
61
+ /** Case and punctuation vary per recognizer; word boundaries do not. */
62
+ const normalize = (text: string) =>
63
+ text
64
+ .toLowerCase()
65
+ .replace(/[^a-z0-9 ]/g, "")
66
+ .split(/\s+/)
67
+ .filter(Boolean);
68
+
69
+ /** Plain Levenshtein distance between two words. */
70
+ function distance(heard: string, want: string): number {
71
+ let previous = Array.from({ length: heard.length + 1 }, (_, index) => index);
72
+ let current = new Array<number>(heard.length + 1).fill(0);
73
+
74
+ for (let row = 1; row <= want.length; row++) {
75
+ current[0] = row;
76
+ for (let column = 1; column <= heard.length; column++) {
77
+ const substitute =
78
+ previous[column - 1] + (want[row - 1] === heard[column - 1] ? 0 : 1);
79
+ current[column] = Math.min(
80
+ substitute,
81
+ previous[column] + 1,
82
+ current[column - 1] + 1,
83
+ );
84
+ }
85
+ [previous, current] = [current, previous];
86
+ }
87
+
88
+ return previous[heard.length];
89
+ }
90
+
91
+ /** Within `budget` edits; the length check short-circuits most words. */
92
+ const near = (heard: string, want: string, budget: number) =>
93
+ Math.abs(heard.length - want.length) <= budget &&
94
+ distance(heard, want) <= budget;
95
+
96
+ /**
97
+ * Whether `want[from..]` is spoken contiguously starting at `heard[at]`.
98
+ * One wanted word may span two heard words ("there's day" for "thursday").
99
+ */
100
+ function saidAt(
101
+ heard: readonly string[],
102
+ at: number,
103
+ want: readonly string[],
104
+ from: number,
105
+ tolerance: number,
106
+ ): boolean {
107
+ if (from === want.length) return true;
108
+ if (at >= heard.length) return false;
109
+
110
+ const word = want[from];
111
+ // Never 0, or "hay" for "hey" fails.
112
+ const budget = Math.max(1, Math.round(word.length * tolerance));
113
+
114
+ if (
115
+ near(heard[at], word, budget) &&
116
+ saidAt(heard, at + 1, want, from + 1, tolerance)
117
+ ) {
118
+ return true;
119
+ }
120
+ return (
121
+ at + 1 < heard.length &&
122
+ near(heard[at] + heard[at + 1], word, budget) &&
123
+ saidAt(heard, at + 2, want, from + 1, tolerance)
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Whether `heard` contains `want` as one contiguous phrase. Scoring is per
129
+ * word, not over the joined string, so every word must be present and adjacent.
130
+ */
131
+ function contains(
132
+ heard: readonly string[],
133
+ want: readonly string[],
134
+ tolerance: number,
135
+ ): boolean {
136
+ for (let at = 0; at < heard.length; at++) {
137
+ if (saidAt(heard, at, want, 0, tolerance)) return true;
138
+ }
139
+ return false;
140
+ }
141
+
142
+ type WakeOptions = {
143
+ /** Releases the microphone when false; must be false while a call is open. */
144
+ enabled: boolean;
145
+ /** Receives the raw transcript that matched. */
146
+ onWake: (heard: string) => void;
147
+ /** Phrases to listen for, matched fuzzily. */
148
+ phrases: readonly string[];
149
+ lang?: string;
150
+ /** See WAKE_TOLERANCE. */
151
+ tolerance?: number;
152
+ /** Unrecoverable failures only (denied or missing microphone). */
153
+ onError?: (reason: string) => void;
154
+ };
155
+
156
+ export function useWakeWord({
157
+ enabled,
158
+ onWake,
159
+ phrases,
160
+ lang = WAKE_LANG,
161
+ tolerance = WAKE_TOLERANCE,
162
+ onError,
163
+ }: WakeOptions) {
164
+ // Read at result time so re-renders and phrase changes do not restart the
165
+ // recognizer; only `lang` must be set before start.
166
+ const latest = useRef({ onWake, onError, phrases, tolerance });
167
+ latest.current = { onWake, onError, phrases, tolerance };
168
+
169
+ useEffect(() => {
170
+ if (!enabled) return;
171
+
172
+ const global = window as unknown as Record<string, unknown>;
173
+ const Ctor = (global.SpeechRecognition ?? global.webkitSpeechRecognition) as
174
+ | SpeechRecognitionCtor
175
+ | undefined;
176
+
177
+ if (!Ctor) {
178
+ latest.current.onError?.("This browser cannot listen for a wake word");
179
+ return;
180
+ }
181
+
182
+ const recognition = new Ctor();
183
+ // Latched off on cleanup so late events cannot revive the recognizer.
184
+ let alive = true;
185
+ // Off from a match until the restart that clears the transcript.
186
+ let armed = true;
187
+ let restart: ReturnType<typeof setTimeout> | null = null;
188
+ let delay = RESTART_MS;
189
+
190
+ recognition.lang = lang;
191
+ // Interim results are enough; waiting for isFinal loses a beat.
192
+ recognition.continuous = true;
193
+ recognition.interimResults = true;
194
+ recognition.maxAlternatives = ALTERNATIVES;
195
+
196
+ const listen = () => {
197
+ if (!alive) return;
198
+ armed = true;
199
+ try {
200
+ recognition.start();
201
+ } catch {
202
+ // Already running (InvalidStateError).
203
+ }
204
+ };
205
+
206
+ recognition.onresult = ({ resultIndex, results }) => {
207
+ if (!alive || !armed) return;
208
+ delay = RESTART_MS;
209
+
210
+ const { phrases, tolerance, onWake } = latest.current;
211
+ const targets = phrases.map(normalize).filter((words) => words.length);
212
+
213
+ // Results before resultIndex are final and already seen.
214
+ for (let index = resultIndex; index < results.length; index++) {
215
+ const result = results[index];
216
+ for (let rank = 0; rank < result.length; rank++) {
217
+ const heard = result[rank].transcript;
218
+ const words = normalize(heard);
219
+ if (!targets.some((target) => contains(words, target, tolerance))) {
220
+ continue;
221
+ }
222
+
223
+ // Abort before notifying: the transcript keeps growing and would
224
+ // match again on the next event. `onend` restarts unless the caller
225
+ // has dropped `enabled` by then.
226
+ armed = false;
227
+ recognition.abort();
228
+ onWake(heard.trim());
229
+ return;
230
+ }
231
+ }
232
+ };
233
+
234
+ recognition.onerror = ({ error }) => {
235
+ const reason = FATAL[error];
236
+ if (reason) {
237
+ alive = false;
238
+ latest.current.onError?.(reason);
239
+ } else if (error === "network") {
240
+ delay = Math.min(delay * 2, RESTART_MAX_MS);
241
+ }
242
+ // no-speech and aborted are normal for this API.
243
+ };
244
+
245
+ // Chrome ends a silent session after about a minute; keep restarting.
246
+ recognition.onend = () => {
247
+ if (!alive) return;
248
+ restart = setTimeout(listen, delay);
249
+ };
250
+
251
+ listen();
252
+
253
+ return () => {
254
+ alive = false;
255
+ if (restart) clearTimeout(restart);
256
+ recognition.onresult = null;
257
+ recognition.onerror = null;
258
+ recognition.onend = null;
259
+ recognition.abort();
260
+ };
261
+ }, [enabled, lang]);
262
+ }
package/lib/limits.ts CHANGED
@@ -9,6 +9,6 @@ export const COMMON_VALIDATE = {
9
9
  max: 100,
10
10
  },
11
11
  prompt: {
12
- max: 2000,
12
+ max: 4000,
13
13
  },
14
14
  };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The page an OAuth redirect lands on: a detour tab that says how it went and closes itself
3
+ * when it went well. Every sign-in that comes back through a browser draws this one.
4
+ */
5
+ export function oauthPage(
6
+ title: string,
7
+ detail: string,
8
+ { autoClose = false }: { autoClose?: boolean } = {},
9
+ ): string {
10
+ return `<!doctype html>
11
+ <meta charset="utf-8">
12
+ <title>${escapeHtml(title)}</title>
13
+ <body style="font-family: ui-monospace, monospace; display: grid; place-items: center; min-height: 100dvh; margin: 0">
14
+ <div style="text-align: center; max-width: 28rem; padding: 1.5rem">
15
+ <p style="font-size: 1.125rem; margin: 0 0 .5rem">${escapeHtml(title)}</p>
16
+ <p style="color: #666; font-size: .875rem; margin: 0">${escapeHtml(detail)}</p>
17
+ </div>
18
+ ${autoClose ? "<script>setTimeout(() => window.close(), 900)</script>" : ""}
19
+ </body>`;
20
+ }
21
+
22
+ function escapeHtml(text: string) {
23
+ return text
24
+ .replaceAll("&", "&amp;")
25
+ .replaceAll("<", "&lt;")
26
+ .replaceAll(">", "&gt;");
27
+ }
@@ -6,8 +6,8 @@ import { createWebRtcTransport } from "./realtime.transport";
6
6
 
7
7
  const CALLS_URL = "https://api.openai.com/v1/realtime/calls";
8
8
 
9
- /** Streams user transcripts as recognized; whisper-1 reports only after the turn ends. */
10
- const TRANSCRIPTION_MODEL = "gpt-4o-mini-transcribe";
9
+ /** Streams user transcripts as recognized; the file models report only after the turn ends. */
10
+ const TRANSCRIPTION_MODEL = "gpt-live-transcribe";
11
11
 
12
12
  export const createOpenAiSession = realtimeSession({
13
13
  transport: ({ credential, audio, on }) =>
@@ -1,3 +1,4 @@
1
+ import { logger } from "@/lib/logger";
1
2
  import { errorToString } from "@/lib/utils";
2
3
  import type {
3
4
  RealtimeFunctionTool,
@@ -85,6 +86,9 @@ export function realtimeSession(
85
86
  } | null = null;
86
87
  let ackTimer: ReturnType<typeof setTimeout> | null = null;
87
88
 
89
+ /** Event types this session has already noted as unhandled (see `default`). */
90
+ const seenUnhandled = new Set<string>();
91
+
88
92
  const turns: Turn[] = [];
89
93
  const slot = new Map<string, number>();
90
94
  const finalized = new Set<string>();
@@ -339,7 +343,25 @@ export function realtimeSession(
339
343
 
340
344
  case "conversation.item.input_audio_transcription.completed":
341
345
  write(event.item_id, "user", event.transcript ?? "", "replace");
342
- finish(event.item_id);
346
+ // Not always the end of the turn. xAI sends this while the user is
347
+ // still speaking, each time with a longer transcript and `in_progress`
348
+ // on it; finishing on the first froze the turn at its opening words
349
+ // and every later transcript was written but never reported (`write`
350
+ // reports only what is not finalized). A provider that sends it once
351
+ // omits the field, so anything but `in_progress` ends the turn.
352
+ if (event.status !== "in_progress") finish(event.item_id);
353
+ break;
354
+
355
+ // A turn nobody could read. Without this the item simply never gets
356
+ // words, and an item with no words is not reported at all (`report`) —
357
+ // the turn disappears from the transcript, and every reader downstream
358
+ // sees a conversation the user did not have.
359
+ case "conversation.item.input_audio_transcription.failed":
360
+ on.warn(
361
+ event.error?.message
362
+ ? `That turn could not be transcribed: ${event.error.message}`
363
+ : "That turn could not be transcribed.",
364
+ );
343
365
  break;
344
366
 
345
367
  case "response.output_audio_transcript.delta":
@@ -388,6 +410,17 @@ export function realtimeSession(
388
410
  finish(event.item_id);
389
411
  onToolCall(event);
390
412
  break;
413
+
414
+ default:
415
+ // Providers speak this protocol with their own additions, and a case
416
+ // that is missing here is invisible: the event is dropped and the
417
+ // conversation quietly loses whatever it carried. Once per type per
418
+ // session, so a busy stream cannot drown the log.
419
+ if (!seenUnhandled.has(event.type)) {
420
+ seenUnhandled.add(event.type);
421
+ logger.debug(`realtime: no case for ${event.type}`);
422
+ }
423
+ break;
391
424
  }
392
425
  settle();
393
426
  };
@@ -46,7 +46,7 @@ export type OpenAiSessionConfig = {
46
46
  audio?: {
47
47
  input?: {
48
48
  format?: RealtimeAudioFormat;
49
- /** Null turns transcription off. `whisper-1` reports only at turn end; `gpt-4o-*-transcribe` streams deltas. */
49
+ /** Null turns transcription off. A file model reports only at turn end; `gpt-live-transcribe` streams deltas. */
50
50
  transcription?: {
51
51
  model: string;
52
52
  language?: string;
@@ -308,6 +308,12 @@ export type RealtimeServerEvent =
308
308
  type: "conversation.item.input_audio_transcription.completed";
309
309
  item_id: string;
310
310
  transcript: string;
311
+ /**
312
+ * xAI sends this event repeatedly while the turn is still being
313
+ * transcribed, each time with more of it and `in_progress` here; only the
314
+ * last carries `completed`. OpenAI sends it once and omits the field.
315
+ */
316
+ status?: "in_progress" | "completed" | string;
311
317
  }
312
318
  /** OpenAI only. */
313
319
  | {
@@ -131,3 +131,125 @@ export function createAudioTap(): RealtimeAudio & {
131
131
  },
132
132
  };
133
133
  }
134
+
135
+ /** What a face moves with on one frame (createVoiceFollower). */
136
+ export type VoiceFrame = {
137
+ /** How far into its own range the voice is now, 0..1; 0 in silence. */
138
+ level: number;
139
+ /** `level` over about half a second: the phrase rather than the syllable. */
140
+ phrase: number;
141
+ /** Strength of a syllable that started on this frame; 0 when none did. */
142
+ onset: number;
143
+ /** Each band inside its own range, low to high; one the voice never reaches stays 0. */
144
+ bands: number[];
145
+ };
146
+
147
+ /** Seconds, except where a line says otherwise. */
148
+ const FOLLOW = {
149
+ /** A band's ceiling jumps to a new peak and sinks back over `ceilRelease`. */
150
+ ceilAttack: 0.03,
151
+ ceilRelease: 2.5,
152
+ /** Its floor drops to the quiet between syllables and creeps back up over `floorRise`. */
153
+ floorFall: 0.12,
154
+ floorRise: 3,
155
+ /** A band whose range is narrower than this (0..1) carries no shape. */
156
+ minSpan: 0.12,
157
+ /** Mean band level (0..1) across which silence turns into voice. */
158
+ quietBelow: 0.03,
159
+ voicedAbove: 0.12,
160
+ fast: 0.05,
161
+ mid: 0.22,
162
+ phrase: 0.45,
163
+ /** A syllable: the fast level rises this far over the mid one, past `onsetMin`, at most once per `onsetGap`. */
164
+ onsetRise: 0.1,
165
+ onsetMin: 0.3,
166
+ onsetGap: 0.12,
167
+ };
168
+
169
+ /**
170
+ * Reads the voice's bands the way a face needs them. A voice is loud and narrow:
171
+ * its bands sit near the top and lean the same way for a whole sentence, so a
172
+ * face driven by them directly stays swollen and still. Here each band is
173
+ * followed inside its own recent range — the quiet between syllables is its
174
+ * floor, the syllables its ceiling — so the face moves with the words whatever
175
+ * the voice or its volume. One per face; it keeps state between frames.
176
+ */
177
+ export function createVoiceFollower() {
178
+ const ceil = new Array<number>(SPECTRUM_BANDS).fill(0);
179
+ const floor = new Array<number>(SPECTRUM_BANDS).fill(0);
180
+ const frame: VoiceFrame = {
181
+ level: 0,
182
+ phrase: 0,
183
+ onset: 0,
184
+ bands: new Array<number>(SPECTRUM_BANDS).fill(0),
185
+ };
186
+ let fast = 0;
187
+ let mid = 0;
188
+ let sinceOnset = Number.POSITIVE_INFINITY;
189
+
190
+ const toward = (from: number, to: number, seconds: number, dt: number) =>
191
+ from + (to - from) * Math.min(1, dt / seconds);
192
+
193
+ return {
194
+ /** Call once per frame with the seconds since the last call. The frame returned is reused. */
195
+ read(input: ArrayLike<number>, dt: number): VoiceFrame {
196
+ let total = 0;
197
+ let within = 0;
198
+ let ranged = 0;
199
+ for (let k = 0; k < SPECTRUM_BANDS; k++) {
200
+ const x = input[k] ?? 0;
201
+ total += x;
202
+ ceil[k] = toward(
203
+ ceil[k],
204
+ x,
205
+ x > ceil[k] ? FOLLOW.ceilAttack : FOLLOW.ceilRelease,
206
+ dt,
207
+ );
208
+ floor[k] = toward(
209
+ floor[k],
210
+ x,
211
+ x < floor[k] ? FOLLOW.floorFall : FOLLOW.floorRise,
212
+ dt,
213
+ );
214
+ const span = ceil[k] - floor[k];
215
+ const at =
216
+ span > FOLLOW.minSpan
217
+ ? Math.min(1, Math.max(0, (x - floor[k]) / span))
218
+ : 0;
219
+ frame.bands[k] = at;
220
+ if (span > FOLLOW.minSpan) {
221
+ within += at;
222
+ ranged++;
223
+ }
224
+ }
225
+
226
+ const mean = total / SPECTRUM_BANDS;
227
+ const edge = Math.min(
228
+ 1,
229
+ Math.max(
230
+ 0,
231
+ (mean - FOLLOW.quietBelow) / (FOLLOW.voicedAbove - FOLLOW.quietBelow),
232
+ ),
233
+ );
234
+ const voiced = edge * edge * (3 - 2 * edge);
235
+ for (let k = 0; k < SPECTRUM_BANDS; k++) frame.bands[k] *= voiced;
236
+
237
+ frame.level = (ranged ? within / ranged : 0) * voiced;
238
+ fast = toward(fast, frame.level, FOLLOW.fast, dt);
239
+ mid = toward(mid, frame.level, FOLLOW.mid, dt);
240
+ frame.phrase = toward(frame.phrase, frame.level, FOLLOW.phrase, dt);
241
+
242
+ sinceOnset += dt;
243
+ frame.onset = 0;
244
+ if (
245
+ fast > mid + FOLLOW.onsetRise &&
246
+ fast > FOLLOW.onsetMin &&
247
+ sinceOnset > FOLLOW.onsetGap
248
+ ) {
249
+ sinceOnset = 0;
250
+ frame.onset = Math.min(1, fast);
251
+ }
252
+ return frame;
253
+ },
254
+ };
255
+ }
package/lib/sandbox.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
3
3
  import { join, resolve as pathResolve, relative, sep } from "node:path";
4
+ import { EXEC_KILL_GRACE_MS, EXEC_TIMEOUT_MS } from "@/config";
4
5
 
5
6
  export type ExecResult = { stdout: string; stderr: string; exitCode: number };
6
7
 
@@ -53,6 +54,25 @@ const IGNORE = new Set([
53
54
  "coverage",
54
55
  ]);
55
56
 
57
+ /**
58
+ * Every file under `dir`, skipping dot entries and the folders a build or a
59
+ * package manager fills (IGNORE). A folder that cannot be read yields nothing.
60
+ */
61
+ export async function* walkFiles(dir: string): AsyncGenerator<string> {
62
+ let entries;
63
+ try {
64
+ entries = await readdir(dir, { withFileTypes: true });
65
+ } catch {
66
+ return;
67
+ }
68
+ for (const e of entries) {
69
+ if (IGNORE.has(e.name) || e.name.startsWith(".")) continue;
70
+ const full = join(dir, e.name);
71
+ if (e.isDirectory()) yield* walkFiles(full);
72
+ else if (e.isFile()) yield full;
73
+ }
74
+ }
75
+
56
76
  /**
57
77
  * Environment for every shell the agent runs: nobody watches it, so no pager
58
78
  * may stall it, and secrets do not travel to children. playwright-cli runs
@@ -100,21 +120,6 @@ export const createSandBox = ({
100
120
  const res = (p: string) =>
101
121
  p.startsWith("/") || /^[A-Za-z]:/.test(p) ? p : pathResolve(cwd, p);
102
122
 
103
- async function* walk(dir: string): AsyncGenerator<string> {
104
- let entries;
105
- try {
106
- entries = await readdir(dir, { withFileTypes: true });
107
- } catch {
108
- return;
109
- }
110
- for (const e of entries) {
111
- if (IGNORE.has(e.name) || e.name.startsWith(".")) continue;
112
- const full = join(dir, e.name);
113
- if (e.isDirectory()) yield* walk(full);
114
- else if (e.isFile()) yield full;
115
- }
116
- }
117
-
118
123
  // A very simple glob → regex. Only **/, * and ? are supported
119
124
  const globToRe = (g: string) =>
120
125
  new RegExp(
@@ -147,7 +152,7 @@ export const createSandBox = ({
147
152
  const root = res(path);
148
153
  const re = globToRe(pattern);
149
154
  const out: string[] = [];
150
- for await (const f of walk(root)) {
155
+ for await (const f of walkFiles(root)) {
151
156
  const rel = relative(root, f).split(sep).join("/");
152
157
  if (re.test(rel) || re.test(f)) out.push(f);
153
158
  if (out.length >= limit) break;
@@ -155,7 +160,7 @@ export const createSandBox = ({
155
160
  return out;
156
161
  },
157
162
 
158
- exec(command, { cwd: c, timeoutMs = 180_000, signal, env } = {}) {
163
+ exec(command, { cwd: c, timeoutMs = EXEC_TIMEOUT_MS, signal, env } = {}) {
159
164
  return new Promise((resolve) => {
160
165
  const base = shellEnv();
161
166
  if (extraPath) base.PATH = `${base.PATH ?? ""}:${extraPath}`;
@@ -172,28 +177,26 @@ export const createSandBox = ({
172
177
  child.stdout?.on("data", (d) => (stdout += d));
173
178
  child.stderr?.on("data", (d) => (stderr += d));
174
179
 
175
- const stop = (why: string) => {
176
- stderr += `\n[${why}]`;
180
+ const group = (name: NodeJS.Signals) => {
177
181
  try {
178
182
  // A negative pid means the group: the shell and everything under it
179
- if (child.pid) process.kill(-child.pid, "SIGTERM");
183
+ if (child.pid) process.kill(-child.pid, name);
180
184
  } catch {
181
185
  // Already gone, or no process groups on this platform
182
- child.kill("SIGTERM");
186
+ child.kill(name);
183
187
  }
184
188
  };
185
189
 
186
- const timer = setTimeout(
187
- () => stop(`Timed out after ${timeoutMs}ms`),
188
- timeoutMs,
189
- );
190
-
191
- const onAbort = () => stop("Aborted");
192
- if (signal?.aborted) onAbort();
193
- else signal?.addEventListener("abort", onAbort, { once: true });
190
+ let settled = false;
191
+ let killing: ReturnType<typeof setTimeout> | undefined;
192
+ let letGo: ReturnType<typeof setTimeout> | undefined;
194
193
 
195
194
  const done = async (result: ExecResult) => {
195
+ if (settled) return;
196
+ settled = true;
196
197
  clearTimeout(timer);
198
+ clearTimeout(killing);
199
+ clearTimeout(letGo);
197
200
  signal?.removeEventListener("abort", onAbort);
198
201
  resolve({
199
202
  ...result,
@@ -202,6 +205,34 @@ export const createSandBox = ({
202
205
  });
203
206
  };
204
207
 
208
+ const stop = (why: string) => {
209
+ if (killing || settled) return;
210
+ stderr += `\n[${why}]`;
211
+ group("SIGTERM");
212
+ // A command that ignores SIGTERM would hold its step, and everything
213
+ // waiting on the job, for good (config EXEC_KILL_GRACE_MS)
214
+ killing = setTimeout(() => {
215
+ stderr += "\n[Killed: it did not exit on SIGTERM]";
216
+ group("SIGKILL");
217
+ // Output held open by a process that left the group never closes;
218
+ // what arrived by now is the result
219
+ letGo = setTimeout(() => {
220
+ child.stdout?.destroy();
221
+ child.stderr?.destroy();
222
+ void done({ stdout, stderr, exitCode: -1 });
223
+ }, 1_000);
224
+ }, EXEC_KILL_GRACE_MS);
225
+ };
226
+
227
+ const timer = setTimeout(
228
+ () => stop(`Timed out after ${timeoutMs}ms`),
229
+ timeoutMs,
230
+ );
231
+
232
+ const onAbort = () => stop("Aborted");
233
+ if (signal?.aborted) onAbort();
234
+ else signal?.addEventListener("abort", onAbort, { once: true });
235
+
205
236
  child.on("close", (code) =>
206
237
  done({ stdout, stderr, exitCode: code ?? -1 }),
207
238
  );
package/lib/tokens.ts CHANGED
@@ -14,3 +14,22 @@ export function estimateTokens(text: string): number {
14
14
  }
15
15
  return Math.ceil(cjk / 1.3 + other / 4);
16
16
  }
17
+
18
+ /**
19
+ * One assembled prompt measured by its own `##` headings, biggest first. Read
20
+ * off the finished text rather than off what built it: what is counted is then
21
+ * what is actually sent, and a chapter cannot be added without appearing here.
22
+ */
23
+ export function sectionTokens(
24
+ text: string,
25
+ ): { name: string; tokens: number }[] {
26
+ return text
27
+ .split(/\n(?=## )/)
28
+ .map((block) => ({
29
+ name: block.startsWith("## ")
30
+ ? block.slice(3, block.indexOf("\n"))
31
+ : "identity",
32
+ tokens: estimateTokens(block),
33
+ }))
34
+ .sort((a, b) => b.tokens - a.tokens);
35
+ }