thursday-agent 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +5 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +5 -5
  5. package/.next/routes-manifest.json +24 -6
  6. package/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +2 -2
  11. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found/page.js +2 -2
  15. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +14 -14
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/server/app/api/artifact/route.js +3 -3
  23. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/files/route/app-paths-manifest.json +3 -0
  25. package/.next/server/app/api/bot/memory/files/route.js +10 -0
  26. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -0
  27. package/.next/server/app/api/bot/memory/files/route_client-reference-manifest.js +3 -0
  28. package/.next/server/app/api/bot/memory/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/memory/route.js +14 -0
  30. package/.next/server/app/api/bot/{notes → memory}/route.js.nft.json +1 -1
  31. package/.next/server/app/api/bot/memory/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/route.js +6 -6
  33. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  34. package/.next/server/app/api/bot/task/[id]/route.js +8 -8
  35. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +1 -1
  36. package/.next/server/app/api/bot/task/route.js +8 -8
  37. package/.next/server/app/api/bot/task/route.js.nft.json +1 -1
  38. package/.next/server/app/api/config/route.js +5 -5
  39. package/.next/server/app/api/config/route.js.nft.json +1 -1
  40. package/.next/server/app/api/events/route.js +4 -5
  41. package/.next/server/app/api/events/route.js.nft.json +1 -1
  42. package/.next/server/app/api/file/[...path]/route.js +3 -3
  43. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/catalog/route.js +9 -8
  45. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +3 -0
  47. package/.next/server/app/api/llm-model/credits/route/build-manifest.json +12 -0
  48. package/.next/server/app/api/llm-model/credits/route/server-reference-manifest.json +4 -0
  49. package/.next/server/app/api/llm-model/credits/route.js +16 -0
  50. package/.next/server/app/api/llm-model/credits/route.js.map +5 -0
  51. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -0
  52. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +3 -0
  53. package/.next/server/app/api/llm-model/route.js +10 -8
  54. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  55. package/.next/server/app/api/llm-model/subscription/route/app-paths-manifest.json +3 -0
  56. package/.next/server/app/api/llm-model/subscription/route/build-manifest.json +12 -0
  57. package/.next/server/app/api/llm-model/subscription/route/server-reference-manifest.json +4 -0
  58. package/.next/server/app/api/llm-model/subscription/route.js +15 -0
  59. package/.next/server/app/api/llm-model/subscription/route.js.map +5 -0
  60. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -0
  61. package/.next/server/app/api/llm-model/subscription/route_client-reference-manifest.js +3 -0
  62. package/.next/server/app/api/mcp/[name]/route.js +4 -4
  63. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
  65. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  66. package/.next/server/app/api/mcp/route.js +4 -4
  67. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  68. package/.next/server/app/api/mcp/tools/route.js +4 -4
  69. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  70. package/.next/server/app/api/memory/edit/route/app-paths-manifest.json +3 -0
  71. package/.next/server/app/api/memory/edit/route/build-manifest.json +12 -0
  72. package/.next/server/app/api/memory/edit/route/server-reference-manifest.json +4 -0
  73. package/.next/server/app/api/memory/edit/route.js +24 -0
  74. package/.next/server/app/api/memory/edit/route.js.map +5 -0
  75. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -0
  76. package/.next/server/app/api/memory/{tidy → edit}/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/memory/route.js +6 -7
  78. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  79. package/.next/server/app/api/skills/[source]/[name]/route.js +3 -3
  80. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  81. package/.next/server/app/api/skills/route.js +3 -3
  82. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  83. package/.next/server/app/api/thursday/call/route.js +9 -7
  84. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  85. package/.next/server/app/api/thursday/skills/route.js +9 -7
  86. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  87. package/.next/server/app/api/thursday/tool-call/route.js +17 -15
  88. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  89. package/.next/server/app/api/workspace/route.js +4 -5
  90. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  91. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  92. package/.next/server/app/artifact/[...path]/page.js +5 -6
  93. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  94. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  95. package/.next/server/app/favicon.ico/route.js +3 -4
  96. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  97. package/.next/server/app/favicon.ico.body +0 -0
  98. package/.next/server/app/page/server-reference-manifest.json +57 -90
  99. package/.next/server/app/page.js +10 -10
  100. package/.next/server/app/page.js.nft.json +1 -1
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app-paths-manifest.json +5 -2
  103. package/.next/server/chunks/[externals]__0dzuk6_._.js +3 -0
  104. package/.next/server/chunks/[root-of-the-server]__01dkp4a._.js +3 -0
  105. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +1 -1
  106. package/.next/server/chunks/[root-of-the-server]__02xjoto._.js +3 -0
  107. package/.next/server/chunks/[root-of-the-server]__04q--0f._.js +8 -0
  108. package/.next/server/chunks/[root-of-the-server]__0bl-e63._.js +3 -0
  109. package/.next/server/chunks/[root-of-the-server]__0ce8nf8._.js +5 -0
  110. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +3 -0
  111. package/.next/server/chunks/[root-of-the-server]__0j7z0r3._.js +12 -0
  112. package/.next/server/chunks/[root-of-the-server]__0jq4ohy._.js +8 -0
  113. package/.next/server/chunks/[root-of-the-server]__0ls6_8y._.js +8 -0
  114. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +3 -0
  115. package/.next/server/chunks/[root-of-the-server]__0pa2n68._.js +3 -0
  116. package/.next/server/chunks/[root-of-the-server]__0q0vvt2._.js +5 -0
  117. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +5 -0
  118. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +5 -0
  119. package/.next/server/chunks/[root-of-the-server]__12cabg9._.js +3 -0
  120. package/.next/server/chunks/[root-of-the-server]__1339jnv._.js +8 -0
  121. package/.next/server/chunks/[root-of-the-server]__15bjnu5._.js +5 -0
  122. package/.next/server/chunks/[root-of-the-server]__18_teo8._.js +8 -0
  123. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +5 -0
  124. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +3 -0
  125. package/.next/server/chunks/[root-of-the-server]__1ccon1w._.js +5 -5
  126. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +3 -0
  127. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +3 -0
  128. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +11 -0
  129. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +3 -0
  130. package/.next/server/chunks/[root-of-the-server]__1wa1k7r._.js +8 -0
  131. package/.next/server/chunks/_0-73of8._.js +5 -5
  132. package/.next/server/chunks/_0-fjql4._.js +26 -0
  133. package/.next/server/chunks/_00xh_q0._.js +27 -0
  134. package/.next/server/chunks/{_0pppbb5._.js → _03kp0jp._.js} +163 -36
  135. package/.next/server/chunks/_051qh8u._.js +3 -0
  136. package/.next/server/chunks/{node_modules_next_04q-o58._.js → _05dla15._.js} +2 -2
  137. package/.next/server/chunks/_05h2cii._.js +1 -1
  138. package/.next/server/chunks/_0c9j6rb._.js +49 -0
  139. package/.next/server/chunks/_0fzqt2y._.js +130 -0
  140. package/.next/server/chunks/{_0vnutv9._.js → _0ioz3nd._.js} +1 -1
  141. package/.next/server/chunks/_0iwfby5._.js +3 -0
  142. package/.next/server/chunks/_0mecv0f._.js +26 -0
  143. package/.next/server/chunks/_0mh8j4m._.js +3 -0
  144. package/.next/server/chunks/_0n74zsf._.js +4 -4
  145. package/.next/server/chunks/_0obojvv._.js +3 -0
  146. package/.next/server/chunks/_0recufk._.js +49 -0
  147. package/.next/server/chunks/_0rnf-6n._.js +4 -4
  148. package/.next/server/chunks/_0sb7tlz._.js +3 -0
  149. package/.next/server/chunks/_0u10wmw._.js +5 -5
  150. package/.next/server/chunks/_0u4aiy2._.js +3 -0
  151. package/.next/server/chunks/_0wp4le3._.js +1 -1
  152. package/.next/server/chunks/_0y5fg-x._.js +1 -1
  153. package/.next/server/chunks/_1230wbx._.js +10 -0
  154. package/.next/server/chunks/_12nheja._.js +3 -0
  155. package/.next/server/chunks/_13510xh._.js +3 -0
  156. package/.next/server/chunks/_15hq89o._.js +1 -1
  157. package/.next/server/chunks/_17l5ygt._.js +49 -0
  158. package/.next/server/chunks/_18-1wcc._.js +5 -5
  159. package/.next/server/chunks/_1_5mnq4._.js +4 -4
  160. package/.next/server/chunks/_1_9mjx-._.js +3 -0
  161. package/.next/server/chunks/_1d0j961._.js +6 -0
  162. package/.next/server/chunks/_1d5zmy8._.js +1 -1
  163. package/.next/server/chunks/_1drgfx4._.js +4 -4
  164. package/.next/server/chunks/_1f46eie._.js +3 -0
  165. package/.next/server/chunks/_1h5_8sk._.js +3 -0
  166. package/.next/server/chunks/_1hdnxb7._.js +3 -0
  167. package/.next/server/chunks/_1j8k_j5._.js +3 -0
  168. package/.next/server/chunks/_1krd9rf._.js +3 -0
  169. package/.next/server/chunks/_1nc0eui._.js +11 -0
  170. package/.next/server/chunks/_1nula3v._.js +3 -0
  171. package/.next/server/chunks/_1pf4qe-._.js +3 -0
  172. package/.next/server/chunks/_1php4eq._.js +1 -1
  173. package/.next/server/chunks/_1qxheoa._.js +3 -0
  174. package/.next/server/chunks/_1x6kd1r._.js +3 -0
  175. package/.next/server/chunks/_1yuv4vp._.js +1 -1
  176. package/.next/server/chunks/_1zjrdag._.js +3 -0
  177. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_files_route_actions_1_xd_8f.js +3 -0
  178. package/.next/server/chunks/_next-internal_server_app_api_bot_memory_route_actions_1a8xfr7.js +3 -0
  179. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +3 -0
  180. package/.next/server/chunks/_next-internal_server_app_api_llm-model_subscription_route_actions_0-udcm5.js +3 -0
  181. package/.next/server/chunks/_next-internal_server_app_api_memory_edit_route_actions_02sfnmr.js +3 -0
  182. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  183. package/.next/server/chunks/features_0rpfxbk._.js +3 -0
  184. package/.next/server/chunks/features_1qf3cei._.js +3 -0
  185. package/.next/server/chunks/features_bot_0zt92oh._.js +3 -0
  186. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +3 -0
  187. package/.next/server/chunks/features_memory_1uqvksn._.js +6 -0
  188. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0a1rd09._.js → node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js} +1 -1
  189. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_06067w6._.js → node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js} +1 -1
  190. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_096ais_._.js → node_modules_consola_dist_chunks_prompt_mjs_0r28-sm._.js} +1 -1
  191. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_02s3hjt._.js → node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js} +1 -1
  192. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xoq2rl._.js +3 -0
  193. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0tvkfgh._.js → node_modules_consola_dist_chunks_prompt_mjs_1y49572._.js} +1 -1
  194. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  195. package/.next/server/chunks/ssr/{[root-of-the-server]__1qfqvmg._.js → [root-of-the-server]__0_69wqr._.js} +2 -2
  196. package/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__0i8ie7f._.js +3 -0
  198. package/.next/server/chunks/ssr/{[root-of-the-server]__0jsmmb-._.js → [root-of-the-server]__0mz33a7._.js} +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0tbkdlx._.js +3 -0
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +3 -0
  201. package/.next/server/chunks/ssr/{[root-of-the-server]__0f6s48x._.js → [root-of-the-server]__0xpcv9w._.js} +3 -3
  202. package/.next/server/chunks/ssr/[root-of-the-server]__0xtssj3._.js +1 -1
  203. package/.next/server/chunks/ssr/[root-of-the-server]__0zkv7z_._.js +3 -0
  204. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +57 -0
  205. package/.next/server/chunks/ssr/[root-of-the-server]__15_uhip._.js +3 -0
  206. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  207. package/.next/server/chunks/ssr/{[root-of-the-server]__0m1b5ky._.js → [root-of-the-server]__1cyjywu._.js} +1 -1
  208. package/.next/server/chunks/ssr/[root-of-the-server]__1eh7hid._.js +3 -0
  209. package/.next/server/chunks/ssr/[root-of-the-server]__1gtlw6v._.js +43 -0
  210. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  211. package/.next/server/chunks/ssr/[root-of-the-server]__1ox7hbk._.js +4 -0
  212. package/.next/server/chunks/ssr/[root-of-the-server]__1pduf5n._.js +3 -0
  213. package/.next/server/chunks/ssr/{_1mznrxk._.js → _001_ms1._.js} +3 -3
  214. package/.next/server/chunks/ssr/_01_6m32._.js +3 -0
  215. package/.next/server/chunks/ssr/_01n3o0m._.js +3 -0
  216. package/.next/server/chunks/ssr/_07uchnc._.js +3 -0
  217. package/.next/server/chunks/ssr/_0ap2fzn._.js +3 -0
  218. package/.next/server/chunks/ssr/_0c-ql2m._.js +3 -0
  219. package/.next/server/chunks/ssr/_0h42fze._.js +3 -0
  220. package/.next/server/chunks/ssr/_0h7zdni._.js +1 -1
  221. package/.next/server/chunks/ssr/_0i_6q1w._.js +41 -0
  222. package/.next/server/chunks/ssr/_0kbkmar._.js +3 -0
  223. package/.next/server/chunks/ssr/{_077-g6s._.js → _0mb8zc8._.js} +3 -3
  224. package/.next/server/chunks/ssr/_0mo2w06._.js +3 -0
  225. package/.next/server/chunks/ssr/{_13punpm._.js → _0q0zan6._.js} +2 -2
  226. package/.next/server/chunks/ssr/{_040sk32._.js → _0u2jv_x._.js} +76 -82
  227. package/.next/server/chunks/ssr/_0y0tiht._.js +4 -0
  228. package/.next/server/chunks/ssr/_0zhoc3r._.js +3 -0
  229. package/.next/server/chunks/ssr/_1-teee5._.js +3 -3
  230. package/.next/server/chunks/ssr/_13fke0x._.js +3 -0
  231. package/.next/server/chunks/ssr/{_1lip4th._.js → _13z3f85._.js} +2 -2
  232. package/.next/server/chunks/ssr/_14_lw10._.js +3 -0
  233. package/.next/server/chunks/ssr/_15j2_8f._.js +3 -0
  234. package/.next/server/chunks/ssr/{_09ja_w1._.js → _1eoqg_g._.js} +2 -2
  235. package/.next/server/chunks/ssr/_1sji22n._.js +3 -0
  236. package/.next/server/chunks/ssr/_1spzm8z._.js +3 -0
  237. package/.next/server/chunks/ssr/{_0x_nu5e._.js → _1vi_uo7._.js} +2 -2
  238. package/.next/server/chunks/ssr/_1vyd1ji._.js +1 -1
  239. package/.next/server/chunks/ssr/{_1m3bsfr._.js → _1xvgn77._.js} +2 -2
  240. package/.next/server/chunks/ssr/_20kd_n0._.js +42 -0
  241. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +3 -0
  242. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  243. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  244. package/.next/server/chunks/ssr/lib_date-like_ts_02is0pw._.js +3 -0
  245. package/.next/server/chunks/ssr/{node_modules_18_dk7_._.js → node_modules_063xwpp._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_01qnv-a._.js → node_modules_0bvraul._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_0n1kj4p._.js → node_modules_0eu1va6._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0kl7-tn._.js → node_modules_0h50b8n._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0_n241r._.js → node_modules_0h5hnr1._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_0lrjk5t._.js → node_modules_0h7u60n._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_0ndvxub._.js → node_modules_0lm7_vm._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_13r44jq._.js → node_modules_0mwym0g._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_17lrt3y._.js → node_modules_0rjg6t1._.js} +1 -1
  254. package/.next/server/chunks/ssr/node_modules_0x3-ply._.js +3 -0
  255. package/.next/server/chunks/ssr/{node_modules_004qlr4._.js → node_modules_0y_cded._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_0kxz4gt._.js → node_modules_0z5tsu8._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_0iz1rzd._.js → node_modules_0zp9r92._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_19dp7ko._.js → node_modules_1-hc6uv._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_1q0p85z._.js → node_modules_113tz0l._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_1toafc-._.js → node_modules_124bue5._.js} +1 -1
  261. package/.next/server/chunks/ssr/node_modules_17bwo43._.js +55 -0
  262. package/.next/server/chunks/ssr/{node_modules_08d8bke._.js → node_modules_1_n3ztw._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1dwguw_._.js → node_modules_1bc7gu8._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_20yebtj._.js → node_modules_1bgb6-f._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1n5ygqe._.js → node_modules_1h4a4pp._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_04n7mjs._.js → node_modules_1i7u1ia._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_1hn8z1f._.js → node_modules_1juq3hs._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_1xyd7ov._.js → node_modules_1l0qtdu._.js} +1 -1
  269. package/.next/server/chunks/ssr/{node_modules_0m93zeg._.js → node_modules_1t9cyee._.js} +1 -1
  270. package/.next/server/chunks/ssr/{node_modules_09xhur7._.js → node_modules_1uuj9x1._.js} +1 -1
  271. package/.next/server/chunks/ssr/{node_modules_1hd-5tv._.js → node_modules_1vqb6po._.js} +1 -1
  272. package/.next/server/chunks/ssr/{node_modules_1zu988w._.js → node_modules_1xx28h1._.js} +1 -1
  273. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0m9a4y0._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0d3skpl._.js} +1 -1
  274. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_13w_wy9._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0i44kk5._.js} +1 -1
  275. package/.next/server/chunks/ssr/node_modules_@vercel_oidc_dist_0qe30a_._.js +3 -0
  276. package/.next/server/chunks/ssr/{node_modules_next_dist_0w6mzq5._.js → node_modules_next_dist_0drixxt._.js} +4 -4
  277. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +2 -2
  278. package/.next/server/instrumentation.js +1 -1
  279. package/.next/server/middleware-build-manifest.js +3 -3
  280. package/.next/server/pages/404.html +1 -1
  281. package/.next/server/pages/500.html +1 -1
  282. package/.next/server/server-reference-manifest.js +1 -1
  283. package/.next/server/server-reference-manifest.json +58 -91
  284. package/.next/static/chunks/{31ttnjt6g35a0.js → 0ev4hyghq0mbb.js} +1 -1
  285. package/.next/static/chunks/0r5qcctujhxli.js +1 -0
  286. package/.next/static/chunks/0tmgrnlje14-s.js +3 -0
  287. package/.next/static/chunks/0x79tx04dxbpp.js +1 -0
  288. package/.next/static/chunks/0xzgvc0fkdb6t.js +1 -0
  289. package/.next/static/chunks/10teww7wt-f6h.js +1 -0
  290. package/.next/static/chunks/14hgtsjg-kael.css +1 -0
  291. package/.next/static/chunks/17donp69y4do7.js +40 -0
  292. package/.next/static/chunks/{3_h9txt3tq8t8.js → 1dkjg87pxk0n9.js} +1 -1
  293. package/.next/static/chunks/1ekc7ul556kbl.js +1 -0
  294. package/.next/static/chunks/{3ard_noqapnw1.js → 1grhjo7a5a0_-.js} +1 -1
  295. package/.next/static/chunks/1kq8h8wi_e0bc.js +53 -0
  296. package/.next/static/chunks/1okqiww3pnwka.js +1 -0
  297. package/.next/static/chunks/26-pr2c9ro222.js +1 -0
  298. package/.next/static/chunks/{18vhba44l1fc9.js → 280t0_e99i276.js} +1 -1
  299. package/.next/static/chunks/28cizcdaabd4h.js +1 -0
  300. package/.next/static/chunks/2a0k6jlq0_v1u.js +2 -0
  301. package/.next/static/chunks/2fzs9fm8yarvq.js +1 -0
  302. package/.next/static/chunks/2h0sd2vumhb15.js +1 -0
  303. package/.next/static/chunks/2hw2f6zmt7fmt.js +1 -0
  304. package/.next/static/chunks/2t4vhi3m8ahya.js +1 -0
  305. package/.next/static/chunks/2tigdtz3dpcy8.js +1 -0
  306. package/.next/static/chunks/3111pj5wnjgos.js +1 -0
  307. package/.next/static/chunks/{07kl352c-lvcz.js → 3agpgkwaa321p.js} +1 -1
  308. package/.next/static/chunks/3cfi_q6d_wtci.js +1 -0
  309. package/.next/static/chunks/3ok9_x74rip3v.js +1 -0
  310. package/.next/static/chunks/3xk7yqgomx7yq.js +1 -0
  311. package/.next/static/chunks/3xpbkl66ssib5.js +38 -0
  312. package/.next/static/media/favicon.37o1pjldwi2uc.ico +0 -0
  313. package/README.md +6 -4
  314. package/app/api/bot/memory/files/route.ts +14 -0
  315. package/app/api/bot/memory/route.ts +5 -0
  316. package/app/api/events/app-event.ts +3 -5
  317. package/app/api/llm-model/credits/route.ts +11 -0
  318. package/app/api/llm-model/route.ts +6 -1
  319. package/app/api/llm-model/subscription/route.ts +11 -0
  320. package/app/api/memory/edit/route.ts +7 -0
  321. package/app/api/memory/route.ts +21 -0
  322. package/app/api/query-key.ts +19 -4
  323. package/bin/thursday.mjs +3 -0
  324. package/components/ui/shiny-text.tsx +48 -134
  325. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/migration.sql +24 -34
  326. package/database/migrations/{20260909060813_optimal_sabretooth → 20260910173049_numerous_spirit}/snapshot.json +71 -145
  327. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +1 -0
  328. package/database/migrations/{20260909063821_bitter_tenebrous → 20260911030320_opposite_jack_power}/snapshot.json +57 -184
  329. package/features/ai/chatgpt.ts +617 -0
  330. package/features/ai/components/chatgpt-sign-in.tsx +66 -0
  331. package/features/ai/components/model-picker.tsx +17 -1
  332. package/features/ai/components/provider-icon.tsx +1 -0
  333. package/features/ai/load-tools.ts +58 -42
  334. package/features/ai/model.schema.ts +232 -34
  335. package/features/ai/model.ts +169 -24
  336. package/features/ai/prompts/bot.prompt.ts +156 -65
  337. package/features/ai/prompts/memory-edit.prompt.ts +33 -0
  338. package/features/ai/prompts/prompt-helper.ts +45 -26
  339. package/features/ai/prompts/thursday.prompt.ts +40 -17
  340. package/features/ai/tools/bot.tool.ts +35 -52
  341. package/features/ai/tools/connected.ts +17 -4
  342. package/features/ai/tools/memory.tool.ts +133 -72
  343. package/features/ai/tools/search.tool.ts +136 -47
  344. package/features/ai/tools/tool-name.ts +2 -5
  345. package/features/ai/tools/workspace.tool.ts +2 -1
  346. package/features/bot/bot.action.ts +8 -18
  347. package/features/bot/bot.memory.ts +89 -0
  348. package/features/bot/bot.query.ts +37 -57
  349. package/features/bot/bot.run.ts +507 -241
  350. package/features/bot/bot.runner.ts +410 -114
  351. package/features/bot/bot.schema.ts +79 -19
  352. package/features/bot/bot.seed.ts +89 -16
  353. package/features/bot/components/bot-mark.tsx +122 -20
  354. package/features/bot/components/bot-room.tsx +159 -130
  355. package/features/bot/components/bot-setting.tsx +790 -402
  356. package/features/bot/components/bot-tool.tsx +2 -6
  357. package/features/bot/components/mark-palette.tsx +54 -0
  358. package/features/bot/components/path-chips.tsx +1 -1
  359. package/features/bot/components/task-badge.tsx +26 -6
  360. package/features/bot/components/task-reply.tsx +22 -33
  361. package/features/bot/components/task-setting.tsx +20 -17
  362. package/features/bot/task.query.ts +215 -28
  363. package/features/bot/task.store.ts +53 -9
  364. package/features/config/components/config-setting.tsx +265 -34
  365. package/features/config/components/models-badge.tsx +42 -0
  366. package/features/config/config.action.ts +12 -0
  367. package/features/config/config.const.ts +38 -2
  368. package/features/connectors/mcp.manager.ts +10 -2
  369. package/features/intro/components/intro.tsx +47 -46
  370. package/features/memory/components/memory-edit.tsx +338 -0
  371. package/features/memory/components/memory-setting.tsx +75 -77
  372. package/features/memory/memory.action.ts +3 -43
  373. package/features/memory/memory.edit.ts +87 -0
  374. package/features/memory/memory.query.ts +24 -42
  375. package/features/memory/memory.schema.ts +29 -106
  376. package/features/settings/components/settings.tsx +2 -0
  377. package/features/settings/settings.alert.ts +3 -1
  378. package/features/thursday/components/ascii-orb.tsx +106 -90
  379. package/features/thursday/components/boot.tsx +7 -0
  380. package/features/thursday/components/call-log.tsx +219 -92
  381. package/features/thursday/components/face.tsx +6 -4
  382. package/features/thursday/components/tab-state.tsx +97 -0
  383. package/features/thursday/components/thursday-mark.tsx +4 -1
  384. package/features/thursday/components/thursday-setting.tsx +17 -47
  385. package/features/thursday/components/thursday.tsx +208 -95
  386. package/features/thursday/thursday.action.ts +12 -17
  387. package/features/thursday/thursday.query.ts +61 -70
  388. package/features/thursday/thursday.schema.ts +20 -7
  389. package/features/thursday/tool-line.ts +85 -11
  390. package/features/thursday/use-thursday.ts +86 -59
  391. package/features/workspace/components/file-view.tsx +4 -2
  392. package/features/workspace/workspace.ts +110 -26
  393. package/lib/limits.ts +1 -1
  394. package/lib/oauth-page.ts +27 -0
  395. package/lib/realtime/openai.ts +2 -2
  396. package/lib/realtime/realtime.protocol.ts +1 -1
  397. package/lib/realtime/realtime.tap.ts +122 -0
  398. package/lib/sandbox.ts +59 -36
  399. package/package.json +1 -1
  400. package/skills/browser/SKILL.md +55 -34
  401. package/.next/server/app/api/bot/notes/route/app-paths-manifest.json +0 -3
  402. package/.next/server/app/api/bot/notes/route.js +0 -14
  403. package/.next/server/app/api/bot/notes/route_client-reference-manifest.js +0 -3
  404. package/.next/server/app/api/memory/tidy/route/app-paths-manifest.json +0 -3
  405. package/.next/server/app/api/memory/tidy/route.js +0 -22
  406. package/.next/server/app/api/memory/tidy/route.js.nft.json +0 -1
  407. package/.next/server/chunks/0d-b_next_dist_server_app-render_after-task-async-storage_external_0-exn7p.js +0 -3
  408. package/.next/server/chunks/[root-of-the-server]__0-npkh_._.js +0 -3
  409. package/.next/server/chunks/[root-of-the-server]__005var5._.js +0 -3
  410. package/.next/server/chunks/[root-of-the-server]__019dx9f._.js +0 -5
  411. package/.next/server/chunks/[root-of-the-server]__02_2sm-._.js +0 -5
  412. package/.next/server/chunks/[root-of-the-server]__04_8spk._.js +0 -3
  413. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +0 -3
  414. package/.next/server/chunks/[root-of-the-server]__06t77t4._.js +0 -11
  415. package/.next/server/chunks/[root-of-the-server]__0bed6hu._.js +0 -8
  416. package/.next/server/chunks/[root-of-the-server]__0cro2dz._.js +0 -5
  417. package/.next/server/chunks/[root-of-the-server]__0dupqt7._.js +0 -5
  418. package/.next/server/chunks/[root-of-the-server]__0emr6go._.js +0 -3
  419. package/.next/server/chunks/[root-of-the-server]__0le4d-p._.js +0 -3
  420. package/.next/server/chunks/[root-of-the-server]__0m8ywyo._.js +0 -10
  421. package/.next/server/chunks/[root-of-the-server]__0nfuugi._.js +0 -5
  422. package/.next/server/chunks/[root-of-the-server]__0p32jfz._.js +0 -12
  423. package/.next/server/chunks/[root-of-the-server]__0phdgco._.js +0 -8
  424. package/.next/server/chunks/[root-of-the-server]__0wvgrsl._.js +0 -3
  425. package/.next/server/chunks/[root-of-the-server]__10qshki._.js +0 -3
  426. package/.next/server/chunks/[root-of-the-server]__11j52t0._.js +0 -5
  427. package/.next/server/chunks/[root-of-the-server]__1692zrv._.js +0 -3
  428. package/.next/server/chunks/[root-of-the-server]__16thabu._.js +0 -3
  429. package/.next/server/chunks/[root-of-the-server]__173nhwf._.js +0 -8
  430. package/.next/server/chunks/[root-of-the-server]__1_aoyr9._.js +0 -3
  431. package/.next/server/chunks/[root-of-the-server]__1bn73ih._.js +0 -10
  432. package/.next/server/chunks/[root-of-the-server]__1bqhuh9._.js +0 -8
  433. package/.next/server/chunks/[root-of-the-server]__1cqizfq._.js +0 -5
  434. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +0 -3
  435. package/.next/server/chunks/[root-of-the-server]__1fboj2j._.js +0 -3
  436. package/.next/server/chunks/[root-of-the-server]__1lr7j9t._.js +0 -5
  437. package/.next/server/chunks/[root-of-the-server]__1oli73c._.js +0 -3
  438. package/.next/server/chunks/[root-of-the-server]__1txedx6._.js +0 -8
  439. package/.next/server/chunks/[root-of-the-server]__1untqv8._.js +0 -5
  440. package/.next/server/chunks/[root-of-the-server]__1zgpz1w._.js +0 -3
  441. package/.next/server/chunks/_00_584r._.js +0 -293
  442. package/.next/server/chunks/_012yhfm._.js +0 -39
  443. package/.next/server/chunks/_06mxlgn._.js +0 -3
  444. package/.next/server/chunks/_07rtlxv._.js +0 -3
  445. package/.next/server/chunks/_0a351g7._.js +0 -6
  446. package/.next/server/chunks/_0kjjmag._.js +0 -3
  447. package/.next/server/chunks/_0nn99o2._.js +0 -3
  448. package/.next/server/chunks/_0zuzmt_._.js +0 -39
  449. package/.next/server/chunks/_106co2o._.js +0 -3
  450. package/.next/server/chunks/_12bbv5i._.js +0 -100
  451. package/.next/server/chunks/_15q1pig._.js +0 -3
  452. package/.next/server/chunks/_19wg5yn._.js +0 -138
  453. package/.next/server/chunks/_1bt95p9._.js +0 -55
  454. package/.next/server/chunks/_1cbk7ms._.js +0 -26
  455. package/.next/server/chunks/_1drv2et._.js +0 -40
  456. package/.next/server/chunks/_1ic3bew._.js +0 -5
  457. package/.next/server/chunks/_1mxn_lb._.js +0 -3
  458. package/.next/server/chunks/_1rysr-r._.js +0 -10
  459. package/.next/server/chunks/_1u3rwbr._.js +0 -3
  460. package/.next/server/chunks/_1x7p319._.js +0 -6
  461. package/.next/server/chunks/_next-internal_server_app_api_bot_notes_route_actions_0qcsyu7.js +0 -3
  462. package/.next/server/chunks/_next-internal_server_app_api_memory_tidy_route_actions_0_cfuom.js +0 -3
  463. package/.next/server/chunks/features_bot_task_query_ts_11xuzl3._.js +0 -3
  464. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js +0 -3
  465. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0vorg6w._.js +0 -3
  466. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1tpvamf._.js +0 -3
  467. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1vmaq9f._.js +0 -3
  468. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1y9-wcr._.js +0 -3
  469. package/.next/server/chunks/ssr/[externals]_node_crypto_1kn79-7._.js +0 -3
  470. package/.next/server/chunks/ssr/[root-of-the-server]__0iuoa-r._.js +0 -3
  471. package/.next/server/chunks/ssr/[root-of-the-server]__0un-erv._.js +0 -4
  472. package/.next/server/chunks/ssr/[root-of-the-server]__1-mnhyd._.js +0 -92
  473. package/.next/server/chunks/ssr/[root-of-the-server]__1bww500._.js +0 -3
  474. package/.next/server/chunks/ssr/[root-of-the-server]__1vcdast._.js +0 -3
  475. package/.next/server/chunks/ssr/[root-of-the-server]__1xwnu-h._.js +0 -3
  476. package/.next/server/chunks/ssr/_0-mc7ro._.js +0 -3
  477. package/.next/server/chunks/ssr/_01p5r6-._.js +0 -3
  478. package/.next/server/chunks/ssr/_03webdr._.js +0 -3
  479. package/.next/server/chunks/ssr/_09-0k3z._.js +0 -3
  480. package/.next/server/chunks/ssr/_0f_b_9s._.js +0 -3
  481. package/.next/server/chunks/ssr/_0fafgvl._.js +0 -3
  482. package/.next/server/chunks/ssr/_0sf1isi._.js +0 -3
  483. package/.next/server/chunks/ssr/_0su6_08._.js +0 -3
  484. package/.next/server/chunks/ssr/_0ti51xc._.js +0 -3
  485. package/.next/server/chunks/ssr/_0w5bgak._.js +0 -3
  486. package/.next/server/chunks/ssr/_0y84qo6._.js +0 -3
  487. package/.next/server/chunks/ssr/_1ciyoo3._.js +0 -3
  488. package/.next/server/chunks/ssr/_1e-dgz0._.js +0 -4
  489. package/.next/server/chunks/ssr/_1fq7zgb._.js +0 -3
  490. package/.next/server/chunks/ssr/_1g6l4uj._.js +0 -3
  491. package/.next/server/chunks/ssr/_1ruzehw._.js +0 -3
  492. package/.next/server/chunks/ssr/features_bot_components_bot-setting_tsx_01ajft6._.js +0 -4
  493. package/.next/server/chunks/ssr/features_config_components_14jqgy4._.js +0 -3
  494. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +0 -4
  495. package/.next/server/chunks/ssr/node_modules_zod_v4_classic_external_15fmmz3.js +0 -55
  496. package/.next/static/chunks/05b6nx_o3_f_n.js +0 -1
  497. package/.next/static/chunks/0dmns-gi0raa4.js +0 -1
  498. package/.next/static/chunks/0f9sq-7q_yxyl.js +0 -1
  499. package/.next/static/chunks/0oc4_xoia77dg.css +0 -1
  500. package/.next/static/chunks/0pheo8m3a-rzi.js +0 -1
  501. package/.next/static/chunks/19i8h2t-5evjx.js +0 -1
  502. package/.next/static/chunks/1c5fcj473025q.js +0 -1
  503. package/.next/static/chunks/1pi_hbmjw-f-z.js +0 -1
  504. package/.next/static/chunks/1twt6k09vg4np.js +0 -1
  505. package/.next/static/chunks/1ytnip8wdng93.js +0 -1
  506. package/.next/static/chunks/28gotuisldmom.js +0 -1
  507. package/.next/static/chunks/2998p0y7k1c8z.js +0 -3
  508. package/.next/static/chunks/29gyb3nubj51j.js +0 -53
  509. package/.next/static/chunks/2l233xfycjpd8.js +0 -1
  510. package/.next/static/chunks/2p5n7pa3c40t-.js +0 -2
  511. package/.next/static/chunks/2ru1q132af7h7.js +0 -1
  512. package/.next/static/chunks/2t8wqycwg3y04.js +0 -2
  513. package/.next/static/chunks/2uxum7qbyeyxd.js +0 -1
  514. package/.next/static/chunks/32z_ypgtchw48.js +0 -1
  515. package/.next/static/chunks/33pyjb3xd1iez.js +0 -1
  516. package/.next/static/chunks/3omud5xunrk1f.js +0 -1
  517. package/.next/static/chunks/42dnrkbph9e-1.js +0 -1
  518. package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
  519. package/database/migrations/20260909063821_bitter_tenebrous/migration.sql +0 -1
  520. package/features/ai/prompts/memory-tidy.prompt.ts +0 -129
  521. package/features/ai/tools/tidy.tool.ts +0 -22
  522. package/features/bot/bot.notes.ts +0 -120
  523. package/features/memory/components/memory-tidy.tsx +0 -395
  524. package/features/memory/memory.tidy.ts +0 -332
  525. package/features/memory/tidy.query.ts +0 -135
  526. package/features/thursday/use-call-title.ts +0 -31
  527. /package/.next/server/app/api/bot/{notes → memory/files}/route/build-manifest.json +0 -0
  528. /package/.next/server/app/api/bot/{notes → memory/files}/route/server-reference-manifest.json +0 -0
  529. /package/.next/server/app/api/bot/{notes → memory/files}/route.js.map +0 -0
  530. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/build-manifest.json +0 -0
  531. /package/.next/server/app/api/{memory/tidy → bot/memory}/route/server-reference-manifest.json +0 -0
  532. /package/.next/server/app/api/{memory/tidy → bot/memory}/route.js.map +0 -0
  533. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_buildManifest.js +0 -0
  534. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_clientMiddlewareManifest.js +0 -0
  535. /package/.next/static/{YR4NWcDDuzwLbTTU7U7Vr → x1cCqY0kWpR_VcYx_lWO5}/_ssgManifest.js +0 -0
