switchroom 0.21.8 → 0.21.9

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 (29) hide show
  1. package/dist/cli/switchroom.js +100 -39
  2. package/dist/host-control/main.js +1 -1
  3. package/package.json +2 -2
  4. package/skills/switchroom-architecture/telegram.md +12 -10
  5. package/skills/switchroom-cli/SKILL.md +1 -1
  6. package/telegram-plugin/README.md +3 -1
  7. package/telegram-plugin/dist/gateway/gateway.js +151 -86
  8. package/telegram-plugin/format.ts +12 -4
  9. package/telegram-plugin/package.json +1 -1
  10. package/telegram-plugin/render/code-segments.ts +38 -4
  11. package/telegram-plugin/render/dollar-math-guard.ts +16 -1
  12. package/telegram-plugin/render/ir.ts +53 -3
  13. package/telegram-plugin/render/parse.ts +73 -14
  14. package/telegram-plugin/render/render.ts +53 -15
  15. package/telegram-plugin/render/unsupported-token-guard.ts +45 -80
  16. package/telegram-plugin/rich-send.ts +22 -7
  17. package/telegram-plugin/shared/bot-runtime.ts +3 -2
  18. package/telegram-plugin/telegraph.ts +6 -4
  19. package/telegram-plugin/tests/grammy-rich-message-types.test.ts +199 -0
  20. package/telegram-plugin/tests/render/dollar-math-guard.test.ts +43 -0
  21. package/telegram-plugin/tests/render/guard-composition.test.ts +102 -0
  22. package/telegram-plugin/tests/render/parse.test.ts +30 -5
  23. package/telegram-plugin/tests/render/render.test.ts +9 -4
  24. package/telegram-plugin/tests/render/rich-render.test.ts +46 -5
  25. package/telegram-plugin/tests/render/tg-entity.test.ts +242 -0
  26. package/telegram-plugin/tests/render/unsupported-token-guard.test.ts +66 -66
  27. package/telegram-plugin/tests/sent-text-capture.test.ts +3 -3
  28. package/telegram-plugin/tests/telegraph.test.ts +1 -1
  29. package/telegram-plugin/uat/scenarios/jtbd-rich-formatting-render-dm.test.ts +17 -8
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
2120
2120
  });
2121
2121
 
2122
2122
  // src/build-info.ts
2123
- var VERSION = "0.21.8", COMMIT_SHA = "d778afb6", COMMIT_DATE = "2026-08-13T03:44:10Z";
2123
+ var VERSION = "0.21.9", COMMIT_SHA = "08262924", COMMIT_DATE = "2026-08-13T12:13:46Z";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -33052,19 +33052,24 @@ You're writing for a phone screen in Telegram. Every reply renders as rich Markd
33052
33052
  decisive phrase inside a longer passage \u2014 rarer than bold, never stacked with it;
33053
33053
  fenced code blocks ALWAYS with a language
