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.
Files changed (470) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/prerender-manifest.json +4 -4
  4. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  5. package/.next/server/app/_global-error.html +1 -1
  6. package/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/server/app/_not-found/page.js +1 -1
  11. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  12. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/server/app/_not-found.html +1 -1
  14. package/.next/server/app/_not-found.rsc +18 -19
  15. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -19
  16. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -15
  17. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  18. package/.next/server/app/api/artifact/route.js +8 -8
  19. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  20. package/.next/server/app/api/bot/keep-working/route.js +7 -7
  21. package/.next/server/app/api/bot/keep-working/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  23. package/.next/server/app/api/bot/memory/route.js +7 -7
  24. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  25. package/.next/server/app/api/bot/route.js +7 -7
  26. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  27. package/.next/server/app/api/bot/thread/[id]/route.js +5 -5
  28. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -1
  29. package/.next/server/app/api/bot/thread/route.js +3 -3
  30. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -1
  31. package/.next/server/app/api/config/route.js +3 -3
  32. package/.next/server/app/api/config/route.js.nft.json +1 -1
  33. package/.next/server/app/api/events/route.js.nft.json +1 -1
  34. package/.next/server/app/api/favicon/[host]/route.js.nft.json +1 -1
  35. package/.next/server/app/api/file/[...path]/route.js +2 -2
  36. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  37. package/.next/server/app/api/llm-model/catalog/route.js +4 -4
  38. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  39. package/.next/server/app/api/llm-model/credits/route.js +4 -4
  40. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  41. package/.next/server/app/api/llm-model/route.js +6 -6
  42. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  43. package/.next/server/app/api/llm-model/subscription/route.js +6 -6
  44. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  45. package/.next/server/app/api/mcp/[name]/route.js +5 -5
  46. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  47. package/.next/server/app/api/mcp/oauth/callback/route.js +5 -5
  48. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  49. package/.next/server/app/api/mcp/route.js +5 -5
  50. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  51. package/.next/server/app/api/mcp/tools/route.js +5 -5
  52. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  53. package/.next/server/app/api/memory/edit/route.js +15 -14
  54. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  55. package/.next/server/app/api/memory/route.js +4 -4
  56. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  57. package/.next/server/app/api/reach/route.js +13 -12
  58. package/.next/server/app/api/reach/route.js.nft.json +1 -1
  59. package/.next/server/app/api/routine/route.js +8 -9
  60. package/.next/server/app/api/routine/route.js.nft.json +1 -1
  61. package/.next/server/app/api/signins/route.js.nft.json +1 -1
  62. package/.next/server/app/api/skills/[source]/[name]/route.js +2 -2
  63. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/skills/route.js +2 -2
  65. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  66. package/.next/server/app/api/thursday/call/route.js +6 -6
  67. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  68. package/.next/server/app/api/thursday/skills/route.js +6 -6
  69. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  70. package/.next/server/app/api/thursday/text/route.js +14 -13
  71. package/.next/server/app/api/thursday/text/route.js.nft.json +1 -1
  72. package/.next/server/app/api/thursday/tool-call/route.js +15 -14
  73. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  74. package/.next/server/app/api/workspace/files/route.js +10 -6
  75. package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
  76. package/.next/server/app/api/workspace/route.js +9 -4
  77. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  78. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +2 -2
  79. package/.next/server/app/artifact/[...path]/page.js +5 -4
  80. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  81. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  82. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  83. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  84. package/.next/server/app/page/server-reference-manifest.json +67 -56
  85. package/.next/server/app/page.js +10 -11
  86. package/.next/server/app/page.js.nft.json +1 -1
  87. package/.next/server/app/page_client-reference-manifest.js +1 -1
  88. package/.next/server/chunks/{[root-of-the-server]__0o49ztf._.js → [root-of-the-server]__0-k4_ie._.js} +2 -2
  89. package/.next/server/chunks/[root-of-the-server]__0209ah4._.js +6 -6
  90. package/.next/server/chunks/[root-of-the-server]__04wldw9._.js +1 -1
  91. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +2 -2
  92. package/.next/server/chunks/{[root-of-the-server]__0cfszwn._.js → [root-of-the-server]__0i23tc1._.js} +2 -2
  93. package/.next/server/chunks/[root-of-the-server]__0mrk2it._.js +1 -1
  94. package/.next/server/chunks/[root-of-the-server]__0nr-v8s._.js +1 -1
  95. package/.next/server/chunks/{[root-of-the-server]__1tg5got._.js → [root-of-the-server]__0paqm5y._.js} +2 -2
  96. package/.next/server/chunks/[root-of-the-server]__0qog7sm._.js +8 -0
  97. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +1 -1
  98. package/.next/server/chunks/[root-of-the-server]__0yisc5v._.js +5 -0
  99. package/.next/server/chunks/[root-of-the-server]__1-swlkw._.js +3 -3
  100. package/.next/server/chunks/[root-of-the-server]__12iddfq._.js +2 -2
  101. package/.next/server/chunks/{[root-of-the-server]__0npn_pn._.js → [root-of-the-server]__15p29m3._.js} +2 -2
  102. package/.next/server/chunks/[root-of-the-server]__17ses32._.js +3 -0
  103. package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +2 -2
  104. package/.next/server/chunks/[root-of-the-server]__1cjxw0-._.js +1 -1
  105. package/.next/server/chunks/[root-of-the-server]__1gi2nns._.js +5 -0
  106. package/.next/server/chunks/{[root-of-the-server]__0rqgb17._.js → [root-of-the-server]__1iauz8a._.js} +2 -2
  107. package/.next/server/chunks/[root-of-the-server]__1k3j52n._.js +1 -1
  108. package/.next/server/chunks/{[root-of-the-server]__209k6pk._.js → [root-of-the-server]__1lb_pxg._.js} +2 -2
  109. package/.next/server/chunks/[root-of-the-server]__1ndi14y._.js +1 -1
  110. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +1 -1
  111. package/.next/server/chunks/[root-of-the-server]__1xqsrqq._.js +5 -0
  112. package/.next/server/chunks/[root-of-the-server]__1ygplx1._.js +1 -1
  113. package/.next/server/chunks/[root-of-the-server]__2163i40._.js +5 -0
  114. package/.next/server/chunks/_0ci0abh._.js +3 -0
  115. package/.next/server/chunks/_0eauz4t._.js +1 -1
  116. package/.next/server/chunks/_0f6ts7z._.js +1 -1
  117. package/.next/server/chunks/_0fg-1oj._.js +5 -0
  118. package/.next/server/chunks/_0khihjk._.js +2 -2
  119. package/.next/server/chunks/_0n74zsf._.js +1 -1
  120. package/.next/server/chunks/_0na2fj1._.js +2 -2
  121. package/.next/server/chunks/_0oh_99-._.js +3 -0
  122. package/.next/server/chunks/_0x-ej3f._.js +24 -24
  123. package/.next/server/chunks/_0z3nz21._.js +3 -0
  124. package/.next/server/chunks/_10tkr26._.js +1 -1
  125. package/.next/server/chunks/_12-amdu._.js +2 -2
  126. package/.next/server/chunks/_136j09a._.js +1 -1
  127. package/.next/server/chunks/_15740dw._.js +1 -1
  128. package/.next/server/chunks/_18izeh1._.js +5 -0
  129. package/.next/server/chunks/_1_5mnq4._.js +1 -1
  130. package/.next/server/chunks/_1ajbhv6._.js +2 -2
  131. package/.next/server/chunks/_1dc_d1q._.js +2 -2
  132. package/.next/server/chunks/_1drgfx4._.js +1 -1
  133. package/.next/server/chunks/_1e48czp._.js +2 -2
  134. package/.next/server/chunks/_1f06zo4._.js +3 -0
  135. package/.next/server/chunks/_1ic3bew._.js +2 -2
  136. package/.next/server/chunks/_1jn-aep._.js +2 -2
  137. package/.next/server/chunks/_1jn5btd._.js +6 -0
  138. package/.next/server/chunks/_1kg70wc._.js +2 -2
  139. package/.next/server/chunks/_1m2i5pt._.js +5 -0
  140. package/.next/server/chunks/_1ogqovh._.js +4 -4
  141. package/.next/server/chunks/_1qxheoa._.js +1 -1
  142. package/.next/server/chunks/_1ry6afh._.js +18 -0
  143. package/.next/server/chunks/_1taa4bs._.js +1 -1
  144. package/.next/server/chunks/_1tpr507._.js +1 -1
  145. package/.next/server/chunks/_1y8w80a._.js +1 -1
  146. package/.next/server/chunks/_1zxp-p6._.js +1 -1
  147. package/.next/server/chunks/_204744f._.js +5 -0
  148. package/.next/server/chunks/_20fsr_z._.js +1 -1
  149. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  150. package/.next/server/chunks/features_0-cnt0l._.js +1 -1
  151. package/.next/server/chunks/features_0hdaci0._.js +1 -1
  152. package/.next/server/chunks/features_0p85gv6._.js +3 -0
  153. package/.next/server/chunks/{node_modules_zod_v4_0_v5xf5._.js → node_modules_zod_v4_01bha1c._.js} +2 -2
  154. package/.next/server/chunks/{node_modules_zod_v4_0q9hvql._.js → node_modules_zod_v4_0b99z6a._.js} +2 -2
  155. package/.next/server/chunks/{node_modules_zod_v4_1jg8iwg._.js → node_modules_zod_v4_1zz6lo1._.js} +2 -2
  156. package/.next/server/chunks/ssr/[root-of-the-server]__04upd5v._.js +3 -0
  157. package/.next/server/chunks/ssr/[root-of-the-server]__0dxszdt._.js +3 -0
  158. package/.next/server/chunks/ssr/[root-of-the-server]__0eezycw._.js +3 -0
  159. package/.next/server/chunks/ssr/[root-of-the-server]__0hpp3nw._.js +1 -1
  160. package/.next/server/chunks/ssr/[root-of-the-server]__0yngu44._.js +3 -0
  161. package/.next/server/chunks/ssr/[root-of-the-server]__16z72ny._.js +6 -0
  162. package/.next/server/chunks/ssr/[root-of-the-server]__1u_ry86._.js +3 -0
  163. package/.next/server/chunks/ssr/{[root-of-the-server]__1iwyp1e._.js → [root-of-the-server]__1unh_ew._.js} +1 -1
  164. package/.next/server/chunks/ssr/[root-of-the-server]__20re7ya._.js +3 -0
  165. package/.next/server/chunks/ssr/_00pgq9d._.js +5 -0
  166. package/.next/server/chunks/ssr/_07ke63g._.js +3 -0
  167. package/.next/server/chunks/ssr/_0agcbk7._.js +3 -0
  168. package/.next/server/chunks/ssr/_0e-gw2_._.js +3 -0
  169. package/.next/server/chunks/ssr/{_0fbi6om._.js → _0f_om6y._.js} +3 -3
  170. package/.next/server/chunks/ssr/_0fqhhwi._.js +1 -1
  171. package/.next/server/chunks/ssr/{_026qnc9._.js → _0gpn71k._.js} +3 -3
  172. package/.next/server/chunks/ssr/_0iizjr9._.js +3 -0
  173. package/.next/server/chunks/ssr/_0ixvzo6._.js +75 -0
  174. package/.next/server/chunks/ssr/_0kkdx7t._.js +3 -0
  175. package/.next/server/chunks/ssr/_0lufvw7._.js +118 -0
  176. package/.next/server/chunks/ssr/_0vi6ky6._.js +115 -0
  177. package/.next/server/chunks/ssr/{_10f-jib._.js → _0yhji3e._.js} +2 -2
  178. package/.next/server/chunks/ssr/_0z38nha._.js +3 -0
  179. package/.next/server/chunks/ssr/{_10mo72m._.js → _11nx2d4._.js} +2 -2
  180. package/.next/server/chunks/ssr/_12mijol._.js +2 -2
  181. package/.next/server/chunks/ssr/_150463c._.js +164 -0
  182. package/.next/server/chunks/ssr/{_0rmaf32._.js → _17d2ikl._.js} +2 -2
  183. package/.next/server/chunks/ssr/_19jez1a._.js +3 -0
  184. package/.next/server/chunks/ssr/_1blui1m._.js +3 -0
  185. package/.next/server/chunks/ssr/_1d423aj._.js +4 -4
  186. package/.next/server/chunks/ssr/_1kbk28w._.js +3 -0
  187. package/.next/server/chunks/ssr/_1kj_r9v._.js +3 -0
  188. package/.next/server/chunks/ssr/_1mqn9mc._.js +1 -1
  189. package/.next/server/chunks/ssr/{_0u5xv6g._.js → _1myh7ss._.js} +2 -2
  190. package/.next/server/chunks/ssr/_1neoj22._.js +1 -1
  191. package/.next/server/chunks/ssr/_1ou5sj0._.js +3 -0
  192. package/.next/server/chunks/ssr/_1p8xorg._.js +3 -0
  193. package/.next/server/chunks/ssr/_1tzacpl._.js +3 -0
  194. package/.next/server/chunks/ssr/_1xoch6f._.js +1 -1
  195. package/.next/server/chunks/ssr/_1yh5bj5._.js +1 -1
  196. package/.next/server/chunks/ssr/{_02c7o30._.js → _2021n9-._.js} +2 -2
  197. package/.next/server/chunks/ssr/_20argo3._.js +3 -0
  198. package/.next/server/chunks/ssr/features_bot_1ll3wp7._.js +3 -0
  199. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +1 -1
  200. package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +1 -1
  201. package/.next/server/chunks/ssr/features_config_1qxe5ur._.js +20 -0
  202. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +3 -3
  203. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +1 -1
  204. package/.next/server/chunks/ssr/features_routine_components_routine-setting_tsx_055fknz._.js +1 -1
  205. package/.next/server/chunks/ssr/features_workspace_00jz2hu._.js +1 -1
  206. package/.next/server/chunks/ssr/{node_modules_0ky76fz._.js → node_modules_06e0wlv._.js} +1 -1
  207. package/.next/server/chunks/ssr/{node_modules_0-x0zxm._.js → node_modules_0cj26-9._.js} +1 -1
  208. package/.next/server/chunks/ssr/{node_modules_0operbz._.js → node_modules_0d1rf5e._.js} +1 -1
  209. package/.next/server/chunks/ssr/{node_modules_0b0iy01._.js → node_modules_0e86703._.js} +1 -1
  210. package/.next/server/chunks/ssr/{node_modules_05b6e99._.js → node_modules_0es09am._.js} +1 -1
  211. package/.next/server/chunks/ssr/{node_modules_1iau_ea._.js → node_modules_0gr_dzf._.js} +1 -1
  212. package/.next/server/chunks/ssr/{node_modules_1hv-j1l._.js → node_modules_0gtcwz9._.js} +1 -1
  213. package/.next/server/chunks/ssr/{node_modules_1c2ikr9._.js → node_modules_0hi9h8f._.js} +1 -1
  214. package/.next/server/chunks/ssr/{node_modules_01u4ea3._.js → node_modules_0lkop0t._.js} +1 -1
  215. package/.next/server/chunks/ssr/{node_modules_1wvf3oo._.js → node_modules_0nghisk._.js} +1 -1
  216. package/.next/server/chunks/ssr/{node_modules_0yzmxfq._.js → node_modules_0stovz0._.js} +1 -1
  217. package/.next/server/chunks/ssr/{node_modules_00nrzz_._.js → node_modules_0we85kr._.js} +1 -1
  218. package/.next/server/chunks/ssr/{node_modules_01ed0yi._.js → node_modules_0ya7y1s._.js} +1 -1
  219. package/.next/server/chunks/ssr/{node_modules_0m3_5ge._.js → node_modules_0yrbwkj._.js} +1 -1
  220. package/.next/server/chunks/ssr/{node_modules_0v_-uht._.js → node_modules_1-x70ie._.js} +1 -1
  221. package/.next/server/chunks/ssr/{node_modules_07jp6tj._.js → node_modules_12fd9g0._.js} +1 -1
  222. package/.next/server/chunks/ssr/{node_modules_1wgnj8q._.js → node_modules_12wxrgr._.js} +1 -1
  223. package/.next/server/chunks/ssr/{node_modules_0azd56x._.js → node_modules_139uu4q._.js} +1 -1
  224. package/.next/server/chunks/ssr/{node_modules_1omg9xr._.js → node_modules_14gpoe1._.js} +1 -1
  225. package/.next/server/chunks/ssr/{node_modules_1ma_y68._.js → node_modules_18fmji6._.js} +1 -1
  226. package/.next/server/chunks/ssr/{node_modules_0ucridu._.js → node_modules_19kkel8._.js} +1 -1
  227. package/.next/server/chunks/ssr/{node_modules_0fpnetd._.js → node_modules_1gcine1._.js} +1 -1
  228. package/.next/server/chunks/ssr/{node_modules_1z3sh11._.js → node_modules_1h4trkm._.js} +1 -1
  229. package/.next/server/chunks/ssr/{node_modules_0lautv3._.js → node_modules_1mub_qu._.js} +1 -1
  230. package/.next/server/chunks/ssr/{node_modules_0ou0all._.js → node_modules_1p78svs._.js} +1 -1
  231. package/.next/server/chunks/ssr/{node_modules_19b0bir._.js → node_modules_1xp-7ep._.js} +1 -1
  232. 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
  233. 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
  234. package/.next/server/middleware-build-manifest.js +3 -3
  235. package/.next/server/pages/404.html +1 -1
  236. package/.next/server/pages/500.html +1 -1
  237. package/.next/server/server-reference-manifest.js +1 -1
  238. package/.next/server/server-reference-manifest.json +69 -58
  239. package/.next/static/chunks/03df16hs01-xi.js +1 -0
  240. package/.next/static/chunks/0crocb7272z8k.js +1 -0
  241. package/.next/static/chunks/{0p9jcyqkpq71f.js → 0dqsenl3uk_8z.js} +1 -1
  242. package/.next/static/chunks/0hhn8mf953761.js +1 -0
  243. package/.next/static/chunks/0n1o3k0z4m7c_.js +1 -0
  244. package/.next/static/chunks/0oe2zavre2a7d.css +1 -0
  245. package/.next/static/chunks/0srg9tv4105-i.js +1 -0
  246. package/.next/static/chunks/0t599wrclly7i.js +18 -0
  247. package/.next/static/chunks/0x34bhth_sn35.js +1 -0
  248. package/.next/static/chunks/{0mscosx0eh3ee.js → 0x_6z8vt8hyf4.js} +3 -3
  249. package/.next/static/chunks/{0p50d-au6-3hx.js → 1_wstwzu1md-6.js} +2 -2
  250. package/.next/static/chunks/{40ij3wsn3vt7h.js → 1aughn81slf90.js} +1 -1
  251. package/.next/static/chunks/1g1j03h_l-e67.js +1 -0
  252. package/.next/static/chunks/1lp02y2nmddxg.js +1 -0
  253. package/.next/static/chunks/211s4xjtecj2l.js +1 -0
  254. package/.next/static/chunks/2244-cat2jlvd.js +1 -0
  255. package/.next/static/chunks/{2r6xnyg7ezyxr.js → 2eev_i93slion.js} +2 -2
  256. package/.next/static/chunks/2sjq4gsimlfqr.js +113 -0
  257. package/.next/static/chunks/{0qgn3u86jkbm7.js → 2uleilh8ph06-.js} +1 -1
  258. package/.next/static/chunks/{1czfknd4luo6t.js → 2zchsg03a1pdp.js} +1 -1
  259. package/.next/static/chunks/32tmfirfjpulv.js +1 -0
  260. package/.next/static/chunks/{2_c7mu6x1lu49.js → 376-s_i83irs-.js} +1 -1
  261. package/.next/static/chunks/3blk-kpn39xr-.js +1 -0
  262. package/.next/static/chunks/3eieehp7wquyu.js +1 -0
  263. package/.next/static/chunks/3kc-e7pcj50ae.js +1 -0
  264. package/.next/static/chunks/3rwpyuo9nrrop.js +17 -0
  265. package/.next/static/chunks/3sf4l25l353ja.js +1 -0
  266. package/.next/static/chunks/3vz7m1w688juj.js +3 -0
  267. package/.next/static/chunks/43skgt0h9woyu.js +1 -0
  268. package/app/api/events/app-event.client.ts +8 -2
  269. package/app/api/events/app-event.server.ts +7 -5
  270. package/app/api/events/app-event.ts +19 -8
  271. package/app/api/query-key.ts +13 -5
  272. package/bin/database.mjs +21 -11
  273. package/bin/thursday.mjs +5 -2
  274. package/components/ui/shiny-text.tsx +2 -2
  275. package/database/migrations/20260920024909_messy_baron_strucker/migration.sql +1 -0
  276. package/database/migrations/20260920024909_messy_baron_strucker/snapshot.json +1937 -0
  277. package/features/artifact/components/artifact-setting.tsx +18 -24
  278. package/features/bot/bot.action.ts +3 -0
  279. package/features/bot/bot.runner.ts +25 -3
  280. package/features/bot/bot.seed.ts +98 -22
  281. package/features/bot/components/bot-badge.tsx +2 -2
  282. package/features/bot/components/bot-mark.tsx +12 -3
  283. package/features/bot/components/bot-room.tsx +33 -10
  284. package/features/bot/components/bot-setting.tsx +88 -34
  285. package/features/bot/components/crew-motion.ts +161 -0
  286. package/features/bot/components/mark-palette.tsx +3 -3
  287. package/features/bot/components/room-conversation.tsx +13 -8
  288. package/features/bot/components/room-list.tsx +9 -5
  289. package/features/bot/components/room-pill.tsx +131 -41
  290. package/features/bot/components/thread-badge.tsx +4 -4
  291. package/features/bot/components/thread-setting.tsx +58 -19
  292. package/features/bot/mark.const.ts +24 -0
  293. package/features/bot/thread.query.ts +32 -14
  294. package/features/bot/thread.store.ts +19 -16
  295. package/features/config/components/config-badge.tsx +2 -2
  296. package/features/config/components/config-setting.tsx +63 -213
  297. package/features/config/config.const.ts +2 -1
  298. package/features/connectors/components/mcp-setting.tsx +60 -29
  299. package/features/intro/components/intro.tsx +2 -2
  300. package/features/memory/components/memory-setting.tsx +11 -7
  301. package/features/reach/channel.ts +9 -1
  302. package/features/reach/components/reach-guide.tsx +606 -105
  303. package/features/reach/discord.ts +18 -3
  304. package/features/reach/reach.schema.ts +6 -0
  305. package/features/reach/reach.ts +55 -2
  306. package/features/reach/slack.ts +2 -1
  307. package/features/reach/telegram.ts +5 -1
  308. package/features/routine/components/routine-setting.tsx +46 -18
  309. package/features/settings/components/setting-ui.tsx +17 -68
  310. package/features/settings/components/settings.tsx +4 -3
  311. package/features/settings/settings.alert.ts +8 -8
  312. package/features/skills/components/skills-setting.tsx +78 -12
  313. package/features/skills/skills.action.ts +12 -0
  314. package/features/skills/skills.query.ts +24 -0
  315. package/features/thursday/components/call-log.tsx +19 -14
  316. package/features/thursday/components/side-captions.tsx +3 -2
  317. package/features/thursday/components/thursday-setting.tsx +5 -6
  318. package/features/thursday/components/thursday.tsx +8 -9
  319. package/features/thursday/components/write-line.tsx +10 -5
  320. package/features/thursday/thursday.action.ts +4 -0
  321. package/features/thursday/thursday.query.ts +3 -2
  322. package/features/thursday/thursday.schema.ts +5 -0
  323. package/features/thursday/use-call-ring.ts +6 -1
  324. package/features/thursday/use-text-call.ts +25 -10
  325. package/features/thursday/use-thursday.ts +10 -1
  326. package/features/workspace/components/artifact-view.tsx +42 -33
  327. package/features/workspace/components/file-thumb.tsx +8 -4
  328. package/features/workspace/components/file-view.tsx +25 -2
  329. package/features/workspace/components/workspace-setting.tsx +27 -23
  330. package/features/workspace/workspace.query.ts +20 -1
  331. package/features/workspace/workspace.ts +14 -0
  332. package/guide/bots.md +27 -4
  333. package/guide/calls.md +5 -3
  334. package/guide/phone.md +23 -12
  335. package/guide/setup.md +20 -5
  336. package/guide/trouble.md +1 -1
  337. package/hooks/use-theme.ts +14 -0
  338. package/lib/protocol/events.client.ts +56 -14
  339. package/lib/protocol/events.server.ts +41 -12
  340. package/lib/utils.ts +1 -1
  341. package/package.json +1 -1
  342. package/scripts/reach-channels.test.mts +15 -2
  343. package/seed-skills/brief/daily-brief/SKILL.md +39 -0
  344. package/seed-skills/brief/daily-brief/page/brief.css +406 -0
  345. package/seed-skills/brief/daily-brief/references/brief.md +106 -0
  346. package/seed-skills/brief/daily-brief/references/preferences.md +67 -0
  347. package/seed-skills/brief/daily-brief/scripts/glance.mjs +128 -0
  348. package/seed-skills/brief/daily-brief/scripts/lib.mjs +182 -0
  349. package/seed-skills/brief/daily-brief/scripts/news.mjs +320 -0
  350. package/seed-skills/brief/daily-brief/scripts/page.mjs +322 -0
  351. package/seed-skills/brief/daily-brief/scripts/story.mjs +265 -0
  352. package/seed-skills/digest/README.md +20 -0
  353. package/seed-skills/digest/media-digest/SKILL.md +32 -0
  354. package/seed-skills/digest/media-digest/references/no-captions.md +20 -0
  355. package/seed-skills/digest/media-digest/references/page.md +56 -0
  356. package/seed-skills/digest/media-digest/references/reading.md +56 -0
  357. package/seed-skills/digest/media-digest/scripts/audio.mjs +232 -0
  358. package/seed-skills/digest/media-digest/scripts/digest.mjs +379 -0
  359. package/seed-skills/digest/media-digest/scripts/lib.mjs +284 -0
  360. package/seed-skills/digest/media-digest/scripts/part.mjs +16 -0
  361. package/seed-skills/digest/media-digest/scripts/text.mjs +287 -0
  362. package/seed-skills/digest/media-digest/scripts/yt.mjs +487 -0
  363. package/seed-skills/docs/README.md +32 -0
  364. package/seed-skills/docs/documents/SKILL.md +34 -0
  365. package/seed-skills/docs/documents/kit/package-lock.json +1596 -0
  366. package/seed-skills/docs/documents/kit/package.json +17 -0
  367. package/seed-skills/docs/documents/references/deck.md +63 -0
  368. package/seed-skills/docs/documents/references/invoice.md +64 -0
  369. package/seed-skills/docs/documents/references/pdf.md +59 -0
  370. package/seed-skills/docs/documents/references/print.md +43 -0
  371. package/seed-skills/docs/documents/references/sheets.md +49 -0
  372. package/seed-skills/docs/documents/references/translate.md +37 -0
  373. package/seed-skills/docs/documents/references/word.md +45 -0
  374. package/seed-skills/docs/documents/scripts/doc.mjs +123 -0
  375. package/seed-skills/docs/documents/scripts/lib/browser.mjs +259 -0
  376. package/seed-skills/docs/documents/scripts/lib/deck-chart.mjs +150 -0
  377. package/seed-skills/docs/documents/scripts/lib/deck.mjs +1132 -0
  378. package/seed-skills/docs/documents/scripts/lib/invoice.mjs +505 -0
  379. package/seed-skills/docs/documents/scripts/lib/kit.mjs +244 -0
  380. package/seed-skills/docs/documents/scripts/lib/pdf.mjs +645 -0
  381. package/seed-skills/docs/documents/scripts/lib/report.mjs +38 -0
  382. package/seed-skills/docs/documents/scripts/lib/sheet.mjs +523 -0
  383. package/seed-skills/docs/documents/scripts/lib/templates.mjs +34 -0
  384. package/seed-skills/docs/documents/scripts/lib/translate.mjs +691 -0
  385. package/seed-skills/docs/documents/scripts/lib/word.mjs +678 -0
  386. package/seed-skills/docs/documents/templates/letter.html +56 -0
  387. package/seed-skills/docs/documents/templates/print.css +219 -0
  388. package/seed-skills/docs/documents/templates/report.html +47 -0
  389. package/seed-skills/docs/documents/templates/resume.html +61 -0
  390. package/seed-skills/insta/instagram/references/post.md +31 -7
  391. package/seed-skills/trip/README.md +11 -0
  392. package/seed-skills/trip/travel/SKILL.md +40 -0
  393. package/seed-skills/trip/travel/page/itinerary.css +488 -0
  394. package/seed-skills/trip/travel/references/itinerary.md +70 -0
  395. package/seed-skills/trip/travel/references/plan.md +75 -0
  396. package/seed-skills/trip/travel/references/watch-and-book.md +39 -0
  397. package/seed-skills/trip/travel/scripts/flights.mjs +374 -0
  398. package/seed-skills/trip/travel/scripts/fx.mjs +57 -0
  399. package/seed-skills/trip/travel/scripts/hotels.mjs +356 -0
  400. package/seed-skills/trip/travel/scripts/itinerary.mjs +482 -0
  401. package/seed-skills/trip/travel/scripts/lib.mjs +120 -0
  402. package/seed-skills/trip/travel/scripts/selectors.mjs +78 -0
  403. package/seed-skills/trip/travel/scripts/watch.mjs +147 -0
  404. package/seed-skills/trip/travel/scripts/weather.mjs +150 -0
  405. package/seed-skills/tutor/picture-book/SKILL.md +6 -0
  406. package/seed-skills/tutor/picture-book/references/picture-book.md +22 -2
  407. package/.next/server/chunks/[root-of-the-server]__014ydvq._.js +0 -8
  408. package/.next/server/chunks/[root-of-the-server]__01d285y._.js +0 -5
  409. package/.next/server/chunks/[root-of-the-server]__04r4h-2._.js +0 -7
  410. package/.next/server/chunks/[root-of-the-server]__0ayldfn._.js +0 -5
  411. package/.next/server/chunks/[root-of-the-server]__17weeeg._.js +0 -5
  412. package/.next/server/chunks/[root-of-the-server]__1ai5lme._.js +0 -8
  413. package/.next/server/chunks/_05v8k21._.js +0 -7
  414. package/.next/server/chunks/_0k6qjcf._.js +0 -5
  415. package/.next/server/chunks/_1d_enhu._.js +0 -3
  416. package/.next/server/chunks/_1jc5g4p._.js +0 -6
  417. package/.next/server/chunks/_1nfr-75._.js +0 -3
  418. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_0md6j0x._.js +0 -3
  419. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_14ih1vy._.js +0 -3
  420. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1d6ez5-._.js +0 -3
  421. package/.next/server/chunks/ssr/[root-of-the-server]__0a967km._.js +0 -3
  422. package/.next/server/chunks/ssr/[root-of-the-server]__0tzekbl._.js +0 -68
  423. package/.next/server/chunks/ssr/[root-of-the-server]__1756892._.js +0 -3
  424. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +0 -3
  425. package/.next/server/chunks/ssr/[root-of-the-server]__1nqw56a._.js +0 -3
  426. package/.next/server/chunks/ssr/[root-of-the-server]__1r77-88._.js +0 -3
  427. package/.next/server/chunks/ssr/[root-of-the-server]__1w9hqq8._.js +0 -8
  428. package/.next/server/chunks/ssr/_05pl_u8._.js +0 -3
  429. package/.next/server/chunks/ssr/_097-ljd._.js +0 -4
  430. package/.next/server/chunks/ssr/_0euzzf8._.js +0 -3
  431. package/.next/server/chunks/ssr/_0evkpto._.js +0 -3
  432. package/.next/server/chunks/ssr/_0igfcax._.js +0 -20
  433. package/.next/server/chunks/ssr/_0lu1n_x._.js +0 -3
  434. package/.next/server/chunks/ssr/_0nvh1h9._.js +0 -3
  435. package/.next/server/chunks/ssr/_0qmpw35._.js +0 -3
  436. package/.next/server/chunks/ssr/_0uv-qs4._.js +0 -3
  437. package/.next/server/chunks/ssr/_132qkfz._.js +0 -5
  438. package/.next/server/chunks/ssr/_15zqt-t._.js +0 -3
  439. package/.next/server/chunks/ssr/_16gfxpn._.js +0 -3
  440. package/.next/server/chunks/ssr/_184327j._.js +0 -3
  441. package/.next/server/chunks/ssr/_18ujhhq._.js +0 -3
  442. package/.next/server/chunks/ssr/_1lx6w_o._.js +0 -67
  443. package/.next/server/chunks/ssr/_1ntpny5._.js +0 -3
  444. package/.next/server/chunks/ssr/_1o1g4uk._.js +0 -5
  445. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  446. package/.next/server/chunks/ssr/_2008vmi._.js +0 -164
  447. package/.next/server/chunks/ssr/features_bot_1n1s7bh._.js +0 -3
  448. package/.next/static/chunks/09pkygbht7ki8.js +0 -18
  449. package/.next/static/chunks/0bm-nhblcmmj4.js +0 -17
  450. package/.next/static/chunks/0c_g4-11sha-1.js +0 -1
  451. package/.next/static/chunks/0hhza87hkbqaz.js +0 -1
  452. package/.next/static/chunks/0samf80yu2b17.js +0 -1
  453. package/.next/static/chunks/0vlgzqo9ka90v.js +0 -1
  454. package/.next/static/chunks/1g9yyvculuxj2.js +0 -1
  455. package/.next/static/chunks/1jz8n0mhtdzr8.js +0 -1
  456. package/.next/static/chunks/206laxm6maiz2.js +0 -1
  457. package/.next/static/chunks/23nfu5g4vl_m7.js +0 -1
  458. package/.next/static/chunks/2h-tlhb2ffhkk.js +0 -1
  459. package/.next/static/chunks/2i5_w8olnrvo0.js +0 -3
  460. package/.next/static/chunks/2m6jd3586ijb-.js +0 -1
  461. package/.next/static/chunks/2m8iqwc6sykln.js +0 -1
  462. package/.next/static/chunks/33fyp-byw48ju.js +0 -65
  463. package/.next/static/chunks/35yd_27d9ylra.js +0 -1
  464. package/.next/static/chunks/3ag1i3__yl94f.js +0 -1
  465. package/.next/static/chunks/3m_ejzg-xn21r.css +0 -1
  466. package/.next/static/chunks/3s-jpd3ky49-n.js +0 -1
  467. package/features/reach/components/reach-state.tsx +0 -71
  468. /package/.next/static/{QSe0rTdXU5kh5BBzr2XBB → fiNGsQfna8qldl8wU8wqr}/_buildManifest.js +0 -0
  469. /package/.next/static/{QSe0rTdXU5kh5BBzr2XBB → fiNGsQfna8qldl8wU8wqr}/_clientMiddlewareManifest.js +0 -0
  470. /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
+ }