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
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
// An invoice, quote or receipt from JSON: every sum worked out here in minor units, never
|
|
2
|
+
// by the model, then laid out as HTML and printed to PDF.
|
|
3
|
+
import { copyFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, extname, join } from "node:path";
|
|
5
|
+
import { printPdf } from "./browser.mjs";
|
|
6
|
+
import {
|
|
7
|
+
escapeHtml as esc,
|
|
8
|
+
input,
|
|
9
|
+
output,
|
|
10
|
+
readJson,
|
|
11
|
+
Stop,
|
|
12
|
+
shown,
|
|
13
|
+
} from "./kit.mjs";
|
|
14
|
+
import { printCss } from "./templates.mjs";
|
|
15
|
+
|
|
16
|
+
const LABELS = {
|
|
17
|
+
en: {
|
|
18
|
+
invoice: "Invoice",
|
|
19
|
+
quote: "Quote",
|
|
20
|
+
receipt: "Receipt",
|
|
21
|
+
number: "No.",
|
|
22
|
+
date: "Date",
|
|
23
|
+
due: "Due",
|
|
24
|
+
valid: "Valid until",
|
|
25
|
+
from: "From",
|
|
26
|
+
to: "Bill to",
|
|
27
|
+
quoteTo: "Prepared for",
|
|
28
|
+
item: "Description",
|
|
29
|
+
qty: "Qty",
|
|
30
|
+
price: "Unit price",
|
|
31
|
+
amount: "Amount",
|
|
32
|
+
subtotal: "Subtotal",
|
|
33
|
+
discount: "Discount",
|
|
34
|
+
shipping: "Shipping",
|
|
35
|
+
tax: "Tax",
|
|
36
|
+
total: "Total",
|
|
37
|
+
paid: "Paid",
|
|
38
|
+
balance: "Amount due",
|
|
39
|
+
payment: "Payment",
|
|
40
|
+
notes: "Notes",
|
|
41
|
+
taxId: "Tax ID",
|
|
42
|
+
},
|
|
43
|
+
ko: {
|
|
44
|
+
invoice: "청구서",
|
|
45
|
+
quote: "견적서",
|
|
46
|
+
receipt: "영수증",
|
|
47
|
+
number: "번호",
|
|
48
|
+
date: "발행일",
|
|
49
|
+
due: "지급 기한",
|
|
50
|
+
valid: "유효 기간",
|
|
51
|
+
from: "공급자",
|
|
52
|
+
to: "청구 대상",
|
|
53
|
+
quoteTo: "수신",
|
|
54
|
+
item: "품목",
|
|
55
|
+
qty: "수량",
|
|
56
|
+
price: "단가",
|
|
57
|
+
amount: "금액",
|
|
58
|
+
subtotal: "공급가액",
|
|
59
|
+
discount: "할인",
|
|
60
|
+
shipping: "배송비",
|
|
61
|
+
tax: "부가세",
|
|
62
|
+
total: "합계",
|
|
63
|
+
paid: "입금액",
|
|
64
|
+
balance: "청구 금액",
|
|
65
|
+
payment: "입금 계좌",
|
|
66
|
+
notes: "비고",
|
|
67
|
+
taxId: "사업자등록번호",
|
|
68
|
+
},
|
|
69
|
+
ja: {
|
|
70
|
+
invoice: "請求書",
|
|
71
|
+
quote: "御見積書",
|
|
72
|
+
receipt: "領収書",
|
|
73
|
+
number: "番号",
|
|
74
|
+
date: "発行日",
|
|
75
|
+
due: "お支払期限",
|
|
76
|
+
valid: "有効期限",
|
|
77
|
+
from: "発行元",
|
|
78
|
+
to: "請求先",
|
|
79
|
+
quoteTo: "宛先",
|
|
80
|
+
item: "品目",
|
|
81
|
+
qty: "数量",
|
|
82
|
+
price: "単価",
|
|
83
|
+
amount: "金額",
|
|
84
|
+
subtotal: "小計",
|
|
85
|
+
discount: "値引き",
|
|
86
|
+
shipping: "送料",
|
|
87
|
+
tax: "消費税",
|
|
88
|
+
total: "合計",
|
|
89
|
+
paid: "入金額",
|
|
90
|
+
balance: "ご請求金額",
|
|
91
|
+
payment: "お振込先",
|
|
92
|
+
notes: "備考",
|
|
93
|
+
taxId: "登録番号",
|
|
94
|
+
},
|
|
95
|
+
zh: {
|
|
96
|
+
invoice: "发票",
|
|
97
|
+
quote: "报价单",
|
|
98
|
+
receipt: "收据",
|
|
99
|
+
number: "编号",
|
|
100
|
+
date: "日期",
|
|
101
|
+
due: "付款期限",
|
|
102
|
+
valid: "有效期至",
|
|
103
|
+
from: "开票方",
|
|
104
|
+
to: "付款方",
|
|
105
|
+
quoteTo: "致",
|
|
106
|
+
item: "项目",
|
|
107
|
+
qty: "数量",
|
|
108
|
+
price: "单价",
|
|
109
|
+
amount: "金额",
|
|
110
|
+
subtotal: "小计",
|
|
111
|
+
discount: "折扣",
|
|
112
|
+
shipping: "运费",
|
|
113
|
+
tax: "税",
|
|
114
|
+
total: "合计",
|
|
115
|
+
paid: "已付",
|
|
116
|
+
balance: "应付金额",
|
|
117
|
+
payment: "付款信息",
|
|
118
|
+
notes: "备注",
|
|
119
|
+
taxId: "税号",
|
|
120
|
+
},
|
|
121
|
+
de: {
|
|
122
|
+
invoice: "Rechnung",
|
|
123
|
+
quote: "Angebot",
|
|
124
|
+
receipt: "Quittung",
|
|
125
|
+
number: "Nr.",
|
|
126
|
+
date: "Datum",
|
|
127
|
+
due: "Fällig am",
|
|
128
|
+
valid: "Gültig bis",
|
|
129
|
+
from: "Von",
|
|
130
|
+
to: "Rechnung an",
|
|
131
|
+
quoteTo: "Für",
|
|
132
|
+
item: "Beschreibung",
|
|
133
|
+
qty: "Menge",
|
|
134
|
+
price: "Einzelpreis",
|
|
135
|
+
amount: "Betrag",
|
|
136
|
+
subtotal: "Zwischensumme",
|
|
137
|
+
discount: "Rabatt",
|
|
138
|
+
shipping: "Versand",
|
|
139
|
+
tax: "USt.",
|
|
140
|
+
total: "Gesamt",
|
|
141
|
+
paid: "Bezahlt",
|
|
142
|
+
balance: "Offener Betrag",
|
|
143
|
+
payment: "Zahlung",
|
|
144
|
+
notes: "Hinweise",
|
|
145
|
+
taxId: "USt-IdNr.",
|
|
146
|
+
},
|
|
147
|
+
fr: {
|
|
148
|
+
invoice: "Facture",
|
|
149
|
+
quote: "Devis",
|
|
150
|
+
receipt: "Reçu",
|
|
151
|
+
number: "N°",
|
|
152
|
+
date: "Date",
|
|
153
|
+
due: "Échéance",
|
|
154
|
+
valid: "Valable jusqu’au",
|
|
155
|
+
from: "De",
|
|
156
|
+
to: "Facturé à",
|
|
157
|
+
quoteTo: "Pour",
|
|
158
|
+
item: "Désignation",
|
|
159
|
+
qty: "Qté",
|
|
160
|
+
price: "Prix unitaire",
|
|
161
|
+
amount: "Montant",
|
|
162
|
+
subtotal: "Sous-total",
|
|
163
|
+
discount: "Remise",
|
|
164
|
+
shipping: "Livraison",
|
|
165
|
+
tax: "TVA",
|
|
166
|
+
total: "Total",
|
|
167
|
+
paid: "Payé",
|
|
168
|
+
balance: "Montant dû",
|
|
169
|
+
payment: "Paiement",
|
|
170
|
+
notes: "Notes",
|
|
171
|
+
taxId: "N° TVA",
|
|
172
|
+
},
|
|
173
|
+
es: {
|
|
174
|
+
invoice: "Factura",
|
|
175
|
+
quote: "Presupuesto",
|
|
176
|
+
receipt: "Recibo",
|
|
177
|
+
number: "N.º",
|
|
178
|
+
date: "Fecha",
|
|
179
|
+
due: "Vencimiento",
|
|
180
|
+
valid: "Válido hasta",
|
|
181
|
+
from: "De",
|
|
182
|
+
to: "Facturar a",
|
|
183
|
+
quoteTo: "Para",
|
|
184
|
+
item: "Descripción",
|
|
185
|
+
qty: "Cant.",
|
|
186
|
+
price: "Precio unitario",
|
|
187
|
+
amount: "Importe",
|
|
188
|
+
subtotal: "Subtotal",
|
|
189
|
+
discount: "Descuento",
|
|
190
|
+
shipping: "Envío",
|
|
191
|
+
tax: "IVA",
|
|
192
|
+
total: "Total",
|
|
193
|
+
paid: "Pagado",
|
|
194
|
+
balance: "Importe pendiente",
|
|
195
|
+
payment: "Pago",
|
|
196
|
+
notes: "Notas",
|
|
197
|
+
taxId: "NIF",
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const KINDS = ["invoice", "quote", "receipt"];
|
|
202
|
+
|
|
203
|
+
const number = (value, what) => {
|
|
204
|
+
const n = typeof value === "string" ? Number(value.replace(/,/g, "")) : value;
|
|
205
|
+
if (typeof n !== "number" || !Number.isFinite(n))
|
|
206
|
+
throw new Stop(`${what} is not a number: ${JSON.stringify(value)}`);
|
|
207
|
+
return n;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
/** A rate as a fraction: 10, "10%" and 0.1 are all ten percent. */
|
|
211
|
+
const rate = (value, what) => {
|
|
212
|
+
if (value == null) return 0;
|
|
213
|
+
const n = number(String(value).replace("%", ""), what);
|
|
214
|
+
return n > 1 ? n / 100 : n;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
function computeTotals(data) {
|
|
218
|
+
const currency = String(data.currency ?? "").toUpperCase();
|
|
219
|
+
if (!/^[A-Z]{3}$/.test(currency))
|
|
220
|
+
throw new Stop(
|
|
221
|
+
'Set "currency" to a three-letter code: USD, EUR, KRW, JPY…',
|
|
222
|
+
);
|
|
223
|
+
const locale = data.locale ?? "en-US";
|
|
224
|
+
const money = new Intl.NumberFormat(locale, {
|
|
225
|
+
style: "currency",
|
|
226
|
+
currency,
|
|
227
|
+
});
|
|
228
|
+
const digits = money.resolvedOptions().maximumFractionDigits;
|
|
229
|
+
const unit = 10 ** digits;
|
|
230
|
+
// Every amount is a whole number of the currency's smallest unit
|
|
231
|
+
const minor = (n) => Math.round(n * unit + Number.EPSILON);
|
|
232
|
+
const show = (m) => money.format(m / unit);
|
|
233
|
+
// A unit price may carry more decimals than the currency's smallest unit: 0.125 per item
|
|
234
|
+
const price = (n) =>
|
|
235
|
+
new Intl.NumberFormat(locale, {
|
|
236
|
+
style: "currency",
|
|
237
|
+
currency,
|
|
238
|
+
minimumFractionDigits: digits,
|
|
239
|
+
maximumFractionDigits: Math.max(digits, 4),
|
|
240
|
+
}).format(n);
|
|
241
|
+
if (!Array.isArray(data.items) || !data.items.length)
|
|
242
|
+
throw new Stop('"items" is a list of { description, quantity, price }.');
|
|
243
|
+
const defaultTax =
|
|
244
|
+
data.tax == null ? 0 : rate(data.tax.rate ?? data.tax, "tax rate");
|
|
245
|
+
const inclusive = Boolean(data.tax?.inclusive);
|
|
246
|
+
|
|
247
|
+
const lines = data.items.map((item, i) => {
|
|
248
|
+
if (!item.description)
|
|
249
|
+
throw new Stop(`Item ${i + 1} has no "description".`);
|
|
250
|
+
const qty = number(item.quantity ?? 1, `Item ${i + 1} quantity`);
|
|
251
|
+
const price = number(item.price, `Item ${i + 1} price`);
|
|
252
|
+
const gross = minor(qty * price);
|
|
253
|
+
const off = item.discount
|
|
254
|
+
? String(item.discount).includes("%") || Number(item.discount) < 1
|
|
255
|
+
? minor((gross / unit) * rate(item.discount, "discount"))
|
|
256
|
+
: minor(number(item.discount, "discount"))
|
|
257
|
+
: 0;
|
|
258
|
+
return {
|
|
259
|
+
...item,
|
|
260
|
+
qty,
|
|
261
|
+
price,
|
|
262
|
+
amount: gross - off,
|
|
263
|
+
off,
|
|
264
|
+
taxRate:
|
|
265
|
+
item.tax == null ? defaultTax : rate(item.tax, `Item ${i + 1} tax`),
|
|
266
|
+
};
|
|
267
|
+
});
|
|
268
|
+
const subtotal = lines.reduce((s, l) => s + l.amount, 0);
|
|
269
|
+
const discount = data.discount
|
|
270
|
+
? String(data.discount).includes("%")
|
|
271
|
+
? minor((subtotal / unit) * rate(data.discount, "discount"))
|
|
272
|
+
: minor(number(data.discount, "discount"))
|
|
273
|
+
: 0;
|
|
274
|
+
// The order discount is shared across lines in proportion, so each tax rate is charged on what is left
|
|
275
|
+
const byRate = new Map();
|
|
276
|
+
for (const line of lines) {
|
|
277
|
+
const share = subtotal
|
|
278
|
+
? line.amount - (discount * line.amount) / subtotal
|
|
279
|
+
: 0;
|
|
280
|
+
byRate.set(line.taxRate, (byRate.get(line.taxRate) ?? 0) + share);
|
|
281
|
+
}
|
|
282
|
+
const taxes = [...byRate]
|
|
283
|
+
.filter(([r]) => r > 0)
|
|
284
|
+
.map(([r, base]) => ({
|
|
285
|
+
rate: r,
|
|
286
|
+
amount: inclusive
|
|
287
|
+
? Math.round(base - base / (1 + r))
|
|
288
|
+
: Math.round(base * r),
|
|
289
|
+
}));
|
|
290
|
+
const tax = taxes.reduce((s, t) => s + t.amount, 0);
|
|
291
|
+
const shipping = data.shipping ? minor(number(data.shipping, "shipping")) : 0;
|
|
292
|
+
const total = subtotal - discount + (inclusive ? 0 : tax) + shipping;
|
|
293
|
+
const paid = data.paid ? minor(number(data.paid, "paid")) : 0;
|
|
294
|
+
return {
|
|
295
|
+
currency,
|
|
296
|
+
locale,
|
|
297
|
+
show,
|
|
298
|
+
price,
|
|
299
|
+
qtyFormat: new Intl.NumberFormat(locale, { maximumFractionDigits: 3 }),
|
|
300
|
+
lines,
|
|
301
|
+
subtotal,
|
|
302
|
+
discount,
|
|
303
|
+
taxes,
|
|
304
|
+
tax,
|
|
305
|
+
inclusive,
|
|
306
|
+
shipping,
|
|
307
|
+
total,
|
|
308
|
+
paid,
|
|
309
|
+
balance: total - paid,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const lines = (value) =>
|
|
314
|
+
(Array.isArray(value) ? value : value ? String(value).split("\n") : [])
|
|
315
|
+
.filter(Boolean)
|
|
316
|
+
.map(esc)
|
|
317
|
+
.join("<br>");
|
|
318
|
+
|
|
319
|
+
/** The sender's own lines under their name, smaller: address, then how to reach them. */
|
|
320
|
+
function fromLines(p, L) {
|
|
321
|
+
if (!p) return "";
|
|
322
|
+
return [
|
|
323
|
+
p.tagline ? esc(p.tagline) : "",
|
|
324
|
+
lines(p.address),
|
|
325
|
+
[p.email, p.phone, p.website].filter(Boolean).map(esc).join(" · "),
|
|
326
|
+
p.tax_id ? `${L.taxId} ${esc(p.tax_id)}` : "",
|
|
327
|
+
]
|
|
328
|
+
.filter(Boolean)
|
|
329
|
+
.join("<br>");
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function party(p, L) {
|
|
333
|
+
if (!p) return "";
|
|
334
|
+
const rest = [
|
|
335
|
+
p.attn ? esc(p.attn) : "",
|
|
336
|
+
lines(p.address),
|
|
337
|
+
p.email ? esc(p.email) : "",
|
|
338
|
+
p.phone ? esc(p.phone) : "",
|
|
339
|
+
p.tax_id ? `${L.taxId} ${esc(p.tax_id)}` : "",
|
|
340
|
+
]
|
|
341
|
+
.filter(Boolean)
|
|
342
|
+
.join("<br>");
|
|
343
|
+
return `<strong>${esc(p.name)}</strong>${rest ? `<br><span class="muted">${rest}</span>` : ""}`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const percent = (r, locale) =>
|
|
347
|
+
new Intl.NumberFormat(locale, {
|
|
348
|
+
style: "percent",
|
|
349
|
+
maximumFractionDigits: 3,
|
|
350
|
+
}).format(r);
|
|
351
|
+
|
|
352
|
+
function invoiceHtml(data, t, logo) {
|
|
353
|
+
const kind = KINDS.includes(data.kind) ? data.kind : "invoice";
|
|
354
|
+
const lang = String(data.language ?? data.locale ?? "en")
|
|
355
|
+
.slice(0, 2)
|
|
356
|
+
.toLowerCase();
|
|
357
|
+
const L = { ...(LABELS[lang] ?? LABELS.en), ...(data.labels ?? {}) };
|
|
358
|
+
const title = data.title ?? L[kind];
|
|
359
|
+
const rows = t.lines
|
|
360
|
+
.map(
|
|
361
|
+
(l, i) => `<tr>
|
|
362
|
+
<td class="n">${i + 1}</td>
|
|
363
|
+
<td><div class="desc">${esc(l.description)}</div>${l.detail ? `<div class="detail">${esc(l.detail)}</div>` : ""}</td>
|
|
364
|
+
<td class="num">${t.qtyFormat.format(l.qty)}${l.unit ? ` <span class="muted">${esc(l.unit)}</span>` : ""}</td>
|
|
365
|
+
<td class="num">${t.price(l.price)}</td>
|
|
366
|
+
<td class="num">${t.show(l.amount)}${l.off ? `<div class="detail">−${t.show(l.off)}</div>` : ""}</td>
|
|
367
|
+
</tr>`,
|
|
368
|
+
)
|
|
369
|
+
.join("\n");
|
|
370
|
+
const sums = [
|
|
371
|
+
[L.subtotal, t.subtotal],
|
|
372
|
+
t.discount ? [L.discount, -t.discount] : null,
|
|
373
|
+
...t.taxes.map((x) => [
|
|
374
|
+
`${data.tax?.label ?? L.tax} ${percent(x.rate, t.locale)}${t.inclusive ? " incl." : ""}`,
|
|
375
|
+
x.amount,
|
|
376
|
+
]),
|
|
377
|
+
t.shipping ? [L.shipping, t.shipping] : null,
|
|
378
|
+
].filter(Boolean);
|
|
379
|
+
const due =
|
|
380
|
+
kind === "quote"
|
|
381
|
+
? data.valid_until
|
|
382
|
+
? [L.valid, data.valid_until]
|
|
383
|
+
: null
|
|
384
|
+
: data.due
|
|
385
|
+
? [L.due, data.due]
|
|
386
|
+
: null;
|
|
387
|
+
const payment = data.payment
|
|
388
|
+
? typeof data.payment === "string"
|
|
389
|
+
? esc(data.payment)
|
|
390
|
+
: Object.entries(data.payment)
|
|
391
|
+
.map(([k, v]) => `<tr><th>${esc(k)}</th><td>${esc(v)}</td></tr>`)
|
|
392
|
+
.join("")
|
|
393
|
+
: "";
|
|
394
|
+
const bottomLine =
|
|
395
|
+
kind === "receipt" ? L.paid : kind === "quote" ? L.total : L.balance;
|
|
396
|
+
const bottomValue = kind === "receipt" ? t.total : t.balance;
|
|
397
|
+
return `<!doctype html>
|
|
398
|
+
<html lang="${esc(lang)}">
|
|
399
|
+
<head>
|
|
400
|
+
<meta charset="utf-8">
|
|
401
|
+
<title>${esc(`${title} ${data.number ?? ""}`.trim())}</title>
|
|
402
|
+
<style>
|
|
403
|
+
${printCss().trim()}
|
|
404
|
+
</style>
|
|
405
|
+
<style>
|
|
406
|
+
:root { --accent: ${esc(data.accent ?? "#1f4e79")}; }
|
|
407
|
+
@page { margin: 16mm 16mm 18mm; }
|
|
408
|
+
.top { display: flex; justify-content: space-between; align-items: flex-start; gap: 20pt; margin-bottom: 26pt; }
|
|
409
|
+
.brand { display: flex; gap: 12pt; align-items: flex-start; }
|
|
410
|
+
.brand .from { font-size: 8.5pt; color: var(--soft); line-height: 1.5; margin-top: 4pt; }
|
|
411
|
+
.brand img { max-height: 40pt; max-width: 120pt; object-fit: contain; }
|
|
412
|
+
.brand .name { font-size: 13pt; font-weight: 700; letter-spacing: -0.01em; }
|
|
413
|
+
.doc { text-align: right; }
|
|
414
|
+
.doc h1 { font-size: 24pt; font-weight: 650; color: var(--accent); letter-spacing: -0.02em; }
|
|
415
|
+
.doc .no { color: var(--soft); margin-top: 3pt; font-size: 9.5pt; white-space: nowrap; }
|
|
416
|
+
.meta { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: 18pt; padding: 12pt 0 14pt; border-top: 0.75pt solid var(--rule); border-bottom: 0.75pt solid var(--rule); margin-bottom: 18pt; line-height: 1.45; }
|
|
417
|
+
.dates div + div { margin-top: 6pt; }
|
|
418
|
+
.owed { text-align: right; }
|
|
419
|
+
.owed b { display: block; font-size: 17pt; font-weight: 700; color: var(--accent); letter-spacing: -0.01em; margin-top: 2pt; }
|
|
420
|
+
.items td.n { color: var(--faint); width: 18pt; }
|
|
421
|
+
.items .desc { font-weight: 550; }
|
|
422
|
+
.items .detail { color: var(--soft); font-size: 8.5pt; margin-top: 1pt; }
|
|
423
|
+
.items th.num, .items td.num { width: 1%; padding-left: 14pt; }
|
|
424
|
+
.sums { display: flex; justify-content: flex-end; margin-top: 4pt; break-inside: avoid; }
|
|
425
|
+
.sums table { width: 46%; margin: 0; }
|
|
426
|
+
.sums td { border: 0; padding: 3pt 0; }
|
|
427
|
+
.sums td.num { padding-left: 16pt; }
|
|
428
|
+
.sums tr.grand td { border-top: 1pt solid var(--ink); padding-top: 8pt; font-size: 12.5pt; font-weight: 700; }
|
|
429
|
+
.sums tr.grand td.num { color: var(--accent); }
|
|
430
|
+
.foot { display: grid; grid-template-columns: 1fr 1fr; gap: 20pt; margin-top: 30pt; break-inside: avoid; }
|
|
431
|
+
.foot table { margin: 0; font-size: 9pt; }
|
|
432
|
+
.foot th { text-transform: none; letter-spacing: 0; font-size: 9pt; color: var(--soft); font-weight: 500; border: 0; padding: 1.5pt 10pt 1.5pt 0; white-space: nowrap; width: 1%; }
|
|
433
|
+
.foot td { border: 0; padding: 1.5pt 0; }
|
|
434
|
+
.thanks { margin-top: 26pt; color: var(--soft); font-size: 9pt; }
|
|
435
|
+
</style>
|
|
436
|
+
</head>
|
|
437
|
+
<body>
|
|
438
|
+
<div class="top">
|
|
439
|
+
<div class="brand">${logo ? `<img src="${esc(logo)}" alt="">` : ""}<div><div class="name">${esc(data.from?.name ?? "")}</div><div class="from">${fromLines(data.from, L)}</div></div></div>
|
|
440
|
+
<div class="doc"><h1>${esc(title)}</h1>${data.number ? `<div class="no">${esc(L.number)} ${esc(data.number)}</div>` : ""}</div>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<div class="meta">
|
|
444
|
+
<div><div class="label">${esc(kind === "quote" ? L.quoteTo : L.to)}</div>${party(data.to, L)}</div>
|
|
445
|
+
<div class="dates">
|
|
446
|
+
${data.date ? `<div><div class="label">${esc(L.date)}</div>${esc(data.date)}</div>` : ""}
|
|
447
|
+
${due ? `<div><div class="label">${esc(due[0])}</div>${esc(due[1])}</div>` : ""}
|
|
448
|
+
</div>
|
|
449
|
+
<div class="owed"><div class="label">${esc(bottomLine)}</div><b>${t.show(bottomValue)}</b></div>
|
|
450
|
+
</div>
|
|
451
|
+
|
|
452
|
+
<table class="items">
|
|
453
|
+
<thead><tr><th>#</th><th>${esc(L.item)}</th><th class="num">${esc(L.qty)}</th><th class="num">${esc(L.price)}</th><th class="num">${esc(L.amount)}</th></tr></thead>
|
|
454
|
+
<tbody>
|
|
455
|
+
${rows}
|
|
456
|
+
</tbody>
|
|
457
|
+
</table>
|
|
458
|
+
|
|
459
|
+
<div class="sums"><table>
|
|
460
|
+
${sums.map(([k, v]) => `<tr><td>${esc(k)}</td><td class="num">${v < 0 ? `−${t.show(-v)}` : t.show(v)}</td></tr>`).join("\n")}
|
|
461
|
+
<tr class="${t.paid ? "" : "grand"}"><td>${esc(L.total)}</td><td class="num">${t.show(t.total)}</td></tr>
|
|
462
|
+
${t.paid ? `<tr><td>${esc(L.paid)}</td><td class="num">−${t.show(t.paid)}</td></tr><tr class="grand"><td>${esc(L.balance)}</td><td class="num">${t.show(t.balance)}</td></tr>` : ""}
|
|
463
|
+
</table></div>
|
|
464
|
+
|
|
465
|
+
${
|
|
466
|
+
payment || data.notes
|
|
467
|
+
? `<div class="foot">
|
|
468
|
+
<div>${payment ? `<div class="label">${esc(L.payment)}</div>${typeof data.payment === "string" ? `<p>${payment}</p>` : `<table>${payment}</table>`}` : ""}</div>
|
|
469
|
+
<div>${data.notes ? `<div class="label">${esc(L.notes)}</div><p>${lines(data.notes)}</p>` : ""}</div>
|
|
470
|
+
</div>`
|
|
471
|
+
: ""
|
|
472
|
+
}
|
|
473
|
+
${data.thanks ? `<p class="thanks">${esc(data.thanks)}</p>` : ""}
|
|
474
|
+
</body>
|
|
475
|
+
</html>
|
|
476
|
+
`;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export async function invoice(dataPath, opts) {
|
|
480
|
+
const data = readJson(dataPath);
|
|
481
|
+
const t = computeTotals(data);
|
|
482
|
+
const kind = KINDS.includes(data.kind) ? data.kind : "invoice";
|
|
483
|
+
const stem = `${kind}-${data.number ?? data.to?.name ?? "draft"}`
|
|
484
|
+
.toLowerCase()
|
|
485
|
+
.replace(/[^\p{L}\p{N}]+/gu, "-")
|
|
486
|
+
.replace(/^-|-$/g, "");
|
|
487
|
+
const pdf = output(opts.out, stem, "pdf");
|
|
488
|
+
const html = pdf.replace(/\.pdf$/, ".html");
|
|
489
|
+
let logo = null;
|
|
490
|
+
if (data.from?.logo) {
|
|
491
|
+
const source = input(data.from.logo);
|
|
492
|
+
logo = `${basename(html, ".html")}-logo${extname(source)}`;
|
|
493
|
+
copyFileSync(source, join(dirname(html), logo));
|
|
494
|
+
}
|
|
495
|
+
writeFileSync(html, invoiceHtml(data, t, logo));
|
|
496
|
+
const { broken, wide } = await printPdf(html, pdf);
|
|
497
|
+
console.log(
|
|
498
|
+
[
|
|
499
|
+
`Subtotal ${t.show(t.subtotal)}${t.discount ? `, discount −${t.show(t.discount)}` : ""}${t.taxes.map((x) => `, tax ${Math.round(x.rate * 100000) / 1000}% ${t.show(x.amount)}${t.inclusive ? " (included)" : ""}`).join("")}${t.shipping ? `, shipping ${t.show(t.shipping)}` : ""}, total ${t.show(t.total)}${t.paid ? `, paid ${t.show(t.paid)}, due ${t.show(t.balance)}` : ""}.`,
|
|
500
|
+
`${shown(html)} is the page it was printed from: edit it and run \`pdf\` on it for a change the data file cannot say.`,
|
|
501
|
+
].join("\n"),
|
|
502
|
+
);
|
|
503
|
+
const { report } = await import("./report.mjs");
|
|
504
|
+
await report(pdf, { broken, wide });
|
|
505
|
+
}
|