33054
33054
  hint (\`\`\`diff, \`\`\`json, \`\`\`bash \u2014 bare fence only for non-code fixed-width output);
33055
- and the flagship \u2014 the **expandable blockquote** \`**> first line\` + \`> continuation\`
33056
- for a long quote, stack trace, or detailed aside the reader can collapse. The \`**>\`
33057
- opener must be at the line start (column 0) \u2014 never indented \u2014 or it won't parse. Use it
33058
- whenever a bulky supporting block would otherwise dominate the message.
33059
-
33060
- Renders wrong on this path \u2014 never emit: underline (\`__x__\` renders as bold),
33061
- \`^sup^\`/\`~sub~\`, \`$math$\`, \`<details>\`, footnotes \`[^1]\`. Write "squared", not \`x^2^\`.
33055
+ and the flagship \u2014 the **collapsible \`<details>\` block**:
33056
+ \`<details><summary>Title</summary>\` + body + \`</details>\` for a long quote, stack
33057
+ trace, or detailed aside the reader opts into (add \`open\` to start expanded). Use it
33058
+ whenever a bulky supporting block would otherwise dominate the message. Never write
33059
+ \`**> \` for a collapsible \u2014 that is MarkdownV2 syntax; this path renders it as
33060
+ literal \`**>\` text.
33061
+
33062
+ Also native on this path: inline math \`$x^2+y^2$\`, footnotes (\`claim[^1]\` +
33063
+ \`[^1]: note\` at the end), task-list checkboxes \`- [ ]\`/\`- [x]\`, and the HTML tags
33064
+ \`<sub>\`/\`<sup>\`/\`<u>\`. Renders wrong \u2014 never emit: \`__x__\` (renders as BOLD, not
33065
+ underline \u2014 use \`<u>\`), or the caret/tilde shorthand \`^sup^\`/\`~sub~\` (literal noise \u2014
33066
+ use \`<sup>\`/\`<sub>\` or words).
33062
33067
 
33063
33068
  The framework normalizes mechanics in code on every outbound message: block spacing,
33064
33069
  em/en dashes, and \`\u2022\` bullet markers are
33065
- rewritten deterministically; unsupported tokens (the CARET \`^highlight^\` form \u2014
33066
- \`==highlight==\` renders fine \u2014 plus \`$math$\`, \`<details>\`, footnotes) are repaired;
33067
- long messages are chunked safely at 32768 chars (fences and
33070
+ rewritten deterministically; the unsupported caret \`^highlight^\` form is repaired
33071
+ (\`==highlight==\` renders fine); accidental currency \`$5M and $10M\` pairs are kept out
33072
+ of math mode; long messages are chunked safely at 32768 chars (fences and
33068
33073
  table rows never bisected); over-bolded messages get their bold stripped. Don't
33069
33074
  hand-tune spacing or fight it \u2014 write the content, the gateway makes typography
33070
33075
  consistent. Long before the cap, ask whether a wall of text is the right answer at all.
@@ -53750,7 +53755,7 @@ var init_doctor_flood_pressure = __esm(() => {
53750
53755
  FIX3 = "A flood ban is server-side and cannot be cleared early \u2014 cut the outbound " + "rate that earns it. Check the gateway's `send-gate stats` and " + "`edit-flood-fuse` lines for the class doing the sending (progress cards and " + "the worker feed are the usual culprits), and see " + "`telegram-plugin/edit-flood-fuse.ts` for the per-class ceilings.";
53751
53756
  });
53752
53757
 
53753
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/filter.js
53758
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/filter.js
53754
53759
  var require_filter = __commonJS((exports2) => {
53755
53760
  Object.defineProperty(exports2, "__esModule", { value: true });
53756
53761
  exports2.matchFilter = matchFilter;
@@ -54041,6 +54046,8 @@ var require_filter = __commonJS((exports2) => {
54041
54046
  checklist: { others_can_add_tasks: {}, others_can_mark_tasks_as_done: {} },
54042
54047
  checklist_tasks_done: {},
54043
54048
  checklist_tasks_added: {},
54049
+ community_chat_added: {},
54050
+ community_chat_removed: {},
54044
54051
  poll_option_added: {},
54045
54052
  poll_option_deleted: {},
54046
54053
  suggested_post_info: {},
@@ -54095,7 +54102,8 @@ var require_filter = __commonJS((exports2) => {
54095
54102
  message_reaction_count: MESSAGE_REACTION_COUNT_UPDATED_KEYS,
54096
54103
  chat_boost: {},
54097
54104
  removed_chat_boost: {},
54098
- purchased_paid_media: {}
54105
+ purchased_paid_media: {},
54106
+ subscription: { state: { canceled: {}, active: {}, failed: {} } }
54099
54107
  };
54100
54108
  var L1_SHORTCUTS = {
54101
54109
  "": ["message", "channel_post"],
@@ -54119,7 +54127,7 @@ var require_filter = __commonJS((exports2) => {
54119
54127
  };
54120
54128
  });
54121
54129
 
54122
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/context.js
54130
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/context.js
54123
54131
  var require_context = __commonJS((exports2) => {
54124
54132
  Object.defineProperty(exports2, "__esModule", { value: true });
54125
54133
  exports2.Context = undefined;
@@ -54360,6 +54368,9 @@ var require_context = __commonJS((exports2) => {
54360
54368
  get purchasedPaidMedia() {
54361
54369
  return this.update.purchased_paid_media;
54362
54370
  }
54371
+ get subscription() {
54372
+ return this.update.subscription;
54373
+ }
54363
54374
  get msg() {
54364
54375
  var _a, _b, _c, _d, _e, _f, _g, _h;
54365
54376
  return (_g = (_f = (_e = (_d = (_c = (_b = (_a = this.message) !== null && _a !== undefined ? _a : this.editedMessage) !== null && _b !== undefined ? _b : this.channelPost) !== null && _c !== undefined ? _c : this.editedChannelPost) !== null && _d !== undefined ? _d : this.businessMessage) !== null && _e !== undefined ? _e : this.editedBusinessMessage) !== null && _f !== undefined ? _f : this.guestMessage) !== null && _g !== undefined ? _g : (_h = this.callbackQuery) === null || _h === undefined ? undefined : _h.message;
@@ -54373,8 +54384,8 @@ var require_context = __commonJS((exports2) => {
54373
54384
  return (_a = this.msg) === null || _a === undefined ? undefined : _a.sender_chat;
54374
54385
  }
54375
54386
  get from() {
54376
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
54377
- return (_h = (_g = (_c = (_b = (_a = this.businessConnection) !== null && _a !== undefined ? _a : this.messageReaction) !== null && _b !== undefined ? _b : this.managedBot) !== null && _c !== undefined ? _c : (_f = (_e = (_d = this.chatBoost) === null || _d === undefined ? undefined : _d.boost) !== null && _e !== undefined ? _e : this.removedChatBoost) === null || _f === undefined ? undefined : _f.source) === null || _g === undefined ? undefined : _g.user) !== null && _h !== undefined ? _h : (_t = (_s = (_r = (_q = (_p = (_o = (_m = (_l = (_k = (_j = this.callbackQuery) !== null && _j !== undefined ? _j : this.msg) !== null && _k !== undefined ? _k : this.inlineQuery) !== null && _l !== undefined ? _l : this.chosenInlineResult) !== null && _m !== undefined ? _m : this.shippingQuery) !== null && _o !== undefined ? _o : this.preCheckoutQuery) !== null && _p !== undefined ? _p : this.myChatMember) !== null && _q !== undefined ? _q : this.chatMember) !== null && _r !== undefined ? _r : this.chatJoinRequest) !== null && _s !== undefined ? _s : this.purchasedPaidMedia) === null || _t === undefined ? undefined : _t.from;
54387
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
54388
+ return (_j = (_h = (_g = (_c = (_b = (_a = this.businessConnection) !== null && _a !== undefined ? _a : this.messageReaction) !== null && _b !== undefined ? _b : this.managedBot) !== null && _c !== undefined ? _c : (_f = (_e = (_d = this.chatBoost) === null || _d === undefined ? undefined : _d.boost) !== null && _e !== undefined ? _e : this.removedChatBoost) === null || _f === undefined ? undefined : _f.source) !== null && _g !== undefined ? _g : this.subscription) === null || _h === undefined ? undefined : _h.user) !== null && _j !== undefined ? _j : (_u = (_t = (_s = (_r = (_q = (_p = (_o = (_m = (_l = (_k = this.callbackQuery) !== null && _k !== undefined ? _k : this.msg) !== null && _l !== undefined ? _l : this.inlineQuery) !== null && _m !== undefined ? _m : this.chosenInlineResult) !== null && _o !== undefined ? _o : this.shippingQuery) !== null && _p !== undefined ? _p : this.preCheckoutQuery) !== null && _q !== undefined ? _q : this.myChatMember) !== null && _r !== undefined ? _r : this.chatMember) !== null && _s !== undefined ? _s : this.chatJoinRequest) !== null && _t !== undefined ? _t : this.purchasedPaidMedia) === null || _u === undefined ? undefined : _u.from;
54378
54389
  }
54379
54390
  get msgId() {
54380
54391
  var _a, _b, _c, _d, _e;
@@ -55033,6 +55044,22 @@ var require_context = __commonJS((exports2) => {
55033
55044
  var _a, _b, _c, _d, _e;
55034
55045
  return this.api.stopPoll(orThrow(this.chatId, "stopPoll"), orThrow((_d = (_b = (_a = this.msg) === null || _a === undefined ? undefined : _a.message_id) !== null && _b !== undefined ? _b : (_c = this.messageReaction) === null || _c === undefined ? undefined : _c.message_id) !== null && _d !== undefined ? _d : (_e = this.messageReactionCount) === null || _e === undefined ? undefined : _e.message_id, "stopPoll"), { business_connection_id: this.businessConnectionId, ...other }, signal);
55035
55046
  }
55047
+ editEphemeralMessageText(text, other, signal) {
55048
+ const msg = orThrow(this.msg, "editEphemeralMessageText");
55049
+ return this.api.editEphemeralMessageText(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageText").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageText"), text, other, signal);
55050
+ }
55051
+ editEphemeralMessageMedia(media, other, signal) {
55052
+ const msg = orThrow(this.msg, "editEphemeralMessageMedia");
55053
+ return this.api.editEphemeralMessageMedia(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageMedia").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageMedia"), media, other, signal);
55054
+ }
55055
+ editEphemeralMessageCaption(caption, other, signal) {
55056
+ const msg = orThrow(this.msg, "editEphemeralMessageCaption");
55057
+ return this.api.editEphemeralMessageCaption(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageCaption").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageCaption"), caption, other, signal);
55058
+ }
55059
+ editEphemeralMessageReplyMarkup(other, signal) {
55060
+ const msg = orThrow(this.msg, "editEphemeralMessageReplyMarkup");
55061
+ return this.api.editEphemeralMessageReplyMarkup(msg.chat.id, orThrow(msg.receiver_user, "editEphemeralMessageReplyMarkup").id, orThrow(msg.ephemeral_message_id, "editEphemeralMessageReplyMarkup"), other, signal);
55062
+ }
55036
55063
  deleteMessage(signal) {
55037
55064
  var _a, _b, _c, _d, _e;
55038
55065
  return this.api.deleteMessage(orThrow(this.chatId, "deleteMessage"), orThrow((_d = (_b = (_a = this.msg) === null || _a === undefined ? undefined : _a.message_id) !== null && _b !== undefined ? _b : (_c = this.messageReaction) === null || _c === undefined ? undefined : _c.message_id) !== null && _d !== undefined ? _d : (_e = this.messageReactionCount) === null || _e === undefined ? undefined : _e.message_id, "deleteMessage"), signal);
@@ -55040,6 +55067,10 @@ var require_context = __commonJS((exports2) => {
55040
55067
  deleteMessages(message_ids, signal) {
55041
55068
  return this.api.deleteMessages(orThrow(this.chatId, "deleteMessages"), message_ids, signal);
55042
55069
  }
55070
+ deleteEphemeralMessage(signal) {
55071
+ const msg = orThrow(this.msg, "deleteEphemeralMessage");
55072
+ return this.api.deleteEphemeralMessage(msg.chat.id, orThrow(msg.receiver_user, "deleteEphemeralMessage").id, orThrow(msg.ephemeral_message_id, "deleteEphemeralMessage"), signal);
55073
+ }
55043
55074
  deleteMessageReaction(other, signal) {
55044
55075
  const reaction = orThrow(this.messageReaction, "deleteMessageReaction");
55045
55076
  if (reaction.user !== undefined) {
@@ -55232,7 +55263,7 @@ var require_context = __commonJS((exports2) => {
55232
55263
  }
55233
55264
  });
55234
55265
 
55235
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/composer.js
55266
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/composer.js
55236
55267
  var require_composer2 = __commonJS((exports2) => {
55237
55268
  Object.defineProperty(exports2, "__esModule", { value: true });
55238
55269
  exports2.Composer = exports2.BotError = undefined;
@@ -56128,7 +56159,7 @@ var require_src = __commonJS((exports2, module) => {
56128
56159
  }
56129
56160
  });
56130
56161
 
56131
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/platform.node.js
56162
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/platform.node.js
56132
56163
  var require_platform_node = __commonJS((exports2) => {
56133
56164
  Object.defineProperty(exports2, "__esModule", { value: true });
56134
56165
  exports2.defaultAdapter = exports2.itrToStream = exports2.debug = undefined;
@@ -56156,19 +56187,21 @@ var require_platform_node = __commonJS((exports2) => {
56156
56187
  if (apiRoot.startsWith("https:")) {
56157
56188
  return {
56158
56189
  compress: true,
56159
- agent: getCached(httpsAgents, apiRoot, () => new https_1.Agent({ keepAlive: true }))
56190
+ agent: getCached(httpsAgents, apiRoot, () => new https_1.Agent({ keepAlive: true })),
56191
+ duplex: "half"
56160
56192
  };
56161
56193
  } else if (apiRoot.startsWith("http:")) {
56162
56194
  return {
56163
- agent: getCached(httpAgents, apiRoot, () => new http_1.Agent({ keepAlive: true }))
56195
+ agent: getCached(httpAgents, apiRoot, () => new http_1.Agent({ keepAlive: true })),
56196
+ duplex: "half"
56164
56197
  };
56165
56198
  } else
56166
- return {};
56199
+ return { duplex: "half" };
56167
56200
  }
56168
56201
  exports2.defaultAdapter = "express";
56169
56202
  });
56170
56203
 
56171
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/error.js
56204
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/error.js
56172
56205
  var require_error2 = __commonJS((exports2) => {
56173
56206
  Object.defineProperty(exports2, "__esModule", { value: true });
56174
56207
  exports2.HttpError = exports2.GrammyError = undefined;
@@ -59103,10 +59136,10 @@ var require_lib3 = __commonJS((exports2, module) => {
59103
59136
  exports2.AbortError = AbortError;
59104
59137
  });
59105
59138
 
59106
- // node_modules/.bun/@grammyjs+types@3.28.0/node_modules/@grammyjs/types/mod.js
59139
+ // node_modules/.bun/@grammyjs+types@4.0.0/node_modules/@grammyjs/types/mod.js
59107
59140
  var exports_mod = {};
59108
59141
 
59109
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/types.node.js
59142
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/types.node.js
59110
59143
  var require_types_node = __commonJS((exports2) => {
59111
59144
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
59112
59145
  if (k2 === undefined)
@@ -59197,7 +59230,7 @@ var require_types_node = __commonJS((exports2) => {
59197
59230
  }
59198
59231
  });
59199
59232
 
59200
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/types.js
59233
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/types.js
59201
59234
  var require_types = __commonJS((exports2) => {
59202
59235
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
59203
59236
  if (k2 === undefined)
@@ -59223,7 +59256,7 @@ var require_types = __commonJS((exports2) => {
59223
59256
  __exportStar(require_types_node(), exports2);
59224
59257
  });
59225
59258
 
59226
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/payload.js
59259
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/payload.js
59227
59260
  var require_payload = __commonJS((exports2) => {
59228
59261
  Object.defineProperty(exports2, "__esModule", { value: true });
59229
59262
  exports2.requiresFormDataUpload = requiresFormDataUpload;
@@ -59883,7 +59916,7 @@ var require_abort_controller = __commonJS((exports2, module) => {
59883
59916
  module.exports.AbortSignal = AbortSignal2;
59884
59917
  });
59885
59918
 
59886
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/shim.node.js
59919
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/shim.node.js
59887
59920
  var require_shim_node = __commonJS((exports2) => {
59888
59921
  Object.defineProperty(exports2, "__esModule", { value: true });
59889
59922
  exports2.fetch = exports2.AbortController = undefined;
@@ -59897,7 +59930,7 @@ var require_shim_node = __commonJS((exports2) => {
59897
59930
  } });
59898
59931
  });
59899
59932
 
59900
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/client.js
59933
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/client.js
59901
59934
  var require_client = __commonJS((exports2) => {
59902
59935
  Object.defineProperty(exports2, "__esModule", { value: true });
59903
59936
  exports2.createRawApi = createRawApi;
@@ -60077,7 +60110,7 @@ If you want to prevent such mistakes in the future, consider using TypeScript. h
60077
60110
  var shim_node_js_1 = require_shim_node();
60078
60111
  });
60079
60112
 
60080
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/core/api.js
60113
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/core/api.js
60081
60114
  var require_api = __commonJS((exports2) => {
60082
60115
  Object.defineProperty(exports2, "__esModule", { value: true });
60083
60116
  exports2.Api = undefined;
@@ -60518,12 +60551,39 @@ var require_api = __commonJS((exports2) => {
60518
60551
  stopPoll(chat_id, message_id, other, signal) {
60519
60552
  return this.raw.stopPoll({ chat_id, message_id, ...other }, signal);
60520
60553
  }
60554
+ editEphemeralMessageText(chat_id, receiver_user_id, ephemeral_message_id, text, other, signal) {
60555
+ return this.raw.editEphemeralMessageText({ chat_id, receiver_user_id, ephemeral_message_id, text, ...other }, signal);
60556
+ }
60557
+ editEphemeralMessageMedia(chat_id, receiver_user_id, ephemeral_message_id, media, other, signal) {
60558
+ return this.raw.editEphemeralMessageMedia({
60559
+ chat_id,
60560
+ receiver_user_id,
60561
+ ephemeral_message_id,
60562
+ media,
60563
+ ...other
60564
+ }, signal);
60565
+ }
60566
+ editEphemeralMessageCaption(chat_id, receiver_user_id, ephemeral_message_id, caption, other, signal) {
60567
+ return this.raw.editEphemeralMessageCaption({
60568
+ chat_id,
60569
+ receiver_user_id,
60570
+ ephemeral_message_id,
60571
+ caption,
60572
+ ...other
60573
+ }, signal);
60574
+ }
60575
+ editEphemeralMessageReplyMarkup(chat_id, receiver_user_id, ephemeral_message_id, other, signal) {
60576
+ return this.raw.editEphemeralMessageReplyMarkup({ chat_id, receiver_user_id, ephemeral_message_id, ...other }, signal);
60577
+ }
60521
60578
  deleteMessage(chat_id, message_id, signal) {
60522
60579
  return this.raw.deleteMessage({ chat_id, message_id }, signal);
60523
60580
  }
60524
60581
  deleteMessages(chat_id, message_ids, signal) {
60525
60582
  return this.raw.deleteMessages({ chat_id, message_ids }, signal);
60526
60583
  }
60584
+ deleteEphemeralMessage(chat_id, receiver_user_id, ephemeral_message_id, signal) {
60585
+ return this.raw.deleteEphemeralMessage({ chat_id, receiver_user_id, ephemeral_message_id }, signal);
60586
+ }
60527
60587
  deleteMessageReactionUser(chat_id, message_id, user_id, other, signal) {
60528
60588
  return this.raw.deleteMessageReaction({
60529
60589
  chat_id,
@@ -60765,7 +60825,7 @@ var require_api = __commonJS((exports2) => {
60765
60825
  exports2.Api = Api;
60766
60826
  });
60767
60827
 
60768
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/bot.js
60828
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/bot.js
60769
60829
  var require_bot = __commonJS((exports2) => {
60770
60830
  Object.defineProperty(exports2, "__esModule", { value: true });
60771
60831
  exports2.Bot = exports2.BotError = exports2.DEFAULT_UPDATE_TYPES = undefined;
@@ -60803,7 +60863,8 @@ var require_bot = __commonJS((exports2) => {
60803
60863
  "managed_bot",
60804
60864
  "chat_join_request",
60805
60865
  "chat_boost",
60806
- "removed_chat_boost"
60866
+ "removed_chat_boost",
60867
+ "subscription"
60807
60868
  ];
60808
60869
 
60809
60870
  class Bot extends composer_js_1.Composer {
@@ -61095,7 +61156,7 @@ On the other hand, if you actually know what you're doing and you do need to ins
61095
61156
  var shim_node_js_1 = require_shim_node();
61096
61157
  });
61097
61158
 
61098
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/constants.js
61159
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/constants.js
61099
61160
  var require_constants = __commonJS((exports2) => {
61100
61161
  Object.defineProperty(exports2, "__esModule", { value: true });
61101
61162
  exports2.API_CONSTANTS = undefined;
@@ -61132,7 +61193,7 @@ var require_constants = __commonJS((exports2) => {
61132
61193
  Object.freeze(exports2.API_CONSTANTS);
61133
61194
  });
61134
61195
 
61135
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/inline_query.js
61196
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/inline_query.js
61136
61197
  var require_inline_query = __commonJS((exports2) => {
61137
61198
  Object.defineProperty(exports2, "__esModule", { value: true });
61138
61199
  exports2.InlineQueryResultBuilder = undefined;
@@ -61337,7 +61398,7 @@ var require_inline_query = __commonJS((exports2) => {
61337
61398
  };
61338
61399
  });
61339
61400
 
61340
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/input_media.js
61401
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/input_media.js
61341
61402
  var require_input_media = __commonJS((exports2) => {
61342
61403
  Object.defineProperty(exports2, "__esModule", { value: true });
61343
61404
  exports2.InputMediaBuilder = undefined;
@@ -61360,7 +61421,7 @@ var require_input_media = __commonJS((exports2) => {
61360
61421
  };
61361
61422
  });
61362
61423
 
61363
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/keyboard.js
61424
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/keyboard.js
61364
61425
  var require_keyboard = __commonJS((exports2) => {
61365
61426
  Object.defineProperty(exports2, "__esModule", { value: true });
61366
61427
  exports2.InlineKeyboard = exports2.Keyboard = undefined;
@@ -61718,7 +61779,7 @@ var require_keyboard = __commonJS((exports2) => {
61718
61779
  }
61719
61780
  });
61720
61781
 
61721
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/session.js
61782
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/session.js
61722
61783
  var require_session = __commonJS((exports2) => {
61723
61784
  Object.defineProperty(exports2, "__esModule", { value: true });
61724
61785
  exports2.MemorySessionStorage = undefined;
@@ -62018,7 +62079,7 @@ var require_session = __commonJS((exports2) => {
62018
62079
  }
62019
62080
  });
62020
62081
 
62021
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/frameworks.js
62082
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/frameworks.js
62022
62083
  var require_frameworks = __commonJS((exports2) => {
62023
62084
  Object.defineProperty(exports2, "__esModule", { value: true });
62024
62085
  exports2.adapters = undefined;
@@ -62390,7 +62451,7 @@ var require_frameworks = __commonJS((exports2) => {
62390
62451
  };
62391
62452
  });
62392
62453
 
62393
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/convenience/webhook.js
62454
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/convenience/webhook.js
62394
62455
  var require_webhook = __commonJS((exports2) => {
62395
62456
  Object.defineProperty(exports2, "__esModule", { value: true });
62396
62457
  exports2.webhookCallback = webhookCallback;
@@ -62484,7 +62545,7 @@ var require_webhook = __commonJS((exports2) => {
62484
62545
  }
62485
62546
  });
62486
62547
 
62487
- // node_modules/.bun/grammy@1.44.0/node_modules/grammy/out/mod.js
62548
+ // node_modules/.bun/grammy@1.45.1/node_modules/grammy/out/mod.js
62488
62549
  var require_mod = __commonJS((exports2) => {
62489
62550
  var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
62490
62551
  if (k2 === undefined)
@@ -21565,7 +21565,7 @@ function allocateAgentUid(name) {
21565
21565
  }
21566
21566
 
21567
21567
  // src/build-info.ts
21568
- var VERSION = "0.21.8";
21568
+ var VERSION = "0.21.9";
21569
21569
 
21570
21570
  // src/setup/hindsight-recall-passthrough.ts
21571
21571
  var HINDSIGHT_RECALL_TAG_WEIGHT_SEED = Object.freeze({ sidechain: 0.8 });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "switchroom",
3
3
  "//version": "NOT the release version — source of truth is the git tag, resolved by scripts/build.mjs:resolveVersion() (see CLAUDE.md > Standard release process). This field is stale by design and only the Layer-4 dev/non-tag fallback for build.mjs + src/cli/resolve-version.ts; do NOT bump it expecting a release to pick it up. npm-pack tarball naming needs a real version — do that as an UNCOMMITTED pack-time bump (see release step 6), never a committed one.",
4
- "version": "0.21.8",
4
+ "version": "0.21.9",
5
5
  "description": "Run Claude Code 24/7 on your Claude Pro/Max subscription over Telegram. Open-source alternative to OpenClaw and NanoClaw — no API keys.",
6
6
  "type": "module",
7
7
  "bin": {
@@ -70,7 +70,7 @@
70
70
  "bcryptjs": "^3.0.3",
71
71
  "chalk": "^5.4.0",
72
72
  "commander": "^13.1.0",
73
- "grammy": "^1.44",
73
+ "grammy": "^1.45",
74
74
  "handlebars": "^4.7.8",
75
75
  "nostr-tools": "^2.24.1",
76
76
  "posthog-node": "^5.29.2",
@@ -6,7 +6,7 @@ Switchroom ships an enhanced `switchroom-telegram` MCP plugin that replaces the
6
6
 
7
7
  | Tool | What it does |
8
8
  |------|-------------|
9
- | `reply` | Send text, photos, or documents — the single final-answer tool. Chunks anything over Telegram's 4096-char limit. Supports threading, topic routing, file attachments. |
9
+ | `reply` | Send text, photos, or documents — the single final-answer tool. Chunks anything over the 32768-char rich-message cap (4096 applies only to plain-text degradations). Supports threading, topic routing, file attachments. |
10
10
  | `react` | Add emoji reactions to messages (Telegram whitelist: 👍 👎 ❤️ 🔥 👀 🎉 etc). |
11
11
  | `edit_message` | Update a previously sent message. Edits are silent (no push notification). |
12
12
  | `delete_message` | Remove a bot-sent message (48h Telegram API limit). |
@@ -40,18 +40,20 @@ History survives process restarts and session resets.
40
40
  For long tasks you do not need to narrate progress by editing a message. The
41
41
  plugin renders an event-driven progress card (Plan → Run → Done with live tool
42
42
  bullets, elapsed time, and status emoji) for free while the turn is in-flight.
43
- Send the final answer once, with `reply` — it chunks anything over Telegram's
44
- 4096-char limit. For an explicit mid-turn check-in use `progress_update`.
43
+ Send the final answer once, with `reply` — it chunks anything over the
44
+ 32768-char rich-message cap (4096 applies only to plain-text degradations).
45
+ For an explicit mid-turn check-in use `progress_update`.
45
46
 
46
47
  ## Formatting
47
48
 
48
- Markdown is auto-converted to Telegram HTML:
49
- - `**bold**` `<b>bold</b>`
50
- - `` `code` `` `<code>code</code>`
51
- - ` ```blocks``` ` `<pre><code>...</code></pre>`
52
- - Smart chunking preserves tag balance across Telegram's 4096-char limit
53
-
54
- Formats: `html` (default), `markdownv2`, `text`
49
+ Every outbound message is sent as raw GFM markdown via the Bot API 10.1
50
+ rich-message path (`sendRichMessage` / `editMessageText({ markdown })`) —
51
+ Telegram parses the markdown server-side. There is no markdownHTML
52
+ conversion and no `parse_mode` on this path. Smart chunking
53
+ (`splitMarkdownChunks`) splits anything over the 32768-char rich cap without
54
+ bisecting code fences or table rows; bodies that degrade to plain text fall
55
+ back to the legacy 4096-char cap. See
56
+ `reference/telegram-formatting-guide.md` for the full vocabulary.
55
57
 
56
58
  ## Access control
57
59
 
@@ -294,7 +294,7 @@ The `switchroom-telegram` plugin is an enhanced fork of the official Telegram MC
294
294
 
295
295
  | Tool | Purpose |
296
296
  |---|---|
297
- | `reply` | Send a text/photo message — the single final-answer tool; chunks anything over Telegram's 4096-char limit. Optional `reply_to` for threaded quotes |
297
+ | `reply` | Send a text/photo message — the single final-answer tool; chunks anything over the 32768-char rich-message cap (4096 applies only to plain-text degradations). Optional `reply_to` for threaded quotes |
298
298
  | `react` | Emoji reaction on an inbound or outbound message |
299
299
  | `edit_message` | Modify an earlier bot message's text |
300
300
  | `delete_message` | Remove an earlier bot message |
@@ -204,7 +204,9 @@ For long tasks the model does **not** need to narrate progress or drive a
204
204
  streaming message itself. The plugin renders an event-driven progress card
205
205
  (Plan → Run → Done with live tool bullets, elapsed time, and status emoji)
206
206
  for free while the turn is in-flight. Send the final answer once, with
207
- `reply` — it chunks anything over Telegram's 4096-char limit. (The retired
207
+ `reply` — it chunks anything over the rich-message wire cap of 32768 chars
208
+ (`RICH_MESSAGE_MAX_CHARS` in `format.ts`; the legacy 4096 cap applies only to
209
+ plain-text degradations). (The retired
208
210
  `stream_reply` tool was a redundant, worse alias of `reply`; the internal
209
211
  progress-card streaming that drove it is preserved and is what renders the
210
212
  live card.)