@femtomc/mu-agent 26.2.117 → 26.2.119
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 +1 -1
- package/dist/extensions/branding.d.ts.map +1 -1
- package/dist/extensions/branding.js +32 -10
- package/dist/extensions/ui.d.ts.map +1 -1
- package/dist/extensions/ui.js +44 -21
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ Default operator UI theme is `mu-gruvbox-dark`.
|
|
|
88
88
|
- `/mu brand on|off|toggle` — enable/disable UI branding
|
|
89
89
|
- `/mu ui ...` — inspect interactive `UiDoc`s (`status`/`snapshot`)
|
|
90
90
|
- `/mu help` — dispatcher catalog of registered `/mu` subcommands
|
|
91
|
-
- `ctrl+shift+u` — reopen local programmable-UI interaction flow
|
|
91
|
+
- `ctrl+shift+u` (primary) or `alt+u` (fallback) — reopen local programmable-UI interaction flow
|
|
92
92
|
|
|
93
93
|
## Tooling model (CLI-first)
|
|
94
94
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/extensions/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../../src/extensions/branding.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;AA0EpF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,QA2PjD;AAED,eAAe,iBAAiB,CAAC"}
|
|
@@ -17,6 +17,7 @@ const EMPTY_SNAPSHOT = {
|
|
|
17
17
|
adapters: [],
|
|
18
18
|
error: null,
|
|
19
19
|
};
|
|
20
|
+
const BRANDING_STATUS_REFRESH_TIMEOUT_MS = 2_000;
|
|
20
21
|
const ANSI_RE = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
21
22
|
function visibleWidth(text) {
|
|
22
23
|
return text.replace(ANSI_RE, "").length;
|
|
@@ -71,6 +72,7 @@ export function brandingExtension(pi) {
|
|
|
71
72
|
let activeCtx = null;
|
|
72
73
|
let pollTimer = null;
|
|
73
74
|
let footerRequestRender = null;
|
|
75
|
+
let refreshInFlight = null;
|
|
74
76
|
function applyDefaultTheme(ctx) {
|
|
75
77
|
if (!ctx.hasUI)
|
|
76
78
|
return;
|
|
@@ -145,8 +147,10 @@ export function brandingExtension(pi) {
|
|
|
145
147
|
ctx.ui.setStatus("mu-overview", undefined);
|
|
146
148
|
}
|
|
147
149
|
async function refreshStatus(ctx) {
|
|
148
|
-
|
|
150
|
+
const isActiveUiContext = () => activeCtx === ctx && ctx.hasUI && enabled;
|
|
151
|
+
if (!isActiveUiContext()) {
|
|
149
152
|
return;
|
|
153
|
+
}
|
|
150
154
|
if (!muServerUrl()) {
|
|
151
155
|
snapshot = {
|
|
152
156
|
...EMPTY_SNAPSHOT,
|
|
@@ -157,7 +161,10 @@ export function brandingExtension(pi) {
|
|
|
157
161
|
return;
|
|
158
162
|
}
|
|
159
163
|
try {
|
|
160
|
-
const status = await fetchMuStatus(
|
|
164
|
+
const status = await fetchMuStatus(BRANDING_STATUS_REFRESH_TIMEOUT_MS);
|
|
165
|
+
if (!isActiveUiContext()) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
161
168
|
const cp = status.control_plane ?? {
|
|
162
169
|
active: false,
|
|
163
170
|
adapters: [],
|
|
@@ -173,21 +180,35 @@ export function brandingExtension(pi) {
|
|
|
173
180
|
ctx.ui.setStatus("mu-overview", ctx.ui.theme.fg("dim", `μ open ${snapshot.openCount} · ready ${snapshot.readyCount} · cp ${snapshot.controlPlaneActive ? "on" : "off"}`));
|
|
174
181
|
}
|
|
175
182
|
catch (err) {
|
|
183
|
+
if (!isActiveUiContext()) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
176
186
|
snapshot = {
|
|
177
187
|
...EMPTY_SNAPSHOT,
|
|
178
188
|
error: err instanceof Error ? err.message : String(err),
|
|
179
189
|
};
|
|
180
190
|
ctx.ui.setStatus("mu-overview", ctx.ui.theme.fg("warning", "μ status refresh failed"));
|
|
181
191
|
}
|
|
192
|
+
if (!isActiveUiContext()) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
182
195
|
footerRequestRender?.();
|
|
183
196
|
}
|
|
197
|
+
function requestStatusRefresh(ctx) {
|
|
198
|
+
if (refreshInFlight) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
refreshInFlight = refreshStatus(ctx).finally(() => {
|
|
202
|
+
refreshInFlight = null;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
184
205
|
function ensurePolling() {
|
|
185
206
|
if (pollTimer)
|
|
186
207
|
return;
|
|
187
208
|
pollTimer = setInterval(() => {
|
|
188
209
|
if (!activeCtx)
|
|
189
210
|
return;
|
|
190
|
-
|
|
211
|
+
requestStatusRefresh(activeCtx);
|
|
191
212
|
}, 12_000);
|
|
192
213
|
}
|
|
193
214
|
function stopPolling() {
|
|
@@ -196,7 +217,7 @@ export function brandingExtension(pi) {
|
|
|
196
217
|
clearInterval(pollTimer);
|
|
197
218
|
pollTimer = null;
|
|
198
219
|
}
|
|
199
|
-
|
|
220
|
+
function initialize(ctx) {
|
|
200
221
|
activeCtx = ctx;
|
|
201
222
|
repoName = basename(ctx.cwd);
|
|
202
223
|
currentModelLabel = shortModelLabel(ctx);
|
|
@@ -205,7 +226,7 @@ export function brandingExtension(pi) {
|
|
|
205
226
|
if (enabled) {
|
|
206
227
|
applyDefaultTheme(ctx);
|
|
207
228
|
applyChrome(ctx);
|
|
208
|
-
|
|
229
|
+
requestStatusRefresh(ctx);
|
|
209
230
|
ensurePolling();
|
|
210
231
|
}
|
|
211
232
|
else {
|
|
@@ -213,11 +234,11 @@ export function brandingExtension(pi) {
|
|
|
213
234
|
stopPolling();
|
|
214
235
|
}
|
|
215
236
|
}
|
|
216
|
-
pi.on("session_start",
|
|
217
|
-
|
|
237
|
+
pi.on("session_start", (_event, ctx) => {
|
|
238
|
+
initialize(ctx);
|
|
218
239
|
});
|
|
219
|
-
pi.on("session_switch",
|
|
220
|
-
|
|
240
|
+
pi.on("session_switch", (_event, ctx) => {
|
|
241
|
+
initialize(ctx);
|
|
221
242
|
});
|
|
222
243
|
pi.on("model_select", async (event, ctx) => {
|
|
223
244
|
currentModelLabel = shortModelLabelFromEvent(event.model);
|
|
@@ -234,6 +255,7 @@ export function brandingExtension(pi) {
|
|
|
234
255
|
stopPolling();
|
|
235
256
|
footerRequestRender = null;
|
|
236
257
|
activeCtx = null;
|
|
258
|
+
refreshInFlight = null;
|
|
237
259
|
});
|
|
238
260
|
registerMuSubcommand(pi, {
|
|
239
261
|
subcommand: "brand",
|
|
@@ -257,7 +279,7 @@ export function brandingExtension(pi) {
|
|
|
257
279
|
if (enabled) {
|
|
258
280
|
applyDefaultTheme(ctx);
|
|
259
281
|
applyChrome(ctx);
|
|
260
|
-
|
|
282
|
+
requestStatusRefresh(ctx);
|
|
261
283
|
ensurePolling();
|
|
262
284
|
}
|
|
263
285
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/extensions/ui.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/extensions/ui.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,+BAA+B,CAAC;AAq/CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QAkO3C;AAED,eAAe,WAAW,CAAC"}
|
package/dist/extensions/ui.js
CHANGED
|
@@ -7,7 +7,10 @@ const UI_PICKER_LIST_ITEMS_MAX = 4;
|
|
|
7
7
|
const UI_PICKER_KEYVALUE_ROWS_MAX = 4;
|
|
8
8
|
const UI_SESSION_KEY_FALLBACK = "__mu_ui_active_session__";
|
|
9
9
|
const UI_PROMPT_PREVIEW_MAX = 160;
|
|
10
|
-
const
|
|
10
|
+
const UI_INTERACT_SHORTCUT_PRIMARY = "ctrl+shift+u";
|
|
11
|
+
const UI_INTERACT_SHORTCUT_FALLBACK = "alt+u";
|
|
12
|
+
const UI_INTERACT_SHORTCUTS = [UI_INTERACT_SHORTCUT_PRIMARY, UI_INTERACT_SHORTCUT_FALLBACK];
|
|
13
|
+
const UI_INTERACT_SHORTCUT_HINT = `${UI_INTERACT_SHORTCUT_PRIMARY} or ${UI_INTERACT_SHORTCUT_FALLBACK}`;
|
|
11
14
|
const UI_PICKER_PANEL_MIN_WIDTH = 56;
|
|
12
15
|
const UI_PICKER_PANEL_MAX_WIDTH = 118;
|
|
13
16
|
const UI_PICKER_PANEL_WIDTH_RATIO = 0.9;
|
|
@@ -41,6 +44,8 @@ function createState() {
|
|
|
41
44
|
promptedRevisionKeys: new Set(),
|
|
42
45
|
awaitingUiIds: new Set(),
|
|
43
46
|
interactionDepth: 0,
|
|
47
|
+
lastStatusText: null,
|
|
48
|
+
lastWidgetSignature: null,
|
|
44
49
|
};
|
|
45
50
|
}
|
|
46
51
|
function pruneStaleStates(nowMs) {
|
|
@@ -1211,11 +1216,30 @@ function refreshUi(ctx) {
|
|
|
1211
1216
|
if (!ctx.hasUI) {
|
|
1212
1217
|
return;
|
|
1213
1218
|
}
|
|
1219
|
+
const commitStatus = (next) => {
|
|
1220
|
+
if (state.lastStatusText === next) {
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
state.lastStatusText = next;
|
|
1224
|
+
ctx.ui.setStatus("mu-ui", next ?? undefined);
|
|
1225
|
+
};
|
|
1226
|
+
const commitWidget = (next) => {
|
|
1227
|
+
const signature = next && next.length > 0 ? next.join("\n") : null;
|
|
1228
|
+
if (state.lastWidgetSignature === signature) {
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
state.lastWidgetSignature = signature;
|
|
1232
|
+
if (next && next.length > 0) {
|
|
1233
|
+
ctx.ui.setWidget("mu-ui", next, { placement: "belowEditor" });
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
ctx.ui.setWidget("mu-ui", undefined);
|
|
1237
|
+
};
|
|
1214
1238
|
retainAwaitingUiIdsForActiveDocs(state);
|
|
1215
1239
|
const docs = activeDocs(state);
|
|
1216
1240
|
if (docs.length === 0) {
|
|
1217
|
-
|
|
1218
|
-
|
|
1241
|
+
commitStatus(null);
|
|
1242
|
+
commitWidget(null);
|
|
1219
1243
|
return;
|
|
1220
1244
|
}
|
|
1221
1245
|
const awaiting = awaitingDocs(state, docs);
|
|
@@ -1237,14 +1261,8 @@ function refreshUi(ctx) {
|
|
|
1237
1261
|
statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("dim", `async ${asyncStatusDocs.length}`));
|
|
1238
1262
|
}
|
|
1239
1263
|
statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("text", labels));
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
if (widgetLines && widgetLines.length > 0) {
|
|
1243
|
-
ctx.ui.setWidget("mu-ui", widgetLines, { placement: "belowEditor" });
|
|
1244
|
-
}
|
|
1245
|
-
else {
|
|
1246
|
-
ctx.ui.setWidget("mu-ui", undefined);
|
|
1247
|
-
}
|
|
1264
|
+
commitStatus(statusParts.join(" "));
|
|
1265
|
+
commitWidget(asyncStatusWidgetLines(ctx, docs));
|
|
1248
1266
|
}
|
|
1249
1267
|
export function uiExtension(pi) {
|
|
1250
1268
|
const commandUsage = "/mu ui status|snapshot [compact|multiline]|interact [ui_id [action_id]]";
|
|
@@ -1376,15 +1394,17 @@ export function uiExtension(pi) {
|
|
|
1376
1394
|
ctx.ui.notify(usage, "info");
|
|
1377
1395
|
},
|
|
1378
1396
|
});
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1397
|
+
for (const shortcut of UI_INTERACT_SHORTCUTS) {
|
|
1398
|
+
pi.registerShortcut(shortcut, {
|
|
1399
|
+
description: "Open programmable UI modal and optionally submit prompt",
|
|
1400
|
+
handler: async (ctx) => {
|
|
1401
|
+
const key = sessionKey(ctx);
|
|
1402
|
+
const state = ensureState(key);
|
|
1403
|
+
await runUiActionFromDoc(ctx, state);
|
|
1404
|
+
refreshUi(ctx);
|
|
1405
|
+
},
|
|
1406
|
+
});
|
|
1407
|
+
}
|
|
1388
1408
|
pi.registerTool({
|
|
1389
1409
|
name: "mu_ui",
|
|
1390
1410
|
label: "mu UI",
|
|
@@ -1434,7 +1454,7 @@ export function uiExtension(pi) {
|
|
|
1434
1454
|
return;
|
|
1435
1455
|
}
|
|
1436
1456
|
if (pending.kind === "action") {
|
|
1437
|
-
ctx.ui.notify(`Agent requested input via ${pending.uiId}. Submit now or press ${
|
|
1457
|
+
ctx.ui.notify(`Agent requested input via ${pending.uiId}. Submit now or press ${UI_INTERACT_SHORTCUT_HINT} later.`, "info");
|
|
1438
1458
|
}
|
|
1439
1459
|
await runUiActionFromDoc(ctx, state, pending.uiId, pending.actionId);
|
|
1440
1460
|
refreshUi(ctx);
|
|
@@ -1442,6 +1462,9 @@ export function uiExtension(pi) {
|
|
|
1442
1462
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
1443
1463
|
const key = sessionKey(ctx);
|
|
1444
1464
|
touchState(key);
|
|
1465
|
+
const state = ensureState(key);
|
|
1466
|
+
state.lastStatusText = null;
|
|
1467
|
+
state.lastWidgetSignature = null;
|
|
1445
1468
|
if (!ctx.hasUI) {
|
|
1446
1469
|
return;
|
|
1447
1470
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.119",
|
|
4
4
|
"description": "Shared operator runtime for mu assistant sessions and serve extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mu",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"themes/**"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@femtomc/mu-core": "26.2.
|
|
27
|
+
"@femtomc/mu-core": "26.2.119",
|
|
28
28
|
"@mariozechner/pi-agent-core": "^0.54.2",
|
|
29
29
|
"@mariozechner/pi-ai": "^0.54.2",
|
|
30
30
|
"@mariozechner/pi-coding-agent": "^0.54.2",
|