thursday-agent 0.18.0 → 0.19.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 (342) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +3 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/routes-manifest.json +22 -12
  6. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  13. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/server/app/_not-found.html +1 -1
  15. package/.next/server/app/_not-found.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  17. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +11 -11
  18. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/.next/server/app/api/artifact/route.js +6 -6
  20. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  21. package/.next/server/app/api/bot/memory/files/route.js +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  23. package/.next/server/app/api/bot/memory/route.js +3 -3
  24. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  25. package/.next/server/app/api/bot/route.js +3 -3
  26. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  27. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -1
  28. package/.next/server/app/api/bot/thread/file/route.js +17 -17
  29. package/.next/server/app/api/bot/thread/file/route.js.nft.json +1 -1
  30. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -1
  31. package/.next/server/app/api/config/route.js.nft.json +1 -1
  32. package/.next/server/app/api/events/route.js +2 -2
  33. package/.next/server/app/api/events/route.js.nft.json +1 -1
  34. package/.next/server/app/api/favicon/[host]/route.js.nft.json +1 -1
  35. package/.next/server/app/api/file/[...path]/route.js +2 -2
  36. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  37. package/.next/server/app/api/llm-model/automatic/route.js +2 -2
  38. package/.next/server/app/api/llm-model/automatic/route.js.nft.json +1 -1
  39. package/.next/server/app/api/llm-model/catalog/[provider]/route/app-paths-manifest.json +3 -0
  40. package/.next/server/app/api/llm-model/catalog/{route.js → [provider]/route.js} +7 -7
  41. package/.next/server/app/api/llm-model/catalog/[provider]/route.js.nft.json +1 -0
  42. package/.next/server/app/api/llm-model/catalog/[provider]/route_client-reference-manifest.js +3 -0
  43. package/.next/server/app/api/llm-model/credits/[provider]/route/app-paths-manifest.json +3 -0
  44. package/.next/server/app/api/llm-model/credits/{route.js → [provider]/route.js} +7 -7
  45. package/.next/server/app/api/llm-model/credits/[provider]/route.js.nft.json +1 -0
  46. package/.next/server/app/api/llm-model/credits/[provider]/route_client-reference-manifest.js +3 -0
  47. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  49. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  50. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  51. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  52. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  53. package/.next/server/app/api/memory/edit/route.js +12 -12
  54. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  55. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  56. package/.next/server/app/api/reach/route.js +16 -16
  57. package/.next/server/app/api/reach/route.js.nft.json +1 -1
  58. package/.next/server/app/api/routine/route.js +5 -5
  59. package/.next/server/app/api/routine/route.js.nft.json +1 -1
  60. package/.next/server/app/api/running/route/app-paths-manifest.json +3 -0
  61. package/.next/server/app/api/running/route/build-manifest.json +12 -0
  62. package/.next/server/app/api/running/route/server-reference-manifest.json +4 -0
  63. package/.next/server/app/api/running/route.js +10 -0
  64. package/.next/server/app/api/running/route.js.map +5 -0
  65. package/.next/server/app/api/running/route.js.nft.json +1 -0
  66. package/.next/server/app/api/running/route_client-reference-manifest.js +3 -0
  67. package/.next/server/app/api/signins/route.js +4 -4
  68. package/.next/server/app/api/signins/route.js.nft.json +1 -1
  69. package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
  70. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  71. package/.next/server/app/api/skills/route.js +6 -6
  72. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  73. package/.next/server/app/api/thursday/call/end/route.js.nft.json +1 -1
  74. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  75. package/.next/server/app/api/thursday/settings/route.js.nft.json +1 -1
  76. package/.next/server/app/api/thursday/text/route.js +12 -12
  77. package/.next/server/app/api/thursday/text/route.js.nft.json +1 -1
  78. package/.next/server/app/api/thursday/tool-call/route.js +12 -12
  79. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  80. package/.next/server/app/api/workspace/files/route.js +6 -6
  81. package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
  82. package/.next/server/app/api/workspace/route.js +5 -5
  83. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  84. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +11 -11
  85. package/.next/server/app/artifact/[...path]/page.js +7 -6
  86. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  87. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  88. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  89. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  90. package/.next/server/app/page/server-reference-manifest.json +63 -63
  91. package/.next/server/app/page.js +10 -9
  92. package/.next/server/app/page.js.nft.json +1 -1
  93. package/.next/server/app/page_client-reference-manifest.js +1 -1
  94. package/.next/server/app-paths-manifest.json +3 -2
  95. package/.next/server/chunks/{[externals]__178rv3v._.js → [externals]__12stas-._.js} +1 -1
  96. package/.next/server/chunks/[root-of-the-server]__02ra64t._.js +1 -1
  97. package/.next/server/chunks/{[root-of-the-server]__05dp5tr._.js → [root-of-the-server]__06ky9of._.js} +2 -2
  98. package/.next/server/chunks/[root-of-the-server]__0b565-x._.js +7 -0
  99. package/.next/server/chunks/{[root-of-the-server]__1izes4_._.js → [root-of-the-server]__0bmtib_._.js} +2 -2
  100. package/.next/server/chunks/[root-of-the-server]__0bqveex._.js +1 -1
  101. package/.next/server/chunks/[root-of-the-server]__0brmiv2._.js +2 -2
  102. package/.next/server/chunks/[root-of-the-server]__0eivkvk._.js +2 -2
  103. package/.next/server/chunks/[root-of-the-server]__0f7m79q._.js +1 -1
  104. package/.next/server/chunks/[root-of-the-server]__0g38-aj._.js +2 -2
  105. package/.next/server/chunks/[root-of-the-server]__0gvdr2h._.js +1 -1
  106. package/.next/server/chunks/[root-of-the-server]__0h656y-._.js +2 -2
  107. package/.next/server/chunks/[root-of-the-server]__0hm3tiq._.js +2 -2
  108. package/.next/server/chunks/[root-of-the-server]__0hzdqnv._.js +2 -2
  109. package/.next/server/chunks/{[root-of-the-server]__0my9geo._.js → [root-of-the-server]__0kzmxpg._.js} +1 -1
  110. package/.next/server/chunks/[root-of-the-server]__0mgyt8p._.js +2 -2
  111. package/.next/server/chunks/[root-of-the-server]__0mrk2it._.js +1 -1
  112. package/.next/server/chunks/[root-of-the-server]__0o5s5-o._.js +5 -0
  113. package/.next/server/chunks/[root-of-the-server]__0p80i1n._.js +1 -1
  114. package/.next/server/chunks/[root-of-the-server]__0qdoc_9._.js +1 -1
  115. package/.next/server/chunks/[root-of-the-server]__0qzho69._.js +1 -1
  116. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +1 -1
  117. package/.next/server/chunks/[root-of-the-server]__0v_kuor._.js +1 -1
  118. package/.next/server/chunks/{[root-of-the-server]__1k2qs1m._.js → [root-of-the-server]__0ypkfbu._.js} +1 -1
  119. package/.next/server/chunks/[root-of-the-server]__1-18_pz._.js +1 -1
  120. package/.next/server/chunks/[root-of-the-server]__13hng6h._.js +1 -1
  121. package/.next/server/chunks/{[root-of-the-server]__01k3vi3._.js → [root-of-the-server]__14iga7p._.js} +1 -1
  122. package/.next/server/chunks/[root-of-the-server]__16gn7zn._.js +3 -0
  123. package/.next/server/chunks/[root-of-the-server]__18e65_-._.js +3 -0
  124. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +2 -2
  125. package/.next/server/chunks/{[root-of-the-server]__0lvjz0b._.js → [root-of-the-server]__1_cgawk._.js} +2 -2
  126. package/.next/server/chunks/[root-of-the-server]__1ceammd._.js +1 -1
  127. package/.next/server/chunks/[root-of-the-server]__1ckt1yj._.js +1 -1
  128. package/.next/server/chunks/[root-of-the-server]__1cu5f3z._.js +1 -1
  129. package/.next/server/chunks/[root-of-the-server]__1dth047._.js +1 -1
  130. package/.next/server/chunks/{[root-of-the-server]__061o2_x._.js → [root-of-the-server]__1fc6v12._.js} +1 -1
  131. package/.next/server/chunks/[root-of-the-server]__1hviq62._.js +2 -2
  132. package/.next/server/chunks/[root-of-the-server]__1m1q6u5._.js +3 -0
  133. package/.next/server/chunks/[root-of-the-server]__1m_dmf6._.js +1 -1
  134. package/.next/server/chunks/[root-of-the-server]__1mys2c3._.js +1 -1
  135. package/.next/server/chunks/[root-of-the-server]__1ndi14y._.js +1 -1
  136. package/.next/server/chunks/[root-of-the-server]__1p0njle._.js +2 -2
  137. package/.next/server/chunks/[root-of-the-server]__1p47fbb._.js +1 -1
  138. package/.next/server/chunks/[root-of-the-server]__1pugoq0._.js +1 -1
  139. package/.next/server/chunks/{[root-of-the-server]__0ts7ai0._.js → [root-of-the-server]__1trns9g._.js} +1 -1
  140. package/.next/server/chunks/[root-of-the-server]__1ygplx1._.js +1 -1
  141. package/.next/server/chunks/[root-of-the-server]__1zn039k._.js +1 -1
  142. package/.next/server/chunks/[root-of-the-server]__20w_g71._.js +3 -0
  143. package/.next/server/chunks/_06hnfi8._.js +2 -2
  144. package/.next/server/chunks/_06u9yo-._.js +1 -1
  145. package/.next/server/chunks/_08_-9ay._.js +2 -2
  146. package/.next/server/chunks/_0bgjf07._.js +1 -1
  147. package/.next/server/chunks/_0c49lmw._.js +1 -1
  148. package/.next/server/chunks/_0hgvg55._.js +1 -1
  149. package/.next/server/chunks/_0s8ao8z._.js +1 -1
  150. package/.next/server/chunks/_0ucx1jv._.js +1 -1
  151. package/.next/server/chunks/_0uzj57i._.js +1 -1
  152. package/.next/server/chunks/_1-sk_q4._.js +1 -1
  153. package/.next/server/chunks/_1dxq827._.js +2 -2
  154. package/.next/server/chunks/_1e54wxa._.js +1 -1
  155. package/.next/server/chunks/_1frcwj1._.js +1 -1
  156. package/.next/server/chunks/_1gn2r2q._.js +4 -2
  157. package/.next/server/chunks/_1gxankq._.js +2 -2
  158. package/.next/server/chunks/_1i3uucm._.js +1 -1
  159. package/.next/server/chunks/_1jvy78-._.js +1 -1
  160. package/.next/server/chunks/_1lg0lsu._.js +53 -0
  161. package/.next/server/chunks/_1njolhx._.js +294 -0
  162. package/.next/server/chunks/_1q6e56i._.js +4 -2
  163. package/.next/server/chunks/_1wtb-77._.js +294 -0
  164. package/.next/server/chunks/_next-internal_server_app_api_llm-model_catalog_[provider]_route_actions_1i0449q.js +3 -0
  165. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_[provider]_route_actions_0iui9hz.js +3 -0
  166. package/.next/server/chunks/_next-internal_server_app_api_running_route_actions_0o1g-aw.js +3 -0
  167. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  168. package/.next/server/chunks/features_bot_0zy_q8y._.js +7 -7
  169. package/.next/server/chunks/features_bot_1dfrdsb._.js +7 -7
  170. package/.next/server/chunks/{node_modules_1rosz79._.js → node_modules_035o7ku._.js} +1 -1
  171. package/.next/server/chunks/{node_modules_1er1u8w._.js → node_modules_0tn5t13._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_103lpef._.js → node_modules_12oq3hr._.js} +1 -1
  173. package/.next/server/chunks/ssr/[root-of-the-server]__04upd5v._.js +1 -1
  174. package/.next/server/chunks/ssr/[root-of-the-server]__0p0mv2u._.js +3 -0
  175. package/.next/server/chunks/ssr/{[root-of-the-server]__1r7tj27._.js → [root-of-the-server]__0sk5enu._.js} +1 -1
  176. package/.next/server/chunks/ssr/[root-of-the-server]__0xyaud4._.js +3 -0
  177. package/.next/server/chunks/ssr/{[root-of-the-server]__128hnrd._.js → [root-of-the-server]__1-gi9sm._.js} +1 -1
  178. package/.next/server/chunks/ssr/{[root-of-the-server]__0h6jo0s._.js → [root-of-the-server]__16nn3pe._.js} +2 -2
  179. package/.next/server/chunks/ssr/[root-of-the-server]__1867koj._.js +1 -1
  180. package/.next/server/chunks/ssr/[root-of-the-server]__1c8-7cw._.js +3 -0
  181. package/.next/server/chunks/ssr/[root-of-the-server]__1tb5vve._.js +2 -1
  182. package/.next/server/chunks/ssr/_02cm0fr._.js +5 -0
  183. package/.next/server/chunks/ssr/_07nmtxo._.js +1 -1
  184. package/.next/server/chunks/ssr/_088vzgn._.js +1 -1
  185. package/.next/server/chunks/ssr/{_1oafxdu._.js → _0bg1u1j._.js} +2 -2
  186. package/.next/server/chunks/ssr/_0cv9tmv._.js +1 -1
  187. package/.next/server/chunks/ssr/_0f9hx5p._.js +1 -1
  188. package/.next/server/chunks/ssr/_0g9ula_._.js +3 -0
  189. package/.next/server/chunks/ssr/{_0wuvkqk._.js → _0irozu9._.js} +2 -2
  190. package/.next/server/chunks/ssr/_0iwsdp7._.js +3 -0
  191. package/.next/server/chunks/ssr/_0l7rjg5._.js +1 -1
  192. package/.next/server/chunks/ssr/{_0fo4552._.js → _0nk80t6._.js} +44 -5
  193. package/.next/server/chunks/ssr/_0pbav_w._.js +1 -1
  194. package/.next/server/chunks/ssr/{_1r4mc3i._.js → _0q-mdwv._.js} +8 -8
  195. package/.next/server/chunks/ssr/{_1w899wx._.js → _0s5_ahb._.js} +2 -2
  196. package/.next/server/chunks/ssr/{_1omom9y._.js → _0t5f2c3._.js} +2 -2
  197. package/.next/server/chunks/ssr/_0v9r8g2._.js +1 -1
  198. package/.next/server/chunks/ssr/_0x8ophf._.js +1 -1
  199. package/.next/server/chunks/ssr/_0x9f717._.js +1 -1
  200. package/.next/server/chunks/ssr/_107vtdk._.js +162 -0
  201. package/.next/server/chunks/ssr/{_0ixe3g3._.js → _12lql1x._.js} +3 -3
  202. package/.next/server/chunks/ssr/_165wnr4._.js +1 -1
  203. package/.next/server/chunks/ssr/_16_7zeo._.js +1 -1
  204. package/.next/server/chunks/ssr/_17komoi._.js +3 -0
  205. package/.next/server/chunks/ssr/{_0j9vh-8._.js → _190hjys._.js} +2 -2
  206. package/.next/server/chunks/ssr/_1bfrntd._.js +2 -2
  207. package/.next/server/chunks/ssr/{_1tx-2k7._.js → _1booff4._.js} +2 -2
  208. package/.next/server/chunks/ssr/{_12jv_41._.js → _1ew1j7l._.js} +2 -2
  209. package/.next/server/chunks/ssr/_1i2swyr._.js +1 -1
  210. package/.next/server/chunks/ssr/_1neoj22._.js +1 -1
  211. package/.next/server/chunks/ssr/{_0osvxkt._.js → _1qsa25k._.js} +2 -2
  212. package/.next/server/chunks/ssr/_1soynbw._.js +2 -2
  213. package/.next/server/chunks/ssr/_1vc2xmu._.js +3 -0
  214. package/.next/server/chunks/ssr/{_1_ogjze._.js → _1wq90j8._.js} +2 -2
  215. package/.next/server/chunks/ssr/{_1pgxh81._.js → _1zrhkf0._.js} +44 -5
  216. package/.next/server/chunks/ssr/{_0mpn6q0._.js → _21awrs2._.js} +2 -2
  217. package/.next/server/chunks/ssr/features_0796o8r._.js +1 -1
  218. package/.next/server/chunks/ssr/features_bot_1c56lew._.js +37 -0
  219. package/.next/server/chunks/ssr/{features_bot_18gqkr_._.js → features_bot_1fn_grf._.js} +2 -2
  220. package/.next/server/chunks/ssr/{features_config_1ond01n._.js → features_config_05zi68v._.js} +3 -3
  221. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  222. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +1 -1
  223. package/.next/server/chunks/ssr/features_routine_components_routine-setting_tsx_055fknz._.js +1 -1
  224. package/.next/server/chunks/ssr/{node_modules_1-4q6is._.js → node_modules_0-sux1a._.js} +1 -1
  225. package/.next/server/chunks/ssr/{node_modules_17o218r._.js → node_modules_01oezhb._.js} +1 -1
  226. package/.next/server/chunks/ssr/{node_modules_0f485jl._.js → node_modules_04m6ebg._.js} +1 -1
  227. package/.next/server/chunks/ssr/{node_modules_0upwx50._.js → node_modules_067jfov._.js} +1 -1
  228. package/.next/server/chunks/ssr/{node_modules_0i_v0-m._.js → node_modules_06ugby3._.js} +1 -1
  229. package/.next/server/chunks/ssr/{node_modules_0lxwg2v._.js → node_modules_07p51j3._.js} +1 -1
  230. package/.next/server/chunks/ssr/{node_modules_16z7p8b._.js → node_modules_0995xyq._.js} +1 -1
  231. package/.next/server/chunks/ssr/{node_modules_004qt-z._.js → node_modules_0_uecwx._.js} +1 -1
  232. package/.next/server/chunks/ssr/{node_modules_0lrn9ci._.js → node_modules_0dsyc90._.js} +1 -1
  233. package/.next/server/chunks/ssr/{node_modules_0v__o4h._.js → node_modules_0hli6s2._.js} +1 -1
  234. package/.next/server/chunks/ssr/{node_modules_1gpapfv._.js → node_modules_0m-bde_._.js} +1 -1
  235. package/.next/server/chunks/ssr/{node_modules_1tus4vi._.js → node_modules_0oqfdbr._.js} +1 -1
  236. package/.next/server/chunks/ssr/{node_modules_09dy7tk._.js → node_modules_0tgy5s5._.js} +1 -1
  237. package/.next/server/chunks/ssr/{node_modules_1hdaxu9._.js → node_modules_1-kjmls._.js} +1 -1
  238. package/.next/server/chunks/ssr/{node_modules_0gbx70b._.js → node_modules_1-l3ka5._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_20448xv._.js → node_modules_1-w3ayh._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_06m6e97._.js → node_modules_133exgm._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_1srjf5c._.js → node_modules_17xc5_k._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_1tv_7lk._.js → node_modules_1_i_w30._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_1hjvwkh._.js → node_modules_1a2cjfk._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_0_hy3i2._.js → node_modules_1k752fe._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_0n2-p5q._.js → node_modules_1lie7z8._.js} +1 -1
  246. package/.next/server/chunks/ssr/{node_modules_0pw13ww._.js → node_modules_1mv70-y._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_10mb0cv._.js → node_modules_1r611t2._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0nj36zf._.js → node_modules_1vfd8dz._.js} +2 -2
  249. package/.next/server/chunks/ssr/{node_modules_0ppirau._.js → node_modules_1yaowd7._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_1j886a5._.js → node_modules_20a1wpo._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0lg9pkl._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1r8pxbe._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1xgbf5j._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1siiu4h._.js} +1 -1
  253. package/.next/server/middleware-build-manifest.js +3 -3
  254. package/.next/server/middleware.js +1 -1
  255. package/.next/server/pages/404.html +1 -1
  256. package/.next/server/pages/500.html +1 -1
  257. package/.next/server/server-reference-manifest.js +1 -1
  258. package/.next/server/server-reference-manifest.json +64 -64
  259. package/.next/static/chunks/{1dpg1u4a16ujt.js → 088d3w5qxu19g.js} +2 -2
  260. package/.next/static/chunks/0bxekp4hnuk1g.js +1 -0
  261. package/.next/static/chunks/{17dx6w478vnb0.js → 0fw4u_s974j24.js} +1 -1
  262. package/.next/static/chunks/0hy2x7qhk8wgx.css +1 -0
  263. package/.next/static/chunks/{240nfv2dtidhc.js → 0n_eshmn_7wfn.js} +2 -2
  264. package/.next/static/chunks/0ulcp_u_y1u0b.js +15 -0
  265. package/.next/static/chunks/0vj93zo0yvix9.js +35 -0
  266. package/.next/static/chunks/{05uvci-bk-vgp.js → 10f98bh4hdmhe.js} +1 -1
  267. package/.next/static/chunks/{0ruf3dqs--3ve.js → 1b8bce_z_act0.js} +1 -1
  268. package/.next/static/chunks/1c32d2azsjaj_.js +1 -0
  269. package/.next/static/chunks/1fs829mz69pxz.js +1 -0
  270. package/.next/static/chunks/{2ug8q1x9e-_j6.js → 1lwlh4mo_vv8d.js} +1 -1
  271. package/.next/static/chunks/{3r7u1y9xjoh-v.js → 1po8fkg40peu-.js} +1 -1
  272. package/.next/static/chunks/{27l8qwnk1j66z.js → 1rg6b9l5fm1hj.js} +1 -1
  273. package/.next/static/chunks/{1pe7i5yu779ta.js → 26g3iwfuad-7p.js} +1 -1
  274. package/.next/static/chunks/2bjnmtke_q43c.js +1 -0
  275. package/.next/static/chunks/2c86k0o-1p9_w.js +1 -0
  276. package/.next/static/chunks/2gf4t0d76bvyv.js +1 -0
  277. package/.next/static/chunks/2rj3q_ahctv19.js +1 -0
  278. package/.next/static/chunks/{2lhc74urf3acr.js → 2x6-fpctvucte.js} +1 -1
  279. package/.next/static/chunks/{2gxfy__ef51n9.js → 2yicf7bky866n.js} +1 -1
  280. package/.next/static/chunks/{0oqviw3f55nfp.js → 350ws7svim7ij.js} +1 -1
  281. package/.next/static/chunks/3e1w_nwfb39j-.js +1 -0
  282. package/.next/static/chunks/3v3ooretb54ag.js +1 -0
  283. package/.next/static/chunks/{2lzg4zedtmyic.js → 44bcbnmup71so.js} +1 -1
  284. package/.next/static/chunks/{1h_6rh86q3i4p.js → 458dtbsemx996.js} +1 -1
  285. package/bin/background.mjs +995 -0
  286. package/bin/lock.mjs +64 -29
  287. package/bin/thursday.mjs +111 -42
  288. package/bin/tools.mjs +58 -4
  289. package/guide/calls.md +8 -0
  290. package/guide/setup.md +27 -13
  291. package/package.json +1 -1
  292. package/seed-skills/concierge/travel/references/itinerary.md +1 -1
  293. package/seed-skills/concierge/travel/scripts/itinerary.mjs +7 -2
  294. package/skills/artifact/references/book.md +3 -3
  295. package/.next/server/app/api/llm-model/catalog/route/app-paths-manifest.json +0 -3
  296. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +0 -1
  297. package/.next/server/app/api/llm-model/catalog/route_client-reference-manifest.js +0 -3
  298. package/.next/server/app/api/llm-model/credits/route/app-paths-manifest.json +0 -3
  299. package/.next/server/app/api/llm-model/credits/route.js.nft.json +0 -1
  300. package/.next/server/app/api/llm-model/credits/route_client-reference-manifest.js +0 -3
  301. package/.next/server/chunks/[root-of-the-server]__03xamry._.js +0 -3
  302. package/.next/server/chunks/[root-of-the-server]__04hhvpu._.js +0 -7
  303. package/.next/server/chunks/[root-of-the-server]__1-rmal0._.js +0 -5
  304. package/.next/server/chunks/[root-of-the-server]__10xnb7e._.js +0 -3
  305. package/.next/server/chunks/[root-of-the-server]__1etbk64._.js +0 -3
  306. package/.next/server/chunks/[root-of-the-server]__1v7x5ym._.js +0 -3
  307. package/.next/server/chunks/_07nxi75._.js +0 -255
  308. package/.next/server/chunks/_0srlnvd._.js +0 -16
  309. package/.next/server/chunks/_0xygcxs._.js +0 -255
  310. package/.next/server/chunks/_next-internal_server_app_api_llm-model_catalog_route_actions_1eu2y41.js +0 -3
  311. package/.next/server/chunks/_next-internal_server_app_api_llm-model_credits_route_actions_0v424pb.js +0 -3
  312. package/.next/server/chunks/ssr/[root-of-the-server]__06knwl5._.js +0 -3
  313. package/.next/server/chunks/ssr/[root-of-the-server]__07ehpky._.js +0 -3
  314. package/.next/server/chunks/ssr/[root-of-the-server]__1gzje-h._.js +0 -3
  315. package/.next/server/chunks/ssr/_0jstvlg._.js +0 -39
  316. package/.next/server/chunks/ssr/_1-41lck._.js +0 -3
  317. package/.next/server/chunks/ssr/_10jtmhl._.js +0 -3
  318. package/.next/server/chunks/ssr/_19jez1a._.js +0 -3
  319. package/.next/server/chunks/ssr/_1jd8rjm._.js +0 -3
  320. package/.next/server/chunks/ssr/_1mdjoak._.js +0 -162
  321. package/.next/static/chunks/09y_43y1cy5jw.js +0 -1
  322. package/.next/static/chunks/0vggwjufw2-6r.js +0 -1
  323. package/.next/static/chunks/0x4m9nj2fazl2.js +0 -35
  324. package/.next/static/chunks/1-1yfu34-3p2p.js +0 -1
  325. package/.next/static/chunks/10oyyypxn_cpx.js +0 -1
  326. package/.next/static/chunks/184-r80rv0xay.css +0 -1
  327. package/.next/static/chunks/1_hgdoungpm0o.js +0 -1
  328. package/.next/static/chunks/2kjwmo70judc2.js +0 -15
  329. package/.next/static/chunks/2uk8rdtr-pk58.js +0 -1
  330. package/.next/static/chunks/3vg1-oc-zgw_7.js +0 -1
  331. package/.next/static/chunks/3vrmcm31ih7gb.js +0 -1
  332. package/.next/static/chunks/41ztsnjn4qrn-.js +0 -1
  333. package/bin/autostart.mjs +0 -192
  334. /package/.next/server/app/api/llm-model/catalog/{route → [provider]/route}/build-manifest.json +0 -0
  335. /package/.next/server/app/api/llm-model/catalog/{route → [provider]/route}/server-reference-manifest.json +0 -0
  336. /package/.next/server/app/api/llm-model/catalog/{route.js.map → [provider]/route.js.map} +0 -0
  337. /package/.next/server/app/api/llm-model/credits/{route → [provider]/route}/build-manifest.json +0 -0
  338. /package/.next/server/app/api/llm-model/credits/{route → [provider]/route}/server-reference-manifest.json +0 -0
  339. /package/.next/server/app/api/llm-model/credits/{route.js.map → [provider]/route.js.map} +0 -0
  340. /package/.next/static/{-IBxB5oqr6e3RuOCCmYtL → YhaRHJqObuAcXZe5VLFs0}/_buildManifest.js +0 -0
  341. /package/.next/static/{-IBxB5oqr6e3RuOCCmYtL → YhaRHJqObuAcXZe5VLFs0}/_clientMiddlewareManifest.js +0 -0
  342. /package/.next/static/{-IBxB5oqr6e3RuOCCmYtL → YhaRHJqObuAcXZe5VLFs0}/_ssgManifest.js +0 -0
