verybot 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/README.md +167 -0
  2. package/dist/aliases/store.d.ts +21 -0
  3. package/dist/aliases/store.js +148 -0
  4. package/dist/aliases/types.d.ts +6 -0
  5. package/dist/aliases/types.js +1 -0
  6. package/dist/brain/agent-registry.d.ts +96 -0
  7. package/dist/brain/agent-registry.js +141 -0
  8. package/dist/brain/agent.d.ts +167 -0
  9. package/dist/brain/agent.js +932 -0
  10. package/dist/brain/channel-store.d.ts +27 -0
  11. package/dist/brain/channel-store.js +78 -0
  12. package/dist/brain/compaction.d.ts +37 -0
  13. package/dist/brain/compaction.js +214 -0
  14. package/dist/brain/context.d.ts +43 -0
  15. package/dist/brain/context.js +139 -0
  16. package/dist/brain/delegation-store.d.ts +33 -0
  17. package/dist/brain/delegation-store.js +106 -0
  18. package/dist/brain/loop.d.ts +24 -0
  19. package/dist/brain/loop.js +318 -0
  20. package/dist/brain/mcp-adapter.d.ts +43 -0
  21. package/dist/brain/mcp-adapter.js +244 -0
  22. package/dist/brain/memory-extractor.d.ts +26 -0
  23. package/dist/brain/memory-extractor.js +82 -0
  24. package/dist/brain/providers.d.ts +14 -0
  25. package/dist/brain/providers.js +85 -0
  26. package/dist/brain/queue.d.ts +18 -0
  27. package/dist/brain/queue.js +111 -0
  28. package/dist/brain/run-tools.d.ts +50 -0
  29. package/dist/brain/run-tools.js +136 -0
  30. package/dist/brain/session-key.d.ts +23 -0
  31. package/dist/brain/session-key.js +41 -0
  32. package/dist/brain/session-state.d.ts +36 -0
  33. package/dist/brain/session-state.js +51 -0
  34. package/dist/brain/session-store.d.ts +50 -0
  35. package/dist/brain/session-store.js +207 -0
  36. package/dist/brain/session.d.ts +32 -0
  37. package/dist/brain/session.js +75 -0
  38. package/dist/brain/task-subscriber.d.ts +56 -0
  39. package/dist/brain/task-subscriber.js +317 -0
  40. package/dist/brain/user-content.d.ts +16 -0
  41. package/dist/brain/user-content.js +32 -0
  42. package/dist/brain/utils.d.ts +4 -0
  43. package/dist/brain/utils.js +26 -0
  44. package/dist/brain/worker-coordinator.d.ts +25 -0
  45. package/dist/brain/worker-coordinator.js +83 -0
  46. package/dist/channels/commands.d.ts +50 -0
  47. package/dist/channels/commands.js +132 -0
  48. package/dist/channels/discord/channel.d.ts +29 -0
  49. package/dist/channels/discord/channel.js +159 -0
  50. package/dist/channels/discord/markdown.d.ts +19 -0
  51. package/dist/channels/discord/markdown.js +62 -0
  52. package/dist/channels/manager.d.ts +29 -0
  53. package/dist/channels/manager.js +100 -0
  54. package/dist/channels/slack/channel.d.ts +37 -0
  55. package/dist/channels/slack/channel.js +227 -0
  56. package/dist/channels/slack/markdown.d.ts +19 -0
  57. package/dist/channels/slack/markdown.js +62 -0
  58. package/dist/channels/specs.d.ts +32 -0
  59. package/dist/channels/specs.js +99 -0
  60. package/dist/channels/telegram/channel.d.ts +29 -0
  61. package/dist/channels/telegram/channel.js +182 -0
  62. package/dist/channels/telegram/markdown.d.ts +17 -0
  63. package/dist/channels/telegram/markdown.js +66 -0
  64. package/dist/channels/types.d.ts +26 -0
  65. package/dist/channels/types.js +1 -0
  66. package/dist/channels/whatsapp/channel.d.ts +34 -0
  67. package/dist/channels/whatsapp/channel.js +276 -0
  68. package/dist/channels/whatsapp/markdown.d.ts +20 -0
  69. package/dist/channels/whatsapp/markdown.js +51 -0
  70. package/dist/cli/claude-login.d.ts +5 -0
  71. package/dist/cli/claude-login.js +47 -0
  72. package/dist/cli/config.d.ts +5 -0
  73. package/dist/cli/config.js +78 -0
  74. package/dist/cli/index.d.ts +11 -0
  75. package/dist/cli/index.js +96 -0
  76. package/dist/computer/browser/actions.d.ts +31 -0
  77. package/dist/computer/browser/actions.js +148 -0
  78. package/dist/computer/browser/context-manager.d.ts +28 -0
  79. package/dist/computer/browser/context-manager.js +78 -0
  80. package/dist/computer/browser/manager.d.ts +91 -0
  81. package/dist/computer/browser/manager.js +344 -0
  82. package/dist/computer/browser/profile-badge.d.ts +13 -0
  83. package/dist/computer/browser/profile-badge.js +67 -0
  84. package/dist/computer/browser/screenshot.d.ts +5 -0
  85. package/dist/computer/browser/screenshot.js +21 -0
  86. package/dist/computer/browser/snapshot.d.ts +30 -0
  87. package/dist/computer/browser/snapshot.js +242 -0
  88. package/dist/computer/browser/tools.d.ts +5 -0
  89. package/dist/computer/browser/tools.js +167 -0
  90. package/dist/computer/browser/types.d.ts +26 -0
  91. package/dist/computer/browser/types.js +1 -0
  92. package/dist/computer/desktop/adapter.d.ts +25 -0
  93. package/dist/computer/desktop/adapter.js +11 -0
  94. package/dist/computer/desktop/macos.d.ts +24 -0
  95. package/dist/computer/desktop/macos.js +223 -0
  96. package/dist/computer/desktop/tools.d.ts +25 -0
  97. package/dist/computer/desktop/tools.js +114 -0
  98. package/dist/config/agent-config.d.ts +55 -0
  99. package/dist/config/agent-config.js +16 -0
  100. package/dist/config/model-catalog.d.ts +22 -0
  101. package/dist/config/model-catalog.js +112 -0
  102. package/dist/config/model-spec.d.ts +8 -0
  103. package/dist/config/model-spec.js +66 -0
  104. package/dist/config/store.d.ts +25 -0
  105. package/dist/config/store.js +143 -0
  106. package/dist/config.d.ts +110 -0
  107. package/dist/config.js +259 -0
  108. package/dist/control-ui/assets/index-Cbl7G5Sc.css +1 -0
  109. package/dist/control-ui/assets/index-Cu1P4C62.js +266 -0
  110. package/dist/control-ui/assets/noto-sans-cyrillic-ext-wght-normal-DSNfmdVt.woff2 +0 -0
  111. package/dist/control-ui/assets/noto-sans-cyrillic-wght-normal-B2hlT84T.woff2 +0 -0
  112. package/dist/control-ui/assets/noto-sans-devanagari-wght-normal-Cv-Vwajv.woff2 +0 -0
  113. package/dist/control-ui/assets/noto-sans-greek-ext-wght-normal-12T8GTDR.woff2 +0 -0
  114. package/dist/control-ui/assets/noto-sans-greek-wght-normal-Ymb6dZNd.woff2 +0 -0
  115. package/dist/control-ui/assets/noto-sans-latin-ext-wght-normal-W1qJv59z.woff2 +0 -0
  116. package/dist/control-ui/assets/noto-sans-latin-wght-normal-BYSzYMf3.woff2 +0 -0
  117. package/dist/control-ui/assets/noto-sans-vietnamese-wght-normal-DLTJy58D.woff2 +0 -0
  118. package/dist/control-ui/index.html +14 -0
  119. package/dist/control-ui/vite.svg +1 -0
  120. package/dist/events.d.ts +2 -0
  121. package/dist/events.js +11 -0
  122. package/dist/gateway/broadcast.d.ts +5 -0
  123. package/dist/gateway/broadcast.js +33 -0
  124. package/dist/gateway/methods/aliases.d.ts +17 -0
  125. package/dist/gateway/methods/aliases.js +22 -0
  126. package/dist/gateway/methods/chat.d.ts +33 -0
  127. package/dist/gateway/methods/chat.js +37 -0
  128. package/dist/gateway/methods/config.d.ts +14 -0
  129. package/dist/gateway/methods/config.js +24 -0
  130. package/dist/gateway/methods/models.d.ts +10 -0
  131. package/dist/gateway/methods/models.js +14 -0
  132. package/dist/gateway/methods/playbooks.d.ts +45 -0
  133. package/dist/gateway/methods/playbooks.js +488 -0
  134. package/dist/gateway/methods/prompt-templates.d.ts +27 -0
  135. package/dist/gateway/methods/prompt-templates.js +106 -0
  136. package/dist/gateway/methods/scheduler.d.ts +62 -0
  137. package/dist/gateway/methods/scheduler.js +129 -0
  138. package/dist/gateway/methods/sessions.d.ts +44 -0
  139. package/dist/gateway/methods/sessions.js +111 -0
  140. package/dist/gateway/methods/system.d.ts +12 -0
  141. package/dist/gateway/methods/system.js +39 -0
  142. package/dist/gateway/methods/tasks.d.ts +40 -0
  143. package/dist/gateway/methods/tasks.js +151 -0
  144. package/dist/gateway/methods/teams.d.ts +69 -0
  145. package/dist/gateway/methods/teams.js +376 -0
  146. package/dist/gateway/methods/tools.d.ts +6 -0
  147. package/dist/gateway/methods/tools.js +7 -0
  148. package/dist/gateway/methods/whatsapp.d.ts +19 -0
  149. package/dist/gateway/methods/whatsapp.js +35 -0
  150. package/dist/gateway/rpc.d.ts +38 -0
  151. package/dist/gateway/rpc.js +79 -0
  152. package/dist/gateway/server.d.ts +9 -0
  153. package/dist/gateway/server.js +137 -0
  154. package/dist/index.d.ts +1 -0
  155. package/dist/index.js +254 -0
  156. package/dist/integrations/github.d.ts +7 -0
  157. package/dist/integrations/github.js +133 -0
  158. package/dist/integrations/mcp.d.ts +7 -0
  159. package/dist/integrations/mcp.js +106 -0
  160. package/dist/integrations/registry.d.ts +47 -0
  161. package/dist/integrations/registry.js +332 -0
  162. package/dist/integrations/scanner.d.ts +10 -0
  163. package/dist/integrations/scanner.js +122 -0
  164. package/dist/integrations/twitter.d.ts +10 -0
  165. package/dist/integrations/twitter.js +120 -0
  166. package/dist/integrations/types.d.ts +72 -0
  167. package/dist/integrations/types.js +1 -0
  168. package/dist/logger.d.ts +16 -0
  169. package/dist/logger.js +104 -0
  170. package/dist/markdown/chunk.d.ts +9 -0
  171. package/dist/markdown/chunk.js +52 -0
  172. package/dist/markdown/ir.d.ts +37 -0
  173. package/dist/markdown/ir.js +529 -0
  174. package/dist/markdown/render.d.ts +22 -0
  175. package/dist/markdown/render.js +148 -0
  176. package/dist/markdown/table-render.d.ts +43 -0
  177. package/dist/markdown/table-render.js +219 -0
  178. package/dist/markdown/tables.d.ts +17 -0
  179. package/dist/markdown/tables.js +27 -0
  180. package/dist/memory/embedding.d.ts +16 -0
  181. package/dist/memory/embedding.js +66 -0
  182. package/dist/memory/explicit.d.ts +16 -0
  183. package/dist/memory/explicit.js +29 -0
  184. package/dist/memory/extractor.d.ts +13 -0
  185. package/dist/memory/extractor.js +82 -0
  186. package/dist/memory/search.d.ts +15 -0
  187. package/dist/memory/search.js +57 -0
  188. package/dist/memory/session-learning.d.ts +23 -0
  189. package/dist/memory/session-learning.js +55 -0
  190. package/dist/memory/store.d.ts +36 -0
  191. package/dist/memory/store.js +334 -0
  192. package/dist/memory/types.d.ts +9 -0
  193. package/dist/memory/types.js +2 -0
  194. package/dist/paths.d.ts +28 -0
  195. package/dist/paths.js +48 -0
  196. package/dist/prompt-templates/builtins/index.d.ts +4 -0
  197. package/dist/prompt-templates/builtins/index.js +5 -0
  198. package/dist/prompt-templates/builtins/planner.d.ts +4 -0
  199. package/dist/prompt-templates/builtins/planner.js +77 -0
  200. package/dist/prompt-templates/store.d.ts +45 -0
  201. package/dist/prompt-templates/store.js +224 -0
  202. package/dist/prompt-templates/types.d.ts +10 -0
  203. package/dist/prompt-templates/types.js +1 -0
  204. package/dist/scheduler/connected-channels.d.ts +24 -0
  205. package/dist/scheduler/connected-channels.js +57 -0
  206. package/dist/scheduler/scheduler.d.ts +22 -0
  207. package/dist/scheduler/scheduler.js +132 -0
  208. package/dist/scheduler/store.d.ts +27 -0
  209. package/dist/scheduler/store.js +205 -0
  210. package/dist/scheduler/types.d.ts +29 -0
  211. package/dist/scheduler/types.js +1 -0
  212. package/dist/security/command-validator.d.ts +22 -0
  213. package/dist/security/command-validator.js +160 -0
  214. package/dist/security/docker-sandbox.d.ts +48 -0
  215. package/dist/security/docker-sandbox.js +218 -0
  216. package/dist/security/env-filter.d.ts +8 -0
  217. package/dist/security/env-filter.js +41 -0
  218. package/dist/skills/loader.d.ts +33 -0
  219. package/dist/skills/loader.js +132 -0
  220. package/dist/skills/prompt.d.ts +6 -0
  221. package/dist/skills/prompt.js +17 -0
  222. package/dist/skills/read-tool.d.ts +7 -0
  223. package/dist/skills/read-tool.js +24 -0
  224. package/dist/skills/scanner.d.ts +6 -0
  225. package/dist/skills/scanner.js +73 -0
  226. package/dist/skills/types.d.ts +15 -0
  227. package/dist/skills/types.js +1 -0
  228. package/dist/tasks/inline-attachment-content.d.ts +9 -0
  229. package/dist/tasks/inline-attachment-content.js +64 -0
  230. package/dist/tasks/store.d.ts +112 -0
  231. package/dist/tasks/store.js +519 -0
  232. package/dist/tasks/types.d.ts +129 -0
  233. package/dist/tasks/types.js +80 -0
  234. package/dist/teams/status-config.d.ts +8 -0
  235. package/dist/teams/status-config.js +40 -0
  236. package/dist/teams/store.d.ts +111 -0
  237. package/dist/teams/store.js +671 -0
  238. package/dist/teams/types.d.ts +30 -0
  239. package/dist/teams/types.js +1 -0
  240. package/dist/tools/bash.d.ts +18 -0
  241. package/dist/tools/bash.js +64 -0
  242. package/dist/tools/channel-history.d.ts +10 -0
  243. package/dist/tools/channel-history.js +43 -0
  244. package/dist/tools/delegate.d.ts +20 -0
  245. package/dist/tools/delegate.js +299 -0
  246. package/dist/tools/fs.d.ts +4 -0
  247. package/dist/tools/fs.js +335 -0
  248. package/dist/tools/integration-toggle.d.ts +14 -0
  249. package/dist/tools/integration-toggle.js +47 -0
  250. package/dist/tools/memory.d.ts +13 -0
  251. package/dist/tools/memory.js +59 -0
  252. package/dist/tools/prompt-templates.d.ts +7 -0
  253. package/dist/tools/prompt-templates.js +133 -0
  254. package/dist/tools/registry.d.ts +6 -0
  255. package/dist/tools/registry.js +9 -0
  256. package/dist/tools/schedule.d.ts +8 -0
  257. package/dist/tools/schedule.js +219 -0
  258. package/dist/tools/speak.d.ts +10 -0
  259. package/dist/tools/speak.js +56 -0
  260. package/dist/tools/tasks.d.ts +67 -0
  261. package/dist/tools/tasks.js +288 -0
  262. package/dist/tools/teams.d.ts +22 -0
  263. package/dist/tools/teams.js +470 -0
  264. package/dist/tools/web-fetch.d.ts +3 -0
  265. package/dist/tools/web-fetch.js +22 -0
  266. package/dist/tts/edge.d.ts +10 -0
  267. package/dist/tts/edge.js +60 -0
  268. package/dist/tts/speak.d.ts +12 -0
  269. package/dist/tts/speak.js +81 -0
  270. package/dist/tts/transcribe.d.ts +5 -0
  271. package/dist/tts/transcribe.js +40 -0
  272. package/dist/utils.d.ts +5 -0
  273. package/dist/utils.js +22 -0
  274. package/dist/version.d.ts +1 -0
  275. package/dist/version.js +13 -0
  276. package/package.json +102 -0
  277. 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
+ }