cli-jaw 2.0.3 → 2.0.5

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 (671) hide show
  1. package/README.ja.md +23 -2
  2. package/README.ko.md +23 -2
  3. package/README.md +23 -2
  4. package/README.zh-CN.md +16 -1
  5. package/dist/bin/cli-jaw.js +7 -1
  6. package/dist/bin/cli-jaw.js.map +1 -1
  7. package/dist/bin/commands/browser.js +5 -0
  8. package/dist/bin/commands/browser.js.map +1 -1
  9. package/dist/bin/commands/connector.js +227 -0
  10. package/dist/bin/commands/connector.js.map +1 -0
  11. package/dist/bin/commands/dashboard-memory.js +243 -0
  12. package/dist/bin/commands/dashboard-memory.js.map +1 -0
  13. package/dist/bin/commands/dashboard.js +5 -0
  14. package/dist/bin/commands/dashboard.js.map +1 -1
  15. package/dist/bin/commands/dispatch-helpers.js +17 -0
  16. package/dist/bin/commands/dispatch-helpers.js.map +1 -0
  17. package/dist/bin/commands/dispatch.js +8 -3
  18. package/dist/bin/commands/dispatch.js.map +1 -1
  19. package/dist/bin/commands/doctor.js +34 -8
  20. package/dist/bin/commands/doctor.js.map +1 -1
  21. package/dist/bin/commands/reminders.js +105 -0
  22. package/dist/bin/commands/reminders.js.map +1 -0
  23. package/dist/bin/postinstall.js +26 -0
  24. package/dist/bin/postinstall.js.map +1 -1
  25. package/dist/server.js +71 -9
  26. package/dist/server.js.map +1 -1
  27. package/dist/src/agent/alert-escalation.js +12 -1
  28. package/dist/src/agent/alert-escalation.js.map +1 -1
  29. package/dist/src/agent/error-classifier.js +14 -8
  30. package/dist/src/agent/error-classifier.js.map +1 -1
  31. package/dist/src/agent/events.js +58 -30
  32. package/dist/src/agent/events.js.map +1 -1
  33. package/dist/src/agent/lifecycle-handler.js +81 -4
  34. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  35. package/dist/src/agent/session-persistence.js +2 -0
  36. package/dist/src/agent/session-persistence.js.map +1 -1
  37. package/dist/src/agent/spawn.js +90 -12
  38. package/dist/src/agent/spawn.js.map +1 -1
  39. package/dist/src/agent/tool-timeout.js +27 -0
  40. package/dist/src/agent/tool-timeout.js.map +1 -0
  41. package/dist/src/agent/watchdog.js +20 -3
  42. package/dist/src/agent/watchdog.js.map +1 -1
  43. package/dist/src/browser/connection.js +69 -15
  44. package/dist/src/browser/connection.js.map +1 -1
  45. package/dist/src/browser/launch-policy.js +1 -1
  46. package/dist/src/browser/launch-policy.js.map +1 -1
  47. package/dist/src/browser/runtime-diagnostics.js +39 -0
  48. package/dist/src/browser/runtime-diagnostics.js.map +1 -1
  49. package/dist/src/browser/web-ai/chatgpt-model.js +102 -19
  50. package/dist/src/browser/web-ai/chatgpt-model.js.map +1 -1
  51. package/dist/src/browser/web-ai/chatgpt-response.js +30 -1
  52. package/dist/src/browser/web-ai/chatgpt-response.js.map +1 -1
  53. package/dist/src/browser/web-ai/chatgpt.js +55 -8
  54. package/dist/src/browser/web-ai/chatgpt.js.map +1 -1
  55. package/dist/src/browser/web-ai/diagnostics.js +1 -0
  56. package/dist/src/browser/web-ai/diagnostics.js.map +1 -1
  57. package/dist/src/browser/web-ai/gemini-live.js +24 -3
  58. package/dist/src/browser/web-ai/gemini-live.js.map +1 -1
  59. package/dist/src/browser/web-ai/interstitial.js +64 -0
  60. package/dist/src/browser/web-ai/interstitial.js.map +1 -0
  61. package/dist/src/browser/web-ai/session.js +12 -0
  62. package/dist/src/browser/web-ai/session.js.map +1 -1
  63. package/dist/src/browser/web-ai/watcher.js +25 -7
  64. package/dist/src/browser/web-ai/watcher.js.map +1 -1
  65. package/dist/src/cli/compact.js +5 -1
  66. package/dist/src/cli/compact.js.map +1 -1
  67. package/dist/src/cli/connector.js +60 -0
  68. package/dist/src/cli/connector.js.map +1 -0
  69. package/dist/src/cli/handlers-runtime.js +39 -0
  70. package/dist/src/cli/handlers-runtime.js.map +1 -1
  71. package/dist/src/cli/reminders.js +29 -0
  72. package/dist/src/cli/reminders.js.map +1 -0
  73. package/dist/src/core/cli-detect.js +161 -0
  74. package/dist/src/core/cli-detect.js.map +1 -0
  75. package/dist/src/core/compact.js +5 -1
  76. package/dist/src/core/compact.js.map +1 -1
  77. package/dist/src/core/config.js +9 -22
  78. package/dist/src/core/config.js.map +1 -1
  79. package/dist/src/core/db.js +14 -1
  80. package/dist/src/core/db.js.map +1 -1
  81. package/dist/src/core/settings-merge.js +2 -2
  82. package/dist/src/core/settings-merge.js.map +1 -1
  83. package/dist/src/jaw-ceo/completion.js +101 -0
  84. package/dist/src/jaw-ceo/completion.js.map +1 -0
  85. package/dist/src/jaw-ceo/confirmations.js +39 -0
  86. package/dist/src/jaw-ceo/confirmations.js.map +1 -0
  87. package/dist/src/jaw-ceo/coordinator-admin.js +295 -0
  88. package/dist/src/jaw-ceo/coordinator-admin.js.map +1 -0
  89. package/dist/src/jaw-ceo/coordinator-completions.js +201 -0
  90. package/dist/src/jaw-ceo/coordinator-completions.js.map +1 -0
  91. package/dist/src/jaw-ceo/coordinator-realtime-tools.js +108 -0
  92. package/dist/src/jaw-ceo/coordinator-realtime-tools.js.map +1 -0
  93. package/dist/src/jaw-ceo/coordinator-types.js +2 -0
  94. package/dist/src/jaw-ceo/coordinator-types.js.map +1 -0
  95. package/dist/src/jaw-ceo/coordinator-utils.js +86 -0
  96. package/dist/src/jaw-ceo/coordinator-utils.js.map +1 -0
  97. package/dist/src/jaw-ceo/coordinator-workers.js +234 -0
  98. package/dist/src/jaw-ceo/coordinator-workers.js.map +1 -0
  99. package/dist/src/jaw-ceo/coordinator.js +116 -0
  100. package/dist/src/jaw-ceo/coordinator.js.map +1 -0
  101. package/dist/src/jaw-ceo/docs-edit.js +142 -0
  102. package/dist/src/jaw-ceo/docs-edit.js.map +1 -0
  103. package/dist/src/jaw-ceo/openai-key.js +22 -0
  104. package/dist/src/jaw-ceo/openai-key.js.map +1 -0
  105. package/dist/src/jaw-ceo/policy.js +92 -0
  106. package/dist/src/jaw-ceo/policy.js.map +1 -0
  107. package/dist/src/jaw-ceo/realtime-sideband.js +372 -0
  108. package/dist/src/jaw-ceo/realtime-sideband.js.map +1 -0
  109. package/dist/src/jaw-ceo/store.js +206 -0
  110. package/dist/src/jaw-ceo/store.js.map +1 -0
  111. package/dist/src/jaw-ceo/transcript-persistence.js +28 -0
  112. package/dist/src/jaw-ceo/transcript-persistence.js.map +1 -0
  113. package/dist/src/jaw-ceo/types.js +2 -0
  114. package/dist/src/jaw-ceo/types.js.map +1 -0
  115. package/dist/src/manager/connector/audit-log.js +95 -0
  116. package/dist/src/manager/connector/audit-log.js.map +1 -0
  117. package/dist/src/manager/connector/routes.js +251 -0
  118. package/dist/src/manager/connector/routes.js.map +1 -0
  119. package/dist/src/manager/connector/types.js +2 -0
  120. package/dist/src/manager/connector/types.js.map +1 -0
  121. package/dist/src/manager/lifecycle.js +1 -1
  122. package/dist/src/manager/lifecycle.js.map +1 -1
  123. package/dist/src/manager/memory/embedding/hybrid-search.js +61 -0
  124. package/dist/src/manager/memory/embedding/hybrid-search.js.map +1 -0
  125. package/dist/src/manager/memory/embedding/index.js +6 -0
  126. package/dist/src/manager/memory/embedding/index.js.map +1 -0
  127. package/dist/src/manager/memory/embedding/provider.js +187 -0
  128. package/dist/src/manager/memory/embedding/provider.js.map +1 -0
  129. package/dist/src/manager/memory/embedding/state-machine.js +68 -0
  130. package/dist/src/manager/memory/embedding/state-machine.js.map +1 -0
  131. package/dist/src/manager/memory/embedding/sync.js +156 -0
  132. package/dist/src/manager/memory/embedding/sync.js.map +1 -0
  133. package/dist/src/manager/memory/embedding/vec-store.js +166 -0
  134. package/dist/src/manager/memory/embedding/vec-store.js.map +1 -0
  135. package/dist/src/manager/memory/federation.js +56 -0
  136. package/dist/src/manager/memory/federation.js.map +1 -0
  137. package/dist/src/manager/memory/index.js +5 -0
  138. package/dist/src/manager/memory/index.js.map +1 -0
  139. package/dist/src/manager/memory/instance-discovery.js +83 -0
  140. package/dist/src/manager/memory/instance-discovery.js.map +1 -0
  141. package/dist/src/manager/memory/result-rerank.js +28 -0
  142. package/dist/src/manager/memory/result-rerank.js.map +1 -0
  143. package/dist/src/manager/memory/types.js +2 -0
  144. package/dist/src/manager/memory/types.js.map +1 -0
  145. package/dist/src/manager/notes/routes.js +7 -0
  146. package/dist/src/manager/notes/routes.js.map +1 -1
  147. package/dist/src/manager/notes/search.js +282 -0
  148. package/dist/src/manager/notes/search.js.map +1 -0
  149. package/dist/src/manager/observability.js.map +1 -1
  150. package/dist/src/manager/preview-origin-proxy.js +12 -2
  151. package/dist/src/manager/preview-origin-proxy.js.map +1 -1
  152. package/dist/src/manager/process-verify.js +4 -1
  153. package/dist/src/manager/process-verify.js.map +1 -1
  154. package/dist/src/manager/registry.js +59 -1
  155. package/dist/src/manager/registry.js.map +1 -1
  156. package/dist/src/manager/reminders/api.js +16 -0
  157. package/dist/src/manager/reminders/api.js.map +1 -0
  158. package/dist/src/manager/reminders/dispatcher.js +40 -0
  159. package/dist/src/manager/reminders/dispatcher.js.map +1 -0
  160. package/dist/src/manager/reminders/due-time.js +16 -0
  161. package/dist/src/manager/reminders/due-time.js.map +1 -0
  162. package/dist/src/manager/reminders/instance-link.js +22 -0
  163. package/dist/src/manager/reminders/instance-link.js.map +1 -0
  164. package/dist/src/manager/reminders/routes.js +170 -0
  165. package/dist/src/manager/reminders/routes.js.map +1 -0
  166. package/dist/src/manager/reminders/scheduler.js +67 -0
  167. package/dist/src/manager/reminders/scheduler.js.map +1 -0
  168. package/dist/src/manager/reminders/store.js +311 -0
  169. package/dist/src/manager/reminders/store.js.map +1 -0
  170. package/dist/src/manager/routes/dashboard-memory.js +380 -0
  171. package/dist/src/manager/routes/dashboard-memory.js.map +1 -0
  172. package/dist/src/manager/server.js +209 -4
  173. package/dist/src/manager/server.js.map +1 -1
  174. package/dist/src/manager/worker-messages.js +60 -0
  175. package/dist/src/manager/worker-messages.js.map +1 -0
  176. package/dist/src/manager/workspace/routes.js +240 -0
  177. package/dist/src/manager/workspace/routes.js.map +1 -0
  178. package/dist/src/manager/workspace/store.js +369 -0
  179. package/dist/src/manager/workspace/store.js.map +1 -0
  180. package/dist/src/manager/workspace/types.js +5 -0
  181. package/dist/src/manager/workspace/types.js.map +1 -0
  182. package/dist/src/memory/bootstrap.js +8 -1
  183. package/dist/src/memory/bootstrap.js.map +1 -1
  184. package/dist/src/memory/indexing.js +245 -131
  185. package/dist/src/memory/indexing.js.map +1 -1
  186. package/dist/src/memory/keyword-expand.js +26 -4
  187. package/dist/src/memory/keyword-expand.js.map +1 -1
  188. package/dist/src/memory/reflect.js +119 -8
  189. package/dist/src/memory/reflect.js.map +1 -1
  190. package/dist/src/memory/shared.js +6 -0
  191. package/dist/src/memory/shared.js.map +1 -1
  192. package/dist/src/memory/synonyms.js +60 -0
  193. package/dist/src/memory/synonyms.js.map +1 -0
  194. package/dist/src/orchestrator/gateway.js +1 -1
  195. package/dist/src/orchestrator/gateway.js.map +1 -1
  196. package/dist/src/orchestrator/parser.js +3 -8
  197. package/dist/src/orchestrator/parser.js.map +1 -1
  198. package/dist/src/orchestrator/pipeline.js +8 -3
  199. package/dist/src/orchestrator/pipeline.js.map +1 -1
  200. package/dist/src/orchestrator/state-machine.js +12 -2
  201. package/dist/src/orchestrator/state-machine.js.map +1 -1
  202. package/dist/src/prompt/builder.js +35 -16
  203. package/dist/src/prompt/builder.js.map +1 -1
  204. package/dist/src/prompt/templates/a1-system.md +23 -1
  205. package/dist/src/reminders/jaw-reminders-bridge.js +313 -0
  206. package/dist/src/reminders/jaw-reminders-bridge.js.map +1 -0
  207. package/dist/src/reminders/types.js +7 -0
  208. package/dist/src/reminders/types.js.map +1 -0
  209. package/dist/src/routes/jaw-ceo.js +290 -0
  210. package/dist/src/routes/jaw-ceo.js.map +1 -0
  211. package/dist/src/routes/jaw-memory.js +37 -1
  212. package/dist/src/routes/jaw-memory.js.map +1 -1
  213. package/dist/src/routes/settings.js +47 -12
  214. package/dist/src/routes/settings.js.map +1 -1
  215. package/package.json +4 -1
  216. package/public/css/chat.css +90 -12
  217. package/public/css/diagram.css +9 -9
  218. package/public/css/modals.css +60 -1
  219. package/public/css/sidebar.css +18 -0
  220. package/public/dist/assets/{AdvancedExport-DJZ2VmBR.js → AdvancedExport-BAdZUC-6.js} +1 -1
  221. package/public/dist/assets/{Agent-CgpLT8IY.js → Agent-DNpehKB2.js} +1 -1
  222. package/public/dist/assets/{Browser-CrkiQoB8.js → Browser-BsdxDVgM.js} +1 -1
  223. package/public/dist/assets/{ChannelsDiscord-CVUC22D4.js → ChannelsDiscord-Dg_jto6l.js} +1 -1
  224. package/public/dist/assets/{ChannelsTelegram-DEatIQNM.js → ChannelsTelegram-DGyZfJGS.js} +1 -1
  225. package/public/dist/assets/DashboardEmbeddingSection-BYdGgqg7.js +2 -0
  226. package/public/dist/assets/{DashboardMeta-BKoxRc7i.js → DashboardMeta-CAH9ONTb.js} +1 -1
  227. package/public/dist/assets/{Display-DnNGV9Km.js → Display-DM_yvyKL.js} +1 -1
  228. package/public/dist/assets/{Employees-DZ2iJYKy.js → Employees-CuYuTy0R.js} +1 -1
  229. package/public/dist/assets/{HealthBadge-Cq2c7G9s.js → HealthBadge-Dtr-dDnw.js} +1 -1
  230. package/public/dist/assets/{Heartbeat-BML6eTXZ.js → Heartbeat-C-vq02MW.js} +1 -1
  231. package/public/dist/assets/{InlineWarn-BooBRm7o.js → InlineWarn-E64UaKFh.js} +1 -1
  232. package/public/dist/assets/{Mcp-BlEviQ3h.js → Mcp-Dlp2X7X7.js} +1 -1
  233. package/public/dist/assets/{Memory-BRyH80He.js → Memory-BPKWJDXK.js} +1 -1
  234. package/public/dist/assets/MilkdownWysiwygEditor-Ctww8i0L.js +160 -0
  235. package/public/dist/assets/{ModelProvider-DxyR7EL9.js → ModelProvider-Bd6vGkXT.js} +1 -1
  236. package/public/dist/assets/{Network-DDOOESh1.js → Network-Df1R2YcQ.js} +1 -1
  237. package/public/dist/assets/{Permissions-Br0eSbKb.js → Permissions-BKJ5K6EL.js} +1 -1
  238. package/public/dist/assets/{Permissions-QHkzStqQ.js → Permissions-CcWZoOVP.js} +1 -1
  239. package/public/dist/assets/{Profile-C79NKumk.js → Profile-DZ7xf1WZ.js} +1 -1
  240. package/public/dist/assets/{Prompts-BmiIDiXW.js → Prompts-Bh5DYt8e.js} +1 -1
  241. package/public/dist/assets/{SpeechKeys-B8304XJK.js → SpeechKeys-CQwtVxOP.js} +1 -1
  242. package/public/dist/assets/app-BxsIleo0.js +32 -0
  243. package/public/dist/assets/app-CB9n5A77.css +1 -0
  244. package/public/dist/assets/architecture-YZFGNWBL-BRI-0IaU.js +1 -0
  245. package/public/dist/assets/{architectureDiagram-Q4EWVU46-D0VjH4Hz.js → architectureDiagram-Q4EWVU46-z0JCgZrJ.js} +1 -1
  246. package/public/dist/assets/{blockDiagram-DXYQGD6D-CY4ROZPD.js → blockDiagram-DXYQGD6D-KaOz3aFS.js} +1 -1
  247. package/public/dist/assets/{c4Diagram-AHTNJAMY-CXSKBhA5.js → c4Diagram-AHTNJAMY-Bp2QLC-s.js} +1 -1
  248. package/public/dist/assets/channel-jLopKIgm.js +1 -0
  249. package/public/dist/assets/{chunk-2KRD3SAO-DKaML5Aw.js → chunk-2KRD3SAO-C8hJZPJu.js} +1 -1
  250. package/public/dist/assets/{chunk-336JU56O-CU3sZss9.js → chunk-336JU56O-CAt5aBOe.js} +1 -1
  251. package/public/dist/assets/chunk-426QAEUC-atJRhvKN.js +1 -0
  252. package/public/dist/assets/{chunk-4BX2VUAB-X0ZSlark.js → chunk-4BX2VUAB-Cm3KqBkS.js} +1 -1
  253. package/public/dist/assets/{chunk-4TB4RGXK-DxI0GIVy.js → chunk-4TB4RGXK-BD7UhIN8.js} +1 -1
  254. package/public/dist/assets/chunk-55IACEB6-CAWcPDdr.js +1 -0
  255. package/public/dist/assets/{chunk-5FUZZQ4R-BqlA0aLQ.js → chunk-5FUZZQ4R-Cg1pzs6p.js} +1 -1
  256. package/public/dist/assets/{chunk-5PVQY5BW-BVW1DG4s.js → chunk-5PVQY5BW-otv3HwE_.js} +1 -1
  257. package/public/dist/assets/{chunk-67CJDMHE-Blm2TZ-J.js → chunk-67CJDMHE-AU2iOKLT.js} +1 -1
  258. package/public/dist/assets/{chunk-7N4EOEYR-BoIOnnji.js → chunk-7N4EOEYR-BTIS4jBw.js} +1 -1
  259. package/public/dist/assets/{chunk-AA7GKIK3-Dsfi7oEW.js → chunk-AA7GKIK3-c9UUJO_T.js} +1 -1
  260. package/public/dist/assets/{chunk-BSJP7CBP-DMGz9IOn.js → chunk-BSJP7CBP-DnSYKjii.js} +1 -1
  261. package/public/dist/assets/{chunk-CIAEETIT-T5_zEp7h.js → chunk-CIAEETIT-Dwbln6rM.js} +1 -1
  262. package/public/dist/assets/{chunk-EDXVE4YY-DjfvQwok.js → chunk-EDXVE4YY-COudQKkJ.js} +1 -1
  263. package/public/dist/assets/{chunk-ENJZ2VHE-LawplD1x.js → chunk-ENJZ2VHE-PT_jAckw.js} +1 -1
  264. package/public/dist/assets/{chunk-FMBD7UC4-C7tckXtF.js → chunk-FMBD7UC4-6yXYicjw.js} +1 -1
  265. package/public/dist/assets/{chunk-FOC6F5B3-xPGbUzqY.js → chunk-FOC6F5B3-BqDmFFeg.js} +1 -1
  266. package/public/dist/assets/{chunk-ICPOFSXX-Cdp_Bt1o.js → chunk-ICPOFSXX-P6V6jqiT.js} +2 -2
  267. package/public/dist/assets/{chunk-K5T4RW27-BwIFil23.js → chunk-K5T4RW27-C42sOmZR.js} +1 -1
  268. package/public/dist/assets/{chunk-KGLVRYIC-BsNQ1OkZ.js → chunk-KGLVRYIC-K-BVa8b2.js} +1 -1
  269. package/public/dist/assets/{chunk-LIHQZDEY-DbaX7k3n.js → chunk-LIHQZDEY-Xw9ZX8of.js} +1 -1
  270. package/public/dist/assets/{chunk-ORNJ4GCN-C6D0ZHHr.js → chunk-ORNJ4GCN-CEXU6WaD.js} +1 -1
  271. package/public/dist/assets/{chunk-OYMX7WX6-C1WV9uUT.js → chunk-OYMX7WX6-DmJG2z1S.js} +1 -1
  272. package/public/dist/assets/chunk-QZHKN3VN-BkVLii_3.js +1 -0
  273. package/public/dist/assets/{chunk-U2HBQHQK-B-5yzlzA.js → chunk-U2HBQHQK-Ny6UwUgK.js} +1 -1
  274. package/public/dist/assets/{chunk-X2U36JSP-yL0Tpsl1.js → chunk-X2U36JSP-CoMFMVNF.js} +1 -1
  275. package/public/dist/assets/{chunk-XPW4576I-CeaUaSCU.js → chunk-XPW4576I-CmAz5C-j.js} +1 -1
  276. package/public/dist/assets/{chunk-YZCP3GAM-CASMOrQq.js → chunk-YZCP3GAM-c7FYtZME.js} +1 -1
  277. package/public/dist/assets/{chunk-ZZ45TVLE-B4c7TOr9.js → chunk-ZZ45TVLE-D5oxCC1O.js} +1 -1
  278. package/public/dist/assets/classDiagram-6PBFFD2Q-BgOyAynm.js +1 -0
  279. package/public/dist/assets/classDiagram-v2-HSJHXN6E-5gBdoVH9.js +1 -0
  280. package/public/dist/assets/{cose-bilkent-S5V4N54A-B21AcnwY.js → cose-bilkent-S5V4N54A-CvH6qY_r.js} +1 -1
  281. package/public/dist/assets/{dagre-DzTKkA3a.js → dagre--20B2-ZQ.js} +1 -1
  282. package/public/dist/assets/{dagre-KV5264BT-fAyzMxIJ.js → dagre-KV5264BT-CQ0wo0ma.js} +1 -1
  283. package/public/dist/assets/{diagram-5BDNPKRD-O30SB9_x.js → diagram-5BDNPKRD-Cl4PzCD0.js} +1 -1
  284. package/public/dist/assets/{diagram-G4DWMVQ6-DZ1S54sq.js → diagram-G4DWMVQ6-_aP6kMTh.js} +1 -1
  285. package/public/dist/assets/{diagram-MMDJMWI5-DRO_GSWW.js → diagram-MMDJMWI5-J1l6Q0JG.js} +1 -1
  286. package/public/dist/assets/{diagram-TYMM5635-BxWgQj5r.js → diagram-TYMM5635-B_Xoa1Gp.js} +1 -1
  287. package/public/dist/assets/{dist-W51oDoeA.js → dist-2oDfqE98.js} +1 -1
  288. package/public/dist/assets/{dist-BZosRD2u.js → dist-55MYVjjj.js} +1 -1
  289. package/public/dist/assets/dist-B1p80u1b.js +1 -0
  290. package/public/dist/assets/{dist-Bd9PlnQm.js → dist-B1rKu9eP.js} +1 -1
  291. package/public/dist/assets/{dist-Ch5VAlV9.js → dist-B6G8pbap.js} +1 -1
  292. package/public/dist/assets/{dist-CpUK8ypo.js → dist-BA7sRne4.js} +1 -1
  293. package/public/dist/assets/{dist-eU7TyC86.js → dist-BDMNMdPF.js} +1 -1
  294. package/public/dist/assets/{dist-DFYRUAjN.js → dist-BGzHP3f8.js} +1 -1
  295. package/public/dist/assets/dist-BKyzWv22.js +1 -0
  296. package/public/dist/assets/{dist-BNfXO3Yr.js → dist-BTp_Oy_x.js} +1 -1
  297. package/public/dist/assets/{dist-BD0UXfgF2.js → dist-BhzKO6nt2.js} +1 -1
  298. package/public/dist/assets/{dist-BUnPYbK3.js → dist-BjqyutOM.js} +1 -1
  299. package/public/dist/assets/dist-BoG5I6U5.js +1 -0
  300. package/public/dist/assets/{dist-yHP6L0Ty.js → dist-BuaQLcgQ.js} +1 -1
  301. package/public/dist/assets/{dist-DZsFVYF4.js → dist-C0sOT_UM.js} +5 -5
  302. package/public/dist/assets/{dist-CIuXW-sc.js → dist-C5S-Rbvc.js} +1 -1
  303. package/public/dist/assets/{dist-Db16ogVk.js → dist-C9LWf2uC.js} +1 -1
  304. package/public/dist/assets/{dist-urPTQzXL.js → dist-CCKktDoF.js} +1 -1
  305. package/public/dist/assets/{dist-D7bCuS3f.js → dist-CEDX2HGI.js} +1 -1
  306. package/public/dist/assets/dist-Ch6JG5jE.js +23 -0
  307. package/public/dist/assets/{dist-SU-YTAIg.js → dist-CkMC2PPt.js} +1 -1
  308. package/public/dist/assets/dist-CxJpXP6s.js +1 -0
  309. package/public/dist/assets/dist-DNLFuTrS.js +1 -0
  310. package/public/dist/assets/{dist-CL4PTYWf.js → dist-DdhWu7OM.js} +1 -1
  311. package/public/dist/assets/{dist-D6cUXP7K.js → dist-G7QUHtDS.js} +1 -1
  312. package/public/dist/assets/{dist-UYn7T-GH.js → dist-W7IGn2ug.js} +1 -1
  313. package/public/dist/assets/{dist-Cp42cMcI.js → dist-wdLr2dSH.js} +1 -1
  314. package/public/dist/assets/{dockerfile-zC7EsydA.js → dockerfile-CrC2HXHP.js} +1 -1
  315. package/public/dist/assets/employees-CIkIyvtL.js +33 -0
  316. package/public/dist/assets/{erDiagram-SMLLAGMA-oYlCN-2d.js → erDiagram-SMLLAGMA-BvtqhMsS.js} +1 -1
  317. package/public/dist/assets/{error-normalize-5n-zlEQ3.js → error-normalize-CkhPeQYx.js} +1 -1
  318. package/public/dist/assets/esm-BmJkIat2.js +4 -0
  319. package/public/dist/assets/{factor-DSufIRGh.js → factor-1CttFx2G.js} +1 -1
  320. package/public/dist/assets/{fields-BtncIZYA.js → fields-BISouxp2.js} +1 -1
  321. package/public/dist/assets/{flowDiagram-DWJPFMVM-er6Wfb34.js → flowDiagram-DWJPFMVM-C_F0rqqT.js} +1 -1
  322. package/public/dist/assets/{ganttDiagram-T4ZO3ILL-Co2j1qn3.js → ganttDiagram-T4ZO3ILL-B5S8EZRg.js} +1 -1
  323. package/public/dist/assets/gitGraph-7Q5UKJZL-DTTW6pxr.js +1 -0
  324. package/public/dist/assets/{gitGraphDiagram-UUTBAWPF-clYndUgV.js → gitGraphDiagram-UUTBAWPF-DMGzYJeb.js} +1 -1
  325. package/public/dist/assets/{graphlib-BjOif-SH.js → graphlib-CZk_Ii16.js} +1 -1
  326. package/public/dist/assets/idb-cache-BnZfG5FD.js +1 -0
  327. package/public/dist/assets/info-OMHHGYJF-BU-iuaSm.js +1 -0
  328. package/public/dist/assets/{infoDiagram-42DDH7IO-uYs7OoSA.js → infoDiagram-42DDH7IO-dzSaYFFK.js} +1 -1
  329. package/public/dist/assets/{ishikawaDiagram-UXIWVN3A-32bIEtCb.js → ishikawaDiagram-UXIWVN3A-DZW-Nqsf.js} +1 -1
  330. package/public/dist/assets/javascript-BhB45e0W.js +1 -0
  331. package/public/dist/assets/{journeyDiagram-VCZTEJTY-hBNsU7mK.js → journeyDiagram-VCZTEJTY-ByVRJxVF.js} +1 -1
  332. package/public/dist/assets/{kanban-definition-6JOO6SKY-DoepMHBI.js → kanban-definition-6JOO6SKY-xwN0YCW2.js} +1 -1
  333. package/public/dist/assets/katex-DamPUmTE.js +1 -0
  334. package/public/dist/assets/manager-B84u-pcn.js +25 -0
  335. package/public/dist/assets/manager-DMg_sTEP.css +1 -0
  336. package/public/dist/assets/memory-BV62wlsG.js +1 -0
  337. package/public/dist/assets/{memory-CsMNkYtv.js → memory-CnBc2_Va.js} +1 -1
  338. package/public/dist/assets/mermaid-loader-DxFGz4EE.js +1 -0
  339. package/public/dist/assets/{mermaid-parser.core-CrXy-45O.js → mermaid-parser.core-CMIZ0my_.js} +1 -1
  340. package/public/dist/assets/mermaid-preprocess-p7OIpOon.js +5 -0
  341. package/public/dist/assets/mermaid.core-CicVBD9l.js +1 -0
  342. package/public/dist/assets/{mermaid.core-DYApH8sc.js → mermaid.core-Dj6viEzN.js} +2 -2
  343. package/public/dist/assets/{mindmap-definition-QFDTVHPH-C-QWWjaf.js → mindmap-definition-QFDTVHPH-Chqgsh1N.js} +1 -1
  344. package/public/dist/assets/{nsis-DLskXEqR.js → nsis-_CjIiUyF.js} +1 -1
  345. package/public/dist/assets/packet-4T2RLAQJ-DzmBsAf0.js +1 -0
  346. package/public/dist/assets/{page-shell-D5tbivHH.js → page-shell-CTxVDJ8Y.js} +1 -1
  347. package/public/dist/assets/pie-ZZUOXDRM-DyG1KzTn.js +1 -0
  348. package/public/dist/assets/{pieDiagram-DEJITSTG-DvMWxH5R.js → pieDiagram-DEJITSTG-DJLiSymi.js} +1 -1
  349. package/public/dist/assets/{pug-B2rz0Rz1.js → pug-CbR8lCtK.js} +1 -1
  350. package/public/dist/assets/{quadrantDiagram-34T5L4WZ-DjoQDyzO.js → quadrantDiagram-34T5L4WZ-qcnWmcRr.js} +1 -1
  351. package/public/dist/assets/radar-PYXPWWZC-CEBZARUu.js +1 -0
  352. package/public/dist/assets/render-lpTpN1El.js +28 -0
  353. package/public/dist/assets/{requirementDiagram-MS252O5E-sQav3xIA.js → requirementDiagram-MS252O5E-wnPtv0LG.js} +1 -1
  354. package/public/dist/assets/{sankeyDiagram-XADWPNL6-DkdEFMeo.js → sankeyDiagram-XADWPNL6-Bn3pUd_K.js} +1 -1
  355. package/public/dist/assets/{sequenceDiagram-FGHM5R23-kaplo282.js → sequenceDiagram-FGHM5R23-DfxcHSdj.js} +1 -1
  356. package/public/dist/assets/settings-CfAXLa8a.js +1 -0
  357. package/public/dist/assets/{settings-BH213Yv3.js → settings-FWgmcubl.js} +8 -8
  358. package/public/dist/assets/sidebar-Cwt0FxQl.js +14 -0
  359. package/public/dist/assets/skills-D-qUVJ-e.js +1 -0
  360. package/public/dist/assets/{skills-CQtCtHPA.js → skills-DDmTyywh.js} +2 -2
  361. package/public/dist/assets/slash-commands-BfI19vIz.js +1 -0
  362. package/public/dist/assets/{slash-commands-Dzk1xHWS.js → slash-commands-D5y5AVvS.js} +1 -1
  363. package/public/dist/assets/{stateDiagram-FHFEXIEX-B2L3h2aE.js → stateDiagram-FHFEXIEX-CiR7P2OG.js} +1 -1
  364. package/public/dist/assets/stateDiagram-v2-QKLJ7IA2-BaWWpysK.js +1 -0
  365. package/public/dist/assets/{timeline-definition-GMOUNBTQ-_Nnp2LU-.js → timeline-definition-GMOUNBTQ-DUz1-iOx.js} +1 -1
  366. package/public/dist/assets/{trace-drawer-SRKcfm2S.js → trace-drawer-DVF5F1df.js} +1 -1
  367. package/public/dist/assets/treeView-SZITEDCU-D5-TP7Qp.js +1 -0
  368. package/public/dist/assets/treemap-W4RFUUIX-BQhm_ZSp.js +1 -0
  369. package/public/dist/assets/ui-BJXY16Dk.js +140 -0
  370. package/public/dist/assets/ui-BXm3OPPh.js +1 -0
  371. package/public/dist/assets/{vendor-render-984tPmpy.js → vendor-render-DEStnpJ8.js} +22 -22
  372. package/public/dist/assets/{vennDiagram-DHZGUBPP-vNU8EDoW.js → vennDiagram-DHZGUBPP-CYu7SDdG.js} +1 -1
  373. package/public/dist/assets/wardley-RL74JXVD-CpnBMRe0.js +1 -0
  374. package/public/dist/assets/{wardleyDiagram-NUSXRM2D-DB2wK0zr.js → wardleyDiagram-NUSXRM2D-CLAhOzap.js} +1 -1
  375. package/public/dist/assets/wiki-link-suggestions-LQuYT22G.js +23 -0
  376. package/public/dist/assets/{xychartDiagram-5P7HB3ND-CisgDiJM.js → xychartDiagram-5P7HB3ND-DLnY9i8z.js} +1 -1
  377. package/public/dist/index.html +36 -12
  378. package/public/dist/manager/index.html +2 -2
  379. package/public/index.html +34 -10
  380. package/public/js/features/chat-messages.ts +132 -0
  381. package/public/js/features/chat-scroll.ts +226 -0
  382. package/public/js/features/chat.ts +6 -1
  383. package/public/js/features/employees.ts +4 -1
  384. package/public/js/features/help-content.ts +11 -1
  385. package/public/js/features/help-dialog.ts +78 -17
  386. package/public/js/features/message-actions.ts +157 -0
  387. package/public/js/features/message-history.ts +138 -0
  388. package/public/js/features/message-item-html.ts +34 -0
  389. package/public/js/features/preview-shortcut-bridge.ts +29 -0
  390. package/public/js/features/process-block-dom.ts +175 -0
  391. package/public/js/features/process-block.ts +34 -6
  392. package/public/js/features/process-log-adapter.ts +104 -0
  393. package/public/js/features/process-step-match.ts +2 -1
  394. package/public/js/features/settings-cli-status.ts +52 -1
  395. package/public/js/features/settings.ts +1 -0
  396. package/public/js/features/sidebar.ts +7 -1
  397. package/public/js/features/ui-status.ts +47 -0
  398. package/public/js/main.ts +10 -3
  399. package/public/js/render/code-copy.ts +47 -0
  400. package/public/js/render/delegations.ts +10 -0
  401. package/public/js/render/file-links.ts +150 -0
  402. package/public/js/render/highlight.ts +83 -0
  403. package/public/js/render/html.ts +26 -0
  404. package/public/js/render/markdown.ts +84 -0
  405. package/public/js/render/math.ts +76 -0
  406. package/public/js/render/mermaid-preprocess.ts +77 -0
  407. package/public/js/render/mermaid.ts +267 -0
  408. package/public/js/render/post-render.ts +35 -0
  409. package/public/js/render/sanitize.ts +51 -0
  410. package/public/js/render/svg-actions.ts +291 -0
  411. package/public/js/render.ts +17 -1081
  412. package/public/js/ui.ts +24 -755
  413. package/public/js/virtual-scroll-bootstrap.ts +23 -3
  414. package/public/js/virtual-scroll.ts +100 -13
  415. package/public/js/ws.ts +8 -3
  416. package/public/locales/en.json +78 -2
  417. package/public/locales/ja.json +76 -2
  418. package/public/locales/ko.json +78 -2
  419. package/public/locales/zh.json +76 -2
  420. package/public/manager/src/App.tsx +150 -258
  421. package/public/manager/src/AppChrome.tsx +144 -0
  422. package/public/manager/src/InstancePreview.tsx +18 -0
  423. package/public/manager/src/SidebarRailRouter.tsx +229 -0
  424. package/public/manager/src/api.ts +17 -0
  425. package/public/manager/src/components/ActivityTimeline.tsx +9 -1
  426. package/public/manager/src/components/ProcessControlPanel.tsx +3 -0
  427. package/public/manager/src/components/SidebarRail.tsx +22 -0
  428. package/public/manager/src/components/Workbench.tsx +17 -13
  429. package/public/manager/src/components/WorkbenchHeader.tsx +44 -33
  430. package/public/manager/src/components/WorkspaceLayout.tsx +3 -0
  431. package/public/manager/src/dashboard-board/DashboardBoardSidebar.tsx +1 -1
  432. package/public/manager/src/dashboard-board/DashboardBoardWorkspace.tsx +6 -0
  433. package/public/manager/src/dashboard-features.ts +4 -1
  434. package/public/manager/src/dashboard-reminders/DashboardRemindersSidebar.tsx +157 -0
  435. package/public/manager/src/dashboard-reminders/DashboardRemindersWorkspace.tsx +502 -0
  436. package/public/manager/src/dashboard-reminders/InlineReminderTitle.tsx +78 -0
  437. package/public/manager/src/dashboard-reminders/ReminderDetailPopover.tsx +118 -0
  438. package/public/manager/src/dashboard-reminders/reminder-order.ts +45 -0
  439. package/public/manager/src/dashboard-reminders/reminders-api.ts +126 -0
  440. package/public/manager/src/dashboard-reminders/reminders-view-model.ts +63 -0
  441. package/public/manager/src/dashboard-reminders/useDashboardReminderDrag.ts +55 -0
  442. package/public/manager/src/dashboard-reminders/useRemindersFeed.ts +72 -0
  443. package/public/manager/src/dashboard-schedule/DashboardScheduleWorkspace.tsx +10 -4
  444. package/public/manager/src/dashboard-settings/DashboardEmbeddingSection.tsx +350 -0
  445. package/public/manager/src/dashboard-settings/DashboardSettingsSidebar.tsx +6 -2
  446. package/public/manager/src/dashboard-settings/DashboardSettingsWorkspace.tsx +217 -6
  447. package/public/manager/src/dashboard-settings/dashboard-settings-ui.ts +2 -0
  448. package/public/manager/src/dashboard-url-state.ts +15 -0
  449. package/public/manager/src/help/HelpDrawer.tsx +5 -6
  450. package/public/manager/src/help/HelpTopicButton.tsx +23 -0
  451. package/public/manager/src/help/help-shortcuts.ts +7 -0
  452. package/public/manager/src/help/helpContent.tsx +155 -5
  453. package/public/manager/src/hooks/useDashboardView.ts +12 -1
  454. package/public/manager/src/hooks/useInstanceMessageEvents.ts +3 -1
  455. package/public/manager/src/jaw-ceo/JawCeoConsole.tsx +108 -0
  456. package/public/manager/src/jaw-ceo/JawCeoConsolePanels.tsx +331 -0
  457. package/public/manager/src/jaw-ceo/JawCeoSettingsPanel.tsx +94 -0
  458. package/public/manager/src/jaw-ceo/JawCeoTabs.tsx +28 -0
  459. package/public/manager/src/jaw-ceo/JawCeoVoiceOverlay.tsx +34 -0
  460. package/public/manager/src/jaw-ceo/JawCeoWorkbenchButton.tsx +61 -0
  461. package/public/manager/src/jaw-ceo/api.ts +169 -0
  462. package/public/manager/src/jaw-ceo/jaw-ceo-console.css +481 -0
  463. package/public/manager/src/jaw-ceo/jaw-ceo-virtual.css +24 -0
  464. package/public/manager/src/jaw-ceo/jaw-ceo.css +429 -0
  465. package/public/manager/src/jaw-ceo/types.ts +164 -0
  466. package/public/manager/src/jaw-ceo/useJawCeo.ts +235 -0
  467. package/public/manager/src/jaw-ceo/useJawCeoConsoleModel.ts +67 -0
  468. package/public/manager/src/jaw-ceo/useJawCeoDashboardBridge.tsx +76 -0
  469. package/public/manager/src/jaw-ceo/useJawCeoVirtualTimeline.ts +109 -0
  470. package/public/manager/src/jaw-ceo/useJawCeoVoice.ts +219 -0
  471. package/public/manager/src/jaw-ceo/voice-cues.ts +34 -0
  472. package/public/manager/src/jaw-ceo/voice-session.ts +87 -0
  473. package/public/manager/src/main.tsx +11 -0
  474. package/public/manager/src/manager-components.css +7 -0
  475. package/public/manager/src/manager-dashboard-board-sidebar-scroll.css +64 -0
  476. package/public/manager/src/manager-dashboard-reminders-parity.css +156 -0
  477. package/public/manager/src/manager-dashboard-reminders-priority.css +164 -0
  478. package/public/manager/src/manager-dashboard-reminders.css +482 -0
  479. package/public/manager/src/manager-dashboard-schedule.css +12 -0
  480. package/public/manager/src/manager-dashboard-settings.css +16 -2
  481. package/public/manager/src/manager-help.css +27 -0
  482. package/public/manager/src/manager-layout.css +19 -0
  483. package/public/manager/src/manager-notes.css +13 -4
  484. package/public/manager/src/manager-p0-1-1.css +3 -3
  485. package/public/manager/src/manager-polish.css +7 -3
  486. package/public/manager/src/manager-shortcuts.ts +116 -0
  487. package/public/manager/src/notes/MarkdownEditor.tsx +20 -3
  488. package/public/manager/src/notes/MarkdownPreview.tsx +10 -1
  489. package/public/manager/src/notes/NotesFileTree.tsx +14 -22
  490. package/public/manager/src/notes/NotesFrontmatterStrip.tsx +61 -0
  491. package/public/manager/src/notes/NotesQuickSwitcher.tsx +187 -0
  492. package/public/manager/src/notes/NotesSearchSidebar.tsx +118 -0
  493. package/public/manager/src/notes/NotesSidebar.tsx +87 -23
  494. package/public/manager/src/notes/NotesWorkspace.tsx +76 -4
  495. package/public/manager/src/notes/frontmatter-preview.ts +16 -0
  496. package/public/manager/src/notes/notes-api.ts +1 -0
  497. package/public/manager/src/notes/notes-quick-switcher.css +151 -0
  498. package/public/manager/src/notes/notes-search.css +90 -0
  499. package/public/manager/src/notes/notes-tags.css +292 -0
  500. package/public/manager/src/notes/notes-types.ts +6 -0
  501. package/public/manager/src/notes/rendering/MarkdownRenderer.tsx +67 -3
  502. package/public/manager/src/notes/rendering/MermaidBlock.tsx +11 -1
  503. package/public/manager/src/notes/useNoteDocument.ts +14 -2
  504. package/public/manager/src/notes/useNotesModel.ts +39 -2
  505. package/public/manager/src/notes/wiki-link-codemirror-completion.ts +55 -0
  506. package/public/manager/src/notes/wiki-link-rendering.ts +129 -0
  507. package/public/manager/src/notes/wiki-link-resolver.ts +220 -0
  508. package/public/manager/src/notes/wiki-link-suggestions.ts +153 -0
  509. package/public/manager/src/notes/wysiwyg/MilkdownWysiwygEditor.tsx +126 -79
  510. package/public/manager/src/notes/wysiwyg/WysiwygFrontmatterPanel.tsx +93 -0
  511. package/public/manager/src/notes/wysiwyg/milkdown-code-block-view.ts +11 -0
  512. package/public/manager/src/notes/wysiwyg/milkdown-editor-utils.ts +32 -0
  513. package/public/manager/src/notes/wysiwyg/milkdown-math.ts +9 -0
  514. package/public/manager/src/notes/wysiwyg/milkdown-wikilink-completion.ts +195 -0
  515. package/public/manager/src/notes/wysiwyg/milkdown-wikilink-plugin.ts +152 -0
  516. package/public/manager/src/notes/wysiwyg/milkdown-wysiwyg-types.ts +13 -0
  517. package/public/manager/src/notes/wysiwyg/wysiwyg-fixtures.ts +4 -0
  518. package/public/manager/src/notes/wysiwyg/wysiwyg-frontmatter.ts +155 -0
  519. package/public/manager/src/preview.ts +20 -1
  520. package/public/manager/src/settings/pages/Embedding.tsx +382 -0
  521. package/public/manager/src/settings-embedding.css +168 -0
  522. package/public/manager/src/types.ts +20 -2
  523. package/scripts/install-officecli.sh +3 -1
  524. package/scripts/install-wsl.sh +107 -19
  525. package/public/dist/assets/MilkdownWysiwygEditor-Cm3uXfWf.js +0 -52
  526. package/public/dist/assets/app-Be58Cs3Y.js +0 -32
  527. package/public/dist/assets/app-CphocJzo.css +0 -1
  528. package/public/dist/assets/architecture-YZFGNWBL-VpdnYwVC.js +0 -1
  529. package/public/dist/assets/channel-xhp7drfS.js +0 -1
  530. package/public/dist/assets/chunk-426QAEUC-DadS7Aoc.js +0 -1
  531. package/public/dist/assets/chunk-55IACEB6-Cr281urY.js +0 -1
  532. package/public/dist/assets/chunk-QZHKN3VN-BYRU3VjK.js +0 -1
  533. package/public/dist/assets/classDiagram-6PBFFD2Q-Brk35lpl.js +0 -1
  534. package/public/dist/assets/classDiagram-v2-HSJHXN6E-CVZHK0Hg.js +0 -1
  535. package/public/dist/assets/dist-BsT5UdNP.js +0 -1
  536. package/public/dist/assets/dist-ClqO40BE.js +0 -1
  537. package/public/dist/assets/dist-CxeLAw2Y.js +0 -1
  538. package/public/dist/assets/dist-D2SH8nxa.js +0 -1
  539. package/public/dist/assets/dist-DfodGES_.js +0 -23
  540. package/public/dist/assets/dist-l9HH00ip.js +0 -1
  541. package/public/dist/assets/employees-CxdghzoD.js +0 -33
  542. package/public/dist/assets/gitGraph-7Q5UKJZL-CBKRRUZJ.js +0 -1
  543. package/public/dist/assets/idb-cache-C5ilDI6r.js +0 -1
  544. package/public/dist/assets/info-OMHHGYJF-BqzRlF_E.js +0 -1
  545. package/public/dist/assets/insert-image-markdown-DIEa-zjk.js +0 -22
  546. package/public/dist/assets/javascript-DT-6B2IU.js +0 -1
  547. package/public/dist/assets/katex-CS4w7U2j.js +0 -1
  548. package/public/dist/assets/manager-DEiyrWDP.css +0 -1
  549. package/public/dist/assets/manager-UEXd1_9T.js +0 -25
  550. package/public/dist/assets/memory-DXad_DPO.js +0 -1
  551. package/public/dist/assets/mermaid-loader-BEFIOoJn.js +0 -1
  552. package/public/dist/assets/mermaid.core-D0tXHgVC.js +0 -1
  553. package/public/dist/assets/packet-4T2RLAQJ-D7VqJs5z.js +0 -1
  554. package/public/dist/assets/pie-ZZUOXDRM-FbISwuBg.js +0 -1
  555. package/public/dist/assets/radar-PYXPWWZC-CLzM3m4R.js +0 -1
  556. package/public/dist/assets/render-DGQX46ei.js +0 -31
  557. package/public/dist/assets/settings-DXT87G2U.js +0 -1
  558. package/public/dist/assets/skills-5o_1v0nz.js +0 -1
  559. package/public/dist/assets/slash-commands-D4-hrrmh.js +0 -1
  560. package/public/dist/assets/stateDiagram-v2-QKLJ7IA2-DScAhoyh.js +0 -1
  561. package/public/dist/assets/treeView-SZITEDCU-HJajkeQK.js +0 -1
  562. package/public/dist/assets/treemap-W4RFUUIX-CsRQ896G.js +0 -1
  563. package/public/dist/assets/ui-CdRKN2S6.js +0 -141
  564. package/public/dist/assets/ui-n43jmg_f.js +0 -1
  565. package/public/dist/assets/wardley-RL74JXVD-DMQFnlJp.js +0 -1
  566. package/public/dist/assets/ws-CTHQFzM1.js +0 -14
  567. /package/public/dist/assets/{agent-meta-DHddpWHQ.js → agent-meta-C1pQzExf.js} +0 -0
  568. /package/public/dist/assets/{apl-1H3fJ-n9.js → apl-HYRstREL.js} +0 -0
  569. /package/public/dist/assets/{asciiarmor-_1f4lqIZ.js → asciiarmor-BDXCrhAK.js} +0 -0
  570. /package/public/dist/assets/{asn1-B_wp1Pdt.js → asn1-CnSBhb0M.js} +0 -0
  571. /package/public/dist/assets/{asterisk-9Hxmlnbz.js → asterisk-AqV7rnIi.js} +0 -0
  572. /package/public/dist/assets/{brainfuck-C-PAVNT8.js → brainfuck-Dv46-iL9.js} +0 -0
  573. /package/public/dist/assets/{chunk-AGHRB4JF-EroDCcEL.js → chunk-AGHRB4JF-DIMn8T3_.js} +0 -0
  574. /package/public/dist/assets/{clike-DAVXDhrz.js → clike-GRffz5hY.js} +0 -0
  575. /package/public/dist/assets/{clojure-BIpQu4v4.js → clojure-DzgT_fqE.js} +0 -0
  576. /package/public/dist/assets/{cmake-YlOBEvgc.js → cmake-Co1237r5.js} +0 -0
  577. /package/public/dist/assets/{cobol-CU8lw6mH.js → cobol-rUaLketb.js} +0 -0
  578. /package/public/dist/assets/{coffeescript-DKG8mABL.js → coffeescript-DQyfHE86.js} +0 -0
  579. /package/public/dist/assets/{commonlisp-CbWboHR_.js → commonlisp-Buue1PGW.js} +0 -0
  580. /package/public/dist/assets/{constants-CYjOMbjf.js → constants-4A2GptQT.js} +0 -0
  581. /package/public/dist/assets/{crystal-WWs3Njra.js → crystal-BMWO0kOJ.js} +0 -0
  582. /package/public/dist/assets/{css-C9qNtc8P.js → css-DaxibPo5.js} +0 -0
  583. /package/public/dist/assets/{cypher-DglnWVZO.js → cypher-CmpGfiBR.js} +0 -0
  584. /package/public/dist/assets/{cytoscape.esm-BH6rhG9A.js → cytoscape.esm-zT8GwLFm.js} +0 -0
  585. /package/public/dist/assets/{d-DiNW6jcC.js → d-qmdtoIzU.js} +0 -0
  586. /package/public/dist/assets/{diff-PxsoX0eK.js → diff-B40m6u1h.js} +0 -0
  587. /package/public/dist/assets/{dist-BRFvH5ne.js → dist-BJyDhGpS.js} +0 -0
  588. /package/public/dist/assets/{dtd-BSiaE0hE.js → dtd-569ynYVj.js} +0 -0
  589. /package/public/dist/assets/{dylan-GcUJt0a5.js → dylan-Dxolp30i.js} +0 -0
  590. /package/public/dist/assets/{ebnf-DSIN9Ycp.js → ebnf-BZiX9Iq3.js} +0 -0
  591. /package/public/dist/assets/{ecl-LP9l5g0J.js → ecl-B8F1Q0oZ.js} +0 -0
  592. /package/public/dist/assets/{eiffel-CqpH5qaY.js → eiffel-Bv8Kvgh1.js} +0 -0
  593. /package/public/dist/assets/{elm-Dw3cJ7hz.js → elm-QWXQaIis.js} +0 -0
  594. /package/public/dist/assets/{erlang-DL9rpJep.js → erlang-CuDGzTGm.js} +0 -0
  595. /package/public/dist/assets/{fcl-DUmfTiJ7.js → fcl-BiFeqtHf.js} +0 -0
  596. /package/public/dist/assets/{forth-BSp-YOKj.js → forth-R7Uc2VcL.js} +0 -0
  597. /package/public/dist/assets/{fortran-BtIRmo6s.js → fortran-kDRG6BzW.js} +0 -0
  598. /package/public/dist/assets/{gas-okqIRy8I.js → gas-CyRkuC5T.js} +0 -0
  599. /package/public/dist/assets/{gherkin-DIlSAX9i.js → gherkin-BE0p00ey.js} +0 -0
  600. /package/public/dist/assets/{groovy-Dn6VQ7le.js → groovy-B_Sh3D1t.js} +0 -0
  601. /package/public/dist/assets/{haskell-DxXJRRAf.js → haskell-DWXgCy4o.js} +0 -0
  602. /package/public/dist/assets/{haxe-Cf0nItU4.js → haxe-xGxZ54Hv.js} +0 -0
  603. /package/public/dist/assets/{http-C3zQeWFV.js → http-CKv9cSBA.js} +0 -0
  604. /package/public/dist/assets/{idb-cache-CjnC_K0x.js → idb-cache-CZ3JdK8r.js} +0 -0
  605. /package/public/dist/assets/{idl-BvqkcZq5.js → idl-DmlI3XzS.js} +0 -0
  606. /package/public/dist/assets/{javascript-D1nkUbtD.js → javascript-j6r5uf_k.js} +0 -0
  607. /package/public/dist/assets/{jsx-runtime-DOs-BiPY.js → jsx-runtime-BjL7qHh8.js} +0 -0
  608. /package/public/dist/assets/{julia-CCUCEuMJ.js → julia-CQSp9Qa0.js} +0 -0
  609. /package/public/dist/assets/{livescript-DJ-6Zja2.js → livescript-CqvtVTlb.js} +0 -0
  610. /package/public/dist/assets/{locale-f397XJgr.js → locale-BHMJIzyw.js} +0 -0
  611. /package/public/dist/assets/{lua-CxE7YJaJ.js → lua-DazQKUZ0.js} +0 -0
  612. /package/public/dist/assets/{mathematica-oNEp3xtK.js → mathematica-DqhJVCs9.js} +0 -0
  613. /package/public/dist/assets/{mbox-AvjHxuWl.js → mbox-Dsyo1_UL.js} +0 -0
  614. /package/public/dist/assets/{mirc-CiJGiXcS.js → mirc-D7ThhoF-.js} +0 -0
  615. /package/public/dist/assets/{mllike-CV8oQtvy.js → mllike-EPZ6pqQD.js} +0 -0
  616. /package/public/dist/assets/{modelica-M4BAagfL.js → modelica-PU45hbqg.js} +0 -0
  617. /package/public/dist/assets/{mscgen-3QXoaqEl.js → mscgen-DEnh2Ojr.js} +0 -0
  618. /package/public/dist/assets/{mumps-BZoVj2VG.js → mumps-8GhR7rRa.js} +0 -0
  619. /package/public/dist/assets/{nginx-CBycrar_.js → nginx-CXwagpwp.js} +0 -0
  620. /package/public/dist/assets/{ntriples-BzBBWYSl.js → ntriples-BDQxxstw.js} +0 -0
  621. /package/public/dist/assets/{octave-BeIsGSMy.js → octave-2c90WnyU.js} +0 -0
  622. /package/public/dist/assets/{oz-DdNR63iD.js → oz-CO0rQ8EL.js} +0 -0
  623. /package/public/dist/assets/{pascal-BvmM4Y7z.js → pascal-CcVwOGeN.js} +0 -0
  624. /package/public/dist/assets/{path-utils-BuEEtj9w.js → path-utils-DySmCVZK.js} +0 -0
  625. /package/public/dist/assets/{perl-DFibaVbf.js → perl-B9UvGoAV.js} +0 -0
  626. /package/public/dist/assets/{pig-DyLcrln-.js → pig-Cd1f86ZJ.js} +0 -0
  627. /package/public/dist/assets/{powershell-CDOpEwhN.js → powershell-DV4cOnkJ.js} +0 -0
  628. /package/public/dist/assets/{preload-helper-CMqhPRCH.js → preload-helper-DuH3-WbD.js} +0 -0
  629. /package/public/dist/assets/{properties-Ju2yMwi3.js → properties-DaSVPhrZ.js} +0 -0
  630. /package/public/dist/assets/{protobuf-CfKx2SfO.js → protobuf-CEtFnY22.js} +0 -0
  631. /package/public/dist/assets/{puppet-dmjzqANu.js → puppet-Ca0DHfcW.js} +0 -0
  632. /package/public/dist/assets/{python-D9BZyYi1.js → python-ydzCwWG-.js} +0 -0
  633. /package/public/dist/assets/{q-C68SC4ma.js → q-Cl8kzQmk.js} +0 -0
  634. /package/public/dist/assets/{r-DP6KYC7N.js → r-DKZPJFrD.js} +0 -0
  635. /package/public/dist/assets/{rough.esm-BRGGwqOp.js → rough.esm-Dnk3WN4D.js} +0 -0
  636. /package/public/dist/assets/{rpm-DH2Z4z_v.js → rpm-D0lqeHoZ.js} +0 -0
  637. /package/public/dist/assets/{ruby-CwiqsW2a.js → ruby-RVmtmNDw.js} +0 -0
  638. /package/public/dist/assets/{sas-Btq5K1IU.js → sas-CEzodAB7.js} +0 -0
  639. /package/public/dist/assets/{scheme-BvG_RNGf.js → scheme-Pqmt6dh3.js} +0 -0
  640. /package/public/dist/assets/{settings-client-ajlwI-oK.js → settings-client-BN3XzwEo.js} +0 -0
  641. /package/public/dist/assets/{shell-waWIPbLL.js → shell-CLG3zy-u.js} +0 -0
  642. /package/public/dist/assets/{sieve-wIycBENd.js → sieve-C95IWC3O.js} +0 -0
  643. /package/public/dist/assets/{simple-mode-lHvrAolQ.js → simple-mode-B9ErAHMD.js} +0 -0
  644. /package/public/dist/assets/{smalltalk-SHoYQOtw.js → smalltalk-4cL-gRJb.js} +0 -0
  645. /package/public/dist/assets/{solr-D1Apesak.js → solr-CEA7oOx_.js} +0 -0
  646. /package/public/dist/assets/{sparql-BJozOrmN.js → sparql-w8kHjP6I.js} +0 -0
  647. /package/public/dist/assets/{spreadsheet-71jLW2fq.js → spreadsheet-C8bDfTgC.js} +0 -0
  648. /package/public/dist/assets/{sql-BaHU6gLz.js → sql-BrKz8968.js} +0 -0
  649. /package/public/dist/assets/{stex-BuVGLRtt.js → stex-xFw1nXeT.js} +0 -0
  650. /package/public/dist/assets/{stylus-Cqweyusm.js → stylus-gS_68vPk.js} +0 -0
  651. /package/public/dist/assets/{swift-Dx3m4XfV.js → swift-D5lXmY2d.js} +0 -0
  652. /package/public/dist/assets/{tcl-5yXjCZ8e.js → tcl-D-41REtC.js} +0 -0
  653. /package/public/dist/assets/{textile-9HVfsYV6.js → textile-D-Znao0j.js} +0 -0
  654. /package/public/dist/assets/{tiddlywiki-DlSf8L__.js → tiddlywiki-Co8lXJKd.js} +0 -0
  655. /package/public/dist/assets/{tiki-CDZRH0A4.js → tiki-DsiNRYMP.js} +0 -0
  656. /package/public/dist/assets/{toml-BgjfE0Y7.js → toml-CaVZGou4.js} +0 -0
  657. /package/public/dist/assets/{troff-B4ZrJIrZ.js → troff-DJvDVr-d.js} +0 -0
  658. /package/public/dist/assets/{ttcn-BJIiaYhP.js → ttcn-DAC92l4d.js} +0 -0
  659. /package/public/dist/assets/{ttcn-cfg-PZp_QKQg.js → ttcn-cfg-C0X-mYlr.js} +0 -0
  660. /package/public/dist/assets/{turtle--ft5y7IN.js → turtle-D6WHyCrL.js} +0 -0
  661. /package/public/dist/assets/{vb-DL6cecZs.js → vb-CEo_ccq3.js} +0 -0
  662. /package/public/dist/assets/{vbscript-Bb1xiv7E.js → vbscript-B_PKDV1v.js} +0 -0
  663. /package/public/dist/assets/{velocity-DKS9ZfbJ.js → velocity-ClKnKBLH.js} +0 -0
  664. /package/public/dist/assets/{vendor-utils-CWelFt6C.js → vendor-utils-IVTPs69f.js} +0 -0
  665. /package/public/dist/assets/{verilog-DSfhYFaT.js → verilog-Pnuspgw6.js} +0 -0
  666. /package/public/dist/assets/{vhdl-CFTSUmh9.js → vhdl-CZnyY4fs.js} +0 -0
  667. /package/public/dist/assets/{w3c-keyname-IiiZScED.js → w3c-keyname-DJlC6DTY.js} +0 -0
  668. /package/public/dist/assets/{webidl-C-IpKmuN.js → webidl-DHr762Dm.js} +0 -0
  669. /package/public/dist/assets/{xquery-9pXYEith.js → xquery-5-FiyUtN.js} +0 -0
  670. /package/public/dist/assets/{yacas-CqSYoSTv.js → yacas-GlqsXIeT.js} +0 -0
  671. /package/public/dist/assets/{z80-BltHQfm4.js → z80-CI7N40Oo.js} +0 -0