package/bin/lock.mjs CHANGED
@@ -6,7 +6,7 @@
6
6
  import { spawnSync } from "node:child_process";
7
7
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
8
  import { join } from "node:path";
9
- import { startsWithMac } from "./autostart.mjs";
9
+ import { backgroundJob } from "./background.mjs";
10
10
  import { thursdayCommand } from "./tools.mjs";
11
11
 
12
12
  /** Beside the database, and named so a checkout never commits it (`*.local.*`). */
@@ -21,37 +21,70 @@ export function runningOn(home) {
21
21
  return null;
22
22
  }
23
23
  if (!Number.isInteger(held?.pid) || held.pid === process.pid) return null;
24
- try {
25
- // Signal 0 asks whether the process exists and sends nothing
26
- process.kill(held.pid, 0);
27
- } catch (error) {
28
- // Someone else's process by that id is still a live one
29
- if (error?.code !== "EPERM") return null;
30
- }
31
- // A lock left by a server that died without its exit (a kill -9, a power cut) names a pid
32
- // another process may hold after a restart, which would refuse every start until the file
33
- // was deleted by hand: the pid is this server only if it started when the lock says. Where
34
- // `ps` cannot say (Windows), or the lock predates `started`, the live pid is all there is.
35
- const started = startedAt(held.pid);
36
- if (typeof held.started === "string" && started && started !== held.started)
37
- return null;
24
+ if (!stillRuns(held)) return null;
38
25
  return {
39
26
  pid: held.pid,
40
27
  url: String(held.url ?? ""),
41
28
  // Null from `pnpm dev`, and from a server started before the lock said
42
29
  version: typeof held.version === "string" ? held.version : null,
30
+ background: held.background === true,
43
31
  };