@@ -14,9 +14,10 @@ import {
14
14
  DATA_DIR,
15
15
  PATHS,
16
16
  TOOL_OUTPUT,
17
+ WORKSPACE_KEEP,
17
18
  } from "@/config";
18
19
  import { logger } from "@/lib/logger";
19
- import { createSandBox, type Sandbox } from "@/lib/sandbox";
20
+ import { createSandBox, type Sandbox, walkFiles } from "@/lib/sandbox";
20
21
 
21
22
  /**
22
23
  * Where the sandbox is opened. The app's own skills live outside the
@@ -225,6 +226,48 @@ export async function ensureBrowser(): Promise<void> {
225
226
  );
226
227
  }
227
228
 
229
+ /** What a job leaves on disk: stale browser snapshots and spilled tool output. */
230
+ export async function pruneJobFiles(): Promise<void> {
231
+ await pruneBrowserFiles();
232
+ await pruneOutputFiles();
233
+ }
234
+
235
+ type ListedBrowser = { name: string; headed?: boolean; attached?: boolean };
236
+
237
+ /**
238
+ * A job that ended closes the browser nobody can see. Headless is the bot's
239
+ * working copy; `--headed` is the bot putting a window on their screen on
240
+ * purpose — an order at checkout, a map with a pin, a sign-in — and that one is
241
+ * theirs to close (`skills/browser`). A session attached to their own Chrome is
242
+ * never touched. Anything unreadable — no playwright, a failed or folded `list`
243
+ * — leaves the browser as it is.
244
+ */
245
+ export async function closeHiddenBrowser(taskId: string): Promise<void> {
246
+ const sandbox = await openWorkspace();
247
+ const env = jobShellEnv(taskId);
248
+ const listed = await sandbox
249
+ .exec("playwright-cli list --json", { env, timeoutMs: 15_000 })
250
+ .catch(() => null);
251
+ let session: ListedBrowser | undefined;
252
+ try {
253
+ const { browsers } = JSON.parse(listed?.stdout ?? "") as {
254
+ browsers?: ListedBrowser[];
255
+ };
256
+ session = browsers?.find((b) => b.name === env.PLAYWRIGHT_CLI_SESSION);
257
+ } catch {}
258
+ if (session?.headed === false && !session.attached) {
259
+ await sandbox
260
+ .exec("playwright-cli close", { env, timeoutMs: 15_000 })
261
+ .catch(() => {});
262
+ }
263
+ await pruneJobFiles();
264
+ }
265
+
266
+ /**
267
+ * Closes the job's browser whatever it shows. Only for a job the user cancelled
268
+ * or deleted: its row is gone, so a window left open would belong to nothing on
269
+ * the screen.
270
+ */
228
271
  export async function closeJobShell(taskId: string): Promise<void> {
229
272
  const sandbox = await openWorkspace();
230
273
  await sandbox
@@ -233,20 +276,18 @@ export async function closeJobShell(taskId: string): Promise<void> {
233
276
  timeoutMs: 15_000,
234
277
  })