@@ -1,1081 +1,17 @@
1
- // ── Render Helpers ──
2
- // Modular markdown rendering: marked + highlight.js + KaTeX + Mermaid
3
- // All libs bundled via npm imports; mermaid lazy-loaded on first use
4
-
5
- import { marked, Renderer } from 'marked';
6
- import { apiJson } from './api.js';
7
- import hljs from 'highlight.js/lib/core';
8
- import javascript from 'highlight.js/lib/languages/javascript';
9
- import typescript from 'highlight.js/lib/languages/typescript';
10
- import python from 'highlight.js/lib/languages/python';
11
- import bash from 'highlight.js/lib/languages/bash';
12
- import shell from 'highlight.js/lib/languages/shell';
13
- import json from 'highlight.js/lib/languages/json';
14
- import css from 'highlight.js/lib/languages/css';
15
- import xml from 'highlight.js/lib/languages/xml';
16
- import markdown from 'highlight.js/lib/languages/markdown';
17
- import yaml from 'highlight.js/lib/languages/yaml';
18
- import sql from 'highlight.js/lib/languages/sql';
19
- import rust from 'highlight.js/lib/languages/rust';
20
- import go from 'highlight.js/lib/languages/go';
21
- import java from 'highlight.js/lib/languages/java';
22
- import cpp from 'highlight.js/lib/languages/cpp';
23
- import diff from 'highlight.js/lib/languages/diff';
24
- import plaintext from 'highlight.js/lib/languages/plaintext';
25
- import katex from 'katex';
26
- import { getDOMPurify } from './sanitizer.js';
27
- import { t } from './features/i18n.js';
28
- import { ICONS } from './icons.js';
29
- import { fixCjkPunctuationBoundary } from './cjk-fix.js';
30
- import {
31
- SvgBlock, shieldCodeFenceSvg, unshieldCodeFenceSvg,
32
- extractTopLevelSvg,
33
- } from './diagram/types.js';
34
-
35
- function purifier() {
36
- return getDOMPurify();
37
- }
38
-
39
- // Register hljs languages (core-only import: ~25KB vs ~1MB full)
40
- hljs.registerLanguage('javascript', javascript);
41
- hljs.registerLanguage('js', javascript);
42
- hljs.registerLanguage('typescript', typescript);
43
- hljs.registerLanguage('ts', typescript);
44
- hljs.registerLanguage('python', python);
45
- hljs.registerLanguage('py', python);
46
- hljs.registerLanguage('bash', bash);
47
- hljs.registerLanguage('shell', shell);
48
- hljs.registerLanguage('sh', shell);
49
- hljs.registerLanguage('json', json);
50
- hljs.registerLanguage('css', css);
51
- hljs.registerLanguage('xml', xml);
52
- hljs.registerLanguage('html', xml);
53
- hljs.registerLanguage('markdown', markdown);
54
- hljs.registerLanguage('md', markdown);
55
- hljs.registerLanguage('yaml', yaml);
56
- hljs.registerLanguage('yml', yaml);
57
- hljs.registerLanguage('sql', sql);
58
- hljs.registerLanguage('rust', rust);
59
- hljs.registerLanguage('rs', rust);
60
- hljs.registerLanguage('go', go);
61
- hljs.registerLanguage('java', java);
62
- hljs.registerLanguage('cpp', cpp);
63
- hljs.registerLanguage('c', cpp);
64
- hljs.registerLanguage('diff', diff);
65
- hljs.registerLanguage('plaintext', plaintext);
66
- hljs.registerLanguage('text', plaintext);
67
-
68
- interface MermaidApi {
69
- initialize(config: Record<string, unknown>): void;
70
- render(id: string, code: string): Promise<{ svg: string }>;
71
- }
72
-
73
- // Lazy mermaid: loaded on first diagram encounter
74
- let mermaidModule: MermaidApi | null = null;
75
-
76
- // Serialise all Mermaid render calls — concurrent renders corrupt shared internal state.
77
- let mermaidQueue: Promise<void> = Promise.resolve();
78
-
79
- function getMermaidThemeVars() {
80
- const isLight = document.documentElement.getAttribute('data-theme') === 'light';
81
- return isLight ? {
82
- primaryColor: '#e2e8f0',
83
- primaryTextColor: '#1a202c',
84
- primaryBorderColor: '#a0aec0',
85
- lineColor: '#718096',
86
- secondaryColor: '#ebf8ff',
87
- tertiaryColor: '#f7fafc',
88
- background: 'transparent',
89
- mainBkg: '#e2e8f0',
90
- nodeBorder: '#a0aec0',
91
- clusterBkg: '#f7fafc',
92
- clusterBorder: '#cbd5e0',
93
- titleColor: '#1a202c',
94
- edgeLabelBackground: '#f7fafc',
95
- } : {
96
- primaryColor: '#2d3748',
97
- primaryTextColor: '#e2e8f0',
98
- primaryBorderColor: '#4a5568',
99
- lineColor: '#718096',
100
- secondaryColor: '#1a365d',
101
- tertiaryColor: '#1a202c',
102
- background: 'transparent',
103
- mainBkg: '#2d3748',
104
- nodeBorder: '#4a5568',
105
- clusterBkg: '#1a202c',
106
- clusterBorder: '#2d3748',
107
- titleColor: '#e2e8f0',
108
- edgeLabelBackground: '#1a202c',
109
- };
110
- }
111
-
112
- async function ensureMermaidLoaded() {
113
- if (!mermaidModule) {
114
- const loader = await import('./mermaid-loader.js');
115
- mermaidModule = loader.loadMermaid();
116
- }
117
- return mermaidModule;
118
- }
119
-
120
- // Re-apply theme config immediately before every render() call.
121
- // Mermaid's internal config can drift after parse()/render() due to
122
- // directive resets — never cache, always re-initialise.
123
- function applyMermaidTheme() {
124
- mermaidModule!.initialize({
125
- startOnLoad: false,
126
- theme: 'base',
127
- htmlLabels: false,
128
- themeVariables: getMermaidThemeVars(),
129
- securityLevel: 'strict',
130
- suppressErrorRendering: true,
131
- });
132
- }
133
-
134
- // Mermaid SVG sanitizer — allows <style> (required for Mermaid theming)
135
- // Separate from sanitizeHtml() which blocks <style> for user-supplied SVGs.
136
- // Mermaid is configured with htmlLabels:false so labels use SVG <text>,
137
- // not <foreignObject> + HTML. This avoids DOMPurify namespace issues.
138
- function sanitizeMermaidSvg(svg: string): string {
139
- const clean = purifier().sanitize(svg, {
140
- USE_PROFILES: { svg: true, svgFilters: true },
141
- FORBID_TAGS: [
142
- 'script', 'iframe', 'object', 'embed', 'form', 'input',
143
- 'foreignObject', 'animate', 'set', 'animateTransform', 'animateMotion',
144
- ],
145
- FORBID_ATTR: ['onerror', 'onclick', 'onload', 'onmouseover', 'onfocus', 'onblur',
146
- 'background'],
147
- });
148
- // Sanitize CSS inside <style> blocks: strip @import, @font-face, external url()
149
- const div = document.createElement('div');
150
- div.innerHTML = clean;
151
- for (const style of div.querySelectorAll('style')) {
152
- let css = style.textContent || '';
153
- css = css.replace(/@import\b[^;]*;?/gi, '/* stripped */');
154
- css = css.replace(/@font-face\s*\{[^}]*\}/gi, '/* stripped */');
155
- css = css.replace(/url\s*\(\s*(?!['"]?#)[^)]*\)/gi, 'none');
156
- style.textContent = css;
157
- }
158
- return div.innerHTML;
159
- }
160
-
161
- export function escapeHtml(str: string): string {
162
- return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
163
- .replace(/"/g, '&quot;').replace(/'/g, '&#39;');
164
- }
165
-
166
- // ── XSS sanitization (hardened for inline SVG — Phase 1) ──
167
- export function sanitizeHtml(html: string): string {
168
- return purifier().sanitize(html, {
169
- USE_PROFILES: { html: true, svg: true, svgFilters: true },
170
- FORBID_TAGS: [
171
- 'script', 'style', 'iframe', 'object', 'embed', 'form', 'input',
172
- // SVG security: block animation + foreignObject (script injection vectors)
173
- 'foreignObject', 'animate', 'set', 'animateTransform', 'animateMotion',
174
- ],
175
- FORBID_ATTR: ['onerror', 'onclick', 'onload', 'onmouseover', 'onfocus', 'onblur',
176
- 'background'], // legacy HTML attr that triggers remote fetch
177
- ADD_TAGS: ['use'],
178
- ADD_ATTR: ['aria-hidden', 'xmlns', 'viewBox', 'role', 'aria-label',
179
- 'data-jaw-svg', 'data-jaw-kind', 'data-mermaid-code-raw',
180
- 'href', 'xlink:href'],
181
- });
182
- }
183
-
184
- // ── Orchestration JSON stripping ──
185
- // Only strip JSON blocks that contain orchestration-specific keys, not all JSON blocks
186
- // Require keys unique to orchestration payloads (avoid generic words like "phase")
187
- const ORCH_KEYS = /["'](?:subtasks|employee_config|agent_phases|orchestration_plan)["']\s*:/;
188
- const PROMPT_LEAK_START = /(^|\n)(?:## Approved Plan \((?:authoritative|auto-injected by orchestrator)[^\n]*\)|\[PABCD — [A-Z]:[^\n]*\]|\[PLANNING MODE[^\n]*\]|\[PLAN AUDIT[^\n]*\]|The approved plan is already injected above)/m;
189
-
190
- export function stripPromptLeakage(text: string): string {
191
- const match = PROMPT_LEAK_START.exec(text);
192
- if (!match || match.index < 0) return text;
193
- return text.slice(0, match.index).trim();
194
- }
195
-
196
- export function stripOrchestration(text: string): string {
197
- // Strip fenced JSON blocks only if they contain orchestration keys
198
- let cleaned = text.replace(/```json\n([\s\S]*?)\n```/g, (_match, inner) =>
199
- ORCH_KEYS.test(inner) ? '' : _match);
200
- // Strip inline orchestration objects containing subtasks array
201
- cleaned = cleaned.replace(/\{[^{}]*"subtasks"\s*:\s*\[[\s\S]*?\]\s*\}/g, '').trim();
202
- return stripPromptLeakage(cleaned);
203
- }
204
-
205
- // ── KaTeX math shield/unshield ──
206
- // Shield: marked 전에 수식을 플레이스홀더로 치환 (marked가 $를 파괴하는 것 방지)
207
- // Unshield: marked 후에 플레이스홀더를 KaTeX 렌더링으로 복원
208
-
209
- interface MathBlock { tex: string; displayMode: boolean; }
210
-
211
- export function shieldMath(text: string): { text: string; blocks: MathBlock[] } {
212
- const blocks: MathBlock[] = [];
213
- // 1. 코드 블록/인라인 코드 보존 (수식 추출 대상에서 제외)
214
- const preserved: string[] = [];
215
- let processed = text
216
- .replace(/```[\s\S]*?```/g, (m) => {
217
- preserved.push(m); return `\x00C${preserved.length - 1}\x00`;
218
- })
219
- .replace(/`[^`]+`/g, (m) => {
220
- preserved.push(m); return `\x00C${preserved.length - 1}\x00`;
221
- });
222
-
223
- // 2. Block math: $$...$$ (먼저 — greedy 방지)
224
- processed = processed.replace(/\$\$([\s\S]+?)\$\$/g, (_, tex: string) => {
225
- blocks.push({ tex: tex.trim(), displayMode: true });
226
- return `\x00MATH-${blocks.length - 1}\x00`;
227
- });
228
-
229
- // 3. GPT-style block math: \[...\]
230
- processed = processed.replace(/\\\[([\s\S]+?)\\\]/g, (_, tex: string) => {
231
- blocks.push({ tex: tex.trim(), displayMode: true });
232
- return `\x00MATH-${blocks.length - 1}\x00`;
233
- });
234
-
235
- // 4. Inline math: $...$ (통화 $10 제외)
236
- processed = processed.replace(/(?<!\$)\$(?!\$)([^\n$]+?)\$(?!\$)/g, (_, tex: string) => {
237
- blocks.push({ tex: tex.trim(), displayMode: false });
238
- return `\x00MATH-${blocks.length - 1}\x00`;
239
- });
240
-
241
- // 5. GPT-style inline math: \(...\)
242
- processed = processed.replace(/\\\((.+?)\\\)/g, (_, tex: string) => {
243
- blocks.push({ tex: tex.trim(), displayMode: false });
244
- return `\x00MATH-${blocks.length - 1}\x00`;
245
- });
246
-
247
- // 4. 코드 블록 복원
248
- processed = processed.replace(/\x00C(\d+)\x00/g, (_, i) => preserved[Number(i)]);
249
-
250
- return { text: processed, blocks };
251
- }
252
-
253
- export function unshieldMath(html: string, blocks: MathBlock[], isStreaming = false): string {
254
- return html.replace(/\x00MATH-(\d+)\x00/g, (_, i) => {
255
- const block = blocks[Number(i)];
256
- if (!block) return `<code title="math placeholder error">[math error]</code>`;
257
-
258
- // During streaming: lightweight placeholder, defer KaTeX to finalize
259
- if (isStreaming) {
260
- return block.displayMode
261
- ? `<div class="math-placeholder">${escapeHtml(block.tex)}</div>`
262
- : `<code class="math-placeholder">${escapeHtml(block.tex)}</code>`;
263
- }
264
-
265
- try {
266
- return katex.renderToString(block.tex, {
267
- displayMode: block.displayMode,
268
- throwOnError: false,
269
- });
270
- } catch {
271
- return block.displayMode
272
- ? `<pre><code>${escapeHtml(block.tex)}</code></pre>`
273
- : `<code>${escapeHtml(block.tex)}</code>`;
274
- }
275
- });
276
- }
277
-
278
- // ── Mermaid deferred rendering (lazy-loaded) ──
279
- let mermaidId = 0;
280
-
281
- /** Re-render all existing Mermaid diagrams (call on theme toggle). */
282
- export async function rerenderMermaidDiagrams(): Promise<void> {
283
- const rendered = document.querySelectorAll('.mermaid-rendered');
284
- if (!rendered.length) return;
285
- mermaidQueue = mermaidQueue.then(async () => {
286
- const mm = await ensureMermaidLoaded();
287
- for (const el of rendered) {
288
- const htmlEl = el as HTMLElement;
289
- const code = htmlEl.dataset['mermaidCode'];
290
- if (!code || !htmlEl.isConnected) continue;
291
- const id = `mermaid-${++mermaidId}`;
292
- try {
293
- applyMermaidTheme();
294
- const { svg } = await mm.render(id, code);
295
- if (!htmlEl.isConnected) continue;
296
- htmlEl.innerHTML = sanitizeMermaidSvg(svg);
297
- appendMermaidActionBtns(htmlEl);
298
- bindDiagramZoom(htmlEl);
299
- } catch { /* keep existing render on failure */ }
300
- }
301
- }).catch(err => {
302
- console.error('[mermaid:queue] rerender failed, keeping queue alive:', err);
303
- });
304
- await mermaidQueue;
305
- }
306
-
307
- // Lazy Mermaid rendering — only render blocks near the viewport
308
- let mermaidObserver: IntersectionObserver | null = null;
309
-
310
- function ensureMermaidObserver(): void {
311
- if (mermaidObserver) return;
312
- mermaidObserver = new IntersectionObserver((entries) => {
313
- for (const entry of entries) {
314
- if (!entry.isIntersecting) continue;
315
- const el = entry.target as HTMLElement;
316
- if (!el.classList.contains('mermaid-pending')) continue;
317
- mermaidObserver!.unobserve(el);
318
- renderSingleMermaid(el);
319
- }
320
- }, { rootMargin: '200px' }); // pre-render 200px before visible
321
- }
322
-
323
- function appendMermaidActionBtns(el: HTMLElement): void {
324
- // Remove existing buttons if present (e.g. re-render)
325
- el.querySelector('.mermaid-zoom-btn')?.remove();
326
- el.querySelector('.mermaid-copy-btn')?.remove();
327
- el.querySelector('.mermaid-save-btn')?.remove();
328
-
329
- const zoomBtn = document.createElement('button');
330
- zoomBtn.className = 'mermaid-zoom-btn';
331
- zoomBtn.type = 'button';
332
- zoomBtn.ariaLabel = 'Expand diagram';
333
- zoomBtn.title = 'Expand';
334
- zoomBtn.textContent = '⤢';
335
- el.appendChild(zoomBtn);
336
-
337
- const saveBtn = document.createElement('button');
338
- saveBtn.className = 'mermaid-save-btn';
339
- saveBtn.type = 'button';
340
- saveBtn.ariaLabel = 'Save as image';
341
- saveBtn.title = 'Save';
342
- saveBtn.innerHTML = ICONS.download;
343
- el.appendChild(saveBtn);
344
-
345
- const copyBtn = document.createElement('button');
346
- copyBtn.className = 'mermaid-copy-btn';
347
- copyBtn.type = 'button';
348
- copyBtn.ariaLabel = 'Copy source';
349
- copyBtn.title = 'Copy';
350
- copyBtn.innerHTML = ICONS.copy;
351
- el.appendChild(copyBtn);
352
- }
353
-
354
- function renderMermaidError(el: HTMLElement, code: string, errMsg: string): void {
355
- el.classList.remove('mermaid-rendered');
356
- el.innerHTML = `
357
- <div class="mermaid-error">
358
- <div class="mermaid-error-title">${ICONS.warning} ${escapeHtml(t('mermaid.renderFail') || 'Mermaid render failed')}</div>
359
- <div class="mermaid-error-msg">${escapeHtml(errMsg.slice(0, 200))}</div>
360
- <pre class="mermaid-error-code"><code>${escapeHtml(code)}</code></pre>
361
- </div>`;
362
- }
363
-
364
- async function renderSingleMermaidImpl(el: HTMLElement): Promise<void> {
365
- if (!el.isConnected) {
366
- delete el.dataset['mermaidQueued'];
367
- delete el.dataset['mermaidInflight'];
368
- return;
369
- }
370
- el.classList.remove('mermaid-pending');
371
- // Phase 127-F1: raw source lives in data attribute (skeleton DOM has no source text).
372
- const encoded = el.dataset['mermaidCodeRaw'] || '';
373
- const code = encoded ? decodeURIComponent(encoded) : (el.textContent || '');
374
- el.dataset['mermaidCode'] = code;
375
- const id = `mermaid-${++mermaidId}`;
376
- el.dataset['mermaidInflight'] = '1';
377
- try {
378
- const mm = await ensureMermaidLoaded();
379
- // Apply theme immediately before render — no intermediate parse()
380
- // that could reset Mermaid's internal config state.
381
- applyMermaidTheme();
382
- const { svg } = await mm.render(id, code);
383
- if (!el.isConnected) {
384
- return;
385
- }
386
- el.innerHTML = sanitizeMermaidSvg(svg);
387
- el.classList.add('mermaid-rendered');
388
- delete el.dataset['mermaidCodeRaw'];
389
- appendMermaidActionBtns(el);
390
- bindDiagramZoom(el);
391
- } catch (err: unknown) {
392
- const errMsg = (err as { message?: string; str?: string })?.message
393
- || (err as { str?: string })?.str || 'Unknown error';
394
- renderMermaidError(el, code, errMsg);
395
- } finally {
396
- delete el.dataset['mermaidQueued'];
397
- delete el.dataset['mermaidInflight'];
398
- }
399
- }
400
-
401
- // Serialise renders to prevent concurrent Mermaid operations from
402
- // corrupting shared internal state (theme config, diagram registry).
403
- function renderSingleMermaid(el: HTMLElement): void {
404
- // Phase 127-N2: synchronous queued guard prevents duplicate enqueueing when
405
- // renderMermaidBlocks immediate mode fires repeatedly (e.g. VS onPostRender
406
- // on every scroll). Class/dataset is set right away so the next pass skips.
407
- if (el.dataset['mermaidQueued'] === '1') return;
408
- el.dataset['mermaidQueued'] = '1';
409
- // Phase 127-F6: .catch tail keeps the queue alive after any rejection so
410
- // one bad render cannot permanently block subsequent diagrams.
411
- mermaidQueue = mermaidQueue
412
- .then(() => renderSingleMermaidImpl(el))
413
- .catch(err => {
414
- console.error('[mermaid:queue] render failed, keeping queue alive:', err);
415
- });
416
- }
417
-
418
- /**
419
- * Phase 127-F5: exposed so streaming finalize / virtual-scroll hooks can push
420
- * new mermaid blocks through the pipeline without waiting for schedulePostRender.
421
- *
422
- * @param scope DOM subtree to scan (defaults to whole document)
423
- * @param opts.immediate if true, render blocks already in (or near) viewport
424
- * right now instead of waiting for the observer.
425
- */
426
- export async function renderMermaidBlocks(
427
- scope?: HTMLElement | Document,
428
- opts: { immediate?: boolean } = {},
429
- ): Promise<void> {
430
- const root = scope || document;
431
- const pending = root.querySelectorAll<HTMLElement>('.mermaid-pending');
432
- if (!pending.length) return;
433
- ensureMermaidObserver();
434
- for (const el of pending) {
435
- if (el.dataset['mermaidQueued'] === '1') continue; // N2 guard
436
- if (opts.immediate) {
437
- const rect = el.getBoundingClientRect();
438
- const vh = window.innerHeight || document.documentElement.clientHeight;
439
- const inView = rect.bottom >= -200 && rect.top <= vh + 200;
440
- if (inView) {
441
- mermaidObserver!.unobserve(el);
442
- renderSingleMermaid(el);
443
- continue;
444
- }
445
- }
446
- mermaidObserver!.observe(el);
447
- }
448
- }
449
-
450
- export function releaseMermaidNodes(scope: HTMLElement): void {
451
- if (!mermaidObserver) return;
452
- const selector = [
453
- '.mermaid-pending',
454
- '[data-mermaid-queued="1"]',
455
- '[data-mermaid-inflight="1"]',
456
- ].join(',');
457
- const nodes: HTMLElement[] = [];
458
- if (scope.matches(selector)) nodes.push(scope);
459
- scope.querySelectorAll<HTMLElement>(selector).forEach((el) => nodes.push(el));
460
- for (const el of nodes) {
461
- mermaidObserver.unobserve(el);
462
- delete el.dataset['mermaidQueued'];
463
- delete el.dataset['mermaidQueuedAt'];
464
- delete el.dataset['mermaidInflight'];
465
- if (!el.classList.contains('mermaid-rendered')
466
- && (el.dataset['mermaidCodeRaw'] || el.dataset['mermaidCode'])) {
467
- el.classList.add('mermaid-pending');
468
- }
469
- }
470
- }
471
-
472
- /**
473
- * Phase 127-F2: prewarm Mermaid module at idle time so the first diagram's
474
- * cold-start does not block rendering. Safe to call multiple times.
475
- */
476
- export function prewarmMermaid(): void {
477
- if (mermaidModule) return;
478
- const run = () => { void ensureMermaidLoaded().catch(() => { /* silent */ }); };
479
- if (typeof (window as unknown as { requestIdleCallback?: unknown }).requestIdleCallback === 'function') {
480
- (window as unknown as { requestIdleCallback: (cb: () => void, opts?: { timeout?: number }) => void })
481
- .requestIdleCallback(run, { timeout: 2000 });
482
- } else {
483
- setTimeout(run, 500);
484
- }
485
- }
486
-
487
- // ── marked.js configuration (ES module — always available) ──
488
- let markedReady = false;
489
-
490
- function ensureMarked(): boolean {
491
- if (markedReady) return true;
492
-
493
- const renderer = new Renderer();
494
-
495
- // Code blocks: highlight.js + mermaid + diagram-html detection
496
- renderer.code = function ({ text, lang }: { text: string; lang?: string }) {
497
- if (lang === 'mermaid') {
498
- // Phase 127-F1: store raw source in data attribute, render a skeleton
499
- // placeholder so users never see raw Mermaid syntax while the diagram loads.
500
- const encodedCode = encodeURIComponent(text);
501
- return `<div class="mermaid-container mermaid-pending" data-mermaid-code-raw="${encodedCode}" role="status" aria-label="Diagram loading">
502
- <div class="mermaid-skeleton">
503
- <div class="mermaid-skeleton-spinner"></div>
504
- <div class="mermaid-skeleton-text">Rendering diagram…</div>
505
- </div>
506
- </div>`;
507
- }
508
- // diagram-html: encode as base64, Phase 2 activateWidgets() inflates to sandboxed iframe
509
- if (lang?.trim().toLowerCase() === 'diagram-html') {
510
- const encoded = btoa(unescape(encodeURIComponent(text)));
511
- return `<div class="diagram-widget-pending" data-diagram-html="${encoded}"
512
- role="status" aria-label="Interactive widget loading">
513
- <div class="diagram-spinner"></div>
514
- </div>`;
515
- }
516
- let highlighted = escapeHtml(text);
517
- if (lang && hljs.getLanguage(lang)) {
518
- try {
519
- highlighted = hljs.highlight(text, { language: lang }).value;
520
- } catch { /* fallback to escaped */ }
521
- } else {
522
- try {
523
- highlighted = hljs.highlightAuto(text).value;
524
- } catch { /* fallback */ }
525
- }
526
- const langDisplay = lang ? escapeHtml(lang) : '';
527
- const copyLabel = t('code.copy') || 'Copy';
528
- return `<div class="code-block"><div class="code-header"><span class="code-lang">${langDisplay}</span><button class="code-copy-btn" type="button" aria-label="${escapeHtml(copyLabel)}">${escapeHtml(copyLabel)}</button></div><pre><code class="hljs${lang ? ` language-${escapeHtml(lang)}` : ''}">${highlighted}</code></pre></div>`;
529
- };
530
-
531
- marked.setOptions({
532
- renderer,
533
- gfm: true,
534
- breaks: false,
535
- });
536
-
537
- markedReady = true;
538
- return true;
539
- }
540
-
541
- // ── Rehighlight all code blocks ──
542
- export function rehighlightAll(scope?: HTMLElement | Document): void {
543
- const root = scope || document;
544
- root.querySelectorAll('.code-block pre code, .code-block-wrapper pre code').forEach(el => {
545
- if ((el as HTMLElement).dataset['highlighted'] === 'yes') return;
546
- const lang = [...el.classList].find(c => c.startsWith('language-'))?.replace('language-', '');
547
- const raw = el.textContent || '';
548
- try {
549
- if (lang && hljs.getLanguage(lang)) {
550
- el.innerHTML = hljs.highlight(raw, { language: lang }).value;
551
- } else {
552
- el.innerHTML = hljs.highlightAuto(raw).value;
553
- }
554
- (el as HTMLElement).dataset['highlighted'] = 'yes';
555
- } catch { /* ignore */ }
556
- });
557
- }
558
-
559
- // ── File path linkification (click-to-open in Finder) ──
560
-
561
- const FILE_PATH_RE_G = /(?:~\/[^\s)`\]"'<>]+|\/(?:Users|home|tmp|var|opt|private)\/[^\s)`\]"'<>]+)/g;
562
- const TRAILING_PUNCT_RE = /[.,!?:;]+$/;
563
- const LOCAL_FILE_HREF_RE = /^(?:~\/|\/(?:Users|home|tmp|var|opt|private)\/)/;
564
-
565
- function isLocalFileHref(href: string): boolean {
566
- return LOCAL_FILE_HREF_RE.test(href);
567
- }
568
-
569
- function openLocalPath(path: string, el?: HTMLElement | null): void {
570
- if (el) el.classList.add('opening');
571
-
572
- apiJson<{ ok?: boolean; error?: string }>('/api/file/open', 'POST', { path })
573
- .then(data => {
574
- el?.classList.remove('opening');
575
- if (data?.ok !== false) {
576
- el?.classList.add('opened');
577
- setTimeout(() => el?.classList.remove('opened'), 1500);
578
- } else {
579
- el?.classList.add('open-failed');
580
- if (el) el.title = data?.error || 'Failed to open';
581
- setTimeout(() => {
582
- el?.classList.remove('open-failed');
583
- if (el) el.title = '';
584
- }, 2000);
585
- }
586
- })
587
- .catch(() => {
588
- el?.classList.remove('opening');
589
- el?.classList.add('open-failed');
590
- setTimeout(() => el?.classList.remove('open-failed'), 2000);
591
- });
592
- }
593
-
594
- /**
595
- * Walk text nodes inside container, wrap file paths in clickable spans.
596
- * Idempotent — skips already-linkified paths.
597
- * Skips: <pre>, <a>, <button>, .file-path-link
598
- */
599
- export function linkifyFilePaths(container: HTMLElement): void {
600
- const SKIP_TAGS = new Set(['PRE', 'A', 'BUTTON', 'TEXTAREA', 'INPUT', 'SCRIPT', 'STYLE']);
601
-
602
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, {
603
- acceptNode(node) {
604
- let el = node.parentElement;
605
- while (el && el !== container) {
606
- if (SKIP_TAGS.has(el.tagName)) return NodeFilter.FILTER_REJECT;
607
- if (el.classList.contains('file-path-link')) return NodeFilter.FILTER_REJECT;
608
- if (el.tagName === 'CODE' && el.parentElement?.tagName === 'PRE') {
609
- return NodeFilter.FILTER_REJECT;
610
- }
611
- el = el.parentElement;
612
- }
613
- return NodeFilter.FILTER_ACCEPT;
614
- },
615
- });
616
-
617
- // Collect text nodes with matches, grouped by node
618
- const nodeMatches = new Map<Text, { index: number; raw: string; clean: string }[]>();
619
- let textNode: Text | null;
620
- while ((textNode = walker.nextNode() as Text | null)) {
621
- const text = textNode.textContent || '';
622
- FILE_PATH_RE_G.lastIndex = 0;
623
- let m: RegExpExecArray | null;
624
- const hits: { index: number; raw: string; clean: string }[] = [];
625
- while ((m = FILE_PATH_RE_G.exec(text))) {
626
- const raw = m[0];
627
- const clean = raw.replace(TRAILING_PUNCT_RE, '');
628
- if (clean.length < 4) continue;
629
- hits.push({ index: m.index, raw, clean });
630
- }
631
- if (hits.length) nodeMatches.set(textNode, hits);
632
- }
633
-
634
- // Replace each text node once — build full fragment with all matches
635
- for (const [node, hits] of nodeMatches) {
636
- const text = node.textContent || '';
637
- const parent = node.parentNode;
638
- if (!parent) continue;
639
-
640
- const frag = document.createDocumentFragment();
641
- let cursor = 0;
642
-
643
- for (const { index, raw, clean } of hits) {
644
- // Text before this match
645
- if (index > cursor) {
646
- frag.appendChild(document.createTextNode(text.slice(cursor, index)));
647
- }
648
- // The clickable span
649
- const span = document.createElement('span');
650
- span.className = 'file-path-link';
651
- span.setAttribute('data-file-path', clean);
652
- span.setAttribute('role', 'button');
653
- span.setAttribute('tabindex', '0');
654
- span.textContent = clean;
655
- frag.appendChild(span);
656
- // Trailing punctuation that was trimmed
657
- const trailingPunct = raw.slice(clean.length);
658
- if (trailingPunct) frag.appendChild(document.createTextNode(trailingPunct));
659
- cursor = index + raw.length;
660
- }
661
-
662
- // Remaining text after last match
663
- if (cursor < text.length) {
664
- frag.appendChild(document.createTextNode(text.slice(cursor)));
665
- }
666
-
667
- parent.replaceChild(frag, node);
668
- }
669
- }
670
-
671
- // ── File path click event delegation (one-time setup) ──
672
- let filePathDelegationReady = false;
673
-
674
- function ensureFilePathDelegation(): void {
675
- if (filePathDelegationReady) return;
676
- filePathDelegationReady = true;
677
-
678
- document.addEventListener('click', (e: MouseEvent) => {
679
- const target = e.target as HTMLElement;
680
- const anchor = target?.closest('a') as HTMLAnchorElement | null;
681
- const href = anchor?.getAttribute('href') || '';
682
- if (anchor && isLocalFileHref(href)) {
683
- e.preventDefault();
684
- anchor.classList.add('file-path-link');
685
- openLocalPath(href, anchor);
686
- return;
687
- }
688
-
689
- const link = target?.closest('.file-path-link') as HTMLElement | null;
690
- if (!link) return;
691
-
692
- const filePath = link.getAttribute('data-file-path');
693
- if (!filePath) return;
694
- openLocalPath(filePath, link);
695
- });
696
-
697
- document.addEventListener('keydown', (e: KeyboardEvent) => {
698
- if (e.key !== 'Enter' && e.key !== ' ') return;
699
- const target = e.target as HTMLElement;
700
- if (target?.classList.contains('file-path-link')) {
701
- e.preventDefault();
702
- target.click();
703
- }
704
- });
705
- }
706
-
707
- // ── Copy button event delegation (one-time setup) ──
708
- let copyDelegationReady = false;
709
-
710
- function ensureCopyDelegation(): void {
711
- if (copyDelegationReady) return;
712
- copyDelegationReady = true;
713
- document.addEventListener('click', (e: MouseEvent) => {
714
- const target = e.target as HTMLElement;
715
- // New structure: .code-copy-btn inside .code-block
716
- const copyBtn = target?.closest('.code-copy-btn') as HTMLElement | null;
717
- if (copyBtn) {
718
- const block = copyBtn.closest('.code-block');
719
- if (!block) return;
720
- const codeEl = block.querySelector('pre code');
721
- if (!codeEl) return;
722
- navigator.clipboard.writeText(codeEl.textContent || '').then(() => {
723
- const orig = copyBtn.textContent || '';
724
- copyBtn.textContent = t('code.copied');
725
- copyBtn.classList.add('copied');
726
- setTimeout(() => {
727
- copyBtn.textContent = orig;
728
- copyBtn.classList.remove('copied');
729
- }, 1500);
730
- }).catch(() => { /* clipboard API fail silently */ });
731
- return;
732
- }
733
- // Legacy structure: .code-lang-label inside .code-block-wrapper
734
- const label = target?.closest('.code-lang-label') as HTMLElement | null;
735
- if (!label) return;
736
- const wrapper = label.closest('.code-block-wrapper');
737
- if (!wrapper) return;
738
- const codeEl = wrapper.querySelector('pre code');
739
- if (!codeEl) return;
740
- navigator.clipboard.writeText(codeEl.textContent || '').then(() => {
741
- const orig = label.textContent || '';
742
- label.textContent = t('code.copied');
743
- label.classList.add('copied');
744
- setTimeout(() => {
745
- label.textContent = orig;
746
- label.classList.remove('copied');
747
- }, 1500);
748
- }).catch(() => { /* clipboard API fail silently */ });
749
- });
750
- }
751
-
752
- // ── Diagram action button event delegation (copy + save) ──
753
- let diagramActionsReady = false;
754
-
755
- function ensureDiagramActionDelegation(): void {
756
- if (diagramActionsReady) return;
757
- diagramActionsReady = true;
758
-
759
- document.addEventListener('click', (e: MouseEvent) => {
760
- const target = e.target as HTMLElement;
761
-
762
- // ── Copy buttons ──
763
- const diagCopyBtn = target?.closest('.diagram-copy-btn') as HTMLElement | null;
764
- if (diagCopyBtn) {
765
- const container = diagCopyBtn.closest('.diagram-container') as HTMLElement | null;
766
- if (!container) return;
767
- let text = '';
768
- if (container.dataset['widgetHtml']) {
769
- try { text = decodeURIComponent(escape(atob(container.dataset['widgetHtml']))); }
770
- catch { return; }
771
- } else {
772
- const svgEl = container.querySelector('svg');
773
- if (svgEl) text = svgEl.outerHTML;
774
- }
775
- if (text) btnFeedback(diagCopyBtn, text, 'copy');
776
- return;
777
- }
778
-
779
- const mermaidCopyBtn = target?.closest('.mermaid-copy-btn') as HTMLElement | null;
780
- if (mermaidCopyBtn) {
781
- const container = mermaidCopyBtn.closest('.mermaid-container') as HTMLElement | null;
782
- if (!container) return;
783
- const code = container.dataset['mermaidCode'] || '';
784
- if (code) btnFeedback(mermaidCopyBtn, code, 'copy');
785
- return;
786
- }
787
-
788
- // ── Save buttons ──
789
- const diagSaveBtn = target?.closest('.diagram-save-btn') as HTMLElement | null;
790
- if (diagSaveBtn) {
791
- const container = diagSaveBtn.closest('.diagram-container') as HTMLElement | null;
792
- if (!container) return;
793
- // Widget: request screenshot via bridge
794
- if (container.dataset['widgetHtml']) {
795
- const iframe = container.querySelector('iframe') as HTMLIFrameElement | null;
796
- if (iframe?.contentWindow) {
797
- iframe.contentWindow.postMessage({ type: 'jaw-request-screenshot' }, '*');
798
- btnFeedback(diagSaveBtn, '', 'save');
799
- }
800
- return;
801
- }
802
- // SVG: convert to PNG
803
- const svgEl = container.querySelector('svg');
804
- if (svgEl) saveSvgAsPng(svgEl, diagSaveBtn);
805
- return;
806
- }
807
-
808
- const mermaidSaveBtn = target?.closest('.mermaid-save-btn') as HTMLElement | null;
809
- if (mermaidSaveBtn) {
810
- const container = mermaidSaveBtn.closest('.mermaid-container') as HTMLElement | null;
811
- if (!container) return;
812
- const svgEl = container.querySelector('svg');
813
- if (svgEl) saveSvgAsPng(svgEl, mermaidSaveBtn);
814
- return;
815
- }
816
- });
817
- }
818
-
819
- function btnFeedback(btn: HTMLElement, text: string, action: 'copy' | 'save'): void {
820
- const doFeedback = () => {
821
- const orig = btn.innerHTML;
822
- btn.innerHTML = ICONS.checkSimple;
823
- btn.classList.add('copied');
824
- setTimeout(() => { btn.innerHTML = orig; btn.classList.remove('copied'); }, 1500);
825
- };
826
- if (action === 'copy') {
827
- navigator.clipboard.writeText(text).then(doFeedback).catch(() => {});
828
- } else {
829
- doFeedback();
830
- }
831
- }
832
-
833
- function inlineComputedStyles(original: Element, clone: Element): void {
834
- const origChildren = original.children;
835
- const cloneChildren = clone.children;
836
- const props = ['fill', 'stroke', 'stroke-width', 'color', 'opacity',
837
- 'rx', 'ry', 'font-size', 'font-weight', 'font-family',
838
- 'text-anchor', 'dominant-baseline'];
839
- for (let i = 0; i < origChildren.length; i++) {
840
- const oc = origChildren[i];
841
- const cc = cloneChildren[i];
842
- if (!oc || !cc) continue;
843
- const cs = getComputedStyle(oc);
844
- for (const p of props) {
845
- const v = cs.getPropertyValue(p);
846
- if (v) (cc as HTMLElement).style.setProperty(p, v);
847
- }
848
- if (oc.children.length) inlineComputedStyles(oc, cc);
849
- }
850
- }
851
-
852
- function saveSvgAsPng(svgEl: SVGElement, btn: HTMLElement): void {
853
- const clone = svgEl.cloneNode(true) as SVGElement;
854
- inlineComputedStyles(svgEl, clone);
855
- const bbox = svgEl.getBoundingClientRect();
856
- if (!clone.getAttribute('width')) clone.setAttribute('width', String(bbox.width));
857
- if (!clone.getAttribute('height')) clone.setAttribute('height', String(bbox.height));
858
-
859
- const svgData = new XMLSerializer().serializeToString(clone);
860
- const dataUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgData);
861
- const img = new Image();
862
- img.onload = () => {
863
- const scale = 2; // retina
864
- const canvas = document.createElement('canvas');
865
- canvas.width = img.naturalWidth * scale;
866
- canvas.height = img.naturalHeight * scale;
867
- const ctx = canvas.getContext('2d')!;
868
- ctx.scale(scale, scale);
869
- ctx.drawImage(img, 0, 0);
870
- canvas.toBlob(blob => {
871
- if (!blob) return;
872
- downloadBlob(blob, `diagram-${Date.now()}.png`);
873
- btnFeedback(btn, '', 'save');
874
- }, 'image/png');
875
- };
876
- img.onerror = () => {
877
- const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
878
- downloadBlob(svgBlob, `diagram-${Date.now()}.svg`);
879
- btnFeedback(btn, '', 'save');
880
- };
881
- img.src = dataUrl;
882
- }
883
-
884
- function downloadBlob(blob: Blob, filename: string): void {
885
- const url = URL.createObjectURL(blob);
886
- const a = document.createElement('a');
887
- a.href = url;
888
- a.download = filename;
889
- a.click();
890
- setTimeout(() => URL.revokeObjectURL(url), 1000);
891
- }
892
-
893
- // ── SVG Block Rendering (Phase 1) ──
894
-
895
- function renderSvgBlock(block: SvgBlock): string {
896
- if (block.kind === 'partial') {
897
- return `<div class="diagram-container diagram-loading" role="status"
898
- aria-label="Diagram loading"><div class="diagram-spinner"></div></div>`;
899
- }
900
- if (block.kind === 'error') {
901
- return `<div class="diagram-container diagram-error" role="alert">
902
- Malformed SVG: unclosed element</div>`;
903
- }
904
- // Complete SVG — sanitize individually (extracted SVGs bypass main pipeline)
905
- const sanitized = sanitizeHtml(block.svg);
906
- return `<div class="diagram-container diagram-svg" tabindex="0"
907
- role="figure" aria-label="SVG diagram">
908
- ${sanitized}
909
- <button class="diagram-save-btn" type="button"
910
- aria-label="Save as image" title="Save">${ICONS.download}</button>
911
- <button class="diagram-copy-btn" type="button"
912
- aria-label="Copy source" title="Copy">${ICONS.copy}</button>
913
- <button class="diagram-zoom-btn" type="button"
914
- aria-label="Expand diagram" title="Expand">⤢</button>
915
- </div>`;
916
- }
917
-
918
- function unshieldSvgBlocks(html: string, blocks: SvgBlock[]): string {
919
- for (const block of blocks) {
920
- const pattern = `<div\\b[^>]*?\\bdata-jaw-svg="${block.id}"[^>]*></div>`;
921
- const re = new RegExp(pattern, 'g');
922
- const rendered = renderSvgBlock(block);
923
- // Use function replacement to avoid $& $' $` special patterns in SVG content
924
- html = html.replace(re, () => rendered);
925
- }
926
- return html;
927
- }
928
-
929
- // ── Diagram Zoom Overlay ──
930
-
931
- export function bindDiagramZoom(scope?: HTMLElement | Document): void {
932
- const root = scope || document;
933
- root.querySelectorAll('.diagram-zoom-btn, .mermaid-zoom-btn').forEach(btn => {
934
- if ((btn as HTMLElement).dataset['bound']) return;
935
- (btn as HTMLElement).dataset['bound'] = '1';
936
- btn.addEventListener('click', () => {
937
- if (btn.closest('.diagram-widget')) return;
938
- const container = btn.closest('.diagram-container, .mermaid-container');
939
- if (!container) return;
940
- const clone = container.cloneNode(true) as HTMLElement;
941
- clone.querySelectorAll('.diagram-zoom-btn, .mermaid-zoom-btn, .diagram-copy-btn, .diagram-save-btn, .mermaid-copy-btn, .mermaid-save-btn')
942
- .forEach(b => b.remove());
943
- openDiagramOverlay(clone.innerHTML);
944
- });
945
- });
946
- }
947
-
948
- export function openDiagramOverlay(innerHtml: string): void {
949
- const previousFocus = document.activeElement as HTMLElement | null;
950
- const overlay = document.createElement('div');
951
- overlay.className = 'diagram-overlay';
952
- overlay.setAttribute('role', 'dialog');
953
- overlay.setAttribute('aria-modal', 'true');
954
- overlay.setAttribute('aria-label', 'Expanded diagram');
955
- // Re-sanitize to prevent mXSS from double HTML parsing
956
- const safeHtml = sanitizeHtml(innerHtml);
957
- overlay.innerHTML = `
958
- <div class="diagram-overlay-content">${safeHtml}</div>
959
- <button class="diagram-overlay-close" type="button" aria-label="Close">✕</button>
960
- `;
961
-
962
- // Ensure SVGs scale inside overlay: add viewBox if missing, remove fixed dimensions
963
- overlay.querySelectorAll<SVGSVGElement>('.diagram-overlay-content svg').forEach(svg => {
964
- if (!svg.getAttribute('viewBox')) {
965
- const w = svg.getAttribute('width') || svg.getBBox?.()?.width;
966
- const h = svg.getAttribute('height') || svg.getBBox?.()?.height;
967
- if (w && h) svg.setAttribute('viewBox', `0 0 ${parseFloat(String(w))} ${parseFloat(String(h))}`);
968
- }
969
- svg.removeAttribute('width');
970
- svg.removeAttribute('height');
971
- });
972
-
973
- const closeBtn = overlay.querySelector('.diagram-overlay-close') as HTMLElement;
974
-
975
- const close = () => {
976
- overlay.remove();
977
- document.removeEventListener('keydown', onKey);
978
- // Restore focus to the element that opened the overlay
979
- if (previousFocus && previousFocus.isConnected) previousFocus.focus();
980
- };
981
- const onKey = (e: KeyboardEvent) => {
982
- if (e.key === 'Escape') { close(); return; }
983
- // Focus trap: Tab cycles within overlay
984
- if (e.key === 'Tab') {
985
- const focusable = overlay.querySelectorAll<HTMLElement>(
986
- 'button, [href], [tabindex]:not([tabindex="-1"])');
987
- if (focusable.length === 0) return;
988
- const first = focusable[0];
989
- const last = focusable[focusable.length - 1];
990
- if (e.shiftKey && document.activeElement === first) {
991
- e.preventDefault(); last.focus();
992
- } else if (!e.shiftKey && document.activeElement === last) {
993
- e.preventDefault(); first.focus();
994
- }
995
- }
996
- };
997
-
998
- closeBtn.addEventListener('click', close);
999
- document.addEventListener('keydown', onKey);
1000
- document.body.appendChild(overlay);
1001
- closeBtn.focus();
1002
- }
1003
-
1004
- // ── Main export ──
1005
- export function renderMarkdown(text: string, isStreaming = false): string {
1006
- const rawCleaned = stripOrchestration(text);
1007
- if (!rawCleaned) return `<em class="text-dim orchestrate-placeholder">${escapeHtml(t('orchestrator.dispatching'))}</em>`;
1008
- // Collapse 3+ consecutive newlines → double newline (prevents excessive paragraph breaks)
1009
- const cleaned = rawCleaned.replace(/\n{3,}/g, '\n\n');
1010
-
1011
- // 1. Shield code fences (protect SVG in code blocks)
1012
- const { text: fenceShielded, fences } = shieldCodeFenceSvg(cleaned);
1013
-
1014
- // 2. Extract top-level SVGs
1015
- const { text: svgShielded, blocks: svgBlocks } = extractTopLevelSvg(fenceShielded, isStreaming);
1016
-
1017
- // 3. Unshield code fences (restore for marked processing)
1018
- const restored = unshieldCodeFenceSvg(svgShielded, fences);
1019
-
1020
- // 4. Shield math
1021
- const { text: shielded, blocks: mathBlocks } = shieldMath(restored);
1022
-
1023
- // 5. Marked parse
1024
- ensureMarked();
1025
- const fixed = fixCjkPunctuationBoundary(shielded);
1026
- let html = marked.parse(fixed) as string;
1027
- html = html.replace(/<table/g, '<div class="table-wrapper"><table').replace(/<\/table>/g, '</table></div>');
1028
-
1029
- // 6. Unshield math
1030
- html = unshieldMath(html, mathBlocks, isStreaming);
1031
-
1032
- // 7. Sanitize
1033
- html = sanitizeHtml(html);
1034
-
1035
- // 8. Unshield SVGs (after sanitize — SVGs sanitized individually in renderSvgBlock)
1036
- html = unshieldSvgBlocks(html, svgBlocks);
1037
-
1038
- // 9. Post-render async tasks — skip during streaming (deferred to finalize)
1039
- if (!isStreaming) {
1040
- schedulePostRender();
1041
- }
1042
-
1043
- ensureCopyDelegation();
1044
- ensureDiagramActionDelegation();
1045
- ensureFilePathDelegation();
1046
-
1047
- return html;
1048
- }
1049
-
1050
- // ── Batched post-render scheduler ──
1051
- // Coalesces multiple renderMarkdown() calls into a single post-render pass.
1052
- let postRenderRAF: number | null = null;
1053
- let postRenderTimer: ReturnType<typeof setTimeout> | null = null;
1054
-
1055
- function schedulePostRender(): void {
1056
- // Debounce: coalesce rapid VS render triggers into a single pass
1057
- if (postRenderTimer) clearTimeout(postRenderTimer);
1058
- if (postRenderRAF) { cancelAnimationFrame(postRenderRAF); postRenderRAF = null; }
1059
- postRenderTimer = setTimeout(() => {
1060
- postRenderTimer = null;
1061
- postRenderRAF = requestAnimationFrame(() => {
1062
- postRenderRAF = null;
1063
- renderMermaidBlocks();
1064
- rehighlightAll();
1065
- bindDiagramZoom();
1066
- const msgContainer = document.getElementById('chatMessages');
1067
- if (msgContainer) linkifyFilePaths(msgContainer);
1068
- });
1069
- }, 100);
1070
- }
1071
-
1072
- export function cancelPostRender(): void {
1073
- if (postRenderTimer) {
1074
- clearTimeout(postRenderTimer);
1075
- postRenderTimer = null;
1076
- }
1077
- if (postRenderRAF) {
1078
- cancelAnimationFrame(postRenderRAF);
1079
- postRenderRAF = null;
1080
- }
1081
- }
1
+ // ── Render Helpers Facade ──
2
+ // Public API is kept stable while implementation lives in focused modules.
3
+
4
+ export { renderMarkdown } from './render/markdown.js';
5
+ export { escapeHtml, stripOrchestration, stripPromptLeakage } from './render/html.js';
6
+ export { sanitizeHtml } from './render/sanitize.js';
7
+ export { shieldMath, unshieldMath } from './render/math.js';
8
+ export { rehighlightAll } from './render/highlight.js';
9
+ export { linkifyFilePaths } from './render/file-links.js';
10
+ export { bindDiagramZoom, openDiagramOverlay } from './render/svg-actions.js';
11
+ export {
12
+ renderMermaidBlocks,
13
+ releaseMermaidNodes,
14
+ rerenderMermaidDiagrams,
15
+ prewarmMermaid,
16
+ } from './render/mermaid.js';
17
+ export { cancelPostRender } from './render/post-render.js';