44
32
  }
45
33
 
34
+ /**
35
+ * Whether the process a lock names is still the one that wrote it. A lock left by a process
36
+ * that died without its exit (a kill -9, a power cut) names a pid another process may hold
37
+ * after a restart, which would refuse every start until the file was deleted by hand: the pid
38
+ * is the writer only if it started when the lock says. Where `ps` cannot say (Windows), or the
39
+ * lock predates its start time, the live pid is all there is.
40
+ */
41
+ export function stillRuns(held) {
42
+ try {
43
+ // Signal 0 asks whether the process exists and sends nothing
44
+ process.kill(held.pid, 0);
45
+ } catch (error) {
46
+ // Someone else's process by that id is still a live one
47
+ if (error?.code !== "EPERM") return false;
48
+ }
49
+ // Compared in UTC: `ps` writes the reader's zone, and a server under launchd (no TZ), a
50
+ // terminal that exports one, or a Mac that moved zones since it started spelled one start
51
+ // two ways — the server read as gone, and a second one opened the same database. A lock
52
+ // written before `startedUtc` has `started` alone, in its writer's zone.
53
+ const [said, zone] =
54
+ typeof held.startedUtc === "string"
55
+ ? [held.startedUtc, "UTC"]
56
+ : [held.started, undefined];
57
+ if (typeof said !== "string") return true;
58
+ const started = startedAt(held.pid, zone);
59
+ return !started || started === said;
60
+ }
61
+
62
+ /**
63
+ * Whether the server holding this folder is `pid`, or runs under it: launchd knows a job by the
64
+ * process it started, and a version manager's shim (Volta's) starts node as its child rather
65
+ * than becoming it.
66
+ */
67
+ export function heldBy(running, pid) {
68
+ if (!running || !pid) return false;
69
+ return (
70
+ running.pid === pid ||
71
+ Number(ps(["-o", "ppid=", "-p", String(running.pid)])) === pid
72
+ );
73
+ }
74
+
46
75
  // LC_ALL=C: a start time is compared as `ps` wrote it, so both reads spell it alike
