thursday-agent 0.16.0 → 0.17.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 (277) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/prerender-manifest.json +3 -3
  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.nft.json +1 -1
  11. package/.next/server/app/_not-found.html +1 -1
  12. package/.next/server/app/_not-found.rsc +1 -1
  13. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/api/artifact/route.js +9 -9
  17. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  18. package/.next/server/app/api/bot/memory/files/route.js +3 -3
  19. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  20. package/.next/server/app/api/bot/memory/route.js +8 -8
  21. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/route.js +8 -8
  23. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/thread/[id]/route.js +3 -3
  25. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -1
  26. package/.next/server/app/api/bot/thread/route.js +3 -3
  27. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -1
  28. package/.next/server/app/api/config/route.js.nft.json +1 -1
  29. package/.next/server/app/api/events/route.js.nft.json +1 -1
  30. package/.next/server/app/api/favicon/[host]/route.js.nft.json +1 -1
  31. package/.next/server/app/api/file/[...path]/route.js +4 -4
  32. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  33. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  34. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  35. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  36. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  37. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  38. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  39. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  40. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  41. package/.next/server/app/api/memory/edit/route.js +11 -11
  42. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  43. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  44. package/.next/server/app/api/reach/route.js +11 -11
  45. package/.next/server/app/api/reach/route.js.nft.json +1 -1
  46. package/.next/server/app/api/routine/route.js +7 -7
  47. package/.next/server/app/api/routine/route.js.nft.json +1 -1
  48. package/.next/server/app/api/signins/route.js +5 -5
  49. package/.next/server/app/api/signins/route.js.nft.json +1 -1
  50. package/.next/server/app/api/skills/[source]/[name]/route.js +7 -7
  51. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/skills/route.js +7 -7
  53. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  54. package/.next/server/app/api/thursday/call/route.js +5 -5
  55. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  56. package/.next/server/app/api/thursday/settings/route.js +5 -5
  57. package/.next/server/app/api/thursday/settings/route.js.nft.json +1 -1
  58. package/.next/server/app/api/thursday/text/route.js +13 -13
  59. package/.next/server/app/api/thursday/text/route.js.nft.json +1 -1
  60. package/.next/server/app/api/thursday/tool-call/route.js +12 -12
  61. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  62. package/.next/server/app/api/workspace/files/route.js +8 -8
  63. package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
  64. package/.next/server/app/api/workspace/route.js +9 -9
  65. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  66. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +3 -3
  67. package/.next/server/app/artifact/[...path]/page.js +4 -4
  68. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  69. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  70. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  71. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  72. package/.next/server/app/page/server-reference-manifest.json +60 -60
  73. package/.next/server/app/page.js +5 -5
  74. package/.next/server/app/page.js.nft.json +1 -1
  75. package/.next/server/app/page_client-reference-manifest.js +1 -1
  76. package/.next/server/chunks/[root-of-the-server]__00qyw01._.js +1 -1
  77. package/.next/server/chunks/[root-of-the-server]__01ypm_z._.js +3 -0
  78. package/.next/server/chunks/[root-of-the-server]__021dkui._.js +3 -0
  79. package/.next/server/chunks/{[root-of-the-server]__18e65_-._.js → [root-of-the-server]__03xamry._.js} +2 -2
  80. package/.next/server/chunks/[root-of-the-server]__05dp5tr._.js +1 -1
  81. package/.next/server/chunks/[root-of-the-server]__09gdscj._.js +7 -0
  82. package/.next/server/chunks/{[root-of-the-server]__10_7vqz._.js → [root-of-the-server]__0b36yfw._.js} +1 -1
  83. package/.next/server/chunks/{[root-of-the-server]__1gamvcz._.js → [root-of-the-server]__0jzwdg-._.js} +2 -2
  84. package/.next/server/chunks/[root-of-the-server]__0mrk2it._.js +1 -1
  85. package/.next/server/chunks/[root-of-the-server]__0nmust6._.js +5 -0
  86. package/.next/server/chunks/[root-of-the-server]__0svzjwa._.js +7 -0
  87. package/.next/server/chunks/{[root-of-the-server]__16yw3mb._.js → [root-of-the-server]__12m24xl._.js} +1 -1
  88. package/.next/server/chunks/{[root-of-the-server]__1zrwxis._.js → [root-of-the-server]__12tahb4._.js} +1 -1
  89. package/.next/server/chunks/{[root-of-the-server]__1ep-pao._.js → [root-of-the-server]__1_h4hf9._.js} +4 -4
  90. package/.next/server/chunks/{[root-of-the-server]__1-tdj60._.js → [root-of-the-server]__1de1o6m._.js} +2 -2
  91. package/.next/server/chunks/{[root-of-the-server]__1voqqyc._.js → [root-of-the-server]__1ignh6-._.js} +1 -1
  92. package/.next/server/chunks/[root-of-the-server]__1t02-1p._.js +3 -0
  93. package/.next/server/chunks/[root-of-the-server]__1ygplx1._.js +1 -1
  94. package/.next/server/chunks/{[root-of-the-server]__11g20j-._.js → [root-of-the-server]__1yl5l25._.js} +1 -1
  95. package/.next/server/chunks/{[root-of-the-server]__1mbd2w_._.js → [root-of-the-server]__208vmyf._.js} +1 -1
  96. package/.next/server/chunks/{_1mfu9a3._.js → _02lipqs._.js} +1 -1
  97. package/.next/server/chunks/_05sa7xl._.js +1 -1
  98. package/.next/server/chunks/{_1rg5bfd._.js → _074f2ts._.js} +1 -1
  99. package/.next/server/chunks/_07nxi75._.js +3 -3
  100. package/.next/server/chunks/_08btiir._.js +7 -0
  101. package/.next/server/chunks/_0caua_s._.js +1 -1
  102. package/.next/server/chunks/{_0qoush_._.js → _0gt6cbj._.js} +1 -1
  103. package/.next/server/chunks/_0xygcxs._.js +3 -3
  104. package/.next/server/chunks/{_09c4we8._.js → _17i1lt2._.js} +1 -1
  105. package/.next/server/chunks/_19kea1l._.js +9 -9
  106. package/.next/server/chunks/_1gn2r2q._.js +3 -3
  107. package/.next/server/chunks/{_03niwml._.js → _1ntwp1s._.js} +1 -1
  108. package/.next/server/chunks/_1q6e56i._.js +3 -3
  109. package/.next/server/chunks/{_02fn1o3._.js → _1tkzgtm._.js} +1 -1
  110. package/.next/server/chunks/_1wl2g8_._.js +2 -2
  111. package/.next/server/chunks/{_1w6uf9k._.js → _1y3mnz4._.js} +1 -1
  112. package/.next/server/chunks/features_workspace_workspace_ts_13h82gv._.js +4 -4
  113. package/.next/server/chunks/features_workspace_workspace_ts_1iyjroj._.js +4 -4
  114. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0cux6zt._.js → node_modules_consola_dist_chunks_prompt_mjs_04oxl25._.js} +1 -1
  115. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0w32bqh._.js → node_modules_consola_dist_chunks_prompt_mjs_0g87zst._.js} +1 -1
  116. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_1clmnaj._.js → node_modules_consola_dist_chunks_prompt_mjs_1341cnf._.js} +1 -1
  117. package/.next/server/chunks/ssr/{[root-of-the-server]__02jdtqa._.js → [root-of-the-server]__07660xu._.js} +2 -2
  118. package/.next/server/chunks/ssr/{[root-of-the-server]__0rnjkw2._.js → [root-of-the-server]__149x25m._.js} +2 -2
  119. package/.next/server/chunks/ssr/[root-of-the-server]__17h1ggo._.js +1 -1
  120. package/.next/server/chunks/ssr/[root-of-the-server]__19s8qyj._.js +3 -0
  121. package/.next/server/chunks/ssr/[root-of-the-server]__1jyeu61._.js +1 -1
  122. package/.next/server/chunks/ssr/_088vzgn._.js +3 -0
  123. package/.next/server/chunks/ssr/{_0wupyvd._.js → _0_vnw9v._.js} +2 -2
  124. package/.next/server/chunks/ssr/{_1u5vsy-._.js → _0aeknva._.js} +2 -2
  125. package/.next/server/chunks/ssr/_0fo4552._.js +3 -3
  126. package/.next/server/chunks/ssr/{_0-ou1b0._.js → _0n2scfq._.js} +2 -2
  127. package/.next/server/chunks/ssr/_0o_o9ji._.js +3 -0
  128. package/.next/server/chunks/ssr/_0qne8xs._.js +3 -0
  129. package/.next/server/chunks/ssr/_0r0g9ki._.js +1 -1
  130. package/.next/server/chunks/ssr/_0v9r8g2._.js +3 -0
  131. package/.next/server/chunks/ssr/_0x8ophf._.js +1 -1
  132. package/.next/server/chunks/ssr/{_0ncuqct._.js → _0ztbn5q._.js} +2 -2
  133. package/.next/server/chunks/ssr/{_0w8r7o7._.js → _1-41lck._.js} +2 -2
  134. package/.next/server/chunks/ssr/{_10fwcz_._.js → _14dfh7a._.js} +2 -2
  135. package/.next/server/chunks/ssr/{_1f6s34p._.js → _15m5ctz._.js} +2 -2
  136. package/.next/server/chunks/ssr/{_11pnnvd._.js → _18-e7zi._.js} +2 -2
  137. package/.next/server/chunks/ssr/{_0y28gl3._.js → _1c5iqz1._.js} +3 -3
  138. package/.next/server/chunks/ssr/{_1dqaksc._.js → _1hbjh6n._.js} +2 -2
  139. package/.next/server/chunks/ssr/_1neoj22._.js +1 -1
  140. package/.next/server/chunks/ssr/{_1k0efi3._.js → _1sttj8x._.js} +2 -2
  141. package/.next/server/chunks/ssr/_1uij_rj._.js +1 -1
  142. package/.next/server/chunks/ssr/_1umbr78._.js +1 -1
  143. package/.next/server/chunks/ssr/{_17ble8k._.js → _1vtgiou._.js} +3 -3
  144. package/.next/server/chunks/ssr/_1w9w1ok._.js +1 -1
  145. package/.next/server/chunks/ssr/{_1z586yw._.js → _1z6pirx._.js} +2 -2
  146. package/.next/server/chunks/ssr/features_0796o8r._.js +1 -1
  147. package/.next/server/chunks/ssr/features_bot_1knyan7._.js +3 -0
  148. package/.next/server/chunks/ssr/features_bot_1kr0_m-._.js +3 -0
  149. package/.next/server/chunks/ssr/{features_config_11dpa7r._.js → features_config_0n0zu89._.js} +3 -3
  150. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  151. package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +1 -1
  152. package/.next/server/chunks/ssr/features_routine_components_routine-setting_tsx_055fknz._.js +1 -1
  153. package/.next/server/chunks/ssr/features_workspace_workspace_ts_1wc7_u_._.js +4 -4
  154. package/.next/server/chunks/ssr/{node_modules_1r5o-bo._.js → node_modules_00h1t1j._.js} +1 -1
  155. package/.next/server/chunks/ssr/{node_modules_1o9n7_n._.js → node_modules_02ficyi._.js} +1 -1
  156. package/.next/server/chunks/ssr/{node_modules_0u24mg0._.js → node_modules_03q71_j._.js} +1 -1
  157. package/.next/server/chunks/ssr/{node_modules_138kcrz._.js → node_modules_03uejh6._.js} +1 -1
  158. package/.next/server/chunks/ssr/{node_modules_0x_2io2._.js → node_modules_06grs09._.js} +1 -1
  159. package/.next/server/chunks/ssr/{node_modules_0n1js5k._.js → node_modules_07mo9rn._.js} +1 -1
  160. package/.next/server/chunks/ssr/{node_modules_0bas34k._.js → node_modules_09e8kz_._.js} +1 -1
  161. package/.next/server/chunks/ssr/{node_modules_1dzye0n._.js → node_modules_09ikzel._.js} +1 -1
  162. package/.next/server/chunks/ssr/{node_modules_18yn_bs._.js → node_modules_0_d_7gq._.js} +1 -1
  163. package/.next/server/chunks/ssr/{node_modules_0ka8te1._.js → node_modules_0_p8w7p._.js} +1 -1
  164. package/.next/server/chunks/ssr/{node_modules_0mark4f._.js → node_modules_0f5bmkb._.js} +1 -1
  165. package/.next/server/chunks/ssr/{node_modules_0sdjzae._.js → node_modules_0kwie-o._.js} +1 -1
  166. package/.next/server/chunks/ssr/{node_modules_1ozyial._.js → node_modules_0r-9e4n._.js} +1 -1
  167. package/.next/server/chunks/ssr/{node_modules_156m1qh._.js → node_modules_0u_8z64._.js} +1 -1
  168. package/.next/server/chunks/ssr/{node_modules_0-ew8f8._.js → node_modules_0zf3wuu._.js} +1 -1
  169. package/.next/server/chunks/ssr/{node_modules_1xua-g1._.js → node_modules_1-7fc7h._.js} +1 -1
  170. package/.next/server/chunks/ssr/{node_modules_0ld7p-1._.js → node_modules_142z3o5._.js} +1 -1
  171. package/.next/server/chunks/ssr/{node_modules_0-8r9yw._.js → node_modules_180l3i0._.js} +1 -1
  172. package/.next/server/chunks/ssr/{node_modules_1tj7_9z._.js → node_modules_197vh1s._.js} +1 -1
  173. package/.next/server/chunks/ssr/{node_modules_0y5uubt._.js → node_modules_1_n9o9s._.js} +1 -1
  174. package/.next/server/chunks/ssr/{node_modules_0etz1i0._.js → node_modules_1fw32pg._.js} +1 -1
  175. package/.next/server/chunks/ssr/{node_modules_0bbwe-u._.js → node_modules_1hefp6h._.js} +1 -1
  176. package/.next/server/chunks/ssr/{node_modules_097cl9f._.js → node_modules_1irot3r._.js} +1 -1
  177. package/.next/server/chunks/ssr/{node_modules_0uibk9z._.js → node_modules_1om2itc._.js} +1 -1
  178. package/.next/server/chunks/ssr/{node_modules_1zkzksd._.js → node_modules_1ubln7w._.js} +1 -1
  179. package/.next/server/chunks/ssr/{node_modules_02uwbwp._.js → node_modules_1wyhtw9._.js} +1 -1
  180. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_133hjui._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0aczkbn._.js} +1 -1
  181. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1b3vwd3._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0ah684s._.js} +1 -1
  182. package/.next/server/middleware-build-manifest.js +3 -3
  183. package/.next/server/pages/404.html +1 -1
  184. package/.next/server/pages/500.html +1 -1
  185. package/.next/server/server-reference-manifest.js +1 -1
  186. package/.next/server/server-reference-manifest.json +61 -61
  187. package/.next/static/chunks/{1ub9obhgfm4jl.js → 024plctckvq-1.js} +1 -1
  188. package/.next/static/chunks/04toe_3nqfjqt.js +1 -0
  189. package/.next/static/chunks/{0609ejkwuy4sf.js → 0_b_bi2pobasx.js} +2 -2
  190. package/.next/static/chunks/{3ro66d9dc70bc.js → 0dfvwgnyrp8qt.js} +1 -1
  191. package/.next/static/chunks/{314szf8yer-3n.js → 0f47nnshdlucs.js} +1 -1
  192. package/.next/static/chunks/0sowxe4nnl5qu.js +1 -0
  193. package/.next/static/chunks/{07vcuxousbmy1.js → 0sv142q1yrva2.js} +1 -1
  194. package/.next/static/chunks/{0q4ws7qd21chx.js → 0tp868040z9nn.js} +2 -2
  195. package/.next/static/chunks/{0unonxbajyknw.js → 1-63yde5eaz7i.js} +1 -1
  196. package/.next/static/chunks/14qitm0kwsb6g.js +15 -0
  197. package/.next/static/chunks/{2xjr5b-yk_h3o.js → 1bgvxd3xny53w.js} +1 -1
  198. package/.next/static/chunks/{245_cp14iz637.js → 1cyrrz4q871aj.js} +1 -1
  199. package/.next/static/chunks/1st3b0c9vhxg3.js +1 -0
  200. package/.next/static/chunks/{39miwvg4k-b2d.js → 1wbqaidq7vc3_.js} +1 -1
  201. package/.next/static/chunks/{0cl_fgkphk1oz.js → 28sxb_k460e9h.js} +1 -1
  202. package/.next/static/chunks/{3j-l8un0d77v7.js → 2v6e_9p95o2e3.js} +1 -1
  203. package/.next/static/chunks/{23tx-2paw9qa6.js → 3-qp777vtfglj.js} +1 -1
  204. package/.next/static/chunks/{2jbjyazqfqyoh.js → 33ekkscpcq-z1.js} +1 -1
  205. package/.next/static/chunks/388l-zszwa_jf.js +1 -0
  206. package/.next/static/chunks/{3vwjs5kq11417.js → 38edd4rpcbvzp.js} +1 -1
  207. package/.next/static/chunks/3bwrvpjk95_x4.js +1 -0
  208. package/.next/static/chunks/{42m371fn687r5.js → 3itdg6t243u6f.js} +1 -1
  209. package/.next/static/chunks/{2oa4gpkzjtpni.js → 44vre0f7xqsh-.js} +1 -1
  210. package/README.md +12 -12
  211. package/guide/bots.md +48 -8
  212. package/guide/calls.md +13 -12
  213. package/guide/setup.md +4 -2
  214. package/package.json +1 -1
  215. package/public/sounds/NOTICE +3 -0
  216. package/public/sounds/opening-land.ogg +0 -0
  217. package/public/sounds/opening-rise.ogg +0 -0
  218. package/public/sounds/opening-step-1.ogg +0 -0
  219. package/public/sounds/opening-step-2.ogg +0 -0
  220. package/public/sounds/opening-step-3.ogg +0 -0
  221. package/skills/README.md +3 -0
  222. package/skills/artifact/SKILL.md +6 -5
  223. package/skills/artifact/references/book.md +22 -8
  224. package/skills/artifact/references/deck.md +4 -2
  225. package/skills/artifact/references/document.md +9 -0
  226. package/skills/artifact/references/sheet.md +108 -0
  227. package/skills/artifact/runtime/book/book.css +75 -0
  228. package/skills/artifact/runtime/book/book.html +6 -3
  229. package/skills/artifact/runtime/book/book.js +21 -0
  230. package/skills/artifact/runtime/canvas/canvas.css +1 -1
  231. package/skills/artifact/runtime/canvas/canvas.js +11 -1
  232. package/skills/artifact/runtime/deck/deck.css +164 -1
  233. package/skills/artifact/runtime/deck/deck.js +76 -1
  234. package/skills/artifact/runtime/document/docx.js +631 -0
  235. package/skills/artifact/runtime/document/markdown.mjs +58 -2
  236. package/skills/artifact/runtime/document/quick.css +66 -0
  237. package/skills/artifact/runtime/document/quick.html +1 -0
  238. package/skills/artifact/runtime/document/quick.js +154 -0
  239. package/skills/artifact/runtime/document/word.mjs +65 -0
  240. package/skills/artifact/runtime/sheet/format.mjs +385 -0
  241. package/skills/artifact/runtime/sheet/formula.mjs +755 -0
  242. package/skills/artifact/runtime/sheet/sheet.css +499 -0
  243. package/skills/artifact/runtime/sheet/sheet.html +102 -0
  244. package/skills/artifact/runtime/sheet/sheet.js +1361 -0
  245. package/skills/artifact/runtime/sheet/xlsx.mjs +320 -0
  246. package/skills/artifact/runtime/shell/head.html +1 -1
  247. package/skills/artifact/runtime/shell/shell.css +3 -0
  248. package/skills/artifact/runtime/shell/wear.mjs +47 -1
  249. package/skills/artifact/runtime/vendor/fflate.LICENSE.md +23 -0
  250. package/skills/artifact/runtime/vendor/fflate.mjs +2710 -0
  251. package/skills/artifact/scripts/book.mjs +141 -5
  252. package/skills/artifact/scripts/chart.mjs +229 -11
  253. package/skills/artifact/scripts/document.mjs +29 -2
  254. package/skills/artifact/scripts/spreadsheet.mjs +1068 -0
  255. package/skills/data-report/SKILL.md +8 -1
  256. package/.next/server/chunks/[root-of-the-server]__0aijj66._.js +0 -3
  257. package/.next/server/chunks/[root-of-the-server]__0tvoct-._.js +0 -3
  258. package/.next/server/chunks/[root-of-the-server]__118qjk_._.js +0 -7
  259. package/.next/server/chunks/[root-of-the-server]__1b8tp42._.js +0 -5
  260. package/.next/server/chunks/[root-of-the-server]__1gzcbda._.js +0 -3
  261. package/.next/server/chunks/[root-of-the-server]__1qcn1ti._.js +0 -7
  262. package/.next/server/chunks/_0xx3ryc._.js +0 -7
  263. package/.next/server/chunks/ssr/[root-of-the-server]__1y5_1cv._.js +0 -3
  264. package/.next/server/chunks/ssr/_0l1-xc6._.js +0 -3
  265. package/.next/server/chunks/ssr/_1g48r6t._.js +0 -3
  266. package/.next/server/chunks/ssr/features_bot_1k25jdg._.js +0 -3
  267. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  268. package/.next/server/chunks/ssr/lib_utils_ts_0_f1xvm._.js +0 -3
  269. package/.next/static/chunks/00d54fcfm-lko.js +0 -1
  270. package/.next/static/chunks/0gjlsu6vrfzod.js +0 -1
  271. package/.next/static/chunks/17yqt1p_svv13.js +0 -1
  272. package/.next/static/chunks/203pbwecfs3tm.js +0 -1
  273. package/.next/static/chunks/3ghvoe_mlljzs.js +0 -15
  274. package/.next/static/chunks/3gn7dubb4-pwy.js +0 -1
  275. /package/.next/static/{RtLRT9EEaGn-OqwpMFdYg → VtbCMn-0G969p8QJsWdGv}/_buildManifest.js +0 -0
  276. /package/.next/static/{RtLRT9EEaGn-OqwpMFdYg → VtbCMn-0G969p8QJsWdGv}/_clientMiddlewareManifest.js +0 -0
  277. /package/.next/static/{RtLRT9EEaGn-OqwpMFdYg → VtbCMn-0G969p8QJsWdGv}/_ssgManifest.js +0 -0
