@femtomc/mu-server 26.2.101 → 26.2.103
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/README.md +6 -1
- package/dist/config.d.ts +0 -3
- package/dist/config.js +0 -11
- package/dist/control_plane.js +48 -15
- package/dist/control_plane_adapter_registry.d.ts +0 -1
- package/dist/control_plane_adapter_registry.js +0 -1
- package/dist/control_plane_telegram_generation.js +0 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -126,6 +126,9 @@ Use `mu store paths --pretty` to resolve `<store>` for the active repo/workspace
|
|
|
126
126
|
"source": "neovim"
|
|
127
127
|
}
|
|
128
128
|
```
|
|
129
|
+
- `session_kind` is optional. When omitted, the server auto-resolves `session_id` across
|
|
130
|
+
`<store>/operator/sessions` and `<store>/control-plane/operator-sessions`.
|
|
131
|
+
If the same id exists in both stores, pass `session_kind` (or `session_dir`) to disambiguate.
|
|
129
132
|
- Optional overrides: `session_file`, `session_dir`, `provider`, `model`, `thinking`, `extension_profile`
|
|
130
133
|
- Response includes: `turn.reply`, `turn.context_entry_id`, `turn.session_file`
|
|
131
134
|
|
|
@@ -186,7 +189,9 @@ Operational fallbacks:
|
|
|
186
189
|
- Missing Slack/Telegram bot tokens surface capability reason codes (`*_bot_token_missing`) and retry behavior.
|
|
187
190
|
|
|
188
191
|
Server channel renderers consume canonical `hud_docs` metadata (`HudDoc`) for Slack/Telegram HUD
|
|
189
|
-
rendering + actions.
|
|
192
|
+
rendering + actions. Optional HUD presentation hints (`title_style`, `snapshot_style`, chip/item styles)
|
|
193
|
+
and metadata presets (`metadata.style_preset`) may be used by richer renderers and safely ignored by
|
|
194
|
+
plain-text channels. New features should extend the shared HUD contract path instead of bespoke
|
|
190
195
|
channel-specific HUD payload formats.
|
|
191
196
|
|
|
192
197
|
## Running the Server
|
package/dist/config.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ export type MuConfig = {
|
|
|
12
12
|
telegram: {
|
|
13
13
|
webhook_secret: string | null;
|
|
14
14
|
bot_token: string | null;
|
|
15
|
-
bot_username: string | null;
|
|
16
15
|
};
|
|
17
16
|
neovim: {
|
|
18
17
|
shared_secret: string | null;
|
|
@@ -44,7 +43,6 @@ export type MuConfigPatch = {
|
|
|
44
43
|
telegram?: {
|
|
45
44
|
webhook_secret?: string | null;
|
|
46
45
|
bot_token?: string | null;
|
|
47
|
-
bot_username?: string | null;
|
|
48
46
|
};
|
|
49
47
|
neovim?: {
|
|
50
48
|
shared_secret?: string | null;
|
|
@@ -76,7 +74,6 @@ export type MuConfigPresence = {
|
|
|
76
74
|
telegram: {
|
|
77
75
|
webhook_secret: boolean;
|
|
78
76
|
bot_token: boolean;
|
|
79
|
-
bot_username: boolean;
|
|
80
77
|
};
|
|
81
78
|
neovim: {
|
|
82
79
|
shared_secret: boolean;
|
package/dist/config.js
CHANGED
|
@@ -15,7 +15,6 @@ export const DEFAULT_MU_CONFIG = {
|
|
|
15
15
|
telegram: {
|
|
16
16
|
webhook_secret: null,
|
|
17
17
|
bot_token: null,
|
|
18
|
-
bot_username: null,
|
|
19
18
|
},
|
|
20
19
|
neovim: {
|
|
21
20
|
shared_secret: null,
|
|
@@ -107,9 +106,6 @@ export function normalizeMuConfig(input) {
|
|
|
107
106
|
if ("bot_token" in telegram) {
|
|
108
107
|
next.control_plane.adapters.telegram.bot_token = normalizeNullableString(telegram.bot_token);
|
|
109
108
|
}
|
|
110
|
-
if ("bot_username" in telegram) {
|
|
111
|
-
next.control_plane.adapters.telegram.bot_username = normalizeNullableString(telegram.bot_username);
|
|
112
|
-
}
|
|
113
109
|
}
|
|
114
110
|
const neovim = asRecord(adapters.neovim);
|
|
115
111
|
if (neovim && "shared_secret" in neovim) {
|
|
@@ -185,9 +181,6 @@ function normalizeMuConfigPatch(input) {
|
|
|
185
181
|
if ("bot_token" in telegram) {
|
|
186
182
|
telegramPatch.bot_token = normalizeNullableString(telegram.bot_token);
|
|
187
183
|
}
|
|
188
|
-
if ("bot_username" in telegram) {
|
|
189
|
-
telegramPatch.bot_username = normalizeNullableString(telegram.bot_username);
|
|
190
|
-
}
|
|
191
184
|
if (Object.keys(telegramPatch).length > 0) {
|
|
192
185
|
patch.control_plane.adapters.telegram = telegramPatch;
|
|
193
186
|
}
|
|
@@ -273,9 +266,6 @@ export function applyMuConfigPatch(base, patchInput) {
|
|
|
273
266
|
if ("bot_token" in adapters.telegram) {
|
|
274
267
|
next.control_plane.adapters.telegram.bot_token = adapters.telegram.bot_token ?? null;
|
|
275
268
|
}
|
|
276
|
-
if ("bot_username" in adapters.telegram) {
|
|
277
|
-
next.control_plane.adapters.telegram.bot_username = adapters.telegram.bot_username ?? null;
|
|
278
|
-
}
|
|
279
269
|
}
|
|
280
270
|
if (adapters.neovim && "shared_secret" in adapters.neovim) {
|
|
281
271
|
next.control_plane.adapters.neovim.shared_secret = adapters.neovim.shared_secret ?? null;
|
|
@@ -372,7 +362,6 @@ export function muConfigPresence(config) {
|
|
|
372
362
|
telegram: {
|
|
373
363
|
webhook_secret: isPresent(config.control_plane.adapters.telegram.webhook_secret),
|
|
374
364
|
bot_token: isPresent(config.control_plane.adapters.telegram.bot_token),
|
|
375
|
-
bot_username: isPresent(config.control_plane.adapters.telegram.bot_username),
|
|
376
365
|
},
|
|
377
366
|
neovim: {
|
|
378
367
|
shared_secret: isPresent(config.control_plane.adapters.neovim.shared_secret),
|
package/dist/control_plane.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeHudDocs } from "@femtomc/mu-core";
|
|
1
|
+
import { applyHudStylePreset, normalizeHudDocs } from "@femtomc/mu-core";
|
|
2
2
|
import { ControlPlaneCommandPipeline, ControlPlaneOutbox, ControlPlaneRuntime, buildSlackHudActionId, getControlPlanePaths, TelegramControlPlaneAdapterSpec, } from "@femtomc/mu-control-plane";
|
|
3
3
|
import { DEFAULT_MU_CONFIG } from "./config.js";
|
|
4
4
|
import { buildMessagingOperatorRuntime, createOutboxDrainLoop } from "./control_plane_bootstrap_helpers.js";
|
|
@@ -148,6 +148,9 @@ const SLACK_ACTIONS_MAX_PER_BLOCK = 5;
|
|
|
148
148
|
const SLACK_ACTIONS_MAX_TOTAL = 20;
|
|
149
149
|
const SLACK_DOCS_MAX = 3;
|
|
150
150
|
const SLACK_SECTION_LINE_MAX = 8;
|
|
151
|
+
function hudDocsForPresentation(input, maxDocs) {
|
|
152
|
+
return normalizeHudDocs(input, { maxDocs }).map((doc) => applyHudStylePreset(doc) ?? doc);
|
|
153
|
+
}
|
|
151
154
|
function truncateSlackText(text, maxLen = SLACK_BLOCK_TEXT_MAX_LEN) {
|
|
152
155
|
if (text.length <= maxLen) {
|
|
153
156
|
return text;
|
|
@@ -176,11 +179,33 @@ function hudTonePrefix(tone) {
|
|
|
176
179
|
return "ℹ️";
|
|
177
180
|
}
|
|
178
181
|
}
|
|
182
|
+
function applySlackHudTextStyle(text, style, opts = {}) {
|
|
183
|
+
const weight = style?.weight ?? opts.defaultWeight;
|
|
184
|
+
const italic = style?.italic ?? opts.defaultItalic ?? false;
|
|
185
|
+
const code = style?.code ?? opts.defaultCode ?? false;
|
|
186
|
+
let out = text;
|
|
187
|
+
if (code) {
|
|
188
|
+
out = `\`${out}\``;
|
|
189
|
+
}
|
|
190
|
+
if (italic) {
|
|
191
|
+
out = `_${out}_`;
|
|
192
|
+
}
|
|
193
|
+
if (weight === "strong") {
|
|
194
|
+
out = `*${out}*`;
|
|
195
|
+
}
|
|
196
|
+
return out;
|
|
197
|
+
}
|
|
198
|
+
function stripSlackMrkdwn(text) {
|
|
199
|
+
return text.replace(/[*_`~]/g, "");
|
|
200
|
+
}
|
|
179
201
|
function hudDocSectionLines(doc) {
|
|
180
202
|
const lines = [];
|
|
181
203
|
const chipsLine = doc.chips
|
|
182
204
|
.slice(0, 8)
|
|
183
|
-
.map((chip) =>
|
|
205
|
+
.map((chip) => {
|
|
206
|
+
const label = applySlackHudTextStyle(chip.label, chip.style, { defaultWeight: "strong" });
|
|
207
|
+
return `${hudTonePrefix(chip.tone)} ${label}`;
|
|
208
|
+
})
|
|
184
209
|
.join(" · ");
|
|
185
210
|
if (chipsLine.length > 0) {
|
|
186
211
|
lines.push(chipsLine);
|
|
@@ -188,25 +213,28 @@ function hudDocSectionLines(doc) {
|
|
|
188
213
|
for (const section of doc.sections) {
|
|
189
214
|
switch (section.kind) {
|
|
190
215
|
case "kv": {
|
|
191
|
-
const title = section.title
|
|
192
|
-
const items = section.items.slice(0, SLACK_SECTION_LINE_MAX).map((item) =>
|
|
216
|
+
const title = applySlackHudTextStyle(section.title ?? "Details", section.title_style, { defaultWeight: "strong" });
|
|
217
|
+
const items = section.items.slice(0, SLACK_SECTION_LINE_MAX).map((item) => {
|
|
218
|
+
const value = applySlackHudTextStyle(item.value, item.value_style);
|
|
219
|
+
return `• *${item.label}:* ${value}`;
|
|
220
|
+
});
|
|
193
221
|
if (items.length > 0) {
|
|
194
222
|
lines.push([title, ...items].join("\n"));
|
|
195
223
|
}
|
|
196
224
|
break;
|
|
197
225
|
}
|
|
198
226
|
case "checklist": {
|
|
199
|
-
const title = section.title
|
|
227
|
+
const title = applySlackHudTextStyle(section.title ?? "Checklist", section.title_style, { defaultWeight: "strong" });
|
|
200
228
|
const items = section.items
|
|
201
229
|
.slice(0, SLACK_SECTION_LINE_MAX)
|
|
202
|
-
.map((item) => `${item.done ? "✅" : "⬜"} ${item.label}`);
|
|
230
|
+
.map((item) => `${item.done ? "✅" : "⬜"} ${applySlackHudTextStyle(item.label, item.style)}`);
|
|
203
231
|
if (items.length > 0) {
|
|
204
232
|
lines.push([title, ...items].join("\n"));
|
|
205
233
|
}
|
|
206
234
|
break;
|
|
207
235
|
}
|
|
208
236
|
case "activity": {
|
|
209
|
-
const title = section.title
|
|
237
|
+
const title = applySlackHudTextStyle(section.title ?? "Activity", section.title_style, { defaultWeight: "strong" });
|
|
210
238
|
const items = section.lines.slice(0, SLACK_SECTION_LINE_MAX).map((line) => `• ${line}`);
|
|
211
239
|
if (items.length > 0) {
|
|
212
240
|
lines.push([title, ...items].join("\n"));
|
|
@@ -214,14 +242,18 @@ function hudDocSectionLines(doc) {
|
|
|
214
242
|
break;
|
|
215
243
|
}
|
|
216
244
|
case "text": {
|
|
217
|
-
const title = section.title
|
|
218
|
-
|
|
245
|
+
const title = section.title
|
|
246
|
+
? `${applySlackHudTextStyle(section.title, section.title_style, { defaultWeight: "strong" })}\n`
|
|
247
|
+
: "";
|
|
248
|
+
const text = applySlackHudTextStyle(section.text, section.style);
|
|
249
|
+
lines.push(`${title}${text}`);
|
|
219
250
|
break;
|
|
220
251
|
}
|
|
221
252
|
}
|
|
222
253
|
}
|
|
223
254
|
if (lines.length === 0) {
|
|
224
|
-
|
|
255
|
+
const snapshot = applySlackHudTextStyle(doc.snapshot_compact, doc.snapshot_style);
|
|
256
|
+
lines.push(`${applySlackHudTextStyle("Snapshot", undefined, { defaultWeight: "strong" })}\n${snapshot}`);
|
|
225
257
|
}
|
|
226
258
|
return lines;
|
|
227
259
|
}
|
|
@@ -257,7 +289,7 @@ export function splitSlackMessageText(text, maxLen = SLACK_MESSAGE_MAX_LEN) {
|
|
|
257
289
|
return chunks;
|
|
258
290
|
}
|
|
259
291
|
function slackBlocksForOutboxRecord(record, body) {
|
|
260
|
-
const hudDocs =
|
|
292
|
+
const hudDocs = hudDocsForPresentation(record.envelope.metadata?.hud_docs, SLACK_DOCS_MAX);
|
|
261
293
|
if (hudDocs.length === 0) {
|
|
262
294
|
return undefined;
|
|
263
295
|
}
|
|
@@ -270,9 +302,10 @@ function slackBlocksForOutboxRecord(record, body) {
|
|
|
270
302
|
if (blocks.length >= SLACK_BLOCKS_MAX) {
|
|
271
303
|
break;
|
|
272
304
|
}
|
|
305
|
+
const styledTitle = applySlackHudTextStyle(doc.title, doc.title_style, { defaultWeight: "strong" });
|
|
273
306
|
blocks.push({
|
|
274
307
|
type: "context",
|
|
275
|
-
elements: [{ type: "mrkdwn", text: truncateSlackText(`*HUD · ${
|
|
308
|
+
elements: [{ type: "mrkdwn", text: truncateSlackText(`*HUD* · ${styledTitle}`) }],
|
|
276
309
|
});
|
|
277
310
|
for (const line of hudDocSectionLines(doc)) {
|
|
278
311
|
if (blocks.length >= SLACK_BLOCKS_MAX) {
|
|
@@ -321,7 +354,7 @@ function utf8ByteLength(value) {
|
|
|
321
354
|
return new TextEncoder().encode(value).length;
|
|
322
355
|
}
|
|
323
356
|
function telegramTextForOutboxRecord(record, body) {
|
|
324
|
-
const hudDocs =
|
|
357
|
+
const hudDocs = hudDocsForPresentation(record.envelope.metadata?.hud_docs, TELEGRAM_DOCS_MAX);
|
|
325
358
|
if (hudDocs.length === 0) {
|
|
326
359
|
return body;
|
|
327
360
|
}
|
|
@@ -329,13 +362,13 @@ function telegramTextForOutboxRecord(record, body) {
|
|
|
329
362
|
for (const doc of hudDocs) {
|
|
330
363
|
lines.push("", `HUD · ${doc.title}`);
|
|
331
364
|
for (const sectionLine of hudDocSectionLines(doc)) {
|
|
332
|
-
lines.push(sectionLine
|
|
365
|
+
lines.push(stripSlackMrkdwn(sectionLine));
|
|
333
366
|
}
|
|
334
367
|
}
|
|
335
368
|
return lines.join("\n").trim();
|
|
336
369
|
}
|
|
337
370
|
async function compileTelegramHudActions(opts) {
|
|
338
|
-
const hudDocs =
|
|
371
|
+
const hudDocs = hudDocsForPresentation(opts.record.envelope.metadata?.hud_docs, TELEGRAM_DOCS_MAX);
|
|
339
372
|
if (hudDocs.length === 0) {
|
|
340
373
|
return { overflowText: "" };
|
|
341
374
|
}
|
|
@@ -8,7 +8,6 @@ export type DetectedTelegramAdapter = {
|
|
|
8
8
|
name: "telegram";
|
|
9
9
|
webhookSecret: string;
|
|
10
10
|
botToken: string | null;
|
|
11
|
-
botUsername: string | null;
|
|
12
11
|
};
|
|
13
12
|
export type DetectedAdapter = DetectedStaticAdapter | DetectedTelegramAdapter;
|
|
14
13
|
export declare function detectAdapters(config: ControlPlaneConfig): DetectedAdapter[];
|
|
@@ -23,21 +23,18 @@ function telegramAdapterConfigFromControlPlane(config) {
|
|
|
23
23
|
return {
|
|
24
24
|
webhookSecret,
|
|
25
25
|
botToken: config.adapters.telegram.bot_token,
|
|
26
|
-
botUsername: config.adapters.telegram.bot_username,
|
|
27
26
|
};
|
|
28
27
|
}
|
|
29
28
|
function applyTelegramAdapterConfig(base, telegram) {
|
|
30
29
|
const next = cloneControlPlaneConfig(base);
|
|
31
30
|
next.adapters.telegram.webhook_secret = telegram?.webhookSecret ?? null;
|
|
32
31
|
next.adapters.telegram.bot_token = telegram?.botToken ?? null;
|
|
33
|
-
next.adapters.telegram.bot_username = telegram?.botUsername ?? null;
|
|
34
32
|
return next;
|
|
35
33
|
}
|
|
36
34
|
function cloneTelegramAdapterConfig(config) {
|
|
37
35
|
return {
|
|
38
36
|
webhookSecret: config.webhookSecret,
|
|
39
37
|
botToken: config.botToken,
|
|
40
|
-
botUsername: config.botUsername,
|
|
41
38
|
};
|
|
42
39
|
}
|
|
43
40
|
function describeError(err) {
|
|
@@ -112,7 +109,6 @@ export class TelegramAdapterGenerationManager {
|
|
|
112
109
|
outbox: this.#outbox,
|
|
113
110
|
webhookSecret: config.webhookSecret,
|
|
114
111
|
botToken: config.botToken,
|
|
115
|
-
botUsername: config.botUsername,
|
|
116
112
|
deferredIngress: true,
|
|
117
113
|
onOutboxEnqueued: this.#onOutboxEnqueued ?? undefined,
|
|
118
114
|
signalObserver: this.#signalObserver ?? 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.103",
|
|
4
4
|
"description": "HTTP API server for mu control-plane transport/session plus run/activity scheduling coordination.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"start": "bun run dist/cli.js"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@femtomc/mu-agent": "26.2.
|
|
34
|
-
"@femtomc/mu-control-plane": "26.2.
|
|
35
|
-
"@femtomc/mu-core": "26.2.
|
|
33
|
+
"@femtomc/mu-agent": "26.2.103",
|
|
34
|
+
"@femtomc/mu-control-plane": "26.2.103",
|
|
35
|
+
"@femtomc/mu-core": "26.2.103"
|
|
36
36
|
}
|
|
37
37
|
}
|