@nodetool-ai/telegram 0.8.1

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 (59) hide show
  1. package/README.md +49 -0
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/bot-api.d.ts +115 -0
  4. package/dist/bot-api.d.ts.map +1 -0
  5. package/dist/bot-api.js +145 -0
  6. package/dist/bot-api.js.map +1 -0
  7. package/dist/chunk.d.ts +36 -0
  8. package/dist/chunk.d.ts.map +1 -0
  9. package/dist/chunk.js +280 -0
  10. package/dist/chunk.js.map +1 -0
  11. package/dist/cli.d.ts +10 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +62 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/commands.d.ts +83 -0
  16. package/dist/commands.d.ts.map +1 -0
  17. package/dist/commands.js +191 -0
  18. package/dist/commands.js.map +1 -0
  19. package/dist/config.d.ts +65 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +139 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/frame-renderer.d.ts +135 -0
  24. package/dist/frame-renderer.d.ts.map +1 -0
  25. package/dist/frame-renderer.js +407 -0
  26. package/dist/frame-renderer.js.map +1 -0
  27. package/dist/identity-client.d.ts +132 -0
  28. package/dist/identity-client.d.ts.map +1 -0
  29. package/dist/identity-client.js +204 -0
  30. package/dist/identity-client.js.map +1 -0
  31. package/dist/index.d.ts +56 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +90 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/markdown-html.d.ts +32 -0
  36. package/dist/markdown-html.d.ts.map +1 -0
  37. package/dist/markdown-html.js +251 -0
  38. package/dist/markdown-html.js.map +1 -0
  39. package/dist/nodetool-client.d.ts +32 -0
  40. package/dist/nodetool-client.d.ts.map +1 -0
  41. package/dist/nodetool-client.js +127 -0
  42. package/dist/nodetool-client.js.map +1 -0
  43. package/dist/register-commands.d.ts +24 -0
  44. package/dist/register-commands.d.ts.map +1 -0
  45. package/dist/register-commands.js +29 -0
  46. package/dist/register-commands.js.map +1 -0
  47. package/dist/strings.d.ts +7 -0
  48. package/dist/strings.d.ts.map +1 -0
  49. package/dist/strings.js +13 -0
  50. package/dist/strings.js.map +1 -0
  51. package/dist/telegram-adapter.d.ts +100 -0
  52. package/dist/telegram-adapter.d.ts.map +1 -0
  53. package/dist/telegram-adapter.js +366 -0
  54. package/dist/telegram-adapter.js.map +1 -0
  55. package/dist/turn-router.d.ts +167 -0
  56. package/dist/turn-router.d.ts.map +1 -0
  57. package/dist/turn-router.js +360 -0
  58. package/dist/turn-router.js.map +1 -0
  59. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # @nodetool-ai/telegram