47
- const ps = (...args) =>
76
+ const ps = (args, zone) =>
48
77
  spawnSync("ps", args, {
49
78
  encoding: "utf8",
50
- env: { ...process.env, LC_ALL: "C" },
79
+ env: { ...process.env, LC_ALL: "C", ...(zone ? { TZ: zone } : {}) },
51
80
  }).stdout?.trim() ?? "";
52
81
 
53
- /** When a process started, to the second, as `ps` has it. Empty where it cannot say. */
54
- const startedAt = (pid) => ps("-o", "lstart=", "-p", String(pid));
82
+ /**
83
+ * When a process started, to the second, as `ps` has it in `zone` (the reader's own when none).
84
+ * Empty where it cannot say.
85
+ */
86
+ export const startedAt = (pid, zone) =>
87
+ ps(["-o", "lstart=", "-p", String(pid)], zone);
55
88
 
56
89
  /**
57
90
  * Where a process runs, as `ps` has it: the terminal it is attached to (null when none), when
@@ -59,27 +92,27 @@ const startedAt = (pid) => ps("-o", "lstart=", "-p", String(pid));
59
92
  * `npx thursday-agent`, not the Node process under it. Null where `ps` cannot say (Windows).
60
93
  */
61
94
  function whereRuns(pid) {
62
- const [tty, group, ...started] = ps(
95
+ const [tty, group, ...started] = ps([
63
96
  "-o",
64
97
  "tty=,pgid=,lstart=",
65
98
  "-p",
66
99
  String(pid),
67
- ).split(/\s+/);
100
+ ]).split(/\s+/);
68
101
  if (!tty || !group) return null;
69
102
  return {
70
103
  terminal: tty === "??" || tty === "?" ? null : tty,
71
104
  group,
72
- // "Fri Sep 25 20:55:51 2026" to the minute
105
+ // "Fri Sep 25 20:55:51 2026" to the minute, in the reader's zone: it is read, not compared
73
106
  since: started.join(" ").replace(/:\d\d \d{4}$/, ""),
74
- typed: ps("-o", "command=", "-p", group),
107
+ typed: ps(["-o", "command=", "-p", group]),
75
108
  };
76
109
  }
