verybot 0.1.3

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.

Potentially problematic release.


This version of verybot might be problematic. Click here for more details.

Files changed (244) hide show
  1. package/dist/brain/agent-registry.d.ts +75 -0
  2. package/dist/brain/agent-registry.js +124 -0
  3. package/dist/brain/agent.d.ts +146 -0
  4. package/dist/brain/agent.js +680 -0
  5. package/dist/brain/channel-store.d.ts +27 -0
  6. package/dist/brain/channel-store.js +78 -0
  7. package/dist/brain/compaction.d.ts +37 -0
  8. package/dist/brain/compaction.js +214 -0
  9. package/dist/brain/context.d.ts +33 -0
  10. package/dist/brain/context.js +77 -0
  11. package/dist/brain/delegation-store.d.ts +33 -0
  12. package/dist/brain/delegation-store.js +106 -0
  13. package/dist/brain/loop.d.ts +21 -0
  14. package/dist/brain/loop.js +161 -0
  15. package/dist/brain/mcp-adapter.d.ts +39 -0
  16. package/dist/brain/mcp-adapter.js +227 -0
  17. package/dist/brain/memory-extractor.d.ts +26 -0
  18. package/dist/brain/memory-extractor.js +82 -0
  19. package/dist/brain/providers.d.ts +10 -0
  20. package/dist/brain/providers.js +69 -0
  21. package/dist/brain/queue.d.ts +18 -0
  22. package/dist/brain/queue.js +84 -0
  23. package/dist/brain/run-tools.d.ts +47 -0
  24. package/dist/brain/run-tools.js +84 -0
  25. package/dist/brain/session-key.d.ts +23 -0
  26. package/dist/brain/session-key.js +41 -0
  27. package/dist/brain/session-state.d.ts +36 -0
  28. package/dist/brain/session-state.js +51 -0
  29. package/dist/brain/session-store.d.ts +50 -0
  30. package/dist/brain/session-store.js +207 -0
  31. package/dist/brain/session.d.ts +32 -0
  32. package/dist/brain/session.js +75 -0
  33. package/dist/brain/utils.d.ts +4 -0
  34. package/dist/brain/utils.js +26 -0
  35. package/dist/brain/worker-coordinator.d.ts +25 -0
  36. package/dist/brain/worker-coordinator.js +83 -0
  37. package/dist/channels/commands.d.ts +35 -0
  38. package/dist/channels/commands.js +65 -0
  39. package/dist/channels/discord/channel.d.ts +18 -0
  40. package/dist/channels/discord/channel.js +154 -0
  41. package/dist/channels/discord/markdown.d.ts +19 -0
  42. package/dist/channels/discord/markdown.js +62 -0
  43. package/dist/channels/manager.d.ts +29 -0
  44. package/dist/channels/manager.js +100 -0
  45. package/dist/channels/slack/channel.d.ts +26 -0
  46. package/dist/channels/slack/channel.js +207 -0
  47. package/dist/channels/slack/markdown.d.ts +19 -0
  48. package/dist/channels/slack/markdown.js +62 -0
  49. package/dist/channels/specs.d.ts +21 -0
  50. package/dist/channels/specs.js +96 -0
  51. package/dist/channels/telegram/channel.d.ts +18 -0
  52. package/dist/channels/telegram/channel.js +156 -0
  53. package/dist/channels/telegram/markdown.d.ts +17 -0
  54. package/dist/channels/telegram/markdown.js +66 -0
  55. package/dist/channels/types.d.ts +26 -0
  56. package/dist/channels/types.js +1 -0
  57. package/dist/channels/whatsapp/channel.d.ts +23 -0
  58. package/dist/channels/whatsapp/channel.js +242 -0
  59. package/dist/channels/whatsapp/markdown.d.ts +20 -0
  60. package/dist/channels/whatsapp/markdown.js +51 -0
  61. package/dist/cli/config.d.ts +5 -0
  62. package/dist/cli/config.js +78 -0
  63. package/dist/cli/index.d.ts +5 -0
  64. package/dist/cli/index.js +13 -0
  65. package/dist/computer/browser/actions.d.ts +31 -0
  66. package/dist/computer/browser/actions.js +148 -0
  67. package/dist/computer/browser/manager.d.ts +55 -0
  68. package/dist/computer/browser/manager.js +496 -0
  69. package/dist/computer/browser/profile-badge.d.ts +13 -0
  70. package/dist/computer/browser/profile-badge.js +67 -0
  71. package/dist/computer/browser/screenshot.d.ts +5 -0
  72. package/dist/computer/browser/screenshot.js +21 -0
  73. package/dist/computer/browser/snapshot.d.ts +30 -0
  74. package/dist/computer/browser/snapshot.js +242 -0
  75. package/dist/computer/browser/tools.d.ts +5 -0
  76. package/dist/computer/browser/tools.js +167 -0
  77. package/dist/computer/desktop/adapter.d.ts +25 -0
  78. package/dist/computer/desktop/adapter.js +11 -0
  79. package/dist/computer/desktop/macos.d.ts +24 -0
  80. package/dist/computer/desktop/macos.js +223 -0
  81. package/dist/computer/desktop/tools.d.ts +25 -0
  82. package/dist/computer/desktop/tools.js +114 -0
  83. package/dist/config/agent-config.d.ts +41 -0
  84. package/dist/config/agent-config.js +14 -0
  85. package/dist/config/model-catalog.d.ts +22 -0
  86. package/dist/config/model-catalog.js +99 -0
  87. package/dist/config/store.d.ts +25 -0
  88. package/dist/config/store.js +143 -0
  89. package/dist/config.d.ts +103 -0
  90. package/dist/config.js +224 -0
  91. package/dist/control-ui/assets/index-BANXNUyt.js +143 -0
  92. package/dist/control-ui/assets/index-BSUFrP9R.css +1 -0
  93. package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
  94. package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
  95. package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
  96. package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
  97. package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
  98. package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
  99. package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
  100. package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
  101. package/dist/control-ui/index.html +14 -0
  102. package/dist/control-ui/vite.svg +1 -0
  103. package/dist/events.d.ts +2 -0
  104. package/dist/events.js +11 -0
  105. package/dist/gateway/broadcast.d.ts +5 -0
  106. package/dist/gateway/broadcast.js +33 -0
  107. package/dist/gateway/methods/chat.d.ts +24 -0
  108. package/dist/gateway/methods/chat.js +19 -0
  109. package/dist/gateway/methods/config.d.ts +13 -0
  110. package/dist/gateway/methods/config.js +14 -0
  111. package/dist/gateway/methods/models.d.ts +10 -0
  112. package/dist/gateway/methods/models.js +14 -0
  113. package/dist/gateway/methods/prompt-templates.d.ts +23 -0
  114. package/dist/gateway/methods/prompt-templates.js +82 -0
  115. package/dist/gateway/methods/scheduler.d.ts +62 -0
  116. package/dist/gateway/methods/scheduler.js +129 -0
  117. package/dist/gateway/methods/sessions.d.ts +26 -0
  118. package/dist/gateway/methods/sessions.js +54 -0
  119. package/dist/gateway/methods/skills.d.ts +35 -0
  120. package/dist/gateway/methods/skills.js +202 -0
  121. package/dist/gateway/methods/system.d.ts +12 -0
  122. package/dist/gateway/methods/system.js +39 -0
  123. package/dist/gateway/methods/tasks.d.ts +21 -0
  124. package/dist/gateway/methods/tasks.js +46 -0
  125. package/dist/gateway/methods/teams.d.ts +70 -0
  126. package/dist/gateway/methods/teams.js +374 -0
  127. package/dist/gateway/methods/tools.d.ts +6 -0
  128. package/dist/gateway/methods/tools.js +7 -0
  129. package/dist/gateway/methods/whatsapp.d.ts +19 -0
  130. package/dist/gateway/methods/whatsapp.js +35 -0
  131. package/dist/gateway/rpc.d.ts +38 -0
  132. package/dist/gateway/rpc.js +75 -0
  133. package/dist/gateway/server.d.ts +4 -0
  134. package/dist/gateway/server.js +133 -0
  135. package/dist/index.d.ts +1 -0
  136. package/dist/index.js +212 -0
  137. package/dist/integrations/github.d.ts +7 -0
  138. package/dist/integrations/github.js +133 -0
  139. package/dist/integrations/mcp.d.ts +7 -0
  140. package/dist/integrations/mcp.js +106 -0
  141. package/dist/integrations/registry.d.ts +43 -0
  142. package/dist/integrations/registry.js +258 -0
  143. package/dist/integrations/scanner.d.ts +10 -0
  144. package/dist/integrations/scanner.js +122 -0
  145. package/dist/integrations/twitter.d.ts +10 -0
  146. package/dist/integrations/twitter.js +120 -0
  147. package/dist/integrations/types.d.ts +72 -0
  148. package/dist/integrations/types.js +1 -0
  149. package/dist/logger.d.ts +16 -0
  150. package/dist/logger.js +104 -0
  151. package/dist/markdown/chunk.d.ts +9 -0
  152. package/dist/markdown/chunk.js +52 -0
  153. package/dist/markdown/ir.d.ts +37 -0
  154. package/dist/markdown/ir.js +529 -0
  155. package/dist/markdown/render.d.ts +22 -0
  156. package/dist/markdown/render.js +148 -0
  157. package/dist/markdown/table-render.d.ts +43 -0
  158. package/dist/markdown/table-render.js +219 -0
  159. package/dist/markdown/tables.d.ts +17 -0
  160. package/dist/markdown/tables.js +27 -0
  161. package/dist/memory/embedding.d.ts +16 -0
  162. package/dist/memory/embedding.js +66 -0
  163. package/dist/memory/extractor.d.ts +6 -0
  164. package/dist/memory/extractor.js +72 -0
  165. package/dist/memory/search.d.ts +15 -0
  166. package/dist/memory/search.js +57 -0
  167. package/dist/memory/store.d.ts +34 -0
  168. package/dist/memory/store.js +328 -0
  169. package/dist/memory/types.d.ts +9 -0
  170. package/dist/memory/types.js +2 -0
  171. package/dist/paths.d.ts +20 -0
  172. package/dist/paths.js +29 -0
  173. package/dist/prompt-templates/builtins.d.ts +2 -0
  174. package/dist/prompt-templates/builtins.js +72 -0
  175. package/dist/prompt-templates/store.d.ts +39 -0
  176. package/dist/prompt-templates/store.js +174 -0
  177. package/dist/prompt-templates/types.d.ts +10 -0
  178. package/dist/prompt-templates/types.js +1 -0
  179. package/dist/scheduler/connected-channels.d.ts +24 -0
  180. package/dist/scheduler/connected-channels.js +57 -0
  181. package/dist/scheduler/scheduler.d.ts +22 -0
  182. package/dist/scheduler/scheduler.js +132 -0
  183. package/dist/scheduler/store.d.ts +27 -0
  184. package/dist/scheduler/store.js +205 -0
  185. package/dist/scheduler/types.d.ts +29 -0
  186. package/dist/scheduler/types.js +1 -0
  187. package/dist/security/command-validator.d.ts +22 -0
  188. package/dist/security/command-validator.js +160 -0
  189. package/dist/security/docker-sandbox.d.ts +48 -0
  190. package/dist/security/docker-sandbox.js +218 -0
  191. package/dist/security/env-filter.d.ts +8 -0
  192. package/dist/security/env-filter.js +41 -0
  193. package/dist/skills/loader.d.ts +33 -0
  194. package/dist/skills/loader.js +132 -0
  195. package/dist/skills/prompt.d.ts +6 -0
  196. package/dist/skills/prompt.js +17 -0
  197. package/dist/skills/read-tool.d.ts +7 -0
  198. package/dist/skills/read-tool.js +24 -0
  199. package/dist/skills/scanner.d.ts +6 -0
  200. package/dist/skills/scanner.js +73 -0
  201. package/dist/skills/types.d.ts +15 -0
  202. package/dist/skills/types.js +1 -0
  203. package/dist/tasks/store.d.ts +47 -0
  204. package/dist/tasks/store.js +193 -0
  205. package/dist/tasks/types.d.ts +75 -0
  206. package/dist/tasks/types.js +32 -0
  207. package/dist/teams/store.d.ts +78 -0
  208. package/dist/teams/store.js +420 -0
  209. package/dist/teams/types.d.ts +23 -0
  210. package/dist/teams/types.js +1 -0
  211. package/dist/tools/bash.d.ts +16 -0
  212. package/dist/tools/bash.js +62 -0
  213. package/dist/tools/channel-history.d.ts +10 -0
  214. package/dist/tools/channel-history.js +43 -0
  215. package/dist/tools/delegate.d.ts +16 -0
  216. package/dist/tools/delegate.js +216 -0
  217. package/dist/tools/fs.d.ts +4 -0
  218. package/dist/tools/fs.js +335 -0
  219. package/dist/tools/integration-toggle.d.ts +14 -0
  220. package/dist/tools/integration-toggle.js +47 -0
  221. package/dist/tools/memory.d.ts +13 -0
  222. package/dist/tools/memory.js +65 -0
  223. package/dist/tools/registry.d.ts +6 -0
  224. package/dist/tools/registry.js +9 -0
  225. package/dist/tools/schedule.d.ts +8 -0
  226. package/dist/tools/schedule.js +219 -0
  227. package/dist/tools/speak.d.ts +10 -0
  228. package/dist/tools/speak.js +56 -0
  229. package/dist/tools/tasks.d.ts +29 -0
  230. package/dist/tools/tasks.js +92 -0
  231. package/dist/tools/teams.d.ts +7 -0
  232. package/dist/tools/teams.js +180 -0
  233. package/dist/tools/web-fetch.d.ts +3 -0
  234. package/dist/tools/web-fetch.js +22 -0
  235. package/dist/tts/edge.d.ts +10 -0
  236. package/dist/tts/edge.js +60 -0
  237. package/dist/tts/speak.d.ts +12 -0
  238. package/dist/tts/speak.js +81 -0
  239. package/dist/tts/transcribe.d.ts +5 -0
  240. package/dist/tts/transcribe.js +40 -0
  241. package/dist/utils.d.ts +5 -0
  242. package/dist/utils.js +22 -0
  243. package/package.json +90 -0
  244. package/verybot.js +2 -0
