thepopebot 1.1.1 → 1.1.2

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.
@@ -3,6 +3,73 @@ const { hydrateReply } = require('@grammyjs/parse-mode');
3
3
 
4
4
  const MAX_LENGTH = 4096;
5
5
 
6
+ /**
7
+ * Convert markdown to Telegram-compatible HTML.
8
+ * Handles: code blocks, inline code, links, bold, italic, strikethrough, headings, lists.
9
+ * Strips unsupported HTML tags.
10
+ * @param {string} text - Markdown text
11
+ * @returns {string} Telegram HTML
12
+ */
13
+ function markdownToTelegramHtml(text) {
14
+ if (!text) return '';
15
+
16
+ const placeholders = [];
17
+ function placeholder(content) {
18
+ const id = `\x00PH${placeholders.length}\x00`;
19
+ placeholders.push(content);
20
+ return id;
21
+ }
22
+
23
+ // 1. Protect existing supported HTML tags (so they survive escaping)
24
+ text = text.replace(/<(\/?(b|i|s|u|code|pre|a)\b[^>]*)>/g, (match) => {
25
+ return placeholder(match);
26
+ });
27
+
28
+ // 2. Extract fenced code blocks (``` ... ```)
29
+ text = text.replace(/```[\w]*\n([\s\S]*?)```/g, (_, code) => {
30
+ return placeholder(`<pre>${escapeHtml(code.replace(/\n$/, ''))}</pre>`);
31
+ });
32
+
33
+ // 3. Extract inline code (` ... `)
34
+ text = text.replace(/`([^`\n]+)`/g, (_, code) => {
35
+ return placeholder(`<code>${escapeHtml(code)}</code>`);
36
+ });
37
+
38
+ // 4. Escape remaining HTML special chars (after code + existing tags are protected)
39
+ text = text.replace(/&/g, '&amp;');
40
+ text = text.replace(/</g, '&lt;');
41
+ text = text.replace(/>/g, '&gt;');
42
+
43
+ // 5. Links: [text](url)
44
+ text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
45
+
46
+ // 6. Bold: **text** or __text__
47
+ text = text.replace(/\*\*(.+?)\*\*/g, '<b>$1</b>');
48
+ text = text.replace(/__(.+?)__/g, '<b>$1</b>');
49
+
50
+ // 7. Italic: *text* or _text_ (but not inside words for underscores)
51
+ text = text.replace(/(?<!\w)\*([^*\n<]+)\*(?!\w)/g, '<i>$1</i>');
52
+ text = text.replace(/(?<!\w)_([^_\n<]+)_(?!\w)/g, '<i>$1</i>');
53
+
54
+ // 8. Strikethrough: ~~text~~
55
+ text = text.replace(/~~(.+?)~~/g, '<s>$1</s>');
56
+
57
+ // 9. Headings: ## text → bold (must be at line start)
58
+ text = text.replace(/^#{1,6}\s+(.+)$/gm, '<b>$1</b>');
59
+
60
+ // 10. List items: - item or * item → bullet
61
+ text = text.replace(/^[\s]*[-*]\s+/gm, '• ');
62
+
63
+ // 11. Numbered list items: 1. item → keep as-is (already plain text friendly)
64
+
65
+ // 12. Restore placeholders
66
+ for (let i = 0; i < placeholders.length; i++) {
67
+ text = text.replace(`\x00PH${i}\x00`, placeholders[i]);
68
+ }
69
+
70
+ return text;
71
+ }
72
+
6
73
  let bot = null;
7
74
  let currentToken = null;
8
75
 
@@ -101,6 +168,7 @@ function escapeHtml(text) {
101
168
  */
102
169
  async function sendMessage(botToken, chatId, text, options = {}) {
103
170
  const b = getBot(botToken);
171
+ text = markdownToTelegramHtml(text);
104
172
  // Strip HTML comments — Telegram's HTML parser doesn't support them
105
173
  text = text.replace(/<!--[\s\S]*?-->/g, '');
106
174
  const chunks = smartSplit(text, MAX_LENGTH);
@@ -215,6 +283,7 @@ module.exports = {
215
283
  sendMessage,
216
284
  smartSplit,
217
285
  escapeHtml,
286
+ markdownToTelegramHtml,
218
287
  formatJobNotification,
219
288
  downloadFile,
220
289
  reactToMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thepopebot",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Create autonomous AI agents with a two-layer architecture: Next.js Event Handler + Docker Agent.",
5
5
  "bin": {
6
6
  "thepopebot": "./bin/cli.js"
@@ -15,7 +15,6 @@ This is an autonomous AI agent powered by [thepopebot](https://github.com/stephe
15
15
  │ ├── CHATBOT.md # Telegram chat system prompt
16
16
  │ ├── JOB_SUMMARY.md # Job completion summary prompt
17
17
  │ ├── HEARTBEAT.md # Periodic check instructions
18
- │ ├── TELEGRAM.md # Telegram formatting guidelines
19
18
  │ ├── AGENT.md # Agent runtime environment
20
19
  │ ├── CRONS.json # Scheduled job definitions
21
20
  │ └── TRIGGERS.json # Webhook trigger definitions
@@ -77,8 +77,6 @@ Use the `get_job_status` tool when the user asks about job progress, running job
77
77
  - Be helpful, direct, and efficient
78
78
  - When you use web search, summarize the key findings concisely
79
79
 
80
- {{config/TELEGRAM.md}}
81
-
82
80
  # Technical Reference
83
81
 
84
82
  Below are technical details on how thepopebot is built.
@@ -14,8 +14,6 @@ You convert job result data into concise summaries for non-technical people. Adj
14
14
  - Provide a 1–2 sentence summary of the agent logs (what it did). Keep it brief on success, more detailed on failure.
15
15
  - Only include a Challenges section when the bot struggled significantly.
16
16
 
17
- {{config/TELEGRAM.md}}
18
-
19
17
  ## Output Format
20
18
 
21
19
  ```
@@ -1,21 +0,0 @@
1
- ## Formatting for Telegram
2
-
3
- Your responses are sent via Telegram with HTML parse mode. Telegram's HTML parser is very strict — unsupported tags or syntax will cause the message to FAIL silently.
4
-
5
- Keep formatting minimal. Write plain text. Only use these tags sparingly:
6
- - <b>bold</b> for key terms
7
- - <i>italic</i> for subtle emphasis
8
- - <code>code</code> for job IDs, commands, file names
9
-
10
- NEVER use:
11
- - Any other HTML tags (no <div>, <p>, <h1>, <ul>, <li>, <br>, <pre>, <blockquote>, etc.)
12
- - HTML comments (<!-- -->)
13
- - Markdown syntax (no **bold**, *italic*, `backticks`, ```code blocks```, ## headings, [links](url))
14
- - Unclosed or malformed tags
15
-
16
- Style:
17
- - Write short, plain text responses
18
- - Use • or - for lists (plain text bullets, not HTML)
19
- - Use CAPS or <b>bold</b> for section headers, not heading tags
20
- - One thought per line, blank lines between sections
21
- - Keep under 1000 chars when possible