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
|
@@ -24,6 +24,12 @@ import {
|
|
|
24
24
|
} from "@/components/ui/tooltip";
|
|
25
25
|
import { type Bot, type BotIcon, isAppStop } from "@/features/bot/bot.schema";
|
|
26
26
|
import { BotMark } from "@/features/bot/components/bot-mark";
|
|
27
|
+
import {
|
|
28
|
+
type BotGesture,
|
|
29
|
+
type CrewMotion,
|
|
30
|
+
type CrewPlaying,
|
|
31
|
+
motionOf,
|
|
32
|
+
} from "@/features/bot/components/crew-motion";
|
|
27
33
|
import { ThursdayMark } from "@/features/thursday/components/thursday-mark";
|
|
28
34
|
import { cn, plainText, WAITING_INK } from "@/lib/utils";
|
|
29
35
|
import { MARK_PALETTE, MARK_SHAPES } from "../mark.const";
|
|
@@ -31,7 +37,6 @@ import {
|
|
|
31
37
|
type BotRef,
|
|
32
38
|
type Chatter,
|
|
33
39
|
latestPerBot,
|
|
34
|
-
rosterOf,
|
|
35
40
|
type ThreadView,
|
|
36
41
|
type ThreadViewStatus,
|
|
37
42
|
useWriteLineUp,
|
|
@@ -39,12 +44,12 @@ import {
|
|
|
39
44
|
} from "../thread.store";
|
|
40
45
|
|
|
41
46
|
import { leadOf, stepOf, THURSDAY } from "./room-conversation";
|
|
42
|
-
import { ThreadRow } from "./room-list";
|
|
47
|
+
import { isUnread, ThreadRow } from "./room-list";
|
|
43
48
|
|
|
44
49
|
/** The room folded: the pill at the foot of the call screen, the faces on it, and what passed between two parties riding above one for a moment. Split out of bot-room by subject; see it for the room as a whole. */
|
|
45
50
|
|
|
46
|
-
/** Faces the row draws before the
|
|
47
|
-
const CREW_MAX =
|
|
51
|
+
/** Faces the row draws before it starts hiding them (the user's pick). */
|
|
52
|
+
const CREW_MAX = 14;
|
|
48
53
|
|
|
49
54
|
/** How long a hand-off stays above a face, ms. */
|
|
50
55
|
const HANDOFF_MS = 3400;
|
|
@@ -58,8 +63,10 @@ type CrewFace = {
|
|
|
58
63
|
icon?: BotIcon | null;
|
|
59
64
|
/** Working or waiting: both are awake. */
|
|
60
65
|
awake: boolean;
|
|
61
|
-
/** Waiting on an answer; carries the dot. */
|
|
66
|
+
/** Waiting on an answer; carries the amber dot. */
|
|
62
67
|
waiting: boolean;
|
|
68
|
+
/** A result of its nobody has opened; carries the blue one. */
|
|
69
|
+
unread: boolean;
|
|
63
70
|
/** The step it is on, in the model's own words. Null when it is not working. */
|
|
64
71
|
word: string | null;
|
|
65
72
|
/** A stand-in for an install with no bots; dimmed with the rest. */
|
|
@@ -174,6 +181,10 @@ export function participantStates(threads: ThreadView[]): Map<string, string> {
|
|
|
174
181
|
* stand for a sync: a failure, then a question, then an ending or a stop, then
|
|
175
182
|
* messages, then a job arriving, an answer, a bot finishing its part or going
|
|
176
183
|
* back to work.
|
|
184
|
+
*
|
|
185
|
+
* The same pass says what each face should do about it (`crew-motion`). One sync
|
|
186
|
+
* shows one bubble but every gesture it turned up, because a gesture sits on the
|
|
187
|
+
* face it belongs to and two of them never cover each other.
|
|
177
188
|
*/
|
|
178
189
|
export function happenedIn(
|
|
179
190
|
thread: ThreadView,
|
|
@@ -181,15 +192,38 @@ export function happenedIn(
|
|
|
181
192
|
had: Set<string>,
|
|
182
193
|
stood: Map<string, string>,
|
|
183
194
|
stands: Map<string, string>,
|
|
184
|
-
): Happening[] {
|
|
195
|
+
): { moments: Happening[]; gestures: BotGesture[] } {
|
|
196
|
+
const own = thread.bot;
|
|
197
|
+
const felt: BotGesture[] = [];
|
|
198
|
+
// A thread this sync is the first to see — just opened, or back in the inbox
|
|
199
|
+
// after dropping out of it — has no history here, so every line in it would
|
|
200
|
+
// read as having just happened. Being taken on is the news; nothing else is.
|
|
201
|
+
if (!was) {
|
|
202
|
+
return thread.status === "working"
|
|
203
|
+
? {
|
|
204
|
+
moments: [
|
|
205
|
+
{
|
|
206
|
+
rank: 1,
|
|
207
|
+
at: own.name,
|
|
208
|
+
from: THURSDAY,
|
|
209
|
+
to: [own],
|
|
210
|
+
text: `took on “${clipWord(thread.label)}”`,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
gestures: [{ bot: own.name, gesture: "took" }],
|
|
214
|
+
}
|
|
215
|
+
: { moments: [], gestures: [] };
|
|
216
|
+
}
|
|
217
|
+
|
|
185
218
|
const out: Happening[] = [];
|
|
186
219
|
const fresh = thread.lines.filter((line) => !had.has(line.id));
|
|
187
|
-
const own = thread.bot;
|
|
188
220
|
|
|
189
221
|
// Bot to bot. A giver handing work to several at once is one bubble naming them all.
|
|
190
222
|
const rounds = new Map<string, Chatter[]>();
|
|
191
223
|
for (const line of fresh) {
|
|
192
224
|
if (line.kind === "user") {
|
|
225
|
+
if (line.steppedIn) felt.push({ bot: line.bot.name, gesture: "read" });
|
|
226
|
+
else felt.push({ bot: line.bot.name, gesture: "took" });
|
|
193
227
|
out.push(
|
|
194
228
|
line.steppedIn
|
|
195
229
|
? // the words were up while they waited (waitingStepIn); read, the bot says so
|
|
@@ -209,6 +243,7 @@ export function happenedIn(
|
|
|
209
243
|
},
|
|
210
244
|
);
|
|
211
245
|
} else if (line.kind === "stop") {
|
|
246
|
+
felt.push({ bot: line.bot.name, gesture: "stop" });
|
|
212
247
|
out.push({
|
|
213
248
|
rank: 3,
|
|
214
249
|
at: line.bot.name,
|
|
@@ -218,6 +253,7 @@ export function happenedIn(
|
|
|
218
253
|
text: leadOf(line.text),
|
|
219
254
|
});
|
|
220
255
|
} else if (line.kind === "ask" && line.to?.name === THURSDAY.name) {
|
|
256
|
+
if (line.question) felt.push({ bot: line.bot.name, gesture: "ask" });
|
|
221
257
|
out.push(
|
|
222
258
|
line.question
|
|
223
259
|
? {
|
|
@@ -245,6 +281,9 @@ export function happenedIn(
|
|
|
245
281
|
for (const line of round) {
|
|
246
282
|
if (line.to) reached.set(line.to.name, line.to);
|
|
247
283
|
}
|
|
284
|
+
felt.push({ bot: giver, gesture: "give" });
|
|
285
|
+
for (const bot of reached.values())
|
|
286
|
+
felt.push({ bot: bot.name, gesture: "take" });
|
|
248
287
|
out.push({
|
|
249
288
|
rank: 2,
|
|
250
289
|
at: giver,
|
|
@@ -258,7 +297,7 @@ export function happenedIn(
|
|
|
258
297
|
}
|
|
259
298
|
|
|
260
299
|
// Another bot done with its part and no last word; the thread's own ending is the job's.
|
|
261
|
-
for (const bot of
|
|
300
|
+
for (const bot of thread.roster) {
|
|
262
301
|
const key = `${thread.id}\n${bot.name}`;
|
|
263
302
|
if (
|
|
264
303
|
bot.name !== own.name &&
|
|
@@ -270,6 +309,7 @@ export function happenedIn(
|
|
|
270
309
|
(line.kind === "ask" || line.kind === "say"),
|
|
271
310
|
)
|
|
272
311
|
) {
|
|
312
|
+
felt.push({ bot: bot.name, gesture: "done" });
|
|
273
313
|
out.push({
|
|
274
314
|
rank: 1,
|
|
275
315
|
at: bot.name,
|
|
@@ -281,21 +321,10 @@ export function happenedIn(
|
|
|
281
321
|
}
|
|
282
322
|
}
|
|
283
323
|
|
|
284
|
-
if (
|
|
285
|
-
if (thread.status === "working") {
|
|
286
|
-
out.push({
|
|
287
|
-
rank: 1,
|
|
288
|
-
at: own.name,
|
|
289
|
-
from: THURSDAY,
|
|
290
|
-
to: [own],
|
|
291
|
-
text: `took on “${clipWord(thread.label)}”`,
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
return out;
|
|
295
|
-
}
|
|
296
|
-
if (was === thread.status) return out;
|
|
324
|
+
if (was === thread.status) return { moments: out, gestures: felt };
|
|
297
325
|
const label = clipWord(thread.label);
|
|
298
326
|
if (thread.status === "cancelled") {
|
|
327
|
+
felt.push({ bot: own.name, gesture: "stop" });
|
|
299
328
|
out.push({
|
|
300
329
|
rank: 3,
|
|
301
330
|
at: own.name,
|
|
@@ -306,10 +335,13 @@ export function happenedIn(
|
|
|
306
335
|
});
|
|
307
336
|
} else if (thread.status === "done") {
|
|
308
337
|
// A job's own ending is the card in the screen's left corner (artifact-view); the pill
|
|
309
|
-
// keeps its bubbles for what is still going on
|
|
338
|
+
// keeps its bubbles for what is still going on. The face still says it happened — a
|
|
339
|
+
// somersault is on the bot, not over it, so it never stands where the card's notice would.
|
|
340
|
+
felt.push({ bot: own.name, gesture: "done" });
|
|
310
341
|
} else if (thread.status === "working") {
|
|
311
342
|
// Words from the user already have their bubble.
|
|
312
343
|
if (!fresh.some((line) => line.kind === "user")) {
|
|
344
|
+
felt.push({ bot: own.name, gesture: "took" });
|
|
313
345
|
out.push({
|
|
314
346
|
rank: 1,
|
|
315
347
|
at: own.name,
|
|
@@ -324,6 +356,7 @@ export function happenedIn(
|
|
|
324
356
|
!out.some((one) => one.sign === "question" || one.sign === "stopped")
|
|
325
357
|
) {
|
|
326
358
|
// A stop with no stop line of its own: the turn limit, or a room gone idle
|
|
359
|
+
felt.push({ bot: own.name, gesture: "stop" });
|
|
327
360
|
out.push({
|
|
328
361
|
rank: 3,
|
|
329
362
|
at: own.name,
|
|
@@ -333,7 +366,7 @@ export function happenedIn(
|
|
|
333
366
|
text: "paused",
|
|
334
367
|
});
|
|
335
368
|
}
|
|
336
|
-
return out;
|
|
369
|
+
return { moments: out, gestures: felt };
|
|
337
370
|
}
|
|
338
371
|
|
|
339
372
|
/** The step a bot is on, as the model labelled it. */
|
|
@@ -346,7 +379,7 @@ function wordOf(line: Chatter | null): string | null {
|
|
|
346
379
|
/**
|
|
347
380
|
* Who is in the row, in the order it is drawn.
|
|
348
381
|
*
|
|
349
|
-
* Anyone moving sorts to the front, so the
|
|
382
|
+
* Anyone moving sorts to the front, so the mark at the tail only ever hides
|
|
350
383
|
* idle bots — a bot with something to say always has a face to say it from,
|
|
351
384
|
* which is what lets a hand-off point at one. A bot that spoke inside somebody
|
|
352
385
|
* else's job is in the room too, whether or not it owns a thread (latestPerBot).
|
|
@@ -355,6 +388,10 @@ export function crewOf(
|
|
|
355
388
|
bots: Bot[] | undefined,
|
|
356
389
|
threads: ThreadView[],
|
|
357
390
|
): { crew: CrewFace[]; more: number } {
|
|
391
|
+
// What is finished and unopened is the other thing a face can carry (the user's pick)
|
|
392
|
+
const unread = new Set(
|
|
393
|
+
threads.filter(isUnread).map((thread) => thread.bot.name),
|
|
394
|
+
);
|
|
358
395
|
const live = new Map<string, { waiting: boolean; word: string | null }>();
|
|
359
396
|
for (const entry of latestPerBot(threads)) {
|
|
360
397
|
const { thread, bot, line } = entry;
|
|
@@ -374,6 +411,7 @@ export function crewOf(
|
|
|
374
411
|
icon: bot.icon,
|
|
375
412
|
awake: live.has(bot.name),
|
|
376
413
|
waiting: live.get(bot.name)?.waiting ?? false,
|
|
414
|
+
unread: unread.has(bot.name),
|
|
377
415
|
word: live.get(bot.name)?.word ?? null,
|
|
378
416
|
});
|
|
379
417
|
}
|
|
@@ -386,6 +424,7 @@ export function crewOf(
|
|
|
386
424
|
icon: null,
|
|
387
425
|
awake: true,
|
|
388
426
|
waiting: doing.waiting,
|
|
427
|
+
unread: unread.has(name),
|
|
389
428
|
word: doing.word,
|
|
390
429
|
});
|
|
391
430
|
}
|
|
@@ -399,8 +438,9 @@ export function crewOf(
|
|
|
399
438
|
if (!named.has(ghost.name)) roster.push(ghost);
|
|
400
439
|
}
|
|
401
440
|
|
|
441
|
+
// Who needs the user first, then who is moving, then who left something to read
|
|
402
442
|
const rank = (face: CrewFace) =>
|
|
403
|
-
face.waiting ? 0 : face.awake ? 1 : face.standIn ?
|
|
443
|
+
face.waiting ? 0 : face.awake ? 1 : face.unread ? 2 : face.standIn ? 4 : 3;
|
|
404
444
|
const sorted = roster
|
|
405
445
|
.map((face, at) => ({ face, at }))
|
|
406
446
|
.sort((a, b) => rank(a.face) - rank(b.face) || a.at - b.at)
|
|
@@ -464,6 +504,7 @@ export function Chip({
|
|
|
464
504
|
count,
|
|
465
505
|
busy,
|
|
466
506
|
pending,
|
|
507
|
+
playing,
|
|
467
508
|
onPick,
|
|
468
509
|
onOpen,
|
|
469
510
|
}: {
|
|
@@ -476,6 +517,8 @@ export function Chip({
|
|
|
476
517
|
count: number;
|
|
477
518
|
busy: number;
|
|
478
519
|
pending: number;
|
|
520
|
+
/** The gesture each face is in the middle of, by bot name (crew-motion). */
|
|
521
|
+
playing: CrewPlaying;
|
|
479
522
|
onPick: (id: string) => void;
|
|
480
523
|
onOpen: () => void;
|
|
481
524
|
}) {
|
|
@@ -540,6 +583,7 @@ export function Chip({
|
|
|
540
583
|
bubble={grown ? null : bubble}
|
|
541
584
|
label={count ? `Threads (${count})` : "Bots"}
|
|
542
585
|
onClick={onOpen}
|
|
586
|
+
playing={playing}
|
|
543
587
|
side={<RoomState busy={busy} pending={pending} grown={grown} />}
|
|
544
588
|
onWrite={writeLine.open}
|
|
545
589
|
/>
|
|
@@ -560,6 +604,7 @@ export function CrewRow({
|
|
|
560
604
|
crew,
|
|
561
605
|
more,
|
|
562
606
|
bubble,
|
|
607
|
+
playing,
|
|
563
608
|
side,
|
|
564
609
|
label,
|
|
565
610
|
onClick,
|
|
@@ -568,6 +613,8 @@ export function CrewRow({
|
|
|
568
613
|
crew: CrewFace[];
|
|
569
614
|
more: number;
|
|
570
615
|
bubble: Handoff | null;
|
|
616
|
+
/** The gesture each face is in the middle of, by bot name (crew-motion). */
|
|
617
|
+
playing: CrewPlaying;
|
|
571
618
|
/** The right side: the room's state, or what just happened. */
|
|
572
619
|
side: ReactNode;
|
|
573
620
|
label: string;
|
|
@@ -607,7 +654,7 @@ export function CrewRow({
|
|
|
607
654
|
aria-label={label}
|
|
608
655
|
className="flex min-w-0 flex-1 items-center gap-2 rounded-full text-left outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
|
|
609
656
|
>
|
|
610
|
-
<Crew crew={crew} more={more} bubble={bubble} />
|
|
657
|
+
<Crew crew={crew} more={more} bubble={bubble} playing={playing} />
|
|
611
658
|
{side}
|
|
612
659
|
</button>
|
|
613
660
|
</div>
|
|
@@ -659,6 +706,7 @@ const GHOSTS: CrewFace[] = ["alto", "brio", "cinder", "delta"].map(
|
|
|
659
706
|
},
|
|
660
707
|
awake: false,
|
|
661
708
|
waiting: false,
|
|
709
|
+
unread: false,
|
|
662
710
|
word: null,
|
|
663
711
|
standIn: true,
|
|
664
712
|
}),
|
|
@@ -677,21 +725,26 @@ const FLOOR = 3;
|
|
|
677
725
|
*
|
|
678
726
|
* A face that is moving is awake: lifted and swollen a little. That layer alone
|
|
679
727
|
* survives every collision — three bots at once are three awake faces, with no
|
|
680
|
-
* order to decide
|
|
728
|
+
* order to decide, and it sits outside the gesture layers so a bot at work is
|
|
729
|
+
* still lifted while it jumps.
|
|
730
|
+
*
|
|
731
|
+
* Under that, a face is three layers and a mark (`crew-motion`): the body through
|
|
732
|
+
* the air, the shape pressing and flattening, the turn. At rest the shape layer
|
|
733
|
+
* breathes. They are keyed on the gesture, so a second event on one face starts
|
|
734
|
+
* over rather than landing mid-way through the first.
|
|
681
735
|
*/
|
|
682
736
|
function Crew({
|
|
683
737
|
crew,
|
|
684
738
|
more,
|
|
685
739
|
bubble,
|
|
740
|
+
playing,
|
|
686
741
|
}: {
|
|
687
742
|
crew: CrewFace[];
|
|
688
743
|
more: number;
|
|
689
744
|
/** The hand-off up, drawn over the face it points at. */
|
|
690
745
|
bubble: Handoff | null;
|
|
746
|
+
playing: CrewPlaying;
|
|
691
747
|
}) {
|
|
692
|
-
// While anyone is moving or waiting, the rest step back so it reads at a glance who is
|
|
693
|
-
const lit = (face: CrewFace) => face.awake || face.waiting || face.word;
|
|
694
|
-
const astir = crew.some(lit);
|
|
695
748
|
return (
|
|
696
749
|
<span className="flex min-w-0 shrink items-center">
|
|
697
750
|
{crew.map((face, index) => {
|
|
@@ -702,8 +755,7 @@ function Crew({
|
|
|
702
755
|
// these are not circles. Earlier faces sit on top, so the dot on a
|
|
703
756
|
// waiting face is never covered by its neighbour.
|
|
704
757
|
className={cn(
|
|
705
|
-
"relative shrink-0 transition-[margin
|
|
706
|
-
astir && !lit(face) && "opacity-40",
|
|
758
|
+
"relative shrink-0 transition-[margin] duration-500 ease-out",
|
|
707
759
|
// A word to the left has already broken the shingle.
|
|
708
760
|
index > 0 && !crew[index - 1].word && "-ml-2",
|
|
709
761
|
face.standIn && "opacity-35",
|
|
@@ -717,7 +769,10 @@ function Crew({
|
|
|
717
769
|
face.awake && "-translate-y-0.5 scale-110",
|
|
718
770
|
)}
|
|
719
771
|
>
|
|
720
|
-
<
|
|
772
|
+
<CrewBody
|
|
773
|
+
face={face}
|
|
774
|
+
motion={motionOf(playing.get(face.name), index)}
|
|
775
|
+
/>
|
|
721
776
|
</span>
|
|
722
777
|
{bubble?.at === face.name && <HandoffBubble handoff={bubble} />}
|
|
723
778
|
</span>
|
|
@@ -736,22 +791,57 @@ function Crew({
|
|
|
736
791
|
);
|
|
737
792
|
})}
|
|
738
793
|
{more > 0 && (
|
|
739
|
-
// Past CREW_MAX the row stops growing. Only idle bots are ever behind it
|
|
740
|
-
// anyone moving sorted to the front
|
|
794
|
+
// Past CREW_MAX the row stops growing. Only idle bots are ever behind it —
|
|
795
|
+
// anyone moving sorted to the front — so the tail says there are more and not
|
|
796
|
+
// how many (the user's pick): a count nobody can act on is a number to read.
|
|
797
|
+
// Brand, but tinted rather than filled: filled brand is what waits on the user,
|
|
798
|
+
// and nothing here does.
|
|
741
799
|
<span
|
|
742
|
-
className=
|
|
743
|
-
"grid size-7 shrink-0 place-items-center rounded-[9px] bg-muted font-mono text-[10px] text-muted-foreground ring-1 ring-border/50",
|
|
744
|
-
!crew.at(-1)?.word && "-ml-2",
|
|
745
|
-
)}
|
|
800
|
+
className="ml-2 flex h-[18px] shrink-0 items-center rounded-full bg-brand/10 px-2 font-mono text-[10.5px] leading-none font-medium text-brand"
|
|
746
801
|
title={`${more} more`}
|
|
747
802
|
>
|
|
748
|
-
+
|
|
803
|
+
+
|
|
749
804
|
</span>
|
|
750
805
|
)}
|
|
751
806
|
</span>
|
|
752
807
|
);
|
|
753
808
|
}
|
|
754
809
|
|
|
810
|
+
/**
|
|
811
|
+
* A face's moving parts: the body, the shape and the turn, outermost first.
|
|
812
|
+
*
|
|
813
|
+
* Each layer animates one thing, because one element can only animate `transform`
|
|
814
|
+
* once and a jump needs its height and its squash on different curves. `data-crew-motion`
|
|
815
|
+
* is what a machine asked to hold still switches off (app/globals.css).
|
|
816
|
+
*/
|
|
817
|
+
function CrewBody({ face, motion }: { face: CrewFace; motion: CrewMotion }) {
|
|
818
|
+
const delay = motion.delayMs
|
|
819
|
+
? { animationDelay: `${motion.delayMs}ms` }
|
|
820
|
+
: undefined;
|
|
821
|
+
return (
|
|
822
|
+
<span
|
|
823
|
+
key={motion.key}
|
|
824
|
+
data-crew-motion
|
|
825
|
+
className={cn("flex", motion.body)}
|
|
826
|
+
style={delay}
|
|
827
|
+
>
|
|
828
|
+
<span
|
|
829
|
+
data-crew-motion
|
|
830
|
+
className={cn("flex origin-bottom", motion.shape)}
|
|
831
|
+
style={delay}
|
|
832
|
+
>
|
|
833
|
+
<span
|
|
834
|
+
data-crew-motion
|
|
835
|
+
className={cn("flex", motion.turn)}
|
|
836
|
+
style={delay}
|
|
837
|
+
>
|
|
838
|
+
<CrewMark face={face} />
|
|
839
|
+
</span>
|
|
840
|
+
</span>
|
|
841
|
+
</span>
|
|
842
|
+
);
|
|
843
|
+
}
|
|
844
|
+
|
|
755
845
|
/** One crew face. Who is moving reads from the lift its row gives it. */
|
|
756
846
|
function CrewMark({ face }: { face: CrewFace }) {
|
|
757
847
|
return (
|
|
@@ -762,7 +852,7 @@ function CrewMark({ face }: { face: CrewFace }) {
|
|
|
762
852
|
shape={face.icon?.shape}
|
|
763
853
|
outline={face.icon?.outline}
|
|
764
854
|
paint={face.icon?.paint}
|
|
765
|
-
notify={face.waiting}
|
|
855
|
+
notify={face.waiting || face.unread}
|
|
766
856
|
/>
|
|
767
857
|
);
|
|
768
858
|
}
|
|
@@ -8,8 +8,8 @@ import { useServerRoute } from "@/lib/protocol/use-server-route";
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* What the thread list owes the user, from the inbox key both readings share:
|
|
11
|
-
* jobs waiting on an answer and endings nobody has opened —
|
|
12
|
-
*
|
|
11
|
+
* jobs waiting on an answer and endings nobody has opened — the brand colour,
|
|
12
|
+
* because both want them. Unread endings remain in the inbox until opened, so every one
|
|
13
13
|
* counted has a row to open. A job never ends as a failure (a model that breaks
|
|
14
14
|
* pauses it as waiting), so nothing here is red.
|
|
15
15
|
*/
|
|
@@ -25,10 +25,10 @@ export function useThreadReport() {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function useThreadAlert(): SectionAlert {
|
|
28
|
-
return useThreadReport().owed > 0 ? "
|
|
28
|
+
return useThreadReport().owed > 0 ? "brand" : null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/** The nav counts what is owed. */
|
|
32
32
|
export function ThreadBadge() {
|
|
33
|
-
return <NavBadge tone="
|
|
33
|
+
return <NavBadge tone="brand" count={useThreadReport().owed} />;
|
|
34
34
|
}
|
|
@@ -47,8 +47,8 @@ import {
|
|
|
47
47
|
Conversation,
|
|
48
48
|
ThreadFacts,
|
|
49
49
|
} from "@/features/bot/components/room-conversation";
|
|
50
|
+
import { isUnread } from "@/features/bot/components/room-list";
|
|
50
51
|
import {
|
|
51
|
-
rosterOf,
|
|
52
52
|
screenActs,
|
|
53
53
|
threadFromRow,
|
|
54
54
|
useSeenOnDetail,
|
|
@@ -105,6 +105,13 @@ export function ThreadSetting() {
|
|
|
105
105
|
|
|
106
106
|
// A thread that leaves the list (deleted, cleared) closes the sheet.
|
|
107
107
|
const reading = threads.find((thread) => thread.id === openId);
|
|
108
|
+
// The list carries lines only for a thread that can still move (thread.query
|
|
109
|
+
// listThreadHistory), so the sheet reads the one it opens whole. The key sits
|
|
110
|
+
// under the list's, so the same signal keeps both live.
|
|
111
|
+
const { data: opened } = useServerRoute<Thread | null>(
|
|
112
|
+
openId ? queryKey.thread(openId) : null,
|
|
113
|
+
);
|
|
114
|
+
const whole = opened?.id === openId ? opened : undefined;
|
|
108
115
|
// Opening a thread is reading its ending; that is what clears its dot.
|
|
109
116
|
useSeenOnDetail(reading);
|
|
110
117
|
|
|
@@ -172,9 +179,12 @@ export function ThreadSetting() {
|
|
|
172
179
|
if (isLoading) return <SettingSkeleton rows={3} />;
|
|
173
180
|
if (error) return <SettingError message={error.message} />;
|
|
174
181
|
|
|
182
|
+
// Both halves of what the nav's one number counts (thread-badge), told apart
|
|
183
|
+
// here because the foot has the room the badge does not.
|
|
175
184
|
const waiting = threads.filter(
|
|
176
185
|
(thread) => thread.status === "waiting",
|
|
177
186
|
).length;
|
|
187
|
+
const unread = threads.filter(isUnread).length;
|
|
178
188
|
|
|
179
189
|
return (
|
|
180
190
|
<>
|
|
@@ -182,12 +192,22 @@ export function ThreadSetting() {
|
|
|
182
192
|
footer={
|
|
183
193
|
<>
|
|
184
194
|
<SettingRailNote>
|
|
185
|
-
{
|
|
195
|
+
{/* "loaded" is the paging word, not the reader's: more arrive as the list is scrolled */}
|
|
196
|
+
{threads.length} shown
|
|
186
197
|
{waiting > 0 && ` · ${waiting} waiting on you`}
|
|
198
|
+
{unread > 0 &&
|
|
199
|
+
` · ${unread} new result${unread === 1 ? "" : "s"}`}
|
|
187
200
|
</SettingRailNote>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
201
|
+
{/* only with something to clear: a page not read yet may hold some */}
|
|
202
|
+
{(hasMore ||
|
|
203
|
+
threads.some(
|
|
204
|
+
(thread) =>
|
|
205
|
+
thread.status === "done" || thread.status === "cancelled",
|
|
206
|
+
)) && (
|
|
207
|
+
<Button variant="outline" size="sm" onClick={confirmClear}>
|
|
208
|
+
Clear finished
|
|
209
|
+
</Button>
|
|
210
|
+
)}
|
|
191
211
|
</>
|
|
192
212
|
}
|
|
193
213
|
>
|
|
@@ -205,7 +225,7 @@ export function ThreadSetting() {
|
|
|
205
225
|
{shown.length === 0 ? (
|
|
206
226
|
<p className="p-4 text-sm leading-relaxed text-muted-foreground">
|
|
207
227
|
{needle
|
|
208
|
-
? "Nothing
|
|
228
|
+
? "Nothing here matches. Keep scrolling to search further back."
|
|
209
229
|
: "Nothing yet. When Thursday hands a job to a bot mid-call, it shows up here — while it runs, and after."}
|
|
210
230
|
</p>
|
|
211
231
|
) : (
|
|
@@ -234,6 +254,7 @@ export function ThreadSetting() {
|
|
|
234
254
|
|
|
235
255
|
<ThreadSheet
|
|
236
256
|
thread={reading}
|
|
257
|
+
whole={whole}
|
|
237
258
|
bots={bots}
|
|
238
259
|
onClose={() => setOpenId(null)}
|
|
239
260
|
onStop={(thread) => stop(thread.id)}
|
|
@@ -287,7 +308,7 @@ function Row({
|
|
|
287
308
|
seed={thread.bot}
|
|
288
309
|
{...markOf(thread.bot, bots)}
|
|
289
310
|
state={running ? "thinking" : "idle"}
|
|
290
|
-
notify={needsThreadReply(thread)}
|
|
311
|
+
notify={needsThreadReply(thread) || isUnread(thread)}
|
|
291
312
|
crossed={thread.status === "cancelled"}
|
|
292
313
|
className="shrink-0"
|
|
293
314
|
/>
|
|
@@ -302,7 +323,7 @@ function Row({
|
|
|
302
323
|
<RoutineMark className="size-3 text-muted-foreground/80" />
|
|
303
324
|
</span>
|
|
304
325
|
)}
|
|
305
|
-
<BotRoster bots={
|
|
326
|
+
<BotRoster bots={view.roster} />
|
|
306
327
|
{running && (
|
|
307
328
|
<Loader2 className="size-3 shrink-0 animate-spin text-muted-foreground" />
|
|
308
329
|
)}
|
|
@@ -404,13 +425,16 @@ function ThreadMenu({
|
|
|
404
425
|
*/
|
|
405
426
|
function ThreadSheet({
|
|
406
427
|
thread,
|
|
428
|
+
whole,
|
|
407
429
|
bots,
|
|
408
430
|
onClose,
|
|
409
431
|
onStop,
|
|
410
432
|
onDelete,
|
|
411
433
|
}: {
|
|
412
|
-
/** The open thread; none closes the sheet. */
|
|
434
|
+
/** The open thread; none closes the sheet. The row, which may carry no lines. */
|
|
413
435
|
thread?: Thread;
|
|
436
|
+
/** The same thread with every line, once it has been read (ThreadSetting). */
|
|
437
|
+
whole?: Thread;
|
|
414
438
|
bots?: Bot[];
|
|
415
439
|
onClose: () => void;
|
|
416
440
|
onStop: (thread: Thread) => void;
|
|
@@ -428,6 +452,13 @@ function ThreadSheet({
|
|
|
428
452
|
() => (thread ? threadFromRow(thread, bots) : null),
|
|
429
453
|
[thread, bots],
|
|
430
454
|
);
|
|
455
|
+
// The conversation is the one part that needs the lines. A row that carries
|
|
456
|
+
// them — a thread still going — draws at once and the whole one takes over.
|
|
457
|
+
const talk = useMemo(
|
|
458
|
+
() =>
|
|
459
|
+
whole ? threadFromRow(whole, bots) : view?.lines.length ? view : null,
|
|
460
|
+
[whole, view, bots],
|
|
461
|
+
);
|
|
431
462
|
const side = thread ? (sides[thread.id] ?? null) : null;
|
|
432
463
|
|
|
433
464
|
return (
|
|
@@ -486,15 +517,23 @@ function ThreadSheet({
|
|
|
486
517
|
</DialogClose>
|
|
487
518
|
</div>
|
|
488
519
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
520
|
+
{talk ? (
|
|
521
|
+
<Conversation
|
|
522
|
+
thread={talk}
|
|
523
|
+
tab={side}
|
|
524
|
+
onTab={(next) =>
|
|
525
|
+
setSides((was) => ({ ...was, [thread.id]: next }))
|
|
526
|
+
}
|
|
527
|
+
className="max-h-none min-h-0 flex-1 px-5"
|
|
528
|
+
tabsClassName="px-5"
|
|
529
|
+
/>
|
|
530
|
+
) : (
|
|
531
|
+
<div className="flex min-h-0 flex-1 flex-col gap-2 px-5 py-4">
|
|
532
|
+
<Skeleton className="h-3 w-4/5" />
|
|
533
|
+
<Skeleton className="h-3 w-3/5" />
|
|
534
|
+
<Skeleton className="h-3 w-2/3" />
|
|
535
|
+
</div>
|
|
536
|
+
)}
|
|
498
537
|
|
|
499
538
|
<div className="shrink-0 px-5 pt-2 pb-4">
|
|
500
539
|
<ThreadReply
|
|
@@ -506,7 +545,7 @@ function ThreadSheet({
|
|
|
506
545
|
room: thread.room,
|
|
507
546
|
}}
|
|
508
547
|
status={thread.status}
|
|
509
|
-
faces={
|
|
548
|
+
faces={view.roster}
|
|
510
549
|
to={side ?? thread.bot}
|
|
511
550
|
/>
|
|
512
551
|
</div>
|
|
@@ -57,6 +57,30 @@ export const MARK_PALETTE: string[] = MARK_COLORS.filter(
|
|
|
57
57
|
/** The app's two status colours. A face wearing one reads as a state it is not in, so no roll lands on them. */
|
|
58
58
|
const STATUS_INK: string[] = [MARK_INK.amber, MARK_INK.red];
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* What a colour is drawn as on a white page. Nine of the eighteen are too light
|
|
62
|
+
* to read there — a yellow face on paper is 1.9:1 against a 3:1 floor for a
|
|
63
|
+
* shape — so each has a twin at the same hue and chroma, lightness lowered
|
|
64
|
+
* until it clears 3.2:1. The dark theme keeps the colour as it is, where all
|
|
65
|
+
* eighteen already pass. The stored value never changes: the picker, the name
|
|
66
|
+
* the user chose and the roll all stay on the original.
|
|
67
|
+
*/
|
|
68
|
+
const ON_PAPER: Record<string, string> = {
|
|
69
|
+
[MARK_INK.cyan]: "#009dbb",
|
|
70
|
+
[MARK_INK.teal]: "#00a190",
|
|
71
|
+
[MARK_INK.green]: "#00a640",
|
|
72
|
+
[MARK_INK.lime]: "#5ca100",
|
|
73
|
+
[MARK_INK.amber]: "#d07b00",
|
|
74
|
+
[MARK_INK.orange]: "#ec6700",
|
|
75
|
+
[MARK_INK.sky]: "#0098dc",
|
|
76
|
+
[MARK_INK.emerald]: "#00a46d",
|
|
77
|
+
[MARK_INK.yellow]: "#bb8600",
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** The colour as this theme should draw it. Anything not in the table is itself. */
|
|
81
|
+
export const markInk = (color: string, dark: boolean): string =>
|
|
82
|
+
dark ? color : (ON_PAPER[color] ?? color);
|
|
83
|
+
|
|
60
84
|
/** How the renderer lays a paint's colours out. */
|
|
61
85
|
export type MarkPaintLook = "flow" | "duo" | "aurora";
|
|
62
86
|
|