@femtomc/mu-server 26.2.40 → 26.2.41
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.
- package/dist/control_plane.d.ts +17 -0
- package/dist/control_plane.js +67 -9
- package/package.json +6 -6
package/dist/control_plane.d.ts
CHANGED
|
@@ -24,6 +24,23 @@ type DetectedAdapter = {
|
|
|
24
24
|
botUsername: string | null;
|
|
25
25
|
};
|
|
26
26
|
export declare function detectAdapters(config: ControlPlaneConfig): DetectedAdapter[];
|
|
27
|
+
export type TelegramSendMessagePayload = {
|
|
28
|
+
chat_id: string;
|
|
29
|
+
text: string;
|
|
30
|
+
parse_mode?: "Markdown";
|
|
31
|
+
disable_web_page_preview?: boolean;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Telegram supports a markdown dialect that uses single markers for emphasis.
|
|
35
|
+
* Normalize the most common LLM/GitHub-style markers (`**bold**`, `__italic__`, headings)
|
|
36
|
+
* while preserving fenced code blocks verbatim.
|
|
37
|
+
*/
|
|
38
|
+
export declare function renderTelegramMarkdown(text: string): string;
|
|
39
|
+
export declare function buildTelegramSendMessagePayload(opts: {
|
|
40
|
+
chatId: string;
|
|
41
|
+
text: string;
|
|
42
|
+
richFormatting: boolean;
|
|
43
|
+
}): TelegramSendMessagePayload;
|
|
27
44
|
export type BootstrapControlPlaneOpts = {
|
|
28
45
|
repoRoot: string;
|
|
29
46
|
config?: ControlPlaneConfig;
|
package/dist/control_plane.js
CHANGED
|
@@ -22,6 +22,56 @@ export function detectAdapters(config) {
|
|
|
22
22
|
}
|
|
23
23
|
return adapters;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Telegram supports a markdown dialect that uses single markers for emphasis.
|
|
27
|
+
* Normalize the most common LLM/GitHub-style markers (`**bold**`, `__italic__`, headings)
|
|
28
|
+
* while preserving fenced code blocks verbatim.
|
|
29
|
+
*/
|
|
30
|
+
export function renderTelegramMarkdown(text) {
|
|
31
|
+
const normalized = text.replaceAll("\r\n", "\n");
|
|
32
|
+
const lines = normalized.split("\n");
|
|
33
|
+
const out = [];
|
|
34
|
+
let inFence = false;
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
const trimmed = line.trimStart();
|
|
37
|
+
if (trimmed.startsWith("```")) {
|
|
38
|
+
inFence = !inFence;
|
|
39
|
+
out.push(line);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (inFence) {
|
|
43
|
+
out.push(line);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
let next = line;
|
|
47
|
+
next = next.replace(/^#{1,6}\s+(.+)$/, "*$1*");
|
|
48
|
+
next = next.replace(/\*\*(.+?)\*\*/g, "*$1*");
|
|
49
|
+
next = next.replace(/__(.+?)__/g, "_$1_");
|
|
50
|
+
out.push(next);
|
|
51
|
+
}
|
|
52
|
+
return out.join("\n");
|
|
53
|
+
}
|
|
54
|
+
export function buildTelegramSendMessagePayload(opts) {
|
|
55
|
+
if (!opts.richFormatting) {
|
|
56
|
+
return {
|
|
57
|
+
chat_id: opts.chatId,
|
|
58
|
+
text: opts.text,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
chat_id: opts.chatId,
|
|
63
|
+
text: renderTelegramMarkdown(opts.text),
|
|
64
|
+
parse_mode: "Markdown",
|
|
65
|
+
disable_web_page_preview: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function postTelegramMessage(botToken, payload) {
|
|
69
|
+
return await fetch(`https://api.telegram.org/bot${botToken}/sendMessage`, {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "Content-Type": "application/json" },
|
|
72
|
+
body: JSON.stringify(payload),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
25
75
|
function buildMessagingOperatorRuntime(opts) {
|
|
26
76
|
if (!opts.config.operator.enabled) {
|
|
27
77
|
return null;
|
|
@@ -113,29 +163,37 @@ export async function bootstrapControlPlane(opts) {
|
|
|
113
163
|
if (!telegramBotToken) {
|
|
114
164
|
return { kind: "retry", error: "telegram bot token not configured in .mu/config.json" };
|
|
115
165
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
chat_id: envelope.channel_conversation_id,
|
|
121
|
-
text: envelope.body,
|
|
122
|
-
}),
|
|
166
|
+
const richPayload = buildTelegramSendMessagePayload({
|
|
167
|
+
chatId: envelope.channel_conversation_id,
|
|
168
|
+
text: envelope.body,
|
|
169
|
+
richFormatting: true,
|
|
123
170
|
});
|
|
171
|
+
let res = await postTelegramMessage(telegramBotToken, richPayload);
|
|
172
|
+
// Fallback: if Telegram rejects markdown entities, retry as plain text.
|
|
173
|
+
if (!res.ok && res.status === 400 && richPayload.parse_mode) {
|
|
174
|
+
const plainPayload = buildTelegramSendMessagePayload({
|
|
175
|
+
chatId: envelope.channel_conversation_id,
|
|
176
|
+
text: envelope.body,
|
|
177
|
+
richFormatting: false,
|
|
178
|
+
});
|
|
179
|
+
res = await postTelegramMessage(telegramBotToken, plainPayload);
|
|
180
|
+
}
|
|
124
181
|
if (res.ok) {
|
|
125
182
|
return { kind: "delivered" };
|
|
126
183
|
}
|
|
184
|
+
const responseBody = await res.text().catch(() => "");
|
|
127
185
|
if (res.status === 429 || res.status >= 500) {
|
|
128
186
|
const retryAfter = res.headers.get("retry-after");
|
|
129
187
|
const retryDelayMs = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : undefined;
|
|
130
188
|
return {
|
|
131
189
|
kind: "retry",
|
|
132
|
-
error: `telegram sendMessage ${res.status}: ${
|
|
190
|
+
error: `telegram sendMessage ${res.status}: ${responseBody}`,
|
|
133
191
|
retryDelayMs: retryDelayMs && Number.isFinite(retryDelayMs) ? retryDelayMs : undefined,
|
|
134
192
|
};
|
|
135
193
|
}
|
|
136
194
|
return {
|
|
137
195
|
kind: "retry",
|
|
138
|
-
error: `telegram sendMessage ${res.status}: ${
|
|
196
|
+
error: `telegram sendMessage ${res.status}: ${responseBody}`,
|
|
139
197
|
};
|
|
140
198
|
}
|
|
141
199
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-server",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.41",
|
|
4
4
|
"description": "HTTP API server for mu status, work items, messaging setup, and web UI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"start": "bun run dist/cli.js"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@femtomc/mu-agent": "26.2.
|
|
35
|
-
"@femtomc/mu-control-plane": "26.2.
|
|
36
|
-
"@femtomc/mu-core": "26.2.
|
|
37
|
-
"@femtomc/mu-forum": "26.2.
|
|
38
|
-
"@femtomc/mu-issue": "26.2.
|
|
34
|
+
"@femtomc/mu-agent": "26.2.41",
|
|
35
|
+
"@femtomc/mu-control-plane": "26.2.41",
|
|
36
|
+
"@femtomc/mu-core": "26.2.41",
|
|
37
|
+
"@femtomc/mu-forum": "26.2.41",
|
|
38
|
+
"@femtomc/mu-issue": "26.2.41"
|
|
39
39
|
}
|
|
40
40
|
}
|