pygpt-net 2.6.40__py3-none-any.whl → 2.6.41__py3-none-any.whl

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 (2182) hide show
  1. pygpt_net/CHANGELOG.txt +4 -0
  2. pygpt_net/__init__.py +3 -3
  3. pygpt_net/app.py +6 -1
  4. pygpt_net/controller/access/access.py +0 -0
  5. pygpt_net/controller/agent/__init__.py +0 -0
  6. pygpt_net/controller/agent/agent.py +0 -0
  7. pygpt_net/controller/agent/common.py +0 -0
  8. pygpt_net/controller/agent/experts.py +0 -0
  9. pygpt_net/controller/agent/legacy.py +0 -0
  10. pygpt_net/controller/agent/llama.py +0 -0
  11. pygpt_net/controller/assistant/__init__.py +0 -0
  12. pygpt_net/controller/assistant/assistant.py +0 -0
  13. pygpt_net/controller/assistant/batch.py +0 -0
  14. pygpt_net/controller/assistant/files.py +0 -0
  15. pygpt_net/controller/assistant/threads.py +0 -0
  16. pygpt_net/controller/attachment/__init__.py +0 -0
  17. pygpt_net/controller/attachment/attachment.py +0 -0
  18. pygpt_net/controller/audio/__init__.py +0 -0
  19. pygpt_net/controller/audio/audio.py +0 -0
  20. pygpt_net/controller/audio/ui.py +0 -0
  21. pygpt_net/controller/calendar/__init__.py +0 -0
  22. pygpt_net/controller/calendar/calendar.py +0 -0
  23. pygpt_net/controller/calendar/note.py +0 -0
  24. pygpt_net/controller/camera/__init__.py +0 -0
  25. pygpt_net/controller/camera/camera.py +0 -0
  26. pygpt_net/controller/chat/audio.py +0 -0
  27. pygpt_net/controller/chat/chat.py +0 -0
  28. pygpt_net/controller/chat/command.py +0 -0
  29. pygpt_net/controller/chat/common.py +0 -0
  30. pygpt_net/controller/chat/files.py +0 -0
  31. pygpt_net/controller/chat/handler/__init__.py +0 -0
  32. pygpt_net/controller/chat/handler/anthropic_stream.py +0 -0
  33. pygpt_net/controller/chat/handler/google_stream.py +0 -0
  34. pygpt_net/controller/chat/handler/langchain_stream.py +0 -0
  35. pygpt_net/controller/chat/handler/llamaindex_stream.py +0 -0
  36. pygpt_net/controller/chat/handler/openai_stream.py +0 -0
  37. pygpt_net/controller/chat/handler/utils.py +0 -0
  38. pygpt_net/controller/chat/handler/worker.py +13 -17
  39. pygpt_net/controller/chat/handler/xai_stream.py +0 -0
  40. pygpt_net/controller/chat/image.py +7 -1
  41. pygpt_net/controller/chat/render.py +25 -8
  42. pygpt_net/controller/chat/response.py +3 -4
  43. pygpt_net/controller/chat/stream.py +40 -7
  44. pygpt_net/controller/chat/text.py +0 -0
  45. pygpt_net/controller/chat/vision.py +0 -0
  46. pygpt_net/controller/command/__init__.py +0 -0
  47. pygpt_net/controller/command/command.py +0 -0
  48. pygpt_net/controller/config/__init__.py +0 -0
  49. pygpt_net/controller/config/config.py +0 -0
  50. pygpt_net/controller/config/field/__init__.py +0 -0
  51. pygpt_net/controller/config/field/checkbox_list.py +0 -0
  52. pygpt_net/controller/config/field/cmd.py +0 -0
  53. pygpt_net/controller/config/field/combo.py +0 -0
  54. pygpt_net/controller/config/field/dictionary.py +0 -0
  55. pygpt_net/controller/config/field/input.py +0 -0
  56. pygpt_net/controller/config/field/slider.py +0 -0
  57. pygpt_net/controller/config/field/textarea.py +0 -0
  58. pygpt_net/controller/config/placeholder.py +0 -0
  59. pygpt_net/controller/ctx/common.py +0 -0
  60. pygpt_net/controller/ctx/summarizer.py +0 -0
  61. pygpt_net/controller/debug/__init__.py +0 -0
  62. pygpt_net/controller/debug/debug.py +19 -0
  63. pygpt_net/controller/dialogs/__init__.py +0 -0
  64. pygpt_net/controller/dialogs/debug.py +0 -0
  65. pygpt_net/controller/dialogs/dialogs.py +0 -0
  66. pygpt_net/controller/files/__init__.py +0 -0
  67. pygpt_net/controller/files/files.py +0 -0
  68. pygpt_net/controller/finder/__init__.py +0 -0
  69. pygpt_net/controller/finder/finder.py +0 -0
  70. pygpt_net/controller/idx/common.py +0 -0
  71. pygpt_net/controller/idx/idx.py +0 -0
  72. pygpt_net/controller/idx/settings.py +0 -0
  73. pygpt_net/controller/kernel/kernel.py +0 -0
  74. pygpt_net/controller/kernel/stack.py +0 -0
  75. pygpt_net/controller/lang/__init__.py +0 -0
  76. pygpt_net/controller/lang/custom.py +0 -0
  77. pygpt_net/controller/lang/lang.py +0 -0
  78. pygpt_net/controller/lang/mapping.py +0 -0
  79. pygpt_net/controller/lang/plugins.py +0 -0
  80. pygpt_net/controller/lang/settings.py +0 -0
  81. pygpt_net/controller/launcher/__init__.py +0 -0
  82. pygpt_net/controller/launcher/launcher.py +0 -0
  83. pygpt_net/controller/layout/__init__.py +0 -0
  84. pygpt_net/controller/layout/layout.py +0 -0
  85. pygpt_net/controller/media/__init__.py +0 -0
  86. pygpt_net/controller/media/media.py +0 -0
  87. pygpt_net/controller/mode/__init__.py +0 -0
  88. pygpt_net/controller/mode/mode.py +0 -0
  89. pygpt_net/controller/model/__init__.py +0 -0
  90. pygpt_net/controller/notepad/__init__.py +0 -0
  91. pygpt_net/controller/painter/__init__.py +0 -0
  92. pygpt_net/controller/painter/common.py +0 -0
  93. pygpt_net/controller/painter/painter.py +0 -0
  94. pygpt_net/controller/plugins/presets.py +0 -0
  95. pygpt_net/controller/presets/experts.py +0 -0
  96. pygpt_net/controller/presets/presets.py +0 -0
  97. pygpt_net/controller/realtime/__init__.py +0 -0
  98. pygpt_net/controller/realtime/manager.py +0 -0
  99. pygpt_net/controller/realtime/realtime.py +0 -0
  100. pygpt_net/controller/settings/__init__.py +0 -0
  101. pygpt_net/controller/settings/profile.py +0 -0
  102. pygpt_net/controller/settings/settings.py +0 -0
  103. pygpt_net/controller/theme/menu.py +0 -0
  104. pygpt_net/controller/theme/nodes.py +0 -0
  105. pygpt_net/controller/theme/theme.py +0 -0
  106. pygpt_net/controller/tools/__init__.py +0 -0
  107. pygpt_net/controller/tools/tools.py +0 -0
  108. pygpt_net/controller/ui/__init__.py +0 -0
  109. pygpt_net/controller/ui/mode.py +0 -0
  110. pygpt_net/controller/ui/tabs.py +0 -0
  111. pygpt_net/controller/ui/ui.py +0 -0
  112. pygpt_net/controller/ui/vision.py +0 -0
  113. pygpt_net/core/__init__.py +0 -0
  114. pygpt_net/core/access/access.py +0 -0
  115. pygpt_net/core/access/helpers.py +0 -0
  116. pygpt_net/core/agents/__init__.py +0 -0
  117. pygpt_net/core/agents/agents.py +0 -0
  118. pygpt_net/core/agents/bridge.py +0 -0
  119. pygpt_net/core/agents/legacy.py +0 -0
  120. pygpt_net/core/agents/observer/__init__.py +0 -0
  121. pygpt_net/core/agents/provider.py +0 -0
  122. pygpt_net/core/agents/runners/__init__.py +0 -0
  123. pygpt_net/core/agents/runners/base.py +0 -0
  124. pygpt_net/core/agents/runners/helpers.py +0 -0
  125. pygpt_net/core/agents/runners/llama_assistant.py +0 -0
  126. pygpt_net/core/agents/runners/llama_plan.py +0 -0
  127. pygpt_net/core/agents/runners/llama_steps.py +0 -0
  128. pygpt_net/core/agents/runners/llama_workflow.py +0 -0
  129. pygpt_net/core/agents/runners/loop.py +0 -0
  130. pygpt_net/core/agents/runners/openai_workflow.py +0 -0
  131. pygpt_net/core/agents/tools.py +0 -0
  132. pygpt_net/core/assistants/__init__.py +0 -0
  133. pygpt_net/core/assistants/assistants.py +0 -0
  134. pygpt_net/core/assistants/files.py +0 -0
  135. pygpt_net/core/assistants/store.py +0 -0
  136. pygpt_net/core/attachments/__init__.py +0 -0
  137. pygpt_net/core/attachments/attachments.py +0 -0
  138. pygpt_net/core/attachments/worker.py +0 -0
  139. pygpt_net/core/audio/audio.py +0 -0
  140. pygpt_net/core/audio/backend/__init__.py +0 -0
  141. pygpt_net/core/audio/backend/native/__init__.py +0 -0
  142. pygpt_net/core/audio/backend/native/player.py +0 -0
  143. pygpt_net/core/audio/backend/native/realtime.py +0 -0
  144. pygpt_net/core/audio/backend/pyaudio/__init__.py +0 -0
  145. pygpt_net/core/audio/backend/pyaudio/playback.py +0 -0
  146. pygpt_net/core/audio/backend/pyaudio/pyaudio.py +0 -0
  147. pygpt_net/core/audio/backend/pyaudio/realtime.py +0 -0
  148. pygpt_net/core/audio/backend/pygame/__init__.py +0 -0
  149. pygpt_net/core/audio/backend/pygame/pygame.py +0 -0
  150. pygpt_net/core/audio/backend/shared/__init__.py +0 -0
  151. pygpt_net/core/audio/backend/shared/conversions.py +0 -0
  152. pygpt_net/core/audio/backend/shared/envelope.py +0 -0
  153. pygpt_net/core/audio/backend/shared/player.py +0 -0
  154. pygpt_net/core/audio/backend/shared/rt.py +0 -0
  155. pygpt_net/core/audio/context.py +0 -0
  156. pygpt_net/core/audio/output.py +0 -0
  157. pygpt_net/core/audio/whisper.py +0 -0
  158. pygpt_net/core/bridge/bridge.py +0 -0
  159. pygpt_net/core/bridge/worker.py +0 -0
  160. pygpt_net/core/calendar/__init__.py +0 -0
  161. pygpt_net/core/calendar/calendar.py +0 -0
  162. pygpt_net/core/camera/__init__.py +0 -0
  163. pygpt_net/core/camera/camera.py +0 -0
  164. pygpt_net/core/camera/worker.py +0 -0
  165. pygpt_net/core/chain/__init__.py +0 -0
  166. pygpt_net/core/chain/chain.py +0 -0
  167. pygpt_net/core/chain/chat.py +0 -0
  168. pygpt_net/core/chain/completion.py +0 -0
  169. pygpt_net/core/command/command.py +0 -0
  170. pygpt_net/core/ctx/bag.py +0 -0
  171. pygpt_net/core/ctx/container.py +0 -0
  172. pygpt_net/core/ctx/ctx.py +0 -0
  173. pygpt_net/core/ctx/idx.py +0 -0
  174. pygpt_net/core/ctx/output.py +0 -0
  175. pygpt_net/core/ctx/reply.py +0 -0
  176. pygpt_net/core/db/__init__.py +0 -0
  177. pygpt_net/core/db/database.py +0 -0
  178. pygpt_net/core/db/viewer.py +0 -0
  179. pygpt_net/core/debug/agent.py +0 -0
  180. pygpt_net/core/debug/console/__init__.py +0 -0
  181. pygpt_net/core/debug/console/console.py +8 -0
  182. pygpt_net/core/debug/db.py +0 -0
  183. pygpt_net/core/debug/debug.py +0 -0
  184. pygpt_net/core/debug/events.py +0 -0
  185. pygpt_net/core/debug/indexes.py +0 -0
  186. pygpt_net/core/debug/kernel.py +0 -0
  187. pygpt_net/core/debug/tabs.py +0 -0
  188. pygpt_net/core/dispatcher/__init__.py +0 -0
  189. pygpt_net/core/dispatcher/dispatcher.py +0 -0
  190. pygpt_net/core/docker/__init__.py +0 -0
  191. pygpt_net/core/docker/builder.py +0 -0
  192. pygpt_net/core/docker/docker.py +0 -0
  193. pygpt_net/core/events/__init__.py +0 -0
  194. pygpt_net/core/events/app.py +0 -0
  195. pygpt_net/core/events/base.py +0 -0
  196. pygpt_net/core/events/control.py +0 -0
  197. pygpt_net/core/events/event.py +0 -0
  198. pygpt_net/core/events/kernel.py +0 -0
  199. pygpt_net/core/events/realtime.py +0 -0
  200. pygpt_net/core/experts/__init__.py +0 -0
  201. pygpt_net/core/experts/worker.py +0 -0
  202. pygpt_net/core/filesystem/actions.py +0 -0
  203. pygpt_net/core/filesystem/editor.py +0 -0
  204. pygpt_net/core/filesystem/filesystem.py +2 -2
  205. pygpt_net/core/filesystem/opener.py +0 -0
  206. pygpt_net/core/filesystem/packer.py +0 -0
  207. pygpt_net/core/filesystem/parser.py +0 -0
  208. pygpt_net/core/filesystem/types.py +0 -0
  209. pygpt_net/core/filesystem/url.py +0 -0
  210. pygpt_net/core/history/__init__.py +0 -0
  211. pygpt_net/core/history/history.py +0 -0
  212. pygpt_net/core/idx/context.py +0 -0
  213. pygpt_net/core/idx/idx.py +0 -0
  214. pygpt_net/core/idx/metadata.py +0 -0
  215. pygpt_net/core/idx/response.py +0 -0
  216. pygpt_net/core/idx/types/__init__.py +0 -0
  217. pygpt_net/core/idx/types/ctx.py +0 -0
  218. pygpt_net/core/idx/types/external.py +0 -0
  219. pygpt_net/core/idx/types/files.py +0 -0
  220. pygpt_net/core/idx/ui/__init__.py +0 -0
  221. pygpt_net/core/idx/ui/loaders.py +0 -0
  222. pygpt_net/core/image/__init__.py +0 -0
  223. pygpt_net/core/image/image.py +0 -0
  224. pygpt_net/core/info/__init__.py +0 -0
  225. pygpt_net/core/info/info.py +0 -0
  226. pygpt_net/core/installer/__init__.py +0 -0
  227. pygpt_net/core/installer/installer.py +0 -0
  228. pygpt_net/core/llm/__init__.py +0 -0
  229. pygpt_net/core/llm/llm.py +0 -0
  230. pygpt_net/core/locale/__init__.py +0 -0
  231. pygpt_net/core/locale/locale.py +0 -0
  232. pygpt_net/core/models/__init__.py +0 -0
  233. pygpt_net/core/models/models.py +0 -0
  234. pygpt_net/core/models/ollama.py +0 -0
  235. pygpt_net/core/modes/__init__.py +0 -0
  236. pygpt_net/core/modes/modes.py +0 -0
  237. pygpt_net/core/notepad/__init__.py +0 -0
  238. pygpt_net/core/notepad/notepad.py +0 -0
  239. pygpt_net/core/platforms/__init__.py +0 -0
  240. pygpt_net/core/platforms/platforms.py +0 -0
  241. pygpt_net/core/plugins/__init__.py +0 -0
  242. pygpt_net/core/plugins/plugins.py +0 -0
  243. pygpt_net/core/presets/__init__.py +0 -0
  244. pygpt_net/core/profile/__init__.py +0 -0
  245. pygpt_net/core/profile/profile.py +0 -0
  246. pygpt_net/core/prompt/__init__.py +0 -0
  247. pygpt_net/core/prompt/base/__init__.py +0 -0
  248. pygpt_net/core/prompt/base/gpt.py +0 -0
  249. pygpt_net/core/prompt/custom.py +0 -0
  250. pygpt_net/core/prompt/prompt.py +0 -0
  251. pygpt_net/core/prompt/template.py +0 -0
  252. pygpt_net/core/realtime/__init__.py +0 -0
  253. pygpt_net/core/realtime/options.py +0 -0
  254. pygpt_net/core/realtime/shared/__init__.py +0 -0
  255. pygpt_net/core/realtime/shared/audio.py +0 -0
  256. pygpt_net/core/realtime/shared/loop.py +0 -0
  257. pygpt_net/core/realtime/shared/session.py +0 -0
  258. pygpt_net/core/realtime/shared/text.py +0 -0
  259. pygpt_net/core/realtime/shared/tools.py +0 -0
  260. pygpt_net/core/realtime/shared/turn.py +0 -0
  261. pygpt_net/core/realtime/shared/types.py +0 -0
  262. pygpt_net/core/realtime/worker.py +0 -0
  263. pygpt_net/core/render/__init__.py +0 -0
  264. pygpt_net/core/render/base.py +5 -1
  265. pygpt_net/core/render/markdown/body.py +0 -0
  266. pygpt_net/core/render/markdown/helpers.py +0 -0
  267. pygpt_net/core/render/markdown/pid.py +0 -0
  268. pygpt_net/core/render/plain/__init__.py +0 -0
  269. pygpt_net/core/render/plain/body.py +0 -0
  270. pygpt_net/core/render/plain/helpers.py +0 -0
  271. pygpt_net/core/render/plain/pid.py +0 -0
  272. pygpt_net/core/render/plain/renderer.py +17 -4
  273. pygpt_net/core/render/web/body.py +78 -1161
  274. pygpt_net/core/render/web/debug.py +217 -0
  275. pygpt_net/core/render/web/helpers.py +44 -12
  276. pygpt_net/core/render/web/pid.py +4 -1
  277. pygpt_net/core/render/web/renderer.py +600 -343
  278. pygpt_net/core/render/web/syntax_highlight.py +0 -0
  279. pygpt_net/core/settings/__init__.py +0 -0
  280. pygpt_net/core/settings/settings.py +0 -0
  281. pygpt_net/core/tabs/tab.py +0 -0
  282. pygpt_net/core/tabs/tabs.py +0 -0
  283. pygpt_net/core/text/__init__.py +0 -0
  284. pygpt_net/core/text/text.py +0 -0
  285. pygpt_net/core/text/utils.py +2 -1
  286. pygpt_net/core/text/web_finder.py +0 -0
  287. pygpt_net/core/tokens/__init__.py +0 -0
  288. pygpt_net/core/tokens/tokens.py +0 -0
  289. pygpt_net/core/types/__init__.py +0 -0
  290. pygpt_net/core/types/agent.py +0 -0
  291. pygpt_net/core/types/base.py +0 -0
  292. pygpt_net/core/types/console.py +0 -0
  293. pygpt_net/core/types/image.py +0 -0
  294. pygpt_net/core/types/mode.py +0 -0
  295. pygpt_net/core/types/model.py +0 -0
  296. pygpt_net/core/types/multimodal.py +0 -0
  297. pygpt_net/core/types/tools.py +0 -0
  298. pygpt_net/core/updater/__init__.py +0 -0
  299. pygpt_net/core/video/__init__.py +0 -0
  300. pygpt_net/core/video/video.py +0 -0
  301. pygpt_net/core/vision/__init__.py +0 -0
  302. pygpt_net/core/vision/analyzer.py +0 -0
  303. pygpt_net/core/vision/vision.py +0 -0
  304. pygpt_net/core/web/__init__.py +0 -0
  305. pygpt_net/core/web/helpers.py +0 -0
  306. pygpt_net/core/web/web.py +0 -0
  307. pygpt_net/core/worker/__init__.py +0 -0
  308. pygpt_net/core/worker/worker.py +0 -0
  309. pygpt_net/css.qrc +1 -1
  310. pygpt_net/css_rc.py +0 -0
  311. pygpt_net/data/audio/click_off.mp3 +0 -0
  312. pygpt_net/data/audio/click_on.mp3 +0 -0
  313. pygpt_net/data/audio/ok.mp3 +0 -0
  314. pygpt_net/data/config/config.json +9 -8
  315. pygpt_net/data/config/models.json +3 -3
  316. pygpt_net/data/config/modes.json +0 -0
  317. pygpt_net/data/config/presets/agent_code_act.json +0 -0
  318. pygpt_net/data/config/presets/agent_openai.json +0 -0
  319. pygpt_net/data/config/presets/agent_openai_assistant.json +0 -0
  320. pygpt_net/data/config/presets/agent_openai_b2b.json +0 -0
  321. pygpt_net/data/config/presets/agent_openai_coder.json +0 -0
  322. pygpt_net/data/config/presets/agent_openai_evolve.json +0 -0
  323. pygpt_net/data/config/presets/agent_openai_expert.json +0 -0
  324. pygpt_net/data/config/presets/agent_openai_planner.json +0 -0
  325. pygpt_net/data/config/presets/agent_openai_researcher.json +0 -0
  326. pygpt_net/data/config/presets/agent_openai_simple.json +0 -0
  327. pygpt_net/data/config/presets/agent_openai_supervisor.json +0 -0
  328. pygpt_net/data/config/presets/agent_openai_writer.json +0 -0
  329. pygpt_net/data/config/presets/agent_planner.json +0 -0
  330. pygpt_net/data/config/presets/agent_react.json +0 -0
  331. pygpt_net/data/config/presets/agent_supervisor.json +0 -0
  332. pygpt_net/data/config/presets/current.agent.json +0 -0
  333. pygpt_net/data/config/presets/current.agent_llama.json +0 -0
  334. pygpt_net/data/config/presets/current.agent_openai.json +0 -0
  335. pygpt_net/data/config/presets/current.audio.json +0 -0
  336. pygpt_net/data/config/presets/current.computer.json +0 -0
  337. pygpt_net/data/config/presets/current.expert.json +0 -0
  338. pygpt_net/data/config/presets/current.llama_index.json +0 -0
  339. pygpt_net/data/config/presets/current.research.json +0 -0
  340. pygpt_net/data/config/presets/joke_agent.json +0 -0
  341. pygpt_net/data/config/presets/joke_expert.json +0 -0
  342. pygpt_net/data/config/settings.json +15 -3
  343. pygpt_net/data/config/settings_section.json +0 -0
  344. pygpt_net/data/css/web-blocks.css +34 -4
  345. pygpt_net/data/css/web-blocks.dark.css +3 -0
  346. pygpt_net/data/css/web-blocks.darkest.css +3 -0
  347. pygpt_net/data/css/web-chatgpt.css +34 -4
  348. pygpt_net/data/css/web-chatgpt.dark.css +3 -0
  349. pygpt_net/data/css/web-chatgpt.darkest.css +3 -0
  350. pygpt_net/data/css/web-chatgpt_wide.css +34 -4
  351. pygpt_net/data/css/web-chatgpt_wide.dark.css +3 -0
  352. pygpt_net/data/css/web-chatgpt_wide.darkest.css +3 -0
  353. pygpt_net/data/fonts/MonaspaceArgon/MonaspaceArgon-Bold.otf +0 -0
  354. pygpt_net/data/fonts/MonaspaceArgon/MonaspaceArgon-BoldItalic.otf +0 -0
  355. pygpt_net/data/fonts/MonaspaceArgon/MonaspaceArgon-Italic.otf +0 -0
  356. pygpt_net/data/fonts/MonaspaceArgon/MonaspaceArgon-Regular.otf +0 -0
  357. pygpt_net/data/fonts/MonaspaceKrypton/MonaspaceKrypton-Bold.otf +0 -0
  358. pygpt_net/data/fonts/MonaspaceKrypton/MonaspaceKrypton-BoldItalic.otf +0 -0
  359. pygpt_net/data/fonts/MonaspaceKrypton/MonaspaceKrypton-Italic.otf +0 -0
  360. pygpt_net/data/fonts/MonaspaceKrypton/MonaspaceKrypton-Regular.otf +0 -0
  361. pygpt_net/data/fonts/MonaspaceNeon/MonaspaceNeon-Bold.otf +0 -0
  362. pygpt_net/data/fonts/MonaspaceNeon/MonaspaceNeon-BoldItalic.otf +0 -0
  363. pygpt_net/data/fonts/MonaspaceNeon/MonaspaceNeon-Italic.otf +0 -0
  364. pygpt_net/data/fonts/MonaspaceNeon/MonaspaceNeon-Regular.otf +0 -0
  365. pygpt_net/data/fonts/MonaspaceRadon/MonaspaceRadon-Bold.otf +0 -0
  366. pygpt_net/data/fonts/MonaspaceRadon/MonaspaceRadon-BoldItalic.otf +0 -0
  367. pygpt_net/data/fonts/MonaspaceRadon/MonaspaceRadon-Italic.otf +0 -0
  368. pygpt_net/data/fonts/MonaspaceRadon/MonaspaceRadon-Regular.otf +0 -0
  369. pygpt_net/data/fonts/MonaspaceXenon/MonaspaceXenon-Bold.otf +0 -0
  370. pygpt_net/data/fonts/MonaspaceXenon/MonaspaceXenon-BoldItalic.otf +0 -0
  371. pygpt_net/data/fonts/MonaspaceXenon/MonaspaceXenon-Italic.otf +0 -0
  372. pygpt_net/data/fonts/MonaspaceXenon/MonaspaceXenon-Regular.otf +0 -0
  373. pygpt_net/data/icon_tray_busy.ico +0 -0
  374. pygpt_net/data/icon_tray_error.ico +0 -0
  375. pygpt_net/data/icon_tray_idle.ico +0 -0
  376. pygpt_net/data/icons/abc.svg +0 -0
  377. pygpt_net/data/icons/accessibility.svg +0 -0
  378. pygpt_net/data/icons/add.svg +0 -0
  379. pygpt_net/data/icons/add_circle.svg +0 -0
  380. pygpt_net/data/icons/add_folder.svg +0 -0
  381. pygpt_net/data/icons/add_library.svg +0 -0
  382. pygpt_net/data/icons/alarm.svg +0 -0
  383. pygpt_net/data/icons/apps.svg +0 -0
  384. pygpt_net/data/icons/asterisk.svg +0 -0
  385. pygpt_net/data/icons/attachment.svg +0 -0
  386. pygpt_net/data/icons/attachments.svg +0 -0
  387. pygpt_net/data/icons/back.svg +0 -0
  388. pygpt_net/data/icons/backspace.svg +0 -0
  389. pygpt_net/data/icons/block.svg +0 -0
  390. pygpt_net/data/icons/bookmark.svg +0 -0
  391. pygpt_net/data/icons/brush.svg +0 -0
  392. pygpt_net/data/icons/build.svg +0 -0
  393. pygpt_net/data/icons/calendar.svg +0 -0
  394. pygpt_net/data/icons/camera.svg +0 -0
  395. pygpt_net/data/icons/chat/audio.png +0 -0
  396. pygpt_net/data/icons/chat/collapse.png +0 -0
  397. pygpt_net/data/icons/chat/copy.png +0 -0
  398. pygpt_net/data/icons/chat/delete.png +0 -0
  399. pygpt_net/data/icons/chat/edit.png +0 -0
  400. pygpt_net/data/icons/chat/join.png +0 -0
  401. pygpt_net/data/icons/chat/preview.png +0 -0
  402. pygpt_net/data/icons/chat/reload.png +0 -0
  403. pygpt_net/data/icons/chat/run.png +0 -0
  404. pygpt_net/data/icons/chat.svg +0 -0
  405. pygpt_net/data/icons/check.svg +0 -0
  406. pygpt_net/data/icons/check_circle.svg +0 -0
  407. pygpt_net/data/icons/checklist.svg +0 -0
  408. pygpt_net/data/icons/circle.svg +0 -0
  409. pygpt_net/data/icons/clear.svg +0 -0
  410. pygpt_net/data/icons/clock.svg +0 -0
  411. pygpt_net/data/icons/close.svg +0 -0
  412. pygpt_net/data/icons/close_circle.svg +0 -0
  413. pygpt_net/data/icons/code.svg +0 -0
  414. pygpt_net/data/icons/collapse.svg +0 -0
  415. pygpt_net/data/icons/computer.svg +0 -0
  416. pygpt_net/data/icons/copy.svg +0 -0
  417. pygpt_net/data/icons/crop.svg +0 -0
  418. pygpt_net/data/icons/cut.svg +0 -0
  419. pygpt_net/data/icons/db.svg +0 -0
  420. pygpt_net/data/icons/delete.svg +0 -0
  421. pygpt_net/data/icons/done.svg +0 -0
  422. pygpt_net/data/icons/download.svg +0 -0
  423. pygpt_net/data/icons/draft.svg +0 -0
  424. pygpt_net/data/icons/drag.svg +0 -0
  425. pygpt_net/data/icons/edit.svg +0 -0
  426. pygpt_net/data/icons/emergency.svg +0 -0
  427. pygpt_net/data/icons/equalizer.svg +0 -0
  428. pygpt_net/data/icons/error.svg +0 -0
  429. pygpt_net/data/icons/event_available.svg +0 -0
  430. pygpt_net/data/icons/expand.svg +0 -0
  431. pygpt_net/data/icons/fast_forward.svg +0 -0
  432. pygpt_net/data/icons/fast_rewind.svg +0 -0
  433. pygpt_net/data/icons/favorite.svg +0 -0
  434. pygpt_net/data/icons/folder.svg +0 -0
  435. pygpt_net/data/icons/folder_filled.svg +0 -0
  436. pygpt_net/data/icons/forward.svg +0 -0
  437. pygpt_net/data/icons/full.svg +0 -0
  438. pygpt_net/data/icons/fullscreen.svg +0 -0
  439. pygpt_net/data/icons/grid.svg +0 -0
  440. pygpt_net/data/icons/hearing.svg +0 -0
  441. pygpt_net/data/icons/help.svg +0 -0
  442. pygpt_net/data/icons/history.svg +0 -0
  443. pygpt_net/data/icons/home.svg +0 -0
  444. pygpt_net/data/icons/home_filled.svg +0 -0
  445. pygpt_net/data/icons/image.svg +0 -0
  446. pygpt_net/data/icons/info.svg +0 -0
  447. pygpt_net/data/icons/input.svg +0 -0
  448. pygpt_net/data/icons/key.svg +0 -0
  449. pygpt_net/data/icons/keyboard.svg +0 -0
  450. pygpt_net/data/icons/language.svg +0 -0
  451. pygpt_net/data/icons/list.svg +0 -0
  452. pygpt_net/data/icons/lock.svg +0 -0
  453. pygpt_net/data/icons/logout.svg +0 -0
  454. pygpt_net/data/icons/map.svg +0 -0
  455. pygpt_net/data/icons/memory.svg +0 -0
  456. pygpt_net/data/icons/menu.svg +0 -0
  457. pygpt_net/data/icons/mic.svg +0 -0
  458. pygpt_net/data/icons/mic_off.svg +0 -0
  459. pygpt_net/data/icons/more_horizontal.svg +0 -0
  460. pygpt_net/data/icons/mute.svg +0 -0
  461. pygpt_net/data/icons/open_tab.svg +0 -0
  462. pygpt_net/data/icons/palette.svg +0 -0
  463. pygpt_net/data/icons/paste.svg +0 -0
  464. pygpt_net/data/icons/pause.svg +0 -0
  465. pygpt_net/data/icons/pause_circle.svg +0 -0
  466. pygpt_net/data/icons/photos.svg +0 -0
  467. pygpt_net/data/icons/pin.svg +0 -0
  468. pygpt_net/data/icons/play.svg +0 -0
  469. pygpt_net/data/icons/play_pause.svg +0 -0
  470. pygpt_net/data/icons/playlist_add.svg +0 -0
  471. pygpt_net/data/icons/power.svg +0 -0
  472. pygpt_net/data/icons/print.svg +0 -0
  473. pygpt_net/data/icons/public_filled.svg +0 -0
  474. pygpt_net/data/icons/redo.svg +0 -0
  475. pygpt_net/data/icons/reload.svg +0 -0
  476. pygpt_net/data/icons/repeat.svg +0 -0
  477. pygpt_net/data/icons/replay.svg +0 -0
  478. pygpt_net/data/icons/resize.svg +0 -0
  479. pygpt_net/data/icons/robot.svg +0 -0
  480. pygpt_net/data/icons/router.svg +0 -0
  481. pygpt_net/data/icons/save.svg +0 -0
  482. pygpt_net/data/icons/schedule.svg +0 -0
  483. pygpt_net/data/icons/screenshot.svg +0 -0
  484. pygpt_net/data/icons/search.svg +0 -0
  485. pygpt_net/data/icons/security.svg +0 -0
  486. pygpt_net/data/icons/sensors.svg +0 -0
  487. pygpt_net/data/icons/settings.svg +0 -0
  488. pygpt_net/data/icons/settings_filled.svg +0 -0
  489. pygpt_net/data/icons/share.svg +0 -0
  490. pygpt_net/data/icons/shedule.svg +0 -0
  491. pygpt_net/data/icons/sort.svg +0 -0
  492. pygpt_net/data/icons/split_screen.svg +0 -0
  493. pygpt_net/data/icons/stack.svg +0 -0
  494. pygpt_net/data/icons/stacks.svg +0 -0
  495. pygpt_net/data/icons/star.svg +0 -0
  496. pygpt_net/data/icons/stop.svg +0 -0
  497. pygpt_net/data/icons/stop_circle.svg +0 -0
  498. pygpt_net/data/icons/sync.svg +0 -0
  499. pygpt_net/data/icons/tag.svg +0 -0
  500. pygpt_net/data/icons/task.svg +0 -0
  501. pygpt_net/data/icons/terminal.svg +0 -0
  502. pygpt_net/data/icons/text.svg +0 -0
  503. pygpt_net/data/icons/textfile.svg +0 -0
  504. pygpt_net/data/icons/timer.svg +0 -0
  505. pygpt_net/data/icons/today.svg +0 -0
  506. pygpt_net/data/icons/tune.svg +0 -0
  507. pygpt_net/data/icons/undo.svg +0 -0
  508. pygpt_net/data/icons/update.svg +0 -0
  509. pygpt_net/data/icons/updater.svg +0 -0
  510. pygpt_net/data/icons/upload.svg +0 -0
  511. pygpt_net/data/icons/video.svg +0 -0
  512. pygpt_net/data/icons/view.svg +0 -0
  513. pygpt_net/data/icons/voice.svg +0 -0
  514. pygpt_net/data/icons/volume.svg +0 -0
  515. pygpt_net/data/icons/warning.svg +0 -0
  516. pygpt_net/data/icons/webcam.svg +0 -0
  517. pygpt_net/data/icons/webcam_off.svg +0 -0
  518. pygpt_net/data/icons/width.svg +0 -0
  519. pygpt_net/data/icons/window.svg +0 -0
  520. pygpt_net/data/icons/work.svg +0 -0
  521. pygpt_net/data/icons/zoom_in.svg +0 -0
  522. pygpt_net/data/icons/zoom_out.svg +0 -0
  523. pygpt_net/data/js/app.js +4348 -0
  524. pygpt_net/data/js/highlight/DIGESTS.md +0 -0
  525. pygpt_net/data/js/highlight/LICENSE +0 -0
  526. pygpt_net/data/js/highlight/README.md +0 -0
  527. pygpt_net/data/js/highlight/es/core.js +0 -0
  528. pygpt_net/data/js/highlight/es/core.min.js +0 -0
  529. pygpt_net/data/js/highlight/es/highlight.js +0 -0
  530. pygpt_net/data/js/highlight/es/highlight.min.js +0 -0
  531. pygpt_net/data/js/highlight/es/languages/1c.js +0 -0
  532. pygpt_net/data/js/highlight/es/languages/1c.min.js +0 -0
  533. pygpt_net/data/js/highlight/es/languages/abnf.js +0 -0
  534. pygpt_net/data/js/highlight/es/languages/abnf.min.js +0 -0
  535. pygpt_net/data/js/highlight/es/languages/accesslog.js +0 -0
  536. pygpt_net/data/js/highlight/es/languages/accesslog.min.js +0 -0
  537. pygpt_net/data/js/highlight/es/languages/actionscript.js +0 -0
  538. pygpt_net/data/js/highlight/es/languages/actionscript.min.js +0 -0
  539. pygpt_net/data/js/highlight/es/languages/ada.js +0 -0
  540. pygpt_net/data/js/highlight/es/languages/ada.min.js +0 -0
  541. pygpt_net/data/js/highlight/es/languages/angelscript.js +0 -0
  542. pygpt_net/data/js/highlight/es/languages/angelscript.min.js +0 -0
  543. pygpt_net/data/js/highlight/es/languages/apache.js +0 -0
  544. pygpt_net/data/js/highlight/es/languages/apache.min.js +0 -0
  545. pygpt_net/data/js/highlight/es/languages/applescript.js +0 -0
  546. pygpt_net/data/js/highlight/es/languages/applescript.min.js +0 -0
  547. pygpt_net/data/js/highlight/es/languages/arcade.js +0 -0
  548. pygpt_net/data/js/highlight/es/languages/arcade.min.js +0 -0
  549. pygpt_net/data/js/highlight/es/languages/arduino.js +0 -0
  550. pygpt_net/data/js/highlight/es/languages/arduino.min.js +0 -0
  551. pygpt_net/data/js/highlight/es/languages/armasm.js +0 -0
  552. pygpt_net/data/js/highlight/es/languages/armasm.min.js +0 -0
  553. pygpt_net/data/js/highlight/es/languages/asciidoc.js +0 -0
  554. pygpt_net/data/js/highlight/es/languages/asciidoc.min.js +0 -0
  555. pygpt_net/data/js/highlight/es/languages/aspectj.js +0 -0
  556. pygpt_net/data/js/highlight/es/languages/aspectj.min.js +0 -0
  557. pygpt_net/data/js/highlight/es/languages/autohotkey.js +0 -0
  558. pygpt_net/data/js/highlight/es/languages/autohotkey.min.js +0 -0
  559. pygpt_net/data/js/highlight/es/languages/autoit.js +0 -0
  560. pygpt_net/data/js/highlight/es/languages/autoit.min.js +0 -0
  561. pygpt_net/data/js/highlight/es/languages/avrasm.js +0 -0
  562. pygpt_net/data/js/highlight/es/languages/avrasm.min.js +0 -0
  563. pygpt_net/data/js/highlight/es/languages/awk.js +0 -0
  564. pygpt_net/data/js/highlight/es/languages/awk.min.js +0 -0
  565. pygpt_net/data/js/highlight/es/languages/axapta.js +0 -0
  566. pygpt_net/data/js/highlight/es/languages/axapta.min.js +0 -0
  567. pygpt_net/data/js/highlight/es/languages/bash.js +0 -0
  568. pygpt_net/data/js/highlight/es/languages/bash.min.js +0 -0
  569. pygpt_net/data/js/highlight/es/languages/basic.js +0 -0
  570. pygpt_net/data/js/highlight/es/languages/basic.min.js +0 -0
  571. pygpt_net/data/js/highlight/es/languages/bnf.js +0 -0
  572. pygpt_net/data/js/highlight/es/languages/bnf.min.js +0 -0
  573. pygpt_net/data/js/highlight/es/languages/brainfuck.js +0 -0
  574. pygpt_net/data/js/highlight/es/languages/brainfuck.min.js +0 -0
  575. pygpt_net/data/js/highlight/es/languages/c.js +0 -0
  576. pygpt_net/data/js/highlight/es/languages/c.min.js +0 -0
  577. pygpt_net/data/js/highlight/es/languages/cal.js +0 -0
  578. pygpt_net/data/js/highlight/es/languages/cal.min.js +0 -0
  579. pygpt_net/data/js/highlight/es/languages/capnproto.js +0 -0
  580. pygpt_net/data/js/highlight/es/languages/capnproto.min.js +0 -0
  581. pygpt_net/data/js/highlight/es/languages/ceylon.js +0 -0
  582. pygpt_net/data/js/highlight/es/languages/ceylon.min.js +0 -0
  583. pygpt_net/data/js/highlight/es/languages/clean.js +0 -0
  584. pygpt_net/data/js/highlight/es/languages/clean.min.js +0 -0
  585. pygpt_net/data/js/highlight/es/languages/clojure-repl.js +0 -0
  586. pygpt_net/data/js/highlight/es/languages/clojure-repl.min.js +0 -0
  587. pygpt_net/data/js/highlight/es/languages/clojure.js +0 -0
  588. pygpt_net/data/js/highlight/es/languages/clojure.min.js +0 -0
  589. pygpt_net/data/js/highlight/es/languages/cmake.js +0 -0
  590. pygpt_net/data/js/highlight/es/languages/cmake.min.js +0 -0
  591. pygpt_net/data/js/highlight/es/languages/coffeescript.js +0 -0
  592. pygpt_net/data/js/highlight/es/languages/coffeescript.min.js +0 -0
  593. pygpt_net/data/js/highlight/es/languages/coq.js +0 -0
  594. pygpt_net/data/js/highlight/es/languages/coq.min.js +0 -0
  595. pygpt_net/data/js/highlight/es/languages/cos.js +0 -0
  596. pygpt_net/data/js/highlight/es/languages/cos.min.js +0 -0
  597. pygpt_net/data/js/highlight/es/languages/cpp.js +0 -0
  598. pygpt_net/data/js/highlight/es/languages/cpp.min.js +0 -0
  599. pygpt_net/data/js/highlight/es/languages/crmsh.js +0 -0
  600. pygpt_net/data/js/highlight/es/languages/crmsh.min.js +0 -0
  601. pygpt_net/data/js/highlight/es/languages/crystal.js +0 -0
  602. pygpt_net/data/js/highlight/es/languages/crystal.min.js +0 -0
  603. pygpt_net/data/js/highlight/es/languages/csharp.js +0 -0
  604. pygpt_net/data/js/highlight/es/languages/csharp.min.js +0 -0
  605. pygpt_net/data/js/highlight/es/languages/csp.js +0 -0
  606. pygpt_net/data/js/highlight/es/languages/csp.min.js +0 -0
  607. pygpt_net/data/js/highlight/es/languages/css.js +0 -0
  608. pygpt_net/data/js/highlight/es/languages/css.min.js +0 -0
  609. pygpt_net/data/js/highlight/es/languages/d.js +0 -0
  610. pygpt_net/data/js/highlight/es/languages/d.min.js +0 -0
  611. pygpt_net/data/js/highlight/es/languages/dart.js +0 -0
  612. pygpt_net/data/js/highlight/es/languages/dart.min.js +0 -0
  613. pygpt_net/data/js/highlight/es/languages/delphi.js +0 -0
  614. pygpt_net/data/js/highlight/es/languages/delphi.min.js +0 -0
  615. pygpt_net/data/js/highlight/es/languages/diff.js +0 -0
  616. pygpt_net/data/js/highlight/es/languages/diff.min.js +0 -0
  617. pygpt_net/data/js/highlight/es/languages/django.js +0 -0
  618. pygpt_net/data/js/highlight/es/languages/django.min.js +0 -0
  619. pygpt_net/data/js/highlight/es/languages/dns.js +0 -0
  620. pygpt_net/data/js/highlight/es/languages/dns.min.js +0 -0
  621. pygpt_net/data/js/highlight/es/languages/dockerfile.js +0 -0
  622. pygpt_net/data/js/highlight/es/languages/dockerfile.min.js +0 -0
  623. pygpt_net/data/js/highlight/es/languages/dos.js +0 -0
  624. pygpt_net/data/js/highlight/es/languages/dos.min.js +0 -0
  625. pygpt_net/data/js/highlight/es/languages/dsconfig.js +0 -0
  626. pygpt_net/data/js/highlight/es/languages/dsconfig.min.js +0 -0
  627. pygpt_net/data/js/highlight/es/languages/dts.js +0 -0
  628. pygpt_net/data/js/highlight/es/languages/dts.min.js +0 -0
  629. pygpt_net/data/js/highlight/es/languages/dust.js +0 -0
  630. pygpt_net/data/js/highlight/es/languages/dust.min.js +0 -0
  631. pygpt_net/data/js/highlight/es/languages/ebnf.js +0 -0
  632. pygpt_net/data/js/highlight/es/languages/ebnf.min.js +0 -0
  633. pygpt_net/data/js/highlight/es/languages/elixir.js +0 -0
  634. pygpt_net/data/js/highlight/es/languages/elixir.min.js +0 -0
  635. pygpt_net/data/js/highlight/es/languages/elm.js +0 -0
  636. pygpt_net/data/js/highlight/es/languages/elm.min.js +0 -0
  637. pygpt_net/data/js/highlight/es/languages/erb.js +0 -0
  638. pygpt_net/data/js/highlight/es/languages/erb.min.js +0 -0
  639. pygpt_net/data/js/highlight/es/languages/erlang-repl.js +0 -0
  640. pygpt_net/data/js/highlight/es/languages/erlang-repl.min.js +0 -0
  641. pygpt_net/data/js/highlight/es/languages/erlang.js +0 -0
  642. pygpt_net/data/js/highlight/es/languages/erlang.min.js +0 -0
  643. pygpt_net/data/js/highlight/es/languages/excel.js +0 -0
  644. pygpt_net/data/js/highlight/es/languages/excel.min.js +0 -0
  645. pygpt_net/data/js/highlight/es/languages/fix.js +0 -0
  646. pygpt_net/data/js/highlight/es/languages/fix.min.js +0 -0
  647. pygpt_net/data/js/highlight/es/languages/flix.js +0 -0
  648. pygpt_net/data/js/highlight/es/languages/flix.min.js +0 -0
  649. pygpt_net/data/js/highlight/es/languages/fortran.js +0 -0
  650. pygpt_net/data/js/highlight/es/languages/fortran.min.js +0 -0
  651. pygpt_net/data/js/highlight/es/languages/fsharp.js +0 -0
  652. pygpt_net/data/js/highlight/es/languages/fsharp.min.js +0 -0
  653. pygpt_net/data/js/highlight/es/languages/gams.js +0 -0
  654. pygpt_net/data/js/highlight/es/languages/gams.min.js +0 -0
  655. pygpt_net/data/js/highlight/es/languages/gauss.js +0 -0
  656. pygpt_net/data/js/highlight/es/languages/gauss.min.js +0 -0
  657. pygpt_net/data/js/highlight/es/languages/gcode.js +0 -0
  658. pygpt_net/data/js/highlight/es/languages/gcode.min.js +0 -0
  659. pygpt_net/data/js/highlight/es/languages/gherkin.js +0 -0
  660. pygpt_net/data/js/highlight/es/languages/gherkin.min.js +0 -0
  661. pygpt_net/data/js/highlight/es/languages/glsl.js +0 -0
  662. pygpt_net/data/js/highlight/es/languages/glsl.min.js +0 -0
  663. pygpt_net/data/js/highlight/es/languages/gml.js +0 -0
  664. pygpt_net/data/js/highlight/es/languages/gml.min.js +0 -0
  665. pygpt_net/data/js/highlight/es/languages/go.js +0 -0
  666. pygpt_net/data/js/highlight/es/languages/go.min.js +0 -0
  667. pygpt_net/data/js/highlight/es/languages/golo.js +0 -0
  668. pygpt_net/data/js/highlight/es/languages/golo.min.js +0 -0
  669. pygpt_net/data/js/highlight/es/languages/gradle.js +0 -0
  670. pygpt_net/data/js/highlight/es/languages/gradle.min.js +0 -0
  671. pygpt_net/data/js/highlight/es/languages/graphql.js +0 -0
  672. pygpt_net/data/js/highlight/es/languages/graphql.min.js +0 -0
  673. pygpt_net/data/js/highlight/es/languages/groovy.js +0 -0
  674. pygpt_net/data/js/highlight/es/languages/groovy.min.js +0 -0
  675. pygpt_net/data/js/highlight/es/languages/haml.js +0 -0
  676. pygpt_net/data/js/highlight/es/languages/haml.min.js +0 -0
  677. pygpt_net/data/js/highlight/es/languages/handlebars.js +0 -0
  678. pygpt_net/data/js/highlight/es/languages/handlebars.min.js +0 -0
  679. pygpt_net/data/js/highlight/es/languages/haskell.js +0 -0
  680. pygpt_net/data/js/highlight/es/languages/haskell.min.js +0 -0
  681. pygpt_net/data/js/highlight/es/languages/haxe.js +0 -0
  682. pygpt_net/data/js/highlight/es/languages/haxe.min.js +0 -0
  683. pygpt_net/data/js/highlight/es/languages/hsp.js +0 -0
  684. pygpt_net/data/js/highlight/es/languages/hsp.min.js +0 -0
  685. pygpt_net/data/js/highlight/es/languages/http.js +0 -0
  686. pygpt_net/data/js/highlight/es/languages/http.min.js +0 -0
  687. pygpt_net/data/js/highlight/es/languages/hy.js +0 -0
  688. pygpt_net/data/js/highlight/es/languages/hy.min.js +0 -0
  689. pygpt_net/data/js/highlight/es/languages/inform7.js +0 -0
  690. pygpt_net/data/js/highlight/es/languages/inform7.min.js +0 -0
  691. pygpt_net/data/js/highlight/es/languages/ini.js +0 -0
  692. pygpt_net/data/js/highlight/es/languages/ini.min.js +0 -0
  693. pygpt_net/data/js/highlight/es/languages/irpf90.js +0 -0
  694. pygpt_net/data/js/highlight/es/languages/irpf90.min.js +0 -0
  695. pygpt_net/data/js/highlight/es/languages/isbl.js +0 -0
  696. pygpt_net/data/js/highlight/es/languages/isbl.min.js +0 -0
  697. pygpt_net/data/js/highlight/es/languages/java.js +0 -0
  698. pygpt_net/data/js/highlight/es/languages/java.min.js +0 -0
  699. pygpt_net/data/js/highlight/es/languages/javascript.js +0 -0
  700. pygpt_net/data/js/highlight/es/languages/javascript.min.js +0 -0
  701. pygpt_net/data/js/highlight/es/languages/jboss-cli.js +0 -0
  702. pygpt_net/data/js/highlight/es/languages/jboss-cli.min.js +0 -0
  703. pygpt_net/data/js/highlight/es/languages/json.js +0 -0
  704. pygpt_net/data/js/highlight/es/languages/json.min.js +0 -0
  705. pygpt_net/data/js/highlight/es/languages/julia-repl.js +0 -0
  706. pygpt_net/data/js/highlight/es/languages/julia-repl.min.js +0 -0
  707. pygpt_net/data/js/highlight/es/languages/julia.js +0 -0
  708. pygpt_net/data/js/highlight/es/languages/julia.min.js +0 -0
  709. pygpt_net/data/js/highlight/es/languages/kotlin.js +0 -0
  710. pygpt_net/data/js/highlight/es/languages/kotlin.min.js +0 -0
  711. pygpt_net/data/js/highlight/es/languages/lasso.js +0 -0
  712. pygpt_net/data/js/highlight/es/languages/lasso.min.js +0 -0
  713. pygpt_net/data/js/highlight/es/languages/latex.js +0 -0
  714. pygpt_net/data/js/highlight/es/languages/latex.min.js +0 -0
  715. pygpt_net/data/js/highlight/es/languages/ldif.js +0 -0
  716. pygpt_net/data/js/highlight/es/languages/ldif.min.js +0 -0
  717. pygpt_net/data/js/highlight/es/languages/leaf.js +0 -0
  718. pygpt_net/data/js/highlight/es/languages/leaf.min.js +0 -0
  719. pygpt_net/data/js/highlight/es/languages/less.js +0 -0
  720. pygpt_net/data/js/highlight/es/languages/less.min.js +0 -0
  721. pygpt_net/data/js/highlight/es/languages/lisp.js +0 -0
  722. pygpt_net/data/js/highlight/es/languages/lisp.min.js +0 -0
  723. pygpt_net/data/js/highlight/es/languages/livecodeserver.js +0 -0
  724. pygpt_net/data/js/highlight/es/languages/livecodeserver.min.js +0 -0
  725. pygpt_net/data/js/highlight/es/languages/livescript.js +0 -0
  726. pygpt_net/data/js/highlight/es/languages/livescript.min.js +0 -0
  727. pygpt_net/data/js/highlight/es/languages/llvm.js +0 -0
  728. pygpt_net/data/js/highlight/es/languages/llvm.min.js +0 -0
  729. pygpt_net/data/js/highlight/es/languages/lsl.js +0 -0
  730. pygpt_net/data/js/highlight/es/languages/lsl.min.js +0 -0
  731. pygpt_net/data/js/highlight/es/languages/lua.js +0 -0
  732. pygpt_net/data/js/highlight/es/languages/lua.min.js +0 -0
  733. pygpt_net/data/js/highlight/es/languages/makefile.js +0 -0
  734. pygpt_net/data/js/highlight/es/languages/makefile.min.js +0 -0
  735. pygpt_net/data/js/highlight/es/languages/markdown.js +0 -0
  736. pygpt_net/data/js/highlight/es/languages/markdown.min.js +0 -0
  737. pygpt_net/data/js/highlight/es/languages/mathematica.js +0 -0
  738. pygpt_net/data/js/highlight/es/languages/mathematica.min.js +0 -0
  739. pygpt_net/data/js/highlight/es/languages/matlab.js +0 -0
  740. pygpt_net/data/js/highlight/es/languages/matlab.min.js +0 -0
  741. pygpt_net/data/js/highlight/es/languages/maxima.js +0 -0
  742. pygpt_net/data/js/highlight/es/languages/maxima.min.js +0 -0
  743. pygpt_net/data/js/highlight/es/languages/mel.js +0 -0
  744. pygpt_net/data/js/highlight/es/languages/mel.min.js +0 -0
  745. pygpt_net/data/js/highlight/es/languages/mercury.js +0 -0
  746. pygpt_net/data/js/highlight/es/languages/mercury.min.js +0 -0
  747. pygpt_net/data/js/highlight/es/languages/mipsasm.js +0 -0
  748. pygpt_net/data/js/highlight/es/languages/mipsasm.min.js +0 -0
  749. pygpt_net/data/js/highlight/es/languages/mizar.js +0 -0
  750. pygpt_net/data/js/highlight/es/languages/mizar.min.js +0 -0
  751. pygpt_net/data/js/highlight/es/languages/mojolicious.js +0 -0
  752. pygpt_net/data/js/highlight/es/languages/mojolicious.min.js +0 -0
  753. pygpt_net/data/js/highlight/es/languages/monkey.js +0 -0
  754. pygpt_net/data/js/highlight/es/languages/monkey.min.js +0 -0
  755. pygpt_net/data/js/highlight/es/languages/moonscript.js +0 -0
  756. pygpt_net/data/js/highlight/es/languages/moonscript.min.js +0 -0
  757. pygpt_net/data/js/highlight/es/languages/n1ql.js +0 -0
  758. pygpt_net/data/js/highlight/es/languages/n1ql.min.js +0 -0
  759. pygpt_net/data/js/highlight/es/languages/nestedtext.js +0 -0
  760. pygpt_net/data/js/highlight/es/languages/nestedtext.min.js +0 -0
  761. pygpt_net/data/js/highlight/es/languages/nginx.js +0 -0
  762. pygpt_net/data/js/highlight/es/languages/nginx.min.js +0 -0
  763. pygpt_net/data/js/highlight/es/languages/nim.js +0 -0
  764. pygpt_net/data/js/highlight/es/languages/nim.min.js +0 -0
  765. pygpt_net/data/js/highlight/es/languages/nix.js +0 -0
  766. pygpt_net/data/js/highlight/es/languages/nix.min.js +0 -0
  767. pygpt_net/data/js/highlight/es/languages/node-repl.js +0 -0
  768. pygpt_net/data/js/highlight/es/languages/node-repl.min.js +0 -0
  769. pygpt_net/data/js/highlight/es/languages/nsis.js +0 -0
  770. pygpt_net/data/js/highlight/es/languages/nsis.min.js +0 -0
  771. pygpt_net/data/js/highlight/es/languages/objectivec.js +0 -0
  772. pygpt_net/data/js/highlight/es/languages/objectivec.min.js +0 -0
  773. pygpt_net/data/js/highlight/es/languages/ocaml.js +0 -0
  774. pygpt_net/data/js/highlight/es/languages/ocaml.min.js +0 -0
  775. pygpt_net/data/js/highlight/es/languages/openscad.js +0 -0
  776. pygpt_net/data/js/highlight/es/languages/openscad.min.js +0 -0
  777. pygpt_net/data/js/highlight/es/languages/oxygene.js +0 -0
  778. pygpt_net/data/js/highlight/es/languages/oxygene.min.js +0 -0
  779. pygpt_net/data/js/highlight/es/languages/parser3.js +0 -0
  780. pygpt_net/data/js/highlight/es/languages/parser3.min.js +0 -0
  781. pygpt_net/data/js/highlight/es/languages/perl.js +0 -0
  782. pygpt_net/data/js/highlight/es/languages/perl.min.js +0 -0
  783. pygpt_net/data/js/highlight/es/languages/pf.js +0 -0
  784. pygpt_net/data/js/highlight/es/languages/pf.min.js +0 -0
  785. pygpt_net/data/js/highlight/es/languages/pgsql.js +0 -0
  786. pygpt_net/data/js/highlight/es/languages/pgsql.min.js +0 -0
  787. pygpt_net/data/js/highlight/es/languages/php-template.js +0 -0
  788. pygpt_net/data/js/highlight/es/languages/php-template.min.js +0 -0
  789. pygpt_net/data/js/highlight/es/languages/php.js +0 -0
  790. pygpt_net/data/js/highlight/es/languages/php.min.js +0 -0
  791. pygpt_net/data/js/highlight/es/languages/plaintext.js +0 -0
  792. pygpt_net/data/js/highlight/es/languages/plaintext.min.js +0 -0
  793. pygpt_net/data/js/highlight/es/languages/pony.js +0 -0
  794. pygpt_net/data/js/highlight/es/languages/pony.min.js +0 -0
  795. pygpt_net/data/js/highlight/es/languages/powershell.js +0 -0
  796. pygpt_net/data/js/highlight/es/languages/powershell.min.js +0 -0
  797. pygpt_net/data/js/highlight/es/languages/processing.js +0 -0
  798. pygpt_net/data/js/highlight/es/languages/processing.min.js +0 -0
  799. pygpt_net/data/js/highlight/es/languages/profile.js +0 -0
  800. pygpt_net/data/js/highlight/es/languages/profile.min.js +0 -0
  801. pygpt_net/data/js/highlight/es/languages/prolog.js +0 -0
  802. pygpt_net/data/js/highlight/es/languages/prolog.min.js +0 -0
  803. pygpt_net/data/js/highlight/es/languages/properties.js +0 -0
  804. pygpt_net/data/js/highlight/es/languages/properties.min.js +0 -0
  805. pygpt_net/data/js/highlight/es/languages/protobuf.js +0 -0
  806. pygpt_net/data/js/highlight/es/languages/protobuf.min.js +0 -0
  807. pygpt_net/data/js/highlight/es/languages/puppet.js +0 -0
  808. pygpt_net/data/js/highlight/es/languages/puppet.min.js +0 -0
  809. pygpt_net/data/js/highlight/es/languages/purebasic.js +0 -0
  810. pygpt_net/data/js/highlight/es/languages/purebasic.min.js +0 -0
  811. pygpt_net/data/js/highlight/es/languages/python-repl.js +0 -0
  812. pygpt_net/data/js/highlight/es/languages/python-repl.min.js +0 -0
  813. pygpt_net/data/js/highlight/es/languages/python.js +0 -0
  814. pygpt_net/data/js/highlight/es/languages/python.min.js +0 -0
  815. pygpt_net/data/js/highlight/es/languages/q.js +0 -0
  816. pygpt_net/data/js/highlight/es/languages/q.min.js +0 -0
  817. pygpt_net/data/js/highlight/es/languages/qml.js +0 -0
  818. pygpt_net/data/js/highlight/es/languages/qml.min.js +0 -0
  819. pygpt_net/data/js/highlight/es/languages/r.js +0 -0
  820. pygpt_net/data/js/highlight/es/languages/r.min.js +0 -0
  821. pygpt_net/data/js/highlight/es/languages/reasonml.js +0 -0
  822. pygpt_net/data/js/highlight/es/languages/reasonml.min.js +0 -0
  823. pygpt_net/data/js/highlight/es/languages/rib.js +0 -0
  824. pygpt_net/data/js/highlight/es/languages/rib.min.js +0 -0
  825. pygpt_net/data/js/highlight/es/languages/roboconf.js +0 -0
  826. pygpt_net/data/js/highlight/es/languages/roboconf.min.js +0 -0
  827. pygpt_net/data/js/highlight/es/languages/routeros.js +0 -0
  828. pygpt_net/data/js/highlight/es/languages/routeros.min.js +0 -0
  829. pygpt_net/data/js/highlight/es/languages/rsl.js +0 -0
  830. pygpt_net/data/js/highlight/es/languages/rsl.min.js +0 -0
  831. pygpt_net/data/js/highlight/es/languages/ruby.js +0 -0
  832. pygpt_net/data/js/highlight/es/languages/ruby.min.js +0 -0
  833. pygpt_net/data/js/highlight/es/languages/ruleslanguage.js +0 -0
  834. pygpt_net/data/js/highlight/es/languages/ruleslanguage.min.js +0 -0
  835. pygpt_net/data/js/highlight/es/languages/rust.js +0 -0
  836. pygpt_net/data/js/highlight/es/languages/rust.min.js +0 -0
  837. pygpt_net/data/js/highlight/es/languages/sas.js +0 -0
  838. pygpt_net/data/js/highlight/es/languages/sas.min.js +0 -0
  839. pygpt_net/data/js/highlight/es/languages/scala.js +0 -0
  840. pygpt_net/data/js/highlight/es/languages/scala.min.js +0 -0
  841. pygpt_net/data/js/highlight/es/languages/scheme.js +0 -0
  842. pygpt_net/data/js/highlight/es/languages/scheme.min.js +0 -0
  843. pygpt_net/data/js/highlight/es/languages/scilab.js +0 -0
  844. pygpt_net/data/js/highlight/es/languages/scilab.min.js +0 -0
  845. pygpt_net/data/js/highlight/es/languages/scss.js +0 -0
  846. pygpt_net/data/js/highlight/es/languages/scss.min.js +0 -0
  847. pygpt_net/data/js/highlight/es/languages/shell.js +0 -0
  848. pygpt_net/data/js/highlight/es/languages/shell.min.js +0 -0
  849. pygpt_net/data/js/highlight/es/languages/smali.js +0 -0
  850. pygpt_net/data/js/highlight/es/languages/smali.min.js +0 -0
  851. pygpt_net/data/js/highlight/es/languages/smalltalk.js +0 -0
  852. pygpt_net/data/js/highlight/es/languages/smalltalk.min.js +0 -0
  853. pygpt_net/data/js/highlight/es/languages/sml.js +0 -0
  854. pygpt_net/data/js/highlight/es/languages/sml.min.js +0 -0
  855. pygpt_net/data/js/highlight/es/languages/sqf.js +0 -0
  856. pygpt_net/data/js/highlight/es/languages/sqf.min.js +0 -0
  857. pygpt_net/data/js/highlight/es/languages/sql.js +0 -0
  858. pygpt_net/data/js/highlight/es/languages/sql.min.js +0 -0
  859. pygpt_net/data/js/highlight/es/languages/stan.js +0 -0
  860. pygpt_net/data/js/highlight/es/languages/stan.min.js +0 -0
  861. pygpt_net/data/js/highlight/es/languages/stata.js +0 -0
  862. pygpt_net/data/js/highlight/es/languages/stata.min.js +0 -0
  863. pygpt_net/data/js/highlight/es/languages/step21.js +0 -0
  864. pygpt_net/data/js/highlight/es/languages/step21.min.js +0 -0
  865. pygpt_net/data/js/highlight/es/languages/stylus.js +0 -0
  866. pygpt_net/data/js/highlight/es/languages/stylus.min.js +0 -0
  867. pygpt_net/data/js/highlight/es/languages/subunit.js +0 -0
  868. pygpt_net/data/js/highlight/es/languages/subunit.min.js +0 -0
  869. pygpt_net/data/js/highlight/es/languages/swift.js +0 -0
  870. pygpt_net/data/js/highlight/es/languages/swift.min.js +0 -0
  871. pygpt_net/data/js/highlight/es/languages/taggerscript.js +0 -0
  872. pygpt_net/data/js/highlight/es/languages/taggerscript.min.js +0 -0
  873. pygpt_net/data/js/highlight/es/languages/tap.js +0 -0
  874. pygpt_net/data/js/highlight/es/languages/tap.min.js +0 -0
  875. pygpt_net/data/js/highlight/es/languages/tcl.js +0 -0
  876. pygpt_net/data/js/highlight/es/languages/tcl.min.js +0 -0
  877. pygpt_net/data/js/highlight/es/languages/thrift.js +0 -0
  878. pygpt_net/data/js/highlight/es/languages/thrift.min.js +0 -0
  879. pygpt_net/data/js/highlight/es/languages/tp.js +0 -0
  880. pygpt_net/data/js/highlight/es/languages/tp.min.js +0 -0
  881. pygpt_net/data/js/highlight/es/languages/twig.js +0 -0
  882. pygpt_net/data/js/highlight/es/languages/twig.min.js +0 -0
  883. pygpt_net/data/js/highlight/es/languages/typescript.js +0 -0
  884. pygpt_net/data/js/highlight/es/languages/typescript.min.js +0 -0
  885. pygpt_net/data/js/highlight/es/languages/vala.js +0 -0
  886. pygpt_net/data/js/highlight/es/languages/vala.min.js +0 -0
  887. pygpt_net/data/js/highlight/es/languages/vbnet.js +0 -0
  888. pygpt_net/data/js/highlight/es/languages/vbnet.min.js +0 -0
  889. pygpt_net/data/js/highlight/es/languages/vbscript-html.js +0 -0
  890. pygpt_net/data/js/highlight/es/languages/vbscript-html.min.js +0 -0
  891. pygpt_net/data/js/highlight/es/languages/vbscript.js +0 -0
  892. pygpt_net/data/js/highlight/es/languages/vbscript.min.js +0 -0
  893. pygpt_net/data/js/highlight/es/languages/verilog.js +0 -0
  894. pygpt_net/data/js/highlight/es/languages/verilog.min.js +0 -0
  895. pygpt_net/data/js/highlight/es/languages/vhdl.js +0 -0
  896. pygpt_net/data/js/highlight/es/languages/vhdl.min.js +0 -0
  897. pygpt_net/data/js/highlight/es/languages/vim.js +0 -0
  898. pygpt_net/data/js/highlight/es/languages/vim.min.js +0 -0
  899. pygpt_net/data/js/highlight/es/languages/wasm.js +0 -0
  900. pygpt_net/data/js/highlight/es/languages/wasm.min.js +0 -0
  901. pygpt_net/data/js/highlight/es/languages/wren.js +0 -0
  902. pygpt_net/data/js/highlight/es/languages/wren.min.js +0 -0
  903. pygpt_net/data/js/highlight/es/languages/x86asm.js +0 -0
  904. pygpt_net/data/js/highlight/es/languages/x86asm.min.js +0 -0
  905. pygpt_net/data/js/highlight/es/languages/xl.js +0 -0
  906. pygpt_net/data/js/highlight/es/languages/xl.min.js +0 -0
  907. pygpt_net/data/js/highlight/es/languages/xml.js +0 -0
  908. pygpt_net/data/js/highlight/es/languages/xml.min.js +0 -0
  909. pygpt_net/data/js/highlight/es/languages/xquery.js +0 -0
  910. pygpt_net/data/js/highlight/es/languages/xquery.min.js +0 -0
  911. pygpt_net/data/js/highlight/es/languages/yaml.js +0 -0
  912. pygpt_net/data/js/highlight/es/languages/yaml.min.js +0 -0
  913. pygpt_net/data/js/highlight/es/languages/zephir.js +0 -0
  914. pygpt_net/data/js/highlight/es/languages/zephir.min.js +0 -0
  915. pygpt_net/data/js/highlight/es/package.json +0 -0
  916. pygpt_net/data/js/highlight/highlight.js +0 -0
  917. pygpt_net/data/js/highlight/highlight.min.js +0 -0
  918. pygpt_net/data/js/highlight/languages/1c.js +0 -0
  919. pygpt_net/data/js/highlight/languages/1c.min.js +0 -0
  920. pygpt_net/data/js/highlight/languages/abnf.js +0 -0
  921. pygpt_net/data/js/highlight/languages/abnf.min.js +0 -0
  922. pygpt_net/data/js/highlight/languages/accesslog.js +0 -0
  923. pygpt_net/data/js/highlight/languages/accesslog.min.js +0 -0
  924. pygpt_net/data/js/highlight/languages/actionscript.js +0 -0
  925. pygpt_net/data/js/highlight/languages/actionscript.min.js +0 -0
  926. pygpt_net/data/js/highlight/languages/ada.js +0 -0
  927. pygpt_net/data/js/highlight/languages/ada.min.js +0 -0
  928. pygpt_net/data/js/highlight/languages/angelscript.js +0 -0
  929. pygpt_net/data/js/highlight/languages/angelscript.min.js +0 -0
  930. pygpt_net/data/js/highlight/languages/apache.js +0 -0
  931. pygpt_net/data/js/highlight/languages/apache.min.js +0 -0
  932. pygpt_net/data/js/highlight/languages/applescript.js +0 -0
  933. pygpt_net/data/js/highlight/languages/applescript.min.js +0 -0
  934. pygpt_net/data/js/highlight/languages/arcade.js +0 -0
  935. pygpt_net/data/js/highlight/languages/arcade.min.js +0 -0
  936. pygpt_net/data/js/highlight/languages/arduino.js +0 -0
  937. pygpt_net/data/js/highlight/languages/arduino.min.js +0 -0
  938. pygpt_net/data/js/highlight/languages/armasm.js +0 -0
  939. pygpt_net/data/js/highlight/languages/armasm.min.js +0 -0
  940. pygpt_net/data/js/highlight/languages/asciidoc.js +0 -0
  941. pygpt_net/data/js/highlight/languages/asciidoc.min.js +0 -0
  942. pygpt_net/data/js/highlight/languages/aspectj.js +0 -0
  943. pygpt_net/data/js/highlight/languages/aspectj.min.js +0 -0
  944. pygpt_net/data/js/highlight/languages/autohotkey.js +0 -0
  945. pygpt_net/data/js/highlight/languages/autohotkey.min.js +0 -0
  946. pygpt_net/data/js/highlight/languages/autoit.js +0 -0
  947. pygpt_net/data/js/highlight/languages/autoit.min.js +0 -0
  948. pygpt_net/data/js/highlight/languages/avrasm.js +0 -0
  949. pygpt_net/data/js/highlight/languages/avrasm.min.js +0 -0
  950. pygpt_net/data/js/highlight/languages/awk.js +0 -0
  951. pygpt_net/data/js/highlight/languages/awk.min.js +0 -0
  952. pygpt_net/data/js/highlight/languages/axapta.js +0 -0
  953. pygpt_net/data/js/highlight/languages/axapta.min.js +0 -0
  954. pygpt_net/data/js/highlight/languages/bash.js +0 -0
  955. pygpt_net/data/js/highlight/languages/bash.min.js +0 -0
  956. pygpt_net/data/js/highlight/languages/basic.js +0 -0
  957. pygpt_net/data/js/highlight/languages/basic.min.js +0 -0
  958. pygpt_net/data/js/highlight/languages/bnf.js +0 -0
  959. pygpt_net/data/js/highlight/languages/bnf.min.js +0 -0
  960. pygpt_net/data/js/highlight/languages/brainfuck.js +0 -0
  961. pygpt_net/data/js/highlight/languages/brainfuck.min.js +0 -0
  962. pygpt_net/data/js/highlight/languages/c.js +0 -0
  963. pygpt_net/data/js/highlight/languages/c.min.js +0 -0
  964. pygpt_net/data/js/highlight/languages/cal.js +0 -0
  965. pygpt_net/data/js/highlight/languages/cal.min.js +0 -0
  966. pygpt_net/data/js/highlight/languages/capnproto.js +0 -0
  967. pygpt_net/data/js/highlight/languages/capnproto.min.js +0 -0
  968. pygpt_net/data/js/highlight/languages/ceylon.js +0 -0
  969. pygpt_net/data/js/highlight/languages/ceylon.min.js +0 -0
  970. pygpt_net/data/js/highlight/languages/clean.js +0 -0
  971. pygpt_net/data/js/highlight/languages/clean.min.js +0 -0
  972. pygpt_net/data/js/highlight/languages/clojure-repl.js +0 -0
  973. pygpt_net/data/js/highlight/languages/clojure-repl.min.js +0 -0
  974. pygpt_net/data/js/highlight/languages/clojure.js +0 -0
  975. pygpt_net/data/js/highlight/languages/clojure.min.js +0 -0
  976. pygpt_net/data/js/highlight/languages/cmake.js +0 -0
  977. pygpt_net/data/js/highlight/languages/cmake.min.js +0 -0
  978. pygpt_net/data/js/highlight/languages/coffeescript.js +0 -0
  979. pygpt_net/data/js/highlight/languages/coffeescript.min.js +0 -0
  980. pygpt_net/data/js/highlight/languages/coq.js +0 -0
  981. pygpt_net/data/js/highlight/languages/coq.min.js +0 -0
  982. pygpt_net/data/js/highlight/languages/cos.js +0 -0
  983. pygpt_net/data/js/highlight/languages/cos.min.js +0 -0
  984. pygpt_net/data/js/highlight/languages/cpp.js +0 -0
  985. pygpt_net/data/js/highlight/languages/cpp.min.js +0 -0
  986. pygpt_net/data/js/highlight/languages/crmsh.js +0 -0
  987. pygpt_net/data/js/highlight/languages/crmsh.min.js +0 -0
  988. pygpt_net/data/js/highlight/languages/crystal.js +0 -0
  989. pygpt_net/data/js/highlight/languages/crystal.min.js +0 -0
  990. pygpt_net/data/js/highlight/languages/csharp.js +0 -0
  991. pygpt_net/data/js/highlight/languages/csharp.min.js +0 -0
  992. pygpt_net/data/js/highlight/languages/csp.js +0 -0
  993. pygpt_net/data/js/highlight/languages/csp.min.js +0 -0
  994. pygpt_net/data/js/highlight/languages/css.js +0 -0
  995. pygpt_net/data/js/highlight/languages/css.min.js +0 -0
  996. pygpt_net/data/js/highlight/languages/d.js +0 -0
  997. pygpt_net/data/js/highlight/languages/d.min.js +0 -0
  998. pygpt_net/data/js/highlight/languages/dart.js +0 -0
  999. pygpt_net/data/js/highlight/languages/dart.min.js +0 -0
  1000. pygpt_net/data/js/highlight/languages/delphi.js +0 -0
  1001. pygpt_net/data/js/highlight/languages/delphi.min.js +0 -0
  1002. pygpt_net/data/js/highlight/languages/diff.js +0 -0
  1003. pygpt_net/data/js/highlight/languages/diff.min.js +0 -0
  1004. pygpt_net/data/js/highlight/languages/django.js +0 -0
  1005. pygpt_net/data/js/highlight/languages/django.min.js +0 -0
  1006. pygpt_net/data/js/highlight/languages/dns.js +0 -0
  1007. pygpt_net/data/js/highlight/languages/dns.min.js +0 -0
  1008. pygpt_net/data/js/highlight/languages/dockerfile.js +0 -0
  1009. pygpt_net/data/js/highlight/languages/dockerfile.min.js +0 -0
  1010. pygpt_net/data/js/highlight/languages/dos.js +0 -0
  1011. pygpt_net/data/js/highlight/languages/dos.min.js +0 -0
  1012. pygpt_net/data/js/highlight/languages/dsconfig.js +0 -0
  1013. pygpt_net/data/js/highlight/languages/dsconfig.min.js +0 -0
  1014. pygpt_net/data/js/highlight/languages/dts.js +0 -0
  1015. pygpt_net/data/js/highlight/languages/dts.min.js +0 -0
  1016. pygpt_net/data/js/highlight/languages/dust.js +0 -0
  1017. pygpt_net/data/js/highlight/languages/dust.min.js +0 -0
  1018. pygpt_net/data/js/highlight/languages/ebnf.js +0 -0
  1019. pygpt_net/data/js/highlight/languages/ebnf.min.js +0 -0
  1020. pygpt_net/data/js/highlight/languages/elixir.js +0 -0
  1021. pygpt_net/data/js/highlight/languages/elixir.min.js +0 -0
  1022. pygpt_net/data/js/highlight/languages/elm.js +0 -0
  1023. pygpt_net/data/js/highlight/languages/elm.min.js +0 -0
  1024. pygpt_net/data/js/highlight/languages/erb.js +0 -0
  1025. pygpt_net/data/js/highlight/languages/erb.min.js +0 -0
  1026. pygpt_net/data/js/highlight/languages/erlang-repl.js +0 -0
  1027. pygpt_net/data/js/highlight/languages/erlang-repl.min.js +0 -0
  1028. pygpt_net/data/js/highlight/languages/erlang.js +0 -0
  1029. pygpt_net/data/js/highlight/languages/erlang.min.js +0 -0
  1030. pygpt_net/data/js/highlight/languages/excel.js +0 -0
  1031. pygpt_net/data/js/highlight/languages/excel.min.js +0 -0
  1032. pygpt_net/data/js/highlight/languages/fix.js +0 -0
  1033. pygpt_net/data/js/highlight/languages/fix.min.js +0 -0
  1034. pygpt_net/data/js/highlight/languages/flix.js +0 -0
  1035. pygpt_net/data/js/highlight/languages/flix.min.js +0 -0
  1036. pygpt_net/data/js/highlight/languages/fortran.js +0 -0
  1037. pygpt_net/data/js/highlight/languages/fortran.min.js +0 -0
  1038. pygpt_net/data/js/highlight/languages/fsharp.js +0 -0
  1039. pygpt_net/data/js/highlight/languages/fsharp.min.js +0 -0
  1040. pygpt_net/data/js/highlight/languages/gams.js +0 -0
  1041. pygpt_net/data/js/highlight/languages/gams.min.js +0 -0
  1042. pygpt_net/data/js/highlight/languages/gauss.js +0 -0
  1043. pygpt_net/data/js/highlight/languages/gauss.min.js +0 -0
  1044. pygpt_net/data/js/highlight/languages/gcode.js +0 -0
  1045. pygpt_net/data/js/highlight/languages/gcode.min.js +0 -0
  1046. pygpt_net/data/js/highlight/languages/gherkin.js +0 -0
  1047. pygpt_net/data/js/highlight/languages/gherkin.min.js +0 -0
  1048. pygpt_net/data/js/highlight/languages/glsl.js +0 -0
  1049. pygpt_net/data/js/highlight/languages/glsl.min.js +0 -0
  1050. pygpt_net/data/js/highlight/languages/gml.js +0 -0
  1051. pygpt_net/data/js/highlight/languages/gml.min.js +0 -0
  1052. pygpt_net/data/js/highlight/languages/go.js +0 -0
  1053. pygpt_net/data/js/highlight/languages/go.min.js +0 -0
  1054. pygpt_net/data/js/highlight/languages/golo.js +0 -0
  1055. pygpt_net/data/js/highlight/languages/golo.min.js +0 -0
  1056. pygpt_net/data/js/highlight/languages/gradle.js +0 -0
  1057. pygpt_net/data/js/highlight/languages/gradle.min.js +0 -0
  1058. pygpt_net/data/js/highlight/languages/graphql.js +0 -0
  1059. pygpt_net/data/js/highlight/languages/graphql.min.js +0 -0
  1060. pygpt_net/data/js/highlight/languages/groovy.js +0 -0
  1061. pygpt_net/data/js/highlight/languages/groovy.min.js +0 -0
  1062. pygpt_net/data/js/highlight/languages/haml.js +0 -0
  1063. pygpt_net/data/js/highlight/languages/haml.min.js +0 -0
  1064. pygpt_net/data/js/highlight/languages/handlebars.js +0 -0
  1065. pygpt_net/data/js/highlight/languages/handlebars.min.js +0 -0
  1066. pygpt_net/data/js/highlight/languages/haskell.js +0 -0
  1067. pygpt_net/data/js/highlight/languages/haskell.min.js +0 -0
  1068. pygpt_net/data/js/highlight/languages/haxe.js +0 -0
  1069. pygpt_net/data/js/highlight/languages/haxe.min.js +0 -0
  1070. pygpt_net/data/js/highlight/languages/hsp.js +0 -0
  1071. pygpt_net/data/js/highlight/languages/hsp.min.js +0 -0
  1072. pygpt_net/data/js/highlight/languages/http.js +0 -0
  1073. pygpt_net/data/js/highlight/languages/http.min.js +0 -0
  1074. pygpt_net/data/js/highlight/languages/hy.js +0 -0
  1075. pygpt_net/data/js/highlight/languages/hy.min.js +0 -0
  1076. pygpt_net/data/js/highlight/languages/inform7.js +0 -0
  1077. pygpt_net/data/js/highlight/languages/inform7.min.js +0 -0
  1078. pygpt_net/data/js/highlight/languages/ini.js +0 -0
  1079. pygpt_net/data/js/highlight/languages/ini.min.js +0 -0
  1080. pygpt_net/data/js/highlight/languages/irpf90.js +0 -0
  1081. pygpt_net/data/js/highlight/languages/irpf90.min.js +0 -0
  1082. pygpt_net/data/js/highlight/languages/isbl.js +0 -0
  1083. pygpt_net/data/js/highlight/languages/isbl.min.js +0 -0
  1084. pygpt_net/data/js/highlight/languages/java.js +0 -0
  1085. pygpt_net/data/js/highlight/languages/java.min.js +0 -0
  1086. pygpt_net/data/js/highlight/languages/javascript.js +0 -0
  1087. pygpt_net/data/js/highlight/languages/javascript.min.js +0 -0
  1088. pygpt_net/data/js/highlight/languages/jboss-cli.js +0 -0
  1089. pygpt_net/data/js/highlight/languages/jboss-cli.min.js +0 -0
  1090. pygpt_net/data/js/highlight/languages/json.js +0 -0
  1091. pygpt_net/data/js/highlight/languages/json.min.js +0 -0
  1092. pygpt_net/data/js/highlight/languages/julia-repl.js +0 -0
  1093. pygpt_net/data/js/highlight/languages/julia-repl.min.js +0 -0
  1094. pygpt_net/data/js/highlight/languages/julia.js +0 -0
  1095. pygpt_net/data/js/highlight/languages/julia.min.js +0 -0
  1096. pygpt_net/data/js/highlight/languages/kotlin.js +0 -0
  1097. pygpt_net/data/js/highlight/languages/kotlin.min.js +0 -0
  1098. pygpt_net/data/js/highlight/languages/lasso.js +0 -0
  1099. pygpt_net/data/js/highlight/languages/lasso.min.js +0 -0
  1100. pygpt_net/data/js/highlight/languages/latex.js +0 -0
  1101. pygpt_net/data/js/highlight/languages/latex.min.js +0 -0
  1102. pygpt_net/data/js/highlight/languages/ldif.js +0 -0
  1103. pygpt_net/data/js/highlight/languages/ldif.min.js +0 -0
  1104. pygpt_net/data/js/highlight/languages/leaf.js +0 -0
  1105. pygpt_net/data/js/highlight/languages/leaf.min.js +0 -0
  1106. pygpt_net/data/js/highlight/languages/less.js +0 -0
  1107. pygpt_net/data/js/highlight/languages/less.min.js +0 -0
  1108. pygpt_net/data/js/highlight/languages/lisp.js +0 -0
  1109. pygpt_net/data/js/highlight/languages/lisp.min.js +0 -0
  1110. pygpt_net/data/js/highlight/languages/livecodeserver.js +0 -0
  1111. pygpt_net/data/js/highlight/languages/livecodeserver.min.js +0 -0
  1112. pygpt_net/data/js/highlight/languages/livescript.js +0 -0
  1113. pygpt_net/data/js/highlight/languages/livescript.min.js +0 -0
  1114. pygpt_net/data/js/highlight/languages/llvm.js +0 -0
  1115. pygpt_net/data/js/highlight/languages/llvm.min.js +0 -0
  1116. pygpt_net/data/js/highlight/languages/lsl.js +0 -0
  1117. pygpt_net/data/js/highlight/languages/lsl.min.js +0 -0
  1118. pygpt_net/data/js/highlight/languages/lua.js +0 -0
  1119. pygpt_net/data/js/highlight/languages/lua.min.js +0 -0
  1120. pygpt_net/data/js/highlight/languages/makefile.js +0 -0
  1121. pygpt_net/data/js/highlight/languages/makefile.min.js +0 -0
  1122. pygpt_net/data/js/highlight/languages/markdown.js +0 -0
  1123. pygpt_net/data/js/highlight/languages/markdown.min.js +0 -0
  1124. pygpt_net/data/js/highlight/languages/mathematica.js +0 -0
  1125. pygpt_net/data/js/highlight/languages/mathematica.min.js +0 -0
  1126. pygpt_net/data/js/highlight/languages/matlab.js +0 -0
  1127. pygpt_net/data/js/highlight/languages/matlab.min.js +0 -0
  1128. pygpt_net/data/js/highlight/languages/maxima.js +0 -0
  1129. pygpt_net/data/js/highlight/languages/maxima.min.js +0 -0
  1130. pygpt_net/data/js/highlight/languages/mel.js +0 -0
  1131. pygpt_net/data/js/highlight/languages/mel.min.js +0 -0
  1132. pygpt_net/data/js/highlight/languages/mercury.js +0 -0
  1133. pygpt_net/data/js/highlight/languages/mercury.min.js +0 -0
  1134. pygpt_net/data/js/highlight/languages/mipsasm.js +0 -0
  1135. pygpt_net/data/js/highlight/languages/mipsasm.min.js +0 -0
  1136. pygpt_net/data/js/highlight/languages/mizar.js +0 -0
  1137. pygpt_net/data/js/highlight/languages/mizar.min.js +0 -0
  1138. pygpt_net/data/js/highlight/languages/mojolicious.js +0 -0
  1139. pygpt_net/data/js/highlight/languages/mojolicious.min.js +0 -0
  1140. pygpt_net/data/js/highlight/languages/monkey.js +0 -0
  1141. pygpt_net/data/js/highlight/languages/monkey.min.js +0 -0
  1142. pygpt_net/data/js/highlight/languages/moonscript.js +0 -0
  1143. pygpt_net/data/js/highlight/languages/moonscript.min.js +0 -0
  1144. pygpt_net/data/js/highlight/languages/n1ql.js +0 -0
  1145. pygpt_net/data/js/highlight/languages/n1ql.min.js +0 -0
  1146. pygpt_net/data/js/highlight/languages/nestedtext.js +0 -0
  1147. pygpt_net/data/js/highlight/languages/nestedtext.min.js +0 -0
  1148. pygpt_net/data/js/highlight/languages/nginx.js +0 -0
  1149. pygpt_net/data/js/highlight/languages/nginx.min.js +0 -0
  1150. pygpt_net/data/js/highlight/languages/nim.js +0 -0
  1151. pygpt_net/data/js/highlight/languages/nim.min.js +0 -0
  1152. pygpt_net/data/js/highlight/languages/nix.js +0 -0
  1153. pygpt_net/data/js/highlight/languages/nix.min.js +0 -0
  1154. pygpt_net/data/js/highlight/languages/node-repl.js +0 -0
  1155. pygpt_net/data/js/highlight/languages/node-repl.min.js +0 -0
  1156. pygpt_net/data/js/highlight/languages/nsis.js +0 -0
  1157. pygpt_net/data/js/highlight/languages/nsis.min.js +0 -0
  1158. pygpt_net/data/js/highlight/languages/objectivec.js +0 -0
  1159. pygpt_net/data/js/highlight/languages/objectivec.min.js +0 -0
  1160. pygpt_net/data/js/highlight/languages/ocaml.js +0 -0
  1161. pygpt_net/data/js/highlight/languages/ocaml.min.js +0 -0
  1162. pygpt_net/data/js/highlight/languages/openscad.js +0 -0
  1163. pygpt_net/data/js/highlight/languages/openscad.min.js +0 -0
  1164. pygpt_net/data/js/highlight/languages/oxygene.js +0 -0
  1165. pygpt_net/data/js/highlight/languages/oxygene.min.js +0 -0
  1166. pygpt_net/data/js/highlight/languages/parser3.js +0 -0
  1167. pygpt_net/data/js/highlight/languages/parser3.min.js +0 -0
  1168. pygpt_net/data/js/highlight/languages/perl.js +0 -0
  1169. pygpt_net/data/js/highlight/languages/perl.min.js +0 -0
  1170. pygpt_net/data/js/highlight/languages/pf.js +0 -0
  1171. pygpt_net/data/js/highlight/languages/pf.min.js +0 -0
  1172. pygpt_net/data/js/highlight/languages/pgsql.js +0 -0
  1173. pygpt_net/data/js/highlight/languages/pgsql.min.js +0 -0
  1174. pygpt_net/data/js/highlight/languages/php-template.js +0 -0
  1175. pygpt_net/data/js/highlight/languages/php-template.min.js +0 -0
  1176. pygpt_net/data/js/highlight/languages/php.js +0 -0
  1177. pygpt_net/data/js/highlight/languages/php.min.js +0 -0
  1178. pygpt_net/data/js/highlight/languages/plaintext.js +0 -0
  1179. pygpt_net/data/js/highlight/languages/plaintext.min.js +0 -0
  1180. pygpt_net/data/js/highlight/languages/pony.js +0 -0
  1181. pygpt_net/data/js/highlight/languages/pony.min.js +0 -0
  1182. pygpt_net/data/js/highlight/languages/powershell.js +0 -0
  1183. pygpt_net/data/js/highlight/languages/powershell.min.js +0 -0
  1184. pygpt_net/data/js/highlight/languages/processing.js +0 -0
  1185. pygpt_net/data/js/highlight/languages/processing.min.js +0 -0
  1186. pygpt_net/data/js/highlight/languages/profile.js +0 -0
  1187. pygpt_net/data/js/highlight/languages/profile.min.js +0 -0
  1188. pygpt_net/data/js/highlight/languages/prolog.js +0 -0
  1189. pygpt_net/data/js/highlight/languages/prolog.min.js +0 -0
  1190. pygpt_net/data/js/highlight/languages/properties.js +0 -0
  1191. pygpt_net/data/js/highlight/languages/properties.min.js +0 -0
  1192. pygpt_net/data/js/highlight/languages/protobuf.js +0 -0
  1193. pygpt_net/data/js/highlight/languages/protobuf.min.js +0 -0
  1194. pygpt_net/data/js/highlight/languages/puppet.js +0 -0
  1195. pygpt_net/data/js/highlight/languages/puppet.min.js +0 -0
  1196. pygpt_net/data/js/highlight/languages/purebasic.js +0 -0
  1197. pygpt_net/data/js/highlight/languages/purebasic.min.js +0 -0
  1198. pygpt_net/data/js/highlight/languages/python-repl.js +0 -0
  1199. pygpt_net/data/js/highlight/languages/python-repl.min.js +0 -0
  1200. pygpt_net/data/js/highlight/languages/python.js +0 -0
  1201. pygpt_net/data/js/highlight/languages/python.min.js +0 -0
  1202. pygpt_net/data/js/highlight/languages/q.js +0 -0
  1203. pygpt_net/data/js/highlight/languages/q.min.js +0 -0
  1204. pygpt_net/data/js/highlight/languages/qml.js +0 -0
  1205. pygpt_net/data/js/highlight/languages/qml.min.js +0 -0
  1206. pygpt_net/data/js/highlight/languages/r.js +0 -0
  1207. pygpt_net/data/js/highlight/languages/r.min.js +0 -0
  1208. pygpt_net/data/js/highlight/languages/reasonml.js +0 -0
  1209. pygpt_net/data/js/highlight/languages/reasonml.min.js +0 -0
  1210. pygpt_net/data/js/highlight/languages/rib.js +0 -0
  1211. pygpt_net/data/js/highlight/languages/rib.min.js +0 -0
  1212. pygpt_net/data/js/highlight/languages/roboconf.js +0 -0
  1213. pygpt_net/data/js/highlight/languages/roboconf.min.js +0 -0
  1214. pygpt_net/data/js/highlight/languages/routeros.js +0 -0
  1215. pygpt_net/data/js/highlight/languages/routeros.min.js +0 -0
  1216. pygpt_net/data/js/highlight/languages/rsl.js +0 -0
  1217. pygpt_net/data/js/highlight/languages/rsl.min.js +0 -0
  1218. pygpt_net/data/js/highlight/languages/ruby.js +0 -0
  1219. pygpt_net/data/js/highlight/languages/ruby.min.js +0 -0
  1220. pygpt_net/data/js/highlight/languages/ruleslanguage.js +0 -0
  1221. pygpt_net/data/js/highlight/languages/ruleslanguage.min.js +0 -0
  1222. pygpt_net/data/js/highlight/languages/rust.js +0 -0
  1223. pygpt_net/data/js/highlight/languages/rust.min.js +0 -0
  1224. pygpt_net/data/js/highlight/languages/sas.js +0 -0
  1225. pygpt_net/data/js/highlight/languages/sas.min.js +0 -0
  1226. pygpt_net/data/js/highlight/languages/scala.js +0 -0
  1227. pygpt_net/data/js/highlight/languages/scala.min.js +0 -0
  1228. pygpt_net/data/js/highlight/languages/scheme.js +0 -0
  1229. pygpt_net/data/js/highlight/languages/scheme.min.js +0 -0
  1230. pygpt_net/data/js/highlight/languages/scilab.js +0 -0
  1231. pygpt_net/data/js/highlight/languages/scilab.min.js +0 -0
  1232. pygpt_net/data/js/highlight/languages/scss.js +0 -0
  1233. pygpt_net/data/js/highlight/languages/scss.min.js +0 -0
  1234. pygpt_net/data/js/highlight/languages/shell.js +0 -0
  1235. pygpt_net/data/js/highlight/languages/shell.min.js +0 -0
  1236. pygpt_net/data/js/highlight/languages/smali.js +0 -0
  1237. pygpt_net/data/js/highlight/languages/smali.min.js +0 -0
  1238. pygpt_net/data/js/highlight/languages/smalltalk.js +0 -0
  1239. pygpt_net/data/js/highlight/languages/smalltalk.min.js +0 -0
  1240. pygpt_net/data/js/highlight/languages/sml.js +0 -0
  1241. pygpt_net/data/js/highlight/languages/sml.min.js +0 -0
  1242. pygpt_net/data/js/highlight/languages/sqf.js +0 -0
  1243. pygpt_net/data/js/highlight/languages/sqf.min.js +0 -0
  1244. pygpt_net/data/js/highlight/languages/sql.js +0 -0
  1245. pygpt_net/data/js/highlight/languages/sql.min.js +0 -0
  1246. pygpt_net/data/js/highlight/languages/stan.js +0 -0
  1247. pygpt_net/data/js/highlight/languages/stan.min.js +0 -0
  1248. pygpt_net/data/js/highlight/languages/stata.js +0 -0
  1249. pygpt_net/data/js/highlight/languages/stata.min.js +0 -0
  1250. pygpt_net/data/js/highlight/languages/step21.js +0 -0
  1251. pygpt_net/data/js/highlight/languages/step21.min.js +0 -0
  1252. pygpt_net/data/js/highlight/languages/stylus.js +0 -0
  1253. pygpt_net/data/js/highlight/languages/stylus.min.js +0 -0
  1254. pygpt_net/data/js/highlight/languages/subunit.js +0 -0
  1255. pygpt_net/data/js/highlight/languages/subunit.min.js +0 -0
  1256. pygpt_net/data/js/highlight/languages/swift.js +0 -0
  1257. pygpt_net/data/js/highlight/languages/swift.min.js +0 -0
  1258. pygpt_net/data/js/highlight/languages/taggerscript.js +0 -0
  1259. pygpt_net/data/js/highlight/languages/taggerscript.min.js +0 -0
  1260. pygpt_net/data/js/highlight/languages/tap.js +0 -0
  1261. pygpt_net/data/js/highlight/languages/tap.min.js +0 -0
  1262. pygpt_net/data/js/highlight/languages/tcl.js +0 -0
  1263. pygpt_net/data/js/highlight/languages/tcl.min.js +0 -0
  1264. pygpt_net/data/js/highlight/languages/thrift.js +0 -0
  1265. pygpt_net/data/js/highlight/languages/thrift.min.js +0 -0
  1266. pygpt_net/data/js/highlight/languages/tp.js +0 -0
  1267. pygpt_net/data/js/highlight/languages/tp.min.js +0 -0
  1268. pygpt_net/data/js/highlight/languages/twig.js +0 -0
  1269. pygpt_net/data/js/highlight/languages/twig.min.js +0 -0
  1270. pygpt_net/data/js/highlight/languages/typescript.js +0 -0
  1271. pygpt_net/data/js/highlight/languages/typescript.min.js +0 -0
  1272. pygpt_net/data/js/highlight/languages/vala.js +0 -0
  1273. pygpt_net/data/js/highlight/languages/vala.min.js +0 -0
  1274. pygpt_net/data/js/highlight/languages/vbnet.js +0 -0
  1275. pygpt_net/data/js/highlight/languages/vbnet.min.js +0 -0
  1276. pygpt_net/data/js/highlight/languages/vbscript-html.js +0 -0
  1277. pygpt_net/data/js/highlight/languages/vbscript-html.min.js +0 -0
  1278. pygpt_net/data/js/highlight/languages/vbscript.js +0 -0
  1279. pygpt_net/data/js/highlight/languages/vbscript.min.js +0 -0
  1280. pygpt_net/data/js/highlight/languages/verilog.js +0 -0
  1281. pygpt_net/data/js/highlight/languages/verilog.min.js +0 -0
  1282. pygpt_net/data/js/highlight/languages/vhdl.js +0 -0
  1283. pygpt_net/data/js/highlight/languages/vhdl.min.js +0 -0
  1284. pygpt_net/data/js/highlight/languages/vim.js +0 -0
  1285. pygpt_net/data/js/highlight/languages/vim.min.js +0 -0
  1286. pygpt_net/data/js/highlight/languages/wasm.js +0 -0
  1287. pygpt_net/data/js/highlight/languages/wasm.min.js +0 -0
  1288. pygpt_net/data/js/highlight/languages/wren.js +0 -0
  1289. pygpt_net/data/js/highlight/languages/wren.min.js +0 -0
  1290. pygpt_net/data/js/highlight/languages/x86asm.js +0 -0
  1291. pygpt_net/data/js/highlight/languages/x86asm.min.js +0 -0
  1292. pygpt_net/data/js/highlight/languages/xl.js +0 -0
  1293. pygpt_net/data/js/highlight/languages/xl.min.js +0 -0
  1294. pygpt_net/data/js/highlight/languages/xml.js +0 -0
  1295. pygpt_net/data/js/highlight/languages/xml.min.js +0 -0
  1296. pygpt_net/data/js/highlight/languages/xquery.js +0 -0
  1297. pygpt_net/data/js/highlight/languages/xquery.min.js +0 -0
  1298. pygpt_net/data/js/highlight/languages/yaml.js +0 -0
  1299. pygpt_net/data/js/highlight/languages/yaml.min.js +0 -0
  1300. pygpt_net/data/js/highlight/languages/zephir.js +0 -0
  1301. pygpt_net/data/js/highlight/languages/zephir.min.js +0 -0
  1302. pygpt_net/data/js/highlight/package.json +0 -0
  1303. pygpt_net/data/js/highlight/styles/1c-light.css +0 -0
  1304. pygpt_net/data/js/highlight/styles/1c-light.min.css +0 -0
  1305. pygpt_net/data/js/highlight/styles/a11y-dark.css +0 -0
  1306. pygpt_net/data/js/highlight/styles/a11y-dark.min.css +0 -0
  1307. pygpt_net/data/js/highlight/styles/a11y-light.css +0 -0
  1308. pygpt_net/data/js/highlight/styles/a11y-light.min.css +0 -0
  1309. pygpt_net/data/js/highlight/styles/agate.css +0 -0
  1310. pygpt_net/data/js/highlight/styles/agate.min.css +0 -0
  1311. pygpt_net/data/js/highlight/styles/an-old-hope.css +0 -0
  1312. pygpt_net/data/js/highlight/styles/an-old-hope.min.css +0 -0
  1313. pygpt_net/data/js/highlight/styles/androidstudio.css +0 -0
  1314. pygpt_net/data/js/highlight/styles/androidstudio.min.css +0 -0
  1315. pygpt_net/data/js/highlight/styles/arduino-light.css +0 -0
  1316. pygpt_net/data/js/highlight/styles/arduino-light.min.css +0 -0
  1317. pygpt_net/data/js/highlight/styles/arta.css +0 -0
  1318. pygpt_net/data/js/highlight/styles/arta.min.css +0 -0
  1319. pygpt_net/data/js/highlight/styles/ascetic.css +0 -0
  1320. pygpt_net/data/js/highlight/styles/ascetic.min.css +0 -0
  1321. pygpt_net/data/js/highlight/styles/atom-one-dark-reasonable.css +0 -0
  1322. pygpt_net/data/js/highlight/styles/atom-one-dark-reasonable.min.css +0 -0
  1323. pygpt_net/data/js/highlight/styles/atom-one-dark.css +0 -0
  1324. pygpt_net/data/js/highlight/styles/atom-one-dark.min.css +0 -0
  1325. pygpt_net/data/js/highlight/styles/atom-one-light.css +0 -0
  1326. pygpt_net/data/js/highlight/styles/atom-one-light.min.css +0 -0
  1327. pygpt_net/data/js/highlight/styles/brown-paper.css +0 -0
  1328. pygpt_net/data/js/highlight/styles/brown-paper.min.css +0 -0
  1329. pygpt_net/data/js/highlight/styles/brown-papersq.png +0 -0
  1330. pygpt_net/data/js/highlight/styles/codepen-embed.css +0 -0
  1331. pygpt_net/data/js/highlight/styles/codepen-embed.min.css +0 -0
  1332. pygpt_net/data/js/highlight/styles/codeschool.css +0 -0
  1333. pygpt_net/data/js/highlight/styles/codeschool.min.css +0 -0
  1334. pygpt_net/data/js/highlight/styles/color-brewer.css +0 -0
  1335. pygpt_net/data/js/highlight/styles/color-brewer.min.css +0 -0
  1336. pygpt_net/data/js/highlight/styles/darcula.css +0 -0
  1337. pygpt_net/data/js/highlight/styles/darcula.min.css +0 -0
  1338. pygpt_net/data/js/highlight/styles/dark.css +0 -0
  1339. pygpt_net/data/js/highlight/styles/dark.min.css +0 -0
  1340. pygpt_net/data/js/highlight/styles/default-dark.css +0 -0
  1341. pygpt_net/data/js/highlight/styles/default-dark.min.css +0 -0
  1342. pygpt_net/data/js/highlight/styles/default-light.css +0 -0
  1343. pygpt_net/data/js/highlight/styles/default-light.min.css +0 -0
  1344. pygpt_net/data/js/highlight/styles/default.css +0 -0
  1345. pygpt_net/data/js/highlight/styles/default.min.css +0 -0
  1346. pygpt_net/data/js/highlight/styles/devibeans.css +0 -0
  1347. pygpt_net/data/js/highlight/styles/devibeans.min.css +0 -0
  1348. pygpt_net/data/js/highlight/styles/docco.css +0 -0
  1349. pygpt_net/data/js/highlight/styles/docco.min.css +0 -0
  1350. pygpt_net/data/js/highlight/styles/far.css +0 -0
  1351. pygpt_net/data/js/highlight/styles/far.min.css +0 -0
  1352. pygpt_net/data/js/highlight/styles/felipec.css +0 -0
  1353. pygpt_net/data/js/highlight/styles/felipec.min.css +0 -0
  1354. pygpt_net/data/js/highlight/styles/foundation.css +0 -0
  1355. pygpt_net/data/js/highlight/styles/foundation.min.css +0 -0
  1356. pygpt_net/data/js/highlight/styles/github-dark-dimmed.css +0 -0
  1357. pygpt_net/data/js/highlight/styles/github-dark-dimmed.min.css +0 -0
  1358. pygpt_net/data/js/highlight/styles/github-dark.css +0 -0
  1359. pygpt_net/data/js/highlight/styles/github-dark.min.css +0 -0
  1360. pygpt_net/data/js/highlight/styles/github.css +0 -0
  1361. pygpt_net/data/js/highlight/styles/github.min.css +0 -0
  1362. pygpt_net/data/js/highlight/styles/gml.css +0 -0
  1363. pygpt_net/data/js/highlight/styles/gml.min.css +0 -0
  1364. pygpt_net/data/js/highlight/styles/googlecode.css +0 -0
  1365. pygpt_net/data/js/highlight/styles/googlecode.min.css +0 -0
  1366. pygpt_net/data/js/highlight/styles/gradient-dark.css +0 -0
  1367. pygpt_net/data/js/highlight/styles/gradient-dark.min.css +0 -0
  1368. pygpt_net/data/js/highlight/styles/gradient-light.css +0 -0
  1369. pygpt_net/data/js/highlight/styles/gradient-light.min.css +0 -0
  1370. pygpt_net/data/js/highlight/styles/grayscale.css +0 -0
  1371. pygpt_net/data/js/highlight/styles/grayscale.min.css +0 -0
  1372. pygpt_net/data/js/highlight/styles/hybrid.css +0 -0
  1373. pygpt_net/data/js/highlight/styles/hybrid.min.css +0 -0
  1374. pygpt_net/data/js/highlight/styles/idea.css +0 -0
  1375. pygpt_net/data/js/highlight/styles/idea.min.css +0 -0
  1376. pygpt_net/data/js/highlight/styles/intellij-light.css +0 -0
  1377. pygpt_net/data/js/highlight/styles/intellij-light.min.css +0 -0
  1378. pygpt_net/data/js/highlight/styles/ir-black.css +0 -0
  1379. pygpt_net/data/js/highlight/styles/ir-black.min.css +0 -0
  1380. pygpt_net/data/js/highlight/styles/isbl-editor-dark.css +0 -0
  1381. pygpt_net/data/js/highlight/styles/isbl-editor-dark.min.css +0 -0
  1382. pygpt_net/data/js/highlight/styles/isbl-editor-light.css +0 -0
  1383. pygpt_net/data/js/highlight/styles/isbl-editor-light.min.css +0 -0
  1384. pygpt_net/data/js/highlight/styles/kimbie-dark.css +0 -0
  1385. pygpt_net/data/js/highlight/styles/kimbie-dark.min.css +0 -0
  1386. pygpt_net/data/js/highlight/styles/kimbie-light.css +0 -0
  1387. pygpt_net/data/js/highlight/styles/kimbie-light.min.css +0 -0
  1388. pygpt_net/data/js/highlight/styles/lightfair.css +0 -0
  1389. pygpt_net/data/js/highlight/styles/lightfair.min.css +0 -0
  1390. pygpt_net/data/js/highlight/styles/lioshi.css +0 -0
  1391. pygpt_net/data/js/highlight/styles/lioshi.min.css +0 -0
  1392. pygpt_net/data/js/highlight/styles/magula.css +0 -0
  1393. pygpt_net/data/js/highlight/styles/magula.min.css +0 -0
  1394. pygpt_net/data/js/highlight/styles/material-darker.css +0 -0
  1395. pygpt_net/data/js/highlight/styles/material-darker.min.css +0 -0
  1396. pygpt_net/data/js/highlight/styles/material-lighter.css +0 -0
  1397. pygpt_net/data/js/highlight/styles/material-lighter.min.css +0 -0
  1398. pygpt_net/data/js/highlight/styles/material-palenight.css +0 -0
  1399. pygpt_net/data/js/highlight/styles/material-palenight.min.css +0 -0
  1400. pygpt_net/data/js/highlight/styles/material-vivid.css +0 -0
  1401. pygpt_net/data/js/highlight/styles/material-vivid.min.css +0 -0
  1402. pygpt_net/data/js/highlight/styles/material.css +0 -0
  1403. pygpt_net/data/js/highlight/styles/material.min.css +0 -0
  1404. pygpt_net/data/js/highlight/styles/mono-blue.css +0 -0
  1405. pygpt_net/data/js/highlight/styles/mono-blue.min.css +0 -0
  1406. pygpt_net/data/js/highlight/styles/monokai-sublime.css +0 -0
  1407. pygpt_net/data/js/highlight/styles/monokai-sublime.min.css +0 -0
  1408. pygpt_net/data/js/highlight/styles/monokai.css +0 -0
  1409. pygpt_net/data/js/highlight/styles/monokai.min.css +0 -0
  1410. pygpt_net/data/js/highlight/styles/night-owl.css +0 -0
  1411. pygpt_net/data/js/highlight/styles/night-owl.min.css +0 -0
  1412. pygpt_net/data/js/highlight/styles/nnfx-dark.css +0 -0
  1413. pygpt_net/data/js/highlight/styles/nnfx-dark.min.css +0 -0
  1414. pygpt_net/data/js/highlight/styles/nnfx-light.css +0 -0
  1415. pygpt_net/data/js/highlight/styles/nnfx-light.min.css +0 -0
  1416. pygpt_net/data/js/highlight/styles/nord.css +0 -0
  1417. pygpt_net/data/js/highlight/styles/nord.min.css +0 -0
  1418. pygpt_net/data/js/highlight/styles/obsidian.css +0 -0
  1419. pygpt_net/data/js/highlight/styles/obsidian.min.css +0 -0
  1420. pygpt_net/data/js/highlight/styles/panda-syntax-dark.css +0 -0
  1421. pygpt_net/data/js/highlight/styles/panda-syntax-dark.min.css +0 -0
  1422. pygpt_net/data/js/highlight/styles/panda-syntax-light.css +0 -0
  1423. pygpt_net/data/js/highlight/styles/panda-syntax-light.min.css +0 -0
  1424. pygpt_net/data/js/highlight/styles/paraiso-dark.css +0 -0
  1425. pygpt_net/data/js/highlight/styles/paraiso-dark.min.css +0 -0
  1426. pygpt_net/data/js/highlight/styles/paraiso-light.css +0 -0
  1427. pygpt_net/data/js/highlight/styles/paraiso-light.min.css +0 -0
  1428. pygpt_net/data/js/highlight/styles/pojoaque.css +0 -0
  1429. pygpt_net/data/js/highlight/styles/pojoaque.jpg +0 -0
  1430. pygpt_net/data/js/highlight/styles/pojoaque.min.css +0 -0
  1431. pygpt_net/data/js/highlight/styles/purebasic.css +0 -0
  1432. pygpt_net/data/js/highlight/styles/purebasic.min.css +0 -0
  1433. pygpt_net/data/js/highlight/styles/qtcreator-dark.css +0 -0
  1434. pygpt_net/data/js/highlight/styles/qtcreator-dark.min.css +0 -0
  1435. pygpt_net/data/js/highlight/styles/qtcreator-light.css +0 -0
  1436. pygpt_net/data/js/highlight/styles/qtcreator-light.min.css +0 -0
  1437. pygpt_net/data/js/highlight/styles/rainbow.css +0 -0
  1438. pygpt_net/data/js/highlight/styles/rainbow.min.css +0 -0
  1439. pygpt_net/data/js/highlight/styles/routeros.css +0 -0
  1440. pygpt_net/data/js/highlight/styles/routeros.min.css +0 -0
  1441. pygpt_net/data/js/highlight/styles/school-book.css +0 -0
  1442. pygpt_net/data/js/highlight/styles/school-book.min.css +0 -0
  1443. pygpt_net/data/js/highlight/styles/shades-of-purple.css +0 -0
  1444. pygpt_net/data/js/highlight/styles/shades-of-purple.min.css +0 -0
  1445. pygpt_net/data/js/highlight/styles/srcery.css +0 -0
  1446. pygpt_net/data/js/highlight/styles/srcery.min.css +0 -0
  1447. pygpt_net/data/js/highlight/styles/stackoverflow-dark.css +0 -0
  1448. pygpt_net/data/js/highlight/styles/stackoverflow-dark.min.css +0 -0
  1449. pygpt_net/data/js/highlight/styles/stackoverflow-light.css +0 -0
  1450. pygpt_net/data/js/highlight/styles/stackoverflow-light.min.css +0 -0
  1451. pygpt_net/data/js/highlight/styles/sunburst.css +0 -0
  1452. pygpt_net/data/js/highlight/styles/sunburst.min.css +0 -0
  1453. pygpt_net/data/js/highlight/styles/tokyo-night-dark.css +0 -0
  1454. pygpt_net/data/js/highlight/styles/tokyo-night-dark.min.css +0 -0
  1455. pygpt_net/data/js/highlight/styles/tokyo-night-light.css +0 -0
  1456. pygpt_net/data/js/highlight/styles/tokyo-night-light.min.css +0 -0
  1457. pygpt_net/data/js/highlight/styles/tomorrow-night-blue.css +0 -0
  1458. pygpt_net/data/js/highlight/styles/tomorrow-night-blue.min.css +0 -0
  1459. pygpt_net/data/js/highlight/styles/tomorrow-night-bright.css +0 -0
  1460. pygpt_net/data/js/highlight/styles/tomorrow-night-bright.min.css +0 -0
  1461. pygpt_net/data/js/highlight/styles/vs.css +0 -0
  1462. pygpt_net/data/js/highlight/styles/vs.min.css +0 -0
  1463. pygpt_net/data/js/highlight/styles/vs2015.css +0 -0
  1464. pygpt_net/data/js/highlight/styles/vs2015.min.css +0 -0
  1465. pygpt_net/data/js/highlight/styles/windows-10-light.css +0 -0
  1466. pygpt_net/data/js/highlight/styles/windows-10-light.min.css +0 -0
  1467. pygpt_net/data/js/highlight/styles/windows-10.css +0 -0
  1468. pygpt_net/data/js/highlight/styles/windows-10.min.css +0 -0
  1469. pygpt_net/data/js/highlight/styles/xcode.css +0 -0
  1470. pygpt_net/data/js/highlight/styles/xcode.min.css +0 -0
  1471. pygpt_net/data/js/highlight/styles/xt256.css +0 -0
  1472. pygpt_net/data/js/highlight/styles/xt256.min.css +0 -0
  1473. pygpt_net/data/js/katex/auto-render.min.js +0 -0
  1474. pygpt_net/data/js/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
  1475. pygpt_net/data/js/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
  1476. pygpt_net/data/js/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  1477. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  1478. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  1479. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  1480. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  1481. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  1482. pygpt_net/data/js/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  1483. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  1484. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  1485. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  1486. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  1487. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  1488. pygpt_net/data/js/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  1489. pygpt_net/data/js/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
  1490. pygpt_net/data/js/katex/fonts/KaTeX_Main-Bold.woff +0 -0
  1491. pygpt_net/data/js/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  1492. pygpt_net/data/js/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  1493. pygpt_net/data/js/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  1494. pygpt_net/data/js/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  1495. pygpt_net/data/js/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
  1496. pygpt_net/data/js/katex/fonts/KaTeX_Main-Italic.woff +0 -0
  1497. pygpt_net/data/js/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  1498. pygpt_net/data/js/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
  1499. pygpt_net/data/js/katex/fonts/KaTeX_Main-Regular.woff +0 -0
  1500. pygpt_net/data/js/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  1501. pygpt_net/data/js/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  1502. pygpt_net/data/js/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  1503. pygpt_net/data/js/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  1504. pygpt_net/data/js/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
  1505. pygpt_net/data/js/katex/fonts/KaTeX_Math-Italic.woff +0 -0
  1506. pygpt_net/data/js/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  1507. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  1508. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  1509. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  1510. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  1511. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  1512. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  1513. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  1514. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  1515. pygpt_net/data/js/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  1516. pygpt_net/data/js/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
  1517. pygpt_net/data/js/katex/fonts/KaTeX_Script-Regular.woff +0 -0
  1518. pygpt_net/data/js/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  1519. pygpt_net/data/js/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
  1520. pygpt_net/data/js/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
  1521. pygpt_net/data/js/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  1522. pygpt_net/data/js/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
  1523. pygpt_net/data/js/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
  1524. pygpt_net/data/js/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  1525. pygpt_net/data/js/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
  1526. pygpt_net/data/js/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
  1527. pygpt_net/data/js/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  1528. pygpt_net/data/js/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
  1529. pygpt_net/data/js/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
  1530. pygpt_net/data/js/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  1531. pygpt_net/data/js/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  1532. pygpt_net/data/js/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  1533. pygpt_net/data/js/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  1534. pygpt_net/data/js/katex/katex.min.css +0 -0
  1535. pygpt_net/data/js/katex/katex.min.js +0 -0
  1536. pygpt_net/data/js/markdown-it/markdown-it-katex.min.js +8 -0
  1537. pygpt_net/data/js/markdown-it/markdown-it.min.js +2 -0
  1538. pygpt_net/data/languages.csv +0 -0
  1539. pygpt_net/data/locale/locale.de.ini +0 -0
  1540. pygpt_net/data/locale/locale.en.ini +4 -0
  1541. pygpt_net/data/locale/locale.es.ini +0 -0
  1542. pygpt_net/data/locale/locale.fr.ini +0 -0
  1543. pygpt_net/data/locale/locale.it.ini +0 -0
  1544. pygpt_net/data/locale/locale.pl.ini +0 -0
  1545. pygpt_net/data/locale/locale.uk.ini +0 -0
  1546. pygpt_net/data/locale/locale.zh.ini +0 -0
  1547. pygpt_net/data/locale/plugin.agent.de.ini +0 -0
  1548. pygpt_net/data/locale/plugin.agent.en.ini +0 -0
  1549. pygpt_net/data/locale/plugin.agent.es.ini +0 -0
  1550. pygpt_net/data/locale/plugin.agent.fr.ini +0 -0
  1551. pygpt_net/data/locale/plugin.agent.it.ini +0 -0
  1552. pygpt_net/data/locale/plugin.agent.pl.ini +0 -0
  1553. pygpt_net/data/locale/plugin.agent.uk.ini +0 -0
  1554. pygpt_net/data/locale/plugin.agent.zh.ini +0 -0
  1555. pygpt_net/data/locale/plugin.audio_input.de.ini +0 -0
  1556. pygpt_net/data/locale/plugin.audio_input.en.ini +0 -0
  1557. pygpt_net/data/locale/plugin.audio_input.es.ini +0 -0
  1558. pygpt_net/data/locale/plugin.audio_input.fr.ini +0 -0
  1559. pygpt_net/data/locale/plugin.audio_input.it.ini +0 -0
  1560. pygpt_net/data/locale/plugin.audio_input.pl.ini +0 -0
  1561. pygpt_net/data/locale/plugin.audio_input.uk.ini +0 -0
  1562. pygpt_net/data/locale/plugin.audio_input.zh.ini +0 -0
  1563. pygpt_net/data/locale/plugin.audio_output.de.ini +0 -0
  1564. pygpt_net/data/locale/plugin.audio_output.en.ini +0 -0
  1565. pygpt_net/data/locale/plugin.audio_output.es.ini +0 -0
  1566. pygpt_net/data/locale/plugin.audio_output.fr.ini +0 -0
  1567. pygpt_net/data/locale/plugin.audio_output.it.ini +0 -0
  1568. pygpt_net/data/locale/plugin.audio_output.pl.ini +0 -0
  1569. pygpt_net/data/locale/plugin.audio_output.uk.ini +0 -0
  1570. pygpt_net/data/locale/plugin.audio_output.zh.ini +0 -0
  1571. pygpt_net/data/locale/plugin.cmd_api.de.ini +0 -0
  1572. pygpt_net/data/locale/plugin.cmd_api.en.ini +0 -0
  1573. pygpt_net/data/locale/plugin.cmd_api.es.ini +0 -0
  1574. pygpt_net/data/locale/plugin.cmd_api.fr.ini +0 -0
  1575. pygpt_net/data/locale/plugin.cmd_api.it.ini +0 -0
  1576. pygpt_net/data/locale/plugin.cmd_api.pl.ini +0 -0
  1577. pygpt_net/data/locale/plugin.cmd_api.uk.ini +0 -0
  1578. pygpt_net/data/locale/plugin.cmd_api.zh.ini +0 -0
  1579. pygpt_net/data/locale/plugin.cmd_code_interpreter.de.ini +0 -0
  1580. pygpt_net/data/locale/plugin.cmd_code_interpreter.en.ini +0 -0
  1581. pygpt_net/data/locale/plugin.cmd_code_interpreter.es.ini +0 -0
  1582. pygpt_net/data/locale/plugin.cmd_code_interpreter.fr.ini +0 -0
  1583. pygpt_net/data/locale/plugin.cmd_code_interpreter.it.ini +0 -0
  1584. pygpt_net/data/locale/plugin.cmd_code_interpreter.pl.ini +0 -0
  1585. pygpt_net/data/locale/plugin.cmd_code_interpreter.uk.ini +0 -0
  1586. pygpt_net/data/locale/plugin.cmd_code_interpreter.zh.ini +0 -0
  1587. pygpt_net/data/locale/plugin.cmd_custom.de.ini +0 -0
  1588. pygpt_net/data/locale/plugin.cmd_custom.en.ini +0 -0
  1589. pygpt_net/data/locale/plugin.cmd_custom.es.ini +0 -0
  1590. pygpt_net/data/locale/plugin.cmd_custom.fr.ini +0 -0
  1591. pygpt_net/data/locale/plugin.cmd_custom.it.ini +0 -0
  1592. pygpt_net/data/locale/plugin.cmd_custom.pl.ini +0 -0
  1593. pygpt_net/data/locale/plugin.cmd_custom.uk.ini +0 -0
  1594. pygpt_net/data/locale/plugin.cmd_custom.zh.ini +0 -0
  1595. pygpt_net/data/locale/plugin.cmd_files.de.ini +0 -0
  1596. pygpt_net/data/locale/plugin.cmd_files.en.ini +0 -0
  1597. pygpt_net/data/locale/plugin.cmd_files.es.ini +0 -0
  1598. pygpt_net/data/locale/plugin.cmd_files.fr.ini +0 -0
  1599. pygpt_net/data/locale/plugin.cmd_files.it.ini +0 -0
  1600. pygpt_net/data/locale/plugin.cmd_files.pl.ini +0 -0
  1601. pygpt_net/data/locale/plugin.cmd_files.uk.ini +0 -0
  1602. pygpt_net/data/locale/plugin.cmd_files.zh.ini +0 -0
  1603. pygpt_net/data/locale/plugin.cmd_history.de.ini +0 -0
  1604. pygpt_net/data/locale/plugin.cmd_history.en.ini +0 -0
  1605. pygpt_net/data/locale/plugin.cmd_history.es.ini +0 -0
  1606. pygpt_net/data/locale/plugin.cmd_history.fr.ini +0 -0
  1607. pygpt_net/data/locale/plugin.cmd_history.it.ini +0 -0
  1608. pygpt_net/data/locale/plugin.cmd_history.pl.ini +0 -0
  1609. pygpt_net/data/locale/plugin.cmd_history.uk.ini +0 -0
  1610. pygpt_net/data/locale/plugin.cmd_history.zh.ini +0 -0
  1611. pygpt_net/data/locale/plugin.cmd_mouse_control.de.ini +0 -0
  1612. pygpt_net/data/locale/plugin.cmd_mouse_control.en.ini +0 -0
  1613. pygpt_net/data/locale/plugin.cmd_mouse_control.es.ini +0 -0
  1614. pygpt_net/data/locale/plugin.cmd_mouse_control.fr.ini +0 -0
  1615. pygpt_net/data/locale/plugin.cmd_mouse_control.it.ini +0 -0
  1616. pygpt_net/data/locale/plugin.cmd_mouse_control.pl.ini +0 -0
  1617. pygpt_net/data/locale/plugin.cmd_mouse_control.uk.ini +0 -0
  1618. pygpt_net/data/locale/plugin.cmd_mouse_control.zh.ini +0 -0
  1619. pygpt_net/data/locale/plugin.cmd_serial.de.ini +0 -0
  1620. pygpt_net/data/locale/plugin.cmd_serial.en.ini +0 -0
  1621. pygpt_net/data/locale/plugin.cmd_serial.es.ini +0 -0
  1622. pygpt_net/data/locale/plugin.cmd_serial.fr.ini +0 -0
  1623. pygpt_net/data/locale/plugin.cmd_serial.it.ini +0 -0
  1624. pygpt_net/data/locale/plugin.cmd_serial.pl.ini +0 -0
  1625. pygpt_net/data/locale/plugin.cmd_serial.uk.ini +0 -0
  1626. pygpt_net/data/locale/plugin.cmd_serial.zh.ini +0 -0
  1627. pygpt_net/data/locale/plugin.cmd_system.de.ini +0 -0
  1628. pygpt_net/data/locale/plugin.cmd_system.en.ini +0 -0
  1629. pygpt_net/data/locale/plugin.cmd_system.es.ini +0 -0
  1630. pygpt_net/data/locale/plugin.cmd_system.fr.ini +0 -0
  1631. pygpt_net/data/locale/plugin.cmd_system.it.ini +0 -0
  1632. pygpt_net/data/locale/plugin.cmd_system.pl.ini +0 -0
  1633. pygpt_net/data/locale/plugin.cmd_system.uk.ini +0 -0
  1634. pygpt_net/data/locale/plugin.cmd_system.zh.ini +0 -0
  1635. pygpt_net/data/locale/plugin.cmd_web.de.ini +0 -0
  1636. pygpt_net/data/locale/plugin.cmd_web.en.ini +0 -0
  1637. pygpt_net/data/locale/plugin.cmd_web.es.ini +0 -0
  1638. pygpt_net/data/locale/plugin.cmd_web.fr.ini +0 -0
  1639. pygpt_net/data/locale/plugin.cmd_web.it.ini +0 -0
  1640. pygpt_net/data/locale/plugin.cmd_web.pl.ini +0 -0
  1641. pygpt_net/data/locale/plugin.cmd_web.uk.ini +0 -0
  1642. pygpt_net/data/locale/plugin.cmd_web.zh.ini +0 -0
  1643. pygpt_net/data/locale/plugin.crontab.de.ini +0 -0
  1644. pygpt_net/data/locale/plugin.crontab.en.ini +0 -0
  1645. pygpt_net/data/locale/plugin.crontab.es.ini +0 -0
  1646. pygpt_net/data/locale/plugin.crontab.fr.ini +0 -0
  1647. pygpt_net/data/locale/plugin.crontab.it.ini +0 -0
  1648. pygpt_net/data/locale/plugin.crontab.pl.ini +0 -0
  1649. pygpt_net/data/locale/plugin.crontab.uk.ini +0 -0
  1650. pygpt_net/data/locale/plugin.crontab.zh.ini +0 -0
  1651. pygpt_net/data/locale/plugin.experts.de.ini +0 -0
  1652. pygpt_net/data/locale/plugin.experts.en.ini +0 -0
  1653. pygpt_net/data/locale/plugin.experts.es.ini +0 -0
  1654. pygpt_net/data/locale/plugin.experts.fr.ini +0 -0
  1655. pygpt_net/data/locale/plugin.experts.it.ini +0 -0
  1656. pygpt_net/data/locale/plugin.experts.pl.ini +0 -0
  1657. pygpt_net/data/locale/plugin.experts.uk.ini +0 -0
  1658. pygpt_net/data/locale/plugin.experts.zh.ini +0 -0
  1659. pygpt_net/data/locale/plugin.extra_prompt.de.ini +0 -0
  1660. pygpt_net/data/locale/plugin.extra_prompt.en.ini +0 -0
  1661. pygpt_net/data/locale/plugin.extra_prompt.es.ini +0 -0
  1662. pygpt_net/data/locale/plugin.extra_prompt.fr.ini +0 -0
  1663. pygpt_net/data/locale/plugin.extra_prompt.it.ini +0 -0
  1664. pygpt_net/data/locale/plugin.extra_prompt.pl.ini +0 -0
  1665. pygpt_net/data/locale/plugin.extra_prompt.uk.ini +0 -0
  1666. pygpt_net/data/locale/plugin.extra_prompt.zh.ini +0 -0
  1667. pygpt_net/data/locale/plugin.idx_llama_index.de.ini +0 -0
  1668. pygpt_net/data/locale/plugin.idx_llama_index.en.ini +0 -0
  1669. pygpt_net/data/locale/plugin.idx_llama_index.es.ini +0 -0
  1670. pygpt_net/data/locale/plugin.idx_llama_index.fr.ini +0 -0
  1671. pygpt_net/data/locale/plugin.idx_llama_index.it.ini +0 -0
  1672. pygpt_net/data/locale/plugin.idx_llama_index.pl.ini +0 -0
  1673. pygpt_net/data/locale/plugin.idx_llama_index.uk.ini +0 -0
  1674. pygpt_net/data/locale/plugin.idx_llama_index.zh.ini +0 -0
  1675. pygpt_net/data/locale/plugin.mailer.en.ini +0 -0
  1676. pygpt_net/data/locale/plugin.openai_dalle.de.ini +0 -0
  1677. pygpt_net/data/locale/plugin.openai_dalle.en.ini +0 -0
  1678. pygpt_net/data/locale/plugin.openai_dalle.es.ini +0 -0
  1679. pygpt_net/data/locale/plugin.openai_dalle.fr.ini +0 -0
  1680. pygpt_net/data/locale/plugin.openai_dalle.it.ini +0 -0
  1681. pygpt_net/data/locale/plugin.openai_dalle.pl.ini +0 -0
  1682. pygpt_net/data/locale/plugin.openai_dalle.uk.ini +0 -0
  1683. pygpt_net/data/locale/plugin.openai_dalle.zh.ini +0 -0
  1684. pygpt_net/data/locale/plugin.openai_vision.de.ini +0 -0
  1685. pygpt_net/data/locale/plugin.openai_vision.en.ini +0 -0
  1686. pygpt_net/data/locale/plugin.openai_vision.es.ini +0 -0
  1687. pygpt_net/data/locale/plugin.openai_vision.fr.ini +0 -0
  1688. pygpt_net/data/locale/plugin.openai_vision.it.ini +0 -0
  1689. pygpt_net/data/locale/plugin.openai_vision.pl.ini +0 -0
  1690. pygpt_net/data/locale/plugin.openai_vision.uk.ini +0 -0
  1691. pygpt_net/data/locale/plugin.openai_vision.zh.ini +0 -0
  1692. pygpt_net/data/locale/plugin.real_time.de.ini +0 -0
  1693. pygpt_net/data/locale/plugin.real_time.en.ini +0 -0
  1694. pygpt_net/data/locale/plugin.real_time.es.ini +0 -0
  1695. pygpt_net/data/locale/plugin.real_time.fr.ini +0 -0
  1696. pygpt_net/data/locale/plugin.real_time.it.ini +0 -0
  1697. pygpt_net/data/locale/plugin.real_time.pl.ini +0 -0
  1698. pygpt_net/data/locale/plugin.real_time.uk.ini +0 -0
  1699. pygpt_net/data/locale/plugin.real_time.zh.ini +0 -0
  1700. pygpt_net/data/locale/plugin.voice_control.de.ini +0 -0
  1701. pygpt_net/data/locale/plugin.voice_control.en.ini +0 -0
  1702. pygpt_net/data/locale/plugin.voice_control.es.ini +0 -0
  1703. pygpt_net/data/locale/plugin.voice_control.fr.ini +0 -0
  1704. pygpt_net/data/locale/plugin.voice_control.it.ini +0 -0
  1705. pygpt_net/data/locale/plugin.voice_control.pl.ini +0 -0
  1706. pygpt_net/data/locale/plugin.voice_control.uk.ini +0 -0
  1707. pygpt_net/data/locale/plugin.voice_control.zh.ini +0 -0
  1708. pygpt_net/data/prompts.csv +0 -0
  1709. pygpt_net/fonts.qrc +60 -60
  1710. pygpt_net/fonts_rc.py +0 -0
  1711. pygpt_net/icons.qrc +138 -138
  1712. pygpt_net/icons_rc.py +0 -0
  1713. pygpt_net/js.qrc +6 -4
  1714. pygpt_net/js_rc.py +10890 -26621
  1715. pygpt_net/migrations/Version20231227152900.py +0 -0
  1716. pygpt_net/migrations/Version20231230095000.py +0 -0
  1717. pygpt_net/migrations/Version20231231230000.py +0 -0
  1718. pygpt_net/migrations/Version20240106060000.py +0 -0
  1719. pygpt_net/migrations/Version20240107060000.py +0 -0
  1720. pygpt_net/migrations/Version20240222160000.py +0 -0
  1721. pygpt_net/migrations/Version20240223050000.py +0 -0
  1722. pygpt_net/migrations/Version20240303190000.py +0 -0
  1723. pygpt_net/migrations/Version20240408180000.py +0 -0
  1724. pygpt_net/migrations/Version20240426050000.py +0 -0
  1725. pygpt_net/migrations/Version20240501030000.py +0 -0
  1726. pygpt_net/migrations/Version20241122130000.py +0 -0
  1727. pygpt_net/migrations/Version20241126170000.py +0 -0
  1728. pygpt_net/migrations/Version20241215110000.py +0 -0
  1729. pygpt_net/migrations/__init__.py +0 -0
  1730. pygpt_net/migrations/base.py +0 -0
  1731. pygpt_net/plugin/agent/config.py +0 -0
  1732. pygpt_net/plugin/agent/plugin.py +0 -0
  1733. pygpt_net/plugin/audio_input/config.py +0 -0
  1734. pygpt_net/plugin/audio_input/plugin.py +0 -0
  1735. pygpt_net/plugin/audio_output/config.py +0 -0
  1736. pygpt_net/plugin/audio_output/plugin.py +0 -0
  1737. pygpt_net/plugin/audio_output/worker.py +0 -0
  1738. pygpt_net/plugin/base/__init__.py +0 -0
  1739. pygpt_net/plugin/base/config.py +0 -0
  1740. pygpt_net/plugin/base/signals.py +0 -0
  1741. pygpt_net/plugin/base/worker.py +0 -0
  1742. pygpt_net/plugin/bitbucket/config.py +0 -0
  1743. pygpt_net/plugin/bitbucket/plugin.py +0 -0
  1744. pygpt_net/plugin/cmd_api/config.py +0 -0
  1745. pygpt_net/plugin/cmd_api/plugin.py +0 -0
  1746. pygpt_net/plugin/cmd_api/worker.py +0 -0
  1747. pygpt_net/plugin/cmd_custom/config.py +0 -0
  1748. pygpt_net/plugin/cmd_custom/plugin.py +0 -0
  1749. pygpt_net/plugin/cmd_custom/worker.py +0 -0
  1750. pygpt_net/plugin/cmd_files/config.py +0 -0
  1751. pygpt_net/plugin/cmd_files/output.py +0 -0
  1752. pygpt_net/plugin/cmd_files/plugin.py +0 -0
  1753. pygpt_net/plugin/cmd_history/config.py +0 -0
  1754. pygpt_net/plugin/cmd_history/plugin.py +0 -0
  1755. pygpt_net/plugin/cmd_history/worker.py +0 -0
  1756. pygpt_net/plugin/cmd_mouse_control/plugin.py +0 -0
  1757. pygpt_net/plugin/cmd_mouse_control/worker.py +0 -0
  1758. pygpt_net/plugin/cmd_serial/config.py +0 -0
  1759. pygpt_net/plugin/cmd_serial/plugin.py +0 -0
  1760. pygpt_net/plugin/cmd_serial/worker.py +0 -0
  1761. pygpt_net/plugin/cmd_system/config.py +0 -0
  1762. pygpt_net/plugin/cmd_system/docker.py +0 -0
  1763. pygpt_net/plugin/cmd_system/output.py +0 -0
  1764. pygpt_net/plugin/cmd_system/plugin.py +0 -0
  1765. pygpt_net/plugin/cmd_web/config.py +0 -0
  1766. pygpt_net/plugin/cmd_web/plugin.py +0 -0
  1767. pygpt_net/plugin/cmd_web/worker.py +0 -0
  1768. pygpt_net/plugin/crontab/config.py +0 -0
  1769. pygpt_net/plugin/crontab/plugin.py +0 -0
  1770. pygpt_net/plugin/experts/config.py +0 -0
  1771. pygpt_net/plugin/experts/plugin.py +0 -0
  1772. pygpt_net/plugin/extra_prompt/config.py +0 -0
  1773. pygpt_net/plugin/extra_prompt/plugin.py +0 -0
  1774. pygpt_net/plugin/facebook/config.py +0 -0
  1775. pygpt_net/plugin/facebook/plugin.py +0 -0
  1776. pygpt_net/plugin/github/config.py +0 -0
  1777. pygpt_net/plugin/github/plugin.py +0 -0
  1778. pygpt_net/plugin/google/plugin.py +0 -0
  1779. pygpt_net/plugin/idx_llama_index/config.py +0 -0
  1780. pygpt_net/plugin/idx_llama_index/plugin.py +0 -0
  1781. pygpt_net/plugin/idx_llama_index/worker.py +0 -0
  1782. pygpt_net/plugin/mailer/plugin.py +0 -0
  1783. pygpt_net/plugin/openai_dalle/config.py +0 -0
  1784. pygpt_net/plugin/openai_dalle/plugin.py +0 -0
  1785. pygpt_net/plugin/openai_vision/config.py +0 -0
  1786. pygpt_net/plugin/openai_vision/plugin.py +0 -0
  1787. pygpt_net/plugin/real_time/config.py +0 -0
  1788. pygpt_net/plugin/real_time/plugin.py +0 -0
  1789. pygpt_net/plugin/server/config.py +0 -0
  1790. pygpt_net/plugin/server/plugin.py +0 -0
  1791. pygpt_net/plugin/slack/config.py +0 -0
  1792. pygpt_net/plugin/slack/plugin.py +0 -0
  1793. pygpt_net/plugin/telegram/config.py +0 -0
  1794. pygpt_net/plugin/telegram/plugin.py +0 -0
  1795. pygpt_net/plugin/tuya/config.py +0 -0
  1796. pygpt_net/plugin/tuya/plugin.py +0 -0
  1797. pygpt_net/plugin/twitter/config.py +0 -0
  1798. pygpt_net/plugin/twitter/plugin.py +0 -0
  1799. pygpt_net/plugin/voice_control/config.py +0 -0
  1800. pygpt_net/plugin/voice_control/plugin.py +0 -0
  1801. pygpt_net/plugin/wikipedia/config.py +0 -0
  1802. pygpt_net/plugin/wikipedia/plugin.py +0 -0
  1803. pygpt_net/provider/__init__.py +0 -0
  1804. pygpt_net/provider/agents/__init__.py +0 -0
  1805. pygpt_net/provider/agents/base.py +0 -0
  1806. pygpt_net/provider/agents/llama_index/__init__.py +0 -0
  1807. pygpt_net/provider/agents/llama_index/codeact_workflow.py +0 -0
  1808. pygpt_net/provider/agents/llama_index/legacy/__init__.py +0 -0
  1809. pygpt_net/provider/agents/llama_index/legacy/openai.py +0 -0
  1810. pygpt_net/provider/agents/llama_index/legacy/openai_assistant.py +0 -0
  1811. pygpt_net/provider/agents/llama_index/legacy/planner.py +0 -0
  1812. pygpt_net/provider/agents/llama_index/legacy/react.py +0 -0
  1813. pygpt_net/provider/agents/llama_index/openai_workflow.py +0 -0
  1814. pygpt_net/provider/agents/llama_index/react_workflow.py +0 -0
  1815. pygpt_net/provider/agents/llama_index/supervisor_workflow.py +0 -0
  1816. pygpt_net/provider/agents/llama_index/workflow/__init__.py +0 -0
  1817. pygpt_net/provider/agents/llama_index/workflow/codeact.py +0 -0
  1818. pygpt_net/provider/agents/llama_index/workflow/events.py +0 -0
  1819. pygpt_net/provider/agents/llama_index/workflow/planner.py +0 -0
  1820. pygpt_net/provider/agents/llama_index/workflow/supervisor.py +0 -0
  1821. pygpt_net/provider/agents/openai/__init__.py +0 -0
  1822. pygpt_net/provider/agents/openai/agent.py +0 -0
  1823. pygpt_net/provider/agents/openai/agent_planner.py +0 -0
  1824. pygpt_net/provider/agents/openai/agent_with_experts.py +0 -0
  1825. pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +0 -0
  1826. pygpt_net/provider/agents/openai/agent_with_feedback.py +0 -0
  1827. pygpt_net/provider/agents/openai/supervisor.py +0 -0
  1828. pygpt_net/provider/api/__init__.py +0 -0
  1829. pygpt_net/provider/api/anthropic/audio.py +0 -0
  1830. pygpt_net/provider/api/anthropic/chat.py +0 -0
  1831. pygpt_net/provider/api/anthropic/image.py +0 -0
  1832. pygpt_net/provider/api/anthropic/tools.py +0 -0
  1833. pygpt_net/provider/api/anthropic/vision.py +0 -0
  1834. pygpt_net/provider/api/fake/__init__.py +0 -0
  1835. pygpt_net/provider/api/fake/generator.py +244 -0
  1836. pygpt_net/provider/api/google/__init__.py +0 -0
  1837. pygpt_net/provider/api/google/audio.py +0 -0
  1838. pygpt_net/provider/api/google/chat.py +0 -0
  1839. pygpt_net/provider/api/google/image.py +0 -0
  1840. pygpt_net/provider/api/google/realtime/__init__.py +0 -0
  1841. pygpt_net/provider/api/google/tools.py +0 -0
  1842. pygpt_net/provider/api/google/video.py +0 -0
  1843. pygpt_net/provider/api/google/vision.py +0 -0
  1844. pygpt_net/provider/api/openai/__init__.py +31 -18
  1845. pygpt_net/provider/api/openai/agents/__init__.py +0 -0
  1846. pygpt_net/provider/api/openai/agents/client.py +0 -0
  1847. pygpt_net/provider/api/openai/agents/computer.py +0 -0
  1848. pygpt_net/provider/api/openai/agents/experts.py +0 -0
  1849. pygpt_net/provider/api/openai/agents/remote_tools.py +0 -0
  1850. pygpt_net/provider/api/openai/agents/utils.py +0 -0
  1851. pygpt_net/provider/api/openai/assistants.py +0 -0
  1852. pygpt_net/provider/api/openai/audio.py +0 -0
  1853. pygpt_net/provider/api/openai/completion.py +0 -0
  1854. pygpt_net/provider/api/openai/computer.py +0 -0
  1855. pygpt_net/provider/api/openai/container.py +0 -0
  1856. pygpt_net/provider/api/openai/image.py +0 -0
  1857. pygpt_net/provider/api/openai/realtime/__init__.py +0 -0
  1858. pygpt_net/provider/api/openai/remote_tools.py +0 -0
  1859. pygpt_net/provider/api/openai/responses.py +3 -1
  1860. pygpt_net/provider/api/openai/store.py +0 -0
  1861. pygpt_net/provider/api/openai/tools.py +0 -0
  1862. pygpt_net/provider/api/openai/utils.py +0 -0
  1863. pygpt_net/provider/api/openai/vision.py +0 -0
  1864. pygpt_net/provider/api/openai/worker/__init__.py +0 -0
  1865. pygpt_net/provider/api/openai/worker/assistants.py +0 -0
  1866. pygpt_net/provider/api/openai/worker/importer.py +0 -0
  1867. pygpt_net/provider/api/x_ai/__init__.py +0 -0
  1868. pygpt_net/provider/api/x_ai/audio.py +0 -0
  1869. pygpt_net/provider/api/x_ai/chat.py +0 -0
  1870. pygpt_net/provider/api/x_ai/image.py +0 -0
  1871. pygpt_net/provider/api/x_ai/remote.py +0 -0
  1872. pygpt_net/provider/api/x_ai/tools.py +0 -0
  1873. pygpt_net/provider/api/x_ai/vision.py +0 -0
  1874. pygpt_net/provider/audio_input/__init__.py +0 -0
  1875. pygpt_net/provider/audio_input/base.py +0 -0
  1876. pygpt_net/provider/audio_input/bing_speech_recognition.py +0 -0
  1877. pygpt_net/provider/audio_input/google_cloud_speech_recognition.py +0 -0
  1878. pygpt_net/provider/audio_input/google_genai.py +0 -0
  1879. pygpt_net/provider/audio_input/google_speech_recognition.py +0 -0
  1880. pygpt_net/provider/audio_input/openai_whisper.py +0 -0
  1881. pygpt_net/provider/audio_input/openai_whisper_local.py +0 -0
  1882. pygpt_net/provider/audio_output/__init__.py +0 -0
  1883. pygpt_net/provider/audio_output/base.py +0 -0
  1884. pygpt_net/provider/audio_output/eleven_labs.py +0 -0
  1885. pygpt_net/provider/audio_output/google_genai_tts.py +0 -0
  1886. pygpt_net/provider/audio_output/google_tts.py +0 -0
  1887. pygpt_net/provider/audio_output/ms_azure_tts.py +0 -0
  1888. pygpt_net/provider/audio_output/openai_tts.py +0 -0
  1889. pygpt_net/provider/core/__init__.py +0 -0
  1890. pygpt_net/provider/core/assistant/__init__.py +0 -0
  1891. pygpt_net/provider/core/assistant/base.py +0 -0
  1892. pygpt_net/provider/core/assistant/json_file.py +0 -0
  1893. pygpt_net/provider/core/assistant_file/__init__.py +0 -0
  1894. pygpt_net/provider/core/assistant_file/base.py +0 -0
  1895. pygpt_net/provider/core/assistant_file/db_sqlite/__init__.py +0 -0
  1896. pygpt_net/provider/core/assistant_file/db_sqlite/patch.py +0 -0
  1897. pygpt_net/provider/core/assistant_file/db_sqlite/provider.py +0 -0
  1898. pygpt_net/provider/core/assistant_file/db_sqlite/storage.py +0 -0
  1899. pygpt_net/provider/core/assistant_file/db_sqlite/utils.py +0 -0
  1900. pygpt_net/provider/core/assistant_store/__init__.py +0 -0
  1901. pygpt_net/provider/core/assistant_store/base.py +0 -0
  1902. pygpt_net/provider/core/assistant_store/db_sqlite/__init__.py +0 -0
  1903. pygpt_net/provider/core/assistant_store/db_sqlite/patch.py +0 -0
  1904. pygpt_net/provider/core/assistant_store/db_sqlite/provider.py +0 -0
  1905. pygpt_net/provider/core/assistant_store/db_sqlite/storage.py +0 -0
  1906. pygpt_net/provider/core/assistant_store/db_sqlite/utils.py +0 -0
  1907. pygpt_net/provider/core/assistant_store/json_file.py +0 -0
  1908. pygpt_net/provider/core/attachment/__init__.py +0 -0
  1909. pygpt_net/provider/core/attachment/base.py +0 -0
  1910. pygpt_net/provider/core/attachment/json_file.py +0 -0
  1911. pygpt_net/provider/core/calendar/__init__.py +0 -0
  1912. pygpt_net/provider/core/calendar/base.py +0 -0
  1913. pygpt_net/provider/core/calendar/db_sqlite/__init__.py +0 -0
  1914. pygpt_net/provider/core/calendar/db_sqlite/patch.py +0 -0
  1915. pygpt_net/provider/core/calendar/db_sqlite/provider.py +0 -0
  1916. pygpt_net/provider/core/calendar/db_sqlite/storage.py +0 -0
  1917. pygpt_net/provider/core/config/__init__.py +0 -0
  1918. pygpt_net/provider/core/config/base.py +0 -0
  1919. pygpt_net/provider/core/config/patch.py +12 -1
  1920. pygpt_net/provider/core/ctx/__init__.py +0 -0
  1921. pygpt_net/provider/core/ctx/base.py +0 -0
  1922. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +0 -0
  1923. pygpt_net/provider/core/ctx/db_sqlite/provider.py +0 -0
  1924. pygpt_net/provider/core/ctx/db_sqlite/storage.py +0 -0
  1925. pygpt_net/provider/core/ctx/db_sqlite/utils.py +0 -0
  1926. pygpt_net/provider/core/ctx/json_file.py +0 -0
  1927. pygpt_net/provider/core/history/__init__.py +0 -0
  1928. pygpt_net/provider/core/history/base.py +0 -0
  1929. pygpt_net/provider/core/history/patch.py +0 -0
  1930. pygpt_net/provider/core/history/txt_file.py +0 -0
  1931. pygpt_net/provider/core/index/__init__.py +0 -0
  1932. pygpt_net/provider/core/index/base.py +0 -0
  1933. pygpt_net/provider/core/index/db_sqlite/__init__.py +0 -0
  1934. pygpt_net/provider/core/index/db_sqlite/patch.py +0 -0
  1935. pygpt_net/provider/core/index/db_sqlite/provider.py +0 -0
  1936. pygpt_net/provider/core/index/db_sqlite/storage.py +0 -0
  1937. pygpt_net/provider/core/index/db_sqlite/utils.py +0 -0
  1938. pygpt_net/provider/core/index/json_file.py +0 -0
  1939. pygpt_net/provider/core/index/patch.py +0 -0
  1940. pygpt_net/provider/core/mode/__init__.py +0 -0
  1941. pygpt_net/provider/core/mode/base.py +0 -0
  1942. pygpt_net/provider/core/mode/json_file.py +0 -0
  1943. pygpt_net/provider/core/mode/patch.py +0 -0
  1944. pygpt_net/provider/core/model/__init__.py +0 -0
  1945. pygpt_net/provider/core/model/base.py +0 -0
  1946. pygpt_net/provider/core/notepad/__init__.py +0 -0
  1947. pygpt_net/provider/core/notepad/base.py +0 -0
  1948. pygpt_net/provider/core/notepad/db_sqlite/__init__.py +0 -0
  1949. pygpt_net/provider/core/notepad/db_sqlite/patch.py +0 -0
  1950. pygpt_net/provider/core/notepad/db_sqlite/provider.py +0 -0
  1951. pygpt_net/provider/core/notepad/db_sqlite/storage.py +0 -0
  1952. pygpt_net/provider/core/notepad/json_file.py +0 -0
  1953. pygpt_net/provider/core/plugin_preset/__init__.py +0 -0
  1954. pygpt_net/provider/core/plugin_preset/base.py +0 -0
  1955. pygpt_net/provider/core/preset/patch.py +0 -0
  1956. pygpt_net/provider/core/prompt/__init__.py +0 -0
  1957. pygpt_net/provider/core/prompt/base.py +0 -0
  1958. pygpt_net/provider/core/prompt/json_file.py +0 -0
  1959. pygpt_net/provider/llms/base.py +0 -0
  1960. pygpt_net/provider/llms/deepseek_api.py +0 -0
  1961. pygpt_net/provider/llms/google.py +0 -0
  1962. pygpt_net/provider/llms/hugging_face_api.py +0 -0
  1963. pygpt_net/provider/llms/hugging_face_router.py +0 -0
  1964. pygpt_net/provider/llms/llama_index/__init__.py +0 -0
  1965. pygpt_net/provider/llms/llama_index/openai/__init__.py +0 -0
  1966. pygpt_net/provider/llms/llama_index/openai/base.py +0 -0
  1967. pygpt_net/provider/llms/llama_index/openai/py.typed +0 -0
  1968. pygpt_net/provider/llms/llama_index/openai/responses.py +0 -0
  1969. pygpt_net/provider/llms/llama_index/openai/utils.py +0 -0
  1970. pygpt_net/provider/llms/llama_index/x_ai/__init__.py +0 -0
  1971. pygpt_net/provider/llms/llama_index/x_ai/embedding.py +0 -0
  1972. pygpt_net/provider/llms/local.py +0 -0
  1973. pygpt_net/provider/llms/mistral.py +0 -0
  1974. pygpt_net/provider/llms/ollama_custom.py +0 -0
  1975. pygpt_net/provider/llms/open_router.py +0 -0
  1976. pygpt_net/provider/llms/perplexity.py +0 -0
  1977. pygpt_net/provider/llms/x_ai.py +0 -0
  1978. pygpt_net/provider/loaders/__init__.py +0 -0
  1979. pygpt_net/provider/loaders/base.py +0 -0
  1980. pygpt_net/provider/loaders/file_csv.py +0 -0
  1981. pygpt_net/provider/loaders/file_docx.py +0 -0
  1982. pygpt_net/provider/loaders/file_epub.py +0 -0
  1983. pygpt_net/provider/loaders/file_excel.py +0 -0
  1984. pygpt_net/provider/loaders/file_html.py +0 -0
  1985. pygpt_net/provider/loaders/file_image_vision.py +0 -0
  1986. pygpt_net/provider/loaders/file_ipynb.py +0 -0
  1987. pygpt_net/provider/loaders/file_json.py +0 -0
  1988. pygpt_net/provider/loaders/file_markdown.py +0 -0
  1989. pygpt_net/provider/loaders/file_pdf.py +0 -0
  1990. pygpt_net/provider/loaders/file_video_audio.py +0 -0
  1991. pygpt_net/provider/loaders/file_xml.py +0 -0
  1992. pygpt_net/provider/loaders/hub/__init__.py +0 -0
  1993. pygpt_net/provider/loaders/hub/bitbucket/__init__.py +0 -0
  1994. pygpt_net/provider/loaders/hub/bitbucket/repo.py +0 -0
  1995. pygpt_net/provider/loaders/hub/chatgpt_retrieval/__init__.py +0 -0
  1996. pygpt_net/provider/loaders/hub/chatgpt_retrieval/base.py +0 -0
  1997. pygpt_net/provider/loaders/hub/database/__init__.py +0 -0
  1998. pygpt_net/provider/loaders/hub/database/base.py +0 -0
  1999. pygpt_net/provider/loaders/hub/github/__init__.py +0 -0
  2000. pygpt_net/provider/loaders/hub/github/issues.py +0 -0
  2001. pygpt_net/provider/loaders/hub/github/repo.py +0 -0
  2002. pygpt_net/provider/loaders/hub/google/__init__.py +0 -0
  2003. pygpt_net/provider/loaders/hub/google/calendar.py +0 -0
  2004. pygpt_net/provider/loaders/hub/google/docs.py +0 -0
  2005. pygpt_net/provider/loaders/hub/google/gmail.py +0 -0
  2006. pygpt_net/provider/loaders/hub/google/keep.py +0 -0
  2007. pygpt_net/provider/loaders/hub/google/sheets.py +0 -0
  2008. pygpt_net/provider/loaders/hub/image_vision/__init__.py +0 -0
  2009. pygpt_net/provider/loaders/hub/image_vision/base.py +0 -0
  2010. pygpt_net/provider/loaders/hub/json/__init__.py +0 -0
  2011. pygpt_net/provider/loaders/hub/json/base.py +0 -0
  2012. pygpt_net/provider/loaders/hub/pandas_excel/__init__.py +0 -0
  2013. pygpt_net/provider/loaders/hub/pandas_excel/base.py +0 -0
  2014. pygpt_net/provider/loaders/hub/simple_csv/__init__.py +0 -0
  2015. pygpt_net/provider/loaders/hub/simple_csv/base.py +0 -0
  2016. pygpt_net/provider/loaders/hub/video_audio/__init__.py +0 -0
  2017. pygpt_net/provider/loaders/hub/video_audio/base.py +0 -0
  2018. pygpt_net/provider/loaders/hub/web_page/__init__.py +0 -0
  2019. pygpt_net/provider/loaders/hub/web_page/base.py +0 -0
  2020. pygpt_net/provider/loaders/hub/yt/__init__.py +0 -0
  2021. pygpt_net/provider/loaders/hub/yt/base.py +0 -0
  2022. pygpt_net/provider/loaders/hub/yt/utils.py +0 -0
  2023. pygpt_net/provider/loaders/web_bitbucket.py +0 -0
  2024. pygpt_net/provider/loaders/web_chatgpt_retrieval.py +0 -0
  2025. pygpt_net/provider/loaders/web_database.py +0 -0
  2026. pygpt_net/provider/loaders/web_github_issues.py +0 -0
  2027. pygpt_net/provider/loaders/web_github_repo.py +0 -0
  2028. pygpt_net/provider/loaders/web_google_calendar.py +0 -0
  2029. pygpt_net/provider/loaders/web_google_docs.py +0 -0
  2030. pygpt_net/provider/loaders/web_google_drive.py +0 -0
  2031. pygpt_net/provider/loaders/web_google_gmail.py +0 -0
  2032. pygpt_net/provider/loaders/web_google_keep.py +0 -0
  2033. pygpt_net/provider/loaders/web_google_sheets.py +0 -0
  2034. pygpt_net/provider/loaders/web_microsoft_onedrive.py +0 -0
  2035. pygpt_net/provider/loaders/web_page.py +0 -0
  2036. pygpt_net/provider/loaders/web_rss.py +0 -0
  2037. pygpt_net/provider/loaders/web_sitemap.py +0 -0
  2038. pygpt_net/provider/loaders/web_twitter.py +0 -0
  2039. pygpt_net/provider/loaders/web_yt.py +0 -0
  2040. pygpt_net/provider/vector_stores/ctx_attachment.py +0 -0
  2041. pygpt_net/provider/web/__init__.py +0 -0
  2042. pygpt_net/provider/web/base.py +0 -0
  2043. pygpt_net/provider/web/duckduck_search.py +0 -0
  2044. pygpt_net/provider/web/google_custom_search.py +0 -0
  2045. pygpt_net/provider/web/microsoft_bing.py +0 -0
  2046. pygpt_net/tools/__init__.py +0 -0
  2047. pygpt_net/tools/audio_transcriber/tool.py +0 -0
  2048. pygpt_net/tools/audio_transcriber/ui/__init__.py +0 -0
  2049. pygpt_net/tools/audio_transcriber/ui/dialogs.py +0 -0
  2050. pygpt_net/tools/base.py +0 -0
  2051. pygpt_net/tools/code_interpreter/body.py +0 -0
  2052. pygpt_net/tools/code_interpreter/ui/__init__.py +0 -0
  2053. pygpt_net/tools/code_interpreter/ui/dialogs.py +0 -0
  2054. pygpt_net/tools/code_interpreter/ui/html.py +0 -0
  2055. pygpt_net/tools/code_interpreter/ui/widgets.py +0 -0
  2056. pygpt_net/tools/html_canvas/tool.py +0 -0
  2057. pygpt_net/tools/html_canvas/ui/__init__.py +0 -0
  2058. pygpt_net/tools/html_canvas/ui/dialogs.py +0 -0
  2059. pygpt_net/tools/html_canvas/ui/widgets.py +0 -0
  2060. pygpt_net/tools/image_viewer/tool.py +0 -0
  2061. pygpt_net/tools/image_viewer/ui/__init__.py +0 -0
  2062. pygpt_net/tools/image_viewer/ui/dialogs.py +0 -0
  2063. pygpt_net/tools/indexer/tool.py +0 -0
  2064. pygpt_net/tools/indexer/ui/__init__.py +0 -0
  2065. pygpt_net/tools/indexer/ui/browse.py +0 -0
  2066. pygpt_net/tools/indexer/ui/ctx.py +0 -0
  2067. pygpt_net/tools/indexer/ui/dialogs.py +0 -0
  2068. pygpt_net/tools/indexer/ui/files.py +0 -0
  2069. pygpt_net/tools/indexer/ui/web.py +0 -0
  2070. pygpt_net/tools/indexer/ui/widgets.py +0 -0
  2071. pygpt_net/tools/media_player/tool.py +0 -0
  2072. pygpt_net/tools/media_player/ui/__init__.py +0 -0
  2073. pygpt_net/tools/media_player/ui/dialogs.py +0 -0
  2074. pygpt_net/tools/media_player/ui/widgets.py +0 -0
  2075. pygpt_net/tools/text_editor/__init__.py +0 -0
  2076. pygpt_net/tools/text_editor/tool.py +0 -0
  2077. pygpt_net/tools/text_editor/ui/__init__.py +0 -0
  2078. pygpt_net/tools/text_editor/ui/dialogs.py +0 -0
  2079. pygpt_net/tools/text_editor/ui/widgets.py +0 -0
  2080. pygpt_net/ui/base/__init__.py +0 -0
  2081. pygpt_net/ui/base/flow_layout.py +0 -0
  2082. pygpt_net/ui/dialog/assistant_store.py +0 -0
  2083. pygpt_net/ui/dialog/create.py +0 -0
  2084. pygpt_net/ui/dialog/db.py +0 -0
  2085. pygpt_net/ui/dialog/dictionary.py +0 -0
  2086. pygpt_net/ui/dialog/find.py +0 -0
  2087. pygpt_net/ui/dialog/models_importer.py +0 -0
  2088. pygpt_net/ui/dialog/preset_plugins.py +0 -0
  2089. pygpt_net/ui/dialog/profile.py +0 -0
  2090. pygpt_net/ui/dialog/snap.py +0 -0
  2091. pygpt_net/ui/dialog/url.py +0 -0
  2092. pygpt_net/ui/dialog/workdir.py +0 -0
  2093. pygpt_net/ui/layout/chat/attachments_ctx.py +0 -0
  2094. pygpt_net/ui/layout/chat/calendar.py +0 -0
  2095. pygpt_net/ui/layout/chat/chat.py +0 -0
  2096. pygpt_net/ui/layout/chat/explorer.py +0 -0
  2097. pygpt_net/ui/layout/chat/painter.py +0 -0
  2098. pygpt_net/ui/layout/ctx/ctx.py +0 -0
  2099. pygpt_net/ui/layout/toolbox/agent.py +0 -0
  2100. pygpt_net/ui/layout/toolbox/agent_llama.py +0 -0
  2101. pygpt_net/ui/layout/toolbox/audio.py +0 -0
  2102. pygpt_net/ui/layout/toolbox/computer_env.py +0 -0
  2103. pygpt_net/ui/layout/toolbox/indexes.py +0 -0
  2104. pygpt_net/ui/layout/toolbox/raw.py +0 -0
  2105. pygpt_net/ui/layout/toolbox/split.py +0 -0
  2106. pygpt_net/ui/layout/toolbox/toolbox.py +0 -0
  2107. pygpt_net/ui/layout/toolbox/video.py +0 -0
  2108. pygpt_net/ui/menu/__init__.py +0 -0
  2109. pygpt_net/ui/menu/audio.py +0 -0
  2110. pygpt_net/ui/menu/config.py +0 -0
  2111. pygpt_net/ui/menu/debug.py +4 -1
  2112. pygpt_net/ui/menu/file.py +0 -0
  2113. pygpt_net/ui/menu/lang.py +0 -0
  2114. pygpt_net/ui/menu/menu.py +0 -0
  2115. pygpt_net/ui/menu/plugins.py +0 -0
  2116. pygpt_net/ui/menu/tools.py +0 -0
  2117. pygpt_net/ui/menu/video.py +0 -0
  2118. pygpt_net/ui/tray.py +0 -0
  2119. pygpt_net/ui/widget/anims/loader.py +0 -0
  2120. pygpt_net/ui/widget/anims/toggles.py +0 -0
  2121. pygpt_net/ui/widget/audio/bar.py +0 -0
  2122. pygpt_net/ui/widget/calendar/__init__.py +0 -0
  2123. pygpt_net/ui/widget/calendar/select.py +0 -0
  2124. pygpt_net/ui/widget/dialog/applog.py +0 -0
  2125. pygpt_net/ui/widget/dialog/assistant_store.py +0 -0
  2126. pygpt_net/ui/widget/dialog/audio.py +0 -0
  2127. pygpt_net/ui/widget/dialog/create.py +0 -0
  2128. pygpt_net/ui/widget/dialog/db.py +0 -0
  2129. pygpt_net/ui/widget/dialog/find.py +0 -0
  2130. pygpt_net/ui/widget/dialog/license.py +0 -0
  2131. pygpt_net/ui/widget/dialog/model.py +0 -0
  2132. pygpt_net/ui/widget/dialog/model_importer.py +0 -0
  2133. pygpt_net/ui/widget/dialog/preset_plugins.py +0 -0
  2134. pygpt_net/ui/widget/dialog/profile.py +0 -0
  2135. pygpt_net/ui/widget/dialog/snap.py +0 -0
  2136. pygpt_net/ui/widget/dialog/url.py +0 -0
  2137. pygpt_net/ui/widget/dialog/workdir.py +0 -0
  2138. pygpt_net/ui/widget/draw/painter.py +0 -0
  2139. pygpt_net/ui/widget/element/button.py +0 -0
  2140. pygpt_net/ui/widget/element/checkbox.py +0 -0
  2141. pygpt_net/ui/widget/lists/assistant_store.py +0 -0
  2142. pygpt_net/ui/widget/lists/attachment_ctx.py +0 -0
  2143. pygpt_net/ui/widget/lists/base_combo.py +0 -0
  2144. pygpt_net/ui/widget/lists/base_list_combo.py +0 -0
  2145. pygpt_net/ui/widget/lists/db.py +0 -0
  2146. pygpt_net/ui/widget/lists/debug.py +0 -0
  2147. pygpt_net/ui/widget/lists/experts.py +0 -0
  2148. pygpt_net/ui/widget/lists/index.py +0 -0
  2149. pygpt_net/ui/widget/lists/index_combo.py +0 -0
  2150. pygpt_net/ui/widget/lists/llama_mode_combo.py +0 -0
  2151. pygpt_net/ui/widget/lists/mode_combo.py +0 -0
  2152. pygpt_net/ui/widget/lists/model_combo.py +0 -0
  2153. pygpt_net/ui/widget/lists/model_editor.py +0 -0
  2154. pygpt_net/ui/widget/lists/model_importer.py +0 -0
  2155. pygpt_net/ui/widget/lists/preset_plugins.py +0 -0
  2156. pygpt_net/ui/widget/lists/profile.py +0 -0
  2157. pygpt_net/ui/widget/lists/settings.py +0 -0
  2158. pygpt_net/ui/widget/option/checkbox_list.py +0 -0
  2159. pygpt_net/ui/widget/option/cmd.py +0 -0
  2160. pygpt_net/ui/widget/option/combo.py +0 -0
  2161. pygpt_net/ui/widget/option/prompt.py +0 -0
  2162. pygpt_net/ui/widget/option/toggle.py +0 -0
  2163. pygpt_net/ui/widget/option/toggle_label.py +0 -0
  2164. pygpt_net/ui/widget/tabs/Input.py +0 -0
  2165. pygpt_net/ui/widget/tabs/__init__.py +0 -0
  2166. pygpt_net/ui/widget/tabs/body.py +0 -0
  2167. pygpt_net/ui/widget/tabs/layout.py +0 -0
  2168. pygpt_net/ui/widget/tabs/output.py +0 -0
  2169. pygpt_net/ui/widget/textarea/calendar_note.py +0 -0
  2170. pygpt_net/ui/widget/textarea/console.py +0 -0
  2171. pygpt_net/ui/widget/textarea/create.py +0 -0
  2172. pygpt_net/ui/widget/textarea/editor.py +0 -0
  2173. pygpt_net/ui/widget/textarea/find.py +0 -0
  2174. pygpt_net/ui/widget/textarea/html.py +0 -0
  2175. pygpt_net/ui/widget/textarea/url.py +0 -0
  2176. pygpt_net/ui/widget/textarea/web.py +84 -154
  2177. pygpt_net/utils.py +17 -0
  2178. {pygpt_net-2.6.40.dist-info → pygpt_net-2.6.41.dist-info}/METADATA +8 -2
  2179. {pygpt_net-2.6.40.dist-info → pygpt_net-2.6.41.dist-info}/RECORD +53 -47
  2180. {pygpt_net-2.6.40.dist-info → pygpt_net-2.6.41.dist-info}/LICENSE +0 -0
  2181. {pygpt_net-2.6.40.dist-info → pygpt_net-2.6.41.dist-info}/WHEEL +0 -0
  2182. {pygpt_net-2.6.40.dist-info → pygpt_net-2.6.41.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,4348 @@
1
+ // v2.6.41 | 2025-09-11
2
+ //
3
+ // PyGPT Runtime for streaming Markdown in QWebEngine:
4
+ //
5
+ // - QWebChannel bridge
6
+ // - markdown-it with lightweight KaTeX placeholders (no KaTeX compute on hot path)
7
+ // - Dollar-delimiter math placeholders: $...$ and $$...$$ (finalize/idle/always policy)
8
+ // - No inline hljs compute in renderer (final code highlight is deferred)
9
+ // - Lightweight, scroll+rAF driven hljs highlighting (no IntersectionObserver)
10
+ // - Async, chunked KaTeX rendering to avoid UI stalls
11
+ // - Async, scheduled tail promotion (small chunks, UI-friendly)
12
+ // - Adaptive snapshots, minimal DOM churn
13
+ // - Incremental, non-flickering code streaming (frozen prefix + plain tail)
14
+ // - Unified, bridge-based logger injected to all subsystems (no console)
15
+ // - Buffered logging with auto-flush when QWebChannel is ready
16
+ // - Runtime promotion of language from first-line directive during streaming
17
+ // - Stream-aware renderer (no linkify on hot path) and plain-text streaming fallback for huge code
18
+ // - Final highlight hard caps to avoid OOM on gigantic blocks
19
+ // - Precomputed code meta (len/head/tail and nl for full renderer) to avoid heavy .textContent reads
20
+
21
+ (function () {
22
+ 'use strict';
23
+
24
+ // ==========================================================================
25
+ // 0) Utils & Config
26
+ // ==========================================================================
27
+
28
+ // Small helper utilities used across the runtime.
29
+ class Utils {
30
+ static g(name, dflt) { return (typeof window[name] !== 'undefined') ? window[name] : dflt; }
31
+ static now() { return (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now(); }
32
+
33
+ // reuse a single detached element to reduce allocations on hot path.
34
+ static escapeHtml(s) {
35
+ const d = Utils._escDiv || (Utils._escDiv = document.createElement('div'));
36
+ d.textContent = String(s ?? '');
37
+ return d.innerHTML;
38
+ }
39
+
40
+ static countNewlines(s) {
41
+ if (!s) return 0;
42
+ let c = 0, i = -1; while ((i = s.indexOf('\n', i + 1)) !== -1) c++;
43
+ return c;
44
+ }
45
+ static reEscape(s) { return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
46
+ // Schedule a function in idle time (falls back to setTimeout).
47
+ static idle(fn, timeout) {
48
+ if ('requestIdleCallback' in window) return requestIdleCallback(fn, { timeout: timeout || 800 });
49
+ return setTimeout(fn, 50);
50
+ }
51
+ // Cancel idle callback if possible (safe for fallback).
52
+ static cancelIdle(id) {
53
+ try {
54
+ if ('cancelIdleCallback' in window) cancelIdleCallback(id);
55
+ else clearTimeout(id);
56
+ } catch (_) {}
57
+ }
58
+ static get SE() { return document.scrollingElement || document.documentElement; }
59
+
60
+ // shared UTF-8 decoder to avoid per-call allocations.
61
+ static utf8Decode(bytes) {
62
+ if (!Utils._td) Utils._td = new TextDecoder('utf-8');
63
+ return Utils._td.decode(bytes);
64
+ }
65
+ }
66
+
67
+ // ==========================================================================
68
+ // 0.1) Unified Logger (bridge-based; injected into classes)
69
+ // ==========================================================================
70
+
71
+ class Logger {
72
+ // Production-grade logger with queue, batch sending and soft caps.
73
+ constructor(cfg) {
74
+ this.cfg = cfg || { LOG: {} };
75
+ // Queue holds strings waiting to be sent over QWebChannel to Python.
76
+ this.queue = [];
77
+ this.queueBytes = 0; // approximate UTF-16 bytes (chars * 2)
78
+ this.armed = false;
79
+ this.maxTries = 480; // ~8s @60fps
80
+ this.tries = 0;
81
+ this.bridge = null;
82
+ this._idleId = 0; // idle-callback handle (backoff-friendly)
83
+ this._lastFlushQueueBytes = 0; // last known bytes to detect progress
84
+
85
+ // Centralized rAF manager handle (bound by runtime); falls back to microtasks until available.
86
+ this.raf = null;
87
+ this._rafScheduled = false;
88
+ this._rafKey = { t: 'Logger:tick' };
89
+
90
+ // Soft limits; tunable from window.* if desired.
91
+ const L = this.cfg.LOG || {};
92
+ this.MAX_QUEUE = Utils.g('LOG_MAX_QUEUE', L.MAX_QUEUE ?? 400);
93
+ this.MAX_BYTES = Utils.g('LOG_MAX_BYTES', L.MAX_BYTES ?? 256 * 1024); // 256 KiB
94
+ this.BATCH_MAX = Utils.g('LOG_BATCH_MAX', L.BATCH_MAX ?? 64);
95
+ this.RATE_LIMIT_PER_SEC = Utils.g('LOG_RATE_LIMIT_PER_SEC', L.RATE_LIMIT_PER_SEC ?? 0); // 0 == off
96
+ this._rlWindowMs = 1000;
97
+ this._rlCount = 0;
98
+ this._rlWindowStart = Utils.now();
99
+ }
100
+ // Connect a QWebChannel bridge and flush any pending messages.
101
+ bindBridge(bridge) {
102
+ this.bridge = bridge || null;
103
+ // When bridge arrives, flush pending messages respecting caps.
104
+ this.flush();
105
+ }
106
+ // Bind RafManager instance – ensures no direct requestAnimationFrame usage in Logger.
107
+ bindRaf(raf) {
108
+ this.raf = raf || null;
109
+ }
110
+ // Check if debug logging is enabled for a namespace.
111
+ isEnabled(ns) {
112
+ if (!ns) return !!(window.STREAM_DEBUG || window.MD_LANG_DEBUG);
113
+ const key1 = ns + '_DEBUG';
114
+ const key2 = ns.toUpperCase() + '_DEBUG';
115
+ return !!(window[key1] || window[key2] || window.STREAM_DEBUG || window.MD_LANG_DEBUG);
116
+ }
117
+ // Pretty-view string (safe truncation for logs).
118
+ pv(s, n = 120) {
119
+ if (!s) return '';
120
+ s = String(s);
121
+ if (s.length <= n) return s.replace(/\n/g, '\\n');
122
+ const k = Math.floor(n / 2);
123
+ return (s.slice(0, k) + ' … ' + s.slice(-k)).replace(/\n/g, '\\n');
124
+ }
125
+ j(o) { try { return JSON.stringify(o); } catch (_) { try { return String(o); } catch(__){ return '[unserializable]'; } } }
126
+ _emit(msg) {
127
+ // Attempt batch-capable sink if provided by the bridge
128
+ try {
129
+ if (this.bridge) {
130
+ if (typeof this.bridge.log_batch === 'function') { this.bridge.log_batch([String(msg)]); return true; }
131
+ if (typeof this.bridge.logBatch === 'function') { this.bridge.logBatch([String(msg)]); return true; }
132
+ if (typeof this.bridge.log === 'function') { this.bridge.log(String(msg)); return true; }
133
+ }
134
+ if (window.runtime && runtime.bridge && typeof runtime.bridge.log === 'function') {
135
+ runtime.bridge.log(String(msg)); return true;
136
+ }
137
+ } catch (_) {}
138
+ return false;
139
+ }
140
+ _emitBatch(arr) {
141
+ try {
142
+ if (!arr || !arr.length) return 0;
143
+ // Prefer batch API if present; otherwise fallback to per-line
144
+ if (this.bridge && typeof this.bridge.log_batch === 'function') { this.bridge.log_batch(arr.map(String)); return arr.length; }
145
+ if (this.bridge && typeof this.bridge.logBatch === 'function') { this.bridge.logBatch(arr.map(String)); return arr.length; }
146
+ if (this.bridge && typeof this.bridge.log === 'function') {
147
+ for (let i = 0; i < arr.length; i++) this.bridge.log(String(arr[i]));
148
+ return arr.length;
149
+ }
150
+ } catch (_) {}
151
+ return 0;
152
+ }
153
+ _maybeDropForCaps(len) {
154
+ // Hard cap queue size and memory to guard Python process via QWebChannel.
155
+ if (this.queue.length <= this.MAX_QUEUE && this.queueBytes <= this.MAX_BYTES) return;
156
+ const targetLen = Math.floor(this.MAX_QUEUE * 0.8);
157
+ const targetBytes = Math.floor(this.MAX_BYTES * 0.8);
158
+ // Drop oldest first; keep newest events
159
+ while ((this.queue.length > targetLen || this.queueBytes > targetBytes) && this.queue.length) {
160
+ const removed = this.queue.shift();
161
+ this.queueBytes -= (removed ? removed.length * 2 : 0);
162
+ }
163
+ // Add one synthetic notice to indicate dropped logs (avoid recursion)
164
+ const notice = '[LOGGER] queue trimmed due to caps';
165
+ this.queue.unshift(notice);
166
+ this.queueBytes += notice.length * 2;
167
+ }
168
+ _passRateLimit() {
169
+ if (!this.RATE_LIMIT_PER_SEC || this.RATE_LIMIT_PER_SEC <= 0) return true;
170
+ const now = Utils.now();
171
+ if (now - this._rlWindowStart > this._rlWindowMs) {
172
+ this._rlWindowStart = now;
173
+ this._rlCount = 0;
174
+ }
175
+ if (this._rlCount >= this.RATE_LIMIT_PER_SEC) return false;
176
+ return true;
177
+ }
178
+ // Push a log line; try immediate send, otherwise enqueue.
179
+ log(text) {
180
+ const msg = String(text);
181
+ // If bridge is available, try immediate emit to avoid queueing overhead.
182
+ if (this.bridge && (typeof this.bridge.log === 'function' || typeof this.bridge.log_batch === 'function' || typeof this.bridge.logBatch === 'function')) {
183
+ if (this._passRateLimit()) {
184
+ const ok = this._emit(msg);
185
+ if (ok) return true;
186
+ }
187
+ }
188
+ // Enqueue with caps; avoid unbounded growth
189
+ this.queue.push(msg);
190
+ this.queueBytes += msg.length * 2;
191
+ this._maybeDropForCaps(msg.length);
192
+ this._arm();
193
+ return false;
194
+ }
195
+ // Debug wrapper respecting per-namespace switch.
196
+ debug(ns, line, ctx) {
197
+ if (!this.isEnabled(ns)) return false;
198
+ let msg = `[${ns}] ${line || ''}`;
199
+ if (typeof ctx !== 'undefined') msg += ' ' + this.j(ctx);
200
+ return this.log(msg);
201
+ }
202
+ // Send a batch of lines if bridge is ready.
203
+ flush(maxPerTick = this.BATCH_MAX) {
204
+ // Centralized flush – no direct cancelAnimationFrame here; RafManager governs frames.
205
+ if (!this.bridge && !(window.runtime && runtime.bridge && typeof runtime.bridge.log === 'function')) return 0;
206
+ const n = Math.min(maxPerTick, this.queue.length);
207
+ if (!n) return 0;
208
+ const batch = this.queue.splice(0, n);
209
+ // Update memory accounting before attempting emit to eagerly unlock memory
210
+ let bytes = 0; for (let i = 0; i < batch.length; i++) bytes += batch[i].length * 2;
211
+ this.queueBytes = Math.max(0, this.queueBytes - bytes);
212
+ const sent = this._emitBatch(batch);
213
+
214
+ // fix byte accounting for partial sends (re-queue remaining with accurate bytes).
215
+ if (sent < batch.length) {
216
+ const remain = batch.slice(sent);
217
+ let remBytes = 0; for (let i = 0; i < remain.length; i++) remBytes += remain[i].length * 2;
218
+ // Prepend remaining back to the queue preserving order
219
+ for (let i = remain.length - 1; i >= 0; i--) this.queue.unshift(remain[i]);
220
+ this.queueBytes += remBytes;
221
+ }
222
+ return sent;
223
+ }
224
+ _scheduleTick(tick) {
225
+ // Prefer idle scheduling when bridge isn't available yet – avoids 60fps RAF churn.
226
+ const preferIdle = !this.bridge;
227
+
228
+ const scheduleIdle = () => {
229
+ try { if (this._idleId) Utils.cancelIdle(this._idleId); } catch (_) {}
230
+ // Use requestIdleCallback when available, fallback to small timeout. Keeps UI cold on idle.
231
+ this._idleId = Utils.idle(() => { this._idleId = 0; tick(); }, 800);
232
+ };
233
+
234
+ if (preferIdle) { scheduleIdle(); return; }
235
+
236
+ if (this._rafScheduled) return;
237
+ this._rafScheduled = true;
238
+ const run = () => { this._rafScheduled = false; tick(); };
239
+ try {
240
+ if (this.raf && typeof this.raf.schedule === 'function') {
241
+ this.raf.schedule(this._rafKey, run, 'Logger', 3);
242
+ } else if (typeof runtime !== 'undefined' && runtime.raf && typeof runtime.raf.schedule === 'function') {
243
+ runtime.raf.schedule(this._rafKey, run, 'Logger', 3);
244
+ } else {
245
+ Promise.resolve().then(run);
246
+ }
247
+ } catch (_) {
248
+ Promise.resolve().then(run);
249
+ }
250
+ }
251
+ _arm() {
252
+ if (this.armed) return;
253
+ this.armed = true; this.tries = 0;
254
+ const tick = () => {
255
+ if (!this.armed) return;
256
+ this.flush();
257
+ this.tries++;
258
+ if (this.queue.length === 0 || this.tries > this.maxTries) {
259
+ this.armed = false;
260
+ try { if (this._idleId) Utils.cancelIdle(this._idleId); } catch (_) {}
261
+ this._idleId = 0;
262
+ return;
263
+ }
264
+ this._scheduleTick(tick);
265
+ };
266
+ this._scheduleTick(tick);
267
+ }
268
+ }
269
+
270
+ // ==========================================================================
271
+ // RafManager (rAF-only)
272
+ // ==========================================================================
273
+
274
+ class RafManager {
275
+ // rAF-only task pump with soft budget per flush to prevent long frames.
276
+ constructor(cfg) {
277
+ this.cfg = cfg || { RAF: {}, ASYNC: {} };
278
+ this.tasks = new Map();
279
+ this.groups = new Map();
280
+ // rAF pump state
281
+ this.tickId = 0;
282
+ this._mode = 'raf';
283
+ this.scheduled = false;
284
+ this._flushInProgress = false;
285
+
286
+ const R = (this.cfg && this.cfg.RAF) || {};
287
+ this.FLUSH_BUDGET_MS = Utils.g('RAF_FLUSH_BUDGET_MS', R.FLUSH_BUDGET_MS ?? 7);
288
+ this.MAX_TASKS_PER_FLUSH = Utils.g('RAF_MAX_TASKS_PER_FLUSH', R.MAX_TASKS_PER_FLUSH ?? 120);
289
+ }
290
+ // Start the pumping loop if needed.
291
+ _armPump() {
292
+ if (this.scheduled) return;
293
+ this.scheduled = true;
294
+
295
+ // Focus/visibility-agnostic, rAF-only scheduling (no timers, no watchdogs).
296
+ const canRAF = typeof requestAnimationFrame === 'function';
297
+ if (canRAF) {
298
+ this._mode = 'raf';
299
+ try {
300
+ this.tickId = requestAnimationFrame(() => this.flush());
301
+ return;
302
+ } catch (_) {}
303
+ }
304
+ // Fallback without timers: schedule a microtask flush.
305
+ this._mode = 'raf';
306
+ Promise.resolve().then(() => this.flush());
307
+ }
308
+ // Schedule a function with an optional group and priority.
309
+ schedule(key, fn, group = 'default', priority = 0) {
310
+ if (!key) key = { k: 'anon' };
311
+ this.tasks.set(key, { fn, group, priority });
312
+ if (group) {
313
+ let set = this.groups.get(group);
314
+ if (!set) { set = new Set(); this.groups.set(group, set); }
315
+ set.add(key);
316
+ }
317
+ this._armPump();
318
+ }
319
+ // Run pending tasks within a time and count budget.
320
+ flush() {
321
+ // Cancel rAF handle if any; nothing else (timers removed).
322
+ try { if (this.tickId) cancelAnimationFrame(this.tickId); } catch (_) {}
323
+ this.tickId = 0;
324
+ this.scheduled = false;
325
+
326
+ // Snapshot tasks and clear the map; re-queue leftovers if we exceed budget.
327
+ const list = Array.from(this.tasks.entries()).map(([key, v]) => ({ key, ...v }));
328
+ this.tasks.clear();
329
+ list.sort((a, b) => a.priority - b.priority);
330
+
331
+ const start = Utils.now();
332
+ let processed = 0;
333
+
334
+ for (let idx = 0; idx < list.length; idx++) {
335
+ const t = list[idx];
336
+ try { t.fn(); } catch (_) {}
337
+ processed++;
338
+ if (t.group) {
339
+ const set = this.groups.get(t.group);
340
+ if (set) { set.delete(t.key); if (set.size === 0) this.groups.delete(t.group); }
341
+ }
342
+
343
+ // Soft budget: if long, re-queue the rest for next rAF.
344
+ const elapsed = Utils.now() - start;
345
+ if (processed >= this.MAX_TASKS_PER_FLUSH || elapsed >= this.FLUSH_BUDGET_MS) {
346
+ for (let j = idx + 1; j < list.length; j++) {
347
+ const r = list[j];
348
+ this.tasks.set(r.key, { fn: r.fn, group: r.group, priority: r.priority });
349
+ }
350
+ this._armPump();
351
+ return;
352
+ }
353
+ }
354
+
355
+ if (this.tasks.size) {
356
+ this._armPump();
357
+ }
358
+ }
359
+ // Force immediate flush or schedule next frame.
360
+ kick(forceImmediate = true) {
361
+ if (forceImmediate && this.tasks.size) {
362
+ if (this._flushInProgress) return;
363
+ this._flushInProgress = true;
364
+ try { this.scheduled = true; this.flush(); } catch (_) {} finally { this._flushInProgress = false; }
365
+ return;
366
+ }
367
+ this._armPump();
368
+ }
369
+ // Cancel a specific scheduled task by key.
370
+ cancel(key) {
371
+ const t = this.tasks.get(key);
372
+ if (!t) return;
373
+ this.tasks.delete(key);
374
+ if (t.group) {
375
+ const set = this.groups.get(t.group);
376
+ if (set) { set.delete(key); if (set.size === 0) this.groups.delete(t.group); }
377
+ }
378
+ }
379
+ // Cancel all tasks in a group.
380
+ cancelGroup(group) {
381
+ const set = this.groups.get(group);
382
+ if (!set) return;
383
+ for (const key of set) this.tasks.delete(key);
384
+ this.groups.delete(group);
385
+ }
386
+ // Cancel everything and reset the pump.
387
+ cancelAll() {
388
+ this.tasks.clear();
389
+ this.groups.clear();
390
+ try { if (this.tickId) cancelAnimationFrame(this.tickId); } catch (_) {}
391
+ this.tickId = 0;
392
+ this.scheduled = false;
393
+ }
394
+ isScheduled(key) { return this.tasks.has(key); }
395
+
396
+ // Awaitable "next frame" helper – resolves on next flush.
397
+ nextFrame() {
398
+ return new Promise((resolve) => {
399
+ const key = { t: 'raf:nextFrame', i: Math.random() };
400
+ this.schedule(key, () => resolve(), 'RafNext', 0);
401
+ });
402
+ }
403
+ }
404
+
405
+ // Return math rendering policy from window.MATH_STREAM_MODE.
406
+ function getMathMode() {
407
+ const v = String(window.MATH_STREAM_MODE || 'finalize-only').toLowerCase();
408
+ return (v === 'idle' || v === 'always' || v === 'finalize-only') ? v : 'finalize-only';
409
+ }
410
+
411
+ // ==========================================================================
412
+ // 0.2) Async runner (cooperative yielding for heavy tasks)
413
+ // ==========================================================================
414
+
415
+ class AsyncRunner {
416
+ // Cooperative scheduler (rAF-based) for CPU-heavy tasks (keeps UI responsive).
417
+ constructor(cfg, raf) {
418
+ this.cfg = cfg || {};
419
+ this.raf = raf || null;
420
+ const A = this.cfg.ASYNC || {};
421
+ this.SLICE_MS = Utils.g('ASYNC_SLICE_MS', A.SLICE_MS ?? 12);
422
+ this.MIN_YIELD_MS = Utils.g('ASYNC_MIN_YIELD_MS', A.MIN_YIELD_MS ?? 0); // kept only for config compatibility
423
+ }
424
+ // Check whether we should yield control to the browser.
425
+ _inputPending() {
426
+ try {
427
+ const s = navigator && navigator.scheduling;
428
+ return !!(s && s.isInputPending && s.isInputPending({ includeContinuous: true }));
429
+ } catch (_) { return false; }
430
+ }
431
+ shouldYield(startTs) {
432
+ if (this._inputPending()) return true;
433
+ return (Utils.now() - startTs) >= this.SLICE_MS;
434
+ }
435
+ // Yield cooperatively via next rAF frame (with a safe fallback).
436
+ async yield() {
437
+ // Centralized rAF yield; fallback to a tiny timer if raf manager is not ready yet.
438
+ if (this.raf && typeof this.raf.nextFrame === 'function') {
439
+ await this.raf.nextFrame();
440
+ return;
441
+ }
442
+ if (typeof runtime !== 'undefined' && runtime.raf && typeof runtime.raf.nextFrame === 'function') {
443
+ await runtime.raf.nextFrame();
444
+ return;
445
+ }
446
+ await new Promise(r => setTimeout(r, 16));
447
+ }
448
+ // Process items in small batches with periodic yields.
449
+ async forEachChunk(arr, fn, label) {
450
+ if (!arr || !arr.length) return;
451
+ let start = Utils.now();
452
+ for (let i = 0; i < arr.length; i++) {
453
+ await fn(arr[i], i);
454
+ if (this.shouldYield(start)) { await this.yield(); start = Utils.now(); }
455
+ }
456
+ }
457
+ }
458
+
459
+ // ==========================================================================
460
+ // Config
461
+ // ==========================================================================
462
+
463
+ class Config {
464
+ constructor() {
465
+ // Process identifier (passed from host).
466
+ this.PID = Utils.g('PID', 0);
467
+
468
+ // UI: scroll behavior and busy/zoom signalling thresholds (milliseconds / pixels).
469
+ this.UI = {
470
+ AUTO_FOLLOW_REENABLE_PX: Utils.g('AUTO_FOLLOW_REENABLE_PX', 8), // Enable auto-follow when near bottom
471
+ SCROLL_NEAR_MARGIN_PX: Utils.g('SCROLL_NEAR_MARGIN_PX', 450), // How close to bottom is considered "near"
472
+ INTERACTION_BUSY_MS: Utils.g('UI_INTERACTION_BUSY_MS', 140), // Minimum busy time for interactions
473
+ ZOOM_BUSY_MS: Utils.g('UI_ZOOM_BUSY_MS', 300) // Minimum busy time for zoom
474
+ };
475
+
476
+ // FAB (floating action button) visibility and debounce.
477
+ this.FAB = {
478
+ SHOW_DOWN_THRESHOLD_PX: Utils.g('SHOW_DOWN_THRESHOLD_PX', 0), // Show "down" arrow when scroll distance is large
479
+ TOGGLE_DEBOUNCE_MS: Utils.g('FAB_TOGGLE_DEBOUNCE_MS', 100) // Debounce for icon/text toggles
480
+ };
481
+
482
+ // Highlighting controls and per-frame budget.
483
+ this.HL = {
484
+ PER_FRAME: Utils.g('HL_PER_FRAME', 2), // How many code blocks to highlight per frame
485
+ DISABLE_ALL: Utils.g('DISABLE_SYNTAX_HIGHLIGHT', false) // Global off switch for hljs
486
+ };
487
+
488
+ // Intersection-like margins (we do our own scan, but these guide budgets).
489
+ this.OBSERVER = {
490
+ CODE_ROOT_MARGIN: Utils.g('CODE_ROOT_MARGIN', '1000px 0px 1000px 0px'),
491
+ BOX_ROOT_MARGIN: Utils.g('BOX_ROOT_MARGIN', '1500px 0px 1500px 0px'),
492
+ CODE_THRESHOLD: [0, 0.001], BOX_THRESHOLD: 0
493
+ };
494
+
495
+ // Viewport scan preload distance (in pixels).
496
+ this.SCAN = { PRELOAD_PX: Utils.g('SCAN_PRELOAD_PX', 1000) };
497
+
498
+ // Code scroll behavior (auto-follow re-enable margin and near-bottom margin).
499
+ this.CODE_SCROLL = {
500
+ AUTO_FOLLOW_REENABLE_PX: Utils.g('CODE_AUTO_FOLLOW_REENABLE_PX', 8),
501
+ NEAR_MARGIN_PX: Utils.g('CODE_SCROLL_NEAR_MARGIN_PX', 48)
502
+ };
503
+
504
+ // Stream (snapshot) budgets and queue limits.
505
+ this.STREAM = {
506
+ MAX_PER_FRAME: Utils.g('STREAM_MAX_PER_FRAME', 8), // How many chunks to process per frame
507
+ EMERGENCY_COALESCE_LEN: Utils.g('STREAM_EMERGENCY_COALESCE_LEN', 300), // If queue grows beyond, coalesce
508
+ COALESCE_MODE: Utils.g('STREAM_COALESCE_MODE', 'fixed'), // fixed | adaptive
509
+ SNAPSHOT_MAX_STEP: Utils.g('STREAM_SNAPSHOT_MAX_STEP', 8000), // Upper bound for adaptive step
510
+ // Bounds for queue to prevent memory growth on bursty streams
511
+ QUEUE_MAX_ITEMS: Utils.g('STREAM_QUEUE_MAX_ITEMS', 1200),
512
+ PRESERVE_CODES_MAX: Utils.g('STREAM_PRESERVE_CODES_MAX', 120) // Max code blocks to attempt reuse
513
+ };
514
+
515
+ // Math (KaTeX) idle batching and per-batch hint.
516
+ this.MATH = {
517
+ IDLE_TIMEOUT_MS: Utils.g('MATH_IDLE_TIMEOUT_MS', 800),
518
+ BATCH_HINT: Utils.g('MATH_BATCH_HINT', 24)
519
+ };
520
+
521
+ // Icon URLs (provided by host app).
522
+ this.ICONS = {
523
+ EXPAND: Utils.g('ICON_EXPAND', ''), COLLAPSE: Utils.g('ICON_COLLAPSE', ''),
524
+ CODE_MENU: Utils.g('ICON_CODE_MENU', ''), CODE_COPY: Utils.g('ICON_CODE_COPY', ''),
525
+ CODE_RUN: Utils.g('ICON_CODE_RUN', ''), CODE_PREVIEW: Utils.g('ICON_CODE_PREVIEW', '')
526
+ };
527
+
528
+ // Localized UI strings.
529
+ this.LOCALE = {
530
+ PREVIEW: Utils.g('LOCALE_PREVIEW', 'Preview'),
531
+ RUN: Utils.g('LOCALE_RUN', 'Run'),
532
+ COLLAPSE: Utils.g('LOCALE_COLLAPSE', 'Collapse'),
533
+ EXPAND: Utils.g('LOCALE_EXPAND', 'Expand'),
534
+ COPY: Utils.g('LOCALE_COPY', 'Copy'),
535
+ COPIED: Utils.g('LOCALE_COPIED', 'Copied')
536
+ };
537
+
538
+ // Code block styling theme (hljs theme key or custom).
539
+ this.CODE_STYLE = Utils.g('CODE_SYNTAX_STYLE', 'default');
540
+
541
+ // Adaptive snapshot profile for plain text.
542
+ this.PROFILE_TEXT = {
543
+ base: Utils.g('PROFILE_TEXT_BASE', 4), // Base step (chars) between snapshots
544
+ growth: Utils.g('PROFILE_TEXT_GROWTH', 1.28), // Growth factor for adaptive
545
+ minInterval: Utils.g('PROFILE_TEXT_MIN_INTERVAL', 4), // Minimum time between snapshots (ms)
546
+ softLatency: Utils.g('PROFILE_TEXT_SOFT_LATENCY', 60), // If idle for this long, force a snapshot
547
+ adaptiveStep: Utils.g('PROFILE_TEXT_ADAPTIVE_STEP', false)
548
+ };
549
+
550
+ // Adaptive snapshot profile for code (line-aware).
551
+ this.PROFILE_CODE = {
552
+ base: 2048, // Fewer snapshots during fence-open warm-up (reduce transient fragments)
553
+ growth: 2.6, // Ramp step quickly if adaptive is enabled
554
+ minInterval: 500, // Minimum time between snapshots (ms) to avoid churn
555
+ softLatency: 1200, // Force snapshot only after a noticeable idle (ms)
556
+ minLinesForHL: 50, minCharsForHL: 5000,
557
+ promoteMinInterval: 300, promoteMaxLatency: 800, promoteMinLines: 50,
558
+ adaptiveStep: Utils.g('PROFILE_CODE_ADAPTIVE_STEP', true),
559
+ // Hard switches to plain streaming (no incremental hljs, minimal DOM churn)
560
+ stopAfterLines: 300, // Turn off incremental hljs very early
561
+ streamPlainAfterLines: 0, // Belt-and-suspenders: enforce plain mode soon after
562
+ streamPlainAfterChars: 0, // Also guard huge single-line code (chars cap)
563
+ maxFrozenChars: 32000, // If promotions slipped through, cap before spans grow too large
564
+ finalHighlightMaxLines: Utils.g('PROFILE_CODE_FINAL_HL_MAX_LINES', 1000),
565
+ finalHighlightMaxChars: Utils.g('PROFILE_CODE_FINAL_HL_MAX_CHARS', 350000)
566
+ };
567
+
568
+ // Debounce for heavy resets (ms).
569
+ this.RESET = {
570
+ HEAVY_DEBOUNCE_MS: Utils.g('RESET_HEAVY_DEBOUNCE_MS', 24)
571
+ };
572
+
573
+ // Logging caps (used by Logger).
574
+ this.LOG = {
575
+ MAX_QUEUE: Utils.g('LOG_MAX_QUEUE', 400),
576
+ MAX_BYTES: Utils.g('LOG_MAX_BYTES', 256 * 1024),
577
+ BATCH_MAX: Utils.g('LOG_BATCH_MAX', 64),
578
+ RATE_LIMIT_PER_SEC: Utils.g('LOG_RATE_LIMIT_PER_SEC', 0)
579
+ };
580
+
581
+ // Async tuning for background work.
582
+ this.ASYNC = {
583
+ SLICE_MS: Utils.g('ASYNC_SLICE_MS', 12),
584
+ MIN_YIELD_MS: Utils.g('ASYNC_MIN_YIELD_MS', 0),
585
+ MD_NODES_PER_SLICE: Utils.g('ASYNC_MD_NODES_PER_SLICE', 12)
586
+ };
587
+
588
+ // RAF pump tuning (budget per frame).
589
+ this.RAF = {
590
+ FLUSH_BUDGET_MS: Utils.g('RAF_FLUSH_BUDGET_MS', 7),
591
+ MAX_TASKS_PER_FLUSH: Utils.g('RAF_MAX_TASKS_PER_FLUSH', 120)
592
+ };
593
+
594
+ // Markdown tuning – allow/disallow indented code blocks.
595
+ this.MD = {
596
+ ALLOW_INDENTED_CODE: Utils.g('MD_ALLOW_INDENTED_CODE', false)
597
+ };
598
+
599
+ // Custom markup rules for simple tags in text.
600
+ this.CUSTOM_MARKUP_RULES = Utils.g('CUSTOM_MARKUP_RULES', [
601
+ { name: 'cmd', open: '[!cmd]', close: '[/!cmd]', tag: 'div', className: 'cmd', innerMode: 'text' },
602
+ { name: 'think', open: '[!think]', close: '[/!think]', tag: 'think', className: '', innerMode: 'text' }
603
+ ]);
604
+ }
605
+ }
606
+
607
+ // ==========================================================================
608
+ // 1) DOM references
609
+ // ==========================================================================
610
+
611
+ class DOMRefs {
612
+ constructor() { this.els = {}; this.domOutputStream = null; this.domStreamMsg = null; }
613
+ // Cache frequently used elements by id.
614
+ init() {
615
+ const ids = [
616
+ 'container','_nodes_','_append_input_','_append_output_before_','_append_output_',
617
+ '_append_live_','_footer_','_loader_','tips','scrollFab','scrollFabIcon'
618
+ ];
619
+ ids.forEach(id => { this.els[id] = document.getElementById(id); });
620
+ }
621
+ // Get element by id (reads cache first).
622
+ get(id) { return this.els[id] || document.getElementById(id); }
623
+ // Reset ephemeral pointers (used during stream).
624
+ resetEphemeral() { this.domStreamMsg = null; }
625
+ // Release refs and restore default scroll behavior.
626
+ cleanup() {
627
+ this.resetEphemeral(); this.domOutputStream = null; this.els = {};
628
+ try { history.scrollRestoration = "auto"; } catch (_) {}
629
+ }
630
+ // Faster clear of a container by avoiding innerHTML='' (which is slow on large trees).
631
+ fastClear(id) {
632
+ const el = this.get(id);
633
+ if (!el) return null;
634
+ // Fast paths:
635
+ if (el.firstChild) {
636
+ // Prefer replaceChildren, fallback to textContent.
637
+ if (el.replaceChildren) el.replaceChildren();
638
+ else el.textContent = '';
639
+ }
640
+ return el;
641
+ }
642
+
643
+ // Clear and ensure paint on next frame (await before reading layout).
644
+ async fastClearAndPaint(id) {
645
+ const el = this.fastClear(id);
646
+ if (!el) return null;
647
+ // Yield to the next frame through the centralized RafManager to ensure repaint.
648
+ try {
649
+ if (typeof runtime !== 'undefined' && runtime.raf && typeof runtime.raf.nextFrame === 'function') {
650
+ await runtime.raf.nextFrame();
651
+ } else {
652
+ await new Promise(r => setTimeout(r, 16));
653
+ }
654
+ } catch (_) {}
655
+ return el;
656
+ }
657
+
658
+ // Hard clear by temporarily hiding element to avoid intermediate paints.
659
+ fastClearHidden(id) {
660
+ const el = this.get(id);
661
+ if (!el) return null;
662
+ const prevDisplay = el.style.display;
663
+ el.style.display = 'none'; // pause paints
664
+ if (el.replaceChildren) el.replaceChildren();
665
+ else el.textContent = '';
666
+ el.style.display = prevDisplay; // resume paints
667
+ return el;
668
+ }
669
+ // Replace element node by a shallow clone (drops children).
670
+ hardReplaceByClone(id) {
671
+ const el = this.get(id);
672
+ if (!el || !el.parentNode) return null;
673
+ const clone = el.cloneNode(false);
674
+ try { el.replaceWith(clone); } catch (_) { el.innerHTML = ''; }
675
+ this.els[id] = clone;
676
+ if (id === '_append_output_') this.domOutputStream = clone;
677
+ return clone;
678
+ }
679
+ // Clear streaming containers and transient state.
680
+ hardResetStreamContainers() {
681
+ this.resetEphemeral();
682
+ this.domOutputStream = null;
683
+ this.fastClearHidden('_append_output_before_');
684
+ this.fastClearHidden('_append_output_');
685
+ }
686
+ // Return output stream container, caching reference.
687
+ getStreamContainer() {
688
+ if (this.domOutputStream && this.domOutputStream.isConnected) return this.domOutputStream;
689
+ const el = this.get('_append_output_'); if (el) this.domOutputStream = el; return el;
690
+ }
691
+ // Get or create current streaming message container (.msg-box > .msg > .md-snapshot-root).
692
+ getStreamMsg(create, name_header) {
693
+ const container = this.getStreamContainer(); if (!container) return null;
694
+ if (this.domStreamMsg && this.domStreamMsg.isConnected) return this.domStreamMsg;
695
+
696
+ let box = container.querySelector('.msg-box'); let msg = null;
697
+ if (!box && create) {
698
+ box = document.createElement('div'); box.classList.add('msg-box', 'msg-bot');
699
+ if (name_header) {
700
+ const name = document.createElement('div'); name.classList.add('name-header','name-bot'); name.innerHTML = name_header; box.appendChild(name);
701
+ }
702
+ msg = document.createElement('div'); msg.classList.add('msg');
703
+ const snap = document.createElement('div'); snap.className = 'md-snapshot-root';
704
+ msg.appendChild(snap); box.appendChild(msg); container.appendChild(box);
705
+ } else if (box) {
706
+ msg = box.querySelector('.msg');
707
+ if (msg && !msg.querySelector('.md-snapshot-root')) {
708
+ const snap = document.createElement('div'); snap.className = 'md-snapshot-root'; msg.appendChild(snap);
709
+ }
710
+ }
711
+ if (msg) this.domStreamMsg = msg;
712
+ return msg;
713
+ }
714
+ // Clear the "before" area (older messages area).
715
+ clearStreamBefore() {
716
+ if (typeof window.hideTips === 'function') { window.hideTips(); }
717
+ const el = this.fastClearHidden('_append_output_before_');
718
+ if (el) { /* no-op */ }
719
+ }
720
+ // Clear output stream area.
721
+ clearOutput() { this.hardResetStreamContainers(); }
722
+ // Clear messages list and reset state.
723
+ clearNodes() {
724
+ this.clearStreamBefore();
725
+ const el = this.fastClearHidden('_nodes_'); if (el) { el.classList.add('empty_list'); }
726
+ this.resetEphemeral();
727
+ }
728
+ // Clear input area.
729
+ clearInput() { this.fastClearHidden('_append_input_'); }
730
+ // Clear live area and hide it.
731
+ clearLive() {
732
+ const el = this.fastClearHidden('_append_live_'); if (!el) return;
733
+ el.classList.remove('visible');
734
+ el.classList.add('hidden');
735
+ this.resetEphemeral();
736
+ }
737
+ }
738
+
739
+ // ==========================================================================
740
+ // 2) Code scroll state manager
741
+ // ==========================================================================
742
+
743
+ class CodeScrollState {
744
+ constructor(cfg, raf) {
745
+ this.cfg = cfg;
746
+ this.raf = raf;
747
+ this.map = new WeakMap();
748
+ this.rafMap = new WeakMap();
749
+ this.rafIds = new Set(); // legacy
750
+ this.rafKeyMap = new WeakMap();
751
+ }
752
+ // Get or create per-code element state.
753
+ state(el) {
754
+ let s = this.map.get(el);
755
+ if (!s) { s = { autoFollow: false, lastScrollTop: 0, userInteracted: false, freezeUntil: 0 }; this.map.set(el, s); }
756
+ return s;
757
+ }
758
+ // Check if code block is already finalized (not streaming).
759
+ isFinalizedCode(el) {
760
+ if (!el || el.tagName !== 'CODE') return false;
761
+ if (el.dataset && el.dataset._active_stream === '1') return false;
762
+ const highlighted = (el.getAttribute('data-highlighted') === 'yes') || el.classList.contains('hljs');
763
+ return highlighted;
764
+ }
765
+ // Is element scrolled close to the bottom by a margin?
766
+ isNearBottomEl(el, margin = 100) {
767
+ if (!el) return true;
768
+ const distance = el.scrollHeight - el.clientHeight - el.scrollTop;
769
+ return distance <= margin;
770
+ }
771
+ // Scroll code element to the bottom respecting interaction state.
772
+ scrollToBottom(el, live = false, force = false) {
773
+ if (!el || !el.isConnected) return;
774
+ if (!force && this.isFinalizedCode(el)) return;
775
+
776
+ const st = this.state(el);
777
+ const now = Utils.now();
778
+ if (!force && st.freezeUntil && now < st.freezeUntil) return;
779
+
780
+ const distNow = el.scrollHeight - el.clientHeight - el.scrollTop;
781
+ if (!force && distNow <= 1) { st.lastScrollTop = el.scrollTop; return; }
782
+
783
+ const marginPx = live ? 96 : this.cfg.CODE_SCROLL.NEAR_MARGIN_PX;
784
+ const behavior = 'instant';
785
+
786
+ if (!force) {
787
+ if (live && st.autoFollow !== true) return;
788
+ if (!live && !(st.autoFollow === true || this.isNearBottomEl(el, marginPx) || !st.userInteracted)) return;
789
+ }
790
+
791
+ try { el.scrollTo({ top: el.scrollHeight, behavior }); } catch (_) { el.scrollTop = el.scrollHeight; }
792
+ st.lastScrollTop = el.scrollTop;
793
+ }
794
+ // Schedule bottom scroll in rAF (coalesces multiple calls).
795
+ scheduleScroll(el, live = false, force = false) {
796
+ if (!el || !el.isConnected) return;
797
+ if (!force && this.isFinalizedCode(el)) return;
798
+ if (this.rafMap.get(el)) return;
799
+ this.rafMap.set(el, true);
800
+
801
+ let key = this.rafKeyMap.get(el);
802
+ if (!key) { key = { t: 'codeScroll', el }; this.rafKeyMap.set(el, key); }
803
+
804
+ this.raf.schedule(key, () => {
805
+ this.rafMap.delete(el);
806
+ this.scrollToBottom(el, live, force);
807
+ }, 'CodeScroll', 0);
808
+ }
809
+ // Attach scroll/wheel/touch handlers to manage auto-follow state.
810
+ attachHandlers(codeEl) {
811
+ if (!codeEl || codeEl.dataset.csListeners === '1') return;
812
+ codeEl.dataset.csListeners = '1';
813
+ const st = this.state(codeEl);
814
+
815
+ const onScroll = (ev) => {
816
+ const top = codeEl.scrollTop;
817
+ const isUser = !!(ev && ev.isTrusted === true);
818
+ const now = Utils.now();
819
+
820
+ if (this.isFinalizedCode(codeEl)) {
821
+ if (isUser) st.userInteracted = true;
822
+ st.autoFollow = false;
823
+ st.lastScrollTop = top;
824
+ return;
825
+ }
826
+
827
+ if (isUser) {
828
+ if (top + 1 < st.lastScrollTop) {
829
+ st.autoFollow = false; st.userInteracted = true; st.freezeUntil = now + 1000;
830
+ } else if (this.isNearBottomEl(codeEl, this.cfg.CODE_SCROLL.AUTO_FOLLOW_REENABLE_PX)) {
831
+ st.autoFollow = true;
832
+ }
833
+ } else {
834
+ if (this.isNearBottomEl(codeEl, this.cfg.CODE_SCROLL.AUTO_FOLLOW_REENABLE_PX)) st.autoFollow = true;
835
+ }
836
+ st.lastScrollTop = top;
837
+ };
838
+
839
+ const onWheel = (ev) => {
840
+ st.userInteracted = true;
841
+ const now = Utils.now();
842
+
843
+ if (this.isFinalizedCode(codeEl)) { st.autoFollow = false; return; }
844
+
845
+ if (ev.deltaY < 0) { st.autoFollow = false; st.freezeUntil = now + 1000; }
846
+ else if (this.isNearBottomEl(codeEl, this.cfg.CODE_SCROLL.AUTO_FOLLOW_REENABLE_PX)) { st.autoFollow = true; }
847
+ };
848
+
849
+ codeEl.addEventListener('scroll', onScroll, { passive: true });
850
+ codeEl.addEventListener('wheel', onWheel, { passive: true });
851
+ codeEl.addEventListener('touchstart', function () { st.userInteracted = true; }, { passive: true });
852
+ }
853
+ // Ensure code starts scrolled to bottom once after insert.
854
+ initCodeBottomOnce(codeEl) {
855
+ if (!codeEl || !codeEl.isConnected) return;
856
+ if (codeEl.dataset && codeEl.dataset._active_stream === '1') return;
857
+ if (codeEl.dataset && codeEl.dataset.csInitBtm === '1') return;
858
+ const wrapper = codeEl.closest('.code-wrapper');
859
+ if (!wrapper) return;
860
+
861
+ codeEl.dataset.csInitBtm = '1';
862
+ const key = { t: 'codeInitBottom', el: codeEl };
863
+ this.raf.schedule(key, () => {
864
+ if (!codeEl.isConnected) return;
865
+ try {
866
+ this.scrollToBottom(codeEl, false, true);
867
+ const st = this.state(codeEl);
868
+ st.autoFollow = false;
869
+ st.lastScrollTop = codeEl.scrollTop;
870
+ } catch (_) {}
871
+ }, 'CodeScroll', 0);
872
+ }
873
+ // Attach handlers to all bot code blocks under root (or document).
874
+ initScrollableBlocks(root) {
875
+ const scope = root || document;
876
+ let nodes = [];
877
+ if (scope.nodeType === 1 && scope.closest && scope.closest('.msg-box.msg-bot')) {
878
+ nodes = scope.querySelectorAll('pre code');
879
+ } else {
880
+ nodes = document.querySelectorAll('.msg-box.msg-bot pre code');
881
+ }
882
+ if (!nodes.length) return;
883
+ nodes.forEach((code) => {
884
+ this.attachHandlers(code);
885
+ if (code.dataset._active_stream === '1') {
886
+ const st = this.state(code);
887
+ st.autoFollow = true;
888
+ this.scheduleScroll(code, true, false);
889
+ } else {
890
+ this.initCodeBottomOnce(code);
891
+ }
892
+ });
893
+ }
894
+ // Transfer stored scroll state between elements (after replace).
895
+ transfer(oldEl, newEl) {
896
+ if (!oldEl || !newEl || oldEl === newEl) return;
897
+ const oldState = this.map.get(oldEl);
898
+ if (oldState) this.map.set(newEl, { ...oldState });
899
+ this.attachHandlers(newEl);
900
+ }
901
+ // Cancel any scheduled scroll tasks for code blocks.
902
+ cancelAllScrolls() {
903
+ try { this.raf.cancelGroup('CodeScroll'); } catch (_) {}
904
+ this.rafMap = new WeakMap();
905
+ this.rafIds.clear();
906
+ }
907
+ }
908
+
909
+ // ==========================================================================
910
+ // 3) Highlighter (hljs) + rAF viewport scan
911
+ // ==========================================================================
912
+
913
+ class Highlighter {
914
+ constructor(cfg, codeScroll, raf) {
915
+ this.cfg = cfg;
916
+ this.codeScroll = codeScroll;
917
+ this.raf = raf;
918
+ this.hlScheduled = false;
919
+ this.hlQueue = [];
920
+ this.hlQueueSet = new Set();
921
+ this.scanScheduled = false;
922
+
923
+ // Global scanning state for budgeted viewport scans (prevents long frames).
924
+ this._globalScanState = null;
925
+ // Budget per scan step (ms) – based on RAF budget hint with a small clamp.
926
+ const hint = (cfg && cfg.RAF && cfg.RAF.FLUSH_BUDGET_MS) ? cfg.RAF.FLUSH_BUDGET_MS : 7;
927
+ this.SCAN_STEP_BUDGET_MS = Math.max(3, Math.min(12, hint));
928
+ }
929
+ // Global switch to skip all highlighting.
930
+ isDisabled() { return !!this.cfg.HL.DISABLE_ALL; }
931
+ // Configure hljs once (safe if hljs not present).
932
+ initHLJS() {
933
+ if (this.isDisabled()) return;
934
+ if (typeof hljs !== 'undefined' && hljs) { try { hljs.configure({ ignoreUnescapedHTML: true }); } catch (_) {} }
935
+ }
936
+ // Check if code is near viewport (with preload).
937
+ _nearViewport(el) {
938
+ const preload = this.cfg.SCAN.PRELOAD_PX;
939
+ const vh = window.innerHeight || Utils.SE.clientHeight || 800;
940
+ const r = el.getBoundingClientRect();
941
+ return r.bottom >= -preload && r.top <= (vh + preload);
942
+ }
943
+ // Queue a code element for highlight; skip active streaming code and heavy-known cases.
944
+ queue(codeEl, activeCode) {
945
+ if (this.isDisabled()) return;
946
+ if (!codeEl || !codeEl.isConnected) return;
947
+ if (activeCode && codeEl === activeCode.codeEl) return;
948
+ if (codeEl.getAttribute('data-highlighted') === 'yes') return;
949
+ if (codeEl.dataset && (codeEl.dataset.hlStreamSuspended === '1' || codeEl.dataset.finalHlSkip === '1')) return; // skip heavy blocks intentionally left plain
950
+ if (!codeEl.closest('.msg-box.msg-bot')) return;
951
+ if (!this.hlQueueSet.has(codeEl)) { this.hlQueueSet.add(codeEl); this.hlQueue.push(codeEl); }
952
+ if (!this.hlScheduled) {
953
+ this.hlScheduled = true;
954
+ this.raf.schedule('HL:flush', () => this.flush(activeCode), 'Highlighter', 1);
955
+ }
956
+ }
957
+ // Process a small batch of code elements per frame.
958
+ flush(activeCode) {
959
+ if (this.isDisabled()) { this.hlScheduled = false; this.hlQueueSet.clear(); this.hlQueue.length = 0; return; }
960
+ this.hlScheduled = false;
961
+ let count = 0;
962
+ while (this.hlQueue.length && count < this.cfg.HL.PER_FRAME) {
963
+ const el = this.hlQueue.shift();
964
+ if (el && el.isConnected) this.safeHighlight(el, activeCode);
965
+ if (el) this.hlQueueSet.delete(el);
966
+ count++;
967
+ try {
968
+ const sched = (navigator && navigator.scheduling && navigator.scheduling.isInputPending) ? navigator.scheduling : null;
969
+ if (sched && sched.isInputPending({ includeContinuous: true })) {
970
+ if (this.hlQueue.length) {
971
+ this.hlScheduled = true;
972
+ this.raf.schedule('HL:flush', () => this.flush(activeCode), 'Highlighter', 1);
973
+ }
974
+ return;
975
+ }
976
+ } catch (_) {}
977
+ }
978
+ if (this.hlQueue.length) {
979
+ this.hlScheduled = true;
980
+ this.raf.schedule('HL:flush', () => this.flush(activeCode), 'Highlighter', 1);
981
+ }
982
+ }
983
+ // Highlight a single code block with safety checks and scroll preservation.
984
+ safeHighlight(codeEl, activeCode) {
985
+ if (this.isDisabled()) return;
986
+ if (!window.hljs || !codeEl || !codeEl.isConnected) return;
987
+ if (!codeEl.closest('.msg-box.msg-bot')) return;
988
+ if (codeEl.getAttribute('data-highlighted') === 'yes') return;
989
+ if (activeCode && codeEl === activeCode.codeEl) return;
990
+
991
+ // fast-skip final highlight for gigantic blocks using precomputed meta.
992
+ try {
993
+ const wrap = codeEl.closest('.code-wrapper');
994
+ const maxLines = this.cfg.PROFILE_CODE.finalHighlightMaxLines | 0;
995
+ const maxChars = this.cfg.PROFILE_CODE.finalHighlightMaxChars | 0;
996
+
997
+ // Prefer wrapper meta if available to avoid .textContent on huge nodes.
998
+ let lines = NaN, chars = NaN;
999
+ if (wrap) {
1000
+ const nlAttr = wrap.getAttribute('data-code-nl');
1001
+ const lenAttr = wrap.getAttribute('data-code-len');
1002
+ if (nlAttr) lines = parseInt(nlAttr, 10);
1003
+ if (lenAttr) chars = parseInt(lenAttr, 10);
1004
+ }
1005
+
1006
+ if ((Number.isFinite(lines) && maxLines > 0 && lines > maxLines) ||
1007
+ (Number.isFinite(chars) && maxChars > 0 && chars > maxChars)) {
1008
+ codeEl.classList.add('hljs');
1009
+ codeEl.setAttribute('data-highlighted', 'yes');
1010
+ codeEl.dataset.finalHlSkip = '1';
1011
+ try { this.codeScroll.attachHandlers(codeEl); } catch (_) {}
1012
+ this.codeScroll.scheduleScroll(codeEl, false, false);
1013
+ return;
1014
+ }
1015
+
1016
+ // Fallback to reading actual text only if wrapper meta is missing.
1017
+ if (!Number.isFinite(lines) || !Number.isFinite(chars)) {
1018
+ const txt0 = codeEl.textContent || '';
1019
+ const ln0 = Utils.countNewlines(txt0);
1020
+ if ((maxLines > 0 && ln0 > maxLines) || (maxChars > 0 && txt0.length > maxChars)) {
1021
+ codeEl.classList.add('hljs');
1022
+ codeEl.setAttribute('data-highlighted', 'yes');
1023
+ codeEl.dataset.finalHlSkip = '1';
1024
+ try { this.codeScroll.attachHandlers(codeEl); } catch (_) {}
1025
+ this.codeScroll.scheduleScroll(codeEl, false, false);
1026
+ return;
1027
+ }
1028
+ }
1029
+ } catch (_) { /* safe fallback */ }
1030
+
1031
+ const wasNearBottom = this.codeScroll.isNearBottomEl(codeEl, 16);
1032
+ const st = this.codeScroll.state(codeEl);
1033
+ const shouldAutoScrollAfter = (st.autoFollow === true) || wasNearBottom;
1034
+
1035
+ try {
1036
+ try { codeEl.classList.remove('hljs'); codeEl.removeAttribute('data-highlighted'); } catch (_) {}
1037
+ const txt = codeEl.textContent || '';
1038
+ codeEl.textContent = txt; // ensure no stale spans remain
1039
+ hljs.highlightElement(codeEl);
1040
+ codeEl.setAttribute('data-highlighted', 'yes');
1041
+ } catch (_) {
1042
+ if (!codeEl.classList.contains('hljs')) codeEl.classList.add('hljs');
1043
+ } finally {
1044
+ try { this.codeScroll.attachHandlers(codeEl); } catch (_) {}
1045
+ const needInitForce = (codeEl.dataset && (codeEl.dataset.csInitBtm === '1' || codeEl.dataset.justFinalized === '1'));
1046
+ const mustScroll = shouldAutoScrollAfter || needInitForce;
1047
+ if (mustScroll) this.codeScroll.scheduleScroll(codeEl, false, !!needInitForce);
1048
+ if (codeEl.dataset) {
1049
+ if (codeEl.dataset.csInitBtm === '1') codeEl.dataset.csInitBtm = '0';
1050
+ if (codeEl.dataset.justFinalized === '1') codeEl.dataset.justFinalized = '0';
1051
+ }
1052
+ }
1053
+ }
1054
+
1055
+ // Start a budgeted global scan – split across frames to avoid long blocking.
1056
+ _startGlobalScan(activeCode) {
1057
+ if (this.isDisabled()) return;
1058
+ const preload = this.cfg.SCAN_PRELOAD_PX || this.cfg.SCAN.PRELOAD_PX;
1059
+ const vh = window.innerHeight || Utils.SE.clientHeight || 800;
1060
+ const rectTop = 0 - preload, rectBottom = vh + preload;
1061
+ const nodes = Array.from(document.querySelectorAll('.msg-box.msg-bot pre code:not([data-highlighted="yes"])'));
1062
+ this._globalScanState = { nodes, idx: 0, rectTop, rectBottom, activeCode };
1063
+ this._scanGlobalStep();
1064
+ }
1065
+ // Continue global scan for visible code elements under a time budget.
1066
+ _scanGlobalStep() {
1067
+ const state = this._globalScanState;
1068
+ if (!state || !state.nodes || state.idx >= state.nodes.length) { this._globalScanState = null; return; }
1069
+ const start = Utils.now();
1070
+ while (state.idx < state.nodes.length) {
1071
+ const code = state.nodes[state.idx++];
1072
+ if (!code || !code.isConnected) continue;
1073
+ if (state.activeCode && code === state.activeCode.codeEl) continue;
1074
+ try {
1075
+ const r = code.getBoundingClientRect();
1076
+ if (r.bottom >= state.rectTop && r.top <= state.rectBottom) this.queue(code, state.activeCode);
1077
+ } catch (_) {}
1078
+ if ((Utils.now() - start) >= this.SCAN_STEP_BUDGET_MS) {
1079
+ // Schedule next slice to keep UI responsive.
1080
+ this.raf.schedule('HL:scanStep', () => this._scanGlobalStep(), 'Highlighter', 2);
1081
+ return;
1082
+ }
1083
+ }
1084
+ this._globalScanState = null;
1085
+ }
1086
+
1087
+ // Observe new code blocks and queue those near the viewport.
1088
+ observeNewCode(root, opts, activeCode) {
1089
+ const scope = root || document;
1090
+ let nodes;
1091
+ if (scope.nodeType === 1 && scope.closest && scope.closest('.msg-box.msg-bot')) nodes = scope.querySelectorAll('pre code');
1092
+ else nodes = document.querySelectorAll('.msg-box.msg-bot pre code');
1093
+ if (!nodes || !nodes.length) return;
1094
+
1095
+ const options = Object.assign({ deferLastIfStreaming: false, minLinesForLast: 2, minCharsForLast: 120 }, (opts || {}));
1096
+ nodes.forEach((code) => {
1097
+ if (!code.closest('.msg-box.msg-bot')) return;
1098
+ this.codeScroll.attachHandlers(code);
1099
+ if (this.isDisabled()) return;
1100
+ if (activeCode && code === activeCode.codeEl) return;
1101
+
1102
+ if (options.deferLastIfStreaming && activeCode && code === activeCode.codeEl) {
1103
+ const tailLen = (activeCode.tailEl && activeCode.tailEl.textContent) ? activeCode.tailEl.textContent.length : 0;
1104
+ const tailLines = (typeof activeCode.tailLines === 'number') ? activeCode.tailLines : 0;
1105
+ if (tailLines < options.minLinesForLast && tailLen < options.minCharsForLast) return;
1106
+ }
1107
+ if (this._nearViewport(code)) this.queue(code, activeCode);
1108
+ });
1109
+ }
1110
+ // Schedule a viewport scan in a budgeted way.
1111
+ scheduleScanVisibleCodes(activeCode) {
1112
+ if (this.isDisabled()) return;
1113
+
1114
+ // Fast bail-out: nothing to highlight and no active streaming code.
1115
+ try {
1116
+ const anyCandidate = document.querySelector('.msg-box.msg-bot pre code:not([data-highlighted="yes"])');
1117
+ const hasActive = !!(activeCode && activeCode.codeEl && activeCode.codeEl.isConnected);
1118
+ if (!anyCandidate && !hasActive) return;
1119
+ } catch (_) { /* safe fallback */ }
1120
+
1121
+ // If a scan is already in progress, just ensure next step is scheduled; otherwise schedule start.
1122
+ if (this._globalScanState) {
1123
+ this.raf.schedule('HL:scanStep', () => this._scanGlobalStep(), 'Highlighter', 2);
1124
+ return;
1125
+ }
1126
+ if (this.scanScheduled) return;
1127
+ this.scanScheduled = true;
1128
+ this.raf.schedule('HL:scan', () => {
1129
+ this.scanScheduled = false;
1130
+ this._startGlobalScan(activeCode || null);
1131
+ }, 'Highlighter', 2);
1132
+ }
1133
+
1134
+ // Direct scan (synchronous) – used in places where root scope is small.
1135
+ scanVisibleCodes(activeCode) {
1136
+ this._startGlobalScan(activeCode || null);
1137
+ }
1138
+ // Scan only inside a given root (synchronous, small scopes).
1139
+ scanVisibleCodesInRoot(root, activeCode) {
1140
+ if (this.isDisabled()) return;
1141
+ const preload = this.cfg.SCAN_PRELOAD_PX || this.cfg.SCAN.PRELOAD_PX;
1142
+ const vh = window.innerHeight || Utils.SE.clientHeight || 800;
1143
+ const rectTop = 0 - preload, rectBottom = vh + preload;
1144
+ const scope = root || document;
1145
+ const nodes = scope.querySelectorAll('.msg-box.msg-bot pre code:not([data-highlighted="yes"])');
1146
+ // Local root scans tend to be small – keep them synchronous for simplicity.
1147
+ nodes.forEach((code) => {
1148
+ if (!code.isConnected) return;
1149
+ if (activeCode && code === activeCode.codeEl) return;
1150
+ const r = code.getBoundingClientRect();
1151
+ if (r.bottom >= rectTop && r.top <= rectBottom) this.queue(code, activeCode);
1152
+ });
1153
+ }
1154
+ installBoxObserver() { /* no-op */ }
1155
+ // Visit bot message boxes and call callback (used for local scans).
1156
+ observeMsgBoxes(root, onBoxIntersect) {
1157
+ const scope = root || document;
1158
+ let boxes;
1159
+ if (scope.nodeType === 1) boxes = scope.querySelectorAll('.msg-box.msg-bot');
1160
+ else boxes = document.querySelectorAll('.msg-box.msg-bot');
1161
+ boxes.forEach((box) => { onBoxIntersect && onBoxIntersect(box); });
1162
+ }
1163
+ // Clear all internal queues and scheduled jobs.
1164
+ cleanup() {
1165
+ try { this.raf.cancelGroup('Highlighter'); } catch (_) {}
1166
+ this.hlScheduled = false;
1167
+ this.scanScheduled = false;
1168
+ this._globalScanState = null;
1169
+ this.hlQueueSet.clear(); this.hlQueue.length = 0;
1170
+ }
1171
+ }
1172
+
1173
+ // ==========================================================================
1174
+ // 4) Custom Markup Processor
1175
+ // ==========================================================================
1176
+
1177
+ class CustomMarkup {
1178
+ // Logger-aware processor; no console usage.
1179
+ constructor(cfg, logger) {
1180
+ this.cfg = cfg || { CUSTOM_MARKUP_RULES: [] };
1181
+ this.logger = logger || new Logger(cfg);
1182
+ this.__compiled = null;
1183
+ }
1184
+ _d(line, ctx) { try { this.logger.debug('CM', line, ctx); } catch (_) {} }
1185
+
1186
+ // Compile rules once; also precompile strict and whitespace-tolerant "full match" regexes.
1187
+ compile(rules) {
1188
+ const src = Array.isArray(rules) ? rules : (window.CUSTOM_MARKUP_RULES || this.cfg.CUSTOM_MARKUP_RULES || []);
1189
+ const compiled = [];
1190
+ for (const r of src) {
1191
+ if (!r || typeof r.open !== 'string' || typeof r.close !== 'string') continue;
1192
+ const tag = (r.tag || 'span').toLowerCase();
1193
+ const className = (r.className || r.class || '').trim();
1194
+ const innerMode = (r.innerMode === 'markdown-inline' || r.innerMode === 'text') ? r.innerMode : 'text';
1195
+
1196
+ const re = new RegExp(Utils.reEscape(r.open) + '([\\s\\S]*?)' + Utils.reEscape(r.close), 'g');
1197
+ const reFull = new RegExp('^' + Utils.reEscape(r.open) + '([\\s\\S]*?)' + Utils.reEscape(r.close) + '$');
1198
+ const reFullTrim = new RegExp('^\\s*' + Utils.reEscape(r.open) + '([\\s\\S]*?)' + Utils.reEscape(r.close) + '\\s*$');
1199
+
1200
+ const item = { name: r.name || tag, tag, className, innerMode, open: r.open, close: r.close, re, reFull, reFullTrim };
1201
+ compiled.push(item);
1202
+ this._d('COMPILE_RULE', { name: item.name, tag: item.tag, innerMode: item.innerMode, open: item.open, close: item.close });
1203
+ }
1204
+ if (compiled.length === 0) {
1205
+ const open = '[!cmd]', close = '[/!cmd]';
1206
+ const item = {
1207
+ name: 'cmd', tag: 'p', className: 'cmd', innerMode: 'text', open, close,
1208
+ re: new RegExp(Utils.reEscape(open) + '([\\s\\S]*?)' + Utils.reEscape(close), 'g'),
1209
+ reFull: new RegExp('^' + Utils.reEscape(open) + '([\\s\\S]*?)' + Utils.reEscape(close) + '$'),
1210
+ reFullTrim: new RegExp('^\\s*' + Utils.reEscape(open) + '([\\s\\S]*?)' + Utils.reEscape(close) + '\\s*$')
1211
+ };
1212
+ compiled.push(item);
1213
+ this._d('COMPILE_RULE_FALLBACK', { name: item.name });
1214
+ }
1215
+ return compiled;
1216
+ }
1217
+ // Ensure rules are compiled and cached.
1218
+ ensureCompiled() {
1219
+ if (!this.__compiled) {
1220
+ this.__compiled = this.compile(window.CUSTOM_MARKUP_RULES || this.cfg.CUSTOM_MARKUP_RULES);
1221
+ this._d('ENSURE_COMPILED', { count: this.__compiled.length });
1222
+ }
1223
+ return this.__compiled;
1224
+ }
1225
+ // Replace rules set (also exposes rules on window).
1226
+ setRules(rules) {
1227
+ this.__compiled = this.compile(rules);
1228
+ window.CUSTOM_MARKUP_RULES = Array.isArray(rules) ? rules.slice() : (this.cfg.CUSTOM_MARKUP_RULES || []).slice();
1229
+ this._d('SET_RULES', { count: this.__compiled.length });
1230
+ }
1231
+ // Return current rules as array.
1232
+ getRules() {
1233
+ const list = (window.CUSTOM_MARKUP_RULES ? window.CUSTOM_MARKUP_RULES.slice()
1234
+ : (this.cfg.CUSTOM_MARKUP_RULES || []).slice());
1235
+ this._d('GET_RULES', { count: list.length });
1236
+ return list;
1237
+ }
1238
+
1239
+ // Context guards
1240
+ isInsideForbiddenContext(node) {
1241
+ const p = node.parentElement; if (!p) return true;
1242
+ return !!p.closest('pre, code, kbd, samp, var, script, style, textarea, .math-pending, .hljs, .code-wrapper');
1243
+ }
1244
+ isInsideForbiddenElement(el) {
1245
+ if (!el) return true;
1246
+ return !!el.closest('pre, code, kbd, samp, var, script, style, textarea, .math-pending, .hljs, .code-wrapper');
1247
+ }
1248
+
1249
+ // Global finder on a single text blob (original per-text-node logic).
1250
+ findNextMatch(text, from, rules) {
1251
+ let best = null;
1252
+ for (const rule of rules) {
1253
+ rule.re.lastIndex = from;
1254
+ const m = rule.re.exec(text);
1255
+ if (m) {
1256
+ const start = m.index, end = rule.re.lastIndex;
1257
+ if (!best || start < best.start) best = { rule, start, end, inner: m[1] || '' };
1258
+ }
1259
+ }
1260
+ return best;
1261
+ }
1262
+
1263
+ // Strict full match of a pure text node (legacy path).
1264
+ findFullMatch(text, rules) {
1265
+ for (const rule of rules) {
1266
+ if (rule.reFull) {
1267
+ const m = rule.reFull.exec(text);
1268
+ if (m) return { rule, inner: m[1] || '' };
1269
+ } else {
1270
+ // Legacy safety net (should not normally execute).
1271
+ rule.re.lastIndex = 0;
1272
+ const m = rule.re.exec(text);
1273
+ if (m && m.index === 0 && (rule.re.lastIndex === text.length)) {
1274
+ const m2 = rule.re.exec(text);
1275
+ if (!m2) return { rule, inner: m[1] || '' };
1276
+ }
1277
+ }
1278
+ }
1279
+ return null;
1280
+ }
1281
+
1282
+ // Set inner content according to the rule's mode.
1283
+ setInnerByMode(el, mode, text, MD) {
1284
+ if (mode === 'markdown-inline' && typeof window.markdownit !== 'undefined') {
1285
+ try {
1286
+ if (MD && typeof MD.renderInline === 'function') { el.innerHTML = MD.renderInline(text || ''); return; }
1287
+ const tempMD = window.markdownit({ html: false, linkify: true, breaks: true, highlight: () => '' });
1288
+ el.innerHTML = tempMD.renderInline(text || ''); return;
1289
+ } catch (_) {}
1290
+ }
1291
+ el.textContent = text || '';
1292
+ }
1293
+
1294
+ // Try to replace an entire <p> that is a full custom markup match.
1295
+ _tryReplaceFullParagraph(el, rules, MD) {
1296
+ if (!el || el.tagName !== 'P') return false;
1297
+ if (this.isInsideForbiddenElement(el)) {
1298
+ this._d('P_SKIP_FORBIDDEN', { tag: el.tagName });
1299
+ return false;
1300
+ }
1301
+ const t = el.textContent || '';
1302
+ if (t.indexOf('[!') === -1) return false;
1303
+
1304
+ for (const rule of rules) {
1305
+ if (!rule || rule.tag !== 'p') continue;
1306
+ const m = rule.reFullTrim ? rule.reFullTrim.exec(t) : null;
1307
+ if (!m) continue;
1308
+
1309
+ const out = document.createElement('p');
1310
+ if (rule.className) out.className = rule.className;
1311
+ out.setAttribute('data-cm', rule.name);
1312
+ const innerText = m[1] || '';
1313
+ this.setInnerByMode(out, rule.innerMode, innerText, MD);
1314
+
1315
+ try { el.replaceWith(out); } catch (_) {
1316
+ const parent = el.parentNode; if (parent) parent.replaceChild(out, el);
1317
+ }
1318
+
1319
+ this._d('P_REPLACED', { rule: rule.name, preview: this.logger.pv(t, 160) });
1320
+ return true;
1321
+ }
1322
+ this._d('P_NO_FULL_MATCH', { preview: this.logger.pv(t, 160) });
1323
+ return false;
1324
+ }
1325
+
1326
+ // Apply custom markup with two-phase strategy:
1327
+ // 1) Full-paragraph tolerant pass (survives linkify splitting).
1328
+ // 2) Legacy per-text-node pass for partial inline cases.
1329
+ apply(root, MD) {
1330
+ this.ensureCompiled();
1331
+ const rules = this.__compiled;
1332
+ if (!root || !rules || !rules.length) return;
1333
+
1334
+ const scope = (root.nodeType === 1 || root.nodeType === 11) ? root : document;
1335
+ try {
1336
+ const paragraphs = (typeof scope.querySelectorAll === 'function') ? scope.querySelectorAll('p') : [];
1337
+ this._d('P_TOLERANT_SCAN_START', { count: paragraphs.length });
1338
+
1339
+ if (paragraphs && paragraphs.length) {
1340
+ for (let i = 0; i < paragraphs.length; i++) {
1341
+ const p = paragraphs[i];
1342
+ if (p && p.getAttribute && p.getAttribute('data-cm')) continue;
1343
+ // Quick check: avoid work if no marker in entire <p>
1344
+ const tc = p && (p.textContent || '');
1345
+ if (!tc || tc.indexOf('[!') === -1) continue;
1346
+ this._tryReplaceFullParagraph(p, rules, MD);
1347
+ }
1348
+ }
1349
+ } catch (e) {
1350
+ this._d('P_TOLERANT_SCAN_ERR', String(e));
1351
+ }
1352
+
1353
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
1354
+ acceptNode: (node) => {
1355
+ if (!node || !node.nodeValue || node.nodeValue.indexOf('[!') === -1) return NodeFilter.FILTER_SKIP;
1356
+ if (this.isInsideForbiddenContext(node)) return NodeFilter.FILTER_REJECT;
1357
+ return NodeFilter.FILTER_ACCEPT;
1358
+ }
1359
+ });
1360
+
1361
+ let node;
1362
+ while ((node = walker.nextNode())) {
1363
+ const text = node.nodeValue;
1364
+ if (!text || text.indexOf('[!') === -1) continue;
1365
+
1366
+ const parent = node.parentElement;
1367
+
1368
+ // Entire text node equals one full match and parent is <p>.
1369
+ if (parent && parent.tagName === 'P' && parent.childNodes.length === 1) {
1370
+ const fm = this.findFullMatch(text, rules);
1371
+ if (fm && fm.rule.tag === 'p') {
1372
+ const out = document.createElement('p');
1373
+ if (fm.rule.className) out.className = fm.rule.className;
1374
+ out.setAttribute('data-cm', fm.rule.name);
1375
+ this.setInnerByMode(out, fm.rule.innerMode, fm.inner, MD);
1376
+ try { parent.replaceWith(out); } catch (_) {
1377
+ const par = parent.parentNode; if (par) par.replaceChild(out, parent);
1378
+ }
1379
+ this._d('WALKER_FULL_REPLACE', { rule: fm.rule.name, preview: this.logger.pv(text, 160) });
1380
+ continue;
1381
+ }
1382
+ }
1383
+
1384
+ // General inline replacement inside the text node (span-like).
1385
+ let i = 0;
1386
+ let didReplace = false;
1387
+ const frag = document.createDocumentFragment();
1388
+
1389
+ while (i < text.length) {
1390
+ const m = this.findNextMatch(text, i, rules);
1391
+ if (!m) break;
1392
+
1393
+ if (m.start > i) {
1394
+ frag.appendChild(document.createTextNode(text.slice(i, m.start)));
1395
+ }
1396
+
1397
+ const tag = (m.rule.tag === 'p') ? 'span' : m.rule.tag;
1398
+ const el = document.createElement(tag);
1399
+ if (m.rule.className) el.className = m.rule.className;
1400
+ el.setAttribute('data-cm', m.rule.name);
1401
+ this.setInnerByMode(el, m.rule.innerMode, m.inner, MD);
1402
+
1403
+ frag.appendChild(el);
1404
+ this._d('WALKER_INLINE_MATCH', { rule: m.rule.name, start: m.start, end: m.end });
1405
+ i = m.end;
1406
+ didReplace = true;
1407
+ }
1408
+
1409
+ if (!didReplace) continue;
1410
+
1411
+ if (i < text.length) {
1412
+ frag.appendChild(document.createTextNode(text.slice(i)));
1413
+ }
1414
+
1415
+ const parentNode = node.parentNode;
1416
+ if (parentNode) {
1417
+ parentNode.replaceChild(frag, node);
1418
+ this._d('WALKER_INLINE_DONE', { preview: this.logger.pv(text, 120) });
1419
+ }
1420
+ }
1421
+ }
1422
+ }
1423
+
1424
+ // ==========================================================================
1425
+ // 5) Markdown runtime (markdown-it + code wrapper + math placeholders)
1426
+ // ==========================================================================
1427
+
1428
+ class MarkdownRenderer {
1429
+ constructor(cfg, customMarkup, logger, asyncer, raf) {
1430
+ this.cfg = cfg; this.customMarkup = customMarkup; this.MD = null;
1431
+ this.logger = logger || new Logger(cfg);
1432
+ // Cooperative async utilities available in renderer for heavy decode/render paths
1433
+ this.asyncer = asyncer || new AsyncRunner(cfg, raf);
1434
+ this.raf = raf || null;
1435
+
1436
+ // Fast-path streaming renderer without linkify to reduce regex work on hot path.
1437
+ this.MD_STREAM = null;
1438
+
1439
+ this.hooks = {
1440
+ observeNewCode: () => {},
1441
+ observeMsgBoxes: () => {},
1442
+ scheduleMathRender: () => {},
1443
+ codeScrollInit: () => {}
1444
+ };
1445
+ }
1446
+ // Initialize markdown-it instances and plugins.
1447
+ init() {
1448
+ if (!window.markdownit) { this.logger.log('[MD] markdown-it not found – rendering skipped.'); return; }
1449
+ // Full renderer (used for non-hot paths, final results)
1450
+ this.MD = window.markdownit({ html: false, linkify: true, breaks: true, highlight: () => '' });
1451
+ // Streaming renderer (no linkify) – hot path
1452
+ this.MD_STREAM = window.markdownit({ html: false, linkify: false, breaks: true, highlight: () => '' });
1453
+
1454
+ // SAFETY: disable CommonMark "indented code blocks" unless explicitly enabled.
1455
+ if (!this.cfg.MD || this.cfg.MD.ALLOW_INDENTED_CODE !== true) {
1456
+ try { this.MD.block.ruler.disable('code'); } catch (_) {}
1457
+ try { this.MD_STREAM.block.ruler.disable('code'); } catch (_) {}
1458
+ }
1459
+
1460
+ const escapeHtml = Utils.escapeHtml;
1461
+
1462
+ // Dollar and bracket math placeholder plugins: generate lightweight placeholders to be picked up by KaTeX later.
1463
+ const mathDollarPlaceholderPlugin = (md) => {
1464
+ function notEscaped(src, pos) { let back = 0; while (pos - back - 1 >= 0 && src.charCodeAt(pos - back - 1) === 0x5C) back++; return (back % 2) === 0; }
1465
+ function math_block_dollar(state, startLine, endLine, silent) {
1466
+ const pos = state.bMarks[startLine] + state.tShift[startLine];
1467
+ const max = state.eMarks[startLine];
1468
+ if (pos + 1 >= max) return false;
1469
+ if (state.src.charCodeAt(pos) !== 0x24 || state.src.charCodeAt(pos + 1) !== 0x24) return false;
1470
+ let nextLine = startLine + 1, found = false;
1471
+ for (; nextLine < endLine; nextLine++) {
1472
+ let p = state.bMarks[nextLine] + state.tShift[nextLine];
1473
+ const pe = state.eMarks[nextLine];
1474
+ if (p + 1 < pe && state.src.charCodeAt(p) === 0x24 && state.src.charCodeAt(p + 1) === 0x24) { found = true; break; }
1475
+ }
1476
+ if (!found) return false;
1477
+ if (silent) return true;
1478
+
1479
+ const contentStart = state.bMarks[startLine] + state.tShift[startLine] + 2;
1480
+ const contentEndLine = nextLine - 1;
1481
+ let content = '';
1482
+ if (contentEndLine >= startLine + 1) {
1483
+ const startIdx = state.bMarks[startLine + 1];
1484
+ const endIdx = state.eMarks[contentEndLine];
1485
+ content = state.src.slice(startIdx, endIdx);
1486
+ } else content = '';
1487
+
1488
+ const token = state.push('math_block_dollar', '', 0);
1489
+ token.block = true; token.content = content; state.line = nextLine + 1; return true;
1490
+ }
1491
+ function math_inline_dollar(state, silent) {
1492
+ const pos = state.pos, src = state.src, max = state.posMax;
1493
+ if (pos >= max) return false;
1494
+ if (src.charCodeAt(pos) !== 0x24) return false;
1495
+ if (pos + 1 < max && src.charCodeAt(pos + 1) === 0x24) return false;
1496
+ const after = pos + 1 < max ? src.charCodeAt(pos + 1) : 0;
1497
+ if (after === 0x20 || after === 0x0A || after === 0x0D) return false;
1498
+ let i = pos + 1;
1499
+ while (i < max) {
1500
+ const ch = src.charCodeAt(i);
1501
+ if (ch === 0x24 && notEscaped(src, i)) {
1502
+ const before = i - 1 >= 0 ? src.charCodeAt(i - 1) : 0;
1503
+ if (before === 0x20 || before === 0x0A || before === 0x0D) { i++; continue; }
1504
+ break;
1505
+ }
1506
+ i++;
1507
+ }
1508
+ if (i >= max || src.charCodeAt(i) !== 0x24) return false;
1509
+
1510
+ if (!silent) {
1511
+ const token = state.push('math_inline_dollar', '', 0);
1512
+ token.block = false; token.content = src.slice(pos + 1, i);
1513
+ }
1514
+ state.pos = i + 1; return true;
1515
+ }
1516
+
1517
+ md.block.ruler.before('fence', 'math_block_dollar', math_block_dollar, { alt: ['paragraph', 'reference', 'blockquote', 'list'] });
1518
+ md.inline.ruler.before('escape', 'math_inline_dollar', math_inline_dollar);
1519
+
1520
+ md.renderer.rules.math_inline_dollar = (tokens, idx) => {
1521
+ const tex = tokens[idx].content || '';
1522
+ return `<span class="math-pending" data-display="0"><span class="math-fallback">$${escapeHtml(tex)}$</span><script type="math/tex">${escapeHtml(tex)}</script></span>`;
1523
+ };
1524
+ md.renderer.rules.math_block_dollar = (tokens, idx) => {
1525
+ const tex = tokens[idx].content || '';
1526
+ return `<div class="math-pending" data-display="1"><div class="math-fallback">$$${escapeHtml(tex)}$$</div><script type="math/tex; mode=display">${escapeHtml(tex)}</script></div>`;
1527
+ };
1528
+ };
1529
+
1530
+ const mathBracketsPlaceholderPlugin = (md) => {
1531
+ function math_brackets(state, silent) {
1532
+ const src = state.src, pos = state.pos, max = state.posMax;
1533
+ if (pos + 1 >= max || src.charCodeAt(pos) !== 0x5C) return false;
1534
+ const next = src.charCodeAt(pos + 1);
1535
+ if (next !== 0x28 && next !== 0x5B) return false;
1536
+ const isInline = (next === 0x28); const close = isInline ? '\\)' : '\\]';
1537
+ const start = pos + 2; const end = src.indexOf(close, start);
1538
+ if (end < 0) return false;
1539
+ const content = src.slice(start, end);
1540
+ if (!silent) {
1541
+ const t = state.push(isInline ? 'math_inline_bracket' : 'math_block_bracket', '', 0);
1542
+ t.content = content; t.block = !isInline;
1543
+ }
1544
+ state.pos = end + 2; return true;
1545
+ }
1546
+ md.inline.ruler.before('escape', 'math_brackets', math_brackets);
1547
+ md.renderer.rules.math_inline_bracket = (tokens, idx) => {
1548
+ const tex = tokens[idx].content || '';
1549
+ return `<span class="math-pending" data-display="0"><span class="math-fallback">\\(${escapeHtml(tex)}\\)</span><script type="math/tex">${escapeHtml(tex)}</script></span>`;
1550
+ };
1551
+ md.renderer.rules.math_block_bracket = (tokens, idx) => {
1552
+ const tex = tokens[idx].content || '';
1553
+ return `<div class="math-pending" data-display="1"><div class="math-fallback">\\[${escapeHtml(tex)}\\]</div><script type="math/tex; mode=display">${escapeHtml(tex)}</script></div>`;
1554
+ };
1555
+ };
1556
+
1557
+ this.MD.use(mathDollarPlaceholderPlugin);
1558
+ this.MD.use(mathBracketsPlaceholderPlugin);
1559
+ this.MD_STREAM.use(mathDollarPlaceholderPlugin);
1560
+ this.MD_STREAM.use(mathBracketsPlaceholderPlugin);
1561
+
1562
+ const cfg = this.cfg; const logger = this.logger;
1563
+ (function codeWrapperPlugin(md, logger) {
1564
+ let CODE_IDX = 1;
1565
+ const log = (line, ctx) => logger.debug('MD_LANG', line, ctx);
1566
+
1567
+ const DEDUP = (window.MD_LANG_LOG_DEDUP !== false);
1568
+ const seenFP = new Set();
1569
+ const makeFP = (info, raw) => {
1570
+ const head = (raw || '').slice(0, 96);
1571
+ return String(info || '') + '|' + String((raw || '').length) + '|' + head;
1572
+ };
1573
+
1574
+ const ALIAS = {
1575
+ txt: 'plaintext', text: 'plaintext', plaintext: 'plaintext',
1576
+ sh: 'bash', shell: 'bash', zsh: 'bash', 'shell-session': 'bash',
1577
+ py: 'python', python3: 'python', py3: 'python',
1578
+ js: 'javascript', node: 'javascript', nodejs: 'javascript',
1579
+ ts: 'typescript', 'ts-node': 'typescript',
1580
+ yml: 'yaml', kt: 'kotlin', rs: 'rust',
1581
+ csharp: 'csharp', 'c#': 'csharp', 'c++': 'cpp',
1582
+ ps: 'powershell', ps1: 'powershell', pwsh: 'powershell', powershell7: 'powershell',
1583
+ docker: 'dockerfile'
1584
+ };
1585
+ function normLang(s) { if (!s) return ''; const v = String(s).trim().toLowerCase(); return ALIAS[v] || v; }
1586
+ function isSupportedByHLJS(lang) { try { return !!(window.hljs && hljs.getLanguage && hljs.getLanguage(lang)); } catch (_) { return false; } }
1587
+ function classForHighlight(lang) { if (!lang) return 'plaintext'; return isSupportedByHLJS(lang) ? lang : 'plaintext'; }
1588
+ function stripBOM(s) { return (s && s.charCodeAt(0) === 0xFEFF) ? s.slice(1) : s; }
1589
+
1590
+ function detectFromFirstLine(raw, rid) {
1591
+ if (!raw) return { lang: '', content: raw, isOutput: false };
1592
+ const lines = raw.split(/\r?\n/);
1593
+ if (!lines.length) return { lang: '', content: raw, isOutput: false };
1594
+ let i = 0; while (i < lines.length && !lines[i].trim()) i++;
1595
+ if (i >= lines.length) { log(`#${rid} first-line: only whitespace`); return { lang: '', content: raw, isOutput: false }; }
1596
+ let first = stripBOM(lines[i]).trim();
1597
+ first = first.replace(/^\s*lang(?:uage)?\s*[:=]\s*/i, '').trim();
1598
+ let token = first.split(/\s+/)[0].replace(/:$/, '');
1599
+ if (!/^[A-Za-z][\w#+\-\.]{0,30}$/.test(token)) { log(`#${rid} first-line: no token match`, { first }); return { lang: '', content: raw, isOutput: false }; }
1600
+ let cand = normLang(token);
1601
+ if (cand === 'output') {
1602
+ const content = lines.slice(i + 1).join('\n');
1603
+ log(`#${rid} first-line: output header`);
1604
+ return { lang: 'python', headerLabel: 'output', content, isOutput: true };
1605
+ }
1606
+ const rest = lines.slice(i + 1).join('\n');
1607
+ if (!rest.trim()) { log(`#${rid} first-line: directive but no content after, ignore`, { cand }); return { lang: '', content: raw, isOutput: false }; }
1608
+ log(`#${rid} first-line: directive accepted`, { cand, restLen: rest.length, hljs: isSupportedByHLJS(cand) });
1609
+ return { lang: cand, headerLabel: cand, content: rest, isOutput: false };
1610
+ }
1611
+
1612
+ md.renderer.rules.fence = (tokens, idx) => renderFence(tokens[idx]);
1613
+ md.renderer.rules.code_block = (tokens, idx) => renderFence({ info: '', content: tokens[idx].content || '' });
1614
+
1615
+ function resolveLanguageAndContent(info, raw, rid) {
1616
+ const infoLangRaw = (info || '').trim().split(/\s+/)[0] || '';
1617
+ let cand = normLang(infoLangRaw);
1618
+ if (cand === 'output') {
1619
+ log(`#${rid} info: output header`);
1620
+ return { lang: 'python', headerLabel: 'output', content: raw, isOutput: true };
1621
+ }
1622
+ if (cand) {
1623
+ log(`#${rid} info: token`, { infoLangRaw, cand, hljs: isSupportedByHLJS(cand) });
1624
+ return { lang: cand, headerLabel: cand, content: raw, isOutput: false };
1625
+ }
1626
+ const det = detectFromFirstLine(raw, rid);
1627
+ if (det && (det.lang || det.isOutput)) return det;
1628
+ log(`#${rid} resolve: fallback`);
1629
+ return { lang: '', headerLabel: 'code', content: raw, isOutput: false };
1630
+ }
1631
+
1632
+ function renderFence(token) {
1633
+ const raw = token.content || '';
1634
+ const rid = String(CODE_IDX + '');
1635
+ const fp = makeFP(token.info || '', raw);
1636
+ const canLog = !DEDUP || !seenFP.has(fp);
1637
+ if (canLog) log(`FENCE_ENTER #${rid}`, { info: (token.info || ''), rawHead: logger.pv(raw) });
1638
+
1639
+ const res = resolveLanguageAndContent(token.info || '', raw, rid);
1640
+ const isOutput = !!res.isOutput;
1641
+ const headerLabel = isOutput ? 'output' : (res.headerLabel || (res.lang || 'code'));
1642
+ const langClass = isOutput ? 'python' : classForHighlight(res.lang);
1643
+
1644
+ if (canLog) {
1645
+ log(`FENCE_RESOLVE #${rid}`, { headerLabel, langToken: (res.lang || ''), langClass, hljsSupported: isSupportedByHLJS(res.lang || ''), contentLen: (res.content || '').length });
1646
+ if (DEDUP) seenFP.add(fp);
1647
+ }
1648
+
1649
+ // precompute code meta to avoid expensive .textContent on next phases
1650
+ const content = res.content || '';
1651
+ const len = content.length;
1652
+ const head = content.slice(0, 64);
1653
+ const tail = content.slice(-64);
1654
+ const headEsc = Utils.escapeHtml(head);
1655
+ const tailEsc = Utils.escapeHtml(tail);
1656
+ // Note: for full renderer we will also persist data-code-nl (see below).
1657
+
1658
+ const inner = Utils.escapeHtml(content);
1659
+ const idxLocal = CODE_IDX++;
1660
+
1661
+ let actions = '';
1662
+ if (langClass === 'html') {
1663
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-preview"><img src="${cfg.ICONS.CODE_PREVIEW}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.PREVIEW)}</span></a>`;
1664
+ } else if (langClass === 'python' && headerLabel !== 'output') {
1665
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-run"><img src="${cfg.ICONS.CODE_RUN}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.RUN)}</span></a>`;
1666
+ }
1667
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-collapse"><img src="${cfg.ICONS.CODE_MENU}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.COLLAPSE)}</span></a>`;
1668
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-copy"><img src="${cfg.ICONS.CODE_COPY}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.COPY)}</span></a>`;
1669
+
1670
+ // attach precomputed meta (len/head/tail) on wrapper for downstream optimizations
1671
+ return (
1672
+ `<div class="code-wrapper highlight" data-index="${idxLocal}"` +
1673
+ ` data-code-lang="${Utils.escapeHtml(res.lang || '')}"` +
1674
+ ` data-code-len="${String(len)}" data-code-head="${headEsc}" data-code-tail="${tailEsc}"` + // meta (no nl here – only in full renderer)
1675
+ ` data-locale-collapse="${Utils.escapeHtml(cfg.LOCALE.COLLAPSE)}" data-locale-expand="${Utils.escapeHtml(cfg.LOCALE.EXPAND)}"` +
1676
+ ` data-locale-copy="${Utils.escapeHtml(cfg.LOCALE.COPY)}" data-locale-copied="${Utils.escapeHtml(cfg.LOCALE.COPIED)}" data-style="${Utils.escapeHtml(cfg.CODE_STYLE)}">` +
1677
+ `<p class="code-header-wrapper"><span><span class="code-header-lang">${Utils.escapeHtml(headerLabel)} </span>${actions}</span></p>` +
1678
+ `<pre><code class="language-${Utils.escapeHtml(langClass)} hljs">${inner}</code></pre>` +
1679
+ `</div>`
1680
+ );
1681
+ }
1682
+ })(this.MD_STREAM, this.logger);
1683
+
1684
+ // Apply wrapper plugin to full renderer with extra meta (includes number of lines).
1685
+ (function codeWrapperPlugin(md, logger) {
1686
+ // identical core logic – augmented with data-code-nl for full renderer
1687
+ let CODE_IDX = 1;
1688
+ const log = (line, ctx) => logger.debug('MD_LANG', line, ctx);
1689
+
1690
+ const DEDUP = (window.MD_LANG_LOG_DEDUP !== false);
1691
+ const seenFP = new Set();
1692
+ const makeFP = (info, raw) => {
1693
+ const head = (raw || '').slice(0, 96);
1694
+ return String(info || '') + '|' + String((raw || '').length) + '|' + head;
1695
+ };
1696
+
1697
+ const ALIAS = {
1698
+ txt: 'plaintext', text: 'plaintext', plaintext: 'plaintext',
1699
+ sh: 'bash', shell: 'bash', zsh: 'bash', 'shell-session': 'bash',
1700
+ py: 'python', python3: 'python', py3: 'python',
1701
+ js: 'javascript', node: 'javascript', nodejs: 'javascript',
1702
+ ts: 'typescript', 'ts-node': 'typescript',
1703
+ yml: 'yaml', kt: 'kotlin', rs: 'rust',
1704
+ csharp: 'csharp', 'c#': 'csharp', 'c++': 'cpp',
1705
+ ps: 'powershell', ps1: 'powershell', pwsh: 'powershell', powershell7: 'powershell',
1706
+ docker: 'dockerfile'
1707
+ };
1708
+ function normLang(s) { if (!s) return ''; const v = String(s).trim().toLowerCase(); return ALIAS[v] || v; }
1709
+ function isSupportedByHLJS(lang) { try { return !!(window.hljs && hljs.getLanguage && hljs.getLanguage(lang)); } catch (_) { return false; } }
1710
+ function classForHighlight(lang) { if (!lang) return 'plaintext'; return isSupportedByHLJS(lang) ? lang : 'plaintext'; }
1711
+ function stripBOM(s) { return (s && s.charCodeAt(0) === 0xFEFF) ? s.slice(1) : s; }
1712
+
1713
+ function detectFromFirstLine(raw, rid) {
1714
+ if (!raw) return { lang: '', content: raw, isOutput: false };
1715
+ const lines = raw.split(/\r?\n/);
1716
+ if (!lines.length) return { lang: '', content: raw, isOutput: false };
1717
+ let i = 0; while (i < lines.length && !lines[i].trim()) i++;
1718
+ if (i >= lines.length) { log(`#${rid} first-line: only whitespace`); return { lang: '', content: raw, isOutput: false }; }
1719
+ let first = stripBOM(lines[i]).trim();
1720
+ first = first.replace(/^\s*lang(?:uage)?\s*[:=]\s*/i, '').trim();
1721
+ let token = first.split(/\s+/)[0].replace(/:$/, '');
1722
+ if (!/^[A-Za-z][\w#+\-\.]{0,30}$/.test(token)) { log(`#${rid} first-line: no token match`, { first }); return { lang: '', content: raw, isOutput: false }; }
1723
+ let cand = normLang(token);
1724
+ if (cand === 'output') {
1725
+ const content = lines.slice(i + 1).join('\n');
1726
+ log(`#${rid} first-line: output header`);
1727
+ return { lang: 'python', headerLabel: 'output', content, isOutput: true };
1728
+ }
1729
+ const rest = lines.slice(i + 1).join('\n');
1730
+ if (!rest.trim()) { log(`#${rid} first-line: directive but no content after, ignore`, { cand }); return { lang: '', content: raw, isOutput: false }; }
1731
+ log(`#${rid} first-line: directive accepted`, { cand, restLen: rest.length, hljs: isSupportedByHLJS(cand) });
1732
+ return { lang: cand, headerLabel: cand, content: rest, isOutput: false };
1733
+ }
1734
+
1735
+ md.renderer.rules.fence = (tokens, idx) => renderFence(tokens[idx]);
1736
+ md.renderer.rules.code_block = (tokens, idx) => renderFence({ info: '', content: tokens[idx].content || '' });
1737
+
1738
+ function resolveLanguageAndContent(info, raw, rid) {
1739
+ const infoLangRaw = (info || '').trim().split(/\s+/)[0] || '';
1740
+ let cand = normLang(infoLangRaw);
1741
+ if (cand === 'output') {
1742
+ log(`#${rid} info: output header`);
1743
+ return { lang: 'python', headerLabel: 'output', content: raw, isOutput: true };
1744
+ }
1745
+ if (cand) {
1746
+ log(`#${rid} info: token`, { infoLangRaw, cand, hljs: isSupportedByHLJS(cand) });
1747
+ return { lang: cand, headerLabel: cand, content: raw, isOutput: false };
1748
+ }
1749
+ const det = detectFromFirstLine(raw, rid);
1750
+ if (det && (det.lang || det.isOutput)) return det;
1751
+ log(`#${rid} resolve: fallback`);
1752
+ return { lang: '', headerLabel: 'code', content: raw, isOutput: false };
1753
+ }
1754
+
1755
+ function renderFence(token) {
1756
+ const raw = token.content || '';
1757
+ const rid = String(CODE_IDX + '');
1758
+ const fp = makeFP(token.info || '', raw);
1759
+ const canLog = !DEDUP || !seenFP.has(fp);
1760
+ if (canLog) log(`FENCE_ENTER #${rid}`, { info: (token.info || ''), rawHead: logger.pv(raw) });
1761
+
1762
+ const res = resolveLanguageAndContent(token.info || '', raw, rid);
1763
+ const isOutput = !!res.isOutput;
1764
+ const headerLabel = isOutput ? 'output' : (res.headerLabel || (res.lang || 'code'));
1765
+ const langClass = isOutput ? 'python' : classForHighlight(res.lang);
1766
+
1767
+ if (canLog) {
1768
+ log(`FENCE_RESOLVE #${rid}`, { headerLabel, langToken: (res.lang || ''), langClass, hljsSupported: isSupportedByHLJS(res.lang || ''), contentLen: (res.content || '').length });
1769
+ if (DEDUP) seenFP.add(fp);
1770
+ }
1771
+
1772
+ // precompute code meta
1773
+ const content = res.content || '';
1774
+ const len = content.length;
1775
+ const head = content.slice(0, 64);
1776
+ const tail = content.slice(-64);
1777
+ const headEsc = Utils.escapeHtml(head);
1778
+ const tailEsc = Utils.escapeHtml(tail);
1779
+ const nl = Utils.countNewlines(content);
1780
+
1781
+ const inner = Utils.escapeHtml(content);
1782
+ const idxLocal = CODE_IDX++;
1783
+
1784
+ let actions = '';
1785
+ if (langClass === 'html') {
1786
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-preview"><img src="${cfg.ICONS.CODE_PREVIEW}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.PREVIEW)}</span></a>`;
1787
+ } else if (langClass === 'python' && headerLabel !== 'output') {
1788
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-run"><img src="${cfg.ICONS.CODE_RUN}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.RUN)}</span></a>`;
1789
+ }
1790
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-collapse"><img src="${cfg.ICONS.CODE_MENU}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.COLLAPSE)}</span></a>`;
1791
+ actions += `<a href="empty:${idxLocal}" class="code-header-action code-header-copy"><img src="${cfg.ICONS.CODE_COPY}" class="action-img" data-id="${idxLocal}"><span>${Utils.escapeHtml(cfg.LOCALE.COPY)}</span></a>`;
1792
+
1793
+ return (
1794
+ `<div class="code-wrapper highlight" data-index="${idxLocal}"` +
1795
+ ` data-code-lang="${Utils.escapeHtml(res.lang || '')}"` +
1796
+ ` data-code-len="${String(len)}" data-code-head="${headEsc}" data-code-tail="${tailEsc}" data-code-nl="${String(nl)}"` + // include nl for full renderer
1797
+ ` data-locale-collapse="${Utils.escapeHtml(cfg.LOCALE.COLLAPSE)}" data-locale-expand="${Utils.escapeHtml(cfg.LOCALE.EXPAND)}"` +
1798
+ ` data-locale-copy="${Utils.escapeHtml(cfg.LOCALE.COPY)}" data-locale-copied="${Utils.escapeHtml(cfg.LOCALE.COPIED)}" data-style="${Utils.escapeHtml(cfg.CODE_STYLE)}">` +
1799
+ `<p class="code-header-wrapper"><span><span class="code-header-lang">${Utils.escapeHtml(headerLabel)} </span>${actions}</span></p>` +
1800
+ `<pre><code class="language-${Utils.escapeHtml(langClass)} hljs">${inner}</code></pre>` +
1801
+ `</div>`
1802
+ );
1803
+ }
1804
+ })(this.MD, this.logger);
1805
+ }
1806
+ // Replace "sandbox:" links with file:// in markdown source (host policy).
1807
+ preprocessMD(s) { return (s || '').replace(/\]\(sandbox:/g, '](file://'); }
1808
+ // Decode base64 UTF-8 to string (shared TextDecoder).
1809
+ b64ToUtf8(b64) {
1810
+ const bin = atob(b64);
1811
+ const bytes = new Uint8Array(bin.length);
1812
+ for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
1813
+ return Utils.utf8Decode(bytes);
1814
+ }
1815
+
1816
+ // Apply custom markup for bot messages only (method name kept for API).
1817
+ applyCustomMarkupForBots(root) {
1818
+ const MD = this.MD;
1819
+ try {
1820
+ const scope = root || document;
1821
+ const targets = [];
1822
+
1823
+ // If scope itself is a bot message box
1824
+ if (scope && scope.nodeType === 1 && scope.classList && scope.classList.contains('msg-box') &&
1825
+ scope.classList.contains('msg-bot')) {
1826
+ targets.push(scope);
1827
+ }
1828
+
1829
+ // Collect bot message boxes within the scope
1830
+ if (scope && typeof scope.querySelectorAll === 'function') {
1831
+ const list = scope.querySelectorAll('.msg-box.msg-bot');
1832
+ for (let i = 0; i < list.length; i++) targets.push(list[i]);
1833
+ }
1834
+
1835
+ // If scope is inside a bot message, include the closest ancestor as well
1836
+ if (scope && scope.nodeType === 1 && typeof scope.closest === 'function') {
1837
+ const closestMsg = scope.closest('.msg-box.msg-bot');
1838
+ if (closestMsg) targets.push(closestMsg);
1839
+ }
1840
+
1841
+ // Deduplicate and apply rules only to bot messages
1842
+ const seen = new Set();
1843
+ for (const el of targets) {
1844
+ if (!el || !el.isConnected || seen.has(el)) continue;
1845
+ seen.add(el);
1846
+ this.customMarkup.apply(el, MD);
1847
+ }
1848
+ } catch (_) {
1849
+ // Keep render path resilient
1850
+ }
1851
+ }
1852
+
1853
+ // Helper: choose renderer (hot vs full) for snapshot use.
1854
+ _md(streamingHint) {
1855
+ return streamingHint ? (this.MD_STREAM || this.MD) : (this.MD || this.MD_STREAM);
1856
+ }
1857
+
1858
+ // Async, batched processing of [data-md64] / [md-block-markdown] to keep UI responsive on heavy loads.
1859
+ // Note: user messages are rendered as plain text (no markdown-it, no custom markup, no KaTeX).
1860
+ async renderPendingMarkdown(root) {
1861
+ const MD = this.MD; if (!MD) return;
1862
+ const scope = root || document;
1863
+
1864
+ // Collect both legacy base64 holders and new native Markdown holders
1865
+ const nodes = Array.from(scope.querySelectorAll('[data-md64], [md-block-markdown]'));
1866
+ if (nodes.length === 0) {
1867
+ // Nothing to materialize right now. Avoid arming rAF work unless there is
1868
+ // actually something present that needs highlight/scroll/math.
1869
+ try {
1870
+ const hasBots = !!(scope && scope.querySelector && scope.querySelector('.msg-box.msg-bot'));
1871
+ const hasWrappers = !!(scope && scope.querySelector && scope.querySelector('.code-wrapper'));
1872
+ const hasCodes = !!(scope && scope.querySelector && scope.querySelector('.msg-box.msg-bot pre code'));
1873
+ const hasUnhighlighted = !!(scope && scope.querySelector && scope.querySelector('.msg-box.msg-bot pre code:not([data-highlighted="yes"])'));
1874
+ const hasMath = !!(scope && scope.querySelector && scope.querySelector('script[type^="math/tex"]'));
1875
+
1876
+ // Apply Custom Markup only if bot messages are present.
1877
+ if (hasBots) { this.applyCustomMarkupForBots(scope); }
1878
+
1879
+ // Restore collapsed state only if we can actually find wrappers.
1880
+ if (hasWrappers) { this.restoreCollapsedCode(scope); }
1881
+
1882
+ // Initialize code scroll helpers for current root.
1883
+ this.hooks.codeScrollInit(scope);
1884
+
1885
+ // Init code-scroll/highlight observers only when there are codes in DOM.
1886
+ if (hasCodes) {
1887
+ this.hooks.observeMsgBoxes(scope);
1888
+ this.hooks.observeNewCode(scope, {
1889
+ deferLastIfStreaming: true,
1890
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
1891
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
1892
+ });
1893
+ if (hasUnhighlighted && typeof runtime !== 'undefined' && runtime.highlighter) {
1894
+ runtime.highlighter.scanVisibleCodesInRoot(scope, runtime.stream.activeCode || null);
1895
+ }
1896
+ }
1897
+
1898
+ // Schedule KaTeX render only if there are math scripts present.
1899
+ if (hasMath) { this.hooks.scheduleMathRender(scope); }
1900
+ this.hooks.codeScrollInit(scope);
1901
+
1902
+ } catch (_) { /* swallow: keep idle path safe */ }
1903
+
1904
+ return;
1905
+ }
1906
+
1907
+ // Track which bot message boxes actually changed to avoid a heavy global Custom Markup pass.
1908
+ const touchedBoxes = new Set();
1909
+
1910
+ // Budgeted, cooperative loop: process nodes one-by-one with per-frame yield when needed.
1911
+ const perSlice = (this.cfg.ASYNC && this.cfg.ASYNC.MD_NODES_PER_SLICE) || 12; // upper bound per frame
1912
+ let sliceCount = 0;
1913
+ let startedAt = Utils.now();
1914
+
1915
+ for (let j = 0; j < nodes.length; j++) {
1916
+ const el = nodes[j];
1917
+ if (!el || !el.isConnected) continue;
1918
+
1919
+ let md = '';
1920
+ const isNative = el.hasAttribute('md-block-markdown');
1921
+ const msgBox = (el.closest && el.closest('.msg-box.msg-bot, .msg-box.msg-user')) || null;
1922
+ const isUserMsg = !!(msgBox && msgBox.classList.contains('msg-user'));
1923
+ const isBotMsg = !!(msgBox && msgBox.classList.contains('msg-bot'));
1924
+
1925
+ // Read source text (do not preprocess for user messages to keep it raw)
1926
+ if (isNative) {
1927
+ try { md = isUserMsg ? (el.textContent || '') : this.preprocessMD(el.textContent || ''); } catch (_) { md = ''; }
1928
+ try { el.removeAttribute('md-block-markdown'); } catch (_) {}
1929
+ } else {
1930
+ const b64 = el.getAttribute('data-md64'); if (!b64) continue;
1931
+ try { md = this.b64ToUtf8(b64); } catch (_) { md = ''; }
1932
+ el.removeAttribute('data-md64');
1933
+ if (!isUserMsg) { try { md = this.preprocessMD(md); } catch (_) {} }
1934
+ }
1935
+
1936
+ if (isUserMsg) {
1937
+ // User message: replace placeholder with raw plain text only.
1938
+ const span = document.createElement('span');
1939
+ span.textContent = md;
1940
+ el.replaceWith(span);
1941
+ // Intentionally do NOT add to touchedBoxes; no Custom Markup for user.
1942
+ } else if (isBotMsg) {
1943
+ // Bot message: full markdown-it render with Custom Markup.
1944
+ let html = '';
1945
+ try { html = MD.render(md); } catch (_) { html = Utils.escapeHtml(md); }
1946
+
1947
+ // build fragment directly (avoid intermediate container allocations).
1948
+ let frag = null;
1949
+ try {
1950
+ const range = document.createRange();
1951
+ const ctx = el.parentNode || document.body || document.documentElement;
1952
+ range.selectNode(ctx);
1953
+ frag = range.createContextualFragment(html);
1954
+ } catch (_) {
1955
+ const tmp = document.createElement('div');
1956
+ tmp.innerHTML = html;
1957
+ frag = document.createDocumentFragment();
1958
+ while (tmp.firstChild) frag.appendChild(tmp.firstChild);
1959
+ }
1960
+
1961
+ // Apply Custom Markup on a lightweight DocumentFragment
1962
+ try { this.customMarkup.apply(frag, MD); } catch (_) {}
1963
+
1964
+ el.replaceWith(frag);
1965
+ touchedBoxes.add(msgBox);
1966
+ } else {
1967
+ // Outside of any message box: materialize as plain text.
1968
+ const span = document.createElement('span');
1969
+ span.textContent = md;
1970
+ el.replaceWith(span);
1971
+ }
1972
+
1973
+ sliceCount++;
1974
+ // Yield by time budget or by count to keep frame short and reactive.
1975
+ if (sliceCount >= perSlice || this.asyncer.shouldYield(startedAt)) {
1976
+ await this.asyncer.yield();
1977
+ startedAt = Utils.now();
1978
+ sliceCount = 0;
1979
+ }
1980
+ }
1981
+
1982
+ // Apply Custom Markup only to actually modified BOT messages (keeps this pass light).
1983
+ try {
1984
+ touchedBoxes.forEach(box => { try { this.customMarkup.apply(box, MD); } catch (_) {} });
1985
+ } catch (_) {}
1986
+
1987
+ // Same post-processing as before (idempotent with external calls).
1988
+ this.restoreCollapsedCode(scope);
1989
+ this.hooks.observeNewCode(scope, {
1990
+ deferLastIfStreaming: true,
1991
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
1992
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
1993
+ });
1994
+ this.hooks.observeMsgBoxes(scope);
1995
+ this.hooks.scheduleMathRender(scope);
1996
+ this.hooks.codeScrollInit(scope);
1997
+
1998
+ if (typeof runtime !== 'undefined' && runtime.highlighter) {
1999
+ runtime.highlighter.scanVisibleCodesInRoot(scope, runtime.stream.activeCode || null);
2000
+ }
2001
+ }
2002
+
2003
+ // Render streaming snapshot (reduced features).
2004
+ renderStreamingSnapshot(src) {
2005
+ const md = this._md(true);
2006
+ if (!md) return '';
2007
+ try { return md.render(src); } catch (_) { return Utils.escapeHtml(src); }
2008
+ }
2009
+ // Render final snapshot (full features).
2010
+ renderFinalSnapshot(src) {
2011
+ const md = this._md(false);
2012
+ if (!md) return '';
2013
+ try { return md.render(src); } catch (_) { return Utils.escapeHtml(src); }
2014
+ }
2015
+
2016
+ // Restore collapse/expand state of code blocks after DOM updates.
2017
+ restoreCollapsedCode(root) {
2018
+ const scope = root || document;
2019
+ const wrappers = scope.querySelectorAll('.code-wrapper');
2020
+ wrappers.forEach((wrapper) => {
2021
+ const index = wrapper.getAttribute('data-index');
2022
+ const localeCollapse = wrapper.getAttribute('data-locale-collapse');
2023
+ const localeExpand = wrapper.getAttribute('data-locale-expand');
2024
+ const source = wrapper.querySelector('code');
2025
+ const isCollapsed = (window.__collapsed_idx || []).includes(index);
2026
+ if (!source) return;
2027
+ const btn = wrapper.querySelector('.code-header-collapse');
2028
+ if (isCollapsed) {
2029
+ source.style.display = 'none';
2030
+ if (btn) { const span = btn.querySelector('span'); if (span) span.textContent = localeExpand; }
2031
+ } else {
2032
+ source.style.display = 'block';
2033
+ if (btn) { const span = btn.querySelector('span'); if (span) span.textContent = localeCollapse; }
2034
+ }
2035
+ });
2036
+ }
2037
+ }
2038
+ window.__collapsed_idx = window.__collapsed_idx || [];
2039
+
2040
+ // ==========================================================================
2041
+ // 6) Math renderer (async, chunked)
2042
+ // ==========================================================================
2043
+ class MathRenderer {
2044
+ constructor(cfg, raf, asyncer) {
2045
+ this.cfg = cfg; this.raf = raf; this.asyncer = asyncer;
2046
+ this.scheduled = false;
2047
+
2048
+ // rAF key used by the central pump (do not change – API compatibility).
2049
+ this.rafKey = { t: 'Math:render' };
2050
+
2051
+ // Pending roots aggregation: if document-level render is requested, it supersedes others.
2052
+ this._pendingRoots = new Set();
2053
+ this._pendingDoc = false;
2054
+ }
2055
+
2056
+ // Async, cooperative KaTeX rendering to avoid long blocking on many formulas.
2057
+ async renderAsync(root) {
2058
+ if (typeof katex === 'undefined') return;
2059
+ const scope = root || document;
2060
+ const scripts = Array.from(scope.querySelectorAll('script[type^="math/tex"]'));
2061
+ const useToString = (typeof katex.renderToString === 'function');
2062
+
2063
+ const batchFn = async (script) => {
2064
+ if (!script || !script.isConnected) return;
2065
+ // Only render math in bot messages
2066
+ if (!script.closest('.msg-box.msg-bot')) return;
2067
+ const t = script.getAttribute('type') || '';
2068
+ const displayMode = t.indexOf('mode=display') > -1;
2069
+ // avoid innerText (it may trigger layout). textContent is sufficient here.
2070
+ const mathContent = script.textContent || '';
2071
+ const parent = script.parentNode; if (!parent) return;
2072
+
2073
+ try {
2074
+ if (useToString) {
2075
+ let html = '';
2076
+ try {
2077
+ html = katex.renderToString(mathContent, { displayMode, throwOnError: false });
2078
+ } catch (_) {
2079
+ const fb = displayMode ? `\\[${mathContent}\\]` : `\\(${mathContent}\\)`;
2080
+ html = (displayMode ? `<div>${Utils.escapeHtml(fb)}</div>` : `<span>${Utils.escapeHtml(fb)}</span>`);
2081
+ }
2082
+ const host = document.createElement(displayMode ? 'div' : 'span');
2083
+ host.innerHTML = html;
2084
+ const el = host.firstElementChild || host;
2085
+ if (parent.classList && parent.classList.contains('math-pending')) parent.replaceWith(el);
2086
+ else parent.replaceChild(el, script);
2087
+ } else {
2088
+ const el = document.createElement(displayMode ? 'div' : 'span');
2089
+ try { katex.render(mathContent, el, { displayMode, throwOnError: false }); }
2090
+ catch (_) { el.textContent = (displayMode ? `\\[${mathContent}\\]` : `\\(${mathContent}\\)`); }
2091
+ if (parent.classList && parent.classList.contains('math-pending')) parent.replaceWith(el);
2092
+ else parent.replaceChild(el, script);
2093
+ }
2094
+ } catch (_) {
2095
+ // Keep fallback text intact on any error
2096
+ }
2097
+ };
2098
+
2099
+ // Process formulas cooperatively (rAF yields).
2100
+ await this.asyncer.forEachChunk(scripts, batchFn, 'MathRenderer');
2101
+ }
2102
+
2103
+ // Schedule math rendering for a root. Coalesces multiple calls.
2104
+ schedule(root, _delayIgnored = 0, forceNow = false) {
2105
+ // If KaTeX is not available, honor no-op. API stays intact.
2106
+ if (typeof katex === 'undefined') return;
2107
+
2108
+ // Normalize root (default to whole document).
2109
+ const targetRoot = root || document;
2110
+
2111
+ // Fast existence check to avoid arming rAF when nothing to do, but still
2112
+ // keep aggregation semantics: if a job is already scheduled we can still
2113
+ // merge new roots into the pending set when they actually contain math.
2114
+ let hasMath = true;
2115
+ if (!forceNow) {
2116
+ try {
2117
+ hasMath = !!(targetRoot && targetRoot.querySelector && targetRoot.querySelector('script[type^="math/tex"]'));
2118
+ } catch (_) { hasMath = false; }
2119
+ if (!hasMath) return; // nothing to render for this root; safe early exit
2120
+ }
2121
+
2122
+ // Aggregate roots so nothing is lost while one job is already scheduled.
2123
+ if (targetRoot === document || targetRoot === document.documentElement || targetRoot === document.body) {
2124
+ this._pendingDoc = true; // promote to a full-document sweep
2125
+ this._pendingRoots.clear(); // small optimization (document covers all)
2126
+ } else if (!this._pendingDoc) {
2127
+ this._pendingRoots.add(targetRoot);
2128
+ }
2129
+
2130
+ // If a task is already scheduled, do not arm another – coalescing will take care of it.
2131
+ if (this.scheduled && this.raf && typeof this.raf.isScheduled === 'function' && this.raf.isScheduled(this.rafKey)) return;
2132
+
2133
+ this.scheduled = true;
2134
+ const priority = forceNow ? 0 : 2;
2135
+
2136
+ // Single rAF job drains all pending roots; renderAsync remains public and unchanged.
2137
+ this.raf.schedule(this.rafKey, () => {
2138
+ this.scheduled = false;
2139
+
2140
+ const useDoc = this._pendingDoc;
2141
+ const roots = [];
2142
+
2143
+ if (useDoc) {
2144
+ roots.push(document);
2145
+ } else {
2146
+ this._pendingRoots.forEach((r) => {
2147
+ // Only keep connected elements to avoid useless work.
2148
+ try {
2149
+ if (r && (r.isConnected === undefined || r.isConnected)) roots.push(r);
2150
+ } catch (_) {
2151
+ // Conservative: keep the root; renderAsync guards internally.
2152
+ roots.push(r);
2153
+ }
2154
+ });
2155
+ }
2156
+
2157
+ // Reset aggregation state before running (new calls can aggregate afresh).
2158
+ this._pendingDoc = false;
2159
+ this._pendingRoots.clear();
2160
+
2161
+ // Fire-and-forget async drain; keep renderAsync API intact.
2162
+ (async () => {
2163
+ for (let i = 0; i < roots.length; i++) {
2164
+ try { await this.renderAsync(roots[i]); } catch (_) { /* swallow – resilient */ }
2165
+ }
2166
+ })();
2167
+ }, 'Math', priority);
2168
+ }
2169
+ // Cleanup pending work and state.
2170
+ cleanup() {
2171
+ try { this.raf.cancelGroup('Math'); } catch (_) {}
2172
+ this.scheduled = false;
2173
+
2174
+ // Ensure pending state is fully cleared on cleanup.
2175
+ try { this._pendingRoots.clear(); } catch (_) {}
2176
+ this._pendingDoc = false;
2177
+ }
2178
+ }
2179
+
2180
+ // ==========================================================================
2181
+ // 7) Scroll manager + FAB
2182
+ // ==========================================================================
2183
+
2184
+ class ScrollManager {
2185
+ constructor(cfg, dom, raf) {
2186
+ this.cfg = cfg; this.dom = dom; this.raf = raf;
2187
+ this.autoFollow = true; this.userInteracted = false;
2188
+ this.lastScrollTop = 0; this.prevScroll = 0;
2189
+ this.currentFabAction = 'none'; this.fabFreezeUntil = 0;
2190
+ this.scrollScheduled = false; this.scrollFabUpdateScheduled = false;
2191
+ this.scrollRAF = 0; this.scrollFabRAF = 0;
2192
+ }
2193
+ // Is page near the bottom by given margin?
2194
+ isNearBottom(marginPx = 100) {
2195
+ const el = Utils.SE; const distance = el.scrollHeight - el.clientHeight - el.scrollTop;
2196
+ return distance <= marginPx;
2197
+ }
2198
+ // Schedule a page scroll to bottom if auto-follow allows it.
2199
+ scheduleScroll(live = false) {
2200
+ if (live === true && this.autoFollow !== true) return;
2201
+ if (this.scrollScheduled) return;
2202
+ this.scrollScheduled = true;
2203
+ this.raf.schedule('SM:scroll', () => { this.scrollScheduled = false; this.scrollToBottom(live); this.scheduleScrollFabUpdate(); }, 'ScrollManager', 1);
2204
+ }
2205
+ // Cancel any pending page scroll.
2206
+ cancelPendingScroll() {
2207
+ try { this.raf.cancelGroup('ScrollManager'); } catch (_) {}
2208
+ this.scrollScheduled = false;
2209
+ this.scrollFabUpdateScheduled = false;
2210
+ this.scrollRAF = 0; this.scrollFabRAF = 0;
2211
+ }
2212
+ // Jump to bottom immediately (no smooth behavior).
2213
+ forceScrollToBottomImmediate() {
2214
+ const el = Utils.SE; el.scrollTop = el.scrollHeight; this.prevScroll = el.scrollHeight;
2215
+ }
2216
+ // Scroll window to bottom based on auto-follow and margins.
2217
+ scrollToBottom(live = false, force = false) {
2218
+ const el = Utils.SE; const marginPx = this.cfg.UI.SCROLL_NEAR_MARGIN_PX; const behavior = 'instant';
2219
+ if (live === true && this.autoFollow !== true) { this.prevScroll = el.scrollHeight; return; }
2220
+ if ((live === true && this.userInteracted === false) || this.isNearBottom(marginPx) || live === false || force) {
2221
+ try { el.scrollTo({ top: el.scrollHeight, behavior }); } catch (_) { el.scrollTop = el.scrollHeight; }
2222
+ }
2223
+ this.prevScroll = el.scrollHeight;
2224
+ }
2225
+ // Check if window has vertical scroll bar.
2226
+ hasVerticalScroll() { const el = Utils.SE; return (el.scrollHeight - el.clientHeight) > 1; }
2227
+ // Compute the current FAB action (none/up/down).
2228
+ computeFabAction() {
2229
+ const el = Utils.SE; const hasScroll = (el.scrollHeight - el.clientHeight) > 1;
2230
+ if (!hasScroll) return 'none';
2231
+ const dist = el.scrollHeight - el.clientHeight - el.scrollTop;
2232
+ if (dist <= 2) return 'up';
2233
+ if (dist >= this.cfg.FAB.SHOW_DOWN_THRESHOLD_PX) return 'down';
2234
+ return 'none';
2235
+ }
2236
+ // Update FAB to show correct direction and label.
2237
+ updateScrollFab(force = false, actionOverride = null, bypassFreeze = false) {
2238
+ const btn = this.dom.get('scrollFab'); const icon = this.dom.get('scrollFabIcon');
2239
+ if (!btn || !icon) return;
2240
+ const now = Utils.now(); const action = actionOverride || this.computeFabAction();
2241
+ if (!force && !bypassFreeze && now < this.fabFreezeUntil && action !== this.currentFabAction) return;
2242
+ if (action === 'none') {
2243
+ if (this.currentFabAction !== 'none' || force) { btn.classList.remove('visible'); this.currentFabAction = 'none'; }
2244
+ return;
2245
+ }
2246
+ if (action !== this.currentFabAction || force) {
2247
+ if (action === 'up') {
2248
+ if (icon.dataset.dir !== 'up') { icon.src = this.cfg.ICONS.COLLAPSE; icon.dataset.dir = 'up'; }
2249
+ btn.title = "Go to top";
2250
+ } else {
2251
+ if (icon.dataset.dir !== 'down') { icon.src = this.cfg.ICONS.EXPAND; icon.dataset.dir = 'down'; }
2252
+ btn.title = "Go to bottom";
2253
+ }
2254
+ btn.setAttribute('aria-label', btn.title);
2255
+ this.currentFabAction = action; btn.classList.add('visible');
2256
+ } else if (!btn.classList.contains('visible')) btn.classList.add('visible');
2257
+ }
2258
+ // Schedule a FAB state refresh.
2259
+ scheduleScrollFabUpdate() {
2260
+ if (this.scrollFabUpdateScheduled) return;
2261
+ this.scrollFabUpdateScheduled = true;
2262
+ this.raf.schedule('SM:fab', () => {
2263
+ this.scrollFabUpdateScheduled = false;
2264
+ const action = this.computeFabAction(); if (action !== this.currentFabAction) this.updateScrollFab(false, action);
2265
+ }, 'ScrollManager', 2);
2266
+ }
2267
+ // If user is near bottom, enable auto-follow again.
2268
+ maybeEnableAutoFollowByProximity() {
2269
+ const el = Utils.SE;
2270
+ if (!this.autoFollow) {
2271
+ const dist = el.scrollHeight - el.clientHeight - el.scrollTop;
2272
+ if (dist <= this.cfg.UI.AUTO_FOLLOW_REENABLE_PX) this.autoFollow = true;
2273
+ }
2274
+ }
2275
+ // User-triggered scroll to top; disables auto-follow.
2276
+ scrollToTopUser() {
2277
+ this.userInteracted = true; this.autoFollow = false;
2278
+ try { const el = Utils.SE; el.scrollTo({ top: 0, behavior: 'instant' }); this.lastScrollTop = el.scrollTop; }
2279
+ catch (_) { const el = Utils.SE; el.scrollTop = 0; this.lastScrollTop = 0; }
2280
+ }
2281
+ // User-triggered scroll to bottom; may re-enable auto-follow if near bottom.
2282
+ scrollToBottomUser() {
2283
+ this.userInteracted = true; this.autoFollow = false;
2284
+ try { const el = Utils.SE; el.scrollTo({ top: el.scrollHeight, behavior: 'instant' }); this.lastScrollTop = el.scrollTop; }
2285
+ catch (_) { const el = Utils.SE; el.scrollTop = el.scrollHeight; this.lastScrollTop = el.scrollTop; }
2286
+ this.maybeEnableAutoFollowByProximity();
2287
+ }
2288
+ }
2289
+
2290
+ // ==========================================================================
2291
+ // 8) Tips manager
2292
+ // ==========================================================================
2293
+
2294
+ // Tips manager (drop-in replacement): rotates small hint messages in a top overlay.
2295
+ class TipsManager {
2296
+ // Lightweight tips rotator that works with your CSS (.tips/.visible)
2297
+ // and is backward-compatible with legacy `let tips = [...]` injection.
2298
+ constructor(dom) {
2299
+ this.dom = dom;
2300
+ this.hidden = false;
2301
+ this._timers = [];
2302
+ this._running = false;
2303
+ this._idx = 0;
2304
+ }
2305
+
2306
+ // Resolve tips list from multiple legacy/new sources.
2307
+ _getList() {
2308
+ // New preferred: window.TIPS (array)
2309
+ const upper = (typeof window !== 'undefined') ? window.TIPS : undefined;
2310
+ if (Array.isArray(upper) && upper.length) return upper;
2311
+
2312
+ // Legacy inline: window.tips (array or JSON string)
2313
+ const lower = (typeof window !== 'undefined') ? window.tips : undefined;
2314
+ if (Array.isArray(lower) && lower.length) return lower;
2315
+ if (typeof lower === 'string' && lower.trim().length) {
2316
+ try { const arr = JSON.parse(lower); if (Array.isArray(arr)) return arr; } catch (_) {}
2317
+ }
2318
+
2319
+ // Optional: data-tips='["...","..."]' on #tips
2320
+ const host = this._host();
2321
+ if (host && host.dataset && typeof host.dataset.tips === 'string') {
2322
+ try { const arr = JSON.parse(host.dataset.tips); if (Array.isArray(arr)) return arr; } catch (_) {}
2323
+ }
2324
+
2325
+ return [];
2326
+ }
2327
+
2328
+ _host() {
2329
+ return this.dom.get('tips') || document.getElementById('tips');
2330
+ }
2331
+
2332
+ _clearTimers() {
2333
+ for (const t of this._timers) { try { clearTimeout(t); } catch (_) {} }
2334
+ this._timers.length = 0;
2335
+ }
2336
+
2337
+ // Stop any running rotation timers.
2338
+ stopTimers() {
2339
+ this._clearTimers();
2340
+ this._running = false;
2341
+ }
2342
+
2343
+ _applyBaseStyle(el) {
2344
+ if (!el) return;
2345
+ // Keep your flex layout and sizing; do not overwrite width/height.
2346
+ // Ensure it renders above other layers.
2347
+ const z = (typeof window !== 'undefined' && typeof window.TIPS_ZINDEX !== 'undefined')
2348
+ ? String(window.TIPS_ZINDEX) : '2147483000';
2349
+ el.style.zIndex = z;
2350
+ }
2351
+
2352
+ // Hide tips layer and stop rotation.
2353
+ hide() {
2354
+ if (this.hidden) return;
2355
+ this.stopTimers();
2356
+ const el = this._host();
2357
+ if (el) {
2358
+ // Remove visibility class and hide hard (used when stream starts etc.)
2359
+ el.classList.remove('visible');
2360
+ el.classList.remove('hidden'); // in case it was set elsewhere
2361
+ el.style.display = 'none';
2362
+ }
2363
+ this.hidden = true;
2364
+ }
2365
+
2366
+ // Show tips layer (does not start rotation).
2367
+ show() {
2368
+ const list = this._getList(); if (!list.length) return;
2369
+ const el = this._host(); if (!el) return;
2370
+
2371
+ this.hidden = false;
2372
+ this._applyBaseStyle(el);
2373
+ el.classList.remove('hidden');
2374
+ el.style.display = 'block'; // CSS handles opacity via .tips/.visible
2375
+ // Do not add 'visible' yet – cycle() takes care of fade-in steps.
2376
+ }
2377
+
2378
+ // Show one tip (by index) and fade it in next frame.
2379
+ _showOne(idx) {
2380
+ const list = this._getList(); if (!list.length) return;
2381
+ const el = this._host(); if (!el || this.hidden) return;
2382
+
2383
+ this._applyBaseStyle(el);
2384
+ el.innerHTML = list[idx % list.length];
2385
+
2386
+ // Centralize "next-frame" visibility toggle through RafManager to guarantee CSS transition.
2387
+ try {
2388
+ if (typeof runtime !== 'undefined' && runtime.raf && typeof runtime.raf.schedule === 'function') {
2389
+ const key = { t: 'Tips:show', el, i: Math.random() };
2390
+ runtime.raf.schedule(key, () => {
2391
+ if (this.hidden || !el.isConnected) return;
2392
+ el.classList.add('visible');
2393
+ }, 'Tips', 2);
2394
+ } else {
2395
+ // Fallback: no frame delay – still functional, transition may not play.
2396
+ el.classList.add('visible');
2397
+ }
2398
+ } catch (_) {
2399
+ el.classList.add('visible');
2400
+ }
2401
+ }
2402
+
2403
+ // Internal loop: show, wait, hide, wait fade, next.
2404
+ _cycleLoop() {
2405
+ if (this.hidden) return;
2406
+ const el = this._host(); if (!el) return;
2407
+
2408
+ const VISIBLE_MS = (typeof window !== 'undefined' && window.TIPS_VISIBLE_MS) ? window.TIPS_VISIBLE_MS : 15000;
2409
+ const FADE_MS = (typeof window !== 'undefined' && window.TIPS_FADE_MS) ? window.TIPS_FADE_MS : 1000;
2410
+
2411
+ this._showOne(this._idx);
2412
+
2413
+ // Sequence: visible -> wait -> remove 'visible' -> wait fade -> next
2414
+ this._timers.push(setTimeout(() => {
2415
+ if (this.hidden) return;
2416
+ el.classList.remove('visible');
2417
+ this._timers.push(setTimeout(() => {
2418
+ if (this.hidden) return;
2419
+ const list = this._getList(); if (!list.length) return;
2420
+ this._idx = (this._idx + 1) % list.length;
2421
+ this._cycleLoop();
2422
+ }, FADE_MS));
2423
+ }, VISIBLE_MS));
2424
+ }
2425
+
2426
+ // Start rotation with initial delay.
2427
+ cycle() {
2428
+ const list = this._getList(); if (!list.length || this._running) return;
2429
+ this._running = true; this._idx = 0;
2430
+ this.show(); // make sure the host is visible and centered
2431
+
2432
+ const INIT_DELAY = (typeof window !== 'undefined' && window.TIPS_INIT_DELAY_MS) ? window.TIPS_INIT_DELAY_MS : 10000;
2433
+ this._timers.push(setTimeout(() => {
2434
+ if (this.hidden) return;
2435
+ this._cycleLoop();
2436
+ }, Math.max(0, INIT_DELAY)));
2437
+ }
2438
+
2439
+ // Stop and reset.
2440
+ cleanup() {
2441
+ this.stopTimers();
2442
+ const el = this._host();
2443
+ if (el) el.classList.remove('visible');
2444
+ }
2445
+ }
2446
+
2447
+ // ==========================================================================
2448
+ // 9) Tool output + Nodes manager
2449
+ // ==========================================================================
2450
+
2451
+ class ToolOutput {
2452
+ // Placeholder for loader show (can be extended by host).
2453
+ showLoader() { return; }
2454
+ // Hide spinner elements in bot messages.
2455
+ hideLoader() {
2456
+ const elements = document.querySelectorAll('.msg-bot');
2457
+ if (elements.length > 0) elements.forEach(el => { const s = el.querySelector('.spinner'); if (s) s.style.display = 'none'; });
2458
+ }
2459
+ begin() { this.showLoader(); }
2460
+ end() { this.hideLoader(); }
2461
+ enable() { const els = document.querySelectorAll('.tool-output'); if (els.length) els[els.length - 1].style.display = 'block'; }
2462
+ disable() { const els = document.querySelectorAll('.tool-output'); if (els.length) els[els.length - 1].style.display = 'none'; }
2463
+ // Append HTML into the latest tool-output content area.
2464
+ append(content) {
2465
+ this.hideLoader(); this.enable();
2466
+ const els = document.querySelectorAll('.tool-output');
2467
+ if (els.length) { const contentEl = els[els.length - 1].querySelector('.content'); if (contentEl) contentEl.insertAdjacentHTML('beforeend', content); }
2468
+ }
2469
+ // Replace inner HTML for the latest tool-output content area.
2470
+ update(content) {
2471
+ this.hideLoader(); this.enable();
2472
+ const els = document.querySelectorAll('.tool-output');
2473
+ if (els.length) { const contentEl = els[els.length - 1].querySelector('.content'); if (contentEl) contentEl.innerHTML = content; }
2474
+ }
2475
+ // Remove children from the latest tool-output content area.
2476
+ clear() {
2477
+ this.hideLoader(); this.enable();
2478
+ const els = document.querySelectorAll('.tool-output');
2479
+ if (els.length) { const contentEl = els[els.length - 1].querySelector('.content'); if (contentEl) contentEl.replaceChildren(); }
2480
+ }
2481
+ // Toggle visibility of a specific tool output block by message id.
2482
+ toggle(id) {
2483
+ const el = document.getElementById('msg-bot-' + id); if (!el) return;
2484
+ const outputEl = el.querySelector('.tool-output'); if (!outputEl) return;
2485
+ const contentEl = outputEl.querySelector('.content');
2486
+ if (contentEl) contentEl.style.display = (contentEl.style.display === 'none') ? 'block' : 'none';
2487
+ const toggleEl = outputEl.querySelector('.toggle-cmd-output img'); if (toggleEl) toggleEl.classList.toggle('toggle-expanded');
2488
+ }
2489
+ }
2490
+
2491
+ class NodesManager {
2492
+ constructor(dom, renderer, highlighter, math) { this.dom = dom; this.renderer = renderer; this.highlighter = highlighter; this.math = math; }
2493
+ // Check if HTML contains only user messages without any markdown or code features.
2494
+ _isUserOnlyContent(html) {
2495
+ try {
2496
+ const tmp = document.createElement('div');
2497
+ tmp.innerHTML = html;
2498
+ const hasBot = !!tmp.querySelector('.msg-box.msg-bot');
2499
+ const hasUser = !!tmp.querySelector('.msg-box.msg-user');
2500
+ const hasMD64 = !!tmp.querySelector('[data-md64]');
2501
+ const hasMDNative = !!tmp.querySelector('[md-block-markdown]');
2502
+ const hasCode = !!tmp.querySelector('pre code');
2503
+ const hasMath = !!tmp.querySelector('script[type^="math/tex"]');
2504
+ return hasUser && !hasBot && !hasMD64 && !hasMDNative && !hasCode && !hasMath;
2505
+ } catch (_) { return false; }
2506
+ }
2507
+ // Convert user markdown placeholders into plain text nodes.
2508
+ _materializeUserMdAsPlainText(scopeEl) {
2509
+ try {
2510
+ const nodes = scopeEl.querySelectorAll('.msg-box.msg-user [data-md64], .msg-box.msg-user [md-block-markdown]');
2511
+ nodes.forEach(el => {
2512
+ let txt = '';
2513
+ if (el.hasAttribute('data-md64')) {
2514
+ const b64 = el.getAttribute('data-md64') || '';
2515
+ el.removeAttribute('data-md64');
2516
+ try { txt = this.renderer.b64ToUtf8(b64); } catch (_) { txt = ''; }
2517
+ } else {
2518
+ // Native Markdown block in user message: keep as plain text (no markdown-it)
2519
+ try { txt = el.textContent || ''; } catch (_) { txt = ''; }
2520
+ try { el.removeAttribute('md-block-markdown'); } catch (_) {}
2521
+ }
2522
+ const span = document.createElement('span'); span.textContent = txt; el.replaceWith(span);
2523
+ });
2524
+ } catch (_) {}
2525
+ }
2526
+ // Append HTML into message input container.
2527
+ appendToInput(content) {
2528
+ // Synchronous DOM update – message input must reflect immediately with no waiting.
2529
+ const el = this.dom.get('_append_input_'); if (!el) return; el.insertAdjacentHTML('beforeend', content);
2530
+ }
2531
+ // Append nodes into messages list and perform post-processing (markdown, code, math).
2532
+ appendNode(content, scrollMgr) {
2533
+ // Keep scroll behavior consistent with existing logic
2534
+ scrollMgr.userInteracted = false; scrollMgr.prevScroll = 0;
2535
+ this.dom.clearStreamBefore();
2536
+
2537
+ const el = this.dom.get('_nodes_'); if (!el) return;
2538
+ el.classList.remove('empty_list');
2539
+
2540
+ const userOnly = this._isUserOnlyContent(content);
2541
+ if (userOnly) {
2542
+ el.insertAdjacentHTML('beforeend', content);
2543
+ this._materializeUserMdAsPlainText(el);
2544
+ scrollMgr.scrollToBottom(false);
2545
+ scrollMgr.scheduleScrollFabUpdate();
2546
+ return;
2547
+ }
2548
+
2549
+ el.insertAdjacentHTML('beforeend', content);
2550
+
2551
+ try {
2552
+ // Schedule all post-processing strictly after Markdown is materialized.
2553
+ const maybePromise = this.renderer.renderPendingMarkdown(el);
2554
+ const post = () => {
2555
+ try { this.highlighter.scheduleScanVisibleCodes(null); } catch (_) {}
2556
+
2557
+ // In finalize-only mode we must explicitly schedule KaTeX,
2558
+ // and do it AFTER Markdown has produced <script type="math/tex"> nodes.
2559
+ try { if (getMathMode() === 'finalize-only') this.math.schedule(el, 0, true); } catch (_) {}
2560
+ };
2561
+
2562
+ if (maybePromise && typeof maybePromise.then === 'function') {
2563
+ maybePromise.then(post);
2564
+ } else {
2565
+ post();
2566
+ }
2567
+ } catch (_) { /* swallow to keep append path resilient */ }
2568
+
2569
+ // Keep scroll/fab logic identical (immediate; rendering completes shortly after)
2570
+ scrollMgr.scrollToBottom(false);
2571
+ scrollMgr.scheduleScrollFabUpdate();
2572
+ }
2573
+ // Replace messages list content entirely and re-run post-processing.
2574
+ replaceNodes(content, scrollMgr) {
2575
+ // Same semantics as appendNode, but using a hard clone reset
2576
+ scrollMgr.userInteracted = false; scrollMgr.prevScroll = 0;
2577
+ this.dom.clearStreamBefore();
2578
+
2579
+ const el = this.dom.hardReplaceByClone('_nodes_'); if (!el) return;
2580
+ el.classList.remove('empty_list');
2581
+
2582
+ const userOnly = this._isUserOnlyContent(content);
2583
+ if (userOnly) {
2584
+ el.insertAdjacentHTML('beforeend', content);
2585
+ this._materializeUserMdAsPlainText(el);
2586
+ scrollMgr.scrollToBottom(false, true);
2587
+ scrollMgr.scheduleScrollFabUpdate();
2588
+ return;
2589
+ }
2590
+
2591
+ el.insertAdjacentHTML('beforeend', content);
2592
+
2593
+ try {
2594
+ // Defer KaTeX schedule to post-Markdown to avoid races.
2595
+ const maybePromise = this.renderer.renderPendingMarkdown(el);
2596
+ const post = () => {
2597
+ try { this.highlighter.scheduleScanVisibleCodes(null); } catch (_) {}
2598
+ try { if (getMathMode() === 'finalize-only') this.math.schedule(el, 0, true); } catch (_) {}
2599
+ };
2600
+
2601
+ if (maybePromise && typeof maybePromise.then === 'function') {
2602
+ maybePromise.then(post);
2603
+ } else {
2604
+ post();
2605
+ }
2606
+ } catch (_) { /* swallow */ }
2607
+
2608
+ scrollMgr.scrollToBottom(false, true);
2609
+ scrollMgr.scheduleScrollFabUpdate();
2610
+ }
2611
+ // Append "extra" content into a specific bot message and post-process locally.
2612
+ appendExtra(id, content, scrollMgr) {
2613
+ const el = document.getElementById('msg-bot-' + id); if (!el) return;
2614
+ const extra = el.querySelector('.msg-extra'); if (!extra) return;
2615
+
2616
+ extra.insertAdjacentHTML('beforeend', content);
2617
+
2618
+ try {
2619
+ const maybePromise = this.renderer.renderPendingMarkdown(extra);
2620
+
2621
+ const post = () => {
2622
+ const activeCode = (typeof runtime !== 'undefined' && runtime.stream) ? runtime.stream.activeCode : null;
2623
+
2624
+ // Attach observers after Markdown produced the nodes
2625
+ try {
2626
+ this.highlighter.observeNewCode(extra, {
2627
+ deferLastIfStreaming: true,
2628
+ minLinesForLast: this.renderer.cfg.PROFILE_CODE.minLinesForHL,
2629
+ minCharsForLast: this.renderer.cfg.PROFILE_CODE.minCharsForHL
2630
+ }, activeCode);
2631
+ this.highlighter.observeMsgBoxes(extra, (box) => this._onBox(box));
2632
+ } catch (_) {}
2633
+
2634
+ // KaTeX: honor stream mode; in finalize-only force immediate schedule,
2635
+ // now guaranteed to find <script type="math/tex"> nodes.
2636
+ try {
2637
+ const mm = getMathMode();
2638
+ if (mm === 'finalize-only') this.math.schedule(extra, 0, true);
2639
+ else this.math.schedule(extra);
2640
+ } catch (_) {}
2641
+ };
2642
+
2643
+ if (maybePromise && typeof maybePromise.then === 'function') {
2644
+ maybePromise.then(post);
2645
+ } else {
2646
+ post();
2647
+ }
2648
+ } catch (_) { /* swallow */ }
2649
+
2650
+ scrollMgr.scheduleScroll(true);
2651
+ }
2652
+ // When a new message box appears, hook up code/highlight handlers.
2653
+ _onBox(box) {
2654
+ const activeCode = (typeof runtime !== 'undefined' && runtime.stream) ? runtime.stream.activeCode : null;
2655
+ this.highlighter.observeNewCode(box, {
2656
+ deferLastIfStreaming: true,
2657
+ minLinesForLast: this.renderer.cfg.PROFILE_CODE.minLinesForHL,
2658
+ minCharsForLast: this.renderer.cfg.PROFILE_CODE.minCharsForHL
2659
+ }, activeCode);
2660
+ this.renderer.hooks.codeScrollInit(box);
2661
+ }
2662
+ // Remove message by id and keep scroll consistent.
2663
+ removeNode(id, scrollMgr) {
2664
+ scrollMgr.prevScroll = 0;
2665
+ let el = document.getElementById('msg-user-' + id); if (el) el.remove();
2666
+ el = document.getElementById('msg-bot-' + id); if (el) el.remove();
2667
+ this.dom.resetEphemeral();
2668
+ try { this.renderer.renderPendingMarkdown(); } catch (_) {}
2669
+ scrollMgr.scheduleScroll(true);
2670
+ }
2671
+ // Remove all messages from (and including) a given message id.
2672
+ removeNodesFromId(id, scrollMgr) {
2673
+ scrollMgr.prevScroll = 0;
2674
+ const container = this.dom.get('_nodes_'); if (!container) return;
2675
+ const elements = container.querySelectorAll('.msg-box');
2676
+ let remove = false;
2677
+ elements.forEach((element) => {
2678
+ if (element.id && element.id.endsWith('-' + id)) remove = true;
2679
+ if (remove) element.remove();
2680
+ });
2681
+ this.dom.resetEphemeral();
2682
+ try { this.renderer.renderPendingMarkdown(container); } catch (_) {}
2683
+ scrollMgr.scheduleScroll(true);
2684
+ }
2685
+ }
2686
+
2687
+ // ==========================================================================
2688
+ // 10) UI manager
2689
+ // ==========================================================================
2690
+
2691
+ class UIManager {
2692
+ // Replace or insert app-level CSS in a <style> tag.
2693
+ updateCSS(styles) {
2694
+ let style = document.getElementById('app-style');
2695
+ if (!style) { style = document.createElement('style'); style.id = 'app-style'; document.head.appendChild(style); }
2696
+ style.textContent = styles;
2697
+ }
2698
+ // Ensure base styles for code header sticky behavior exist.
2699
+ ensureStickyHeaderStyle() {
2700
+ let style = document.getElementById('code-sticky-style');
2701
+ if (style) return;
2702
+ style = document.createElement('style'); style.id = 'code-sticky-style';
2703
+ style.textContent = [
2704
+ '.code-wrapper { position: relative; }',
2705
+ '.code-wrapper .code-header-wrapper { position: sticky; top: var(--code-header-sticky-top, 0px); z-index: 2; box-shadow: 0 1px 0 rgba(0,0,0,.06); }',
2706
+ '.code-wrapper pre { overflow: visible; margin-top: 0; }',
2707
+ '.code-wrapper pre code { display: block; white-space: pre; max-height: 100dvh; overflow: auto;',
2708
+ ' overscroll-behavior: contain; -webkit-overflow-scrolling: touch; overflow-anchor: none; scrollbar-gutter: stable both-edges; scroll-behavior: auto; }',
2709
+ '#_loader_.hidden { display: none !important; visibility: hidden !important; }',
2710
+ '#_loader_.visible { display: block; visibility: visible; }'
2711
+ ].join('\n');
2712
+ document.head.appendChild(style);
2713
+ }
2714
+ // Toggle classes controlling optional UI features.
2715
+ enableEditIcons() { document.body && document.body.classList.add('display-edit-icons'); }
2716
+ disableEditIcons() { document.body && document.body.classList.remove('display-edit-icons'); }
2717
+ enableTimestamp() { document.body && document.body.classList.add('display-timestamp'); }
2718
+ disableTimestamp() { document.body && document.body.classList.remove('display-timestamp'); }
2719
+ enableBlocks() { document.body && document.body.classList.add('display-blocks'); }
2720
+ disableBlocks() { document.body && document.body.classList.remove('display-blocks'); }
2721
+ }
2722
+
2723
+ // ==========================================================================
2724
+ // 11) Stream snapshot engine + incremental code streaming
2725
+ // ==========================================================================
2726
+
2727
+ class StreamEngine {
2728
+ constructor(cfg, dom, renderer, math, highlighter, codeScroll, scrollMgr, raf, asyncer, logger) {
2729
+ this.cfg = cfg; this.dom = dom; this.renderer = renderer; this.math = math;
2730
+ this.highlighter = highlighter; this.codeScroll = codeScroll; this.scrollMgr = scrollMgr; this.raf = raf;
2731
+ this.asyncer = asyncer;
2732
+ this.logger = logger || new Logger(cfg);
2733
+
2734
+ // Streaming buffer (rope-like) – avoids O(n^2) string concatenation when many small chunks arrive.
2735
+ // streamBuf holds the already materialized prefix; _sbParts keeps recent tail parts; _sbLen tracks their length.
2736
+ this.streamBuf = ''; // materialized prefix (string used by render)
2737
+ this._sbParts = []; // pending string chunks (array) not yet joined
2738
+ this._sbLen = 0; // length of pending chunks
2739
+
2740
+ this.fenceOpen = false; this.fenceMark = '`'; this.fenceLen = 3;
2741
+ this.fenceTail = ''; this.fenceBuf = '';
2742
+ this.lastSnapshotTs = 0; this.nextSnapshotStep = cfg.PROFILE_TEXT.base;
2743
+ this.snapshotScheduled = false; this.snapshotRAF = 0;
2744
+
2745
+ this.codeStream = { open: false, lines: 0, chars: 0 };
2746
+ this.activeCode = null;
2747
+
2748
+ this.suppressPostFinalizePass = false;
2749
+
2750
+ this._promoteScheduled = false;
2751
+
2752
+ // Guard to ensure first fence-open is materialized immediately when stream starts with code.
2753
+ this._firstCodeOpenSnapDone = false;
2754
+
2755
+ // Streaming mode flag – controls reduced rendering (no linkify etc.) on hot path.
2756
+ this.isStreaming = false;
2757
+ }
2758
+ _d(tag, data) { this.logger.debug('STREAM', tag, data); }
2759
+
2760
+ // --- Rope buffer helpers (internal) ---
2761
+
2762
+ // Append a chunk into the rope without immediately touching the large string.
2763
+ _appendChunk(s) {
2764
+ if (!s) return;
2765
+ this._sbParts.push(s);
2766
+ this._sbLen += s.length;
2767
+ }
2768
+ // Current logical length of the stream text (materialized prefix + pending tail).
2769
+ getStreamLength() {
2770
+ return (this.streamBuf.length + this._sbLen);
2771
+ }
2772
+ // Materialize the rope into a single string for rendering (cheap if nothing pending).
2773
+ getStreamText() {
2774
+ if (this._sbLen > 0) {
2775
+ // Join pending parts into the materialized prefix and clear the tail.
2776
+ // Single-part fast path avoids a temporary array join.
2777
+ this.streamBuf += (this._sbParts.length === 1 ? this._sbParts[0] : this._sbParts.join(''));
2778
+ this._sbParts.length = 0;
2779
+ this._sbLen = 0;
2780
+ }
2781
+ return this.streamBuf;
2782
+ }
2783
+ // Reset the rope to an empty state.
2784
+ _clearStreamBuffer() {
2785
+ this.streamBuf = '';
2786
+ this._sbParts.length = 0;
2787
+ this._sbLen = 0;
2788
+ }
2789
+
2790
+ // Reset all streaming state and counters.
2791
+ reset() {
2792
+ this._clearStreamBuffer();
2793
+ this.fenceOpen = false; this.fenceMark = '`'; this.fenceLen = 3;
2794
+ this.fenceTail = ''; this.fenceBuf = '';
2795
+ this.lastSnapshotTs = 0; this.nextSnapshotStep = this.profile().base;
2796
+ this.snapshotScheduled = false; this.snapshotRAF = 0;
2797
+ this.codeStream = { open: false, lines: 0, chars: 0 };
2798
+ this.activeCode = null; this.suppressPostFinalizePass = false;
2799
+ this._promoteScheduled = false;
2800
+ this._firstCodeOpenSnapDone = false;
2801
+ this._d('RESET', { });
2802
+ }
2803
+ // Turn active streaming code block into plain text (safety on abort).
2804
+ defuseActiveToPlain() {
2805
+ if (!this.activeCode || !this.activeCode.codeEl || !this.activeCode.codeEl.isConnected) return;
2806
+ const codeEl = this.activeCode.codeEl;
2807
+ const fullText = (this.activeCode.frozenEl?.textContent || '') + (this.activeCode.tailEl?.textContent || '');
2808
+ try {
2809
+ codeEl.textContent = fullText;
2810
+ codeEl.removeAttribute('data-highlighted');
2811
+ codeEl.classList.remove('hljs');
2812
+ codeEl.dataset._active_stream = '0';
2813
+ const st = this.codeScroll.state(codeEl); st.autoFollow = false;
2814
+ } catch (_) {}
2815
+ this._d('DEFUSE_ACTIVE_TO_PLAIN', { len: fullText.length });
2816
+ this.activeCode = null;
2817
+ }
2818
+ // If there are orphan streaming code blocks in DOM, finalize them as plain text.
2819
+ defuseOrphanActiveBlocks(root) {
2820
+ try {
2821
+ const scope = root || document;
2822
+ const nodes = scope.querySelectorAll('pre code[data-_active_stream="1"]');
2823
+ let n = 0;
2824
+ nodes.forEach(codeEl => {
2825
+ if (!codeEl.isConnected) return;
2826
+ let text = '';
2827
+ const frozen = codeEl.querySelector('.hl-frozen');
2828
+ const tail = codeEl.querySelector('.hl-tail');
2829
+ if (frozen || tail) text = (frozen?.textContent || '') + (tail?.textContent || '');
2830
+ else text = codeEl.textContent || '';
2831
+ codeEl.textContent = text;
2832
+ codeEl.removeAttribute('data-highlighted');
2833
+ codeEl.classList.remove('hljs');
2834
+ codeEl.dataset._active_stream = '0';
2835
+ try { this.codeScroll.attachHandlers(codeEl); } catch (_) {}
2836
+ n++;
2837
+ });
2838
+ if (n) this._d('DEFUSE_ORPHAN_ACTIVE_BLOCKS', { count: n });
2839
+ } catch (e) { this._d('DEFUSE_ORPHAN_ACTIVE_ERR', String(e)); }
2840
+ }
2841
+ // Abort streaming and clear state with options.
2842
+ abortAndReset(opts) {
2843
+ const o = Object.assign({
2844
+ finalizeActive: true,
2845
+ clearBuffer: true,
2846
+ clearMsg: false,
2847
+ defuseOrphans: true,
2848
+ reason: '',
2849
+ suppressLog: false
2850
+ }, (opts || {}));
2851
+
2852
+ try { this.raf.cancelGroup('StreamEngine'); } catch (_) {}
2853
+ try { this.raf.cancel('SE:snapshot'); } catch (_) {}
2854
+ this.snapshotScheduled = false; this.snapshotRAF = 0;
2855
+
2856
+ const hadActive = !!this.activeCode;
2857
+ try {
2858
+ if (this.activeCode) {
2859
+ if (o.finalizeActive === true) this.finalizeActiveCode();
2860
+ else this.defuseActiveToPlain();
2861
+ }
2862
+ } catch (e) {
2863
+ this._d('ABORT_FINALIZE_ERR', String(e));
2864
+ }
2865
+
2866
+ if (o.defuseOrphans) {
2867
+ try { this.defuseOrphanActiveBlocks(); }
2868
+ catch (e) { this._d('ABORT_DEFUSE_ORPHANS_ERR', String(e)); }
2869
+ }
2870
+
2871
+ if (o.clearBuffer) {
2872
+ this._clearStreamBuffer();
2873
+ this.fenceOpen = false; this.fenceMark = '`'; this.fenceLen = 3;
2874
+ this.fenceTail = ''; this.fenceBuf = '';
2875
+ this.codeStream.open = false; this.codeStream.lines = 0; this.codeStream.chars = 0;
2876
+ window.__lastSnapshotLen = 0;
2877
+ }
2878
+ if (o.clearMsg === true) {
2879
+ try { this.dom.resetEphemeral(); } catch (_) {}
2880
+ }
2881
+ if (!o.suppressLog) this._d('ABORT_AND_RESET', { hadActive, ...o });
2882
+ }
2883
+ // Select profile for current stream state (code vs text).
2884
+ profile() { return this.fenceOpen ? this.cfg.PROFILE_CODE : this.cfg.PROFILE_TEXT; }
2885
+ // Reset adaptive snapshot budget to base.
2886
+ resetBudget() { this.nextSnapshotStep = this.profile().base; }
2887
+ // Check whether [from, end) contains only spaces/tabs.
2888
+ onlyTrailingWhitespace(s, from, end) {
2889
+ for (let i = from; i < end; i++) { const c = s.charCodeAt(i); if (c !== 0x20 && c !== 0x09) return false; }
2890
+ return true;
2891
+ }
2892
+ // Update fence state based on a fresh chunk and buffer tail; detect openings and closings.
2893
+ updateFenceHeuristic(chunk) {
2894
+ const prev = (this.fenceBuf || '');
2895
+ const s = prev + (chunk || '');
2896
+ const preLen = prev.length;
2897
+ const n = s.length; let i = 0;
2898
+ let opened = false; let closed = false; let splitAt = -1;
2899
+ let atLineStart = (preLen === 0) ? true : /[\n\r]$/.test(prev);
2900
+
2901
+ const inNewOrCrosses = (j, k) => (j >= preLen) || (k > preLen);
2902
+
2903
+ while (i < n) {
2904
+ const ch = s[i];
2905
+ if (ch === '\r' || ch === '\n') { atLineStart = true; i++; continue; }
2906
+ if (!atLineStart) { i++; continue; }
2907
+ atLineStart = false;
2908
+
2909
+ let j = i;
2910
+ while (j < n) {
2911
+ let localSpaces = 0;
2912
+ while (j < n && (s[j] === ' ' || s[j] === '\t')) { localSpaces += (s[j] === '\t') ? 4 : 1; j++; if (localSpaces > 3) break; }
2913
+ if (j < n && s[j] === '>') { j++; if (j < n && s[j] === ' ') j++; continue; }
2914
+ let saved = j;
2915
+ if (j < n && (s[j] === '-' || s[j] === '*' || s[j] === '+')) {
2916
+ let jj = j + 1; if (jj < n && s[jj] === ' ') { j = jj + 1; } else { j = saved; }
2917
+ } else {
2918
+ let k2 = j; let hasDigit = false;
2919
+ while (k2 < n && s[k2] >= '0' && s[k2] <= '9') { hasDigit = true; k2++; }
2920
+ if (hasDigit && k2 < n && (s[k2] === '.' || s[k2] === ')')) {
2921
+ k2++; if (k2 < n && s[k2] === ' ') { j = k2 + 1; } else { j = saved; }
2922
+ } else { j = saved; }
2923
+ }
2924
+ break;
2925
+ }
2926
+
2927
+ let indent = 0;
2928
+ while (j < n && (s[j] === ' ' || s[j] === '\t')) {
2929
+ indent += (s[j] === '\t') ? 4 : 1; j++; if (indent > 3) break;
2930
+ }
2931
+ if (indent > 3) { i = j; continue; }
2932
+
2933
+ if (j < n && (s[j] === '`' || s[j] === '~')) {
2934
+ const mark = s[j]; let k = j; while (k < n && s[k] === mark) k++; const run = k - j;
2935
+
2936
+ if (!this.fenceOpen) {
2937
+ if (run >= 3) {
2938
+ if (!inNewOrCrosses(j, k)) { i = k; continue; }
2939
+ this.fenceOpen = true; this.fenceMark = mark; this.fenceLen = run; opened = true; i = k;
2940
+ this._d('FENCE_OPEN_DETECTED', { mark, run, idxStart: j, idxEnd: k, bufTail: this.fenceTail, region: (j >= preLen) ? 'new' : 'cross' });
2941
+ continue;
2942
+ }
2943
+ } else {
2944
+ if (mark === this.fenceMark && run >= this.fenceLen) {
2945
+ if (!inNewOrCrosses(j, k)) { i = k; continue; }
2946
+ let eol = k; while (eol < n && s[eol] !== '\n' && s[eol] !== '\r') eol++;
2947
+ if (this.onlyTrailingWhitespace(s, k, eol)) {
2948
+ this.fenceOpen = false; closed = true;
2949
+ const endInS = k;
2950
+ const rel = endInS - preLen;
2951
+ const split = Math.max(0, Math.min((chunk ? chunk.length : 0), rel));
2952
+ splitAt = split; i = k;
2953
+ this._d('FENCE_CLOSE_DETECTED', { mark, run, idxStart: j, idxEnd: k, splitAt, region: (j >= preLen) ? 'new' : 'cross' });
2954
+ continue;
2955
+ } else {
2956
+ this._d('FENCE_CLOSE_REJECTED_NON_WS_AFTER', { mark, run, idxStart: j, idxEnd: k, region: (j >= preLen) ? 'new' : (k > preLen ? 'cross' : 'old') });
2957
+ }
2958
+ }
2959
+ }
2960
+ }
2961
+ i = j + 1;
2962
+ }
2963
+
2964
+ const MAX_TAIL = 512;
2965
+ this.fenceBuf = s.slice(-MAX_TAIL);
2966
+ this.fenceTail = s.slice(-3);
2967
+ return { opened, closed, splitAt };
2968
+ }
2969
+ // Ensure message snapshot container exists.
2970
+ getMsgSnapshotRoot(msg) {
2971
+ if (!msg) return null;
2972
+ let snap = msg.querySelector('.md-snapshot-root');
2973
+ if (!snap) { snap = document.createElement('div'); snap.className = 'md-snapshot-root'; msg.appendChild(snap); }
2974
+ return snap;
2975
+ }
2976
+ // Detect structural boundaries in a chunk (for snapshot decisions).
2977
+ hasStructuralBoundary(chunk) { if (!chunk) return false; return /\n(\n|[-*]\s|\d+\.\s|#{1,6}\s|>\s)/.test(chunk); }
2978
+ // Decide whether we should snapshot on this chunk.
2979
+ shouldSnapshotOnChunk(chunk, chunkHasNL, hasBoundary) {
2980
+ const prof = this.profile(); const now = Utils.now();
2981
+ if (this.activeCode && this.fenceOpen) return false;
2982
+ if ((now - this.lastSnapshotTs) < prof.minInterval) return false;
2983
+ if (hasBoundary) return true;
2984
+
2985
+ const delta = Math.max(0, this.getStreamLength() - (window.__lastSnapshotLen || 0));
2986
+ if (this.fenceOpen) { if (chunkHasNL && delta >= this.nextSnapshotStep) return true; return false; }
2987
+ if (delta >= this.nextSnapshotStep) return true;
2988
+ return false;
2989
+ }
2990
+ // If we are getting slow, schedule a soft snapshot based on time.
2991
+ maybeScheduleSoftSnapshot(msg, chunkHasNL) {
2992
+ const prof = this.profile(); const now = Utils.now();
2993
+ if (this.activeCode && this.fenceOpen) return;
2994
+ if (this.fenceOpen && this.codeStream.lines < 1 && !chunkHasNL) return;
2995
+ if ((now - this.lastSnapshotTs) >= prof.softLatency) this.scheduleSnapshot(msg);
2996
+ }
2997
+ // Schedule snapshot rendering (coalesced via rAF).
2998
+ scheduleSnapshot(msg, force = false) {
2999
+ if (this.snapshotScheduled && !this.raf.isScheduled('SE:snapshot')) this.snapshotScheduled = false;
3000
+ if (!force) {
3001
+ if (this.snapshotScheduled) return;
3002
+ if (this.activeCode && this.fenceOpen) return;
3003
+ } else {
3004
+ if (this.snapshotScheduled && this.raf.isScheduled('SE:snapshot')) return;
3005
+ }
3006
+ this.snapshotScheduled = true;
3007
+ this.raf.schedule('SE:snapshot', () => { this.snapshotScheduled = false; this.renderSnapshot(msg); }, 'StreamEngine', 0);
3008
+ }
3009
+ // Split code element into frozen and tail spans if needed.
3010
+ ensureSplitCodeEl(codeEl) {
3011
+ if (!codeEl) return null;
3012
+ let frozen = codeEl.querySelector('.hl-frozen'); let tail = codeEl.querySelector('.hl-tail');
3013
+ if (frozen && tail) return { codeEl, frozenEl: frozen, tailEl: tail };
3014
+ const text = codeEl.textContent || ''; codeEl.innerHTML = '';
3015
+ frozen = document.createElement('span'); frozen.className = 'hl-frozen';
3016
+ tail = document.createElement('span'); tail.className = 'hl-tail';
3017
+ codeEl.appendChild(frozen); codeEl.appendChild(tail);
3018
+ if (text) tail.textContent = text; return { codeEl, frozenEl: frozen, tailEl: tail };
3019
+ }
3020
+ // Create active code context from the latest snapshot.
3021
+ setupActiveCodeFromSnapshot(snap) {
3022
+ const codes = snap.querySelectorAll('pre code'); if (!codes.length) return null;
3023
+ const last = codes[codes.length - 1];
3024
+ const cls = Array.from(last.classList).find(c => c.startsWith('language-')) || 'language-plaintext';
3025
+ const lang = (cls.replace('language-', '') || 'plaintext');
3026
+ const parts = this.ensureSplitCodeEl(last); if (!parts) return null;
3027
+ const st = this.codeScroll.state(parts.codeEl); st.autoFollow = true; st.userInteracted = false;
3028
+ parts.codeEl.dataset._active_stream = '1';
3029
+ const baseFrozenNL = Utils.countNewlines(parts.frozenEl.textContent || ''); const baseTailNL = Utils.countNewlines(parts.tailEl.textContent || '');
3030
+ const ac = { codeEl: parts.codeEl, frozenEl: parts.frozenEl, tailEl: parts.tailEl, lang, frozenLen: parts.frozenEl.textContent.length, lastPromoteTs: 0,
3031
+ lines: 0, tailLines: baseTailNL, linesSincePromote: 0, initialLines: baseFrozenNL + baseTailNL, haltHL: false, plainStream: false };
3032
+ this._d('ACTIVE_CODE_SETUP', { lang, frozenLen: ac.frozenLen, tailLines: ac.tailLines, initialLines: ac.initialLines });
3033
+ return ac;
3034
+ }
3035
+ // Copy previous active code state into the new one (after snapshot).
3036
+ rehydrateActiveCode(oldAC, newAC) {
3037
+ if (!oldAC || !newAC) return;
3038
+ newAC.frozenEl.innerHTML = oldAC.frozenEl ? oldAC.frozenEl.innerHTML : '';
3039
+ const fullText = newAC.codeEl.textContent || ''; const remainder = fullText.slice(oldAC.frozenLen);
3040
+ newAC.tailEl.textContent = remainder;
3041
+ newAC.frozenLen = oldAC.frozenLen; newAC.lang = oldAC.lang;
3042
+ newAC.lines = oldAC.lines; newAC.tailLines = Utils.countNewlines(remainder);
3043
+ newAC.lastPromoteTs = oldAC.lastPromoteTs; newAC.linesSincePromote = oldAC.linesSincePromote || 0;
3044
+ newAC.initialLines = oldAC.initialLines || 0; newAC.haltHL = !!oldAC.haltHL;
3045
+ newAC.plainStream = !!oldAC.plainStream;
3046
+ this._d('ACTIVE_CODE_REHYDRATE', { lang: newAC.lang, frozenLen: newAC.frozenLen, tailLines: newAC.tailLines, initialLines: newAC.initialLines, halted: newAC.haltHL, plainStream: newAC.plainStream });
3047
+ }
3048
+ // Append text to active tail span and update counters.
3049
+ appendToActiveTail(text) {
3050
+ if (!this.activeCode || !this.activeCode.tailEl || !text) return;
3051
+ this.activeCode.tailEl.insertAdjacentText('beforeend', text);
3052
+ const nl = Utils.countNewlines(text);
3053
+ this.activeCode.tailLines += nl; this.activeCode.linesSincePromote += nl;
3054
+ this.codeScroll.scheduleScroll(this.activeCode.codeEl, true, false);
3055
+ if (this.logger.isEnabled('STREAM') && (nl > 0 || text.length >= 64)) {
3056
+ this._d('TAIL_APPEND', { addLen: text.length, addNL: nl, totalTailNL: this.activeCode.tailLines });
3057
+ }
3058
+ }
3059
+ // Enforce budgets: stop incremental hljs and switch to plain streaming if needed.
3060
+ enforceHLStopBudget() {
3061
+ if (!this.activeCode) return;
3062
+ // If global disable was requested, halt early and switch to plain streaming.
3063
+ if (this.cfg.HL.DISABLE_ALL) { this.activeCode.haltHL = true; this.activeCode.plainStream = true; return; }
3064
+ const stop = (this.cfg.PROFILE_CODE.stopAfterLines | 0);
3065
+ const streamPlainLines = (this.cfg.PROFILE_CODE.streamPlainAfterLines | 0);
3066
+ const streamPlainChars = (this.cfg.PROFILE_CODE.streamPlainAfterChars | 0);
3067
+ const maxFrozenChars = (this.cfg.PROFILE_CODE.maxFrozenChars | 0);
3068
+
3069
+ const totalLines = (this.activeCode.initialLines || 0) + (this.activeCode.lines || 0);
3070
+ const frozenChars = this.activeCode.frozenLen | 0;
3071
+ const tailChars = (this.activeCode.tailEl?.textContent || '').length | 0;
3072
+ const totalStreamedChars = frozenChars + tailChars;
3073
+
3074
+ // Switch to plain streaming after budgets – no incremental hljs
3075
+ if ((streamPlainLines > 0 && totalLines >= streamPlainLines) ||
3076
+ (streamPlainChars > 0 && totalStreamedChars >= streamPlainChars) ||
3077
+ (maxFrozenChars > 0 && frozenChars >= maxFrozenChars)) {
3078
+ this.activeCode.haltHL = true;
3079
+ this.activeCode.plainStream = true;
3080
+ try { this.activeCode.codeEl.dataset.hlStreamSuspended = '1'; } catch (_) {}
3081
+ this._d('STREAM_HL_SUSPENDED', { totalLines, totalStreamedChars, frozenChars, reason: 'budget' });
3082
+ return;
3083
+ }
3084
+
3085
+ if (stop > 0 && totalLines >= stop) {
3086
+ this.activeCode.haltHL = true;
3087
+ this.activeCode.plainStream = true;
3088
+ try { this.activeCode.codeEl.dataset.hlStreamSuspended = '1'; } catch (_) {}
3089
+ this._d('STREAM_HL_SUSPENDED', { totalLines, stopAfter: stop, reason: 'stopAfterLines' });
3090
+ }
3091
+ }
3092
+ _aliasLang(token) {
3093
+ const ALIAS = {
3094
+ txt: 'plaintext', text: 'plaintext', plaintext: 'plaintext',
3095
+ sh: 'bash', shell: 'bash', zsh: 'bash', 'shell-session': 'bash',
3096
+ py: 'python', python3: 'python', py3: 'python',
3097
+ js: 'javascript', node: 'javascript', nodejs: 'javascript',
3098
+ ts: 'typescript', 'ts-node': 'typescript',
3099
+ yml: 'yaml', kt: 'kotlin', rs: 'rust',
3100
+ csharp: 'csharp', 'c#': 'csharp', 'c++': 'cpp',
3101
+ ps: 'powershell', ps1: 'powershell', pwsh: 'powershell', powershell7: 'powershell',
3102
+ docker: 'dockerfile'
3103
+ };
3104
+ const v = String(token || '').trim().toLowerCase();
3105
+ return ALIAS[v] || v;
3106
+ }
3107
+ _isHLJSSupported(lang) {
3108
+ try { return !!(window.hljs && hljs.getLanguage && hljs.getLanguage(lang)); } catch (_) { return false; }
3109
+ }
3110
+ // Try to detect language from a "language: X" style first line directive.
3111
+ _detectDirectiveLangFromText(text) {
3112
+ if (!text) return null;
3113
+ let s = String(text);
3114
+ if (s.charCodeAt(0) === 0xFEFF) s = s.slice(1);
3115
+ const lines = s.split(/\r?\n/);
3116
+ let i = 0; while (i < lines.length && !lines[i].trim()) i++;
3117
+ if (i >= lines.length) return null;
3118
+ let first = lines[i].trim();
3119
+ first = first.replace(/^\s*lang(?:uage)?\s*[:=]\s*/i, '').trim();
3120
+ let token = first.split(/\s+/)[0].replace(/:$/, '');
3121
+ if (!/^[A-Za-z][\w#+\-\.]{0,30}$/.test(token)) return null;
3122
+
3123
+ let cand = this._aliasLang(token);
3124
+ const rest = lines.slice(i + 1).join('\n');
3125
+ if (!rest.trim()) return null;
3126
+
3127
+ let pos = 0, seen = 0;
3128
+ while (seen < i && pos < s.length) { const nl = s.indexOf('\n', pos); if (nl === -1) return null; pos = nl + 1; seen++; }
3129
+ let end = s.indexOf('\n', pos);
3130
+ if (end === -1) end = s.length; else end = end + 1;
3131
+ return { lang: cand, deleteUpto: end };
3132
+ }
3133
+ // Update code element class to reflect new lang (language-xxx).
3134
+ _updateCodeLangClass(codeEl, newLang) {
3135
+ try {
3136
+ Array.from(codeEl.classList).forEach(c => { if (c.startsWith('language-')) codeEl.classList.remove(c); });
3137
+ codeEl.classList.add('language-' + (newLang || 'plaintext'));
3138
+ } catch (_) {}
3139
+ }
3140
+ // Update code header label and data attribute.
3141
+ _updateCodeHeaderLabel(codeEl, newLabel, newLangToken) {
3142
+ try {
3143
+ const wrap = codeEl.closest('.code-wrapper');
3144
+ if (!wrap) return;
3145
+ const span = wrap.querySelector('.code-header-lang');
3146
+ if (span) span.textContent = newLabel || (newLangToken || 'code');
3147
+ wrap.setAttribute('data-code-lang', newLangToken || '');
3148
+ } catch (_) {}
3149
+ }
3150
+ // Try to promote language from a directive and remove its header line.
3151
+ maybePromoteLanguageFromDirective() {
3152
+ if (!this.activeCode || !this.activeCode.codeEl) return;
3153
+ if (this.activeCode.lang && this.activeCode.lang !== 'plaintext') return;
3154
+
3155
+ const frozenTxt = this.activeCode.frozenEl ? this.activeCode.frozenEl.textContent : '';
3156
+ const tailTxt = this.activeCode.tailEl ? this.activeCode.tailEl.textContent : '';
3157
+ const combined = frozenTxt + tailTxt;
3158
+ if (!combined) return;
3159
+
3160
+ const det = this._detectDirectiveLangFromText(combined);
3161
+ if (!det || !det.lang) return;
3162
+
3163
+ const newLang = det.lang;
3164
+ const newCombined = combined.slice(det.deleteUpto);
3165
+
3166
+ try {
3167
+ const codeEl = this.activeCode.codeEl;
3168
+ codeEl.innerHTML = '';
3169
+ const frozen = document.createElement('span'); frozen.className = 'hl-frozen';
3170
+ const tail = document.createElement('span'); tail.className = 'hl-tail';
3171
+ tail.textContent = newCombined;
3172
+ codeEl.appendChild(frozen); codeEl.appendChild(tail);
3173
+ this.activeCode.frozenEl = frozen; this.activeCode.tailEl = tail;
3174
+ this.activeCode.frozenLen = 0;
3175
+ this.activeCode.tailLines = Utils.countNewlines(newCombined);
3176
+ this.activeCode.linesSincePromote = 0;
3177
+
3178
+ this.activeCode.lang = newLang;
3179
+ this._updateCodeLangClass(codeEl, newLang);
3180
+ this._updateCodeHeaderLabel(codeEl, newLang, newLang);
3181
+
3182
+ this._d('LANG_PROMOTE', { to: newLang, removedChars: det.deleteUpto, tailLines: this.activeCode.tailLines });
3183
+ this.schedulePromoteTail(true);
3184
+ } catch (e) {
3185
+ this._d('LANG_PROMOTE_ERR', String(e));
3186
+ }
3187
+ }
3188
+ // Highlight a small piece of text based on language (safe fallback to escapeHtml).
3189
+ highlightDeltaText(lang, text) {
3190
+ if (this.cfg.HL.DISABLE_ALL) return Utils.escapeHtml(text);
3191
+ if (window.hljs && lang && hljs.getLanguage && hljs.getLanguage(lang)) {
3192
+ try { return hljs.highlight(text, { language: lang, ignoreIllegals: true }).value; }
3193
+ catch (_) { return Utils.escapeHtml(text); }
3194
+ }
3195
+ return Utils.escapeHtml(text);
3196
+ }
3197
+ // Schedule cooperative tail promotion (async) to avoid blocking UI on each chunk.
3198
+ schedulePromoteTail(force = false) {
3199
+ if (!this.activeCode || !this.activeCode.tailEl) return;
3200
+ if (this._promoteScheduled) return;
3201
+ this._promoteScheduled = true;
3202
+ this.raf.schedule('SE:promoteTail', () => {
3203
+ this._promoteScheduled = false;
3204
+ this._promoteTailWork(force);
3205
+ }, 'StreamEngine', 1);
3206
+ }
3207
+ // Move a full-line part of tail into frozen region (with highlight if budgets allow).
3208
+ async _promoteTailWork(force = false) {
3209
+ if (!this.activeCode || !this.activeCode.tailEl) return;
3210
+
3211
+ // If plain streaming mode is on, or incremental hljs is disabled, promote as plain text only.
3212
+ const now = Utils.now(); const prof = this.cfg.PROFILE_CODE;
3213
+ const tailText0 = this.activeCode.tailEl.textContent || ''; if (!tailText0) return;
3214
+
3215
+ if (!force) {
3216
+ if ((now - this.activeCode.lastPromoteTs) < prof.promoteMinInterval) return;
3217
+ const enoughLines = (this.activeCode.linesSincePromote || 0) >= (prof.promoteMinLines || 10);
3218
+ const enoughChars = tailText0.length >= prof.minCharsForHL;
3219
+ if (!enoughLines && !enoughChars) return;
3220
+ }
3221
+
3222
+ // Cut at last full line to avoid moving partial tokens
3223
+ const idx = tailText0.lastIndexOf('\n');
3224
+ if (idx <= -1 && !force) return;
3225
+ const cut = (idx >= 0) ? (idx + 1) : tailText0.length;
3226
+ const delta = tailText0.slice(0, cut); if (!delta) return;
3227
+
3228
+ // Re-evaluate budgets before performing any heavy work
3229
+ this.enforceHLStopBudget();
3230
+ const usePlain = this.activeCode.haltHL || this.activeCode.plainStream || !this._isHLJSSupported(this.activeCode.lang);
3231
+
3232
+ // Cooperative rAF yield before heavy highlight
3233
+ if (!usePlain) await this.asyncer.yield();
3234
+
3235
+ // If tail changed since we captured it, validate prefix to avoid duplication
3236
+ if (!this.activeCode || !this.activeCode.tailEl) return;
3237
+ const tailNow = this.activeCode.tailEl.textContent || '';
3238
+ if (!tailNow.startsWith(delta)) {
3239
+ // New data arrived; reschedule for next frame without touching DOM
3240
+ this.schedulePromoteTail(false);
3241
+ return;
3242
+ }
3243
+
3244
+ // Apply DOM updates: either highlighted HTML delta or plain text
3245
+ if (usePlain) {
3246
+ // Plain text promotion – extremely cheap, no spans created.
3247
+ this.activeCode.frozenEl.insertAdjacentText('beforeend', delta);
3248
+ } else {
3249
+ // Highlighted promotion – still capped by budgets above.
3250
+ let html = Utils.escapeHtml(delta);
3251
+ try { html = this.highlightDeltaText(this.activeCode.lang, delta); } catch (_) { html = Utils.escapeHtml(delta); }
3252
+ this.activeCode.frozenEl.insertAdjacentHTML('beforeend', html);
3253
+ }
3254
+
3255
+ // Update tail and counters
3256
+ this.activeCode.tailEl.textContent = tailNow.slice(delta.length);
3257
+ this.activeCode.frozenLen += delta.length;
3258
+ const promotedLines = Utils.countNewlines(delta);
3259
+ this.activeCode.tailLines = Math.max(0, (this.activeCode.tailLines || 0) - promotedLines);
3260
+ this.activeCode.linesSincePromote = Math.max(0, (this.activeCode.linesSincePromote || 0) - promotedLines);
3261
+ this.activeCode.lastPromoteTs = Utils.now();
3262
+ this.codeScroll.scheduleScroll(this.activeCode.codeEl, true, false);
3263
+ this._d(usePlain ? 'TAIL_PROMOTE_PLAIN' : 'TAIL_PROMOTE_ASYNC', { cut, promotedLines, lang: this.activeCode.lang, plain: usePlain });
3264
+ }
3265
+ // Finalize the current active code block. Keep it plain for now and schedule highlight lazily.
3266
+ finalizeActiveCode() {
3267
+ if (!this.activeCode) return;
3268
+ const codeEl = this.activeCode.codeEl;
3269
+ const fromBottomBefore = Math.max(0, codeEl.scrollHeight - codeEl.clientHeight - codeEl.scrollTop);
3270
+ const wasNearBottom = this.codeScroll.isNearBottomEl(codeEl, this.cfg.CODE_SCROLL.NEAR_MARGIN_PX);
3271
+ const fullText = (this.activeCode.frozenEl.textContent || '') + (this.activeCode.tailEl.textContent || '');
3272
+
3273
+ // Non-blocking finalize: place plain text now, schedule highlight via Highlighter later.
3274
+ try {
3275
+ codeEl.innerHTML = '';
3276
+ codeEl.textContent = fullText;
3277
+ codeEl.classList.add('hljs'); // keep visual parity until highlight applies
3278
+ codeEl.removeAttribute('data-highlighted');
3279
+ } catch (_) {}
3280
+
3281
+ const st = this.codeScroll.state(codeEl); st.autoFollow = false;
3282
+ const maxScrollTop = Math.max(0, codeEl.scrollHeight - codeEl.clientHeight);
3283
+ const target = wasNearBottom ? maxScrollTop : Math.max(0, maxScrollTop - fromBottomBefore);
3284
+ try { codeEl.scrollTop = target; } catch (_) {}
3285
+ st.lastScrollTop = codeEl.scrollTop;
3286
+ codeEl.dataset._active_stream = '0';
3287
+
3288
+ try { codeEl.dataset.justFinalized = '1'; } catch (_) {}
3289
+ this.codeScroll.scheduleScroll(codeEl, false, true);
3290
+
3291
+ // Schedule async highlight on the finalized element (viewport-aware).
3292
+ try { if (!this.cfg.HL.DISABLE_ALL) this.highlighter.queue(codeEl, null); } catch (_) {}
3293
+
3294
+ this.suppressPostFinalizePass = true;
3295
+
3296
+ this._d('FINALIZE_CODE_NONBLOCK', { lang: this.activeCode.lang, len: fullText.length, highlighted: false });
3297
+ this.activeCode = null;
3298
+ }
3299
+ // Make a simple fingerprint to reuse identical closed code blocks between snapshots.
3300
+ codeFingerprint(codeEl) {
3301
+ const cls = Array.from(codeEl.classList).find(c => c.startsWith('language-')) || 'language-plaintext';
3302
+ const lang = cls.replace('language-', '') || 'plaintext';
3303
+ const t = codeEl.textContent || ''; const len = t.length; const head = t.slice(0, 64); const tail = t.slice(-64);
3304
+ return `${lang}|${len}|${head}|${tail}`;
3305
+ }
3306
+ // fingerprint using precomputed meta on wrapper (avoids .textContent for heavy blocks).
3307
+ codeFingerprintFromWrapper(codeEl) {
3308
+ try {
3309
+ const wrap = codeEl.closest('.code-wrapper'); if (!wrap) return null;
3310
+ const cls = Array.from(codeEl.classList).find(c => c.startsWith('language-')) || 'language-plaintext';
3311
+ const lang = (cls.replace('language-', '') || 'plaintext');
3312
+ const len = wrap.getAttribute('data-code-len') || '';
3313
+ const head = wrap.getAttribute('data-code-head') || '';
3314
+ const tail = wrap.getAttribute('data-code-tail') || '';
3315
+ if (!len) return null; // ensure at least length exists
3316
+ return `${lang}|${len}|${head}|${tail}`;
3317
+ } catch (_) {
3318
+ return null;
3319
+ }
3320
+ }
3321
+ // Try to reuse old finalized code block DOM nodes to avoid re-highlighting.
3322
+ preserveStableClosedCodes(oldSnap, newRoot, skipLastIfStreaming) {
3323
+ try {
3324
+ const oldCodes = Array.from(oldSnap.querySelectorAll('pre code')); if (!oldCodes.length) return;
3325
+ // Safety guard: avoid heavy fingerprint work on extremely large outputs
3326
+ const newCodesPre = Array.from(newRoot.querySelectorAll('pre code'));
3327
+ if (newCodesPre.length > this.cfg.STREAM.PRESERVE_CODES_MAX || oldCodes.length > this.cfg.STREAM.PRESERVE_CODES_MAX) return;
3328
+
3329
+ const map = new Map();
3330
+ for (const el of oldCodes) {
3331
+ if (el.querySelector('.hl-frozen')) continue; // skip streaming blocks
3332
+ if (this.activeCode && el === this.activeCode.codeEl) continue;
3333
+ // Try wrapper-based fingerprint first, fallback to text-based
3334
+ let fp = this.codeFingerprintFromWrapper(el);
3335
+ if (!fp) fp = el.dataset.fp || (el.dataset.fp = this.codeFingerprint(el));
3336
+ const arr = map.get(fp) || []; arr.push(el); map.set(fp, arr);
3337
+ }
3338
+ const newCodes = newCodesPre;
3339
+ const end = (skipLastIfStreaming && newCodes.length > 0) ? (newCodes.length - 1) : newCodes.length;
3340
+ let reuseCount = 0;
3341
+ for (let i = 0; i < end; i++) {
3342
+ const nc = newCodes[i];
3343
+ if (nc.getAttribute('data-highlighted') === 'yes') continue;
3344
+ // Fingerprint new code: prefer wrapper meta (no .textContent read)
3345
+ let fp = this.codeFingerprintFromWrapper(nc);
3346
+ if (!fp) fp = this.codeFingerprint(nc);
3347
+ const arr = map.get(fp);
3348
+ if (arr && arr.length) {
3349
+ const oldEl = arr.shift();
3350
+ if (oldEl && oldEl.isConnected) {
3351
+ try {
3352
+ nc.replaceWith(oldEl);
3353
+ this.codeScroll.attachHandlers(oldEl);
3354
+ // Preserve whatever final state the old element had
3355
+ if (!oldEl.getAttribute('data-highlighted')) oldEl.setAttribute('data-highlighted', 'yes');
3356
+ const st = this.codeScroll.state(oldEl); st.autoFollow = false;
3357
+ reuseCount++;
3358
+ } catch (_) {}
3359
+ }
3360
+ if (!arr.length) map.delete(fp);
3361
+ }
3362
+ }
3363
+ if (reuseCount) this._d('PRESERVE_CODES_REUSED', { reuseCount, skipLastIfStreaming });
3364
+ } catch (e) {
3365
+ this._d('PRESERVE_CODES_ERROR', String(e));
3366
+ }
3367
+ }
3368
+ // Ensure blocks marked as just-finalized are scrolled to bottom.
3369
+ _ensureBottomForJustFinalized(root) {
3370
+ try {
3371
+ const scope = root || document;
3372
+ const nodes = scope.querySelectorAll('pre code[data-just-finalized="1"]');
3373
+ if (!nodes || !nodes.length) return;
3374
+ nodes.forEach((codeEl) => {
3375
+ this.codeScroll.scheduleScroll(codeEl, false, true);
3376
+ const key = { t: 'JF:forceBottom', el: codeEl, n: Math.random() };
3377
+ this.raf.schedule(key, () => {
3378
+ this.codeScroll.scrollToBottom(codeEl, false, true);
3379
+ try { codeEl.dataset.justFinalized = '0'; } catch (_) {}
3380
+ }, 'CodeScroll', 2);
3381
+ });
3382
+ } catch (_) {}
3383
+ }
3384
+ // If stream is visible but something got stuck, force a quick refresh.
3385
+ kickVisibility() {
3386
+ const msg = this.getMsg(false, '');
3387
+ if (!msg) return;
3388
+ if (this.codeStream.open && !this.activeCode) {
3389
+ this.scheduleSnapshot(msg, true);
3390
+ return;
3391
+ }
3392
+ const needSnap = (this.getStreamLength() !== (window.__lastSnapshotLen || 0));
3393
+ if (needSnap) this.scheduleSnapshot(msg, true);
3394
+ if (this.activeCode && this.activeCode.codeEl) {
3395
+ this.codeScroll.scheduleScroll(this.activeCode.codeEl, true, false);
3396
+ this.schedulePromoteTail(true);
3397
+ }
3398
+ }
3399
+ // Render a snapshot of current stream buffer into the DOM.
3400
+ renderSnapshot(msg) {
3401
+ const streaming = !!this.isStreaming;
3402
+ const snap = this.getMsgSnapshotRoot(msg); if (!snap) return;
3403
+
3404
+ // No-op if nothing changed and no active code
3405
+ const prevLen = (window.__lastSnapshotLen || 0);
3406
+ const curLen = this.getStreamLength();
3407
+ if (!this.fenceOpen && !this.activeCode && curLen === prevLen) {
3408
+ this.lastSnapshotTs = Utils.now();
3409
+ this._d('SNAPSHOT_SKIPPED_NO_DELTA', { bufLen: curLen });
3410
+ return;
3411
+ }
3412
+
3413
+ const t0 = Utils.now();
3414
+
3415
+ // Slightly adjusted: when fence is open we append '\n' to ensure stable fence-close detection
3416
+ const allText = this.getStreamText();
3417
+ const src = this.fenceOpen ? (allText + '\n') : allText;
3418
+
3419
+ // Use streaming renderer (no linkify) on hot path to reduce CPU/allocs
3420
+ const html = streaming ? this.renderer.renderStreamingSnapshot(src) : this.renderer.renderFinalSnapshot(src);
3421
+
3422
+ // parse HTML into a DocumentFragment directly to avoid intermediate container allocations.
3423
+ let frag = null;
3424
+ try {
3425
+ const range = document.createRange();
3426
+ range.selectNodeContents(snap);
3427
+ frag = range.createContextualFragment(html);
3428
+ } catch (_) {
3429
+ // Fallback: safe temporary container
3430
+ const tmp = document.createElement('div');
3431
+ tmp.innerHTML = html;
3432
+ frag = document.createDocumentFragment();
3433
+ while (tmp.firstChild) frag.appendChild(tmp.firstChild);
3434
+ }
3435
+
3436
+ // Reuse closed, stable code blocks from previous snapshot to avoid re-highlighting
3437
+ this.preserveStableClosedCodes(snap, frag, this.fenceOpen === true);
3438
+
3439
+ // Replace content
3440
+ snap.replaceChildren(frag);
3441
+
3442
+ // Restore code UI state and ensure bottoming for freshly finalized elements
3443
+ this.renderer.restoreCollapsedCode(snap);
3444
+ this._ensureBottomForJustFinalized(snap);
3445
+
3446
+ // Setup active streaming code if fence is open, otherwise clear active state
3447
+ if (this.fenceOpen) {
3448
+ const newAC = this.setupActiveCodeFromSnapshot(snap);
3449
+ this.activeCode = newAC || null;
3450
+ } else {
3451
+ this.activeCode = null;
3452
+ }
3453
+
3454
+ // Attach scroll/highlight observers (viewport aware)
3455
+ if (!this.fenceOpen) {
3456
+ this.codeScroll.initScrollableBlocks(snap);
3457
+ }
3458
+ this.highlighter.observeNewCode(snap, {
3459
+ deferLastIfStreaming: true,
3460
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
3461
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
3462
+ }, this.activeCode);
3463
+ this.highlighter.observeMsgBoxes(snap, (box) => {
3464
+ this.highlighter.observeNewCode(box, {
3465
+ deferLastIfStreaming: true,
3466
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
3467
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
3468
+ }, this.activeCode);
3469
+ this.codeScroll.initScrollableBlocks(box);
3470
+ });
3471
+
3472
+ // Schedule math render according to mode; keep "finalize-only" cheap on hot path
3473
+ const mm = getMathMode();
3474
+ if (!this.suppressPostFinalizePass) {
3475
+ if (mm === 'idle') this.math.schedule(snap);
3476
+ else if (mm === 'always') this.math.schedule(snap, 0, true);
3477
+ }
3478
+
3479
+ // If streaming code is visible, keep it glued to bottom
3480
+ if (this.fenceOpen && this.activeCode && this.activeCode.codeEl) {
3481
+ this.codeScroll.attachHandlers(this.activeCode.codeEl);
3482
+ this.codeScroll.scheduleScroll(this.activeCode.codeEl, true, false);
3483
+ } else if (!this.fenceOpen) {
3484
+ this.codeScroll.initScrollableBlocks(snap);
3485
+ }
3486
+
3487
+ // Advance snapshot budget and remember progress
3488
+ window.__lastSnapshotLen = this.getStreamLength();
3489
+ this.lastSnapshotTs = Utils.now();
3490
+
3491
+ const prof = this.profile();
3492
+ if (prof.adaptiveStep) {
3493
+ const maxStep = this.cfg.STREAM.SNAPSHOT_MAX_STEP || 8000;
3494
+ this.nextSnapshotStep = Math.min(Math.ceil(this.nextSnapshotStep * prof.growth), maxStep);
3495
+ } else {
3496
+ this.nextSnapshotStep = prof.base;
3497
+ }
3498
+
3499
+ // Keep page scroll/fab in sync
3500
+ this.scrollMgr.scheduleScroll(true);
3501
+ this.scrollMgr.fabFreezeUntil = Utils.now() + this.cfg.FAB.TOGGLE_DEBOUNCE_MS;
3502
+ this.scrollMgr.scheduleScrollFabUpdate();
3503
+
3504
+ if (this.suppressPostFinalizePass) this.suppressPostFinalizePass = false;
3505
+
3506
+ const dt = Utils.now() - t0;
3507
+ this._d('SNAPSHOT', { fenceOpen: this.fenceOpen, activeCode: !!this.activeCode, bufLen: this.getStreamLength(), timeMs: Math.round(dt), streaming });
3508
+ }
3509
+ // Get current message container (.msg) or create if allowed.
3510
+ getMsg(create, name_header) { return this.dom.getStreamMsg(create, name_header); }
3511
+ // Start a new streaming session (clear state and display loader, if any).
3512
+ beginStream(chunk = false) {
3513
+ this.isStreaming = true; // engage streaming mode (no linkify etc.)
3514
+ if (chunk) runtime.loading.hide();
3515
+ this.scrollMgr.userInteracted = false;
3516
+ this.dom.clearOutput();
3517
+ this.reset();
3518
+ this.scrollMgr.forceScrollToBottomImmediate();
3519
+ this.scrollMgr.scheduleScroll();
3520
+ this._d('BEGIN_STREAM', { chunkFlag: !!chunk });
3521
+ }
3522
+ // End streaming session, finalize active code if present, and complete math/highlight.
3523
+ endStream() {
3524
+ // Switch to final mode before the last snapshot to allow full renderer (linkify etc.)
3525
+ this.isStreaming = false;
3526
+
3527
+ const msg = this.getMsg(false, '');
3528
+ if (msg) this.renderSnapshot(msg);
3529
+
3530
+ this.snapshotScheduled = false;
3531
+ try { this.raf.cancel('SE:snapshot'); } catch (_) {}
3532
+ this.snapshotRAF = 0;
3533
+
3534
+ const hadActive = !!this.activeCode;
3535
+ if (this.activeCode) this.finalizeActiveCode();
3536
+
3537
+ if (!hadActive) {
3538
+ if (this.highlighter.hlQueue && this.highlighter.hlQueue.length) {
3539
+ this.highlighter.flush(this.activeCode);
3540
+ }
3541
+ const snap = msg ? this.getMsgSnapshotRoot(msg) : null;
3542
+ if (snap) this.math.renderAsync(snap); // ensure math completes eagerly but async
3543
+ }
3544
+
3545
+ this.fenceOpen = false; this.codeStream.open = false; this.activeCode = null; this.lastSnapshotTs = Utils.now();
3546
+ this.suppressPostFinalizePass = false;
3547
+ this._d('END_STREAM', { hadActive });
3548
+ }
3549
+ // Apply incoming chunk to stream buffer and update DOM when needed.
3550
+ applyStream(name_header, chunk, alreadyBuffered = false) {
3551
+ if (!this.activeCode && !this.fenceOpen) {
3552
+ try { if (document.querySelector('pre code[data-_active_stream="1"]')) this.defuseOrphanActiveBlocks(); } catch (_) {}
3553
+ }
3554
+ if (this.snapshotScheduled && !this.raf.isScheduled('SE:snapshot')) this.snapshotScheduled = false;
3555
+
3556
+ const msg = this.getMsg(true, name_header); if (!msg || !chunk) return;
3557
+ const s = String(chunk);
3558
+ if (!alreadyBuffered) this._appendChunk(s);
3559
+
3560
+ const change = this.updateFenceHeuristic(s);
3561
+ const nlCount = Utils.countNewlines(s); const chunkHasNL = nlCount > 0;
3562
+
3563
+ this._d('APPLY_CHUNK', { len: s.length, nl: nlCount, opened: change.opened, closed: change.closed, splitAt: change.splitAt, fenceOpenBefore: this.fenceOpen || false, codeOpenBefore: this.codeStream.open || false, rebroadcast: !!alreadyBuffered });
3564
+
3565
+ // Track if we just materialized the first code-open snapshot synchronously.
3566
+ let didImmediateOpenSnap = false;
3567
+
3568
+ if (change.opened) {
3569
+ this.codeStream.open = true; this.codeStream.lines = 0; this.codeStream.chars = 0;
3570
+ this.resetBudget();
3571
+ this.scheduleSnapshot(msg);
3572
+ this._d('CODE_STREAM_OPEN', { });
3573
+
3574
+ // Fast-path: if stream starts with a code fence and no snapshot was made yet,
3575
+ // immediately materialize the code block so tail streaming can proceed without click.
3576
+ if (!this._firstCodeOpenSnapDone && !this.activeCode && ((window.__lastSnapshotLen || 0) === 0)) {
3577
+ try {
3578
+ this.renderSnapshot(msg);
3579
+ try { this.raf.cancel('SE:snapshot'); } catch (_) {}
3580
+ this.snapshotScheduled = false;
3581
+ this._firstCodeOpenSnapDone = true;
3582
+ didImmediateOpenSnap = true;
3583
+ this._d('CODE_OPEN_IMMEDIATE_SNAPSHOT', { bufLen: this.getStreamLength() });
3584
+ } catch (_) {
3585
+ // Keep going; normal scheduled snapshot will land soon.
3586
+ }
3587
+ }
3588
+ }
3589
+
3590
+ if (this.codeStream.open) {
3591
+ this.codeStream.lines += nlCount; this.codeStream.chars += s.length;
3592
+
3593
+ if (this.activeCode && this.activeCode.codeEl && this.activeCode.codeEl.isConnected) {
3594
+ let partForCode = s; let remainder = '';
3595
+
3596
+ if (didImmediateOpenSnap) {
3597
+ partForCode = '';
3598
+ } else {
3599
+ if (change.closed && change.splitAt >= 0 && change.splitAt <= s.length) {
3600
+ partForCode = s.slice(0, change.splitAt); remainder = s.slice(change.splitAt);
3601
+ }
3602
+ }
3603
+
3604
+ if (partForCode) {
3605
+ this.appendToActiveTail(partForCode);
3606
+ this.activeCode.lines += Utils.countNewlines(partForCode);
3607
+
3608
+ this.maybePromoteLanguageFromDirective();
3609
+ this.enforceHLStopBudget();
3610
+
3611
+ if (!this.activeCode.haltHL) {
3612
+ if (partForCode.indexOf('\n') >= 0 || (this.activeCode.tailEl.textContent || '').length >= this.cfg.PROFILE_CODE.minCharsForHL) {
3613
+ this.schedulePromoteTail(false);
3614
+ }
3615
+ }
3616
+ }
3617
+ this.scrollMgr.scrollFabUpdateScheduled = false;
3618
+ this.scrollMgr.scheduleScroll(true);
3619
+ this.scrollMgr.fabFreezeUntil = Utils.now() + this.cfg.FAB.TOGGLE_DEBOUNCE_MS;
3620
+ this.scrollMgr.scheduleScrollFabUpdate();
3621
+
3622
+ if (change.closed) {
3623
+ this.finalizeActiveCode();
3624
+ this.codeStream.open = false; this.resetBudget(); this.scheduleSnapshot(msg);
3625
+ this._d('CODE_STREAM_CLOSE_FINALIZED', { remainderLen: remainder.length });
3626
+ if (remainder && remainder.length) { this.applyStream(name_header, remainder, true); }
3627
+ }
3628
+ return;
3629
+ } else {
3630
+ if (!this.activeCode && (this.codeStream.lines >= 2 || this.codeStream.chars >= 80)) {
3631
+ this.scheduleSnapshot(msg, true);
3632
+ return;
3633
+ }
3634
+ if (change.closed) {
3635
+ this.codeStream.open = false; this.resetBudget(); this.scheduleSnapshot(msg);
3636
+ this._d('CODE_CLOSED_WITHOUT_ACTIVE', { sinceLastSnapMs: Math.round(Utils.now() - this.lastSnapshotTs), snapshotScheduled: this.snapshotScheduled });
3637
+ } else {
3638
+ const boundary = this.hasStructuralBoundary(s);
3639
+ if (this.shouldSnapshotOnChunk(s, chunkHasNL, boundary)) this.scheduleSnapshot(msg);
3640
+ else this.maybeScheduleSoftSnapshot(msg, chunkHasNL);
3641
+ }
3642
+ return;
3643
+ }
3644
+ }
3645
+
3646
+ if (change.closed) {
3647
+ this.codeStream.open = false; this.resetBudget(); this.scheduleSnapshot(msg);
3648
+ this._d('CODE_STREAM_CLOSE', { });
3649
+ } else {
3650
+ const boundary = this.hasStructuralBoundary(s);
3651
+ if (this.shouldSnapshotOnChunk(s, chunkHasNL, boundary)) {
3652
+ this.scheduleSnapshot(msg);
3653
+ this._d('SCHEDULE_SNAPSHOT_BOUNDARY', { boundary });
3654
+ } else {
3655
+ this.maybeScheduleSoftSnapshot(msg, chunkHasNL);
3656
+ }
3657
+ }
3658
+ }
3659
+ }
3660
+
3661
+ // ==========================================================================
3662
+ // 12) Stream queue
3663
+ // ==========================================================================
3664
+
3665
+ class StreamQueue {
3666
+ constructor(cfg, engine, scrollMgr, raf) {
3667
+ this.cfg = cfg; this.engine = engine; this.scrollMgr = scrollMgr; this.raf = raf;
3668
+ this.q = []; this.drainScheduled = false;
3669
+ this.batching = false; this.needScroll = false;
3670
+ }
3671
+ // Coalesce contiguous entries for the same header to reduce overhead.
3672
+ _compactContiguousSameName() {
3673
+ // Coalesce contiguous entries for the same message header to reduce string objects count.
3674
+ if (this.q.length < 2) return;
3675
+ const out = [];
3676
+ let last = this.q[0];
3677
+ for (let i = 1; i < this.q.length; i++) {
3678
+ const cur = this.q[i];
3679
+ if (cur.name_header === last.name_header) {
3680
+ // Merge payloads; reduce object overhead without changing semantics
3681
+ last.chunk = (last.chunk || '') + (cur.chunk || '');
3682
+ }
3683
+ else {
3684
+ out.push(last);
3685
+ last = cur;
3686
+ }
3687
+ }
3688
+ out.push(last);
3689
+ this.q = out;
3690
+ }
3691
+ // Push new chunk into the queue and schedule drain.
3692
+ enqueue(name_header, chunk) {
3693
+ this.q.push({ name_header, chunk });
3694
+ // Guard against unbounded growth during bursts
3695
+ if (this.q.length > this.cfg.STREAM.EMERGENCY_COALESCE_LEN) this._compactContiguousSameName();
3696
+ if (this.q.length > this.cfg.STREAM.QUEUE_MAX_ITEMS) this._compactContiguousSameName();
3697
+ if (!this.drainScheduled) {
3698
+ this.drainScheduled = true;
3699
+ this.raf.schedule('SQ:drain', () => this.drain(), 'StreamQueue', 0);
3700
+ }
3701
+ }
3702
+ // Drain a limited number of chunks per frame (adaptive if configured).
3703
+ drain() {
3704
+ this.drainScheduled = false; let processed = 0;
3705
+ const adaptive = (this.cfg.STREAM.COALESCE_MODE === 'adaptive');
3706
+ const coalesceAggressive = adaptive && (this.q.length >= this.cfg.STREAM.EMERGENCY_COALESCE_LEN);
3707
+
3708
+ // Adaptive per-frame budget: increase throughput if queue is long
3709
+ const basePerFrame = this.cfg.STREAM.MAX_PER_FRAME | 0;
3710
+ const perFrame = adaptive ? Math.min(basePerFrame + Math.floor(this.q.length / 20), basePerFrame * 4) : basePerFrame;
3711
+
3712
+ this.batching = true;
3713
+ while (this.q.length && processed < perFrame) {
3714
+ let { name_header, chunk } = this.q.shift();
3715
+ if (chunk && chunk.length > 0) {
3716
+ const chunks = [chunk];
3717
+ while (this.q.length) {
3718
+ const next = this.q[0];
3719
+ if (next.name_header === name_header) {
3720
+ chunks.push(next.chunk); this.q.shift();
3721
+ if (!coalesceAggressive) break;
3722
+ } else break;
3723
+ }
3724
+ chunk = chunks.join('');
3725
+ }
3726
+ this.engine.applyStream(name_header, chunk);
3727
+ processed++;
3728
+ }
3729
+ this.batching = false;
3730
+ if (this.needScroll) { this.scrollMgr.scheduleScroll(true); this.needScroll = false; }
3731
+ if (this.q.length) {
3732
+ this.drainScheduled = true;
3733
+ this.raf.schedule('SQ:drain', () => this.drain(), 'StreamQueue', 0);
3734
+ }
3735
+ }
3736
+ // Force a drain soon.
3737
+ kick() {
3738
+ if (this.q.length || this.drainScheduled) {
3739
+ this.drainScheduled = true;
3740
+ this.raf.schedule('SQ:drain', () => this.drain(), 'StreamQueue', 0);
3741
+ }
3742
+ }
3743
+ // Clear queued work and cancel scheduled drains.
3744
+ clear() {
3745
+ this.q.length = 0;
3746
+ try { this.raf.cancelGroup('StreamQueue'); } catch (_) {}
3747
+ this.drainScheduled = false;
3748
+ }
3749
+ }
3750
+
3751
+ // ==========================================================================
3752
+ // 13) Bridge manager (QWebChannel)
3753
+ // ==========================================================================
3754
+
3755
+ class BridgeManager {
3756
+ constructor(cfg, logger) {
3757
+ this.cfg = cfg; this.logger = logger || new Logger(cfg);
3758
+ this.bridge = null; this.connected = false;
3759
+ }
3760
+ // Low-level log via bridge if available.
3761
+ log(text) { try { if (this.bridge && this.bridge.log) this.bridge.log(text); } catch (_) {} }
3762
+ // Wire JS callbacks to QWebChannel signals.
3763
+ connect(onChunk, onNode, onNodeReplace, onNodeInput) {
3764
+ if (!this.bridge) return false; if (this.connected) return true;
3765
+ try {
3766
+ if (this.bridge.chunk) this.bridge.chunk.connect(onChunk);
3767
+ if (this.bridge.node) this.bridge.node.connect(onNode);
3768
+ if (this.bridge.nodeReplace) this.bridge.nodeReplace.connect(onNodeReplace);
3769
+ if (this.bridge.nodeInput) this.bridge.nodeInput.connect(onNodeInput);
3770
+ this.connected = true; return true;
3771
+ } catch (e) { this.log(e); return false; }
3772
+ }
3773
+ // Detach callbacks.
3774
+ disconnect() {
3775
+ if (!this.bridge) return false; if (!this.connected) return true;
3776
+ try {
3777
+ if (this.bridge.chunk) this.bridge.chunk.disconnect();
3778
+ if (this.bridge.node) this.bridge.node.disconnect();
3779
+ if (this.bridge.nodeReplace) this.bridge.nodeReplace.disconnect();
3780
+ if (this.bridge.nodeInput) this.bridge.nodeInput.disconnect();
3781
+ } catch (_) {}
3782
+ this.connected = false; return true;
3783
+ }
3784
+ // Initialize QWebChannel and notify Python side that JS is ready.
3785
+ initQWebChannel(pid, onReady) {
3786
+ try {
3787
+ new QWebChannel(qt.webChannelTransport, (channel) => {
3788
+ this.bridge = channel.objects.bridge;
3789
+ try { this.logger.bindBridge(this.bridge); } catch (_) {}
3790
+ onReady && onReady(this.bridge);
3791
+ if (this.bridge && this.bridge.js_ready) this.bridge.js_ready(pid);
3792
+ });
3793
+ } catch (e) { /* swallow: logger will flush when bridge arrives later */ }
3794
+ }
3795
+ // Convenience wrappers for host actions.
3796
+ copyCode(text) { if (this.bridge && this.bridge.copy_text) this.bridge.copy_text(text); }
3797
+ previewCode(text) { if (this.bridge && this.bridge.preview_text) this.bridge.preview_text(text); }
3798
+ runCode(text) { if (this.bridge && this.bridge.run_text) this.bridge.run_text(text); }
3799
+ updateScrollPosition(pos) { if (this.bridge && this.bridge.update_scroll_position) this.bridge.update_scroll_position(pos); }
3800
+ }
3801
+
3802
+ // ==========================================================================
3803
+ // 14) Loading indicator
3804
+ // ==========================================================================
3805
+
3806
+ class Loading {
3807
+ constructor(dom) { this.dom = dom; }
3808
+ // Show loader element (and hide tips if visible).
3809
+ show() { if (typeof window.hideTips === 'function') { window.hideTips(); } const el = this.dom.get('_loader_'); if (!el) return; if (el.classList.contains('hidden')) el.classList.remove('hidden'); el.classList.add('visible'); }
3810
+ // Hide loader element.
3811
+ hide() { const el = this.dom.get('_loader_'); if (!el) return; if (el.classList.contains('visible')) el.classList.remove('visible'); el.classList.add('hidden'); }
3812
+ }
3813
+
3814
+ // ==========================================================================
3815
+ // 15) Event manager
3816
+ // ==========================================================================
3817
+
3818
+ class EventManager {
3819
+ constructor(cfg, dom, scrollMgr, highlighter, codeScroll, toolOutput, bridge) {
3820
+ this.cfg = cfg; this.dom = dom; this.scrollMgr = scrollMgr; this.highlighter = highlighter;
3821
+ this.codeScroll = codeScroll; this.toolOutput = toolOutput; this.bridge = bridge;
3822
+ this.handlers = { wheel: null, scroll: null, resize: null, fabClick: null, mouseover: null, mouseout: null, click: null, keydown: null, docClickFocus: null, visibility: null, focus: null, pageshow: null };
3823
+ }
3824
+ _findWrapper(target) { if (!target || typeof target.closest !== 'function') return null; return target.closest('.code-wrapper'); }
3825
+ _getCodeEl(wrapper) { if (!wrapper) return null; return wrapper.querySelector('pre > code'); }
3826
+ _collectCodeText(codeEl) {
3827
+ if (!codeEl) return '';
3828
+ const frozen = codeEl.querySelector('.hl-frozen'); const tail = codeEl.querySelector('.hl-tail');
3829
+ if (frozen || tail) return (frozen?.textContent || '') + (tail?.textContent || '');
3830
+ return codeEl.textContent || '';
3831
+ }
3832
+ // Copy to clipboard via bridge if available, otherwise use browser APIs.
3833
+ async _copyTextRobust(text) {
3834
+ try { if (this.bridge && typeof this.bridge.copyCode === 'function') { this.bridge.copyCode(text); return true; } } catch (_) {}
3835
+ try { if (navigator && navigator.clipboard && navigator.clipboard.writeText) { await navigator.clipboard.writeText(text); return true; } } catch (_) {}
3836
+ try {
3837
+ const ta = document.createElement('textarea');
3838
+ ta.value = text; ta.setAttribute('readonly', ''); ta.style.position = 'fixed'; ta.style.top = '-9999px'; ta.style.opacity = '0';
3839
+ document.body.appendChild(ta); ta.select(); const ok = document.execCommand && document.execCommand('copy'); document.body.removeChild(ta); return !!ok;
3840
+ } catch (_) { return false; }
3841
+ }
3842
+ // Flash "Copied" feedback on the copy button.
3843
+ _flashCopied(btn, wrapper) {
3844
+ if (!btn || !wrapper) return;
3845
+ const span = btn.querySelector('span'); if (!span) return;
3846
+ const L_COPY = wrapper.getAttribute('data-locale-copy') || 'Copy';
3847
+ const L_COPIED = wrapper.getAttribute('data-locale-copied') || 'Copied';
3848
+ try { if (btn.__copyTimer) { clearTimeout(btn.__copyTimer); btn.__copyTimer = 0; } } catch (_) {}
3849
+ span.textContent = L_COPIED; btn.classList.add('copied');
3850
+ btn.__copyTimer = setTimeout(() => { try { span.textContent = L_COPY; btn.classList.remove('copied'); } catch (_) {} btn.__copyTimer = 0; }, 1200);
3851
+ }
3852
+ // Toggle code collapse/expand and remember collapsed indices.
3853
+ _toggleCollapse(wrapper) {
3854
+ if (!wrapper) return;
3855
+ const codeEl = this._getCodeEl(wrapper); if (!codeEl) return;
3856
+ const btn = wrapper.querySelector('.code-header-collapse');
3857
+ const span = btn ? btn.querySelector('span') : null;
3858
+ const L_COLLAPSE = wrapper.getAttribute('data-locale-collapse') || 'Collapse';
3859
+ const L_EXPAND = wrapper.getAttribute('data-locale-expand') || 'Expand';
3860
+ const idx = String(wrapper.getAttribute('data-index') || '');
3861
+ const arr = window.__collapsed_idx || (window.__collapsed_idx = []);
3862
+ const isHidden = (codeEl.style.display === 'none');
3863
+
3864
+ if (isHidden) {
3865
+ codeEl.style.display = 'block';
3866
+ if (span) span.textContent = L_COLLAPSE;
3867
+ const p = arr.indexOf(idx); if (p !== -1) arr.splice(p, 1);
3868
+ } else {
3869
+ codeEl.style.display = 'none';
3870
+ if (span) span.textContent = L_EXPAND;
3871
+ if (!arr.includes(idx)) arr.push(idx);
3872
+ }
3873
+ }
3874
+ // Attach global UI event handlers and container-level interactions.
3875
+ install() {
3876
+ try { history.scrollRestoration = "manual"; } catch (_) {}
3877
+
3878
+ this.handlers.keydown = (event) => {
3879
+ if (event.ctrlKey && event.key === 'f') { window.location.href = 'bridge://open_find:' + runtime.cfg.PID; event.preventDefault(); }
3880
+ if (event.key === 'Escape') { window.location.href = 'bridge://escape'; event.preventDefault(); }
3881
+ };
3882
+ document.addEventListener('keydown', this.handlers.keydown, { passive: false });
3883
+
3884
+ // Removed global click-to-focus navigation and visibility/focus wakeups to keep the pump rAF-only and click-agnostic.
3885
+
3886
+ const container = this.dom.get('container');
3887
+ const addClassToMsg = (id, className) => { const el = document.getElementById('msg-bot-' + id); if (el) el.classList.add(className); };
3888
+ const removeClassFromMsg = (id, className) => { const el = document.getElementById('msg-bot-' + id); if (el) el.classList.remove(className); };
3889
+
3890
+ this.handlers.mouseover = (event) => { if (event.target.classList.contains('action-img')) { const id = event.target.getAttribute('data-id'); addClassToMsg(id, 'msg-highlight'); } };
3891
+ this.handlers.mouseout = (event) => { if (event.target.classList.contains('action-img')) { const id = event.target.getAttribute('data-id'); const el = document.getElementById('msg-bot-' + id); if (el) el.classList.remove('msg-highlight'); } };
3892
+ if (container) {
3893
+ container.addEventListener('mouseover', this.handlers.mouseover, { passive: true });
3894
+ container.addEventListener('mouseout', this.handlers.mouseout, { passive: true });
3895
+ }
3896
+
3897
+ this.handlers.click = async (ev) => {
3898
+ const a = ev.target && (ev.target.closest ? ev.target.closest('a.code-header-action') : null);
3899
+ if (!a) return;
3900
+ const wrapper = this._findWrapper(a);
3901
+ if (!wrapper) return;
3902
+
3903
+ ev.preventDefault();
3904
+ ev.stopPropagation();
3905
+
3906
+ const isCopy = a.classList.contains('code-header-copy');
3907
+ const isCollapse = a.classList.contains('code-header-collapse');
3908
+ const isRun = a.classList.contains('code-header-run');
3909
+ const isPreview = a.classList.contains('code-header-preview');
3910
+
3911
+ let codeEl = null, text = '';
3912
+ if (isCopy || isRun || isPreview) {
3913
+ codeEl = this._getCodeEl(wrapper);
3914
+ text = this._collectCodeText(codeEl);
3915
+ }
3916
+
3917
+ try {
3918
+ if (isCopy) {
3919
+ const ok = await this._copyTextRobust(text);
3920
+ if (ok) this._flashCopied(a, wrapper);
3921
+ } else if (isCollapse) {
3922
+ this._toggleCollapse(wrapper);
3923
+ } else if (isRun) {
3924
+ if (this.bridge && typeof this.bridge.runCode === 'function') this.bridge.runCode(text);
3925
+ } else if (isPreview) {
3926
+ if (this.bridge && typeof this.bridge.previewCode === 'function') this.bridge.previewCode(text);
3927
+ }
3928
+ } catch (_) { /* swallow */ }
3929
+ };
3930
+ if (container) container.addEventListener('click', this.handlers.click, { passive: false });
3931
+
3932
+ this.handlers.wheel = (ev) => {
3933
+ runtime.scrollMgr.userInteracted = true;
3934
+ if (ev.deltaY < 0) runtime.scrollMgr.autoFollow = false;
3935
+ else runtime.scrollMgr.maybeEnableAutoFollowByProximity();
3936
+ this.highlighter.scheduleScanVisibleCodes(runtime.stream.activeCode);
3937
+ };
3938
+ document.addEventListener('wheel', this.handlers.wheel, { passive: true });
3939
+
3940
+ this.handlers.scroll = () => {
3941
+ const el = Utils.SE; const top = el.scrollTop;
3942
+ if (top + 1 < runtime.scrollMgr.lastScrollTop) runtime.scrollMgr.autoFollow = false;
3943
+ runtime.scrollMgr.maybeEnableAutoFollowByProximity();
3944
+ runtime.scrollMgr.lastScrollTop = top;
3945
+ const action = runtime.scrollMgr.computeFabAction();
3946
+ if (action !== runtime.scrollMgr.currentFabAction) runtime.scrollMgr.updateScrollFab(false, action, true);
3947
+ this.highlighter.scheduleScanVisibleCodes(runtime.stream.activeCode);
3948
+ };
3949
+ window.addEventListener('scroll', this.handlers.scroll, { passive: true });
3950
+
3951
+ const fab = this.dom.get('scrollFab');
3952
+ if (fab) {
3953
+ this.handlers.fabClick = (ev) => {
3954
+ ev.preventDefault(); ev.stopPropagation();
3955
+ const action = runtime.scrollMgr.computeFabAction();
3956
+ if (action === 'up') runtime.scrollMgr.scrollToTopUser();
3957
+ else if (action === 'down') runtime.scrollMgr.scrollToBottomUser();
3958
+ runtime.scrollMgr.fabFreezeUntil = Utils.now() + this.cfg.FAB.TOGGLE_DEBOUNCE_MS;
3959
+ runtime.scrollMgr.updateScrollFab(true);
3960
+ };
3961
+ fab.addEventListener('click', this.handlers.fabClick, { passive: false });
3962
+ }
3963
+
3964
+ this.handlers.resize = () => {
3965
+ runtime.scrollMgr.maybeEnableAutoFollowByProximity();
3966
+ runtime.scrollMgr.scheduleScrollFabUpdate();
3967
+ this.highlighter.scheduleScanVisibleCodes(runtime.stream.activeCode);
3968
+ };
3969
+ window.addEventListener('resize', this.handlers.resize, { passive: true });
3970
+
3971
+ // Note: visibility/focus/pageshow kickers removed intentionally.
3972
+ }
3973
+ // Detach all installed handlers and reset local refs.
3974
+ cleanup() {
3975
+ const container = this.dom.get('container');
3976
+ if (this.handlers.wheel) document.removeEventListener('wheel', this.handlers.wheel);
3977
+ if (this.handlers.scroll) window.removeEventListener('scroll', this.handlers.scroll);
3978
+ if (this.handlers.resize) window.removeEventListener('resize', this.handlers.resize);
3979
+ const fab = this.dom.get('scrollFab'); if (fab && this.handlers.fabClick) fab.removeEventListener('click', this.handlers.fabClick);
3980
+ if (container && this.handlers.mouseover) container.removeEventListener('mouseover', this.handlers.mouseover);
3981
+ if (container && this.handlers.mouseout) container.removeEventListener('mouseout', this.handlers.mouseout);
3982
+ if (container && this.handlers.click) container.removeEventListener('click', this.handlers.click);
3983
+ if (this.handlers.keydown) document.removeEventListener('keydown', this.handlers.keydown);
3984
+ if (this.handlers.docClickFocus) document.removeEventListener('click', this.handlers.docClickFocus);
3985
+ if (this.handlers.visibility) document.removeEventListener('visibilitychange', this.handlers.visibility);
3986
+ if (this.handlers.focus) window.removeEventListener('focus', this.handlers.focus);
3987
+ if (this.handlers.pageshow) window.removeEventListener('pageshow', this.handlers.pageshow);
3988
+ this.handlers = {};
3989
+ }
3990
+ }
3991
+
3992
+ // ==========================================================================
3993
+ // 16) Orchestrator runtime
3994
+ // ==========================================================================
3995
+
3996
+ class Runtime {
3997
+ constructor() {
3998
+ this.cfg = new Config();
3999
+ this.logger = new Logger(this.cfg);
4000
+
4001
+ this.dom = new DOMRefs();
4002
+ this.customMarkup = new CustomMarkup(this.cfg, this.logger);
4003
+ this.raf = new RafManager(this.cfg);
4004
+
4005
+ // Ensure logger uses central RafManager for its internal tick pump.
4006
+ try { this.logger.bindRaf(this.raf); } catch (_) {}
4007
+
4008
+ this.async = new AsyncRunner(this.cfg, this.raf);
4009
+ this.renderer = new MarkdownRenderer(this.cfg, this.customMarkup, this.logger, this.async, this.raf);
4010
+
4011
+ this.math = new MathRenderer(this.cfg, this.raf, this.async);
4012
+ this.codeScroll = new CodeScrollState(this.cfg, this.raf);
4013
+ this.highlighter = new Highlighter(this.cfg, this.codeScroll, this.raf);
4014
+ this.scrollMgr = new ScrollManager(this.cfg, this.dom, this.raf);
4015
+ this.toolOutput = new ToolOutput();
4016
+ this.loading = new Loading(this.dom);
4017
+ this.nodes = new NodesManager(this.dom, this.renderer, this.highlighter, this.math);
4018
+ this.bridge = new BridgeManager(this.cfg, this.logger);
4019
+ this.ui = new UIManager();
4020
+ this.stream = new StreamEngine(this.cfg, this.dom, this.renderer, this.math, this.highlighter, this.codeScroll, this.scrollMgr, this.raf, this.async, this.logger);
4021
+ this.streamQ = new StreamQueue(this.cfg, this.stream, this.scrollMgr, this.raf);
4022
+ this.events = new EventManager(this.cfg, this.dom, this.scrollMgr, this.highlighter, this.codeScroll, this.toolOutput, this.bridge);
4023
+
4024
+ this.tips = null;
4025
+ this._lastHeavyResetMs = 0;
4026
+
4027
+ // Bridge hooks between renderer and other subsystems.
4028
+ this.renderer.hooks.observeNewCode = (root, opts) => this.highlighter.observeNewCode(root, opts, this.stream.activeCode);
4029
+ this.renderer.hooks.observeMsgBoxes = (root) => this.highlighter.observeMsgBoxes(root, (box) => {
4030
+ this.highlighter.observeNewCode(box, {
4031
+ deferLastIfStreaming: true,
4032
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
4033
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
4034
+ }, this.stream.activeCode);
4035
+ this.codeScroll.initScrollableBlocks(box);
4036
+ });
4037
+ this.renderer.hooks.scheduleMathRender = (root) => {
4038
+ const mm = getMathMode();
4039
+ if (mm === 'idle') this.math.schedule(root);
4040
+ else if (mm === 'always') this.math.schedule(root, 0, true);
4041
+ };
4042
+ this.renderer.hooks.codeScrollInit = (root) => this.codeScroll.initScrollableBlocks(root);
4043
+ }
4044
+ // Reset stream state and optionally perform a heavy reset of schedulers and observers.
4045
+ resetStreamState(origin, opts) {
4046
+ try { this.streamQ.clear(); } catch (_) {}
4047
+
4048
+ const def = Object.assign({
4049
+ finalizeActive: true, clearBuffer: true, clearMsg: false, defuseOrphans: true, forceHeavy: false, reason: String(origin || 'external-op')
4050
+ }, (opts || {}));
4051
+
4052
+ const now = Utils.now();
4053
+ const withinDebounce = (now - (this._lastHeavyResetMs || 0)) <= (this.cfg.RESET.HEAVY_DEBOUNCE_MS || 24);
4054
+ const mustHeavyByOrigin =
4055
+ def.forceHeavy === true || def.clearMsg === true ||
4056
+ origin === 'beginStream' || origin === 'nextStream' ||
4057
+ origin === 'clearStream' || origin === 'replaceNodes' ||
4058
+ origin === 'clearNodes' || origin === 'clearOutput' ||
4059
+ origin === 'clearLive' || origin === 'clearInput';
4060
+ const shouldHeavy = mustHeavyByOrigin || !withinDebounce;
4061
+ const suppressLog = withinDebounce && origin !== 'beginStream';
4062
+
4063
+ try { this.stream.abortAndReset({ ...def, suppressLog }); } catch (_) {}
4064
+
4065
+ if (shouldHeavy) {
4066
+ try { this.highlighter.cleanup(); } catch (_) {}
4067
+ try { this.math.cleanup(); } catch (_) {}
4068
+ try { this.codeScroll.cancelAllScrolls(); } catch (_) {}
4069
+ try { this.scrollMgr.cancelPendingScroll(); } catch (_) {}
4070
+ try { this.raf.cancelAll(); } catch (_) {}
4071
+ this._lastHeavyResetMs = now;
4072
+ } else {
4073
+ try { this.raf.cancelGroup('StreamQueue'); } catch (_) {}
4074
+ }
4075
+
4076
+ try { this.tips && this.tips.hide(); } catch (_) {}
4077
+ }
4078
+ // API: begin stream.
4079
+ api_beginStream = (chunk = false) => { this.tips && this.tips.hide(); this.resetStreamState('beginStream', { clearMsg: true, finalizeActive: false, forceHeavy: true }); this.stream.beginStream(chunk); };
4080
+ // API: end stream.
4081
+ api_endStream = () => { this.stream.endStream(); };
4082
+ // API: apply chunk.
4083
+ api_applyStream = (name, chunk) => { this.stream.applyStream(name, chunk); };
4084
+ // API: enqueue chunk (drained on rAF).
4085
+ api_appendStream = (name, chunk) => { this.streamQ.enqueue(name, chunk); };
4086
+ // API: move current output to "before" area and prepare for next stream.
4087
+ api_nextStream = () => {
4088
+ this.tips && this.tips.hide();
4089
+ const element = this.dom.get('_append_output_'); const before = this.dom.get('_append_output_before_');
4090
+ if (element && before) {
4091
+ const frag = document.createDocumentFragment();
4092
+ while (element.firstChild) frag.appendChild(element.firstChild);
4093
+ before.appendChild(frag);
4094
+ }
4095
+ this.resetStreamState('nextStream', { clearMsg: true, finalizeActive: false, forceHeavy: true });
4096
+ this.scrollMgr.scheduleScroll();
4097
+ };
4098
+ // API: clear streaming output area entirely.
4099
+ api_clearStream = () => { this.tips && this.tips.hide(); this.resetStreamState('clearStream', { clearMsg: true, forceHeavy: true }); const el = this.dom.getStreamContainer(); if (!el) return; el.replaceChildren(); };
4100
+
4101
+ // API: append rendered nodes (messages).
4102
+ api_appendNode = (html) => { this.resetStreamState('appendNode'); this.nodes.appendNode(html, this.scrollMgr); };
4103
+ // API: replace messages list.
4104
+ api_replaceNodes = (html) => { this.resetStreamState('replaceNodes', { clearMsg: true, forceHeavy: true }); this.dom.clearNodes(); this.nodes.replaceNodes(html, this.scrollMgr); };
4105
+ // API: append to input area.
4106
+ api_appendToInput = (html) => { this.nodes.appendToInput(html); this.scrollMgr.userInteracted = false; this.scrollMgr.scheduleScroll(); this.resetStreamState('appendToInput'); };
4107
+
4108
+ // API: clear messages list.
4109
+ api_clearNodes = () => { this.dom.clearNodes(); this.resetStreamState('clearNodes', { clearMsg: true, forceHeavy: true }); };
4110
+ // API: clear input area.
4111
+ api_clearInput = () => { this.resetStreamState('clearInput', { forceHeavy: true }); this.dom.clearInput(); };
4112
+ // API: clear output area.
4113
+ api_clearOutput = () => { this.dom.clearOutput(); this.resetStreamState('clearOutput', { clearMsg: true, forceHeavy: true }); };
4114
+ // API: clear live area.
4115
+ api_clearLive = () => { this.dom.clearLive(); this.resetStreamState('clearLive', { forceHeavy: true }); };
4116
+
4117
+ // API: tool output helpers.
4118
+ api_appendToolOutput = (c) => this.toolOutput.append(c);
4119
+ api_updateToolOutput = (c) => this.toolOutput.update(c);
4120
+ api_clearToolOutput = () => this.toolOutput.clear();
4121
+ api_beginToolOutput = () => this.toolOutput.begin();
4122
+ api_endToolOutput = () => this.toolOutput.end();
4123
+ api_enableToolOutput = () => this.toolOutput.enable();
4124
+ api_disableToolOutput = () => this.toolOutput.disable();
4125
+ api_toggleToolOutput = (id) => this.toolOutput.toggle(id);
4126
+
4127
+ // API: append extra content to a bot message.
4128
+ api_appendExtra = (id, c) => this.nodes.appendExtra(id, c, this.scrollMgr);
4129
+ // API: remove one message by id.
4130
+ api_removeNode = (id) => this.nodes.removeNode(id, this.scrollMgr);
4131
+ // API: remove all messages starting from id.
4132
+ api_removeNodesFromId = (id) => this.nodes.removeNodesFromId(id, this.scrollMgr);
4133
+
4134
+ // API: replace live area content (with local post-processing).
4135
+ api_replaceLive = (content) => {
4136
+ const el = this.dom.get('_append_live_'); if (!el) return;
4137
+ if (el.classList.contains('hidden')) { el.classList.remove('hidden'); el.classList.add('visible'); }
4138
+ el.innerHTML = content;
4139
+
4140
+ try {
4141
+ const maybePromise = this.renderer.renderPendingMarkdown(el);
4142
+
4143
+ const post = () => {
4144
+ try {
4145
+ this.highlighter.observeNewCode(el, {
4146
+ deferLastIfStreaming: true,
4147
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
4148
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
4149
+ }, this.stream.activeCode);
4150
+
4151
+ this.highlighter.observeMsgBoxes(el, (box) => {
4152
+ this.highlighter.observeNewCode(box, {
4153
+ deferLastIfStreaming: true,
4154
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
4155
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
4156
+ }, this.stream.activeCode);
4157
+ this.codeScroll.initScrollableBlocks(box);
4158
+ });
4159
+ } catch (_) {}
4160
+
4161
+ try {
4162
+ const mm = getMathMode();
4163
+ // In finalize-only we must force now; otherwise normal schedule is fine.
4164
+ if (mm === 'finalize-only') this.math.schedule(el, 0, true);
4165
+ else this.math.schedule(el);
4166
+ } catch (_) {}
4167
+
4168
+ this.scrollMgr.scheduleScroll();
4169
+ };
4170
+
4171
+ if (maybePromise && typeof maybePromise.then === 'function') {
4172
+ maybePromise.then(post);
4173
+ } else {
4174
+ post();
4175
+ }
4176
+ } catch (_) {
4177
+ // Worst-case: keep UX responsive even if something throws before post-processing
4178
+ this.scrollMgr.scheduleScroll();
4179
+ }
4180
+ };
4181
+
4182
+ // API: update footer content.
4183
+ api_updateFooter = (html) => { const el = this.dom.get('_footer_'); if (el) el.innerHTML = html; };
4184
+
4185
+ // API: toggle UI features.
4186
+ api_enableEditIcons = () => this.ui.enableEditIcons();
4187
+ api_disableEditIcons = () => this.ui.disableEditIcons();
4188
+ api_enableTimestamp = () => this.ui.enableTimestamp();
4189
+ api_disableTimestamp = () => this.ui.disableTimestamp();
4190
+ api_enableBlocks = () => this.ui.enableBlocks();
4191
+ api_disableBlocks = () => this.ui.disableBlocks();
4192
+ api_updateCSS = (styles) => this.ui.updateCSS(styles);
4193
+
4194
+ // API: sync scroll position with host.
4195
+ api_getScrollPosition = () => { this.bridge.updateScrollPosition(window.scrollY); };
4196
+ api_setScrollPosition = (pos) => { try { window.scrollTo(0, pos); this.scrollMgr.prevScroll = parseInt(pos); } catch (_) {} };
4197
+
4198
+ // API: show/hide loading overlay.
4199
+ api_showLoading = () => this.loading.show();
4200
+ api_hideLoading = () => this.loading.hide();
4201
+
4202
+ // API: restore collapsed state of codes in a given root.
4203
+ api_restoreCollapsedCode = (root) => this.renderer.restoreCollapsedCode(root);
4204
+ // API: user-triggered page scroll.
4205
+ api_scrollToTopUser = () => this.scrollMgr.scrollToTopUser();
4206
+ api_scrollToBottomUser = () => this.scrollMgr.scrollToBottomUser();
4207
+
4208
+ // API: tips visibility control.
4209
+ api_showTips = () => this.tips.show();
4210
+ api_hideTips = () => this.tips.hide();
4211
+
4212
+ // API: custom markup rules control.
4213
+ api_getCustomMarkupRules = () => this.customMarkup.getRules();
4214
+ api_setCustomMarkupRules = (rules) => { this.customMarkup.setRules(rules); };
4215
+
4216
+ // Initialize runtime (called on DOMContentLoaded).
4217
+ init() {
4218
+ this.highlighter.initHLJS();
4219
+ this.dom.init();
4220
+ this.ui.ensureStickyHeaderStyle();
4221
+
4222
+ // Tips manager with rAF-based centering and rotation
4223
+ this.tips = new TipsManager(this.dom);
4224
+
4225
+ this.events.install();
4226
+
4227
+ this.bridge.initQWebChannel(this.cfg.PID, (bridge) => {
4228
+ const onChunk = (name, chunk) => this.api_appendStream(name, chunk);
4229
+ const onNode = (html) => this.api_appendNode(html);
4230
+ const onNodeReplace = (html) => this.api_replaceNodes(html);
4231
+ const onNodeInput = (html) => this.api_appendToInput(html);
4232
+ this.bridge.connect(onChunk, onNode, onNodeReplace, onNodeInput);
4233
+ try { this.logger.bindBridge(this.bridge.bridge || this.bridge); } catch (_) {}
4234
+ });
4235
+
4236
+ this.renderer.init();
4237
+ try { this.renderer.renderPendingMarkdown(document); } catch (_) {}
4238
+
4239
+ this.highlighter.observeMsgBoxes(document, (box) => {
4240
+ this.highlighter.observeNewCode(box, {
4241
+ deferLastIfStreaming: true,
4242
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
4243
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
4244
+ }, this.stream.activeCode);
4245
+ this.codeScroll.initScrollableBlocks(box);
4246
+ });
4247
+ this.highlighter.observeNewCode(document, {
4248
+ deferLastIfStreaming: true,
4249
+ minLinesForLast: this.cfg.PROFILE_CODE.minLinesForHL,
4250
+ minCharsForLast: this.cfg.PROFILE_CODE.minCharsForHL
4251
+ }, this.stream.activeCode);
4252
+ this.highlighter.scheduleScanVisibleCodes(this.stream.activeCode);
4253
+
4254
+ // Start tips rotation; internal delay matches legacy timing (TIPS_INIT_DELAY_MS)
4255
+ this.tips.cycle();
4256
+ this.scrollMgr.updateScrollFab(true);
4257
+ }
4258
+
4259
+ // Cleanup runtime and detach from DOM/bridge.
4260
+ cleanup() {
4261
+ this.tips.cleanup();
4262
+ try { this.bridge.disconnect(); } catch (_) {}
4263
+ this.events.cleanup();
4264
+ this.highlighter.cleanup();
4265
+ this.math.cleanup();
4266
+ this.streamQ.clear();
4267
+ this.dom.cleanup();
4268
+ }
4269
+ }
4270
+
4271
+ // Ensure RafManager.cancel uses the correct group key cleanup.
4272
+ if (typeof RafManager !== 'undefined' && RafManager.prototype && typeof RafManager.prototype.cancel === 'function') {
4273
+ RafManager.prototype.cancel = function(key) {
4274
+ const t = this.tasks.get(key);
4275
+ if (!t) return;
4276
+ this.tasks.delete(key);
4277
+ if (t.group) {
4278
+ const set = this.groups.get(t.group);
4279
+ if (set) { set.delete(key); if (set.size === 0) this.groups.delete(t.group); }
4280
+ }
4281
+ };
4282
+ }
4283
+
4284
+ const runtime = new Runtime();
4285
+
4286
+ document.addEventListener('DOMContentLoaded', () => runtime.init());
4287
+
4288
+ Object.defineProperty(window, 'SE', { get() { return Utils.SE; } });
4289
+
4290
+ window.beginStream = (chunk) => runtime.api_beginStream(chunk);
4291
+ window.endStream = () => runtime.api_endStream();
4292
+ window.applyStream = (name, chunk) => runtime.api_applyStream(name, chunk);
4293
+ window.appendStream = (name, chunk) => runtime.api_appendStream(name, chunk);
4294
+ window.nextStream = () => runtime.api_nextStream();
4295
+ window.clearStream = () => runtime.api_clearStream();
4296
+
4297
+ window.appendNode = (html) => runtime.api_appendNode(html);
4298
+ window.replaceNodes = (html) => runtime.api_replaceNodes(html);
4299
+ window.appendToInput = (html) => runtime.api_appendToInput(html);
4300
+
4301
+ window.clearNodes = () => runtime.api_clearNodes();
4302
+ window.clearInput = () => runtime.api_clearInput();
4303
+ window.clearOutput = () => runtime.api_clearOutput();
4304
+ window.clearLive = () => runtime.api_clearLive();
4305
+
4306
+ window.appendToolOutput = (c) => runtime.api_appendToolOutput(c);
4307
+ window.updateToolOutput = (c) => runtime.api_updateToolOutput(c);
4308
+ window.clearToolOutput = () => runtime.api_clearToolOutput();
4309
+ window.beginToolOutput = () => runtime.api_beginToolOutput();
4310
+ window.endToolOutput = () => runtime.api_endToolOutput();
4311
+ window.enableToolOutput = () => runtime.api_enableToolOutput();
4312
+ window.disableToolOutput = () => runtime.api_disableToolOutput();
4313
+ window.toggleToolOutput = (id) => runtime.api_toggleToolOutput(id);
4314
+
4315
+ window.appendExtra = (id, c) => runtime.api_appendExtra(id, c);
4316
+ window.removeNode = (id) => runtime.api_removeNode(id);
4317
+ window.removeNodesFromId = (id) => runtime.api_removeNodesFromId(id);
4318
+
4319
+ window.replaceLive = (c) => runtime.api_replaceLive(c);
4320
+ window.updateFooter = (c) => runtime.api_updateFooter(c);
4321
+
4322
+ window.enableEditIcons = () => runtime.api_enableEditIcons();
4323
+ window.disableEditIcons = () => runtime.api_disableEditIcons();
4324
+ window.enableTimestamp = () => runtime.api_enableTimestamp();
4325
+ window.disableTimestamp = () => runtime.api_disableTimestamp();
4326
+ window.enableBlocks = () => runtime.api_enableBlocks();
4327
+ window.disableBlocks = () => runtime.api_disableBlocks();
4328
+ window.updateCSS = (s) => runtime.api_updateCSS(s);
4329
+
4330
+ window.getScrollPosition = () => runtime.api_getScrollPosition();
4331
+ window.setScrollPosition = (pos) => runtime.api_setScrollPosition(pos);
4332
+
4333
+ window.showLoading = () => runtime.api_showLoading();
4334
+ window.hideLoading = () => runtime.api_hideLoading();
4335
+
4336
+ window.restoreCollapsedCode = (root) => runtime.api_restoreCollapsedCode(root);
4337
+ window.scrollToTopUser = () => runtime.api_scrollToTopUser();
4338
+ window.scrollToBottomUser = () => runtime.api_scrollToBottomUser();
4339
+
4340
+ window.showTips = () => runtime.api_showTips();
4341
+ window.hideTips = () => runtime.api_hideTips();
4342
+
4343
+ window.getCustomMarkupRules = () => runtime.api_getCustomMarkupRules();
4344
+ window.setCustomMarkupRules = (rules) => runtime.api_setCustomMarkupRules(rules);
4345
+
4346
+ window.__pygpt_cleanup = () => runtime.cleanup();
4347
+
4348
+ })();