@@ -0,0 +1,529 @@
1
+ /**
2
+ * Markdown Intermediate Representation (IR) parser.
3
+ * Markdown IR parser — standalone with no external deps
4
+ * beyond markdown-it.
5
+ */
6
+ import MarkdownIt from "markdown-it";
7
+ import { chunkText } from "./chunk.js";
8
+ import { initTableState, initCellTarget, finishTableCell, renderTableAsBullets, renderTableAsCode, } from "./table-render.js";
9
+ function createMarkdownIt(options) {
10
+ const md = new MarkdownIt({
11
+ html: false,
12
+ linkify: options.linkify ?? true,
13
+ breaks: false,
14
+ typographer: false,
15
+ });
16
+ md.enable("strikethrough");
17
+ if (options.tableMode && options.tableMode !== "off") {
18
+ md.enable("table");
19
+ }
20
+ else {
21
+ md.disable("table");
22
+ }
23
+ if (options.autolink === false) {
24
+ md.disable("autolink");
25
+ }
26
+ return md;
27
+ }
28
+ function getAttr(token, name) {
29
+ if (token.attrGet) {
30
+ return token.attrGet(name);
31
+ }
32
+ if (token.attrs) {
33
+ for (const [key, value] of token.attrs) {
34
+ if (key === name) {
35
+ return value;
36
+ }
37
+ }
38
+ }
39
+ return null;
40
+ }
41
+ function createTextToken(base, content) {
42
+ return { ...base, type: "text", content, children: undefined };
43
+ }
44
+ function applySpoilerTokens(tokens) {
45
+ for (const token of tokens) {
46
+ if (token.children && token.children.length > 0) {
47
+ token.children = injectSpoilersIntoInline(token.children);
48
+ }
49
+ }
50
+ }
51
+ function injectSpoilersIntoInline(tokens) {
52
+ const result = [];
53
+ const state = { spoilerOpen: false };
54
+ for (const token of tokens) {
55
+ if (token.type !== "text") {
56
+ result.push(token);
57
+ continue;
58
+ }
59
+ const content = token.content ?? "";
60
+ if (!content.includes("||")) {
61
+ result.push(token);
62
+ continue;
63
+ }
64
+ let index = 0;
65
+ while (index < content.length) {
66
+ const next = content.indexOf("||", index);
67
+ if (next === -1) {
68
+ if (index < content.length) {
69
+ result.push(createTextToken(token, content.slice(index)));
70
+ }
71
+ break;
72
+ }
73
+ if (next > index) {
74
+ result.push(createTextToken(token, content.slice(index, next)));
75
+ }
76
+ state.spoilerOpen = !state.spoilerOpen;
77
+ result.push({
78
+ type: state.spoilerOpen ? "spoiler_open" : "spoiler_close",
79
+ });
80
+ index = next + 2;
81
+ }
82
+ }
83
+ return result;
84
+ }
85
+ function initRenderTarget() {
86
+ return {
87
+ text: "",
88
+ styles: [],
89
+ openStyles: [],
90
+ links: [],
91
+ linkStack: [],
92
+ };
93
+ }
94
+ function resolveRenderTarget(state) {
95
+ return state.table?.currentCell ?? state;
96
+ }
97
+ function appendText(state, value) {
98
+ if (!value) {
99
+ return;
100
+ }
101
+ const target = resolveRenderTarget(state);
102
+ target.text += value;
103
+ }
104
+ function openStyle(state, style) {
105
+ const target = resolveRenderTarget(state);
106
+ target.openStyles.push({ style, start: target.text.length });
107
+ }
108
+ function closeStyle(state, style) {
109
+ const target = resolveRenderTarget(state);
110
+ for (let i = target.openStyles.length - 1; i >= 0; i -= 1) {
111
+ if (target.openStyles[i]?.style === style) {
112
+ const start = target.openStyles[i].start;
113
+ target.openStyles.splice(i, 1);
114
+ const end = target.text.length;
115
+ if (end > start) {
116
+ target.styles.push({ start, end, style });
117
+ }
118
+ return;
119
+ }
120
+ }
121
+ }
122
+ function appendParagraphSeparator(state) {
123
+ if (state.env.listStack.length > 0) {
124
+ return;
125
+ }
126
+ if (state.table) {
127
+ return;
128
+ }
129
+ state.text += "\n\n";
130
+ }
131
+ function appendListPrefix(state) {
132
+ const stack = state.env.listStack;
133
+ const top = stack[stack.length - 1];
134
+ if (!top) {
135
+ return;
136
+ }
137
+ top.index += 1;
138
+ const indent = " ".repeat(Math.max(0, stack.length - 1));
139
+ const prefix = top.type === "ordered" ? `${top.index}. ` : "\u2022 ";
140
+ state.text += `${indent}${prefix}`;
141
+ }
142
+ function renderInlineCode(state, content) {
143
+ if (!content) {
144
+ return;
145
+ }
146
+ const target = resolveRenderTarget(state);
147
+ const start = target.text.length;
148
+ target.text += content;
149
+ target.styles.push({ start, end: start + content.length, style: "code" });
150
+ }
151
+ function renderCodeBlock(state, content) {
152
+ let code = content ?? "";
153
+ if (!code.endsWith("\n")) {
154
+ code = `${code}\n`;
155
+ }
156
+ const target = resolveRenderTarget(state);
157
+ const start = target.text.length;
158
+ target.text += code;
159
+ target.styles.push({ start, end: start + code.length, style: "code_block" });
160
+ if (state.env.listStack.length === 0) {
161
+ target.text += "\n";
162
+ }
163
+ }
164
+ function handleLinkClose(state) {
165
+ const target = resolveRenderTarget(state);
166
+ const link = target.linkStack.pop();
167
+ if (!link?.href) {
168
+ return;
169
+ }
170
+ const href = link.href.trim();
171
+ if (!href) {
172
+ return;
173
+ }
174
+ const start = link.labelStart;
175
+ const end = target.text.length;
176
+ target.links.push({ start, end, href });
177
+ }
178
+ function closeRemainingStyles(target) {
179
+ for (let i = target.openStyles.length - 1; i >= 0; i -= 1) {
180
+ const open = target.openStyles[i];
181
+ const end = target.text.length;
182
+ if (end > open.start) {
183
+ target.styles.push({
184
+ start: open.start,
185
+ end,
186
+ style: open.style,
187
+ });
188
+ }
189
+ }
190
+ target.openStyles = [];
191
+ }
192
+ function renderTokens(tokens, state) {
193
+ for (const token of tokens) {
194
+ switch (token.type) {
195
+ case "inline":
196
+ if (token.children) {
197
+ renderTokens(token.children, state);
198
+ }
199
+ break;
200
+ case "text":
201
+ appendText(state, token.content ?? "");
202
+ break;
203
+ case "em_open":
204
+ openStyle(state, "italic");
205
+ break;
206
+ case "em_close":
207
+ closeStyle(state, "italic");
208
+ break;
209
+ case "strong_open":
210
+ openStyle(state, "bold");
211
+ break;
212
+ case "strong_close":
213
+ closeStyle(state, "bold");
214
+ break;
215
+ case "s_open":
216
+ openStyle(state, "strikethrough");
217
+ break;
218
+ case "s_close":
219
+ closeStyle(state, "strikethrough");
220
+ break;
221
+ case "code_inline":
222
+ renderInlineCode(state, token.content ?? "");
223
+ break;
224
+ case "spoiler_open":
225
+ if (state.enableSpoilers) {
226
+ openStyle(state, "spoiler");
227
+ }
228
+ break;
229
+ case "spoiler_close":
230
+ if (state.enableSpoilers) {
231
+ closeStyle(state, "spoiler");
232
+ }
233
+ break;
234
+ case "link_open": {
235
+ const href = getAttr(token, "href") ?? "";
236
+ const target = resolveRenderTarget(state);
237
+ target.linkStack.push({ href, labelStart: target.text.length });
238
+ break;
239
+ }
240
+ case "link_close":
241
+ handleLinkClose(state);
242
+ break;
243
+ case "image":
244
+ appendText(state, token.content ?? "");
245
+ break;
246
+ case "softbreak":
247
+ case "hardbreak":
248
+ appendText(state, "\n");
249
+ break;
250
+ case "paragraph_close":
251
+ appendParagraphSeparator(state);
252
+ break;
253
+ case "heading_open":
254
+ if (state.headingStyle === "bold") {
255
+ openStyle(state, "bold");
256
+ }
257
+ break;
258
+ case "heading_close":
259
+ if (state.headingStyle === "bold") {
260
+ closeStyle(state, "bold");
261
+ }
262
+ appendParagraphSeparator(state);
263
+ break;
264
+ case "blockquote_open":
265
+ if (state.blockquotePrefix) {
266
+ state.text += state.blockquotePrefix;
267
+ }
268
+ break;
269
+ case "blockquote_close":
270
+ state.text += "\n";
271
+ break;
272
+ case "bullet_list_open":
273
+ state.env.listStack.push({ type: "bullet", index: 0 });
274
+ break;
275
+ case "bullet_list_close":
276
+ state.env.listStack.pop();
277
+ break;
278
+ case "ordered_list_open": {
279
+ const start = Number(getAttr(token, "start") ?? "1");
280
+ state.env.listStack.push({ type: "ordered", index: start - 1 });
281
+ break;
282
+ }
283
+ case "ordered_list_close":
284
+ state.env.listStack.pop();
285
+ break;
286
+ case "list_item_open":
287
+ appendListPrefix(state);
288
+ break;
289
+ case "list_item_close":
290
+ state.text += "\n";
291
+ break;
292
+ case "code_block":
293
+ case "fence":
294
+ renderCodeBlock(state, token.content ?? "");
295
+ break;
296
+ case "html_block":
297
+ case "html_inline":
298
+ appendText(state, token.content ?? "");
299
+ break;
300
+ // Table handling
301
+ case "table_open":
302
+ if (state.tableMode !== "off") {
303
+ state.table = initTableState();
304
+ state.hasTables = true;
305
+ }
306
+ break;
307
+ case "table_close":
308
+ if (state.table) {
309
+ const inList = state.env.listStack.length > 0;
310
+ if (state.tableMode === "bullets") {
311
+ renderTableAsBullets(state, state.table);
312
+ }
313
+ else if (state.tableMode === "code") {
314
+ renderTableAsCode(state, state.table, inList);
315
+ }
316
+ }
317
+ state.table = null;
318
+ break;
319
+ case "thead_open":
320
+ if (state.table) {
321
+ state.table.inHeader = true;
322
+ }
323
+ break;
324
+ case "thead_close":
325
+ if (state.table) {
326
+ state.table.inHeader = false;
327
+ }
328
+ break;
329
+ case "tbody_open":
330
+ case "tbody_close":
331
+ break;
332
+ case "tr_open":
333
+ if (state.table) {
334
+ state.table.currentRow = [];
335
+ }
336
+ break;
337
+ case "tr_close":
338
+ if (state.table) {
339
+ if (state.table.inHeader) {
340
+ state.table.headers = state.table.currentRow;
341
+ }
342
+ else {
343
+ state.table.rows.push(state.table.currentRow);
344
+ }
345
+ state.table.currentRow = [];
346
+ }
347
+ break;
348
+ case "th_open":
349
+ case "td_open":
350
+ if (state.table) {
351
+ state.table.currentCell = initCellTarget();
352
+ }
353
+ break;
354
+ case "th_close":
355
+ case "td_close":
356
+ if (state.table?.currentCell) {
357
+ state.table.currentRow.push(finishTableCell(state.table.currentCell));
358
+ state.table.currentCell = null;
359
+ }
360
+ break;
361
+ case "hr":
362
+ state.text += "\n";
363
+ break;
364
+ default:
365
+ if (token.children) {
366
+ renderTokens(token.children, state);
367
+ }
368
+ break;
369
+ }
370
+ }
371
+ }
372
+ function clampStyleSpans(spans, maxLength) {
373
+ const clamped = [];
374
+ for (const span of spans) {
375
+ const start = Math.max(0, Math.min(span.start, maxLength));
376
+ const end = Math.max(start, Math.min(span.end, maxLength));
377
+ if (end > start) {
378
+ clamped.push({ start, end, style: span.style });
379
+ }
380
+ }
381
+ return clamped;
382
+ }
383
+ function clampLinkSpans(spans, maxLength) {
384
+ const clamped = [];
385
+ for (const span of spans) {
386
+ const start = Math.max(0, Math.min(span.start, maxLength));
387
+ const end = Math.max(start, Math.min(span.end, maxLength));
388
+ if (end > start) {
389
+ clamped.push({ start, end, href: span.href });
390
+ }
391
+ }
392
+ return clamped;
393
+ }
394
+ function mergeStyleSpans(spans) {
395
+ const sorted = [...spans].sort((a, b) => {
396
+ if (a.start !== b.start) {
397
+ return a.start - b.start;
398
+ }
399
+ if (a.end !== b.end) {
400
+ return a.end - b.end;
401
+ }
402
+ return a.style.localeCompare(b.style);
403
+ });
404
+ const merged = [];
405
+ for (const span of sorted) {
406
+ const prev = merged[merged.length - 1];
407
+ if (prev && prev.style === span.style && span.start <= prev.end) {
408
+ prev.end = Math.max(prev.end, span.end);
409
+ continue;
410
+ }
411
+ merged.push({ ...span });
412
+ }
413
+ return merged;
414
+ }
415
+ function sliceStyleSpans(spans, start, end) {
416
+ if (spans.length === 0) {
417
+ return [];
418
+ }
419
+ const sliced = [];
420
+ for (const span of spans) {
421
+ const sliceStart = Math.max(span.start, start);
422
+ const sliceEnd = Math.min(span.end, end);
423
+ if (sliceEnd > sliceStart) {
424
+ sliced.push({
425
+ start: sliceStart - start,
426
+ end: sliceEnd - start,
427
+ style: span.style,
428
+ });
429
+ }
430
+ }
431
+ return mergeStyleSpans(sliced);
432
+ }
433
+ function sliceLinkSpans(spans, start, end) {
434
+ if (spans.length === 0) {
435
+ return [];
436
+ }
437
+ const sliced = [];
438
+ for (const span of spans) {
439
+ const sliceStart = Math.max(span.start, start);
440
+ const sliceEnd = Math.min(span.end, end);
441
+ if (sliceEnd > sliceStart) {
442
+ sliced.push({
443
+ start: sliceStart - start,
444
+ end: sliceEnd - start,
445
+ href: span.href,
446
+ });
447
+ }
448
+ }
449
+ return sliced;
450
+ }
451
+ export function markdownToIR(markdown, options = {}) {
452
+ return markdownToIRWithMeta(markdown, options).ir;
453
+ }
454
+ export function markdownToIRWithMeta(markdown, options = {}) {
455
+ const env = { listStack: [] };
456
+ const md = createMarkdownIt(options);
457
+ const tokens = md.parse(markdown ?? "", env);
458
+ if (options.enableSpoilers) {
459
+ applySpoilerTokens(tokens);
460
+ }
461
+ const tableMode = options.tableMode ?? "off";
462
+ const state = {
463
+ text: "",
464
+ styles: [],
465
+ openStyles: [],
466
+ links: [],
467
+ linkStack: [],
468
+ env,
469
+ headingStyle: options.headingStyle ?? "none",
470
+ blockquotePrefix: options.blockquotePrefix ?? "",
471
+ enableSpoilers: options.enableSpoilers ?? false,
472
+ tableMode,
473
+ table: null,
474
+ hasTables: false,
475
+ };
476
+ renderTokens(tokens, state);
477
+ closeRemainingStyles(state);
478
+ const trimmedText = state.text.trimEnd();
479
+ const trimmedLength = trimmedText.length;
480
+ let codeBlockEnd = 0;
481
+ for (const span of state.styles) {
482
+ if (span.style !== "code_block") {
483
+ continue;
484
+ }
485
+ if (span.end > codeBlockEnd) {
486
+ codeBlockEnd = span.end;
487
+ }
488
+ }
489
+ const finalLength = Math.max(trimmedLength, codeBlockEnd);
490
+ const finalText = finalLength === state.text.length ? state.text : state.text.slice(0, finalLength);
491
+ return {
492
+ ir: {
493
+ text: finalText,
494
+ styles: mergeStyleSpans(clampStyleSpans(state.styles, finalLength)),
495
+ links: clampLinkSpans(state.links, finalLength),
496
+ },
497
+ hasTables: state.hasTables,
498
+ };
499
+ }
500
+ export function chunkMarkdownIR(ir, limit) {
501
+ if (!ir.text) {
502
+ return [];
503
+ }
504
+ if (limit <= 0 || ir.text.length <= limit) {
505
+ return [ir];
506
+ }
507
+ const chunks = chunkText(ir.text, limit);
508
+ const results = [];
509
+ let cursor = 0;
510
+ chunks.forEach((chunk, index) => {
511
+ if (!chunk) {
512
+ return;
513
+ }
514
+ if (index > 0) {
515
+ while (cursor < ir.text.length && /\s/.test(ir.text[cursor] ?? "")) {
516
+ cursor += 1;
517
+ }
518
+ }
519
+ const start = cursor;
520
+ const end = Math.min(ir.text.length, start + chunk.length);
521
+ results.push({
522
+ text: chunk,
523
+ styles: sliceStyleSpans(ir.styles, start, end),
524
+ links: sliceLinkSpans(ir.links, start, end),
525
+ });
526
+ cursor = end;
527
+ });
528
+ return results;
529
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Generic marker-based renderer for Markdown IR.
3
+ * Generic marker-based renderer for Markdown IR.
4
+ */
5
+ import type { MarkdownIR, MarkdownLinkSpan, MarkdownStyle } from "./ir.js";
6
+ export type RenderStyleMarker = {
7
+ open: string;
8
+ close: string;
9
+ };
10
+ export type RenderStyleMap = Partial<Record<MarkdownStyle, RenderStyleMarker>>;
11
+ export type RenderLink = {
12
+ start: number;
13
+ end: number;
14
+ open: string;
15
+ close: string;
16
+ };
17
+ export type RenderOptions = {
18
+ styleMarkers: RenderStyleMap;
19
+ escapeText: (text: string) => string;
20
+ buildLink?: (link: MarkdownLinkSpan, text: string) => RenderLink | null;
21
+ };
22
+ export declare function renderMarkdownWithMarkers(ir: MarkdownIR, options: RenderOptions): string;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Generic marker-based renderer for Markdown IR.
3
+ * Generic marker-based renderer for Markdown IR.
4
+ */
5
+ const STYLE_ORDER = [
6
+ "code_block",
7
+ "code",
8
+ "bold",
9
+ "italic",
10
+ "strikethrough",
11
+ "spoiler",
12
+ ];
13
+ const STYLE_RANK = new Map(STYLE_ORDER.map((style, index) => [style, index]));
14
+ function sortStyleSpans(spans) {
15
+ return [...spans].sort((a, b) => {
16
+ if (a.start !== b.start) {
17
+ return a.start - b.start;
18
+ }
19
+ if (a.end !== b.end) {
20
+ return b.end - a.end;
21
+ }
22
+ return (STYLE_RANK.get(a.style) ?? 0) - (STYLE_RANK.get(b.style) ?? 0);
23
+ });
24
+ }
25
+ export function renderMarkdownWithMarkers(ir, options) {
26
+ const text = ir.text ?? "";
27
+ if (!text) {
28
+ return "";
29
+ }
30
+ const styleMarkers = options.styleMarkers;
31
+ const styled = sortStyleSpans(ir.styles.filter((span) => Boolean(styleMarkers[span.style])));
32
+ const boundaries = new Set();
33
+ boundaries.add(0);
34
+ boundaries.add(text.length);
35
+ const startsAt = new Map();
36
+ for (const span of styled) {
37
+ if (span.start === span.end) {
38
+ continue;
39
+ }
40
+ boundaries.add(span.start);
41
+ boundaries.add(span.end);
42
+ const bucket = startsAt.get(span.start);
43
+ if (bucket) {
44
+ bucket.push(span);
45
+ }
46
+ else {
47
+ startsAt.set(span.start, [span]);
48
+ }
49
+ }
50
+ for (const spans of startsAt.values()) {
51
+ spans.sort((a, b) => {
52
+ if (a.end !== b.end) {
53
+ return b.end - a.end;
54
+ }
55
+ return (STYLE_RANK.get(a.style) ?? 0) - (STYLE_RANK.get(b.style) ?? 0);
56
+ });
57
+ }
58
+ const linkStarts = new Map();
59
+ if (options.buildLink) {
60
+ for (const link of ir.links) {
61
+ if (link.start === link.end) {
62
+ continue;
63
+ }
64
+ const rendered = options.buildLink(link, text);
65
+ if (!rendered) {
66
+ continue;
67
+ }
68
+ boundaries.add(rendered.start);
69
+ boundaries.add(rendered.end);
70
+ const openBucket = linkStarts.get(rendered.start);
71
+ if (openBucket) {
72
+ openBucket.push(rendered);
73
+ }
74
+ else {
75
+ linkStarts.set(rendered.start, [rendered]);
76
+ }
77
+ }
78
+ }
79
+ const points = [...boundaries].sort((a, b) => a - b);
80
+ const stack = [];
81
+ let out = "";
82
+ for (let i = 0; i < points.length; i += 1) {
83
+ const pos = points[i];
84
+ // Close ALL elements in LIFO order at this position
85
+ while (stack.length && stack[stack.length - 1]?.end === pos) {
86
+ const item = stack.pop();
87
+ if (item) {
88
+ out += item.close;
89
+ }
90
+ }
91
+ const openingItems = [];
92
+ const openingLinks = linkStarts.get(pos);
93
+ if (openingLinks && openingLinks.length > 0) {
94
+ for (const [index, link] of openingLinks.entries()) {
95
+ openingItems.push({
96
+ end: link.end,
97
+ open: link.open,
98
+ close: link.close,
99
+ kind: "link",
100
+ index,
101
+ });
102
+ }
103
+ }
104
+ const openingStyles = startsAt.get(pos);
105
+ if (openingStyles) {
106
+ for (const [index, span] of openingStyles.entries()) {
107
+ const marker = styleMarkers[span.style];
108
+ if (!marker) {
109
+ continue;
110
+ }
111
+ openingItems.push({
112
+ end: span.end,
113
+ open: marker.open,
114
+ close: marker.close,
115
+ kind: "style",
116
+ style: span.style,
117
+ index,
118
+ });
119
+ }
120
+ }
121
+ if (openingItems.length > 0) {
122
+ openingItems.sort((a, b) => {
123
+ if (a.end !== b.end) {
124
+ return b.end - a.end;
125
+ }
126
+ if (a.kind !== b.kind) {
127
+ return a.kind === "link" ? -1 : 1;
128
+ }
129
+ if (a.kind === "style" && b.kind === "style") {
130
+ return (STYLE_RANK.get(a.style) ?? 0) - (STYLE_RANK.get(b.style) ?? 0);
131
+ }
132
+ return a.index - b.index;
133
+ });
134
+ for (const item of openingItems) {
135
+ out += item.open;
136
+ stack.push({ close: item.close, end: item.end });
137
+ }
138
+ }
139
+ const next = points[i + 1];
140
+ if (next === undefined) {
141
+ break;
142
+ }
143
+ if (next > pos) {
144
+ out += options.escapeText(text.slice(pos, next));
145
+ }
146
+ }
147
+ return out;
148
+ }