77
110
 
78
111
  /**
79
112
  * How to stop the server with this pid, said where it can be done. A person told only "stop
80
113
  * it" looked for a terminal they could not find: the one it runs in is named, with a command
81
- * that does the same from any terminal. One that starts with the Mac is started again by
82
- * launchd, so it is stopped by turning that off. Lines to print, without indent.
114
+ * that does the same from any terminal. One that runs in the background is started again by
115
+ * launchd, so it is stopped by stopping that. Lines to print, without indent.
83
116
  */
84
117
  export function stopLines(pid, home) {
85
118
  const where = whereRuns(pid);
@@ -88,10 +121,8 @@ export function stopLines(pid, home) {
88
121
  `It runs in a terminal (${where.terminal}${where.typed ? `, ${where.typed}` : ""}, since ${where.since}).`,
89
122
  `Ctrl+C there, or from any terminal: kill -INT -${where.group}`,
90
123
  ];
91
- if (startsWithMac(home))
92
- return [
93
- `It starts with your Mac. To stop it: ${thursdayCommand()} autostart --off`,
94
- ];
124
+ if (backgroundJob()?.home === home)
125
+ return [`It runs in the background. To stop it: ${thursdayCommand()} stop`];
95
126
  if (where) return [`It runs in the background. To stop it: kill ${pid}`];
96
127
  return ["Ctrl+C where it runs."];
97
128
  }
@@ -120,9 +151,13 @@ export function holdFolder(home, url, version) {
120
151
  file,
121
152
  `${JSON.stringify({
122
153
  pid: process.pid,
154
+ startedUtc: startedAt(process.pid, "UTC") || undefined,
155
+ // What a starter from before `startedUtc` reads, in this process's zone
123
156
  started: startedAt(process.pid) || undefined,
124
157
  url,
125
158
  version,
159
+ // Which one launchd started, so a stop can end it when launchd did not (background.mjs)
160
+ background: process.env.THURSDAY_BACKGROUND ? true : undefined,
126
161
  })}\n`,
127
162
  );
