thursday-agent 0.5.0 → 0.7.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 (667) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +3 -2
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.json +8 -1
  6. package/.next/routes-manifest.json +18 -6
  7. package/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  14. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +13 -13
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +12 -12
  19. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  20. package/.next/server/app/api/artifact/route.js +10 -6
  21. package/.next/server/app/api/artifact/route.js.nft.json +1 -1
  22. package/.next/server/app/api/bot/memory/files/route.js +5 -4
  23. package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
  24. package/.next/server/app/api/bot/memory/route.js +8 -8
  25. package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
  26. package/.next/server/app/api/bot/route.js +8 -8
  27. package/.next/server/app/api/bot/route.js.nft.json +1 -1
  28. package/.next/server/app/api/bot/thread/[id]/route/app-paths-manifest.json +3 -0
  29. package/.next/server/app/api/bot/thread/[id]/route.js +15 -0
  30. package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -0
  31. package/.next/server/app/api/bot/thread/[id]/route_client-reference-manifest.js +3 -0
  32. package/.next/server/app/api/bot/thread/route/app-paths-manifest.json +3 -0
  33. package/.next/server/app/api/bot/thread/route.js +15 -0
  34. package/.next/server/app/api/bot/thread/route.js.nft.json +1 -0
  35. package/.next/server/app/api/bot/thread/route_client-reference-manifest.js +3 -0
  36. package/.next/server/app/api/config/route.js +7 -7
  37. package/.next/server/app/api/config/route.js.nft.json +1 -1
  38. package/.next/server/app/api/events/route.js +3 -3
  39. package/.next/server/app/api/events/route.js.nft.json +1 -1
  40. package/.next/server/app/api/file/[...path]/route.js +4 -4
  41. package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
  42. package/.next/server/app/api/llm-model/catalog/route.js +8 -8
  43. package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
  44. package/.next/server/app/api/llm-model/credits/route.js +8 -8
  45. package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
  46. package/.next/server/app/api/llm-model/route.js +8 -8
  47. package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
  48. package/.next/server/app/api/llm-model/subscription/route.js +8 -8
  49. package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
  50. package/.next/server/app/api/mcp/[name]/route.js +6 -6
  51. package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
  52. package/.next/server/app/api/mcp/oauth/callback/route.js +4 -4
  53. package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
  54. package/.next/server/app/api/mcp/route.js +6 -6
  55. package/.next/server/app/api/mcp/route.js.nft.json +1 -1
  56. package/.next/server/app/api/mcp/tools/route.js +6 -6
  57. package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
  58. package/.next/server/app/api/memory/edit/route.js +15 -15
  59. package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
  60. package/.next/server/app/api/memory/route.js +7 -6
  61. package/.next/server/app/api/memory/route.js.nft.json +1 -1
  62. package/.next/server/app/api/skills/[source]/[name]/route.js +6 -6
  63. package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
  64. package/.next/server/app/api/skills/route.js +6 -6
  65. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  66. package/.next/server/app/api/thursday/call/route.js +10 -11
  67. package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
  68. package/.next/server/app/api/thursday/skills/route.js +9 -10
  69. package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
  70. package/.next/server/app/api/thursday/tool-call/route.js +15 -15
  71. package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
  72. package/.next/server/app/api/workspace/missing/route/app-paths-manifest.json +3 -0
  73. package/.next/server/app/api/workspace/missing/route/build-manifest.json +12 -0
  74. package/.next/server/app/api/workspace/missing/route/server-reference-manifest.json +4 -0
  75. package/.next/server/app/api/workspace/missing/route.js +12 -0
  76. package/.next/server/app/api/workspace/missing/route.js.map +5 -0
  77. package/.next/server/app/api/workspace/missing/route.js.nft.json +1 -0
  78. package/.next/server/app/api/workspace/missing/route_client-reference-manifest.js +3 -0
  79. package/.next/server/app/api/workspace/route.js +5 -5
  80. package/.next/server/app/api/workspace/route.js.nft.json +1 -1
  81. package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
  82. package/.next/server/app/artifact/[...path]/page.js +4 -3
  83. package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
  84. package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
  85. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  86. package/.next/server/app/page/server-reference-manifest.json +67 -45
  87. package/.next/server/app/page.js +11 -9
  88. package/.next/server/app/page.js.nft.json +1 -1
  89. package/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/.next/server/app-paths-manifest.json +3 -2
  91. package/.next/server/chunks/[root-of-the-server]__0-06t3f._.js +8 -0
  92. package/.next/server/chunks/[root-of-the-server]__02846fb._.js +8 -0
  93. package/.next/server/chunks/[root-of-the-server]__05luceg._.js +3 -0
  94. package/.next/server/chunks/[root-of-the-server]__06--3q3._.js +8 -0
  95. package/.next/server/chunks/[root-of-the-server]__06l05n_._.js +3 -0
  96. package/.next/server/chunks/[root-of-the-server]__07bnah_._.js +3 -0
  97. package/.next/server/chunks/[root-of-the-server]__08eae20._.js +8 -0
  98. package/.next/server/chunks/[root-of-the-server]__0_ue8oe._.js +3 -0
  99. package/.next/server/chunks/[root-of-the-server]__0btqrct._.js +3 -0
  100. package/.next/server/chunks/[root-of-the-server]__0c9fgca._.js +5 -0
  101. package/.next/server/chunks/[root-of-the-server]__0h_x6q6._.js +5 -0
  102. package/.next/server/chunks/{[root-of-the-server]__0pa2n68._.js → [root-of-the-server]__0kxrvxf._.js} +2 -2
  103. package/.next/server/chunks/{[root-of-the-server]__0q0vvt2._.js → [root-of-the-server]__0ov3iir._.js} +2 -2
  104. package/.next/server/chunks/[root-of-the-server]__0qwtlmx._.js +8 -0
  105. package/.next/server/chunks/[root-of-the-server]__0sm5xvm._.js +3 -0
  106. package/.next/server/chunks/[root-of-the-server]__0zp35ul._.js +5 -0
  107. package/.next/server/chunks/[root-of-the-server]__144u9d_._.js +3 -0
  108. package/.next/server/chunks/[root-of-the-server]__18-2tsq._.js +5 -0
  109. package/.next/server/chunks/[root-of-the-server]__1e-ci13._.js +3 -0
  110. package/.next/server/chunks/[root-of-the-server]__1e2365e._.js +8 -0
  111. package/.next/server/chunks/[root-of-the-server]__1fix932._.js +8 -0
  112. package/.next/server/chunks/{[root-of-the-server]__0ce8nf8._.js → [root-of-the-server]__1g3t7vn._.js} +3 -3
  113. package/.next/server/chunks/[root-of-the-server]__1kp-83u._.js +5 -0
  114. package/.next/server/chunks/[root-of-the-server]__1kv8p3e._.js +5 -0
  115. package/.next/server/chunks/[root-of-the-server]__1orn-5b._.js +2 -3
  116. package/.next/server/chunks/_02szwk8._.js +5 -0
  117. package/.next/server/chunks/_05h2cii._.js +1 -1
  118. package/.next/server/chunks/_06c9kie._.js +216 -0
  119. package/.next/server/chunks/{_1x6kd1r._.js → _07y2gj-._.js} +1 -1
  120. package/.next/server/chunks/_0a43a-0._.js +3 -0
  121. package/.next/server/chunks/_0bujjey._.js +5 -0
  122. package/.next/server/chunks/_0c9j6rb._.js +1 -1
  123. package/.next/server/chunks/_0dkd549._.js +3 -0
  124. package/.next/server/chunks/_0ej1kvv._.js +3 -0
  125. package/.next/server/chunks/_0f6ts7z._.js +3 -0
  126. package/.next/server/chunks/_0gm9hyv._.js +55 -0
  127. package/.next/server/chunks/_0i55en5._.js +25 -0
  128. package/.next/server/chunks/_0k50n27._.js +18 -0
  129. package/.next/server/chunks/_0khihjk._.js +3 -3
  130. package/.next/server/chunks/_0n74zsf._.js +5 -5
  131. package/.next/server/chunks/_0nvm9ef._.js +3 -0
  132. package/.next/server/chunks/_0p56fn0._.js +3 -0
  133. package/.next/server/chunks/_0recufk._.js +1 -1
  134. package/.next/server/chunks/_0xbkz10._.js +3 -0
  135. package/.next/server/chunks/_10tkr26._.js +3 -0
  136. package/.next/server/chunks/{_0ioz3nd._.js → _11u2kp7._.js} +1 -1
  137. package/.next/server/chunks/_11ujpya._.js +3 -0
  138. package/.next/server/chunks/_127nx_p._.js +5 -0
  139. package/.next/server/chunks/_17l5ygt._.js +1 -1
  140. package/.next/server/chunks/_19uauj6._.js +3 -0
  141. package/.next/server/chunks/_1_5mnq4._.js +5 -5
  142. package/.next/server/chunks/_1abl6t9._.js +55 -0
  143. package/.next/server/chunks/_1d0j961._.js +3 -3
  144. package/.next/server/chunks/_1dbixxz._.js +3 -0
  145. package/.next/server/chunks/_1dc_d1q._.js +98 -0
  146. package/.next/server/chunks/_1drgfx4._.js +5 -5
  147. package/.next/server/chunks/_1e48czp._.js +3 -3
  148. package/.next/server/chunks/_1f31u5x._.js +5 -0
  149. package/.next/server/chunks/_1gnjfli._.js +3 -0
  150. package/.next/server/chunks/_1kg70wc._.js +3 -3
  151. package/.next/server/chunks/_1klbcft._.js +5 -0
  152. package/.next/server/chunks/_1krd9rf._.js +4 -1
  153. package/.next/server/chunks/_1kwmzab._.js +3 -0
  154. package/.next/server/chunks/{_1pf4qe-._.js → _1oxj9fa._.js} +1 -1
  155. package/.next/server/chunks/{_1f46eie._.js → _1pcmdbb._.js} +1 -1
  156. package/.next/server/chunks/_1qgix-j._.js +3 -0
  157. package/.next/server/chunks/{lib_logger_ts_1exwjut._.js → _1rpchta._.js} +5 -5
  158. package/.next/server/chunks/_1vsej-s._.js +5 -0
  159. package/.next/server/chunks/_1yx0p_s._.js +5 -0
  160. package/.next/server/chunks/{_0rnf-6n._.js → _20fsr_z._.js} +6 -6
  161. package/.next/server/chunks/_2128hkj._.js +5 -0
  162. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_[id]_route_actions_1fstjn2.js +3 -0
  163. package/.next/server/chunks/_next-internal_server_app_api_bot_thread_route_actions_003ccso.js +3 -0
  164. package/.next/server/chunks/_next-internal_server_app_api_workspace_missing_route_actions_1fidi6p.js +3 -0
  165. package/.next/server/chunks/config_ts_1g4sz5o._.js +1 -1
  166. package/.next/server/chunks/features_0-cnt0l._.js +4 -0
  167. package/.next/server/chunks/features_0hdaci0._.js +4 -0
  168. package/.next/server/chunks/features_1e39j7-._.js +8 -0
  169. package/.next/server/chunks/features_bot_bot_query_ts_12mgkl2._.js +1 -1
  170. package/.next/server/chunks/features_memory_1uqvksn._.js +1 -1
  171. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0v_7drq._.js → node_modules_consola_dist_chunks_prompt_mjs_0a7-pbw._.js} +1 -1
  172. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_17k8irj._.js → node_modules_consola_dist_chunks_prompt_mjs_0gzvgfv._.js} +1 -1
  173. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0i7cvml._.js → node_modules_consola_dist_chunks_prompt_mjs_107pxfn._.js} +1 -1
  174. package/.next/server/chunks/{node_modules_consola_dist_chunks_prompt_mjs_0icqaqw._.js → node_modules_consola_dist_chunks_prompt_mjs_15hbel8._.js} +1 -1
  175. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_18i-23e._.js +3 -0
  176. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1bewgf3._.js +3 -0
  177. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1nlww1m._.js +3 -0
  178. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1q77nfx._.js +3 -0
  179. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1xqdzx_._.js +3 -0
  180. package/.next/server/chunks/{node_modules_zod_v4_1801ax7._.js → node_modules_zod_v4_0lkux5-._.js} +2 -2
  181. package/.next/server/chunks/{node_modules_zod_v4_1cha_bw._.js → node_modules_zod_v4_1jmr9cq._.js} +2 -2
  182. package/.next/server/chunks/{node_modules_zod_v4_0ubdflj._.js → node_modules_zod_v4_1yrxmek._.js} +2 -2
  183. package/.next/server/chunks/node_modules_zod_v4_classic_errors_0tp0y-q.js +3 -0
  184. package/.next/server/chunks/ssr/[root-of-the-server]__0-e011f._.js +3 -0
  185. package/.next/server/chunks/ssr/[root-of-the-server]__09q9med._.js +1 -1
  186. package/.next/server/chunks/ssr/[root-of-the-server]__0lyi8i2._.js +1 -1
  187. package/.next/server/chunks/ssr/[root-of-the-server]__0pd8yr7._.js +3 -0
  188. package/.next/server/chunks/ssr/[root-of-the-server]__16jc196._.js +1 -1
  189. package/.next/server/chunks/ssr/[root-of-the-server]__18dthbp._.js +3 -0
  190. package/.next/server/chunks/ssr/[root-of-the-server]__18e68w8._.js +3 -0
  191. package/.next/server/chunks/ssr/[root-of-the-server]__1mzi-ju._.js +1 -1
  192. package/.next/server/chunks/ssr/[root-of-the-server]__1nygfik._.js +5 -0
  193. package/.next/server/chunks/ssr/[root-of-the-server]__1sdphb0._.js +8 -0
  194. package/.next/server/chunks/ssr/[root-of-the-server]__1vdmfbe._.js +3 -0
  195. package/.next/server/chunks/ssr/[root-of-the-server]__1waa3rc._.js +85 -0
  196. package/.next/server/chunks/ssr/_0-2qsxo._.js +3 -0
  197. package/.next/server/chunks/ssr/_00rehl_._.js +3 -0
  198. package/.next/server/chunks/ssr/{_1lz_cq2._.js → _02oc_h5._.js} +76 -97
  199. package/.next/server/chunks/ssr/_05yghx6._.js +3 -0
  200. package/.next/server/chunks/ssr/_07nbwap._.js +3 -0
  201. package/.next/server/chunks/ssr/_08c4z-9._.js +3 -0
  202. package/.next/server/chunks/ssr/_0_qfdlw._.js +4 -0
  203. package/.next/server/chunks/ssr/{_0m2lsd1._.js → _0b6_jv-._.js} +2 -2
  204. package/.next/server/chunks/ssr/_0evkpto._.js +3 -0
  205. package/.next/server/chunks/ssr/_0geg212._.js +3 -0
  206. package/.next/server/chunks/ssr/{_1jdgjv9._.js → _0hxt2ul._.js} +2 -2
  207. package/.next/server/chunks/ssr/_0i_6q1w._.js +2 -2
  208. package/.next/server/chunks/ssr/_0lu1n_x._.js +1 -1
  209. package/.next/server/chunks/ssr/_0no7i1o._.js +3 -0
  210. package/.next/server/chunks/ssr/_0tzg--b._.js +3 -0
  211. package/.next/server/chunks/ssr/{_15j2_8f._.js → _0wzaht-._.js} +2 -2
  212. package/.next/server/chunks/ssr/_0z-g0uy._.js +3 -0
  213. package/.next/server/chunks/ssr/_114ylv7._.js +7 -0
  214. package/.next/server/chunks/ssr/_123y-ah._.js +3 -0
  215. package/.next/server/chunks/ssr/_12c-iwh._.js +3 -0
  216. package/.next/server/chunks/ssr/_12w42gi._.js +3 -0
  217. package/.next/server/chunks/ssr/_161kqav._.js +3 -0
  218. package/.next/server/chunks/ssr/_167hchk._.js +3 -0
  219. package/.next/server/chunks/ssr/{_0ap2fzn._.js → _16c6_xm._.js} +2 -2
  220. package/.next/server/chunks/ssr/_18opah7._.js +3 -0
  221. package/.next/server/chunks/ssr/_1_krfph._.js +3 -0
  222. package/.next/server/chunks/ssr/{_0rzucul._.js → _1_x5spz._.js} +3 -3
  223. package/.next/server/chunks/ssr/_1a61fc9._.js +3 -0
  224. package/.next/server/chunks/ssr/_1ey7qn-._.js +70 -0
  225. package/.next/server/chunks/ssr/_1g9vs7q._.js +3 -0
  226. package/.next/server/chunks/ssr/_1jmz33w._.js +3 -0
  227. package/.next/server/chunks/ssr/_1rgtxhr._.js +5 -0
  228. package/.next/server/chunks/ssr/_1slp25y._.js +3 -0
  229. package/.next/server/chunks/ssr/_1w_t7h7._.js +101 -0
  230. package/.next/server/chunks/ssr/{_0s99bgb._.js → _1wyfaq_._.js} +9 -3
  231. package/.next/server/chunks/ssr/_200gt-m._.js +102 -0
  232. package/.next/server/chunks/ssr/components_ui_tabs_tsx_0ej40b4._.js +3 -0
  233. package/.next/server/chunks/ssr/features_bot_thread_query_ts_023eklt._.js +4 -0
  234. package/.next/server/chunks/ssr/features_config_components_config-setting_tsx_0xfwqdg._.js +1 -1
  235. package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
  236. package/.next/server/chunks/ssr/features_workspace_00jz2hu._.js +8 -0
  237. package/.next/server/chunks/ssr/{_1-teee5._.js → lib_logger_ts_0-olsze._.js} +2 -7
  238. package/.next/server/chunks/ssr/{node_modules_05-n6dz._.js → node_modules_02ai7br._.js} +1 -1
  239. package/.next/server/chunks/ssr/{node_modules_1chvq5f._.js → node_modules_02deexj._.js} +1 -1
  240. package/.next/server/chunks/ssr/{node_modules_0m383r2._.js → node_modules_07za262._.js} +1 -1
  241. package/.next/server/chunks/ssr/{node_modules_07dsgkx._.js → node_modules_0_s9get._.js} +1 -1
  242. package/.next/server/chunks/ssr/{node_modules_1a0kmjl._.js → node_modules_0n3c7h0._.js} +1 -1
  243. package/.next/server/chunks/ssr/{node_modules_0zeg3x_._.js → node_modules_0od6jwr._.js} +1 -1
  244. package/.next/server/chunks/ssr/{node_modules_1y79i83._.js → node_modules_0rdt7pk._.js} +1 -1
  245. package/.next/server/chunks/ssr/{node_modules_17bwo43._.js → node_modules_0tusx4d._.js} +3 -3
  246. package/.next/server/chunks/ssr/{node_modules_04sksn9._.js → node_modules_0w1z7kz._.js} +1 -1
  247. package/.next/server/chunks/ssr/{node_modules_1uyk91w._.js → node_modules_0wdupfz._.js} +1 -1
  248. package/.next/server/chunks/ssr/{node_modules_0ifp389._.js → node_modules_1720w0a._.js} +1 -1
  249. package/.next/server/chunks/ssr/{node_modules_0u9da1h._.js → node_modules_18lsg7d._.js} +1 -1
  250. package/.next/server/chunks/ssr/{node_modules_1k6n600._.js → node_modules_1b94fxf._.js} +1 -1
  251. package/.next/server/chunks/ssr/{node_modules_20c28js._.js → node_modules_1ecdo1s._.js} +1 -1
  252. package/.next/server/chunks/ssr/{node_modules_0fkeku3._.js → node_modules_1fa9ag7._.js} +1 -1
  253. package/.next/server/chunks/ssr/{node_modules_1j8j4pt._.js → node_modules_1fv-_si._.js} +1 -1
  254. package/.next/server/chunks/ssr/{node_modules_0-dr_o7._.js → node_modules_1hf461g._.js} +1 -1
  255. package/.next/server/chunks/ssr/{node_modules_1lz0oxc._.js → node_modules_1m71ta-._.js} +1 -1
  256. package/.next/server/chunks/ssr/{node_modules_1t77e4n._.js → node_modules_1n93n-g._.js} +1 -1
  257. package/.next/server/chunks/ssr/{node_modules_16mkxuo._.js → node_modules_1n9lqu9._.js} +1 -1
  258. package/.next/server/chunks/ssr/{node_modules_1k7z2j6._.js → node_modules_1npnsvd._.js} +1 -1
  259. package/.next/server/chunks/ssr/{node_modules_056qgf-._.js → node_modules_1rn2r0n._.js} +1 -1
  260. package/.next/server/chunks/ssr/{node_modules_0x3-ply._.js → node_modules_1seuurl._.js} +2 -2
  261. package/.next/server/chunks/ssr/{node_modules_0bvopy2._.js → node_modules_1vq-mfk._.js} +1 -1
  262. package/.next/server/chunks/ssr/{node_modules_0iur59s._.js → node_modules_1vzyw1t._.js} +1 -1
  263. package/.next/server/chunks/ssr/{node_modules_1k8j8n0._.js → node_modules_1w359w4._.js} +1 -1
  264. package/.next/server/chunks/ssr/{node_modules_1x0ztf4._.js → node_modules_1yajbl6._.js} +1 -1
  265. package/.next/server/chunks/ssr/{node_modules_1-y7nni._.js → node_modules_20eqhy8._.js} +1 -1
  266. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0bkwd0u._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_019sbis._.js} +1 -1
  267. package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0p9a9su._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0s6piq3._.js} +1 -1
  268. package/.next/server/chunks/ssr/{node_modules_@vercel_oidc_dist_1o553h-._.js → node_modules_@vercel_oidc_dist_05itbb1._.js} +1 -1
  269. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_trash_mjs_0px2gzr._.js +3 -0
  270. package/.next/server/middleware-build-manifest.js +3 -3
  271. package/.next/server/pages/404.html +1 -1
  272. package/.next/server/pages/500.html +1 -1
  273. package/.next/server/server-reference-manifest.js +1 -1
  274. package/.next/server/server-reference-manifest.json +68 -46
  275. package/.next/static/chunks/07vqbk_9t4em4.js +2 -0
  276. package/.next/static/chunks/08krja1zx7nqg.js +1 -0
  277. package/.next/static/chunks/0g4b348l0pve7.js +1 -0
  278. package/.next/static/chunks/0qcuwdk132jjt.js +1 -0
  279. package/.next/static/chunks/0vlgzqo9ka90v.js +1 -0
  280. package/.next/static/chunks/{11r2yp_yh9_qn.js → 0z69gvysmave7.js} +1 -1
  281. package/.next/static/chunks/0zrupxgci5gqc.js +1 -0
  282. package/.next/static/chunks/12fvz1w5ows75.js +1 -0
  283. package/.next/static/chunks/14t03ned286iu.js +1 -0
  284. package/.next/static/chunks/156xxbkrz5lzu.js +18 -0
  285. package/.next/static/chunks/1fz14reod4lft.js +1 -0
  286. package/.next/static/chunks/1g23dbabl-vkr.js +1 -0
  287. package/.next/static/chunks/1ohslk4568tm3.js +1 -0
  288. package/.next/static/chunks/1qy_rc3oxfxok.js +1 -0
  289. package/.next/static/chunks/1sbmwswc9k2-1.js +1 -0
  290. package/.next/static/chunks/1vqezbhjm3goq.js +1 -0
  291. package/.next/static/chunks/1zea7qdl-7365.js +1 -0
  292. package/.next/static/chunks/1zvqumkg7kmo0.css +1 -0
  293. package/.next/static/chunks/26hpqt3y6bogl.js +12 -0
  294. package/.next/static/chunks/2_j5mqm6d-z18.js +99 -0
  295. package/.next/static/chunks/2dt6tu7a22svs.js +1 -0
  296. package/.next/static/chunks/2h5ls3d86kya6.js +1 -0
  297. package/.next/static/chunks/2wc6y1ht6dfuy.js +1 -0
  298. package/.next/static/chunks/{435atsnhs7ksu.js → 2xr0zpll7thyi.js} +2 -2
  299. package/.next/static/chunks/31jztc-yq30m7.js +1 -0
  300. package/.next/static/chunks/391af0i8eljzk.js +1 -0
  301. package/.next/static/chunks/3bfwpww3m3x4u.js +1 -0
  302. package/.next/static/chunks/{38gweqdo4jpfj.js → 3izg0a3k87q1-.js} +5 -5
  303. package/.next/static/chunks/3p2s2cjokx1aa.js +5 -0
  304. package/.next/static/chunks/{408ueu4hfvcg7.js → 41s3fml5oivsa.js} +1 -1
  305. package/README.md +45 -193
  306. package/app/api/events/app-event.ts +6 -4
  307. package/app/api/query-key.ts +25 -16
  308. package/bin/database.mjs +37 -0
  309. package/bin/thursday.mjs +44 -28
  310. package/components/ui/custom-icon.tsx +0 -60
  311. package/components/ui/radio-group.tsx +37 -0
  312. package/components/ui/shiny-text.tsx +33 -6
  313. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/migration.sql +80 -24
  314. package/database/migrations/{20260910173049_numerous_spirit → 20260916145701_clever_multiple_man}/snapshot.json +689 -110
  315. package/database/migrations/20260916160713_thread_cancelled/migration.sql +2 -0
  316. package/database/migrations/{20260911030320_opposite_jack_power → 20260916160713_thread_cancelled}/snapshot.json +706 -84
  317. package/docs/how-it-works.md +40 -35
  318. package/docs/images/keeps-going.png +0 -0
  319. package/docs/images/two-minds.png +0 -0
  320. package/docs/live-calls.md +236 -0
  321. package/docs/thread-rooms.md +71 -0
  322. package/features/ai/chatgpt.ts +1 -2
  323. package/features/ai/live.schema.ts +128 -0
  324. package/features/ai/load-tools.ts +152 -79
  325. package/features/ai/model.schema.ts +2 -120
  326. package/features/ai/model.ts +52 -88
  327. package/features/ai/prompts/bot.prompt.ts +91 -214
  328. package/features/ai/prompts/live.prompt.ts +169 -0
  329. package/features/ai/prompts/prompt-helper.ts +92 -32
  330. package/features/ai/prompts/thursday.prompt.ts +164 -190
  331. package/features/ai/tools/bot.tool.ts +38 -145
  332. package/features/ai/tools/call.tool.ts +33 -5
  333. package/features/ai/tools/connected.ts +5 -3
  334. package/features/ai/tools/mcp.tool.ts +7 -4
  335. package/features/ai/tools/memory.tool.ts +35 -31
  336. package/features/ai/tools/skills.tool.ts +11 -6
  337. package/features/ai/tools/studio.tool.ts +26 -21
  338. package/features/ai/tools/tool-name.ts +3 -5
  339. package/features/ai/tools/workspace.tool.ts +33 -10
  340. package/features/artifact/artifact.action.ts +2 -2
  341. package/features/artifact/artifact.query.ts +112 -61
  342. package/features/artifact/artifact.schema.ts +8 -6
  343. package/features/artifact/components/artifact-setting.tsx +83 -33
  344. package/features/bot/bot.action.ts +43 -36
  345. package/features/bot/bot.memory.ts +137 -20
  346. package/features/bot/bot.query.ts +28 -11
  347. package/features/bot/bot.run.ts +296 -744
  348. package/features/bot/bot.runner.ts +463 -864
  349. package/features/bot/bot.schema.ts +93 -82
  350. package/features/bot/bot.seed.ts +141 -64
  351. package/features/bot/components/bot-mark.tsx +324 -232
  352. package/features/bot/components/bot-room.tsx +1613 -697
  353. package/features/bot/components/bot-roster.tsx +8 -13
  354. package/features/bot/components/bot-setting.tsx +58 -42
  355. package/features/bot/components/bot-tool.tsx +55 -87
  356. package/features/bot/components/mark-palette.tsx +35 -32
  357. package/features/bot/components/path-chips.tsx +33 -3
  358. package/features/bot/components/thread-badge.tsx +34 -0
  359. package/features/bot/components/thread-reply.tsx +639 -0
  360. package/features/bot/components/thread-setting.tsx +674 -0
  361. package/features/bot/mark.const.ts +79 -31
  362. package/features/bot/room.query.ts +889 -0
  363. package/features/bot/room.schema.ts +64 -0
  364. package/features/bot/seed-bots.ts +2 -1
  365. package/features/bot/thread.query.ts +971 -0
  366. package/features/bot/thread.store.ts +587 -0
  367. package/features/config/components/voice-key.tsx +113 -88
  368. package/features/config/config.const.ts +5 -9
  369. package/features/connectors/mcp.schema.ts +0 -2
  370. package/features/intro/components/intro.tsx +169 -139
  371. package/features/memory/components/memory-setting.tsx +2 -7
  372. package/features/memory/memory.schema.ts +14 -23
  373. package/features/settings/components/setting-ui.tsx +0 -44
  374. package/features/settings/components/settings.tsx +12 -12
  375. package/features/settings/settings.alert.ts +3 -3
  376. package/features/settings/settings.store.ts +1 -1
  377. package/features/skills/skills.schema.ts +0 -2
  378. package/features/thursday/ascii.const.ts +74 -0
  379. package/features/thursday/components/ascii-field.tsx +24 -44
  380. package/features/thursday/components/ascii-orb.tsx +525 -381
  381. package/features/thursday/components/call-log.tsx +46 -44
  382. package/features/thursday/components/face.tsx +40 -10
  383. package/features/thursday/components/side-captions.tsx +273 -0
  384. package/features/thursday/components/tab-state.tsx +14 -6
  385. package/features/thursday/components/thursday-mark.tsx +1 -0
  386. package/features/thursday/components/thursday-setting.tsx +633 -333
  387. package/features/thursday/components/thursday.tsx +315 -274
  388. package/features/thursday/components/voice-picker.tsx +255 -0
  389. package/features/thursday/face.store.ts +5 -0
  390. package/features/thursday/thursday.action.ts +96 -72
  391. package/features/thursday/thursday.query.ts +49 -30
  392. package/features/thursday/thursday.schema.ts +37 -35
  393. package/features/thursday/thursday.store.ts +14 -7
  394. package/features/thursday/tool-call.ts +3 -3
  395. package/features/thursday/tool-line.ts +5 -3
  396. package/features/thursday/use-thursday.ts +801 -457
  397. package/features/workspace/file-kind.ts +9 -0
  398. package/features/workspace/workspace.query.ts +17 -0
  399. package/features/workspace/workspace.ts +82 -36
  400. package/hooks/use-hotkey.ts +3 -2
  401. package/lib/live/live.schema.ts +26 -0
  402. package/lib/live/live.server.ts +153 -0
  403. package/lib/live/live.session.ts +574 -0
  404. package/lib/{realtime/realtime.tap.ts → live/live.tap.ts} +41 -12
  405. package/lib/live/live.transport.ts +152 -0
  406. package/lib/protocol/use-server-pages.ts +9 -5
  407. package/lib/utils.ts +21 -20
  408. package/package.json +2 -2
  409. package/public/voices/alloy.ogg +0 -0
  410. package/public/voices/ash.ogg +0 -0
  411. package/public/voices/ballad.ogg +0 -0
  412. package/public/voices/beacon.ogg +0 -0
  413. package/public/voices/bossa.ogg +0 -0
  414. package/public/voices/cedar.ogg +0 -0
  415. package/public/voices/cinder.ogg +0 -0
  416. package/public/voices/coral.ogg +0 -0
  417. package/public/voices/delta.ogg +0 -0
  418. package/public/voices/echo.ogg +0 -0
  419. package/public/voices/gleam.ogg +0 -0
  420. package/public/voices/marin.ogg +0 -0
  421. package/public/voices/meridian.ogg +0 -0
  422. package/public/voices/quartz.ogg +0 -0
  423. package/public/voices/ripple.ogg +0 -0
  424. package/public/voices/sage.ogg +0 -0
  425. package/public/voices/shimmer.ogg +0 -0
  426. package/public/voices/stone.ogg +0 -0
  427. package/public/voices/tempo.ogg +0 -0
  428. package/public/voices/verse.ogg +0 -0
  429. package/public/voices/vesper.ogg +0 -0
  430. package/public/voices/willow.ogg +0 -0
  431. package/scripts/artifact-paths.test.mts +38 -0
  432. package/scripts/bot-context.test.mts +1408 -0
  433. package/scripts/live-history.test.mts +115 -0
  434. package/scripts/live-session.test.mts +938 -0
  435. package/server.js +1 -1
  436. package/skills/browser/SKILL.md +11 -1
  437. package/skills/computer/SKILL.md +1 -1
  438. package/skills/find-skills/SKILL.md +3 -8
  439. package/skills/interactive-page/SKILL.md +12 -7
  440. package/skills/interactive-page/references/diagram.md +89 -0
  441. package/skills/interactive-page/scripts/archify/LICENSE +22 -0
  442. package/skills/interactive-page/scripts/archify/README.md +25 -0
  443. package/skills/interactive-page/scripts/archify/assets/JetBrainsMono-OFL.txt +93 -0
  444. package/skills/interactive-page/scripts/archify/assets/template.html +14934 -0
  445. package/skills/interactive-page/scripts/archify/bin/archify.mjs +2126 -0
  446. package/skills/interactive-page/scripts/archify/bin/open-artifact.mjs +86 -0
  447. package/skills/interactive-page/scripts/archify/bin/preview.mjs +653 -0
  448. package/skills/interactive-page/scripts/archify/bin/visual-check.mjs +829 -0
  449. package/skills/interactive-page/scripts/archify/delta/architecture-delta.mjs +1223 -0
  450. package/skills/interactive-page/scripts/archify/examples/agent-run.lifecycle.json +60 -0
  451. package/skills/interactive-page/scripts/archify/examples/agent-tool-call.workflow.json +94 -0
  452. package/skills/interactive-page/scripts/archify/examples/async-job-roundtrip.sequence.json +61 -0
  453. package/skills/interactive-page/scripts/archify/examples/cache-miss-request.sequence.json +82 -0
  454. package/skills/interactive-page/scripts/archify/examples/checkout-platform.base.architecture.json +31 -0
  455. package/skills/interactive-page/scripts/archify/examples/checkout-platform.head.architecture.json +31 -0
  456. package/skills/interactive-page/scripts/archify/examples/deployment-release.lifecycle.json +49 -0
  457. package/skills/interactive-page/scripts/archify/examples/event-stream.dataflow.json +57 -0
  458. package/skills/interactive-page/scripts/archify/examples/incident-response.workflow.json +64 -0
  459. package/skills/interactive-page/scripts/archify/examples/product-analytics.dataflow.json +76 -0
  460. package/skills/interactive-page/scripts/archify/examples/production-deployment.architecture.json +71 -0
  461. package/skills/interactive-page/scripts/archify/examples/release-delivery.workflow.json +62 -0
  462. package/skills/interactive-page/scripts/archify/examples/web-app.architecture.json +46 -0
  463. package/skills/interactive-page/scripts/archify/migrations/workflow-v2.mjs +279 -0
  464. package/skills/interactive-page/scripts/archify/recipes/scenarios.mjs +284 -0
  465. package/skills/interactive-page/scripts/archify/references/authoring-contract.md +243 -0
  466. package/skills/interactive-page/scripts/archify/references/delivery-contract.md +120 -0
  467. package/skills/interactive-page/scripts/archify/references/viewer-runtime.md +45 -0
  468. package/skills/interactive-page/scripts/archify/renderers/architecture/grid.mjs +62 -0
  469. package/skills/interactive-page/scripts/archify/renderers/architecture/render-architecture.mjs +1078 -0
  470. package/skills/interactive-page/scripts/archify/renderers/dataflow/README.md +104 -0
  471. package/skills/interactive-page/scripts/archify/renderers/dataflow/render-dataflow.mjs +483 -0
  472. package/skills/interactive-page/scripts/archify/renderers/lifecycle/README.md +115 -0
  473. package/skills/interactive-page/scripts/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
  474. package/skills/interactive-page/scripts/archify/renderers/sequence/README.md +114 -0
  475. package/skills/interactive-page/scripts/archify/renderers/sequence/render-sequence.mjs +464 -0
  476. package/skills/interactive-page/scripts/archify/renderers/shared/brand-marks.mjs +563 -0
  477. package/skills/interactive-page/scripts/archify/renderers/shared/cli.mjs +218 -0
  478. package/skills/interactive-page/scripts/archify/renderers/shared/desktop-readability.mjs +26 -0
  479. package/skills/interactive-page/scripts/archify/renderers/shared/diagnostics.mjs +127 -0
  480. package/skills/interactive-page/scripts/archify/renderers/shared/engineering-profiles.mjs +157 -0
  481. package/skills/interactive-page/scripts/archify/renderers/shared/generated-brand-marks.mjs +3 -0
  482. package/skills/interactive-page/scripts/archify/renderers/shared/generated-validators.mjs +13 -0
  483. package/skills/interactive-page/scripts/archify/renderers/shared/geometry.mjs +1423 -0
  484. package/skills/interactive-page/scripts/archify/renderers/shared/i18n.mjs +595 -0
  485. package/skills/interactive-page/scripts/archify/renderers/shared/layout-report.mjs +40 -0
  486. package/skills/interactive-page/scripts/archify/renderers/shared/legend.mjs +217 -0
  487. package/skills/interactive-page/scripts/archify/renderers/shared/output-path.mjs +340 -0
  488. package/skills/interactive-page/scripts/archify/renderers/shared/repository-evidence.mjs +238 -0
  489. package/skills/interactive-page/scripts/archify/renderers/shared/repository-location.mjs +58 -0
  490. package/skills/interactive-page/scripts/archify/renderers/shared/text-fit.mjs +49 -0
  491. package/skills/interactive-page/scripts/archify/renderers/shared/utils.mjs +232 -0
  492. package/skills/interactive-page/scripts/archify/renderers/shared/validator.mjs +86 -0
  493. package/skills/interactive-page/scripts/archify/renderers/workflow/README.md +223 -0
  494. package/skills/interactive-page/scripts/archify/renderers/workflow/render-workflow.mjs +35 -0
  495. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
  496. package/skills/interactive-page/scripts/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
  497. package/skills/interactive-page/scripts/archify/schemas/README.md +211 -0
  498. package/skills/interactive-page/scripts/archify/schemas/architecture.schema.json +178 -0
  499. package/skills/interactive-page/scripts/archify/schemas/common.schema.json +115 -0
  500. package/skills/interactive-page/scripts/archify/schemas/dataflow.schema.json +243 -0
  501. package/skills/interactive-page/scripts/archify/schemas/lifecycle.schema.json +266 -0
  502. package/skills/interactive-page/scripts/archify/schemas/sequence.schema.json +223 -0
  503. package/skills/interactive-page/scripts/archify/schemas/workflow.schema.json +428 -0
  504. package/skills/interactive-page/scripts/archify/scripts/check-render-output.mjs +916 -0
  505. package/skills/interactive-page/scripts/archify/scripts/render-examples.mjs +26 -0
  506. package/skills/interactive-page/scripts/bundle-artifact.sh +9 -8
  507. package/skills/skill-creator/SKILL.md +4 -5
  508. package/.next/server/app/api/bot/task/[id]/route/app-paths-manifest.json +0 -3
  509. package/.next/server/app/api/bot/task/[id]/route.js +0 -16
  510. package/.next/server/app/api/bot/task/[id]/route.js.nft.json +0 -1
  511. package/.next/server/app/api/bot/task/[id]/route_client-reference-manifest.js +0 -3
  512. package/.next/server/app/api/bot/task/route/app-paths-manifest.json +0 -3
  513. package/.next/server/app/api/bot/task/route.js +0 -16
  514. package/.next/server/app/api/bot/task/route.js.nft.json +0 -1
  515. package/.next/server/app/api/bot/task/route_client-reference-manifest.js +0 -3
  516. package/.next/server/chunks/[root-of-the-server]__026u77e._.js +0 -5
  517. package/.next/server/chunks/[root-of-the-server]__02va5wz._.js +0 -3
  518. package/.next/server/chunks/[root-of-the-server]__050zri4._.js +0 -3
  519. package/.next/server/chunks/[root-of-the-server]__0bg9710._.js +0 -3
  520. package/.next/server/chunks/[root-of-the-server]__0ffbg85._.js +0 -3
  521. package/.next/server/chunks/[root-of-the-server]__0in-d5s._.js +0 -3
  522. package/.next/server/chunks/[root-of-the-server]__0ncs9uu._.js +0 -3
  523. package/.next/server/chunks/[root-of-the-server]__0pa9k-f._.js +0 -8
  524. package/.next/server/chunks/[root-of-the-server]__0qi_m0e._.js +0 -8
  525. package/.next/server/chunks/[root-of-the-server]__0tq0m_k._.js +0 -3
  526. package/.next/server/chunks/[root-of-the-server]__0xep6j_._.js +0 -3
  527. package/.next/server/chunks/[root-of-the-server]__1-ga0kh._.js +0 -5
  528. package/.next/server/chunks/[root-of-the-server]__11n256_._.js +0 -5
  529. package/.next/server/chunks/[root-of-the-server]__144l7qt._.js +0 -8
  530. package/.next/server/chunks/[root-of-the-server]__1_04mcf._.js +0 -5
  531. package/.next/server/chunks/[root-of-the-server]__1anc1p9._.js +0 -3
  532. package/.next/server/chunks/[root-of-the-server]__1fizn31._.js +0 -3
  533. package/.next/server/chunks/[root-of-the-server]__1jg8t86._.js +0 -8
  534. package/.next/server/chunks/[root-of-the-server]__1lldzy9._.js +0 -3
  535. package/.next/server/chunks/[root-of-the-server]__1llj3-b._.js +0 -3
  536. package/.next/server/chunks/[root-of-the-server]__1p8m3f4._.js +0 -3
  537. package/.next/server/chunks/[root-of-the-server]__1peqvsi._.js +0 -3
  538. package/.next/server/chunks/[root-of-the-server]__1w8gm5h._.js +0 -10
  539. package/.next/server/chunks/[root-of-the-server]__1xt39nn._.js +0 -8
  540. package/.next/server/chunks/[root-of-the-server]__1zb8mfo._.js +0 -8
  541. package/.next/server/chunks/_0-73of8._.js +0 -55
  542. package/.next/server/chunks/_0-fjql4._.js +0 -31
  543. package/.next/server/chunks/_00xh_q0._.js +0 -25
  544. package/.next/server/chunks/_051qh8u._.js +0 -3
  545. package/.next/server/chunks/_05sovvj._.js +0 -3
  546. package/.next/server/chunks/_091bi8d._.js +0 -3
  547. package/.next/server/chunks/_0fzqt2y._.js +0 -142
  548. package/.next/server/chunks/_0lr92vd._.js +0 -3
  549. package/.next/server/chunks/_0mecv0f._.js +0 -31
  550. package/.next/server/chunks/_0mh8j4m._.js +0 -3
  551. package/.next/server/chunks/_0sb7tlz._.js +0 -3
  552. package/.next/server/chunks/_0si7xzn._.js +0 -3
  553. package/.next/server/chunks/_0u10wmw._.js +0 -55
  554. package/.next/server/chunks/_0wp4le3._.js +0 -3
  555. package/.next/server/chunks/_0y5fg-x._.js +0 -3
  556. package/.next/server/chunks/_1230wbx._.js +0 -10
  557. package/.next/server/chunks/_12nheja._.js +0 -3
  558. package/.next/server/chunks/_13510xh._.js +0 -3
  559. package/.next/server/chunks/_15hq89o._.js +0 -3
  560. package/.next/server/chunks/_18-1wcc._.js +0 -55
  561. package/.next/server/chunks/_18d7-5p._.js +0 -3
  562. package/.next/server/chunks/_1c78vw5._.js +0 -237
  563. package/.next/server/chunks/_1h5_8sk._.js +0 -3
  564. package/.next/server/chunks/_1hdnxb7._.js +0 -3
  565. package/.next/server/chunks/_1j8k_j5._.js +0 -3
  566. package/.next/server/chunks/_1nula3v._.js +0 -3
  567. package/.next/server/chunks/_1php4eq._.js +0 -3
  568. package/.next/server/chunks/_1yuv4vp._.js +0 -3
  569. package/.next/server/chunks/_1zkfbaa._.js +0 -3
  570. package/.next/server/chunks/_next-internal_server_app_api_bot_task_[id]_route_actions_1_k_8u3.js +0 -3
  571. package/.next/server/chunks/_next-internal_server_app_api_bot_task_route_actions_0xln6ra.js +0 -3
  572. package/.next/server/chunks/features_0rpfxbk._.js +0 -3
  573. package/.next/server/chunks/features_1qf3cei._.js +0 -8
  574. package/.next/server/chunks/features_bot_0zt92oh._.js +0 -3
  575. package/.next/server/chunks/node_modules_consola_dist_chunks_prompt_mjs_1jidylq._.js +0 -3
  576. package/.next/server/chunks/ssr/[externals]__0dizgek._.js +0 -3
  577. package/.next/server/chunks/ssr/[root-of-the-server]__0-nob52._.js +0 -4
  578. package/.next/server/chunks/ssr/[root-of-the-server]__092knlj._.js +0 -3
  579. package/.next/server/chunks/ssr/[root-of-the-server]__0mz33a7._.js +0 -3
  580. package/.next/server/chunks/ssr/[root-of-the-server]__0s4wb56._.js +0 -3
  581. package/.next/server/chunks/ssr/[root-of-the-server]__0s9dq5u._.js +0 -3
  582. package/.next/server/chunks/ssr/[root-of-the-server]__0sd3izg._.js +0 -3
  583. package/.next/server/chunks/ssr/[root-of-the-server]__0vnmv-s._.js +0 -3
  584. package/.next/server/chunks/ssr/[root-of-the-server]__1-13tcn._.js +0 -43
  585. package/.next/server/chunks/ssr/[root-of-the-server]__10-dz5o._.js +0 -61
  586. package/.next/server/chunks/ssr/[root-of-the-server]__1zidpfl._.js +0 -3
  587. package/.next/server/chunks/ssr/_001_ms1._.js +0 -33
  588. package/.next/server/chunks/ssr/_01n3o0m._.js +0 -3
  589. package/.next/server/chunks/ssr/_04z2c7b._.js +0 -3
  590. package/.next/server/chunks/ssr/_06tssji._.js +0 -3
  591. package/.next/server/chunks/ssr/_0fk4c7d._.js +0 -3
  592. package/.next/server/chunks/ssr/_0h42fze._.js +0 -3
  593. package/.next/server/chunks/ssr/_0h7zdni._.js +0 -3
  594. package/.next/server/chunks/ssr/_0mggveb._.js +0 -3
  595. package/.next/server/chunks/ssr/_0nbpc_8._.js +0 -3
  596. package/.next/server/chunks/ssr/_0q0zan6._.js +0 -70
  597. package/.next/server/chunks/ssr/_0zcjrbg._.js +0 -3
  598. package/.next/server/chunks/ssr/_0zhoc3r._.js +0 -3
  599. package/.next/server/chunks/ssr/_11j92tu._.js +0 -3
  600. package/.next/server/chunks/ssr/_13fke0x._.js +0 -3
  601. package/.next/server/chunks/ssr/_18cymkq._.js +0 -3
  602. package/.next/server/chunks/ssr/_1ebxla1._.js +0 -3
  603. package/.next/server/chunks/ssr/_1nj4niv._.js +0 -42
  604. package/.next/server/chunks/ssr/_1ov37if._.js +0 -3
  605. package/.next/server/chunks/ssr/_1ovmc9s._.js +0 -3
  606. package/.next/server/chunks/ssr/_1sji22n._.js +0 -3
  607. package/.next/server/chunks/ssr/_1vi_uo7._.js +0 -3
  608. package/.next/server/chunks/ssr/_1vyd1ji._.js +0 -3
  609. package/.next/server/chunks/ssr/_1xx4zlb._.js +0 -3
  610. package/.next/server/chunks/ssr/components_ui_1y1l7yj._.js +0 -3
  611. package/.next/server/chunks/ssr/features_bot_1s_-2vj._.js +0 -3
  612. package/.next/server/chunks/ssr/lib_realtime_12wg_dd._.js +0 -27
  613. package/.next/server/chunks/ssr/lib_realtime_15h_v1v._.js +0 -27
  614. package/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_0npjf8-._.js +0 -3
  615. package/.next/static/chunks/0n3jle9kbqfr2.js +0 -40
  616. package/.next/static/chunks/0r5qcctujhxli.js +0 -1
  617. package/.next/static/chunks/10teww7wt-f6h.js +0 -1
  618. package/.next/static/chunks/126fj4pga_72k.js +0 -1
  619. package/.next/static/chunks/159udiexf6dom.js +0 -2
  620. package/.next/static/chunks/18a96rkhi4_yd.js +0 -1
  621. package/.next/static/chunks/18gi7o2ibrgh8.js +0 -3
  622. package/.next/static/chunks/1dkjg87pxk0n9.js +0 -28
  623. package/.next/static/chunks/1q9z1tohil7xn.js +0 -1
  624. package/.next/static/chunks/1sjgfets224re.js +0 -1
  625. package/.next/static/chunks/1wszsr83t01gh.js +0 -1
  626. package/.next/static/chunks/22_zkas21rpna.js +0 -1
  627. package/.next/static/chunks/2fh4-3z_q8b_w.js +0 -1
  628. package/.next/static/chunks/2h0sd2vumhb15.js +0 -1
  629. package/.next/static/chunks/2szintyibu0s5.js +0 -1
  630. package/.next/static/chunks/2t4vhi3m8ahya.js +0 -1
  631. package/.next/static/chunks/2tigdtz3dpcy8.js +0 -1
  632. package/.next/static/chunks/3-b6b7entqazs.js +0 -1
  633. package/.next/static/chunks/3786h5vayt80-.js +0 -28
  634. package/.next/static/chunks/3cq5g494yuke8.css +0 -1
  635. package/.next/static/chunks/3dmbhsv2u_8kj.js +0 -1
  636. package/.next/static/chunks/3hibbjnt85-k6.js +0 -1
  637. package/.next/static/chunks/3i0a5px-oufgc.js +0 -1
  638. package/.next/static/chunks/3wexk9qo8zuj3.js +0 -18
  639. package/.next/static/chunks/3xk7yqgomx7yq.js +0 -1
  640. package/.next/static/chunks/3xre8bu_pk1p_.js +0 -1
  641. package/.next/static/chunks/3zv6t3i77xhr_.js +0 -1
  642. package/database/migrations/20260911030320_opposite_jack_power/migration.sql +0 -1
  643. package/docs/images/task-thread.png +0 -0
  644. package/features/bot/components/task-badge.tsx +0 -42
  645. package/features/bot/components/task-reply.tsx +0 -328
  646. package/features/bot/components/task-setting.tsx +0 -524
  647. package/features/bot/task.query.ts +0 -1079
  648. package/features/bot/task.store.ts +0 -487
  649. package/lib/realtime/client-secret.ts +0 -86
  650. package/lib/realtime/open-session.ts +0 -31
  651. package/lib/realtime/openai.ts +0 -35
  652. package/lib/realtime/realtime.audio.ts +0 -196
  653. package/lib/realtime/realtime.driver.ts +0 -489
  654. package/lib/realtime/realtime.protocol.ts +0 -393
  655. package/lib/realtime/realtime.schema.ts +0 -37
  656. package/lib/realtime/realtime.session.ts +0 -106
  657. package/lib/realtime/realtime.transport.ts +0 -384
  658. package/lib/realtime/xai.ts +0 -39
  659. /package/.next/server/app/api/bot/{task → thread}/[id]/route/build-manifest.json +0 -0
  660. /package/.next/server/app/api/bot/{task → thread}/[id]/route/server-reference-manifest.json +0 -0
  661. /package/.next/server/app/api/bot/{task → thread}/[id]/route.js.map +0 -0
  662. /package/.next/server/app/api/bot/{task → thread}/route/build-manifest.json +0 -0
  663. /package/.next/server/app/api/bot/{task → thread}/route/server-reference-manifest.json +0 -0
  664. /package/.next/server/app/api/bot/{task → thread}/route.js.map +0 -0
  665. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_buildManifest.js +0 -0
  666. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_clientMiddlewareManifest.js +0 -0
  667. /package/.next/static/{G6-gNoyGDEcgAsq-L4PE1 → yyRVBc0xxYQsh3GpbQX9b}/_ssgManifest.js +0 -0