2
+
3
+ The Telegram bridge for NodeTool. It translates Telegram updates into
4
+ `chat_message` commands on a running NodeTool server's `/ws` chat protocol, and
5
+ the streamed `ProcessingMessage` frames back into Telegram messages. The agent
6
+ loop, tools, permissions, thread persistence and cost tracking stay on the
7
+ server — this package holds no user credentials and no conversation state.
8
+
9
+ Design: [docs/telegram-bot-design.md](../../docs/telegram-bot-design.md).
10
+ Plan: [docs/telegram-bot-implementation-plan.md](../../docs/telegram-bot-implementation-plan.md).
11
+
12
+ ## Status
13
+
14
+ Milestone M2 is landing in waves. This package currently ships the pure core:
15
+
16
+ | Module | What it owns |
17
+ |---|---|
18
+ | `src/config.ts` | Env + `telegram-bot.json`, zod-validated at the boundary |
19
+ | `src/chunk.ts` | 3800-char splitter that reopens fences and inline tags it cuts |
20
+ | `src/markdown-html.ts` | Agent markdown → Telegram HTML, plain-text fallback |
21
+ | `src/frame-renderer.ts` | Pure fold of server frames → render ops |
22
+
23
+ `startTelegramBot` / `stopTelegramBot` throw until the identity client, turn
24
+ router and Bot API adapter land (T2.5–T2.9).
25
+
26
+ ## Configuration
27
+
28
+ ```
29
+ TELEGRAM_BOT_TOKEN required (from @BotFather)
30
+ NODETOOL_API_URL default http://127.0.0.1:7777
31
+ NODETOOL_INTEGRATION_TOKEN required (the bot's service token)
32
+ TELEGRAM_WEBHOOK_URL optional; set = webhook mode, unset = long polling
33
+ TELEGRAM_WEBHOOK_SECRET required in webhook mode
34
+ ```
35
+
36
+ ```jsonc
37
+ // telegram-bot.json (optional)
38
+ {
39
+ "allowUsers": [], // Telegram user ids allowed to link; empty = anyone
40
+ "editThrottleMs": 1500,
41
+ "maxQueuedTurns": 3
42
+ }
43
+ ```
44
+
45
+ ## Tests
46
+
47
+ ```bash
48
+ npm run test --workspace=packages/telegram
49
+ ```
@@ -0,0 +1 @@
1
+ 2026-09-28T09:19:19.487Z
@@ -0,0 +1,115 @@
1
+ /**
2
+ * The Bot API surface the bridge uses — eight methods over `fetch`, no SDK
3
+ * (design §13). Everything HTTP about Telegram lives here: the URL shape, the
4
+ * `{ok, result, description}` envelope, and the two failures that are routine
5
+ * rather than exceptional (429 with `retry_after`, and 400 for text the parse
6
+ * mode rejects).
7
+ */
8
+ export declare const TELEGRAM_API_BASE = "https://api.telegram.org";
9
+ /** Max upload the Bot API accepts from a bot. */
10
+ export declare const TELEGRAM_UPLOAD_LIMIT_BYTES: number;
11
+ export interface BotApiOptions {
12
+ readonly botToken: string;
13
+ readonly fetch: typeof fetch;
14
+ /** Defaults to {@link TELEGRAM_API_BASE}. */
15
+ readonly baseUrl?: string;
16
+ }
17
+ /** A Bot API call that answered `ok: false` or a non-2xx status. */
18
+ export declare class BotApiError extends Error {
19
+ readonly method: string;
20
+ readonly status: number;
21
+ readonly description: string;
22
+ /** Seconds Telegram asked the bot to wait, when it answered 429. */
23
+ readonly retryAfterSeconds: number | null;
24
+ constructor(init: {
25
+ method: string;
26
+ status: number;
27
+ description: string;
28
+ retryAfterSeconds: number | null;
29
+ });
30
+ /** The text was rejected by the parse mode; resending unparsed will work. */
31
+ get isParseFailure(): boolean;
32
+ /** An edit whose text equals what the message already shows. */
33
+ get isUnmodified(): boolean;
34
+ /** Another `getUpdates` consumer holds the bot token. */
35
+ get isConflict(): boolean;
36
+ }
37
+ /** A Telegram message, narrowed to the fields the bridge reads. */
38
+ export interface TelegramMessage {
39
+ readonly message_id: number;
40
+ readonly text?: string;
41
+ readonly caption?: string;
42
+ readonly date?: number;
43
+ readonly chat: {
44
+ readonly id: number;
45
+ readonly type: string;
46
+ };
47
+ readonly from?: {
48
+ readonly id: number;
49
+ readonly username?: string;
50
+ readonly first_name?: string;
51
+ };
52
+ readonly entities?: readonly {
53
+ readonly type: string;
54
+ readonly offset: number;
55
+ readonly length: number;
56
+ }[];
57
+ readonly photo?: readonly unknown[];
58
+ readonly document?: unknown;
59
+ readonly voice?: unknown;
60
+ readonly audio?: unknown;
61
+ readonly video?: unknown;
62
+ }
63
+ export interface TelegramCallbackQuery {
64
+ readonly id: string;
65
+ readonly data?: string;
66
+ readonly from: {
67
+ readonly id: number;
68
+ };
69
+ readonly message?: {
70
+ readonly message_id: number;
71
+ readonly chat: {
72
+ readonly id: number;
73
+ readonly type: string;
74
+ };
75
+ };
76
+ }
77
+ export interface TelegramUpdate {
78
+ readonly update_id: number;
79
+ readonly message?: TelegramMessage;
80
+ readonly edited_message?: TelegramMessage;
81
+ readonly callback_query?: TelegramCallbackQuery;
82
+ }
83
+ /** One command as `setMyCommands` takes it. */
84
+ export interface BotCommandSpec {
85
+ readonly command: string;
86
+ readonly description: string;
87
+ }
88
+ /** Raw Bot API client. One method per call the bridge makes. */
89
+ export declare class BotApi {
90
+ private readonly botToken;
91
+ private readonly fetchImpl;
92
+ private readonly baseUrl;
93
+ constructor(options: BotApiOptions);
94
+ /** Call a Bot API method with a JSON body. */
95
+ call<T = unknown>(method: string, payload: Record<string, unknown>): Promise<T>;
96
+ /** Call a Bot API method with a multipart body, for file uploads. */
97
+ callMultipart<T = unknown>(method: string, form: FormData): Promise<T>;
98
+ /**
99
+ * Long-poll for updates. `timeout` is the Bot API's own long-poll seconds,
100
+ * so the request itself blocks rather than the bridge spinning.
101
+ */
102
+ getUpdates(offset: number, timeoutSeconds: number): Promise<TelegramUpdate[]>;
103
+ sendMessage(payload: Record<string, unknown>): Promise<TelegramMessage>;
104
+ editMessageText(payload: Record<string, unknown>): Promise<unknown>;
105
+ sendChatAction(chatId: string, action: string): Promise<unknown>;
106
+ answerCallbackQuery(callbackQueryId: string, text?: string): Promise<unknown>;
107
+ setMyCommands(commands: readonly BotCommandSpec[]): Promise<unknown>;
108
+ getMe(): Promise<{
109
+ id: number;
110
+ username?: string;
111
+ }>;
112
+ private url;
113
+ private unwrap;
114
+ }
115
+ //# sourceMappingURL=bot-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-api.d.ts","sourceRoot":"","sources":["../src/bot-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The Bot API surface the bridge uses — eight methods over `fetch`, no SDK
3
+ * (design §13). Everything HTTP about Telegram lives here: the URL shape, the
4
+ * `{ok, result, description}` envelope, and the two failures that are routine
5
+ * rather than exceptional (429 with `retry_after`, and 400 for text the parse
6
+ * mode rejects).
7
+ */
8
+ /** Base URL of the Bot API. Overridable so tests never resolve a real host. */
9
+ import { trimTrailingSlashes } from "./strings.js";
10
+ export const TELEGRAM_API_BASE = "https://api.telegram.org";
11
+ /** Max upload the Bot API accepts from a bot. */
12
+ export const TELEGRAM_UPLOAD_LIMIT_BYTES = 50 * 1024 * 1024;
13
+ /** A Bot API call that answered `ok: false` or a non-2xx status. */
14
+ export class BotApiError extends Error {
15
+ method;
16
+ status;
17
+ description;
18
+ /** Seconds Telegram asked the bot to wait, when it answered 429. */
19
+ retryAfterSeconds;
20
+ constructor(init) {
21
+ super(`Telegram ${init.method} failed (${init.status}): ${init.description}`);
22
+ this.name = "BotApiError";
23
+ this.method = init.method;
24
+ this.status = init.status;
25
+ this.description = init.description;
26
+ this.retryAfterSeconds = init.retryAfterSeconds;
27
+ }
28
+ /** The text was rejected by the parse mode; resending unparsed will work. */
29
+ get isParseFailure() {
30
+ return this.status === 400 && /can't parse entities/i.test(this.description);
31
+ }
32
+ /** An edit whose text equals what the message already shows. */
33
+ get isUnmodified() {
34
+ return this.status === 400 && /message is not modified/i.test(this.description);
35
+ }
36
+ /** Another `getUpdates` consumer holds the bot token. */
37
+ get isConflict() {
38
+ return this.status === 409;
39
+ }
40
+ }
41
+ function isRecord(value) {
42
+ return typeof value === "object" && value !== null && !Array.isArray(value);
43
+ }
44
+ function readRetryAfter(body) {
45
+ if (!isRecord(body)) {
46
+ return null;
47
+ }
48
+ const parameters = body.parameters;
49
+ if (!isRecord(parameters)) {
50
+ return null;
51
+ }
52
+ const value = parameters.retry_after;
53
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
54
+ }
55
+ function readDescription(body, fallback) {
56
+ if (isRecord(body) && typeof body.description === "string" && body.description.length > 0) {
57
+ return body.description;
58
+ }
59
+ return fallback;
60
+ }
61
+ /** Raw Bot API client. One method per call the bridge makes. */
62
+ export class BotApi {
63
+ botToken;
64
+ fetchImpl;
65
+ baseUrl;
66
+ constructor(options) {
67
+ this.botToken = options.botToken;
68
+ this.fetchImpl = options.fetch;
69
+ this.baseUrl = trimTrailingSlashes(options.baseUrl ?? TELEGRAM_API_BASE);
70
+ }
71
+ /** Call a Bot API method with a JSON body. */
72
+ async call(method, payload) {
73
+ const response = await this.fetchImpl(this.url(method), {
74
+ method: "POST",
75
+ headers: { "content-type": "application/json" },
76
+ body: JSON.stringify(payload)
77
+ });
78
+ return this.unwrap(method, response);
79
+ }
80
+ /** Call a Bot API method with a multipart body, for file uploads. */
81
+ async callMultipart(method, form) {
82
+ const response = await this.fetchImpl(this.url(method), { method: "POST", body: form });
83
+ return this.unwrap(method, response);
84
+ }
85
+ /**
86
+ * Long-poll for updates. `timeout` is the Bot API's own long-poll seconds,
87
+ * so the request itself blocks rather than the bridge spinning.
88
+ */
89
+ getUpdates(offset, timeoutSeconds) {
90
+ return this.call("getUpdates", {
91
+ offset,
92
+ timeout: timeoutSeconds,
93
+ allowed_updates: ["message", "callback_query"]
94
+ });
95
+ }
96
+ sendMessage(payload) {
97
+ return this.call("sendMessage", payload);
98
+ }
99
+ editMessageText(payload) {
100
+ return this.call("editMessageText", payload);
101
+ }
102
+ sendChatAction(chatId, action) {
103
+ return this.call("sendChatAction", { chat_id: chatId, action });
104
+ }
105
+ answerCallbackQuery(callbackQueryId, text) {
106
+ const payload = { callback_query_id: callbackQueryId };
107
+ if (text !== undefined) {
108
+ payload.text = text;
109
+ }
110
+ return this.call("answerCallbackQuery", payload);
111
+ }
112
+ setMyCommands(commands) {
113
+ return this.call("setMyCommands", { commands });
114
+ }
115
+ getMe() {
116
+ return this.call("getMe", {});
117
+ }
118
+ url(method) {
119
+ return `${this.baseUrl}/bot${this.botToken}/${method}`;
120
+ }
121
+ async unwrap(method, response) {
122
+ const text = await response.text();
123
+ let body = null;
124
+ if (text.length > 0) {
125
+ try {
126
+ body = JSON.parse(text);
127
+ }
128
+ catch {
129
+ // Telegram answers JSON; anything else is a proxy in the way, and the
130
+ // status is then the only signal.
131
+ body = null;
132
+ }
133
+ }
134
+ if (!response.ok || !(isRecord(body) && body.ok === true)) {
135
+ throw new BotApiError({
136
+ method,
137
+ status: response.status,
138
+ description: readDescription(body, text.slice(0, 200) || response.statusText),
139
+ retryAfterSeconds: readRetryAfter(body)
140
+ });
141
+ }
142
+ return body.result;
143
+ }
144
+ }
145
+ //# sourceMappingURL=bot-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bot-api.js","sourceRoot":"","sources":["../src/bot-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Splitting long agent output into Telegram-sized messages.
3
+ *
4
+ * Telegram caps a message at 4096 characters, so the bridge splits at 3800 to
5
+ * leave headroom for the tags a chunk has to reopen. Two things make this more
6
+ * than `slice()`:
7
+ *
8
+ * - A boundary must never land inside a markup token. Cutting `&amp;` in half
9
+ * or `<b` in half produces a message Telegram rejects outright.
10
+ * - A boundary inside a fenced code block or an open inline tag must close the
11
+ * markup and reopen it on the next chunk, or every following chunk renders
12
+ * as broken HTML.
13
+ *
14
+ * The scanner therefore understands both markdown fences and the five HTML
15
+ * tags Telegram's HTML parse mode accepts, so the same function is correct
16
+ * whether it is handed raw agent markdown or the converted HTML.
17
+ */
18
+ /** Default split length: 4096 minus headroom for reopened markup. */
19
+ export declare const DEFAULT_CHUNK_MAX = 3800;
20
+ /** Telegram's hard limit on a text message. */
21
+ export declare const TELEGRAM_MESSAGE_LIMIT = 4096;
22
+ /**
23
+ * Split `text` into chunks no longer than `max`, reopening any fence or inline
24
+ * tag a chunk was cut inside of. Every returned chunk is non-empty.
25
+ */
26
+ export declare function chunkText(text: string, max?: number): string[];
27
+ /**
28
+ * Split off the largest leading chunk that fits in `max`, returning it with
29
+ * the untouched remainder. The renderer uses this for rollover: it needs the
30
+ * rest as source text, not as a finished chunk.
31
+ */
32
+ export declare function splitOnce(text: string, max?: number): {
33
+ head: string;
34
+ rest: string;
35
+ };
36
+ //# sourceMappingURL=chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,+CAA+C;AAC/C,eAAO,MAAM,sBAAsB,OAAO,CAAC;AA4N3C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,MAA0B,GAAG,MAAM,EAAE,CA2DjF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAA0B,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAgBhC"}
package/dist/chunk.js ADDED
@@ -0,0 +1,280 @@
1
+ /**
2
+ * Splitting long agent output into Telegram-sized messages.
3
+ *
4
+ * Telegram caps a message at 4096 characters, so the bridge splits at 3800 to
5
+ * leave headroom for the tags a chunk has to reopen. Two things make this more
6
+ * than `slice()`:
7
+ *
8
+ * - A boundary must never land inside a markup token. Cutting `&amp;` in half
9
+ * or `<b` in half produces a message Telegram rejects outright.
10
+ * - A boundary inside a fenced code block or an open inline tag must close the
11
+ * markup and reopen it on the next chunk, or every following chunk renders
12
+ * as broken HTML.
13
+ *
14
+ * The scanner therefore understands both markdown fences and the five HTML
15
+ * tags Telegram's HTML parse mode accepts, so the same function is correct
16
+ * whether it is handed raw agent markdown or the converted HTML.
17
+ */
18
+ /** Default split length: 4096 minus headroom for reopened markup. */
19
+ export const DEFAULT_CHUNK_MAX = 3800;
20
+ /** Telegram's hard limit on a text message. */
21
+ export const TELEGRAM_MESSAGE_LIMIT = 4096;
22
+ /** Tags Telegram's HTML parse mode understands. */
23
+ const SUPPORTED_TAGS = new Set(["b", "strong", "i", "em", "u", "s", "code", "pre", "a"]);
24
+ const EMPTY_STATE = { fence: null, tags: [] };
25
+ const FENCE_LINE = /^ {0,3}(`{3,}|~{3,})(.*)$/;
26
+ // No whitespace tolerated after "<" or "/": Telegram's HTML mode rejects it,
27
+ // our converter never emits it, and the adjacent-\s* ambiguity it needed is
28
+ // quadratic on adversarial input (CodeQL js/polynomial-redos).
29
+ const TAG = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)(\s[^<>]*)?>/;
30
+ const ENTITY = /^&(#[0-9]{1,7}|#[xX][0-9a-fA-F]{1,6}|[a-zA-Z][a-zA-Z0-9]{1,31});/;
31
+ function fenceMarker(openingLine) {
32
+ const match = FENCE_LINE.exec(openingLine);
33
+ return match ? match[1] : "```";
34
+ }
35
+ /**
36
+ * Split the source into markup-atomic tokens. Fence delimiter lines are
37
+ * atomic; everything between them is plain text (a `<` inside a code block is
38
+ * content, not a tag).
39
+ */
40
+ function tokenize(text) {
41
+ const tokens = [];
42
+ let textStart = 0;
43
+ let i = 0;
44
+ let fenceOpen = null;
45
+ const flushText = (end) => {
46
+ if (end > textStart) {
47
+ tokens.push({
48
+ kind: "text",
49
+ start: textStart,
50
+ end,
51
+ raw: text.slice(textStart, end)
52
+ });
53
+ }
54
+ };
55
+ while (i < text.length) {
56
+ const atLineStart = i === 0 || text[i - 1] === "\n";
57
+ if (atLineStart) {
58
+ const lineEnd = text.indexOf("\n", i);
59
+ const line = text.slice(i, lineEnd === -1 ? text.length : lineEnd);
60
+ const match = FENCE_LINE.exec(line);
61
+ const closes = fenceOpen !== null && match !== null && match[1][0] === fenceMarker(fenceOpen)[0];
62
+ if (match !== null && (fenceOpen === null || closes)) {
63
+ flushText(i);
64
+ tokens.push({
65
+ kind: "fence",
66
+ start: i,
67
+ end: i + line.length,
68
+ raw: line
69
+ });
70
+ fenceOpen = fenceOpen === null ? line : null;
71
+ i += line.length;
72
+ textStart = i;
73
+ continue;
74
+ }
75
+ }
76
+ if (fenceOpen === null && text[i] === "<") {
77
+ const match = TAG.exec(text.slice(i));
78
+ if (match !== null && SUPPORTED_TAGS.has(match[2].toLowerCase())) {
79
+ flushText(i);
80
+ tokens.push({
81
+ kind: match[1] === "/" ? "tag-close" : "tag-open",
82
+ start: i,
83
+ end: i + match[0].length,
84
+ raw: match[0],
85
+ name: match[2].toLowerCase()
86
+ });
87
+ i += match[0].length;
88
+ textStart = i;
89
+ continue;
90
+ }
91
+ }
92
+ if (fenceOpen === null && text[i] === "&") {
93
+ const match = ENTITY.exec(text.slice(i));
94
+ if (match !== null) {
95
+ flushText(i);
96
+ tokens.push({
97
+ kind: "entity",
98
+ start: i,
99
+ end: i + match[0].length,
100
+ raw: match[0]
101
+ });
102
+ i += match[0].length;
103
+ textStart = i;
104
+ continue;
105
+ }
106
+ }
107
+ i += 1;
108
+ }
109
+ flushText(text.length);
110
+ return tokens;
111
+ }
112
+ function applyToken(state, token) {
113
+ switch (token.kind) {
114
+ case "fence":
115
+ return { fence: state.fence === null ? token.raw : null, tags: state.tags };
116
+ case "tag-open":
117
+ return { fence: state.fence, tags: [...state.tags, token.raw] };
118
+ case "tag-close": {
119
+ const tags = [...state.tags];
120
+ for (let i = tags.length - 1; i >= 0; i -= 1) {
121
+ if (tagNameOf(tags[i]) === token.name) {
122
+ tags.splice(i, 1);
123
+ return { fence: state.fence, tags };
124
+ }
125
+ }
126
+ return state;
127
+ }
128
+ default:
129
+ return state;
130
+ }
131
+ }
132
+ function tagNameOf(openingTag) {
133
+ const match = TAG.exec(openingTag);
134
+ return match ? match[2].toLowerCase() : "";
135
+ }
136
+ /** Markup to reopen at the start of a chunk that begins mid-markup. */
137
+ function prefixFor(state) {
138
+ const tags = state.tags.join("");
139
+ return state.fence === null ? tags : `${tags}${state.fence}\n`;
140
+ }
141
+ /** Markup to close at the end of a chunk that ends mid-markup. */
142
+ function suffixFor(state) {
143
+ const closers = [...state.tags]
144
+ .reverse()
145
+ .map((tag) => `</${tagNameOf(tag)}>`)
146
+ .join("");
147
+ return state.fence === null ? closers : `\n${fenceMarker(state.fence)}${closers}`;
148
+ }
149
+ /**
150
+ * Nudge `index` off any markup token it would cut in half, moving left to the
151
+ * token's start. Returns -1 when no safe index at or below `index` exists.
152
+ */
153
+ function safeIndex(tokens, index) {
154
+ for (const token of tokens) {
155
+ if (index <= token.start) {
156
+ return index;
157
+ }
158
+ if (index < token.end) {
159
+ return token.kind === "text" ? index : token.start;
160
+ }
161
+ }
162
+ return index;
163
+ }
164
+ /** State of the markup after everything strictly before `index`. */
165
+ function stateAt(tokens, from, index) {
166
+ let state = from;
167
+ for (const token of tokens) {
168
+ if (token.end > index) {
169
+ break;
170
+ }
171
+ state = applyToken(state, token);
172
+ }
173
+ return state;
174
+ }
175
+ /**
176
+ * Best split offset inside `text[0, budget]`, preferring a paragraph break,
177
+ * then a line break, then a word break, and finally a hard cut. Boundaries
178
+ * that would cut a markup token in half are moved left off it.
179
+ */
180
+ function findBoundary(text, tokens, budget) {
181
+ const window = text.slice(0, budget);
182
+ const floor = Math.floor(budget * 0.3);
183
+ const candidates = [
184
+ window.lastIndexOf("\n\n") >= 0 ? window.lastIndexOf("\n\n") + 2 : -1,
185
+ window.lastIndexOf("\n") >= 0 ? window.lastIndexOf("\n") + 1 : -1,
186
+ window.lastIndexOf(" ") >= 0 ? window.lastIndexOf(" ") + 1 : -1
187
+ ];
188
+ for (const candidate of candidates) {
189
+ if (candidate <= floor) {
190
+ continue;
191
+ }
192
+ const safe = safeIndex(tokens, candidate);
193
+ if (safe > 0) {
194
+ return safe;
195
+ }
196
+ }
197
+ const hard = safeIndex(tokens, budget);
198
+ return hard > 0 ? hard : budget;
199
+ }
200
+ /**
201
+ * Split `text` into chunks no longer than `max`, reopening any fence or inline
202
+ * tag a chunk was cut inside of. Every returned chunk is non-empty.
203
+ */
204
+ export function chunkText(text, max = DEFAULT_CHUNK_MAX) {
205
+ if (max <= 0) {
206
+ throw new Error("chunkText: max must be greater than zero");
207
+ }
208
+ if (text.length === 0) {
209
+ return [];
210
+ }
211
+ if (text.length <= max) {
212
+ const single = text.trimEnd();
213
+ return single.length > 0 ? [single] : [];
214
+ }
215
+ const chunks = [];
216
+ let remaining = text;
217
+ let carried = EMPTY_STATE;
218
+ while (remaining.length > 0) {
219
+ const tokens = tokenize(remaining);
220
+ const prefix = prefixFor(carried);
221
+ if (prefix.length + remaining.length <= max) {
222
+ const tail = (prefix + remaining).trimEnd();
223
+ if (tail.length > 0) {
224
+ chunks.push(tail);
225
+ }
226
+ break;
227
+ }
228
+ // The suffix depends on the boundary, and the boundary on the suffix.
229
+ // Two passes settle it: guess with no suffix, then re-cut with the real one.
230
+ let budget = max - prefix.length;
231
+ let boundary = findBoundary(remaining, tokens, budget);
232
+ let endState = stateAt(tokens, carried, boundary);
233
+ let suffix = suffixFor(endState);
234
+ if (prefix.length + boundary + suffix.length > max) {
235
+ budget = Math.max(1, max - prefix.length - suffix.length);
236
+ boundary = findBoundary(remaining, tokens, budget);
237
+ endState = stateAt(tokens, carried, boundary);
238
+ suffix = suffixFor(endState);
239
+ }
240
+ if (boundary <= 0) {
241
+ // Nothing splittable fits — emit the whole remainder rather than loop.
242
+ chunks.push((prefix + remaining).trimEnd());
243
+ break;
244
+ }
245
+ const body = remaining.slice(0, boundary).trimEnd();
246
+ const chunk = `${prefix}${body}${suffix}`;
247
+ if (chunk.length > 0) {
248
+ chunks.push(chunk);
249
+ }
250
+ carried = endState;
251
+ remaining = remaining.slice(boundary).replace(/^[ \t]*\n?/, "");
252
+ if (remaining.trim().length === 0) {
253
+ break;
254
+ }
255
+ }
256
+ return chunks.filter((chunk) => chunk.length > 0);
257
+ }
258
+ /**
259
+ * Split off the largest leading chunk that fits in `max`, returning it with
260
+ * the untouched remainder. The renderer uses this for rollover: it needs the
261
+ * rest as source text, not as a finished chunk.
262
+ */
263
+ export function splitOnce(text, max = DEFAULT_CHUNK_MAX) {
264
+ if (max <= 0) {
265
+ throw new Error("splitOnce: max must be greater than zero");
266
+ }
267
+ if (text.length <= max) {
268
+ return { head: text, rest: "" };
269
+ }
270
+ const tokens = tokenize(text);
271
+ const boundary = findBoundary(text, tokens, max);
272
+ if (boundary <= 0) {
273
+ return { head: text.slice(0, max), rest: text.slice(max) };
274
+ }
275
+ return {
276
+ head: text.slice(0, boundary).trimEnd(),
277
+ rest: text.slice(boundary).replace(/^[ \t]*\n?/, "")
278
+ };
279
+ }
280
+ //# sourceMappingURL=chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.js","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":"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"}