thursday-agent 0.12.0 → 0.13.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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +4 -4
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +18 -19
- package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -19
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -15
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/artifact/route.js +8 -8
- package/.next/server/app/api/artifact/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/keep-working/route.js +7 -7
- package/.next/server/app/api/bot/keep-working/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/route.js +7 -7
- package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/route.js +7 -7
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/[id]/route.js +5 -5
- package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/route.js +3 -3
- package/.next/server/app/api/bot/thread/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route.js +3 -3
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/favicon/[host]/route.js.nft.json +1 -1
- package/.next/server/app/api/file/[...path]/route.js +2 -2
- package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/catalog/route.js +4 -4
- package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/credits/route.js +4 -4
- package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/route.js +6 -6
- package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/subscription/route.js +6 -6
- package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/[name]/route.js +5 -5
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js +5 -5
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js +5 -5
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/edit/route.js +15 -14
- package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/route.js +4 -4
- package/.next/server/app/api/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/reach/route.js +13 -12
- package/.next/server/app/api/reach/route.js.nft.json +1 -1
- package/.next/server/app/api/routine/route.js +8 -9
- package/.next/server/app/api/routine/route.js.nft.json +1 -1
- package/.next/server/app/api/signins/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[source]/[name]/route.js +2 -2
- package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js +2 -2
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/call/route.js +6 -6
- package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/skills/route.js +6 -6
- package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/text/route.js +14 -13
- package/.next/server/app/api/thursday/text/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/tool-call/route.js +15 -14
- package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/files/route.js +10 -6
- package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/route.js +9 -4
- package/.next/server/app/api/workspace/route.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +2 -2
- package/.next/server/app/artifact/[...path]/page.js +5 -4
- package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/.next/server/app/page/server-reference-manifest.json +67 -56
- package/.next/server/app/page.js +10 -11
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0o49ztf._.js → [root-of-the-server]__0-k4_ie._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__0209ah4._.js +6 -6
- package/.next/server/chunks/[root-of-the-server]__04wldw9._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0cfszwn._.js → [root-of-the-server]__0i23tc1._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__0mrk2it._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0nr-v8s._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__1tg5got._.js → [root-of-the-server]__0paqm5y._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__0qog7sm._.js +8 -0
- package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0yisc5v._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1-swlkw._.js +3 -3
- package/.next/server/chunks/[root-of-the-server]__12iddfq._.js +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0npn_pn._.js → [root-of-the-server]__15p29m3._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__17ses32._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__1cjxw0-._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1gi2nns._.js +5 -0
- package/.next/server/chunks/{[root-of-the-server]__0rqgb17._.js → [root-of-the-server]__1iauz8a._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__1k3j52n._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__209k6pk._.js → [root-of-the-server]__1lb_pxg._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__1ndi14y._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1xqsrqq._.js +5 -0
- package/.next/server/chunks/[root-of-the-server]__1ygplx1._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__2163i40._.js +5 -0
- package/.next/server/chunks/_0ci0abh._.js +3 -0
- package/.next/server/chunks/_0eauz4t._.js +1 -1
- package/.next/server/chunks/_0f6ts7z._.js +1 -1
- package/.next/server/chunks/_0fg-1oj._.js +5 -0
- package/.next/server/chunks/_0khihjk._.js +2 -2
- package/.next/server/chunks/_0n74zsf._.js +1 -1
- package/.next/server/chunks/_0na2fj1._.js +2 -2
- package/.next/server/chunks/_0oh_99-._.js +3 -0
- package/.next/server/chunks/_0x-ej3f._.js +24 -24
- package/.next/server/chunks/_0z3nz21._.js +3 -0
- package/.next/server/chunks/_10tkr26._.js +1 -1
- package/.next/server/chunks/_12-amdu._.js +2 -2
- package/.next/server/chunks/_136j09a._.js +1 -1
- package/.next/server/chunks/_15740dw._.js +1 -1
- package/.next/server/chunks/_18izeh1._.js +5 -0
- package/.next/server/chunks/_1_5mnq4._.js +1 -1
- package/.next/server/chunks/_1ajbhv6._.js +2 -2
- package/.next/server/chunks/_1dc_d1q._.js +2 -2
- package/.next/server/chunks/_1drgfx4._.js +1 -1
- package/.next/server/chunks/_1e48czp._.js +2 -2
- package/.next/server/chunks/_1f06zo4._.js +3 -0
- package/.next/server/chunks/_1ic3bew._.js +2 -2
- package/.next/server/chunks/_1jn-aep._.js +2 -2
- package/.next/server/chunks/_1jn5btd._.js +6 -0
- package/.next/server/chunks/_1kg70wc._.js +2 -2
- package/.next/server/chunks/_1m2i5pt._.js +5 -0
- package/.next/server/chunks/_1ogqovh._.js +4 -4
- package/.next/server/chunks/_1qxheoa._.js +1 -1
- package/.next/server/chunks/_1ry6afh._.js +18 -0
- package/.next/server/chunks/_1taa4bs._.js +1 -1
- package/.next/server/chunks/_1tpr507._.js +1 -1
- package/.next/server/chunks/_1y8w80a._.js +1 -1
- package/.next/server/chunks/_1zxp-p6._.js +1 -1
- package/.next/server/chunks/_204744f._.js +5 -0
- package/.next/server/chunks/_20fsr_z._.js +1 -1
- package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
- package/.next/server/chunks/features_0-cnt0l._.js +1 -1
- package/.next/server/chunks/features_0hdaci0._.js +1 -1
- package/.next/server/chunks/features_0p85gv6._.js +3 -0
- package/.next/server/chunks/{node_modules_zod_v4_0_v5xf5._.js → node_modules_zod_v4_01bha1c._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_0q9hvql._.js → node_modules_zod_v4_0b99z6a._.js} +2 -2
- package/.next/server/chunks/{node_modules_zod_v4_1jg8iwg._.js → node_modules_zod_v4_1zz6lo1._.js} +2 -2
- package/.next/server/chunks/ssr/[root-of-the-server]__04upd5v._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0dxszdt._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0eezycw._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0hpp3nw._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0yngu44._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__16z72ny._.js +6 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1u_ry86._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__1iwyp1e._.js → [root-of-the-server]__1unh_ew._.js} +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__20re7ya._.js +3 -0
- package/.next/server/chunks/ssr/_00pgq9d._.js +5 -0
- package/.next/server/chunks/ssr/_07ke63g._.js +3 -0
- package/.next/server/chunks/ssr/_0agcbk7._.js +3 -0
- package/.next/server/chunks/ssr/_0e-gw2_._.js +3 -0
- package/.next/server/chunks/ssr/{_0fbi6om._.js → _0f_om6y._.js} +3 -3
- package/.next/server/chunks/ssr/_0fqhhwi._.js +1 -1
- package/.next/server/chunks/ssr/{_026qnc9._.js → _0gpn71k._.js} +3 -3
- package/.next/server/chunks/ssr/_0iizjr9._.js +3 -0
- package/.next/server/chunks/ssr/_0ixvzo6._.js +75 -0
- package/.next/server/chunks/ssr/_0kkdx7t._.js +3 -0
- package/.next/server/chunks/ssr/_0lufvw7._.js +118 -0
- package/.next/server/chunks/ssr/_0vi6ky6._.js +115 -0
- package/.next/server/chunks/ssr/{_10f-jib._.js → _0yhji3e._.js} +2 -2
- package/.next/server/chunks/ssr/_0z38nha._.js +3 -0
- package/.next/server/chunks/ssr/{_10mo72m._.js → _11nx2d4._.js} +2 -2
- package/.next/server/chunks/ssr/_12mijol._.js +2 -2
- package/.next/server/chunks/ssr/_150463c._.js +164 -0
- package/.next/server/chunks/ssr/{_0rmaf32._.js → _17d2ikl._.js} +2 -2
- package/.next/server/chunks/ssr/_19jez1a._.js +3 -0
- package/.next/server/chunks/ssr/_1blui1m._.js +3 -0
- package/.next/server/chunks/ssr/_1d423aj._.js +4 -4
- package/.next/server/chunks/ssr/_1kbk28w._.js +3 -0
- package/.next/server/chunks/ssr/_1kj_r9v._.js +3 -0
- package/.next/server/chunks/ssr/_1mqn9mc._.js +1 -1
- package/.next/server/chunks/ssr/{_0u5xv6g._.js → _1myh7ss._.js} +2 -2
- package/.next/server/chunks/ssr/_1neoj22._.js +1 -1
- package/.next/server/chunks/ssr/_1ou5sj0._.js +3 -0
- package/.next/server/chunks/ssr/_1p8xorg._.js +3 -0
- package/.next/server/chunks/ssr/_1tzacpl._.js +3 -0
- package/.next/server/chunks/ssr/_1xoch6f._.js +1 -1
- package/.next/server/chunks/ssr/_1yh5bj5._.js +1 -1
- package/.next/server/chunks/ssr/{_02c7o30._.js → _2021n9-._.js} +2 -2
- package/.next/server/chunks/ssr/_20argo3._.js +3 -0
- package/.next/server/chunks/ssr/features_bot_1ll3wp7._.js +3 -0
- package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +1 -1
- package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +1 -1
- package/.next/server/chunks/ssr/features_config_1qxe5ur._.js +20 -0
- package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +3 -3
- package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +1 -1
- package/.next/server/chunks/ssr/features_routine_components_routine-setting_tsx_055fknz._.js +1 -1
- package/.next/server/chunks/ssr/features_workspace_00jz2hu._.js +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ky76fz._.js → node_modules_06e0wlv._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0-x0zxm._.js → node_modules_0cj26-9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0operbz._.js → node_modules_0d1rf5e._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0b0iy01._.js → node_modules_0e86703._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_05b6e99._.js → node_modules_0es09am._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1iau_ea._.js → node_modules_0gr_dzf._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1hv-j1l._.js → node_modules_0gtcwz9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1c2ikr9._.js → node_modules_0hi9h8f._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_01u4ea3._.js → node_modules_0lkop0t._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1wvf3oo._.js → node_modules_0nghisk._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0yzmxfq._.js → node_modules_0stovz0._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_00nrzz_._.js → node_modules_0we85kr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_01ed0yi._.js → node_modules_0ya7y1s._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0m3_5ge._.js → node_modules_0yrbwkj._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0v_-uht._.js → node_modules_1-x70ie._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_07jp6tj._.js → node_modules_12fd9g0._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1wgnj8q._.js → node_modules_12wxrgr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0azd56x._.js → node_modules_139uu4q._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1omg9xr._.js → node_modules_14gpoe1._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1ma_y68._.js → node_modules_18fmji6._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ucridu._.js → node_modules_19kkel8._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0fpnetd._.js → node_modules_1gcine1._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1z3sh11._.js → node_modules_1h4trkm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0lautv3._.js → node_modules_1mub_qu._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0ou0all._.js → node_modules_1p78svs._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_19b0bir._.js → node_modules_1xp-7ep._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0tmjn9w._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0ay7_oi._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1_e8c3o._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_182ydq_._.js} +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +69 -58
- package/.next/static/chunks/03df16hs01-xi.js +1 -0
- package/.next/static/chunks/0crocb7272z8k.js +1 -0
- package/.next/static/chunks/{0p9jcyqkpq71f.js → 0dqsenl3uk_8z.js} +1 -1
- package/.next/static/chunks/0hhn8mf953761.js +1 -0
- package/.next/static/chunks/0n1o3k0z4m7c_.js +1 -0
- package/.next/static/chunks/0oe2zavre2a7d.css +1 -0
- package/.next/static/chunks/0srg9tv4105-i.js +1 -0
- package/.next/static/chunks/0t599wrclly7i.js +18 -0
- package/.next/static/chunks/0x34bhth_sn35.js +1 -0
- package/.next/static/chunks/{0mscosx0eh3ee.js → 0x_6z8vt8hyf4.js} +3 -3
- package/.next/static/chunks/{0p50d-au6-3hx.js → 1_wstwzu1md-6.js} +2 -2
- package/.next/static/chunks/{40ij3wsn3vt7h.js → 1aughn81slf90.js} +1 -1
- package/.next/static/chunks/1g1j03h_l-e67.js +1 -0
- package/.next/static/chunks/1lp02y2nmddxg.js +1 -0
- package/.next/static/chunks/211s4xjtecj2l.js +1 -0
- package/.next/static/chunks/2244-cat2jlvd.js +1 -0
- package/.next/static/chunks/{2r6xnyg7ezyxr.js → 2eev_i93slion.js} +2 -2
- package/.next/static/chunks/2sjq4gsimlfqr.js +113 -0
- package/.next/static/chunks/{0qgn3u86jkbm7.js → 2uleilh8ph06-.js} +1 -1
- package/.next/static/chunks/{1czfknd4luo6t.js → 2zchsg03a1pdp.js} +1 -1
- package/.next/static/chunks/32tmfirfjpulv.js +1 -0
- package/.next/static/chunks/{2_c7mu6x1lu49.js → 376-s_i83irs-.js} +1 -1
- package/.next/static/chunks/3blk-kpn39xr-.js +1 -0
- package/.next/static/chunks/3eieehp7wquyu.js +1 -0
- package/.next/static/chunks/3kc-e7pcj50ae.js +1 -0
- package/.next/static/chunks/3rwpyuo9nrrop.js +17 -0
- package/.next/static/chunks/3sf4l25l353ja.js +1 -0
- package/.next/static/chunks/3vz7m1w688juj.js +3 -0
- package/.next/static/chunks/43skgt0h9woyu.js +1 -0
- package/app/api/events/app-event.client.ts +8 -2
- package/app/api/events/app-event.server.ts +7 -5
- package/app/api/events/app-event.ts +19 -8
- package/app/api/query-key.ts +13 -5
- package/bin/database.mjs +21 -11
- package/bin/thursday.mjs +5 -2
- package/components/ui/shiny-text.tsx +2 -2
- package/database/migrations/20260920024909_messy_baron_strucker/migration.sql +1 -0
- package/database/migrations/20260920024909_messy_baron_strucker/snapshot.json +1937 -0
- package/features/artifact/components/artifact-setting.tsx +18 -24
- package/features/bot/bot.action.ts +3 -0
- package/features/bot/bot.runner.ts +25 -3
- package/features/bot/bot.seed.ts +98 -22
- package/features/bot/components/bot-badge.tsx +2 -2
- package/features/bot/components/bot-mark.tsx +12 -3
- package/features/bot/components/bot-room.tsx +33 -10
- package/features/bot/components/bot-setting.tsx +88 -34
- package/features/bot/components/crew-motion.ts +161 -0
- package/features/bot/components/mark-palette.tsx +3 -3
- package/features/bot/components/room-conversation.tsx +13 -8
- package/features/bot/components/room-list.tsx +9 -5
- package/features/bot/components/room-pill.tsx +131 -41
- package/features/bot/components/thread-badge.tsx +4 -4
- package/features/bot/components/thread-setting.tsx +58 -19
- package/features/bot/mark.const.ts +24 -0
- package/features/bot/thread.query.ts +32 -14
- package/features/bot/thread.store.ts +19 -16
- package/features/config/components/config-badge.tsx +2 -2
- package/features/config/components/config-setting.tsx +63 -213
- package/features/config/config.const.ts +2 -1
- package/features/connectors/components/mcp-setting.tsx +60 -29
- package/features/intro/components/intro.tsx +2 -2
- package/features/memory/components/memory-setting.tsx +11 -7
- package/features/reach/channel.ts +9 -1
- package/features/reach/components/reach-guide.tsx +606 -105
- package/features/reach/discord.ts +18 -3
- package/features/reach/reach.schema.ts +6 -0
- package/features/reach/reach.ts +55 -2
- package/features/reach/slack.ts +2 -1
- package/features/reach/telegram.ts +5 -1
- package/features/routine/components/routine-setting.tsx +46 -18
- package/features/settings/components/setting-ui.tsx +17 -68
- package/features/settings/components/settings.tsx +4 -3
- package/features/settings/settings.alert.ts +8 -8
- package/features/skills/components/skills-setting.tsx +78 -12
- package/features/skills/skills.action.ts +12 -0
- package/features/skills/skills.query.ts +24 -0
- package/features/thursday/components/call-log.tsx +19 -14
- package/features/thursday/components/side-captions.tsx +3 -2
- package/features/thursday/components/thursday-setting.tsx +5 -6
- package/features/thursday/components/thursday.tsx +8 -9
- package/features/thursday/components/write-line.tsx +10 -5
- package/features/thursday/thursday.action.ts +4 -0
- package/features/thursday/thursday.query.ts +3 -2
- package/features/thursday/thursday.schema.ts +5 -0
- package/features/thursday/use-call-ring.ts +6 -1
- package/features/thursday/use-text-call.ts +25 -10
- package/features/thursday/use-thursday.ts +10 -1
- package/features/workspace/components/artifact-view.tsx +42 -33
- package/features/workspace/components/file-thumb.tsx +8 -4
- package/features/workspace/components/file-view.tsx +25 -2
- package/features/workspace/components/workspace-setting.tsx +27 -23
- package/features/workspace/workspace.query.ts +20 -1
- package/features/workspace/workspace.ts +14 -0
- package/guide/bots.md +27 -4
- package/guide/calls.md +5 -3
- package/guide/phone.md +23 -12
- package/guide/setup.md +20 -5
- package/guide/trouble.md +1 -1
- package/hooks/use-theme.ts +14 -0
- package/lib/protocol/events.client.ts +56 -14
- package/lib/protocol/events.server.ts +41 -12
- package/lib/utils.ts +1 -1
- package/package.json +1 -1
- package/scripts/reach-channels.test.mts +15 -2
- package/seed-skills/brief/daily-brief/SKILL.md +39 -0
- package/seed-skills/brief/daily-brief/page/brief.css +406 -0
- package/seed-skills/brief/daily-brief/references/brief.md +106 -0
- package/seed-skills/brief/daily-brief/references/preferences.md +67 -0
- package/seed-skills/brief/daily-brief/scripts/glance.mjs +128 -0
- package/seed-skills/brief/daily-brief/scripts/lib.mjs +182 -0
- package/seed-skills/brief/daily-brief/scripts/news.mjs +320 -0
- package/seed-skills/brief/daily-brief/scripts/page.mjs +322 -0
- package/seed-skills/brief/daily-brief/scripts/story.mjs +265 -0
- package/seed-skills/digest/README.md +20 -0
- package/seed-skills/digest/media-digest/SKILL.md +32 -0
- package/seed-skills/digest/media-digest/references/no-captions.md +20 -0
- package/seed-skills/digest/media-digest/references/page.md +56 -0
- package/seed-skills/digest/media-digest/references/reading.md +56 -0
- package/seed-skills/digest/media-digest/scripts/audio.mjs +232 -0
- package/seed-skills/digest/media-digest/scripts/digest.mjs +379 -0
- package/seed-skills/digest/media-digest/scripts/lib.mjs +284 -0
- package/seed-skills/digest/media-digest/scripts/part.mjs +16 -0
- package/seed-skills/digest/media-digest/scripts/text.mjs +287 -0
- package/seed-skills/digest/media-digest/scripts/yt.mjs +487 -0
- package/seed-skills/docs/README.md +32 -0
- package/seed-skills/docs/documents/SKILL.md +34 -0
- package/seed-skills/docs/documents/kit/package-lock.json +1596 -0
- package/seed-skills/docs/documents/kit/package.json +17 -0
- package/seed-skills/docs/documents/references/deck.md +63 -0
- package/seed-skills/docs/documents/references/invoice.md +64 -0
- package/seed-skills/docs/documents/references/pdf.md +59 -0
- package/seed-skills/docs/documents/references/print.md +43 -0
- package/seed-skills/docs/documents/references/sheets.md +49 -0
- package/seed-skills/docs/documents/references/translate.md +37 -0
- package/seed-skills/docs/documents/references/word.md +45 -0
- package/seed-skills/docs/documents/scripts/doc.mjs +123 -0
- package/seed-skills/docs/documents/scripts/lib/browser.mjs +259 -0
- package/seed-skills/docs/documents/scripts/lib/deck-chart.mjs +150 -0
- package/seed-skills/docs/documents/scripts/lib/deck.mjs +1132 -0
- package/seed-skills/docs/documents/scripts/lib/invoice.mjs +505 -0
- package/seed-skills/docs/documents/scripts/lib/kit.mjs +244 -0
- package/seed-skills/docs/documents/scripts/lib/pdf.mjs +645 -0
- package/seed-skills/docs/documents/scripts/lib/report.mjs +38 -0
- package/seed-skills/docs/documents/scripts/lib/sheet.mjs +523 -0
- package/seed-skills/docs/documents/scripts/lib/templates.mjs +34 -0
- package/seed-skills/docs/documents/scripts/lib/translate.mjs +691 -0
- package/seed-skills/docs/documents/scripts/lib/word.mjs +678 -0
- package/seed-skills/docs/documents/templates/letter.html +56 -0
- package/seed-skills/docs/documents/templates/print.css +219 -0
- package/seed-skills/docs/documents/templates/report.html +47 -0
- package/seed-skills/docs/documents/templates/resume.html +61 -0
- package/seed-skills/insta/instagram/references/post.md +31 -7
- package/seed-skills/trip/README.md +11 -0
- package/seed-skills/trip/travel/SKILL.md +40 -0
- package/seed-skills/trip/travel/page/itinerary.css +488 -0
- package/seed-skills/trip/travel/references/itinerary.md +70 -0
- package/seed-skills/trip/travel/references/plan.md +75 -0
- package/seed-skills/trip/travel/references/watch-and-book.md +39 -0
- package/seed-skills/trip/travel/scripts/flights.mjs +374 -0
- package/seed-skills/trip/travel/scripts/fx.mjs +57 -0
- package/seed-skills/trip/travel/scripts/hotels.mjs +356 -0
- package/seed-skills/trip/travel/scripts/itinerary.mjs +482 -0
- package/seed-skills/trip/travel/scripts/lib.mjs +120 -0
- package/seed-skills/trip/travel/scripts/selectors.mjs +78 -0
- package/seed-skills/trip/travel/scripts/watch.mjs +147 -0
- package/seed-skills/trip/travel/scripts/weather.mjs +150 -0
- package/seed-skills/tutor/picture-book/SKILL.md +6 -0
- package/seed-skills/tutor/picture-book/references/picture-book.md +22 -2
- package/.next/server/chunks/[root-of-the-server]__014ydvq._.js +0 -8
- package/.next/server/chunks/[root-of-the-server]__01d285y._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__04r4h-2._.js +0 -7
- package/.next/server/chunks/[root-of-the-server]__0ayldfn._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__17weeeg._.js +0 -5
- package/.next/server/chunks/[root-of-the-server]__1ai5lme._.js +0 -8
- package/.next/server/chunks/_05v8k21._.js +0 -7
- package/.next/server/chunks/_0k6qjcf._.js +0 -5
- package/.next/server/chunks/_1d_enhu._.js +0 -3
- package/.next/server/chunks/_1jc5g4p._.js +0 -6
- package/.next/server/chunks/_1nfr-75._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0md6j0x._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_14ih1vy._.js +0 -3
- package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1d6ez5-._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0a967km._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0tzekbl._.js +0 -68
- package/.next/server/chunks/ssr/[root-of-the-server]__1756892._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1nqw56a._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1r77-88._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__1w9hqq8._.js +0 -8
- package/.next/server/chunks/ssr/_05pl_u8._.js +0 -3
- package/.next/server/chunks/ssr/_097-ljd._.js +0 -4
- package/.next/server/chunks/ssr/_0euzzf8._.js +0 -3
- package/.next/server/chunks/ssr/_0evkpto._.js +0 -3
- package/.next/server/chunks/ssr/_0igfcax._.js +0 -20
- package/.next/server/chunks/ssr/_0lu1n_x._.js +0 -3
- package/.next/server/chunks/ssr/_0nvh1h9._.js +0 -3
- package/.next/server/chunks/ssr/_0qmpw35._.js +0 -3
- package/.next/server/chunks/ssr/_0uv-qs4._.js +0 -3
- package/.next/server/chunks/ssr/_132qkfz._.js +0 -5
- package/.next/server/chunks/ssr/_15zqt-t._.js +0 -3
- package/.next/server/chunks/ssr/_16gfxpn._.js +0 -3
- package/.next/server/chunks/ssr/_184327j._.js +0 -3
- package/.next/server/chunks/ssr/_18ujhhq._.js +0 -3
- package/.next/server/chunks/ssr/_1lx6w_o._.js +0 -67
- package/.next/server/chunks/ssr/_1ntpny5._.js +0 -3
- package/.next/server/chunks/ssr/_1o1g4uk._.js +0 -5
- package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
- package/.next/server/chunks/ssr/_2008vmi._.js +0 -164
- package/.next/server/chunks/ssr/features_bot_1n1s7bh._.js +0 -3
- package/.next/static/chunks/09pkygbht7ki8.js +0 -18
- package/.next/static/chunks/0bm-nhblcmmj4.js +0 -17
- package/.next/static/chunks/0c_g4-11sha-1.js +0 -1
- package/.next/static/chunks/0hhza87hkbqaz.js +0 -1
- package/.next/static/chunks/0samf80yu2b17.js +0 -1
- package/.next/static/chunks/0vlgzqo9ka90v.js +0 -1
- package/.next/static/chunks/1g9yyvculuxj2.js +0 -1
- package/.next/static/chunks/1jz8n0mhtdzr8.js +0 -1
- package/.next/static/chunks/206laxm6maiz2.js +0 -1
- package/.next/static/chunks/23nfu5g4vl_m7.js +0 -1
- package/.next/static/chunks/2h-tlhb2ffhkk.js +0 -1
- package/.next/static/chunks/2i5_w8olnrvo0.js +0 -3
- package/.next/static/chunks/2m6jd3586ijb-.js +0 -1
- package/.next/static/chunks/2m8iqwc6sykln.js +0 -1
- package/.next/static/chunks/33fyp-byw48ju.js +0 -65
- package/.next/static/chunks/35yd_27d9ylra.js +0 -1
- package/.next/static/chunks/3ag1i3__yl94f.js +0 -1
- package/.next/static/chunks/3m_ejzg-xn21r.css +0 -1
- package/.next/static/chunks/3s-jpd3ky49-n.js +0 -1
- package/features/reach/components/reach-state.tsx +0 -71
- /package/.next/static/{QSe0rTdXU5kh5BBzr2XBB → fiNGsQfna8qldl8wU8wqr}/_buildManifest.js +0 -0
- /package/.next/static/{QSe0rTdXU5kh5BBzr2XBB → fiNGsQfna8qldl8wU8wqr}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{QSe0rTdXU5kh5BBzr2XBB → fiNGsQfna8qldl8wU8wqr}/_ssgManifest.js +0 -0
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Wrench,
|
|
12
12
|
X,
|
|
13
13
|
} from "lucide-react";
|
|
14
|
-
import { type ReactNode, useState } from "react";
|
|
14
|
+
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
15
15
|
import { queryKey } from "@/app/api/query-key";
|
|
16
16
|
import { Button } from "@/components/ui/button";
|
|
17
17
|
import {
|
|
@@ -34,6 +34,11 @@ import { ShinyText } from "@/components/ui/shiny-text";
|
|
|
34
34
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
35
35
|
import { Switch } from "@/components/ui/switch";
|
|
36
36
|
import { Textarea } from "@/components/ui/textarea";
|
|
37
|
+
import {
|
|
38
|
+
Tooltip,
|
|
39
|
+
TooltipContent,
|
|
40
|
+
TooltipTrigger,
|
|
41
|
+
} from "@/components/ui/tooltip";
|
|
37
42
|
import { APP_NAME, BOT_RUN, PROMPT_CROWDED } from "@/config";
|
|
38
43
|
import { ModelPicker } from "@/features/ai/components/model-picker";
|
|
39
44
|
import {
|
|
@@ -74,6 +79,7 @@ import {
|
|
|
74
79
|
mediaModelWords,
|
|
75
80
|
} from "@/features/config/config.const";
|
|
76
81
|
import {
|
|
82
|
+
PICKED_ROW,
|
|
77
83
|
SettingDialogContent,
|
|
78
84
|
SettingError,
|
|
79
85
|
SettingNote,
|
|
@@ -99,9 +105,18 @@ import { revalidate, useServerRoute } from "@/lib/protocol/use-server-route";
|
|
|
99
105
|
import { cn, formatCount, WAITING_INK } from "@/lib/utils";
|
|
100
106
|
import { MARK_SHAPES, MARK_SYSTEM } from "../mark.const";
|
|
101
107
|
|
|
108
|
+
/** A new bot's Create, raised from its page to the rail at the foot of the screen. */
|
|
109
|
+
type DraftCreate = {
|
|
110
|
+
/** What the form still lacks, in words ("a name"); empty when it can be created. */
|
|
111
|
+
missing: string[];
|
|
112
|
+
creating: boolean;
|
|
113
|
+
submit: () => void;
|
|
114
|
+
};
|
|
115
|
+
|
|
102
116
|
/**
|
|
103
117
|
* The bots Thursday hands background work to. Roster on the left, the picked bot's
|
|
104
|
-
* page on the right. Fields save on blur or on pick; only a new bot has a Create button
|
|
118
|
+
* page on the right. Fields save on blur or on pick; only a new bot has a Create button,
|
|
119
|
+
* in the rail at the foot where every other form keeps its own.
|
|
105
120
|
*/
|
|
106
121
|
export function BotSetting() {
|
|
107
122
|
const { data, isLoading, error } = useServerRoute<Bot[]>(queryKey.bot);
|
|
@@ -121,6 +136,7 @@ export function BotSetting() {
|
|
|
121
136
|
* no two rosters look alike; a seed itself carries none).
|
|
122
137
|
*/
|
|
123
138
|
const [faces] = useState(rollSeedIcons);
|
|
139
|
+
const [draft, setDraft] = useState<DraftCreate | null>(null);
|
|
124
140
|
|
|
125
141
|
if (isLoading) return <SettingPanesSkeleton />;
|
|
126
142
|
if (error) return <SettingError message={error.message} />;
|
|
@@ -135,7 +151,11 @@ export function BotSetting() {
|
|
|
135
151
|
|
|
136
152
|
return (
|
|
137
153
|
<SettingPanes
|
|
138
|
-
footer={
|
|
154
|
+
footer={
|
|
155
|
+
bots.length === 0 && !drafting ? null : (
|
|
156
|
+
<BotRail bot={current} draft={drafting ? draft : null} />
|
|
157
|
+
)
|
|
158
|
+
}
|
|
139
159
|
left={
|
|
140
160
|
<div className="flex flex-col py-2">
|
|
141
161
|
{/* The two ways to get a bot, on one line and apart from the roster
|
|
@@ -147,7 +167,7 @@ export function BotSetting() {
|
|
|
147
167
|
className={cn(
|
|
148
168
|
"flex flex-1 items-center gap-2 rounded-md px-2 py-1.5 text-left text-[13px] outline-none focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:ring-inset",
|
|
149
169
|
drafting
|
|
150
|
-
?
|
|
170
|
+
? PICKED_ROW
|
|
151
171
|
: "text-muted-foreground hover:bg-muted/60 hover:text-foreground",
|
|
152
172
|
)}
|
|
153
173
|
>
|
|
@@ -190,7 +210,7 @@ export function BotSetting() {
|
|
|
190
210
|
key="new"
|
|
191
211
|
jobs={[]}
|
|
192
212
|
onDone={(name) => setPicked(name)}
|
|
193
|
-
|
|
213
|
+
onDraft={setDraft}
|
|
194
214
|
/>
|
|
195
215
|
) : current ? (
|
|
196
216
|
// Keyed by name so field state does not carry over to the next bot.
|
|
@@ -213,7 +233,7 @@ export function BotSetting() {
|
|
|
213
233
|
) : (
|
|
214
234
|
<div className="space-y-4 p-8">
|
|
215
235
|
<p className="text-sm leading-relaxed text-muted-foreground">
|
|
216
|
-
|
|
236
|
+
Thursday talks; bots do the rest — search the web, draft a reply,
|
|
217
237
|
check a schedule. Give one a job and a model, and work gets handed
|
|
218
238
|
over mid-call while the conversation keeps going.
|
|
219
239
|
</p>
|
|
@@ -253,7 +273,7 @@ function RosterRow({
|
|
|
253
273
|
onClick={onPick}
|
|
254
274
|
className={cn(
|
|
255
275
|
"mx-2 flex items-center gap-2.5 rounded-md px-2 py-2 text-left outline-none focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:ring-inset",
|
|
256
|
-
active ?
|
|
276
|
+
active ? PICKED_ROW : "hover:bg-muted/60",
|
|
257
277
|
)}
|
|
258
278
|
>
|
|
259
279
|
<BotMark
|
|
@@ -424,7 +444,7 @@ function SeedRows({
|
|
|
424
444
|
owned
|
|
425
445
|
? "opacity-45 ring-border/60"
|
|
426
446
|
: on
|
|
427
|
-
? "ring-brand"
|
|
447
|
+
? cn(PICKED_ROW, "ring-brand")
|
|
428
448
|
: "ring-border/60",
|
|
429
449
|
)}
|
|
430
450
|
>
|
|
@@ -669,15 +689,15 @@ function BotPage({
|
|
|
669
689
|
bot,
|
|
670
690
|
jobs,
|
|
671
691
|
onDone,
|
|
672
|
-
|
|
692
|
+
onDraft,
|
|
673
693
|
}: {
|
|
674
694
|
bot?: Bot;
|
|
675
695
|
/** Recent jobs for this bot (RECENT); empty for a new bot. */
|
|
676
696
|
jobs: Thread[];
|
|
677
697
|
/** Created or deleted; where the roster should look next. */
|
|
678
698
|
onDone: (name: string | null) => void;
|
|
679
|
-
/** New bot only:
|
|
680
|
-
|
|
699
|
+
/** New bot only: where its Create goes, the rail at the foot (BotRail). */
|
|
700
|
+
onDraft?: (draft: DraftCreate | null) => void;
|
|
681
701
|
}) {
|
|
682
702
|
// Lazy init so a new bot's icon is not re-rolled per render; the page is keyed per bot.
|
|
683
703
|
const [fields, patch] = useObjectState(() => ({
|
|
@@ -743,6 +763,11 @@ function BotPage({
|
|
|
743
763
|
|
|
744
764
|
const ready =
|
|
745
765
|
name.trim() && description.trim() && provider && model.trim() && !creating;
|
|
766
|
+
const missing = [
|
|
767
|
+
!name.trim() && "a name",
|
|
768
|
+
!description.trim() && "a description",
|
|
769
|
+
!(provider && model.trim()) && "a model",
|
|
770
|
+
].filter((one): one is string => Boolean(one));
|
|
746
771
|
|
|
747
772
|
const submit = () => {
|
|
748
773
|
if (!ready || !provider) return;
|
|
@@ -760,11 +785,24 @@ function BotPage({
|
|
|
760
785
|
});
|
|
761
786
|
};
|
|
762
787
|
|
|
788
|
+
// The rail draws the Create: told when what it needs changes, never every render
|
|
789
|
+
const submitNow = useRef(submit);
|
|
790
|
+
submitNow.current = submit;
|
|
791
|
+
const lacking = missing.join(",");
|
|
792
|
+
useEffect(() => {
|
|
793
|
+
onDraft?.({
|
|
794
|
+
missing: lacking ? lacking.split(",") : [],
|
|
795
|
+
creating,
|
|
796
|
+
submit: () => submitNow.current(),
|
|
797
|
+
});
|
|
798
|
+
}, [onDraft, lacking, creating]);
|
|
799
|
+
useEffect(() => () => onDraft?.(null), [onDraft]);
|
|
800
|
+
|
|
763
801
|
const confirmRemove = async () => {
|
|
764
802
|
if (!bot) return;
|
|
765
803
|
const confirmed = await notify.confirm({
|
|
766
804
|
title: `Delete ${bot.name}?`,
|
|
767
|
-
description: "
|
|
805
|
+
description: "Thursday can no longer hand work to it.",
|
|
768
806
|
okText: "Delete",
|
|
769
807
|
destructive: true,
|
|
770
808
|
});
|
|
@@ -785,13 +823,19 @@ function BotPage({
|
|
|
785
823
|
off
|
|
786
824
|
</span>
|
|
787
825
|
)}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
826
|
+
{/* what on means, said where it is switched: the word "on" alone does not */}
|
|
827
|
+
<Tooltip>
|
|
828
|
+
<TooltipTrigger render={<span className="mr-1 flex shrink-0" />}>
|
|
829
|
+
<Switch
|
|
830
|
+
checked={!bot.disabled}
|
|
831
|
+
onCheckedChange={(on) => commit({ disabled: !on })}
|
|
832
|
+
aria-label={`${bot.name} on or off`}
|
|
833
|
+
/>
|
|
834
|
+
</TooltipTrigger>
|
|
835
|
+
<TooltipContent side="bottom">
|
|
836
|
+
Thursday can hand it work
|
|
837
|
+
</TooltipContent>
|
|
838
|
+
</Tooltip>
|
|
795
839
|
<Button
|
|
796
840
|
size="icon-sm"
|
|
797
841
|
variant="ghost"
|
|
@@ -951,17 +995,6 @@ function BotPage({
|
|
|
951
995
|
|
|
952
996
|
{bot && <Recent jobs={jobs} />}
|
|
953
997
|
|
|
954
|
-
{!bot && (
|
|
955
|
-
<div className="flex items-center justify-end gap-2 pt-1">
|
|
956
|
-
<Button variant="ghost" onClick={onCancel}>
|
|
957
|
-
Cancel
|
|
958
|
-
</Button>
|
|
959
|
-
<Button loading={creating} disabled={!ready} onClick={submit}>
|
|
960
|
-
Create
|
|
961
|
-
</Button>
|
|
962
|
-
</div>
|
|
963
|
-
)}
|
|
964
|
-
|
|
965
998
|
{createError && (
|
|
966
999
|
<p className="font-mono text-xs text-destructive">{createError}</p>
|
|
967
1000
|
)}
|
|
@@ -1123,7 +1156,14 @@ const underItsRow = (content: string) =>
|
|
|
1123
1156
|
* any bot's: whether bots keep their own memory, and whether their work goes on once
|
|
1124
1157
|
* every tab is closed.
|
|
1125
1158
|
*/
|
|
1126
|
-
function BotRail({
|
|
1159
|
+
function BotRail({
|
|
1160
|
+
bot,
|
|
1161
|
+
draft = null,
|
|
1162
|
+
}: {
|
|
1163
|
+
bot: Bot | null;
|
|
1164
|
+
/** A new bot on the page: its Create stands at the end of the rail. */
|
|
1165
|
+
draft?: DraftCreate | null;
|
|
1166
|
+
}) {
|
|
1127
1167
|
const { data: memoryOn, mutate } = useServerRoute<boolean>(
|
|
1128
1168
|
queryKey.botMemory,
|
|
1129
1169
|
);
|
|
@@ -1151,9 +1191,13 @@ function BotRail({ bot }: { bot: Bot | null }) {
|
|
|
1151
1191
|
<span className="px-1.5 opacity-50">·</span>
|
|
1152
1192
|
since {whenOf(bot.createdAt)}
|
|
1153
1193
|
</span>
|
|
1154
|
-
) : (
|
|
1155
|
-
|
|
1156
|
-
|
|
1194
|
+
) : draft?.missing.length ? (
|
|
1195
|
+
`Needs ${
|
|
1196
|
+
draft.missing.length > 1
|
|
1197
|
+
? `${draft.missing.slice(0, -1).join(", ")} and ${draft.missing.at(-1)}`
|
|
1198
|
+
: draft.missing[0]
|
|
1199
|
+
}`
|
|
1200
|
+
) : null}
|
|
1157
1201
|
</SettingRailNote>
|
|
1158
1202
|
<KeepWorkingSwitch />
|
|
1159
1203
|
<span className="h-4 w-px shrink-0 bg-border" />
|
|
@@ -1169,6 +1213,16 @@ function BotRail({ bot }: { bot: Bot | null }) {
|
|
|
1169
1213
|
}}
|
|
1170
1214
|
aria-label="Bots keep their own memory"
|
|
1171
1215
|
/>
|
|
1216
|
+
{draft && (
|
|
1217
|
+
<Button
|
|
1218
|
+
size="sm"
|
|
1219
|
+
loading={draft.creating}
|
|
1220
|
+
disabled={draft.missing.length > 0}
|
|
1221
|
+
onClick={draft.submit}
|
|
1222
|
+
>
|
|
1223
|
+
Create bot
|
|
1224
|
+
</Button>
|
|
1225
|
+
)}
|
|
1172
1226
|
</>
|
|
1173
1227
|
);
|
|
1174
1228
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The crew's body language: what a face does when something happens to the bot behind it.
|
|
5
|
+
*
|
|
6
|
+
* At rest every face breathes and nothing else moves. A gesture then plays ONCE, on the ONE face
|
|
7
|
+
* the event belongs to, over the breath — so the pill says what happened where it happened,
|
|
8
|
+
* instead of leaving it to the bubble that only has room for one thing at a time.
|
|
9
|
+
*
|
|
10
|
+
* A jump reads as weight only when the body and the shape run on different curves, so a face is a
|
|
11
|
+
* stack of layers (room-pill `Crew`) and a gesture names which of them it takes: `body` moves it
|
|
12
|
+
* through the air, `shape` presses and flattens it, `turn` rotates it. A layer a gesture does not
|
|
13
|
+
* name keeps doing what it was: the shape layer goes back to breathing.
|
|
14
|
+
*
|
|
15
|
+
* The keyframes are in `app/globals.css`; every duration here is the length that file cuts them to.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** What a face can be doing. `wave` is the whole row arriving; every other one happens to one bot. */
|
|
19
|
+
export type Gesture =
|
|
20
|
+
| "wave"
|
|
21
|
+
| "done"
|
|
22
|
+
| "ask"
|
|
23
|
+
| "took"
|
|
24
|
+
| "give"
|
|
25
|
+
| "take"
|
|
26
|
+
| "stop"
|
|
27
|
+
| "read";
|
|
28
|
+
|
|
29
|
+
/** One bot, and what its face should do. */
|
|
30
|
+
export type BotGesture = { bot: string; gesture: Gesture };
|
|
31
|
+
|
|
32
|
+
/** How long each runs, ms. */
|
|
33
|
+
const GESTURE_MS: Record<Gesture, number> = {
|
|
34
|
+
wave: 740,
|
|
35
|
+
done: 740,
|
|
36
|
+
ask: 820,
|
|
37
|
+
took: 740,
|
|
38
|
+
give: 900,
|
|
39
|
+
take: 520,
|
|
40
|
+
stop: 1150,
|
|
41
|
+
read: 560,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** The wave walks along the row: a face's own start is its place times this. */
|
|
45
|
+
const WAVE_STEP_MS = 70;
|
|
46
|
+
|
|
47
|
+
/** Which layer takes which animation. */
|
|
48
|
+
const LAYERS: Record<
|
|
49
|
+
Gesture,
|
|
50
|
+
{ body?: string; shape?: string; turn?: string }
|
|
51
|
+
> = {
|
|
52
|
+
wave: { body: "animate-crew-hop", shape: "animate-crew-hop-shape" },
|
|
53
|
+
took: { body: "animate-crew-hop", shape: "animate-crew-hop-shape" },
|
|
54
|
+
done: {
|
|
55
|
+
body: "animate-crew-hop",
|
|
56
|
+
shape: "animate-crew-hop-shape",
|
|
57
|
+
turn: "animate-crew-spin",
|
|
58
|
+
},
|
|
59
|
+
ask: { body: "animate-crew-ask", turn: "animate-crew-ask-turn" },
|
|
60
|
+
give: { turn: "animate-crew-give" },
|
|
61
|
+
take: { body: "animate-crew-take", shape: "animate-crew-take-shape" },
|
|
62
|
+
stop: { body: "animate-crew-sink", shape: "animate-crew-sink-shape" },
|
|
63
|
+
read: { body: "animate-crew-nod", shape: "animate-crew-nod-shape" },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** A gesture on a face, and the token that makes React start it over rather than let it run on. */
|
|
67
|
+
export type Playing = { gesture: Gesture; id: number };
|
|
68
|
+
|
|
69
|
+
/** What each face is in the middle of, by bot name. */
|
|
70
|
+
export type CrewPlaying = Map<string, Playing>;
|
|
71
|
+
|
|
72
|
+
/** What each face's layers wear this render. */
|
|
73
|
+
export type CrewMotion = {
|
|
74
|
+
/** Changes with every gesture, so the layers remount and the animation restarts. */
|
|
75
|
+
key: number;
|
|
76
|
+
body: string;
|
|
77
|
+
shape: string;
|
|
78
|
+
turn: string;
|
|
79
|
+
/** Only the wave staggers; everything else starts at once on the face it belongs to. */
|
|
80
|
+
delayMs: number;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/** The resting state, which a gesture borrows a layer from and gives back. */
|
|
84
|
+
const RESTING: CrewMotion = {
|
|
85
|
+
key: 0,
|
|
86
|
+
body: "",
|
|
87
|
+
shape: "animate-crew-breath",
|
|
88
|
+
turn: "",
|
|
89
|
+
delayMs: 0,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* What one face is doing. `at` is its place in the row, which only the wave reads; a face's breath
|
|
94
|
+
* takes its phase from the same number, so a row at rest ripples instead of pulsing as one object.
|
|
95
|
+
*/
|
|
96
|
+
export function motionOf(playing: Playing | undefined, at: number): CrewMotion {
|
|
97
|
+
if (!playing) return { ...RESTING, delayMs: at * -370 };
|
|
98
|
+
const layers = LAYERS[playing.gesture];
|
|
99
|
+
return {
|
|
100
|
+
key: playing.id,
|
|
101
|
+
body: layers.body ?? "",
|
|
102
|
+
shape: layers.shape ?? "animate-crew-breath",
|
|
103
|
+
turn: layers.turn ?? "",
|
|
104
|
+
delayMs: playing.gesture === "wave" ? at * WAVE_STEP_MS : 0,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The gestures playing right now, and how to start more.
|
|
110
|
+
*
|
|
111
|
+
* One at a time per bot: a second event on the same face replaces the first rather than queueing,
|
|
112
|
+
* because two gestures are two layers fighting over the same transform, and the newer thing is the
|
|
113
|
+
* true one. A gesture clears itself when it is over, which is what puts the face back to resting.
|
|
114
|
+
*/
|
|
115
|
+
export function useCrewGestures(): [
|
|
116
|
+
CrewPlaying,
|
|
117
|
+
(played: BotGesture[]) => void,
|
|
118
|
+
] {
|
|
119
|
+
const [playing, setPlaying] = useState<CrewPlaying>(new Map());
|
|
120
|
+
const timers = useRef(new Map<string, ReturnType<typeof setTimeout>>());
|
|
121
|
+
const token = useRef(0);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
const held = timers.current;
|
|
125
|
+
return () => {
|
|
126
|
+
for (const timer of held.values()) clearTimeout(timer);
|
|
127
|
+
held.clear();
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
const play = useCallback((played: BotGesture[]) => {
|
|
132
|
+
if (!played.length) return;
|
|
133
|
+
setPlaying((was) => {
|
|
134
|
+
const now = new Map(was);
|
|
135
|
+
for (const { bot, gesture } of played) {
|
|
136
|
+
token.current += 1;
|
|
137
|
+
now.set(bot, { gesture, id: token.current });
|
|
138
|
+
const running = timers.current.get(bot);
|
|
139
|
+
if (running) clearTimeout(running);
|
|
140
|
+
timers.current.set(
|
|
141
|
+
bot,
|
|
142
|
+
setTimeout(
|
|
143
|
+
() => {
|
|
144
|
+
timers.current.delete(bot);
|
|
145
|
+
setPlaying((held) => {
|
|
146
|
+
const next = new Map(held);
|
|
147
|
+
next.delete(bot);
|
|
148
|
+
return next;
|
|
149
|
+
});
|
|
150
|
+
// The wave's last face starts a row-length after the first one does.
|
|
151
|
+
},
|
|
152
|
+
GESTURE_MS[gesture] + (gesture === "wave" ? WAVE_STEP_MS * 20 : 0),
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return now;
|
|
157
|
+
});
|
|
158
|
+
}, []);
|
|
159
|
+
|
|
160
|
+
return [playing, play];
|
|
161
|
+
}
|
|
@@ -11,8 +11,7 @@ import {
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* A mark's colours in one line under the face they paint: the theme dot, the
|
|
14
|
-
* colours, then the paints.
|
|
15
|
-
* they differ only in what the dot means.
|
|
14
|
+
* colours, then the paints. On a narrow bot page the dots shrink rather than wrap.
|
|
16
15
|
*/
|
|
17
16
|
export function MarkPalette({
|
|
18
17
|
color,
|
|
@@ -31,7 +30,8 @@ export function MarkPalette({
|
|
|
31
30
|
onPaint?: (paint: MarkPaint) => void;
|
|
32
31
|
}) {
|
|
33
32
|
return (
|
|
34
|
-
|
|
33
|
+
// As wide as the page, not as its dots: they shrink to it rather than push past it
|
|
34
|
+
<div className="flex w-full items-center justify-center gap-1.5 px-2">
|
|
35
35
|
<Swatch color={null} picked={themePicked} onPick={onTheme} />
|
|
36
36
|
{MARK_PALETTE.map((each) => (
|
|
37
37
|
<Swatch
|
|
@@ -41,7 +41,6 @@ import {
|
|
|
41
41
|
type BotRef,
|
|
42
42
|
type Chatter,
|
|
43
43
|
heardBy,
|
|
44
|
-
rosterOf,
|
|
45
44
|
type ThreadItem,
|
|
46
45
|
type ThreadView,
|
|
47
46
|
type ThreadViewStatus,
|
|
@@ -100,12 +99,6 @@ export function ThreadHeader({
|
|
|
100
99
|
/>
|
|
101
100
|
<span className="min-w-0 flex-1 truncate text-[13px] font-medium">
|
|
102
101
|
{thread.label}
|
|
103
|
-
<span
|
|
104
|
-
title={thread.id}
|
|
105
|
-
className="ml-1.5 font-mono text-[10px] font-normal text-muted-foreground/60"
|
|
106
|
-
>
|
|
107
|
-
{thread.id.slice(0, 8)}
|
|
108
|
-
</span>
|
|
109
102
|
</span>
|
|
110
103
|
<ThreadFacts thread={thread} />
|
|
111
104
|
<FoldButton onClick={onClose} />
|
|
@@ -273,7 +266,7 @@ export function Conversation({
|
|
|
273
266
|
}) {
|
|
274
267
|
const scroller = useRef<HTMLDivElement>(null);
|
|
275
268
|
const following = useRef(true);
|
|
276
|
-
const roster =
|
|
269
|
+
const roster = thread.roster;
|
|
277
270
|
const side =
|
|
278
271
|
onTab && tab !== thread.bot.name && roster.some((bot) => bot.name === tab)
|
|
279
272
|
? tab
|
|
@@ -295,6 +288,18 @@ export function Conversation({
|
|
|
295
288
|
if (box && following.current) box.scrollTop = box.scrollHeight;
|
|
296
289
|
}, [thread.lines, thread.status, side]);
|
|
297
290
|
|
|
291
|
+
// A page or a picture under a message is drawn a moment after the words and grows the
|
|
292
|
+
// turn it is under: without this the last tiles end up behind the composer
|
|
293
|
+
useEffect(() => {
|
|
294
|
+
const box = scroller.current;
|
|
295
|
+
if (!box) return;
|
|
296
|
+
const watch = new ResizeObserver(() => {
|
|
297
|
+
if (following.current) box.scrollTop = box.scrollHeight;
|
|
298
|
+
});
|
|
299
|
+
for (const child of Array.from(box.children)) watch.observe(child);
|
|
300
|
+
return () => watch.disconnect();
|
|
301
|
+
}, [items.length, thread.lines, side]);
|
|
302
|
+
|
|
298
303
|
return (
|
|
299
304
|
// One FileViewer per conversation, not per bubble.
|
|
300
305
|
<FileViewer>
|
|
@@ -28,15 +28,19 @@ import { RoutineMark } from "@/features/routine/components/routine-mark";
|
|
|
28
28
|
import { type DateLike, shortAgo, toDate } from "@/lib/date-like";
|
|
29
29
|
import { type ServerPages } from "@/lib/protocol/use-server-pages";
|
|
30
30
|
import { cn, plainText, WAITING_INK } from "@/lib/utils";
|
|
31
|
-
import { lastSaid,
|
|
31
|
+
import { lastSaid, type ThreadView } from "../thread.store";
|
|
32
32
|
import { FoldButton, TAB } from "./room-conversation";
|
|
33
33
|
|
|
34
34
|
/** The room open on its lists: what is happening now, and the history behind it. Split out of bot-room by subject; see it for the room as a whole. */
|
|
35
35
|
|
|
36
36
|
export const needsYou = needsThreadReply;
|
|
37
37
|
|
|
38
|
-
/**
|
|
39
|
-
|
|
38
|
+
/**
|
|
39
|
+
* An ending nobody has opened. It needs the user too, to read rather than to
|
|
40
|
+
* answer. Takes the two fields it reads, as `needsThreadReply` does, so a
|
|
41
|
+
* stored row answers it as well as a drawn one.
|
|
42
|
+
*/
|
|
43
|
+
export const isUnread = (thread: { status: string; seen: boolean }) =>
|
|
40
44
|
thread.status === "done" && !thread.seen;
|
|
41
45
|
|
|
42
46
|
/** The room's two lists. */
|
|
@@ -359,7 +363,7 @@ export function ThreadRow({
|
|
|
359
363
|
outline={thread.bot.icon?.outline}
|
|
360
364
|
paint={thread.bot.icon?.paint}
|
|
361
365
|
state={thread.status === "working" ? "thinking" : "idle"}
|
|
362
|
-
notify={attention}
|
|
366
|
+
notify={attention || isUnread(thread)}
|
|
363
367
|
crossed={thread.status === "cancelled"}
|
|
364
368
|
/>
|
|
365
369
|
</span>
|
|
@@ -398,7 +402,7 @@ export function ThreadRow({
|
|
|
398
402
|
<RoutineMark className="size-3 text-muted-foreground/80" />
|
|
399
403
|
</span>
|
|
400
404
|
)}
|
|
401
|
-
<BotRoster bots={
|
|
405
|
+
<BotRoster bots={thread.roster} />
|
|
402
406
|
<span className="flex-1" />
|
|
403
407
|
<span className="shrink-0 font-mono text-[11px] leading-4 text-muted-foreground/70 tabular-nums">
|
|
404
408
|
{shortAgo(thread.updatedAt)}
|