@@ -0,0 +1,916 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { collectAmbiguousCorridors, collectBorderRuns, collectLabelRouteClearance, collectRouteRhythmIssues, routeBudgetMetrics } from '../renderers/shared/geometry.mjs';
6
+ import {
7
+ DESKTOP_READABILITY_VIEWPORT,
8
+ DESKTOP_READER_DIAGRAM_WIDTH,
9
+ MIN_PROJECTED_NODE_TEXT_PX,
10
+ projectedNodeTextPx,
11
+ } from '../renderers/shared/desktop-readability.mjs';
12
+
13
+ const input = process.argv[2];
14
+
15
+ if (!input || input === '-h' || input === '--help') {
16
+ console.error('Usage: node scripts/check-render-output.mjs <diagram.html>');
17
+ process.exit(input ? 0 : 2);
18
+ }
19
+
20
+ const htmlPath = path.resolve(input);
21
+ let html;
22
+ try {
23
+ html = fs.readFileSync(htmlPath, 'utf8');
24
+ } catch (err) {
25
+ console.error(JSON.stringify({
26
+ ok: false,
27
+ file: htmlPath,
28
+ checks: [{ name: 'file_readable', ok: false, details: [err.message] }],
29
+ }, null, 2));
30
+ process.exit(1);
31
+ }
32
+
33
+ const checks = [];
34
+ let composition = {
35
+ schemaVersion: 1,
36
+ profile: 'standard',
37
+ status: 'pass',
38
+ summary: { errors: 0, warnings: 0 },
39
+ metrics: {
40
+ properCrossings: 0,
41
+ ambiguousCorridors: 0,
42
+ containerBorderRuns: 0,
43
+ labelRouteClearanceIssues: 0,
44
+ minLabelRouteClearance: null,
45
+ maxBends: 0,
46
+ routesOverSuggestedBends: 0,
47
+ maxStretch: null,
48
+ routesOverSuggestedStretch: 0,
49
+ minSegmentPx: null,
50
+ minInteriorSegmentPx: null,
51
+ shortSegmentCount: 0,
52
+ shortEndpointSegmentCount: 0,
53
+ shortInteriorSegmentCount: 0,
54
+ microSegmentCount: 0,
55
+ desktopReadabilityIssues: 0,
56
+ minProjectedNodeTextPx: null,
57
+ },
58
+ suggestedLimits: { bendsPerRelationship: 2, stretch: 1.35, segmentPx: 16, microSegmentPx: 8 },
59
+ issues: [],
60
+ };
61
+
62
+ const NON_FINITE_TOKEN = /\b(?:NaN|undefined|Infinity)\b/;
63
+ // Consume comments/CDATA as whole tokens, including any tag-like prose.
64
+ const SVG_TAG_TOKEN = /<!--[\s\S]*?(?:-->|$)|<!\[CDATA\[[\s\S]*?(?:\]\]>|$)|<(\/?)([A-Za-z][\w:-]*)(?=[\s/>])(?:[^>"']|"[^"]*"|'[^']*')*>/g;
65
+ const HTML_VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
66
+ const SVG_HTML_INTEGRATION_POINTS = new Set(['foreignobject', 'desc', 'title']);
67
+ const HTML_ATTRIBUTE = /([A-Za-z_:][\w:.-]*)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/g;
68
+ const NUMERIC_ATTRS = new Set([
69
+ 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'dx', 'dy', 'cx', 'cy', 'r', 'rx', 'ry', 'fx', 'fy',
70
+ 'fr', 'width', 'height', 'd', 'points', 'pathlength', 'transform', 'viewbox', 'offset',
71
+ 'opacity', 'fill-opacity', 'flood-opacity', 'stop-opacity', 'stroke-opacity', 'font-size',
72
+ 'font-size-adjust', 'font-weight', 'letter-spacing', 'word-spacing', 'kerning', 'stroke-width',
73
+ 'stroke-dasharray', 'stroke-dashoffset', 'stroke-miterlimit', 'textlength', 'startoffset',
74
+ 'rotate', 'markerwidth', 'markerheight', 'refx', 'refy', 'orient', 'patterntransform',
75
+ 'gradienttransform', 'filterres', 'stddeviation', 'basefrequency', 'numoctaves', 'seed',
76
+ 'surfacescale', 'diffuseconstant', 'specularconstant', 'specularexponent',
77
+ 'limitingconeangle', 'azimuth', 'elevation', 'pointsatx', 'pointsaty', 'pointsatz',
78
+ 'kernelmatrix', 'order', 'divisor', 'bias', 'targetx', 'targety', 'kernelunitlength',
79
+ 'scale', 'radius', 'k1', 'k2', 'k3', 'k4', 'tablevalues', 'slope', 'intercept',
80
+ 'amplitude', 'exponent',
81
+ ]);
82
+ const ELEMENT_NUMERIC_ATTRS = new Map([
83
+ ['fecolormatrix', new Set(['values'])],
84
+ ['fepointlight', new Set(['z'])],
85
+ ['fespotlight', new Set(['z'])],
86
+ ]);
87
+
88
+ function addCheck(name, ok, details = []) {
89
+ checks.push({ name, ok, details });
90
+ }
91
+
92
+ const svgMatches = [...html.matchAll(/<svg\b[\s\S]*?<\/svg>/gi)];
93
+ addCheck('single_svg', svgMatches.length === 1, [`found ${svgMatches.length} <svg> block(s)`]);
94
+
95
+ if (svgMatches.length === 1) {
96
+ const svg = svgMatches[0][0];
97
+ const svgRoot = svg.match(/<svg\b[^>]*>/i)?.[0] || '';
98
+ const svgAttrs = parseAttrs(svgRoot);
99
+ const qualityProfile = svgAttrs['data-quality-profile'] || 'standard';
100
+ const qualityGatesEnforced = svgAttrs['data-quality-gates'] !== 'advisory';
101
+ const nonFiniteAttrs = collectNonFiniteAttrs(svg);
102
+ addCheck('finite_svg', nonFiniteAttrs.length === 0, nonFiniteAttrs);
103
+ const legendStart = svg.indexOf('<!-- Legend -->');
104
+ const beforeLegend = legendStart >= 0 ? svg.slice(0, legendStart) : svg;
105
+ const desktopReadabilityIssue = collectDesktopReadability(svgAttrs, beforeLegend);
106
+ const arrows = collectArrows(beforeLegend);
107
+ const diagonal = arrows.flatMap((arrow) => diagonalStraightSegments(arrow).map((segment) => ({ arrow, ...segment })));
108
+ addCheck(
109
+ 'orthogonal_arrows',
110
+ diagonal.length === 0,
111
+ diagonal.map(({ arrow, segmentIndex }) => `${arrow.kind} ${arrow.index} segment ${segmentIndex + 1}: ${arrow.raw}`),
112
+ );
113
+ const relationshipCrossings = collectRelationshipCrossings(arrows);
114
+ const compositionFrames = collectCompositionFrames(beforeLegend);
115
+ const containerBorderRuns = collectBorderRuns({
116
+ routedRelations: arrows
117
+ .filter((arrow) => arrow.from && arrow.to && arrow.borderSegments.length)
118
+ .map((arrow) => ({
119
+ relation: arrow,
120
+ relationIndex: arrow.index,
121
+ segments: arrow.borderSegments,
122
+ })),
123
+ frames: compositionFrames,
124
+ });
125
+ const routedRelationships = arrows
126
+ .filter((arrow) => arrow.from && arrow.to && arrow.routePoints.length)
127
+ .map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints }));
128
+ const routeMetrics = routeBudgetMetrics({ routedRelations: routedRelationships });
129
+ const routeRhythmIssues = collectRouteRhythmIssues({ routedRelations: routedRelationships });
130
+ const ambiguousCorridors = collectAmbiguousCorridors({ routedRelations: routedRelationships });
131
+ const relationshipLabels = collectRelationshipLabelMasks(beforeLegend, arrows);
132
+ const labelClearanceThreshold = qualityProfile === 'showcase' ? 4 : 2;
133
+ const labelRouteMeasurements = collectLabelRouteClearance({
134
+ labels: relationshipLabels,
135
+ routedRelations: arrows.map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints })),
136
+ threshold: Number.MAX_VALUE,
137
+ });
138
+ const labelRouteClearance = collectLabelRouteClearance({
139
+ labels: relationshipLabels,
140
+ routedRelations: arrows.map((arrow) => ({ relation: arrow, relationIndex: arrow.index, points: arrow.routePoints })),
141
+ threshold: labelClearanceThreshold,
142
+ });
143
+ const crossingIsError = qualityProfile === 'showcase';
144
+ const corridorIsError = qualityProfile === 'showcase';
145
+ const rhythmIsError = qualityProfile === 'showcase';
146
+ const labelClearanceIsError = qualityProfile === 'showcase';
147
+ const desktopReadabilityIsError = qualityProfile === 'showcase';
148
+ const compositionErrors = (qualityGatesEnforced ? containerBorderRuns.length : 0)
149
+ + (crossingIsError ? relationshipCrossings.length : 0)
150
+ + (corridorIsError ? ambiguousCorridors.length : 0)
151
+ + (labelClearanceIsError ? labelRouteClearance.length : 0)
152
+ + (rhythmIsError ? routeRhythmIssues.length : 0)
153
+ + (desktopReadabilityIsError && desktopReadabilityIssue ? 1 : 0);
154
+ const compositionWarnings = (qualityGatesEnforced ? 0 : containerBorderRuns.length)
155
+ + (crossingIsError ? 0 : relationshipCrossings.length)
156
+ + (corridorIsError ? 0 : ambiguousCorridors.length)
157
+ + (labelClearanceIsError ? 0 : labelRouteClearance.length)
158
+ + (rhythmIsError ? 0 : routeRhythmIssues.length)
159
+ + (desktopReadabilityIsError || !desktopReadabilityIssue ? 0 : 1);
160
+ composition = {
161
+ schemaVersion: 1,
162
+ profile: qualityProfile,
163
+ status: compositionErrors ? 'fail' : 'pass',
164
+ summary: {
165
+ errors: compositionErrors,
166
+ warnings: compositionWarnings,
167
+ },
168
+ metrics: {
169
+ properCrossings: relationshipCrossings.length,
170
+ ambiguousCorridors: ambiguousCorridors.length,
171
+ containerBorderRuns: containerBorderRuns.length,
172
+ labelRouteClearanceIssues: labelRouteClearance.length,
173
+ minLabelRouteClearance: labelRouteMeasurements.length
174
+ ? Math.round(Math.min(...labelRouteMeasurements.map((hit) => hit.clearance)) * 10) / 10
175
+ : null,
176
+ desktopReadabilityIssues: desktopReadabilityIssue ? 1 : 0,
177
+ minProjectedNodeTextPx: desktopReadabilityIssue?.projectedFontPx ?? null,
178
+ ...roundedRouteMetrics(routeMetrics),
179
+ },
180
+ suggestedLimits: { bendsPerRelationship: 2, stretch: 1.35, segmentPx: 16, microSegmentPx: 8 },
181
+ issues: [
182
+ ...containerBorderRuns.map((hit) => ({
183
+ severity: qualityGatesEnforced ? 'error' : 'warning',
184
+ code: 'composition/container-border-run',
185
+ relationship: relationshipRecord(hit.relation),
186
+ frame: frameRecord(hit.frame),
187
+ side: hit.side,
188
+ segmentIndex: hit.segmentIndex,
189
+ overlapLength: Math.round(hit.overlapLength * 10) / 10,
190
+ from: hit.overlapStart.map((value) => Math.round(value * 10) / 10),
191
+ to: hit.overlapEnd.map((value) => Math.round(value * 10) / 10),
192
+ })),
193
+ ...labelRouteClearance.map((hit) => ({
194
+ severity: labelClearanceIsError ? 'error' : 'warning',
195
+ code: 'composition/label-route-clearance',
196
+ label: hit.label?.label || hit.labelRelation?.label || '',
197
+ labelRelationship: relationshipRecord(hit.labelRelation),
198
+ otherRelationship: relationshipRecord(hit.otherRelation),
199
+ segmentIndex: hit.segmentIndex,
200
+ labelRect: roundedRect(hit.rect),
201
+ clearance: Math.round(hit.clearance * 10) / 10,
202
+ intersectionLength: Math.round((hit.intersectionLength || 0) * 10) / 10,
203
+ threshold: hit.threshold,
204
+ from: hit.start.map((value) => Math.round(value * 10) / 10),
205
+ to: hit.end.map((value) => Math.round(value * 10) / 10),
206
+ })),
207
+ ...relationshipCrossings.map((hit) => ({
208
+ severity: crossingIsError ? 'error' : 'warning',
209
+ code: 'composition/proper-crossing',
210
+ relationship: relationshipRecord(hit.left),
211
+ otherRelationship: relationshipRecord(hit.right),
212
+ point: hit.point.map((value) => Math.round(value * 10) / 10),
213
+ })),
214
+ ...ambiguousCorridors.map((hit) => ({
215
+ severity: corridorIsError ? 'error' : 'warning',
216
+ code: 'composition/ambiguous-corridor',
217
+ relationship: relationshipRecord(hit.left.relation),
218
+ otherRelationship: relationshipRecord(hit.right.relation),
219
+ segmentIndex: hit.leftSegment,
220
+ otherSegmentIndex: hit.rightSegment,
221
+ overlapLength: Math.round(hit.overlapLength * 10) / 10,
222
+ from: hit.overlapStart.map((value) => Math.round(value * 10) / 10),
223
+ to: hit.overlapEnd.map((value) => Math.round(value * 10) / 10),
224
+ })),
225
+ ...routeRhythmIssues.map((hit) => ({
226
+ severity: rhythmIsError ? 'error' : 'warning',
227
+ code: hit.code,
228
+ relationship: relationshipRecord(hit.relation),
229
+ segmentIndex: hit.segmentIndex,
230
+ position: hit.position,
231
+ length: Math.round(hit.length * 10) / 10,
232
+ from: hit.start.map((value) => Math.round(value * 10) / 10),
233
+ to: hit.end.map((value) => Math.round(value * 10) / 10),
234
+ })),
235
+ ...(desktopReadabilityIssue ? [{
236
+ severity: desktopReadabilityIsError ? 'error' : 'warning',
237
+ code: 'composition/desktop-readability',
238
+ viewportWidth: DESKTOP_READABILITY_VIEWPORT.width,
239
+ viewportHeight: DESKTOP_READABILITY_VIEWPORT.height,
240
+ availableDiagramWidth: DESKTOP_READER_DIAGRAM_WIDTH,
241
+ viewBoxWidth: desktopReadabilityIssue.viewBoxWidth,
242
+ scale: desktopReadabilityIssue.scale,
243
+ text: desktopReadabilityIssue.text,
244
+ detail: desktopReadabilityIssue.detail,
245
+ sourceFontPx: desktopReadabilityIssue.sourceFontPx,
246
+ projectedFontPx: desktopReadabilityIssue.projectedFontPx,
247
+ minimumProjectedFontPx: MIN_PROJECTED_NODE_TEXT_PX,
248
+ }] : []),
249
+ ],
250
+ };
251
+ addCheck(
252
+ 'label_route_clearance',
253
+ !labelClearanceIsError || labelRouteClearance.length === 0,
254
+ labelRouteClearance.map((hit) => (
255
+ `[composition/label-route-clearance] ${qualityProfile} label "${hit.label?.label || hit.labelRelation?.label || ''}" on ${relationshipName(hit.labelRelation)} is ${Math.round(hit.clearance * 10) / 10}px from ${relationshipName(hit.otherRelation)} segment ${hit.segmentIndex} [${formatPoint(hit.start)}] -> [${formatPoint(hit.end)}]${hit.intersectionLength > 0 ? ` with ${Math.round(hit.intersectionLength * 10) / 10}px hidden by the mask` : ''} (minimum ${hit.threshold}px) — use renderer-supported label controls (message y for sequence; otherwise labelAt, labelDx, labelDy, or labelSegment), or adjust the other relationship route/via/channel.`
256
+ )),
257
+ );
258
+ addCheck(
259
+ 'relationship_crossings',
260
+ !crossingIsError || relationshipCrossings.length === 0,
261
+ relationshipCrossings.map((hit) => (
262
+ `[composition/proper-crossing] ${qualityProfile} ${relationshipName(hit.left)} crosses ${relationshipName(hit.right)} at [${formatPoint(hit.point)}]`
263
+ )),
264
+ );
265
+ addCheck(
266
+ 'relationship_corridors',
267
+ !corridorIsError || ambiguousCorridors.length === 0,
268
+ ambiguousCorridors.map((hit) => (
269
+ `[composition/ambiguous-corridor] ${qualityProfile} ${relationshipName(hit.left.relation)} shares a ${Math.round(hit.overlapLength * 10) / 10}px corridor with ${relationshipName(hit.right.relation)} at [${formatPoint(hit.overlapStart)}] -> [${formatPoint(hit.overlapEnd)}]`
270
+ )),
271
+ );
272
+ addCheck(
273
+ 'container_border_runs',
274
+ !qualityGatesEnforced || containerBorderRuns.length === 0,
275
+ containerBorderRuns.map((hit) => (
276
+ `[composition/container-border-run] ${relationshipName(hit.relation)} follows ${frameName(hit.frame)} ${hit.side} border for ${Math.round(hit.overlapLength * 10) / 10}px on segment ${hit.segmentIndex} [${formatPoint(hit.overlapStart)}] -> [${formatPoint(hit.overlapEnd)}]`
277
+ )),
278
+ );
279
+ addCheck(
280
+ 'route_rhythm',
281
+ !rhythmIsError || routeRhythmIssues.length === 0,
282
+ routeRhythmIssues.map((hit) => (
283
+ `[${hit.code}] ${qualityProfile} ${relationshipName(hit.relation)} has a ${Math.round(hit.length * 10) / 10}px ${hit.position} segment ${hit.segmentIndex} [${formatPoint(hit.start)}] -> [${formatPoint(hit.end)}]`
284
+ )),
285
+ );
286
+
287
+ if (legendStart >= 0) {
288
+ const legendFragment = svg.slice(legendStart);
289
+ const legendBoxes = collectLegendBoxes(legendFragment);
290
+ const collisions = collectLegendCollisions(arrows, legendBoxes);
291
+ addCheck(
292
+ 'legend_clearance',
293
+ collisions.length === 0,
294
+ collisions.map((hit) => `${hit.arrow.kind} ${hit.arrow.index} crosses legend ${hit.box.label}`),
295
+ );
296
+ } else {
297
+ addCheck('legend_clearance', true, ['no legend marker found']);
298
+ }
299
+ }
300
+
301
+ const ok = checks.every((check) => check.ok) && composition.status !== 'fail';
302
+ console.log(JSON.stringify({ ok, file: htmlPath, checks, composition }, null, 2));
303
+ // Let pending stdout writes drain: large receipts are asynchronous when piped.
304
+ process.exitCode = ok ? 0 : 1;
305
+
306
+ function collectArrows(fragment) {
307
+ const arrows = [];
308
+ let index = 0;
309
+
310
+ for (const tag of fragment.matchAll(/<(path|line)\b[^>]*>/gi)) {
311
+ const raw = tag[0];
312
+ if (!/\bclass="[^"]*\ba-(?:default|emphasis|security|dashed)\b/.test(raw)) continue;
313
+ if (!/\bmarker-end=/.test(raw)) continue;
314
+ const attrs = parseAttrs(raw);
315
+ const segments = tag[1].toLowerCase() === 'line'
316
+ ? lineSegments(attrs)
317
+ : pathSegments(attrs.d || '');
318
+ const borderSegments = tag[1].toLowerCase() === 'line'
319
+ ? segments
320
+ : straightPathSegments(attrs.d || '');
321
+ arrows.push({
322
+ kind: tag[1].toLowerCase(),
323
+ index: index += 1,
324
+ raw,
325
+ segments,
326
+ borderSegments,
327
+ routePoints: parseRoutePoints(attrs['data-composition-points']) || (
328
+ borderSegments.length ? [borderSegments[0].start, ...borderSegments.map((segment) => segment.end)] : []
329
+ ),
330
+ from: attrs['data-edge-from'] || attrs['data-composition-edge-from'],
331
+ to: attrs['data-edge-to'] || attrs['data-composition-edge-to'],
332
+ id: attrs['data-edge-id'] || attrs['data-composition-edge-id'],
333
+ key: attrs['data-edge-key'],
334
+ label: attrs['data-edge-label'],
335
+ offset: tag.index,
336
+ });
337
+ }
338
+
339
+ return arrows;
340
+ }
341
+
342
+ function collectRelationshipLabelMasks(fragment, arrows) {
343
+ const labels = [];
344
+ for (const match of fragment.matchAll(/<g\b[^>]*\bdata-edge-(?:key|id|from)="[^"]*"[^>]*>[\s\S]*?<\/g>/gi)) {
345
+ const group = match[0];
346
+ const groupAttrs = parseAttrs(group.match(/<g\b[^>]*>/i)?.[0] || '');
347
+ const rectTag = [...group.matchAll(/<rect\b[^>]*>/gi)]
348
+ .map((item) => item[0])
349
+ .find((tag) => /\bclass="[^"]*\bc-mask\b/.test(tag));
350
+ if (!rectTag) continue;
351
+ const attrs = parseAttrs(rectTag);
352
+ const rect = {
353
+ x: numberAttr(attrs, 'x'),
354
+ y: numberAttr(attrs, 'y'),
355
+ width: numberAttr(attrs, 'width'),
356
+ height: numberAttr(attrs, 'height'),
357
+ };
358
+ if (![rect.x, rect.y, rect.width, rect.height].every(Number.isFinite)) continue;
359
+ const groupStart = match.index;
360
+ const groupEnd = groupStart + group.length;
361
+ const containedOwner = arrows.find((arrow) => (
362
+ arrow.offset > groupStart
363
+ && arrow.offset < groupEnd
364
+ && arrow.from === groupAttrs['data-edge-from']
365
+ && arrow.to === groupAttrs['data-edge-to']
366
+ && (!groupAttrs['data-edge-id'] || !arrow.id || arrow.id === groupAttrs['data-edge-id'])
367
+ ));
368
+ const owner = arrows.find((arrow) => (
369
+ groupAttrs['data-edge-key'] !== undefined && arrow.key === groupAttrs['data-edge-key']
370
+ )) || containedOwner || arrows.find((arrow) => (
371
+ arrow.id === groupAttrs['data-edge-id']
372
+ && arrow.from === groupAttrs['data-edge-from']
373
+ && arrow.to === groupAttrs['data-edge-to']
374
+ ));
375
+ if (!owner) continue;
376
+ if (owner.key === undefined && groupAttrs['data-edge-key'] !== undefined) owner.key = groupAttrs['data-edge-key'];
377
+ if (!owner.id && groupAttrs['data-edge-id']) owner.id = groupAttrs['data-edge-id'];
378
+ if (!owner.label && groupAttrs['data-edge-label']) owner.label = groupAttrs['data-edge-label'];
379
+ labels.push({
380
+ relation: owner,
381
+ relationIndex: owner.index,
382
+ label: groupAttrs['data-edge-label'] || '',
383
+ rect,
384
+ });
385
+ }
386
+ return labels;
387
+ }
388
+
389
+ function roundedRect(rect) {
390
+ return Object.fromEntries(Object.entries(rect).map(([key, value]) => [key, Math.round(value * 10) / 10]));
391
+ }
392
+
393
+ function roundedRouteMetrics(metrics) {
394
+ return {
395
+ ...metrics,
396
+ maxStretch: metrics.maxStretch == null ? null : Math.round(metrics.maxStretch * 1000) / 1000,
397
+ minSegmentPx: metrics.minSegmentPx == null ? null : Math.round(metrics.minSegmentPx * 10) / 10,
398
+ minInteriorSegmentPx: metrics.minInteriorSegmentPx == null ? null : Math.round(metrics.minInteriorSegmentPx * 10) / 10,
399
+ };
400
+ }
401
+
402
+ function parseRoutePoints(value) {
403
+ if (!value) return null;
404
+ const points = value.split(';').map((pair) => pair.split(',').map(Number));
405
+ return points.length >= 2 && points.every(isPoint) ? points : null;
406
+ }
407
+
408
+ function collectRelationshipCrossings(arrows) {
409
+ const relationships = arrows.filter((arrow) => arrow.from && arrow.to && arrow.segments.length);
410
+ const crossings = [];
411
+ for (let leftIndex = 0; leftIndex < relationships.length; leftIndex += 1) {
412
+ const left = relationships[leftIndex];
413
+ for (let rightIndex = leftIndex + 1; rightIndex < relationships.length; rightIndex += 1) {
414
+ const right = relationships[rightIndex];
415
+ if ([left.from, left.to].some((id) => id === right.from || id === right.to)) continue;
416
+ let point = null;
417
+ for (const leftSegment of left.segments) {
418
+ for (const rightSegment of right.segments) {
419
+ point = properSegmentIntersection(leftSegment.start, leftSegment.end, rightSegment.start, rightSegment.end);
420
+ if (point) break;
421
+ }
422
+ if (point) break;
423
+ }
424
+ if (point) crossings.push({ left, right, point });
425
+ }
426
+ }
427
+ return crossings;
428
+ }
429
+
430
+ function relationshipName(arrow) {
431
+ return arrow.id
432
+ ? `relationship id "${arrow.id}" ("${arrow.from}" -> "${arrow.to}")`
433
+ : `relationship "${arrow.from}" -> "${arrow.to}"`;
434
+ }
435
+
436
+ function relationshipRecord(arrow) {
437
+ const stableIndex = Number(arrow.key);
438
+ return {
439
+ id: arrow.id,
440
+ from: arrow.from,
441
+ to: arrow.to,
442
+ label: arrow.label || '',
443
+ collectionIndex: Number.isInteger(stableIndex) && stableIndex >= 0 ? stableIndex : arrow.index - 1,
444
+ artifactIndex: arrow.index,
445
+ };
446
+ }
447
+
448
+ function collectCompositionFrames(fragment) {
449
+ const frames = [];
450
+ for (const match of fragment.matchAll(/<(rect|path|line)\b[^>]*>/gi)) {
451
+ const attrs = parseAttrs(match[0]);
452
+ const kind = attrs['data-composition-frame-kind'];
453
+ if (!kind) continue;
454
+ const identity = attrs['data-composition-frame-id'] || frames.length;
455
+ if (match[1].toLowerCase() === 'rect') {
456
+ const frame = {
457
+ kind,
458
+ id: identity,
459
+ x: numberAttr(attrs, 'x'),
460
+ y: numberAttr(attrs, 'y'),
461
+ width: numberAttr(attrs, 'width'),
462
+ height: numberAttr(attrs, 'height'),
463
+ radius: numberAttr(attrs, 'rx') || 0,
464
+ };
465
+ if ([frame.x, frame.y, frame.width, frame.height].every(Number.isFinite)) frames.push(frame);
466
+ continue;
467
+ }
468
+ const segments = match[1].toLowerCase() === 'line'
469
+ ? lineSegments(attrs)
470
+ : pathSegments(attrs.d || '');
471
+ for (const [segmentIndex, segment] of segments.entries()) {
472
+ frames.push({
473
+ kind,
474
+ id: segments.length > 1 ? `${identity}:${segmentIndex}` : identity,
475
+ shape: 'line',
476
+ start: segment.start,
477
+ end: segment.end,
478
+ });
479
+ }
480
+ }
481
+ return frames;
482
+ }
483
+
484
+ function frameName(frame) {
485
+ return `${frame.kind || 'frame'} "${frame.id}"`;
486
+ }
487
+
488
+ function frameRecord(frame) {
489
+ return { kind: frame.kind, id: frame.id };
490
+ }
491
+
492
+ function formatPoint(point) {
493
+ return point.map((value) => Math.round(value * 10) / 10).join(', ');
494
+ }
495
+
496
+ function lineSegments(attrs) {
497
+ const start = [numberAttr(attrs, 'x1'), numberAttr(attrs, 'y1')];
498
+ const end = [numberAttr(attrs, 'x2'), numberAttr(attrs, 'y2')];
499
+ if (!isPoint(start) || !isPoint(end)) return [];
500
+ return [{ start, end }];
501
+ }
502
+
503
+ function pathSegments(d) {
504
+ const points = pointsFromPath(d);
505
+ const segments = [];
506
+ for (let i = 1; i < points.length; i += 1) {
507
+ segments.push({ start: points[i - 1], end: points[i] });
508
+ }
509
+ return segments;
510
+ }
511
+
512
+ // Border runs use exact visible primitives. Non-collinear Q curves are never
513
+ // flattened into chords here: a tangent or sampled near-horizontal curve is
514
+ // not a structural border run. A fully collinear Q remains a straight visible
515
+ // primitive and is included.
516
+ function straightPathSegments(d) {
517
+ const tokens = d.match(/[MLHVQZmlhvqz]|[-+]?(?:\d*\.)?\d+(?:e[-+]?\d+)?/g) || [];
518
+ const segments = [];
519
+ let i = 0;
520
+ let command = '';
521
+ let current = [0, 0];
522
+ let start = null;
523
+ while (i < tokens.length) {
524
+ if (isCommand(tokens[i])) command = tokens[i++];
525
+ if (!command) break;
526
+ const absolute = command === command.toUpperCase();
527
+ switch (command.toUpperCase()) {
528
+ case 'M':
529
+ case 'L': {
530
+ let first = true;
531
+ while (i + 1 < tokens.length && !isCommand(tokens[i])) {
532
+ const point = [Number.parseFloat(tokens[i++]), Number.parseFloat(tokens[i++])];
533
+ if (!point.every(Number.isFinite)) break;
534
+ const next = absolute ? point : [current[0] + point[0], current[1] + point[1]];
535
+ if (command.toUpperCase() === 'L' || !first) segments.push({ start: current, end: next });
536
+ current = next;
537
+ if (!start) start = current;
538
+ first = false;
539
+ }
540
+ break;
541
+ }
542
+ case 'H': {
543
+ while (i < tokens.length && !isCommand(tokens[i])) {
544
+ const value = Number.parseFloat(tokens[i++]);
545
+ if (!Number.isFinite(value)) break;
546
+ const next = [absolute ? value : current[0] + value, current[1]];
547
+ segments.push({ start: current, end: next });
548
+ current = next;
549
+ }
550
+ break;
551
+ }
552
+ case 'V': {
553
+ while (i < tokens.length && !isCommand(tokens[i])) {
554
+ const value = Number.parseFloat(tokens[i++]);
555
+ if (!Number.isFinite(value)) break;
556
+ const next = [current[0], absolute ? value : current[1] + value];
557
+ segments.push({ start: current, end: next });
558
+ current = next;
559
+ }
560
+ break;
561
+ }
562
+ case 'Q': {
563
+ while (i + 3 < tokens.length && !isCommand(tokens[i])) {
564
+ const values = [0, 0, 0, 0].map(() => Number.parseFloat(tokens[i++]));
565
+ if (!values.every(Number.isFinite)) break;
566
+ const control = absolute ? values.slice(0, 2) : [current[0] + values[0], current[1] + values[1]];
567
+ const end = absolute ? values.slice(2, 4) : [current[0] + values[2], current[1] + values[3]];
568
+ if (Math.abs(crossProduct(current, control, end)) <= 1e-9) segments.push({ start: current, end });
569
+ current = end;
570
+ }
571
+ break;
572
+ }
573
+ case 'Z':
574
+ if (start) segments.push({ start: current, end: start });
575
+ current = start || current;
576
+ command = '';
577
+ break;
578
+ default:
579
+ return [];
580
+ }
581
+ }
582
+ return segments.filter(({ start: a, end: b }) => isPoint(a) && isPoint(b));
583
+ }
584
+
585
+ function diagonalStraightSegments(arrow) {
586
+ return arrow.borderSegments.flatMap(({ start, end }, segmentIndex) => (
587
+ Math.abs(start[0] - end[0]) > 0.01 && Math.abs(start[1] - end[1]) > 0.01
588
+ ? [{ segmentIndex, start, end }]
589
+ : []
590
+ ));
591
+ }
592
+
593
+ function collectLegendBoxes(fragment) {
594
+ const boxes = [];
595
+
596
+ for (const match of fragment.matchAll(/<rect\b[^>]*>/gi)) {
597
+ const attrs = parseAttrs(match[0]);
598
+ const x = numberAttr(attrs, 'x');
599
+ const y = numberAttr(attrs, 'y');
600
+ const width = numberAttr(attrs, 'width');
601
+ const height = numberAttr(attrs, 'height');
602
+ if ([x, y, width, height].every(Number.isFinite)) {
603
+ boxes.push({ x1: x, y1: y, x2: x + width, y2: y + height, label: `rect@${x},${y}` });
604
+ }
605
+ }
606
+
607
+ for (const match of fragment.matchAll(/<text\b([^>]*)>([\s\S]*?)<\/text>/gi)) {
608
+ const attrs = parseAttrs(match[1]);
609
+ const box = textBox(attrs, stripTags(match[2]).trim());
610
+ if (box) boxes.push(box);
611
+ }
612
+
613
+ return boxes;
614
+ }
615
+
616
+ function collectLegendCollisions(arrows, boxes) {
617
+ const collisions = [];
618
+ for (const arrow of arrows) {
619
+ for (const segment of arrow.segments) {
620
+ for (const box of boxes) {
621
+ if (segmentIntersectsBox(segment, padBox(box, 2))) {
622
+ collisions.push({ arrow, box });
623
+ }
624
+ }
625
+ }
626
+ }
627
+ return collisions;
628
+ }
629
+
630
+ function textBox(attrs, text) {
631
+ const x = numberAttr(attrs, 'x');
632
+ const y = numberAttr(attrs, 'y');
633
+ const fontSize = Number.parseFloat(attrs['font-size'] || '10');
634
+ if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(fontSize)) return null;
635
+ const width = estimatedTextWidth(text, fontSize);
636
+ const anchor = attrs['text-anchor'] || 'start';
637
+ let x1 = x;
638
+ if (anchor === 'middle') x1 = x - width / 2;
639
+ if (anchor === 'end') x1 = x - width;
640
+ return {
641
+ x1,
642
+ y1: y - fontSize,
643
+ x2: x1 + width,
644
+ y2: y + fontSize * 0.25,
645
+ label: text || `text@${x},${y}`,
646
+ };
647
+ }
648
+
649
+ function collectDesktopReadability(svgAttrs, fragment) {
650
+ const viewBox = String(svgAttrs.viewBox || '').trim().split(/[\s,]+/).map(Number);
651
+ const viewBoxWidth = viewBox.length === 4 ? viewBox[2] : Number.NaN;
652
+ if (!Number.isFinite(viewBoxWidth) || viewBoxWidth <= 0) return null;
653
+ const scale = Math.min(1, DESKTOP_READER_DIAGRAM_WIDTH / viewBoxWidth);
654
+ let worst = null;
655
+ for (const match of fragment.matchAll(/<text\b([^>]*)>([\s\S]*?)<\/text>/gi)) {
656
+ const primary = /\bdata-node-label(?:\s*=|\s|$)/i.test(match[1]);
657
+ const boundary = /\bdata-boundary-label(?:\s*=|\s|$)/i.test(match[1]);
658
+ const context = /\bdata-detail\s*=\s*"context"/i.test(match[1]);
659
+ if (!primary && !boundary && !context) continue;
660
+ const attrs = parseAttrs(match[1]);
661
+ const fontSize = Number.parseFloat(attrs['font-size'] || '');
662
+ if (!Number.isFinite(fontSize)) continue;
663
+ const projected = projectedNodeTextPx(fontSize, viewBoxWidth);
664
+ if (projected >= MIN_PROJECTED_NODE_TEXT_PX) continue;
665
+ const candidate = {
666
+ viewBoxWidth,
667
+ scale,
668
+ text: stripTags(match[2]).trim(),
669
+ detail: primary
670
+ ? 'primary'
671
+ : boundary ? 'boundary' : 'context',
672
+ sourceFontPx: fontSize,
673
+ projectedFontPx: projected,
674
+ };
675
+ if (!worst || candidate.projectedFontPx < worst.projectedFontPx) worst = candidate;
676
+ }
677
+ return worst;
678
+ }
679
+
680
+ function estimatedTextWidth(text, fontSize) {
681
+ let units = 0;
682
+ for (const char of text) units += char.charCodeAt(0) > 255 ? 1.8 : 0.62;
683
+ return Math.max(fontSize, units * fontSize);
684
+ }
685
+
686
+ function pointsFromPath(d) {
687
+ const tokens = d.match(/[MLHVQZmlhvqz]|[-+]?(?:\d*\.)?\d+(?:e[-+]?\d+)?/g) || [];
688
+ const points = [];
689
+ let i = 0;
690
+ let command = '';
691
+ let current = [0, 0];
692
+ let start = null;
693
+
694
+ while (i < tokens.length) {
695
+ if (isCommand(tokens[i])) command = tokens[i++];
696
+ if (!command) break;
697
+
698
+ const absolute = command === command.toUpperCase();
699
+ switch (command.toUpperCase()) {
700
+ case 'M':
701
+ case 'L': {
702
+ while (i + 1 < tokens.length && !isCommand(tokens[i])) {
703
+ const x = Number.parseFloat(tokens[i++]);
704
+ const y = Number.parseFloat(tokens[i++]);
705
+ if (!Number.isFinite(x) || !Number.isFinite(y)) break;
706
+ current = absolute ? [x, y] : [current[0] + x, current[1] + y];
707
+ points.push(current);
708
+ if (!start) start = current;
709
+ }
710
+ break;
711
+ }
712
+ case 'H': {
713
+ while (i < tokens.length && !isCommand(tokens[i])) {
714
+ const x = Number.parseFloat(tokens[i++]);
715
+ if (!Number.isFinite(x)) break;
716
+ current = absolute ? [x, current[1]] : [current[0] + x, current[1]];
717
+ points.push(current);
718
+ }
719
+ break;
720
+ }
721
+ case 'V': {
722
+ while (i < tokens.length && !isCommand(tokens[i])) {
723
+ const y = Number.parseFloat(tokens[i++]);
724
+ if (!Number.isFinite(y)) break;
725
+ current = absolute ? [current[0], y] : [current[0], current[1] + y];
726
+ points.push(current);
727
+ }
728
+ break;
729
+ }
730
+ case 'Q': {
731
+ while (i + 3 < tokens.length && !isCommand(tokens[i])) {
732
+ const controlX = Number.parseFloat(tokens[i++]);
733
+ const controlY = Number.parseFloat(tokens[i++]);
734
+ const endX = Number.parseFloat(tokens[i++]);
735
+ const endY = Number.parseFloat(tokens[i++]);
736
+ if (![controlX, controlY, endX, endY].every(Number.isFinite)) break;
737
+ const control = absolute
738
+ ? [controlX, controlY]
739
+ : [current[0] + controlX, current[1] + controlY];
740
+ const end = absolute
741
+ ? [endX, endY]
742
+ : [current[0] + endX, current[1] + endY];
743
+ const startPoint = current;
744
+ for (let step = 1; step <= 8; step += 1) {
745
+ const amount = step / 8;
746
+ const remaining = 1 - amount;
747
+ points.push([
748
+ remaining * remaining * startPoint[0] + 2 * remaining * amount * control[0] + amount * amount * end[0],
749
+ remaining * remaining * startPoint[1] + 2 * remaining * amount * control[1] + amount * amount * end[1],
750
+ ]);
751
+ }
752
+ current = end;
753
+ }
754
+ break;
755
+ }
756
+ case 'Z': {
757
+ if (start) points.push(start);
758
+ break;
759
+ }
760
+ default:
761
+ return [];
762
+ }
763
+ }
764
+
765
+ return points.filter(isPoint);
766
+ }
767
+
768
+ function properSegmentIntersection(a, b, c, d) {
769
+ const abC = crossProduct(a, b, c);
770
+ const abD = crossProduct(a, b, d);
771
+ const cdA = crossProduct(c, d, a);
772
+ const cdB = crossProduct(c, d, b);
773
+ const epsilon = 1e-9;
774
+ const opposite = (left, right) => (left > epsilon && right < -epsilon) || (left < -epsilon && right > epsilon);
775
+ if (!opposite(abC, abD) || !opposite(cdA, cdB)) return null;
776
+ const denominator = (a[0] - b[0]) * (c[1] - d[1]) - (a[1] - b[1]) * (c[0] - d[0]);
777
+ if (Math.abs(denominator) < epsilon) return null;
778
+ const ab = a[0] * b[1] - a[1] * b[0];
779
+ const cd = c[0] * d[1] - c[1] * d[0];
780
+ return [
781
+ (ab * (c[0] - d[0]) - (a[0] - b[0]) * cd) / denominator,
782
+ (ab * (c[1] - d[1]) - (a[1] - b[1]) * cd) / denominator,
783
+ ];
784
+ }
785
+
786
+ function crossProduct(a, b, c) {
787
+ return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
788
+ }
789
+
790
+ function segmentIntersectsBox(segment, box) {
791
+ const { start, end } = segment;
792
+ if (pointInsideBox(start, box) || pointInsideBox(end, box)) return true;
793
+ const edges = [
794
+ [[box.x1, box.y1], [box.x2, box.y1]],
795
+ [[box.x2, box.y1], [box.x2, box.y2]],
796
+ [[box.x2, box.y2], [box.x1, box.y2]],
797
+ [[box.x1, box.y2], [box.x1, box.y1]],
798
+ ];
799
+ return edges.some(([a, b]) => segmentsIntersect(start, end, a, b));
800
+ }
801
+
802
+ function segmentsIntersect(a, b, c, d) {
803
+ const o1 = orientation(a, b, c);
804
+ const o2 = orientation(a, b, d);
805
+ const o3 = orientation(c, d, a);
806
+ const o4 = orientation(c, d, b);
807
+
808
+ if (o1 !== o2 && o3 !== o4) return true;
809
+ if (o1 === 0 && onSegment(a, c, b)) return true;
810
+ if (o2 === 0 && onSegment(a, d, b)) return true;
811
+ if (o3 === 0 && onSegment(c, a, d)) return true;
812
+ if (o4 === 0 && onSegment(c, b, d)) return true;
813
+ return false;
814
+ }
815
+
816
+ function orientation(a, b, c) {
817
+ const value = (b[1] - a[1]) * (c[0] - b[0]) - (b[0] - a[0]) * (c[1] - b[1]);
818
+ if (Math.abs(value) < 1e-9) return 0;
819
+ return value > 0 ? 1 : 2;
820
+ }
821
+
822
+ function onSegment(a, b, c) {
823
+ return b[0] <= Math.max(a[0], c[0]) + 1e-9
824
+ && b[0] + 1e-9 >= Math.min(a[0], c[0])
825
+ && b[1] <= Math.max(a[1], c[1]) + 1e-9
826
+ && b[1] + 1e-9 >= Math.min(a[1], c[1]);
827
+ }
828
+
829
+ function pointInsideBox(point, box) {
830
+ return point[0] >= box.x1 && point[0] <= box.x2 && point[1] >= box.y1 && point[1] <= box.y2;
831
+ }
832
+
833
+ function padBox(box, padding) {
834
+ return {
835
+ ...box,
836
+ x1: box.x1 - padding,
837
+ y1: box.y1 - padding,
838
+ x2: box.x2 + padding,
839
+ y2: box.y2 + padding,
840
+ };
841
+ }
842
+
843
+ // Only geometry/numeric attributes are scanned: authored prose such as node
844
+ // tags, <title> text, aria-labels, or data-* attributes may legitimately
845
+ // mention "NaN" or "Infinity" without any coordinate being non-finite.
846
+ function collectNonFiniteAttrs(svg) {
847
+ const details = [];
848
+ const stack = [];
849
+ for (const match of svg.matchAll(SVG_TAG_TOKEN)) {
850
+ if (!match[2]) continue;
851
+ const element = match[2].toLowerCase();
852
+ if (match[1]) {
853
+ const index = stack.map(entry => entry.element).lastIndexOf(element);
854
+ if (index >= 0) stack.length = index;
855
+ continue;
856
+ }
857
+ const parent = stack[stack.length - 1];
858
+ const inSvg = element === 'svg'
859
+ || Boolean(parent?.inSvg && !SVG_HTML_INTEGRATION_POINTS.has(parent.element));
860
+ if (inSvg) {
861
+ for (const [name, value] of attrEntries(match[0])) {
862
+ if (!isNumericAttr(element, name) || !NON_FINITE_TOKEN.test(decodeNumericReferences(value))) continue;
863
+ details.push(`${match[2]} ${name}="${value}"`);
864
+ }
865
+ }
866
+ // HTML void elements do not open a context; SVG self-closing tags do not
867
+ // either. A nested <svg> inside foreignObject restores SVG checking.
868
+ if (!(inSvg ? /\/\s*>$/.test(match[0]) : HTML_VOID_ELEMENTS.has(element))) {
869
+ stack.push({ element, inSvg });
870
+ }
871
+ }
872
+ return details;
873
+ }
874
+
875
+ function decodeNumericReferences(value) {
876
+ // Numeric references can encode every letter of NaN/Infinity/undefined.
877
+ // Decode once, locally: other checks and diagnostic evidence keep raw values.
878
+ return value.replace(/&#(?:x([0-9a-f]+)|([0-9]+));?/gi, (_, hex, decimal) => {
879
+ const point = Number.parseInt(hex || decimal, hex ? 16 : 10);
880
+ return point > 0 && point <= 0x10ffff && !(point >= 0xd800 && point <= 0xdfff)
881
+ ? String.fromCodePoint(point) : '\uFFFD';
882
+ });
883
+ }
884
+
885
+ function isNumericAttr(elementName, attrName) {
886
+ const normalizedAttr = attrName.toLowerCase();
887
+ return NUMERIC_ATTRS.has(normalizedAttr)
888
+ || ELEMENT_NUMERIC_ATTRS.get(elementName.toLowerCase())?.has(normalizedAttr);
889
+ }
890
+
891
+ function attrEntries(tag) {
892
+ return [...tag.matchAll(HTML_ATTRIBUTE)].map((match) => [
893
+ match[1],
894
+ match[2] ?? match[3] ?? match[4],
895
+ ]);
896
+ }
897
+
898
+ function parseAttrs(tag) {
899
+ return Object.fromEntries(attrEntries(tag));
900
+ }
901
+
902
+ function numberAttr(attrs, name) {
903
+ return Number.parseFloat(attrs[name]);
904
+ }
905
+
906
+ function isCommand(token) {
907
+ return /^[A-Za-z]$/.test(token);
908
+ }
909
+
910
+ function isPoint(point) {
911
+ return Array.isArray(point) && point.length === 2 && point.every(Number.isFinite);
912
+ }
913
+
914
+ function stripTags(value) {
915
+ return value.replace(/<[^>]*>/g, '');
916
+ }