@@ -0,0 +1,320 @@
1
+ // A workbook as an .xlsx file and back, with no spreadsheet library: an .xlsx is a zip of a few
2
+ // XML files (Office Open XML, ECMA-376), and fflate zips. Written: the sheets, each a header row,
3
+ // its rows and a totals row; numbers, text, booleans and formulas with the value each holds;
4
+ // the header bold and frozen with a filter on it, column widths, number formats. Read: every
5
+ // sheet's cells, the value Excel last stored for each formula and the formula when it is
6
+ // written out, dates as Excel's day numbers with their format, column widths and number formats.
7
+ import { strFromU8, strToU8, unzipSync, zipSync } from "../vendor/fflate.mjs";
8
+ import { checkFormat, xlsxFormat } from "./format.mjs";
9
+ import { colIndex, colName } from "./formula.mjs";
10
+
11
+ const xml = (text) =>
12
+ String(text)
13
+ // Characters XML 1.0 cannot hold at all
14
+ .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\ufffe\uffff]/g, "")
15
+ .replaceAll("&", "&")
16
+ .replaceAll("<", "&lt;")
17
+ .replaceAll(">", "&gt;")
18
+ .replaceAll('"', "&quot;");
19
+ const unxml = (text) =>
20
+ text
21
+ .replace(/_x([0-9A-Fa-f]{4})_/g, (_, hex) =>
22
+ String.fromCharCode(Number.parseInt(hex, 16)),
23
+ )
24
+ .replaceAll("&lt;", "<")
25
+ .replaceAll("&gt;", ">")
26
+ .replaceAll("&quot;", '"')
27
+ .replaceAll("&apos;", "'")
28
+ .replace(/&#(\d+);/g, (_, n) => String.fromCodePoint(Number(n)))
29
+ .replace(/&#x([0-9a-f]+);/gi, (_, n) =>
30
+ String.fromCodePoint(Number.parseInt(n, 16)),
31
+ )
32
+ .replaceAll("&amp;", "&");
33
+
34
+ const MAIN = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
35
+ const REL =
36
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
37
+ const PKG = "http://schemas.openxmlformats.org/package/2006/relationships";
38
+
39
+ /** A sheet's name quoted for a formula or a defined name. */
40
+ export const sheetRef = (name) => `'${name.replaceAll("'", "''")}'`;
41
+
42
+ /**
43
+ * The .xlsx of `book`: `{ sheets: [{ name, columns: [{ name, width, format }], cells, totals }] }`,
44
+ * `cells` rows of `{ v, f }` with row 0 the header, `totals` the index of the totals row or null.
45
+ * `width` is in characters, as Excel counts them.
46
+ */
47
+ export function writeXlsx(book) {
48
+ // Formats and looks as Excel indexes them: each distinct one once
49
+ const formats = [];
50
+ const formatId = (code) => {
51
+ const kept = xlsxFormat(code);
52
+ if (kept === "General") return 0;
53
+ const builtIn = {
54
+ 0: 1,
55
+ "0.00": 2,
56
+ "#,##0": 3,
57
+ "#,##0.00": 4,
58
+ "0%": 9,
59
+ "0.00%": 10,
60
+ }[kept];
61
+ if (builtIn) return builtIn;
62
+ let at = formats.indexOf(kept);
63
+ if (at === -1) at = formats.push(kept) - 1;
64
+ return 164 + at;
65
+ };
66
+ const looks = ["0|0|0|0"];
67
+ const look = (fmt, bold, fill, line) => {
68
+ const key = `${fmt}|${bold ? 1 : 0}|${fill ? 1 : 0}|${line ? 1 : 0}`;
69
+ let at = looks.indexOf(key);
70
+ if (at === -1) at = looks.push(key) - 1;
71
+ return at;
72
+ };
73
+
74
+ const sheetXml = book.sheets.map((sheet) => {
75
+ const ids = sheet.columns.map((column) => formatId(column.format));
76
+ const last = sheet.cells.length;
77
+ const width = sheet.columns.length;
78
+ const rows = sheet.cells.map((row, r) => {
79
+ const head = r === 0;
80
+ const total = r === sheet.totals;
81
+ const cells = row.map((cell, c) => {
82
+ const ref = `${colName(c)}${r + 1}`;
83
+ const s = look(head ? 0 : ids[c], head || total, head, total);
84
+ const style = s ? ` s="${s}"` : "";
85
+ const { v, f } = cell ?? {};
86
+ const formula =
87
+ f !== undefined ? `<f>${xml(String(f).replace(/^=/, ""))}</f>` : "";
88
+ if (v === null || v === undefined || v === "")
89
+ return formula
90
+ ? `<c r="${ref}"${style}>${formula}</c>`
91
+ : style
92
+ ? `<c r="${ref}"${style}/>`
93
+ : "";
94
+ if (typeof v === "object" && "error" in v)
95
+ return `<c r="${ref}"${style} t="e">${formula}<v>${xml(v.error)}</v></c>`;
96
+ if (typeof v === "number")
97
+ return `<c r="${ref}"${style}>${formula}<v>${v}</v></c>`;
98
+ if (typeof v === "boolean")
99
+ return `<c r="${ref}"${style} t="b">${formula}<v>${v ? 1 : 0}</v></c>`;
100
+ if (formula)
101
+ return `<c r="${ref}"${style} t="str">${formula}<v>${xml(v)}</v></c>`;
102
+ return `<c r="${ref}"${style} t="inlineStr"><is><t xml:space="preserve">${xml(v)}</t></is></c>`;
103
+ });
104
+ return `<row r="${r + 1}">${cells.join("")}</row>`;
105
+ });
106
+ const cols = sheet.columns
107
+ .map(
108
+ (column, c) =>
109
+ `<col min="${c + 1}" max="${c + 1}" width="${column.width}" customWidth="1"/>`,
110
+ )
111
+ .join("");
112
+ const dataEnd = sheet.totals ?? last;
113
+ const filter =
114
+ width && dataEnd > 1
115
+ ? `<autoFilter ref="A1:${colName(width - 1)}${dataEnd}"/>`
116
+ : "";
117
+ return {
118
+ filter: filter
119
+ ? `${sheetRef(sheet.name)}!$A$1:$${colName(width - 1)}$${dataEnd}`
120
+ : null,
121
+ text: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
122
+ <worksheet xmlns="${MAIN}" xmlns:r="${REL}"><sheetViews><sheetView workbookViewId="0"${book.sheets.indexOf(sheet) === 0 ? ' tabSelected="1"' : ""}><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/><selection pane="bottomLeft" activeCell="A2" sqref="A2"/></sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>${cols ? `<cols>${cols}</cols>` : ""}<sheetData>${rows.join("")}</sheetData>${filter}</worksheet>`,
123
+ };
124
+ });
125
+
126
+ const numFmts = formats.length
127
+ ? `<numFmts count="${formats.length}">${formats.map((code, i) => `<numFmt numFmtId="${164 + i}" formatCode="${xml(code)}"/>`).join("")}</numFmts>`
128
+ : "";
129
+ const xfs = looks.map((key) => {
130
+ const [fmt, bold, fill, line] = key.split("|").map(Number);
131
+ return `<xf numFmtId="${fmt}" fontId="${bold}" fillId="${fill ? 2 : 0}" borderId="${line}" xfId="0"${fmt ? ' applyNumberFormat="1"' : ""}${bold ? ' applyFont="1"' : ""}${fill ? ' applyFill="1"' : ""}${line ? ' applyBorder="1"' : ""}/>`;
132
+ });
133
+ const styles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
134
+ <styleSheet xmlns="${MAIN}">${numFmts}<fonts count="2"><font><sz val="11"/><name val="Calibri"/><family val="2"/></font><font><b/><sz val="11"/><name val="Calibri"/><family val="2"/></font></fonts><fills count="3"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FFF2F4F7"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="2"><border><left/><right/><top/><bottom/><diagonal/></border><border><left/><right/><top style="thin"><color rgb="FF8C959F"/></top><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="${xfs.length}">${xfs.join("")}</cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
135
+
136
+ const names = sheetXml
137
+ .map((s, i) =>
138
+ s.filter
139
+ ? `<definedName name="_xlnm._FilterDatabase" localSheetId="${i}" hidden="1">${xml(s.filter)}</definedName>`
140
+ : "",
141
+ )
142
+ .join("");
143
+ const workbook = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
144
+ <workbook xmlns="${MAIN}" xmlns:r="${REL}"><bookViews><workbookView/></bookViews><sheets>${book.sheets.map((s, i) => `<sheet name="${xml(s.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`).join("")}</sheets>${names ? `<definedNames>${names}</definedNames>` : ""}<calcPr calcId="191029" fullCalcOnLoad="1"/></workbook>`;
145
+ const n = book.sheets.length;
146
+ const files = {
147
+ "[Content_Types].xml": `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
148
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>${book.sheets.map((_, i) => `<Override PartName="/xl/worksheets/sheet${i + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`).join("")}<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>`,
149
+ "_rels/.rels": `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
150
+ <Relationships xmlns="${PKG}"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`,
151
+ "xl/workbook.xml": workbook,
152
+ "xl/_rels/workbook.xml.rels": `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
153
+ <Relationships xmlns="${PKG}">${book.sheets.map((_, i) => `<Relationship Id="rId${i + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${i + 1}.xml"/>`).join("")}<Relationship Id="rId${n + 1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>`,
154
+ "xl/styles.xml": styles,
155
+ };
156
+ sheetXml.forEach((s, i) => {
157
+ files[`xl/worksheets/sheet${i + 1}.xml`] = s.text;
158
+ });
159
+ return zipSync(
160
+ Object.fromEntries(
161
+ Object.entries(files).map(([path, text]) => [path, strToU8(text)]),
162
+ ),
163
+ { level: 6, mtime: new Date("2026-01-01T00:00:00Z") },
164
+ );
165
+ }
166
+
167
+ // ── reading one ────────────────────────────────────────────────────────────
168
+
169
+ const attr = (tag, name) => {
170
+ const m = new RegExp(`\\s${name}="([^"]*)"`).exec(tag);
171
+ return m ? unxml(m[1]) : null;
172
+ };
173
+ /** Every piece of text inside `inside` (a shared string, an inline one, rich text or not). */
174
+ const texts = (inside) =>
175
+ [...inside.matchAll(/<t(?:\s[^>]*)?>([\s\S]*?)<\/t>/g)]
176
+ .map((m) => unxml(m[1]))
177
+ .join("");
178
+
179
+ /**
180
+ * Excel's own date and time formats by their number, as codes this sheet draws: the ones that
181
+ * follow the reader's locale in Excel are written the one way everywhere.
182
+ */
183
+ const BUILTIN_DATES = {
184
+ 14: "yyyy-mm-dd",
185
+ 15: "d-mmm-yy",
186
+ 16: "d-mmm",
187
+ 17: "mmm-yy",
188
+ 18: "h:mm AM/PM",
189
+ 19: "h:mm:ss AM/PM",
190
+ 20: "h:mm",
191
+ 21: "h:mm:ss",
192
+ 22: "yyyy-mm-dd h:mm",
193
+ 27: "yyyy-mm-dd",
194
+ 30: "yyyy-mm-dd",
195
+ 36: "yyyy-mm-dd",
196
+ 45: "mm:ss",
197
+ 46: "h:mm:ss",
198
+ 47: "mm:ss",
199
+ 50: "yyyy-mm-dd",
200
+ 57: "yyyy-mm-dd",
201
+ };
202
+
203
+ /**
204
+ * An .xlsx read back: `{ sheets: [{ name, rows, widths, formats }] }`, `rows` of `{ v, f }` with
205
+ * the value Excel stored and the formula when it is written out (a shared one's copies carry
206
+ * the value alone), `widths` in characters and `formats` each column's first format code.
207
+ */
208
+ export function readXlsx(bytes) {
209
+ let files;
210
+ try {
211
+ files = unzipSync(bytes);
212
+ } catch {
213
+ throw new Error(
214
+ "It is not an .xlsx file: it does not open as one (an old .xls, or a damaged file?).",
215
+ );
216
+ }
217
+ const text = (path) => (files[path] ? strFromU8(files[path]) : null);
218
+ const workbook = text("xl/workbook.xml");
219
+ if (!workbook)
220
+ throw new Error("It is not an .xlsx file: it has no workbook in it.");
221
+ const rels = new Map(
222
+ [
223
+ ...(text("xl/_rels/workbook.xml.rels") ?? "").matchAll(
224
+ /<Relationship\b[^>]*>/g,
225
+ ),
226
+ ].map((m) => [attr(m[0], "Id"), attr(m[0], "Target")]),
227
+ );
228
+ const shared = [
229
+ ...(text("xl/sharedStrings.xml") ?? "").matchAll(/<si>([\s\S]*?)<\/si>/g),
230
+ ].map((m) => texts(m[1]));
231
+ const stylesXml = text("xl/styles.xml") ?? "";
232
+ const codes = new Map(
233
+ [...stylesXml.matchAll(/<numFmt\b[^>]*>/g)].map((m) => [
234
+ Number(attr(m[0], "numFmtId")),
235
+ attr(m[0], "formatCode"),
236
+ ]),
237
+ );
238
+ const xfBlock =
239
+ /<cellXfs\b[^>]*>([\s\S]*?)<\/cellXfs>/.exec(stylesXml)?.[1] ?? "";
240
+ const xfFormats = [...xfBlock.matchAll(/<xf\b[^>]*>/g)].map((m) =>
241
+ Number(attr(m[0], "numFmtId") ?? 0),
242
+ );
243
+ const isDate = (id) =>
244
+ id in BUILTIN_DATES ||
245
+ /[ydh]/i.test(
246
+ (codes.get(id) ?? "")
247
+ .replace(/"[^"]*"/g, "")
248
+ .replace(/\[[^\]]*\]/g, "")
249
+ .replace(/\\./g, ""),
250
+ );
251
+ // A date's own code when the sheet draws it, else a date all the same: never a bare number
252
+ const codeOf = (id) => {
253
+ const code =
254
+ BUILTIN_DATES[id] ??
255
+ { 1: "0", 2: "0.00", 3: "#,##0", 4: "#,##0.00", 9: "0%", 10: "0.00%" }[
256
+ id
257
+ ] ??
258
+ codes.get(id) ??
259
+ null;
260
+ if (!isDate(id) || (code && !checkFormat(code))) return code;
261
+ // Hours counted past a day ([h]:mm) are a length of time, not a date: left a number
262
+ if (/\[[hms]+\]/i.test(code ?? "")) return null;
263
+ return /h/i.test(code ?? "") ? "yyyy-mm-dd hh:mm" : "yyyy-mm-dd";
264
+ };
265
+
266
+ const sheets = [...workbook.matchAll(/<sheet\b[^>]*>/g)].map((m) => {
267
+ const name = attr(m[0], "name");
268
+ const target = rels.get(attr(m[0], "r:id")) ?? "";
269
+ const path = target.startsWith("/")
270
+ ? target.slice(1)
271
+ : `xl/${target.replace(/^\.\//, "")}`;
272
+ const body = text(path) ?? "";
273
+ const rows = [];
274
+ const formats = [];
275
+ for (const cell of body.matchAll(/<c\b([^>]*?)(?:\/>|>([\s\S]*?)<\/c>)/g)) {
276
+ const ref = attr(cell[1], "r");
277
+ const at = ref && /^([A-Z]+)(\d+)$/.exec(ref);
278
+ if (!at) continue;
279
+ const [r, c] = [Number(at[2]) - 1, colIndex(at[1])];
280
+ const type = attr(cell[1], "t");
281
+ const styleId = xfFormats[Number(attr(cell[1], "s") ?? 0)] ?? 0;
282
+ const inside = cell[2] ?? "";
283
+ const raw = /<v>([\s\S]*?)<\/v>/.exec(inside)?.[1];
284
+ const f = /<f(?:\s[^>]*)?>([\s\S]*?)<\/f>/.exec(inside)?.[1];
285
+ let v = null;
286
+ if (type === "s") v = shared[Number(raw)] ?? null;
287
+ else if (type === "inlineStr") v = texts(inside);
288
+ else if (type === "str") v = raw === undefined ? null : unxml(raw);
289
+ else if (type === "b") v = raw === "1";
290
+ else if (type === "e")
291
+ v = raw === undefined ? null : { error: unxml(raw) };
292
+ else if (raw !== undefined) {
293
+ v = Number(raw);
294
+ }
295
+ rows[r] ??= [];
296
+ rows[r][c] = { v, ...(f ? { f: `=${unxml(f)}` } : {}) };
297
+ if (r > 0 && formats[c] === undefined && typeof v === "number")
298
+ formats[c] = codeOf(styleId);
299
+ }
300
+ const widths = [];
301
+ for (const col of body.matchAll(/<col\b[^>]*>/g)) {
302
+ const width = Number(attr(col[0], "width"));
303
+ for (
304
+ let c = Number(attr(col[0], "min"));
305
+ c <= Number(attr(col[0], "max")) && c <= 200;
306
+ c++
307
+ )
308
+ widths[c - 1] = width;
309
+ }
310
+ // Rows with nothing in them are holes in `rows`, which map() would skip
311
+ let wide = 0;
312
+ for (let r = 0; r < rows.length; r++)
313
+ wide = Math.max(wide, rows[r]?.length ?? 0);
314
+ const full = Array.from({ length: rows.length }, (_, r) =>
315
+ Array.from({ length: wide }, (_, c) => rows[r]?.[c] ?? { v: null }),
316
+ );
317
+ return { name, rows: full, widths, formats };
318
+ });
319
+ return { sheets };
320
+ }
@@ -11,7 +11,7 @@
11
11
  <meta name="revision" content="{{revision}}">
12
12
 
13
13
  <!-- part: who -->
14
- <span class="sh-who" data-bot="{{bot}}"><b>{{bot}}</b></span>
14
+ <span class="sh-who" data-bot="{{bot}}">{{mark}}<b>{{bot}}</b></span>
15
15
  <i class="sh-dot"></i>
16
16
 
17
17
  <!-- part: theme -->
@@ -114,6 +114,9 @@ body {
114
114
  gap: 0.4375rem;
115
115
  font-weight: 600;
116
116
  }
117
+ .sh-mark {
118
+ flex: none;
119
+ }
117
120
  .sh-who[data-bot=""],
118
121
  .sh-who[data-bot=""] + .sh-dot {
119
122
  display: none;
@@ -17,6 +17,50 @@ const escape = (text) =>
17
17
  (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c],
18
18
  );
19
19
 
20
+ /** Path data as the app draws a mark: commands and numbers, nothing that could close the tag. */
21
+ const PATH = /^[MLCZ0-9 .-]{1,40000}$/;
22
+ /** A colour the app gives a mark: the page's text, a hex, or a paint's oklch. */
23
+ const INK = /^(currentColor|#[0-9a-fA-F]{6}|oklch\([0-9. ]+\))$/;
24
+
25
+ let marks = 0;
26
+
27
+ /**
28
+ * The bot's face as its shell gives it (`THURSDAY_BOT_MARK`, the app's markStill): a still
29
+ * SVG at `size` px, or "" when there is none. The app writes that variable; anything in it
30
+ * that is not a mark's path data or colours draws no face rather than reaching the page.
31
+ * The eyes are holes in the body, so they show whatever the page is.
32
+ */
33
+ export function markSvg(size = 16, raw = process.env.THURSDAY_BOT_MARK) {
34
+ let mark;
35
+ try {
36
+ mark = JSON.parse(raw ?? "");
37
+ } catch {
38
+ return "";
39
+ }
40
+ const { head, eyes, ink, paint, outline } = mark ?? {};
41
+ const shapes = [head, ...(Array.isArray(eyes) ? eyes : [])];
42
+ if (shapes.length !== 3 || !shapes.every((d) => PATH.test(String(d))))
43
+ return "";
44
+ const colors = Array.isArray(paint) ? paint : [];
45
+ if (!INK.test(String(ink)) || !colors.every((c) => INK.test(String(c))))
46
+ return "";
47
+ const id = `sh-mark-${++marks}`;
48
+ const fill = colors.length > 1 ? `url(#${id})` : ink;
49
+ const stops = colors
50
+ .map(
51
+ (c, i) => `<stop offset="${i / (colors.length - 1)}" stop-color="${c}"/>`,
52
+ )
53
+ .join("");
54
+ const defs =
55
+ colors.length > 1
56
+ ? `<defs><linearGradient id="${id}" x1="0" y1="0" x2="1" y2="1">${stops}</linearGradient></defs>`
57
+ : "";
58
+ const body = outline
59
+ ? `<path d="${head}" fill="none" stroke="${fill}" stroke-width="14" stroke-linejoin="round"/><path d="${eyes[0]}${eyes[1]}" fill="${fill}"/>`
60
+ : `<path d="${head}${eyes[0]}${eyes[1]}" fill="${fill}" fill-rule="evenodd"/>`;
61
+ return `<svg class="sh-mark" width="${size}" height="${size}" viewBox="-18 -18 276 276" aria-hidden="true">${defs}${body}</svg>`;
62
+ }
63
+
20
64
  /** A page's own name for itself, in its tab and in its head (each kind's `.sh-title`). */
21
65
  export const retitle = (html, title) =>
22
66
  html
@@ -49,7 +93,9 @@ export function wear(html) {
49
93
  .replaceAll("{{shell.meta}}", () =>
50
94
  part.meta.replace("{{revision}}", revision()),
51
95
  )
52
- .replaceAll("{{shell.who}}", () => part.who.replaceAll("{{bot}}", bot))
96
+ .replaceAll("{{shell.who}}", () =>
97
+ part.who.replaceAll("{{bot}}", bot).replace("{{mark}}", () => markSvg()),
98
+ )
53
99
  .replaceAll("{{shell.theme}}", () => part.theme)
54
100
  .replaceAll("{{shell.export}}", () => part.export)
55
101
  .replaceAll("{{shell.download}}", () => part.download);
@@ -0,0 +1,23 @@
1
+ fflate 0.8.3 — https://github.com/101arrowz/fflate
2
+
3
+ MIT License
4
+
5
+ Copyright (c) 2026 Arjun Barrett
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.