128
163
  } catch {
package/bin/thursday.mjs CHANGED
@@ -14,12 +14,19 @@ import {
14
14
  symlinkSync,
15
15
  } from "node:fs";
16
16
  import { readFile } from "node:fs/promises";
17
- import { homedir } from "node:os";
18
17
  import { join, resolve } from "node:path";
18
+ import { backgroundJob, keepLogShort, offerBackground } from "./background.mjs";
19
19
  import { askToSetDatabaseAside, MIGRATION_FAILED_EXIT } from "./database.mjs";
20
20
  import { holdFolder, runningOn, stopLines } from "./lock.mjs";
21
21
  import { freePort } from "./port.mjs";
22
- import { ROOT, thursdayCommand, toolPath } from "./tools.mjs";
22
+ import {
23
+ commandFor,
24
+ DEFAULT_HOME,
25
+ openBrowser,
26
+ ROOT,
27
+ thursdayCommand,
28
+ toolPath,
29
+ } from "./tools.mjs";
23
30
 
24
31
  const { version, name } = JSON.parse(
25
32
  await readFile(join(ROOT, "package.json"), "utf8"),
@@ -39,8 +46,11 @@ if (has("-h", "--help")) {
39
46
  ${name} ${version}
40
47
 
41
48
  Usage
42
- $ ${command} [options]
43
- $ ${command} autostart [--off] Start with the computer, macOS only
49
+ $ ${command} [options] Start it here, in this terminal
50
+ $ ${command} start [options] Keep it running in the background, and start it
51
+ when you log in (macOS)
52
+ $ ${command} stop Stop it in the background
53
+ $ ${command} status Whether it runs, where, and how to reach it
44
54
 
45
55
  Options
46
56
  --port <n> Port to serve on (default 4747, or the next free one)
@@ -72,62 +82,112 @@ if (!APP) {
72
82
  process.exit(1);
73
83
  }
74
84
 
75
- /**
76
- * The user's files: database, workspace, installed skills. An installed package
77
- * keeps them in the home folder, never inside the package — an upgrade replaces
78
- * that. A checkout keeps them in the checkout, which is where `pnpm dev` already
79
- * writes them (config.ts DATA_DIR): a build started here opens the data it was
80
- * developed against, not a second, empty one beside it.
81
- */
82
- const DEFAULT_HOME = APP === ROOT ? join(homedir(), ".thursday") : ROOT;
83
-
84
- const asked = flag("port") ?? process.env.PORT;
85
+ // An exported `PORT=` with nothing in it asks for no port
86
+ const asked = flag("port") ?? (process.env.PORT?.trim() || undefined);
85
87
  const home = resolve(flag("home") || process.env.THURSDAY_HOME || DEFAULT_HOME);
86
88
 
87
- // Turning it on or off is the whole command; it never goes on to serve.
88
- if (argv[0] === "autostart") {
89
- const { autostart } = await import("./autostart.mjs");
90
- await autostart({ root: ROOT, home, off: has("--off") });
91
- process.exit(0);
92
- }
93
-
94
- /** A browser that will not open is not a failure. */
95
- function openBrowser(url) {
96
- const [command, args] =
97
- process.platform === "darwin"
98
- ? ["open", [url]]
99
- : process.platform === "win32"
100
- ? ["cmd", ["/c", "start", "", url]]
101
- : ["xdg-open", [url]];
102
- spawn(command, args, { stdio: "ignore" }).on("error", () => {});
89
+ // The background (background.mjs): each is the whole command, and never goes on to serve.
90
+ // `autostart` and `autostart --off` are what earlier versions called start and stop.
91
+ const said =
92
+ argv[0] === "autostart" ? (has("--off") ? "stop" : "start") : argv[0];
93
+ const background = ["start", "stop", "status"].includes(said) ? said : null;
94
+ /** A start that could not run it in the background, and serves in this terminal instead. */
95
+ let fellBack = false;
96
+ if (background) {
97
+ const { printStatus, startInBackground, stopBackground } = await import(
98
+ "./background.mjs"
99
+ );
100
+ if (background === "status") {
101
+ printStatus({ home });
102
+ process.exit(0);
103
+ }
104
+ if (background === "stop")
105
+ process.exit((await stopBackground({ home })) ? 0 : 1);
106
+ const started = await startInBackground({
107
+ root: ROOT,
108
+ home,
109
+ port: asked,
110
+ open: !has("--no-open"),
111
+ version,
112
+ });
113
+ if (started === true) process.exit(0);
114
+ // A person at a terminal still gets it running, there, for as long as it stays open, as the
115
+ // first run's question does. "held" is a folder something else serves already; a script
116
+ // gets the failure
117
+ if (started === "held" || !process.stdin.isTTY || !process.stdout.isTTY)
118
+ process.exit(1);
119
+ fellBack = true;
103
120
  }
104
121
 
105
- // Before a port is picked: a second server on this folder would take the next one, and
106
- // serve the same calls, jobs and phone twice (lock.mjs). Run again, it is usually the app
107
- // they came for — a second `npx` once its tab is closed — so that one opens instead. One of
108
- // another version does not: they ran this one to have this one.
109
- const running = runningOn(home);
110
- if (running) {
122
+ /**
123
+ * Leaves when this folder already has a server: a second one would take the next port, and
124
+ * serve the same calls, jobs and phone twice (lock.mjs). Run again, it is usually the app they
125
+ * came for — a second `npx` once its tab is closed — so that one opens instead. One of another
126
+ * version does not: they ran this one to have this one.
127
+ */
128
+ function leaveToRunning() {
129
+ const running = runningOn(home);
130
+ if (!running) return;
111
131
  const other =
112
132
  running.version && running.version !== version ? running.version : null;
113
133
  const opens = Boolean(running.url) && !other && !has("--no-open");
134
+ // The copy in the background moves to this version by starting it from this one: through
135
+ // npx pinned, since a bare `npx thursday-agent` is whichever version npm resolves that day
136
+ const command = thursdayCommand();
137
+ const moves =
138
+ other && backgroundJob()?.home === home
139
+ ? ` To move it to ${version}: ${commandFor(
140
+ "start",
141
+ home,
142
+ command === "npx thursday-agent"
143
+ ? `npx thursday-agent@${version}`
144
+ : command,
145
+ )}\n`
146
+ : null;
114
147
  console.log(
115
148
  `\n Thursday${other ? ` ${other}` : ""} is already running on this data folder${running.url ? `: ${running.url}` : ""}\n${
116
149
  opens
117
150
  ? " Opened it in your browser.\n"
118
- : other
119
- ? ` To run ${version} instead, stop that one and run this again.\n`
120
- : ""
121
- }${stopLines(running.pid, home)
122
- .map((line) => ` ${line}\n`)
123
- .join("")}`,
151
+ : (moves ??
152
+ (other
153
+ ? ` To run ${version} instead, stop that one and run this again.\n`
154
+ : ""))
155
+ }${
156
+ moves
157
+ ? ""
158
+ : stopLines(running.pid, home)
159
+ .map((line) => ` ${line}\n`)
160
+ .join("")
161
+ }`,
124
162
  );
125
163
  if (opens) openBrowser(running.url);
126
164
  process.exit(other ? 1 : 0);
127
165
  }
166
+
167
+ // Before a port is picked
168
+ leaveToRunning();
169
+
170
+ if (fellBack) console.log(" Running it in this terminal instead.");
171
+ else {
172
+ // A first run in a terminal asks once whether to keep it running in the background; said
173
+ // yes, the background serves and this run is done
174
+ const chose = await offerBackground({
175
+ root: ROOT,
176
+ home,
177
+ port: asked,
178
+ open: !has("--no-open"),
179
+ version,
180
+ });
181
+ if (chose !== "terminal") process.exit(chose === "background" ? 0 : 1);
182
+ }
183
+ // The question waits as long as the person does, and a start takes a minute: a server another
184
+ // terminal started on this folder meanwhile is the one to use, not a second beside it
185
+ leaveToRunning();
128
186
  const port = String(await freePort(asked, home));
129
187
  const url = `http://localhost:${port}`;
130
188
  holdFolder(home, url, version);
189
+ // launchd writes the background's output to a log that nothing else trims
190
+ if (process.env.THURSDAY_BACKGROUND) keepLogShort(home);
131
191
  /** Where config.ts DB_PATH puts the database under the home. */
132
192
  const database = join(home, "local.db");
133
193
 
@@ -173,6 +233,15 @@ function start() {
173
233
  THURSDAY_URL: url,
174
234
  // Where a bot's shell finds playwright-cli (workspace.ts TOOL_PATH)
175
235
  THURSDAY_TOOL_PATH: toolPath().join(":"),
236
+ // How it was started and what the person types to run it, for Settings to say where it
237
+ // runs and how to stop or keep it (features/settings/running.ts)
238
+ THURSDAY_RUNS: process.env.THURSDAY_BACKGROUND
239
+ ? "background"
240
+ : process.stdin.isTTY
241
+ ? "terminal"
242
+ : "elsewhere",
243
+ THURSDAY_COMMAND: thursdayCommand(),
244
+ THURSDAY_START: commandFor("start", home),
176
245
  PORT: port,
177
246
  // This machine only. A voice agent with a shell is not a thing to expose.
178
247
  // Never inherited: Docker exports HOSTNAME as the container and some
package/bin/tools.mjs CHANGED
@@ -2,8 +2,10 @@
2
2
  // imports: this runs from the published `bin`, on a machine that has neither a
3
3
  // build nor a TypeScript loader.
4
4
 
5
+ import { spawn } from "node:child_process";
5
6
  import { existsSync } from "node:fs";
6
7
  import { createRequire } from "node:module";
8
+ import { homedir } from "node:os";
7
9
  import { dirname, join, resolve, sep } from "node:path";
8
10
 
9
11
  const require = createRequire(import.meta.url);
@@ -11,22 +13,74 @@ const require = createRequire(import.meta.url);
11
13
  /** The checkout, or the installed package. */
12
14
  export const ROOT = resolve(import.meta.dirname, "..");
13
15
 
16
+ /**
17
+ * Where the copy that runs in the background is installed (background.mjs). Beside the
18
+ * default data folder, so everything the app keeps on the computer is under one folder.
19
+ */
20
+ export const PROGRAM = join(homedir(), ".thursday", "app");
21
+
22
+ /** The one copy with the dev script beside it; the package ships no `scripts`. */
23
+ export const isCheckout = (root) =>
24
+ existsSync(join(root, "scripts", "dev.mts"));
25
+
26
+ /**
27
+ * The user's files when no `--home` is given: database, workspace, installed skills. An
28
+ * installed package keeps them in the home folder, never inside the package — an upgrade
29
+ * replaces that. A checkout keeps them in the checkout, which is where `pnpm dev` already
30
+ * writes them (config.ts DATA_DIR): a build started here opens the data it was developed
31
+ * against, not a second, empty one beside it.
32
+ */
33
+ export const DEFAULT_HOME = isCheckout(ROOT)
34
+ ? ROOT
35
+ : join(homedir(), ".thursday");
36
+
14
37
  /**
15
38
  * What this person types to run the app, for a line that tells them to run it again. Only a
16
39
  * global install puts `thursday` on the PATH: said to someone who ran `npx`, it is a command
17
- * they do not have. npx names itself in npm_lifecycle_event and unpacks into its `_npx` cache;
18
- * a checkout is the one copy with the dev script beside it (the package ships no `scripts`).
40
+ * they do not have. npx names itself in npm_lifecycle_event and unpacks into its `_npx` cache,
41
+ * and the copy that runs in the background was put there from one.
19
42
  */
20
43
  export function thursdayCommand() {
44
+ // Written into the background job by the command that started it, which knew
45
+ if (process.env.THURSDAY_COMMAND?.trim())
46
+ return process.env.THURSDAY_COMMAND.trim();
21
47
  if (
22
48
  process.env.npm_lifecycle_event === "npx" ||
23
- ROOT.includes(`${sep}_npx${sep}`)
49
+ ROOT.includes(`${sep}_npx${sep}`) ||
50
+ ROOT.startsWith(`${PROGRAM}${sep}`)
24
51
  )
25
52
  return "npx thursday-agent";
26
- if (existsSync(join(ROOT, "scripts", "dev.mts"))) return "pnpm start";
53
+ if (isCheckout(ROOT)) return "pnpm start";
27
54
  return "thursday";
28
55
  }
29
56
 
57
+ /**
58
+ * The line to type for `sub` — start, stop, status, or "" to run it in a terminal — on this
59
+ * data folder: `--home` is said when it is not the one the command finds by itself. Followed
60
+ * as printed without it, a line served another folder, an empty app or a checkout's own data.
61
+ */
62
+ export function commandFor(sub, home, command = thursdayCommand()) {
63
+ const line = sub ? `${command} ${sub}` : command;
64
+ return home && resolve(home) !== DEFAULT_HOME
65
+ ? `${line} --home ${shellWord(home)}`
66
+ : line;
67
+ }
68
+
69
+ /** A path a shell reads back as it is: quoted once it holds more than plain characters. */
70
+ const shellWord = (path) =>
71
+ /^[\w@%+=:,./-]+$/.test(path) ? path : `'${path.replaceAll("'", `'\\''`)}'`;
72
+
73
+ /** A browser that will not open is not a failure. */
74
+ export function openBrowser(url) {
75
+ const [command, args] =
76
+ process.platform === "darwin"
77
+ ? ["open", [url]]
78
+ : process.platform === "win32"
79
+ ? ["cmd", ["/c", "start", "", url]]
80
+ : ["xdg-open", [url]];
81
+ spawn(command, args, { stdio: "ignore" }).on("error", () => {});
82
+ }
83
+
30
84
  /**
31
85
  * The `playwright-cli` entry, resolved rather than guessed: pnpm keeps it under
32
86
  * `.pnpm`, npm hoists it, npx puts it in a temp tree. Null when it is not
package/guide/calls.md CHANGED
@@ -28,6 +28,14 @@ several steps — goes to a bot while the call carries on. She picks the bot and
28
28
  While she is working, the line under her face says so. The microphone stays open: anything said
29
29
  meanwhile is heard and answered once she is done, so there is no need to repeat it.
30
30
 
31
+ **Share screen**, on that line during a spoken call, shows her a screen, a window or a tab; the
32
+ browser asks which. A small copy of it stands at the top right while it is shared. Nothing of it
33
+ is sent while it is only shared: she looks when what they ask needs it — "what does this error
34
+ say?" — and then a picture of it as it is at that moment goes to the model behind her, nowhere
35
+ else. **Stop** on the line, the browser's own bar, or the end of the call stops sharing. When the
36
+ browser refuses — on a Mac, the browser needs Screen Recording in System Settings › Privacy &
37
+ Security to share a window or the whole screen — its reason shows, and nothing is shared.
38
+
31
39
  ## Ending it
32
40
 
33
41
  Saying goodbye usually ends the call, but not always. Tapping her face ends it for certain, and so
package/guide/setup.md CHANGED
@@ -36,14 +36,17 @@ Two easier ways for bots come next:
36
36
  shows how much of the plan is used and when it resets. It does not cover a spoken call, which
37
37
  OpenAI bills by the minute on a key.
38
38
  - **Vercel AI Gateway**: one key for every model; its row shows what credit is left.
39
+ - **OpenRouter**: the same, one key for every model it carries, free ones among them; its row
40
+ shows what credit is left.
39
41
 
40
42
  Under them, every other provider (Claude, Gemini, xAI and more, some behind **More**) is a mark to
41
43
  tap and paste a key into, with a link to the page that makes one.
42
44
 
43
45
  A search key (Exa) is optional. With it, calls and bots all search through Exa, which is cheap and
44
46
  has free monthly credits. Without it, a call uses OpenAI's own search, and a bot uses its model's
45
- own search: the GPT Subscription, OpenAI, Claude, Gemini and xAI have one. A bot on the Gateway or
46
- any other provider has no search of its own, so it opens pages in its browser instead.
47
+ own search: the GPT Subscription, OpenAI, Claude, Gemini, xAI and OpenRouter have one. A bot on
48
+ the Gateway or any other provider has no search of its own, so it opens pages in its browser
49
+ instead.
47
50
 
48
51
  ## Models
49
52
 
@@ -121,20 +124,29 @@ with it. Chrome and Edge can install it as its own window with its own icon. The
121
124
  this once (**Install** or **Not now**), and **Install app** stays at the foot of the Settings list
122
125
  until it is installed. In Safari on a Mac it is **File › Add to Dock**; Firefox cannot do it.
123
126
 
124
- The window only shows what the server serves, and the server is started in a terminal with `npx
125
- thursday-agent`. On a Mac, `thursday autostart` makes the computer start it at login and restart it
126
- if it stops, so no terminal is needed; this needs the app installed with `npm i -g thursday-agent`,
127
- not run through `npx`. `thursday autostart --off` turns it off. On Linux and Windows, add it to the
128
- programs that start at login.
127
+ The window only shows what the server serves, and the server is started with `npx
128
+ thursday-agent`. On a Mac, the first start in a terminal asks once whether to keep it running in
129
+ the background. Yes, and no terminal is needed: it starts again when they log in, and comes back
130
+ by itself if it stops. `npx thursday-agent start` does the same later, and moves the background to
131
+ the version it was run as; if that version does not come up, the one before is started again, and
132
+ when nothing can run in the background, it runs in that terminal instead. When the Node it was
133
+ started with is removed, by a version manager or an upgrade, it starts on another Node it finds and
134
+ says which in its log, which keeps to about 10 MB with the one before beside it.
135
+ `npx thursday-agent stop` stops it, and it no longer starts at login; `npx thursday-agent status`
136
+ says whether it runs, where, and where its log is. **Settings › Thursday › Running** shows the same
137
+ and the command to change it, to copy; the app never stops or moves itself. The copy that runs in
138
+ the background is kept in `~/.thursday/app`. On Linux and Windows it runs in a terminal; add it to
139
+ the programs that start at login.
129
140
 
130
141
  The app uses the same address every time: port 4747 by default. If that port is taken one day, it
131
142
  says so and uses the next free one for that run, and the browser shows different settings there.
132
- `--port` with a number moves it for good (turn autostart on again after that). `--home` uses another
143
+ `--port` with a number moves it for good (in the background, `start` with it). `--home` uses another
133
144
  data folder, `--no-open` starts without opening a browser, and `--help` lists everything.
134
145
 
135
146
  Starting it again while it already runs on the same data folder opens the running one in the
136
147
  browser instead of starting a second, and says how to stop it. It needs Node 22.18 or newer.
137
- Closing the terminal it runs in stops it like Ctrl+C: running jobs pause and wait for **Continue**.
148
+ Closing the terminal it runs in stops it like Ctrl+C: running jobs pause and wait for **Continue**;
149
+ in the background, closing the terminal changes nothing.
138
150
 
139
151
  ## Where the files are
140
152
 
@@ -142,15 +154,17 @@ Everything is on this computer, in one folder: `.thursday` in their home folder
142
154
  `npx thursday-agent` or installed, or the folder it was started from otherwise; every start prints
143
155
  it. It holds the database (calls, memory, bots, keys, her settings), the kept sign-ins, and the
144
156
  workspace with finished work, each bot's folder and installed skills. Updating the app never touches
145
- it. Nothing is sent anywhere except to the model providers and services they set up. The app listens
146
- only to this computer and has no account.
157
+ any of these. On a Mac that keeps it running in the background, `app` in it is the copy that runs
158
+ there, which `start` replaces with each version. Nothing is sent anywhere except to the model
159
+ providers and services they set up. The app listens only to this computer and has no account.
147
160
 
148
161
  The bots' browser is the one thing outside it: a download of a few hundred megabytes in the
149
162
  computer's cache folder.
150
163
 
151
164
  To back up, copy that folder with the app stopped; moving to another computer is the same folder
152
- put in the same place. If the app ever cannot open the database, the terminal asks whether to set it
153
- aside and start fresh; the old file is kept beside the new one, with `.corrupt-` in its name.
165
+ put in the same place, and `app` need not come along: `start` there installs a copy for that
166
+ computer. If the app ever cannot open the database, the terminal asks whether to set it aside and
167
+ start fresh; the old file is kept beside the new one, with `.corrupt-` in its name.
154
168
 
155
169
  ## What it costs
156
170
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thursday-agent",
3
- "version": "0.18.0",
3
+ "version": "0.19.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": [
@@ -61,7 +61,7 @@ Words on the page are yours, in the user's language: set `lang` and `labels` whe
61
61
  - **A photo per stop** is one of three: `"wiki"`, the English Wikipedia title of the place
62
62
  (`"pt:Mosteiro dos Jerónimos"` for another language's — a place outside the English-speaking
63
63
  world often has an article, or a picture, only in its own language), whose lead picture comes
64
- with its author and licence; `"photo"` as a page url, whose own share picture is taken through the browser; `"photo"` as a
64
+ with who made it and, where its file says, its licence; `"photo"` as a page url, whose own share picture is taken through the browser; `"photo"` as a
65
65
  file beside the JSON. A stop with none shows without one — the airport, the hotel check-in, a walk.
66
66
  - **Every link is a full `http(s)` address** — `flights.link`, `stay.link`, a stop's `link`, a
67
67
  source's `url`. Anything shorter stops the build by name before a single photo is fetched.
@@ -188,14 +188,19 @@ const plain = (html) =>
188
188
  .replace(/\s+/g, " ")
189
189
  .trim();
190
190
 
191
- /** A Wikipedia article's own lead picture, with who made it and its licence from Commons. */
191
+ /**
192
+ * A Wikipedia article's own lead picture, with who made it and, where its file says, its licence.
193
+ * `pilicense=any`: the lead picture the article shows, not only a freely licensed one — the
194
+ * default (`free`) returns none for an article led by a non-free image, and the stop then shows
195
+ * without its photo.
196
+ */
192
197
  async function fromWiki(title) {
193
198
  const [wiki, name] = /^[a-z]{2,3}:/.test(title)
194
199
  ? [title.slice(0, title.indexOf(":")), title.slice(title.indexOf(":") + 1)]
195
200
  : ["en", title];
196
201
  const api = `https://${wiki}.wikipedia.org/w/api.php?format=json&action=query&redirects=1`;
197
202
  const q = await getJson(
198
- `${api}&prop=pageimages|info&inprop=url&piprop=thumbnail|name&pithumbsize=960&titles=${encodeURIComponent(name)}`,
203
+ `${api}&prop=pageimages|info&inprop=url&piprop=thumbnail|name&pithumbsize=960&pilicense=any&titles=${encodeURIComponent(name)}`,
199
204
  );
200
205
  const page = Object.values(q.query?.pages ?? {})[0];
201
206
  if (!page || "missing" in page)
@@ -77,8 +77,7 @@ first is the cover, asking the question the book answers.
77
77
  Choose each page's picture in this order:
78
78
 
79
79
  - **A real thing whose look matters** — a place, an animal, a machine, a
80
- person's work — is a real photo from the web. Take it from the page you read,
81
- or from Wikimedia Commons, whose files allow reuse with credit:
80
+ person's work — is a real photo from the web, taken from the page you read:
82
81
 
83
82
  ```bash
84
83
  node "$THURSDAY_SKILLS/browser/scripts/webimage.mjs" <page url> --out <the book's folder> [--all]
@@ -88,7 +87,8 @@ Choose each page's picture in this order:
88
87
  through the session's browser, keeps only what came back as an image, and
89
88
  prints each file with its size and a `Credit:` line. Every run writes `web-01.…`, so rename what you keep to the
90
89
  page's own name before fetching the next one. Put the credit in the figure:
91
- `<figcaption>Photo: <author>, <a href="…">source</a>, <license></figcaption>`.
90
+ `<figcaption>Photo: <a href="…">source</a></figcaption>`, with who made it and
91
+ its licence added when the page says them.
92
92
  - **A structure, a flow, a relation** — parts of a whole, one thing asking
93
93
  another, a before and after — is an inline `<svg viewBox="0 0 800 400">`
94
94
  drawn by hand. Fill it with `var(--ink)`, `var(--paper)`, `var(--blue)`,
@@ -1,3 +0,0 @@
1
- {
2
- "/api/llm-model/catalog/route": "app/api/llm-model/catalog/route.js"
3
- }