@femtomc/mu-agent 26.2.116 → 26.2.118
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/ui.d.ts.map +1 -1
- package/dist/extensions/ui.js +101 -18
- 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":"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;AAi+CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QA+N3C;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;
|
|
@@ -20,6 +23,8 @@ const UI_PICKER_TWO_PANE_LEFT_MIN = 24;
|
|
|
20
23
|
const UI_PICKER_TWO_PANE_RIGHT_MIN = 32;
|
|
21
24
|
const UI_PICKER_TWO_PANE_SEPARATOR_WIDTH = 3;
|
|
22
25
|
const UI_PICKER_INTERACTION_HINT = "↑/↓ move · tab switch pane · enter select/submit · esc cancel · click rows";
|
|
26
|
+
const UI_ASYNC_WIDGET_DOCS_MAX = 4;
|
|
27
|
+
const UI_ASYNC_WIDGET_SNAPSHOT_MAX = 96;
|
|
23
28
|
const UI_ENABLE_MOUSE_TRACKING = "\x1b[?1000h\x1b[?1006h";
|
|
24
29
|
const UI_DISABLE_MOUSE_TRACKING = "\x1b[?1000l\x1b[?1006l";
|
|
25
30
|
const UI_INTERACT_OVERLAY_OPTIONS = {
|
|
@@ -106,7 +111,7 @@ function retainPendingPromptsForActiveDocs(state) {
|
|
|
106
111
|
return false;
|
|
107
112
|
}
|
|
108
113
|
if (pending.kind === "review") {
|
|
109
|
-
return
|
|
114
|
+
return isReviewStatusProfileStatusVariant(doc);
|
|
110
115
|
}
|
|
111
116
|
const actions = runnableActions(doc);
|
|
112
117
|
if (actions.length === 0) {
|
|
@@ -160,7 +165,9 @@ function armAutoPromptForUiDocs(state, changedUiIds) {
|
|
|
160
165
|
enqueuePendingPrompt(state, { kind: "action", uiId: doc.ui_id, actionId });
|
|
161
166
|
state.promptedRevisionKeys.add(docRevisionKey(doc));
|
|
162
167
|
}
|
|
163
|
-
const statusCandidates = unpromptedDocs
|
|
168
|
+
const statusCandidates = unpromptedDocs
|
|
169
|
+
.filter((doc) => isReviewStatusProfileStatusVariant(doc))
|
|
170
|
+
.sort(byMostRecentRevision);
|
|
164
171
|
if (statusCandidates.length > 0) {
|
|
165
172
|
const doc = statusCandidates[0];
|
|
166
173
|
enqueuePendingPrompt(state, { kind: "review", uiId: doc.ui_id });
|
|
@@ -221,9 +228,39 @@ function statusProfileVariant(doc) {
|
|
|
221
228
|
const rawVariant = typeof profile?.variant === "string" ? profile.variant.trim().toLowerCase() : "";
|
|
222
229
|
return rawVariant.length > 0 ? rawVariant : "status";
|
|
223
230
|
}
|
|
231
|
+
const UI_STATUS_PROFILE_ASYNC_DEFAULT_IDS = new Set([
|
|
232
|
+
"planning",
|
|
233
|
+
"subagents",
|
|
234
|
+
"control-flow",
|
|
235
|
+
"model-routing",
|
|
236
|
+
]);
|
|
224
237
|
function isStatusProfileStatusVariant(doc) {
|
|
225
238
|
return statusProfileId(doc) !== null && statusProfileVariant(doc) === "status";
|
|
226
239
|
}
|
|
240
|
+
function statusProfileDelivery(doc) {
|
|
241
|
+
if (!isStatusProfileStatusVariant(doc)) {
|
|
242
|
+
return "review";
|
|
243
|
+
}
|
|
244
|
+
const profile = statusProfileMetadata(doc);
|
|
245
|
+
const rawDelivery = typeof profile?.delivery === "string" ? profile.delivery.trim().toLowerCase() : "";
|
|
246
|
+
if (rawDelivery === "async") {
|
|
247
|
+
return "async";
|
|
248
|
+
}
|
|
249
|
+
if (rawDelivery === "review") {
|
|
250
|
+
return "review";
|
|
251
|
+
}
|
|
252
|
+
const profileId = statusProfileId(doc)?.trim().toLowerCase();
|
|
253
|
+
if (profileId && UI_STATUS_PROFILE_ASYNC_DEFAULT_IDS.has(profileId)) {
|
|
254
|
+
return "async";
|
|
255
|
+
}
|
|
256
|
+
return "review";
|
|
257
|
+
}
|
|
258
|
+
function isAsyncStatusProfileStatusVariant(doc) {
|
|
259
|
+
return isStatusProfileStatusVariant(doc) && statusProfileDelivery(doc) === "async";
|
|
260
|
+
}
|
|
261
|
+
function isReviewStatusProfileStatusVariant(doc) {
|
|
262
|
+
return isStatusProfileStatusVariant(doc) && statusProfileDelivery(doc) === "review";
|
|
263
|
+
}
|
|
227
264
|
function statusProfileSnapshot(doc, format) {
|
|
228
265
|
if (!isStatusProfileStatusVariant(doc)) {
|
|
229
266
|
return null;
|
|
@@ -1137,6 +1174,40 @@ function buildToolResult(opts) {
|
|
|
1137
1174
|
};
|
|
1138
1175
|
return result;
|
|
1139
1176
|
}
|
|
1177
|
+
function asyncStatusWidgetLines(ctx, docs) {
|
|
1178
|
+
if (!ctx.hasUI) {
|
|
1179
|
+
return null;
|
|
1180
|
+
}
|
|
1181
|
+
const asyncDocs = docs
|
|
1182
|
+
.filter((doc) => isAsyncStatusProfileStatusVariant(doc))
|
|
1183
|
+
.sort((left, right) => {
|
|
1184
|
+
if (left.updated_at_ms !== right.updated_at_ms) {
|
|
1185
|
+
return right.updated_at_ms - left.updated_at_ms;
|
|
1186
|
+
}
|
|
1187
|
+
return left.ui_id.localeCompare(right.ui_id);
|
|
1188
|
+
});
|
|
1189
|
+
if (asyncDocs.length === 0) {
|
|
1190
|
+
return null;
|
|
1191
|
+
}
|
|
1192
|
+
const visible = asyncDocs.slice(0, UI_ASYNC_WIDGET_DOCS_MAX);
|
|
1193
|
+
const lines = [
|
|
1194
|
+
ctx.ui.theme.fg("dim", `ui async status · ${asyncDocs.length} ${pluralize(asyncDocs.length, "doc")}`),
|
|
1195
|
+
];
|
|
1196
|
+
for (const doc of visible) {
|
|
1197
|
+
const profileId = statusProfileId(doc) ?? doc.ui_id;
|
|
1198
|
+
const snapshot = statusProfileSnapshot(doc, "compact") ?? doc.summary ?? `${doc.title} (${doc.revision.version})`;
|
|
1199
|
+
lines.push([
|
|
1200
|
+
ctx.ui.theme.fg("muted", " •"),
|
|
1201
|
+
ctx.ui.theme.fg("text", short(profileId, 24)),
|
|
1202
|
+
ctx.ui.theme.fg("muted", "·"),
|
|
1203
|
+
ctx.ui.theme.fg("dim", short(snapshot, UI_ASYNC_WIDGET_SNAPSHOT_MAX)),
|
|
1204
|
+
].join(" "));
|
|
1205
|
+
}
|
|
1206
|
+
if (asyncDocs.length > visible.length) {
|
|
1207
|
+
lines.push(ctx.ui.theme.fg("muted", ` ... (+${asyncDocs.length - visible.length} more)`));
|
|
1208
|
+
}
|
|
1209
|
+
return lines;
|
|
1210
|
+
}
|
|
1140
1211
|
function refreshUi(ctx) {
|
|
1141
1212
|
const key = sessionKey(ctx);
|
|
1142
1213
|
const state = ensureState(key);
|
|
@@ -1151,22 +1222,32 @@ function refreshUi(ctx) {
|
|
|
1151
1222
|
return;
|
|
1152
1223
|
}
|
|
1153
1224
|
const awaiting = awaitingDocs(state, docs);
|
|
1225
|
+
const asyncStatusDocs = docs.filter((doc) => isAsyncStatusProfileStatusVariant(doc));
|
|
1154
1226
|
const labels = docs.map((doc) => doc.ui_id).join(", ");
|
|
1155
1227
|
const readiness = state.interactionDepth > 0
|
|
1156
1228
|
? ctx.ui.theme.fg("accent", "prompting")
|
|
1157
1229
|
: awaiting.length > 0
|
|
1158
1230
|
? ctx.ui.theme.fg("accent", `awaiting ${awaiting.length}`)
|
|
1159
1231
|
: ctx.ui.theme.fg("dim", "ready");
|
|
1160
|
-
|
|
1232
|
+
const statusParts = [
|
|
1161
1233
|
ctx.ui.theme.fg("dim", "ui"),
|
|
1162
1234
|
ctx.ui.theme.fg("muted", "·"),
|
|
1163
1235
|
ctx.ui.theme.fg("accent", `${docs.length}`),
|
|
1164
1236
|
ctx.ui.theme.fg("muted", "·"),
|
|
1165
1237
|
readiness,
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1238
|
+
];
|
|
1239
|
+
if (asyncStatusDocs.length > 0) {
|
|
1240
|
+
statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("dim", `async ${asyncStatusDocs.length}`));
|
|
1241
|
+
}
|
|
1242
|
+
statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("text", labels));
|
|
1243
|
+
ctx.ui.setStatus("mu-ui", statusParts.join(" "));
|
|
1244
|
+
const widgetLines = asyncStatusWidgetLines(ctx, docs);
|
|
1245
|
+
if (widgetLines && widgetLines.length > 0) {
|
|
1246
|
+
ctx.ui.setWidget("mu-ui", widgetLines, { placement: "belowEditor" });
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
ctx.ui.setWidget("mu-ui", undefined);
|
|
1250
|
+
}
|
|
1170
1251
|
}
|
|
1171
1252
|
export function uiExtension(pi) {
|
|
1172
1253
|
const commandUsage = "/mu ui status|snapshot [compact|multiline]|interact [ui_id [action_id]]";
|
|
@@ -1298,15 +1379,17 @@ export function uiExtension(pi) {
|
|
|
1298
1379
|
ctx.ui.notify(usage, "info");
|
|
1299
1380
|
},
|
|
1300
1381
|
});
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1382
|
+
for (const shortcut of UI_INTERACT_SHORTCUTS) {
|
|
1383
|
+
pi.registerShortcut(shortcut, {
|
|
1384
|
+
description: "Open programmable UI modal and optionally submit prompt",
|
|
1385
|
+
handler: async (ctx) => {
|
|
1386
|
+
const key = sessionKey(ctx);
|
|
1387
|
+
const state = ensureState(key);
|
|
1388
|
+
await runUiActionFromDoc(ctx, state);
|
|
1389
|
+
refreshUi(ctx);
|
|
1390
|
+
},
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1310
1393
|
pi.registerTool({
|
|
1311
1394
|
name: "mu_ui",
|
|
1312
1395
|
label: "mu UI",
|
|
@@ -1356,7 +1439,7 @@ export function uiExtension(pi) {
|
|
|
1356
1439
|
return;
|
|
1357
1440
|
}
|
|
1358
1441
|
if (pending.kind === "action") {
|
|
1359
|
-
ctx.ui.notify(`Agent requested input via ${pending.uiId}. Submit now or press ${
|
|
1442
|
+
ctx.ui.notify(`Agent requested input via ${pending.uiId}. Submit now or press ${UI_INTERACT_SHORTCUT_HINT} later.`, "info");
|
|
1360
1443
|
}
|
|
1361
1444
|
await runUiActionFromDoc(ctx, state, pending.uiId, pending.actionId);
|
|
1362
1445
|
refreshUi(ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@femtomc/mu-agent",
|
|
3
|
-
"version": "26.2.
|
|
3
|
+
"version": "26.2.118",
|
|
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.118",
|
|
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",
|