235
278
  .catch(() => {});
236
- await pruneBrowserFiles();
237
- await pruneOutputFiles();
279
+ await pruneJobFiles();
238
280
  }
239
281
 
240
- /**
241
- * playwright-cli never deletes its snapshot files. Refs go stale on the next
242
- * click, so anything older than an hour belongs to no running job.
243
- */
244
- const BROWSER_FILE_TTL_MS = 60 * 60 * 1000;
282
+ const pruneOutputFiles = () => pruneOldFiles(PATHS.output);
283
+
284
+ const pruneBrowserFiles = () => pruneOldFiles(BROWSER_DIR);
245
285
 
246
- async function pruneOutputFiles(): Promise<void> {
247
- const dir = join(WORKSPACE, PATHS.output);
286
+ /** Files directly in a workspace folder that have not changed for WORKSPACE_KEEP.forMs. */
287
+ async function pruneOldFiles(folder: string): Promise<void> {
288
+ const dir = join(WORKSPACE, folder);
248
289
  const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
249
- const cutoff = Date.now() - OUTPUT_FILE_TTL_MS;
290
+ const cutoff = Date.now() - WORKSPACE_KEEP.forMs;
250
291
  for (const entry of entries) {
251
292
  if (!entry.isFile()) continue;
252
293
  const file = join(dir, entry.name);
@@ -255,24 +296,35 @@ async function pruneOutputFiles(): Promise<void> {
255
296
  }
256
297
  }
257
298
 
299
+ /** Every folder under `scratch/`, workspace-relative, as jobScratch names them. */
300
+ export async function listScratchFolders(): Promise<string[]> {
301
+ const entries = await readdir(join(WORKSPACE, PATHS.scratch), {
302
+ withFileTypes: true,
303
+ }).catch(() => []);
304
+ return entries
305
+ .filter((entry) => entry.isDirectory())
306
+ .map((entry) => `${PATHS.scratch}/${entry.name}`);
307
+ }
308
+
258
309
  /**
259
- * Tool output over `TOOL_OUTPUT.max` is written here in full and the model is
260
- * told where. Nothing read it after the run that made it, and nothing deleted
261
- * it either a day is long enough to still be looking, short enough that the
262
- * folder does not become the biggest thing in the workspace.
310
+ * Removes the workspace folders among `folders` that have not changed for
311
+ * WORKSPACE_KEEP.forMs, judged by the folder itself. Only for folders no job owns
312
+ * (bot.runner sweepJobFiles): a job that has just made its folder is never old
313
+ * enough to be caught. Returns what went.
263
314
  */
264
- const OUTPUT_FILE_TTL_MS = 24 * 60 * 60 * 1000;
265
-
266
- async function pruneBrowserFiles(): Promise<void> {
267
- const dir = join(WORKSPACE, BROWSER_DIR);
268
- const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
269
- const cutoff = Date.now() - BROWSER_FILE_TTL_MS;
270
- for (const entry of entries) {
271
- if (!entry.isFile()) continue;
272
- const file = join(dir, entry.name);
273
- const info = await stat(file).catch(() => null);
274
- if (info && info.mtimeMs < cutoff) await unlink(file).catch(() => {});
315
+ export async function removeUnchangedFolders(
316
+ folders: string[],
317
+ ): Promise<string[]> {
318
+ const cutoff = Date.now() - WORKSPACE_KEEP.forMs;
319
+ const removed: string[] = [];
320
+ for (const folder of folders) {
321
+ const full = join(WORKSPACE, folder);
322
+ const info = await stat(full).catch(() => null);
323
+ if (!info?.isDirectory() || info.mtimeMs >= cutoff) continue;
324
+ await rm(full, { recursive: true, force: true }).catch(() => {});
325
+ removed.push(folder);
275
326
  }
327
+ return removed;
276
328
  }
277
329
 
278
330
  /**
@@ -304,6 +356,38 @@ export async function openWorkspace(): Promise<Sandbox> {
304
356
  });
305
357
  }
306
358
 
359
+ /** Files read off one job's folder at most; a folder of generated files is not a list anyone reads. */
360
+ const JOB_FOLDER_WALK = 500;
361
+
362
+ /**
363
+ * What of a job's files is on disk: the paths it gave `write_file` that still exist,
364
+ * and every file under its own folder however it got there — a shell command, a
365
+ * download, a screenshot. Workspace-relative where inside the workspace, each once,
366
+ * the most recently changed last (bot.run filesUnder).
367
+ */
368
+ export async function filesOnDisk(
369
+ written: string[],
370
+ folder: string | null,
371
+ ): Promise<string[]> {
372
+ const candidates = written.map((path) => resolve(WORKSPACE, path));
373
+ if (folder) {
374
+ let walked = 0;
375
+ for await (const full of walkFiles(join(WORKSPACE, folder))) {
376
+ candidates.push(full);
377
+ walked += 1;
378
+ if (walked >= JOB_FOLDER_WALK) break;
379
+ }
380
+ }
381
+ const found = new Map<string, number>();
382
+ for (const full of candidates) {
383
+ const info = await stat(full).catch(() => null);
384
+ if (!info?.isFile()) continue;
385
+ const rel = relative(WORKSPACE, full);
386
+ found.set(rel && !rel.startsWith("..") ? rel : full, info.mtimeMs);
387
+ }
388
+ return [...found].sort((a, b) => a[1] - b[1]).map(([path]) => path);
389
+ }
390
+
307
391
  /**
308
392
  * Removes a job's working folder. Its lifetime is the task's: when the row goes,
309
393
  * so does what it was working with (features/bot/bot.runner). Never touches
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 }) =>
@@ -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;
@@ -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,17 +1,10 @@
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
 
7
- /**
8
- * How long one command may run before its process group is killed. Nobody is
9
- * watching the shell, so a command waiting on a prompt would otherwise hang
10
- * the job; anything that legitimately runs longer belongs in the background.
11
- * Named because the shell guide states it to the model (ai/tools/workspace.tool).
12
- */
13
- export const EXEC_TIMEOUT_MS = 180_000;
14
-
15
8
  export interface Sandbox {
16
9
  /** Absolute. Relative paths resolve from here */
17
10
  readonly cwd: string;
@@ -61,6 +54,25 @@ const IGNORE = new Set([
61
54
  "coverage",
62
55
  ]);
63
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
+
64
76
  /**
65
77
  * Environment for every shell the agent runs: nobody watches it, so no pager
66
78
  * may stall it, and secrets do not travel to children. playwright-cli runs
@@ -108,21 +120,6 @@ export const createSandBox = ({
108
120
  const res = (p: string) =>
109
121
  p.startsWith("/") || /^[A-Za-z]:/.test(p) ? p : pathResolve(cwd, p);
110
122
 
111
- async function* walk(dir: string): AsyncGenerator<string> {
112
- let entries;
113
- try {
114
- entries = await readdir(dir, { withFileTypes: true });
115
- } catch {
116
- return;
117
- }
118
- for (const e of entries) {
119
- if (IGNORE.has(e.name) || e.name.startsWith(".")) continue;
120
- const full = join(dir, e.name);
121
- if (e.isDirectory()) yield* walk(full);
122
- else if (e.isFile()) yield full;
123
- }
124
- }
125
-
126
123
  // A very simple glob → regex. Only **/, * and ? are supported
127
124
  const globToRe = (g: string) =>
128
125
  new RegExp(
@@ -155,7 +152,7 @@ export const createSandBox = ({
155
152
  const root = res(path);
156
153
  const re = globToRe(pattern);
157
154
  const out: string[] = [];
158
- for await (const f of walk(root)) {
155
+ for await (const f of walkFiles(root)) {
159
156
  const rel = relative(root, f).split(sep).join("/");
160
157
  if (re.test(rel) || re.test(f)) out.push(f);
161
158
  if (out.length >= limit) break;
@@ -180,28 +177,26 @@ export const createSandBox = ({
180
177
  child.stdout?.on("data", (d) => (stdout += d));
181
178
  child.stderr?.on("data", (d) => (stderr += d));
182
179
 
183
- const stop = (why: string) => {
184
- stderr += `\n[${why}]`;
180
+ const group = (name: NodeJS.Signals) => {
185
181
  try {
186
182
  // A negative pid means the group: the shell and everything under it
187
- if (child.pid) process.kill(-child.pid, "SIGTERM");
183
+ if (child.pid) process.kill(-child.pid, name);
188
184
  } catch {
189
185
  // Already gone, or no process groups on this platform
190
- child.kill("SIGTERM");
186
+ child.kill(name);
191
187
  }
192
188
  };
193
189
 
194
- const timer = setTimeout(
195
- () => stop(`Timed out after ${timeoutMs}ms`),
196
- timeoutMs,
197
- );
198
-
199
- const onAbort = () => stop("Aborted");
200
- if (signal?.aborted) onAbort();
201
- 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;
202
193
 
203
194
  const done = async (result: ExecResult) => {
195
+ if (settled) return;
196
+ settled = true;
204
197
  clearTimeout(timer);
198
+ clearTimeout(killing);
199
+ clearTimeout(letGo);
205
200
  signal?.removeEventListener("abort", onAbort);
206
201
  resolve({
207
202
  ...result,
@@ -210,6 +205,34 @@ export const createSandBox = ({
210
205
  });
211
206
  };
212
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
+
213
236
  child.on("close", (code) =>
214
237
  done({ stdout, stderr, exitCode: code ?? -1 }),
215
238
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thursday-agent",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "A voice agent that runs on your own machine — talk to her, she hands the slow work to bots with a shell, a browser and skills.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: browser
3
- description: "Any browser and anything on the web — a page, a click, a form, a sign-in, a tab. Open a page and read it, fill a form, sign in, download, screenshot, print a page or an HTML file to PDF. This opens a real window on their screen, and it is how a browser is reached even when one is already running on their Mac (`attach`) — a browser is never driven by clicking it through the machine. A page that wants a sign-in is still this skill's job: the user signs in themselves, in the window this opens."
3
+ description: "Any browser and anything on the web — a page, a click, a form, a sign-in, a tab. Open a page and read it, fill a form, sign in, download, screenshot, print a page or an HTML file to PDF. It can put a real window on their screen to show them the thing itself — an order at checkout, a map, a page — and it is how a browser is reached even when one is already running on their Mac (`attach`) — a browser is never driven by clicking it through the machine. A page that wants a sign-in is still this skill's job: a kept session, the browser they are already in, or the window this opens in front of them."
4
4
  allowed-tools: Bash(playwright-cli:*) Bash(npx:*) Bash(npm:*)
5
5
  ---
6
6
 
@@ -15,8 +15,8 @@ Everything the app has to say about the browser is here; the prompts do not
15
15
  repeat it.
16
16
 
17
17
  **Every browser goes through here.** A job that names a browser, a site, a URL,
18
- a sign-in or a tab is this one's. The window `playwright-cli` opens is a real
19
- one on their screen — they can watch it and type into it. Never drive Chrome by
18
+ a sign-in or a tab is this one's. With `--headed` the window `playwright-cli`
19
+ opens is a real one on their screen — they can watch it and type into it. Never drive Chrome by
20
20
  clicking it through the machine (`osascript`, `peekaboo`, System Events): that
21
21
  window cannot be snapshotted or acted on by ref. For the browser they already
22
22
  have open — a tab they left, a profile they are signed into — attach instead:
@@ -24,13 +24,27 @@ have open — a tab they left, a profile they are signed into — attach instead
24
24
 
25
25
  **Your browser is this job's own.** Its session is already in your shell
26
26
  (`PLAYWRIGHT_CLI_SESSION`): never pass `-s=`, never `close-all` or `kill-all` —
27
- other jobs are running theirs. The server closes yours when the job ends.
28
-
29
- **Headless unless they should see it.** Add `--headed` when the window is the
30
- point a sign-in, something they asked to watch and say so in your
31
- `description`. A site that will want a session before it shows you anything a
32
- shop, a console, a dashboard, an account page starts `--headed --persistent`
33
- rather than finding out headless and starting over.
27
+ other jobs are running theirs.
28
+
29
+ **Headless is yours; headed is theirs.** A browser opens headless: nobody sees
30
+ it, and the app closes it when the job ends. `--headed` puts a real window on
31
+ their screen, and that window outlives the job the app never closes it, they
32
+ do. So you can show them the thing itself instead of describing it: the order
33
+ sitting at checkout for them to confirm, the map with the pin dropped, the page
34
+ they asked to watch, a sign-in for them to finish. Open it `--headed`, leave it
35
+ open, and say in your answer that it is on their screen. A window you opened
36
+ headed only to get past a wall and are done with, `close` yourself. Only a job
37
+ they cancel or delete takes its windows with it.
38
+
39
+ **A payment is theirs to press.** Take a purchase, a top-up or a subscription
40
+ as far as the last screen before money moves, open it `--headed`, and answer
41
+ with what it buys, for how much, and that the pay button is on their screen.
42
+ That is the job done, not stopped — never press it yourself, whatever the
43
+ request said.
44
+
45
+ A site that will want a session before it shows you anything — a shop, a
46
+ console, a dashboard, an account page — starts `--headed --persistent` rather
47
+ than finding out headless and starting over.
34
48
 
35
49
  **Blocked, not broken.** A 403, an "access denied" page, a wall about automated
36
50
  traffic is refusing the headless browser, not the job. `close`, then
@@ -39,29 +53,36 @@ most of it, and is worth trying before you conclude anything about the site.
39
53
  Still refused after that, the wall is real: say so in your report, with the url
40
54
  and whatever you did bring back.
41
55
 
42
- **A sign-in is not a wall.** The user is at this screen and signs in
43
- themselves, in a window you put in front of them. Never type a password, a
44
- one-time code, or answer a passkey prompt — not with `fill`, `type` or `eval`.
45
- An email or username they gave you is not a secret: fill it, press next, stop
46
- at the password. When you do not have it, look before you ask — `memory_recall`
47
- the note for that site or account carries the address they use; only when it is
48
- nowhere does the sign-in go back to them. When a page wants the secret half:
49
-
50
- ```bash
51
- playwright-cli close
52
- playwright-cli open <the login url> --headed --persistent
53
- ```
54
-
55
- Open the login page itself, not the front door. Then `ask_thursday` in one
56
- linewhat to sign into, that the window is open — with options
57
- `Signed in` / `Not now`, and stop. The window stays open while the job waits.
58
- When the answer comes back, continue from a fresh `snapshot`. A captcha is the
59
- same move. Never `show` it blocks waiting for annotations nobody will send.
60
-
61
- **Keep a sign-in for the next job.** After one succeeds:
62
- `state-save .auth/<site>.json`. Before a site that will want one, `ls .auth/`
63
- and `state-load .auth/<site>.json` if its file is there. These files never go
64
- in a report.
56
+ **A sign-in is a fork, not a wall.** Four ways through, and which one fits is
57
+ yours to read off the job:
58
+
59
+ - **A session you already kept.** `ls <your folder>/.auth/`, then `state-load`
60
+ that file and `goto` the site cookies without a reload leave the signed-out
61
+ page that was already drawn, which reads as an expired session when it is not.
62
+ Cheapest when it works, so look before anything else.
63
+ - **The browser they are already in.** `attach --cdp=chrome` carries their own
64
+ profile and whatever it is signed into.
65
+ - **They sign in themselves.** `open <the login url> --headed --persistent` —
66
+ the login page, not the front door then `ask_thursday` in one line saying
67
+ what to sign into and that the window is open, options `Signed in` / `Not
68
+ now`, and stop. The window stays open while the job waits; continue from a
69
+ fresh `snapshot` when the answer comes. A captcha is the same move. Not
70
+ `show`it blocks waiting for annotations nobody will send.
71
+ - **You have the credentials.** Ask before you use them: `ask_thursday` in one
72
+ line naming the account, options `Sign in with it` / `I'll do it`, and on the
73
+ second take the fork above. An answer to your own sign-in question is the
74
+ exception — credentials given there are already the yes, so type them.
75
+
76
+ The line is where the secret comes from, not what kind it is: never guess,
77
+ invent, or go looking for one somewhere they did not point you at. An email or
78
+ username they gave you is not a secret — fill it and press next. `memory_recall`
79
+ the note for that site when you are missing the address they use.
80
+
81
+ **Keep a sign-in for the next job.** `mkdir -p <your folder>/.auth` and
82
+ `state-save` into it after one succeeds — your own folder, the one your
83
+ instructions name, because a session is yours across jobs and the workspace root
84
+ is nobody's. Say that you kept it: it signs every later job in as them, which is
85
+ theirs to want or not. These files never go in a report.
65
86
 
66
87
  **Reading a page.** Every command writes a snapshot file and prints its path.
67
88
  `find "Create Key"` returns only the matching nodes with a few lines around
@@ -87,7 +108,7 @@ A click that seems to do nothing may have opened a tab: `tab-list`,
87
108
  `goto http://127.0.0.1:48800/<file>.html`; `pdf --filename=out.pdf` prints
88
109
  it. Kill the server when done.
89
110
 
90
- Snapshots land in `.playwright-cli/` and are cleared after an hour. A file you
111
+ Snapshots land in `.playwright-cli/` and are cleared after a few days. A file you
91
112
  name — `--filename=`, a `pdf`, a download — goes under `scratch/`, or
92
113
  `artifacts/` when it is the result.
93
114
 
@@ -1,3 +0,0 @@
1
- {
2
- "/api/bot/notes/route": "app/api/bot/notes/route.js"
3
- }