@femtomc/mu-agent 26.2.115 → 26.2.117

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.
@@ -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;AAw4CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QA6N3C;AAED,eAAe,WAAW,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;AA89CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QA6N3C;AAED,eAAe,WAAW,CAAC"}
@@ -20,6 +20,8 @@ const UI_PICKER_TWO_PANE_LEFT_MIN = 24;
20
20
  const UI_PICKER_TWO_PANE_RIGHT_MIN = 32;
21
21
  const UI_PICKER_TWO_PANE_SEPARATOR_WIDTH = 3;
22
22
  const UI_PICKER_INTERACTION_HINT = "↑/↓ move · tab switch pane · enter select/submit · esc cancel · click rows";
23
+ const UI_ASYNC_WIDGET_DOCS_MAX = 4;
24
+ const UI_ASYNC_WIDGET_SNAPSHOT_MAX = 96;
23
25
  const UI_ENABLE_MOUSE_TRACKING = "\x1b[?1000h\x1b[?1006h";
24
26
  const UI_DISABLE_MOUSE_TRACKING = "\x1b[?1000l\x1b[?1006l";
25
27
  const UI_INTERACT_OVERLAY_OPTIONS = {
@@ -106,7 +108,7 @@ function retainPendingPromptsForActiveDocs(state) {
106
108
  return false;
107
109
  }
108
110
  if (pending.kind === "review") {
109
- return isStatusProfileStatusVariant(doc);
111
+ return isReviewStatusProfileStatusVariant(doc);
110
112
  }
111
113
  const actions = runnableActions(doc);
112
114
  if (actions.length === 0) {
@@ -160,7 +162,9 @@ function armAutoPromptForUiDocs(state, changedUiIds) {
160
162
  enqueuePendingPrompt(state, { kind: "action", uiId: doc.ui_id, actionId });
161
163
  state.promptedRevisionKeys.add(docRevisionKey(doc));
162
164
  }
163
- const statusCandidates = unpromptedDocs.filter((doc) => isStatusProfileStatusVariant(doc)).sort(byMostRecentRevision);
165
+ const statusCandidates = unpromptedDocs
166
+ .filter((doc) => isReviewStatusProfileStatusVariant(doc))
167
+ .sort(byMostRecentRevision);
164
168
  if (statusCandidates.length > 0) {
165
169
  const doc = statusCandidates[0];
166
170
  enqueuePendingPrompt(state, { kind: "review", uiId: doc.ui_id });
@@ -221,9 +225,39 @@ function statusProfileVariant(doc) {
221
225
  const rawVariant = typeof profile?.variant === "string" ? profile.variant.trim().toLowerCase() : "";
222
226
  return rawVariant.length > 0 ? rawVariant : "status";
223
227
  }
228
+ const UI_STATUS_PROFILE_ASYNC_DEFAULT_IDS = new Set([
229
+ "planning",
230
+ "subagents",
231
+ "control-flow",
232
+ "model-routing",
233
+ ]);
224
234
  function isStatusProfileStatusVariant(doc) {
225
235
  return statusProfileId(doc) !== null && statusProfileVariant(doc) === "status";
226
236
  }
237
+ function statusProfileDelivery(doc) {
238
+ if (!isStatusProfileStatusVariant(doc)) {
239
+ return "review";
240
+ }
241
+ const profile = statusProfileMetadata(doc);
242
+ const rawDelivery = typeof profile?.delivery === "string" ? profile.delivery.trim().toLowerCase() : "";
243
+ if (rawDelivery === "async") {
244
+ return "async";
245
+ }
246
+ if (rawDelivery === "review") {
247
+ return "review";
248
+ }
249
+ const profileId = statusProfileId(doc)?.trim().toLowerCase();
250
+ if (profileId && UI_STATUS_PROFILE_ASYNC_DEFAULT_IDS.has(profileId)) {
251
+ return "async";
252
+ }
253
+ return "review";
254
+ }
255
+ function isAsyncStatusProfileStatusVariant(doc) {
256
+ return isStatusProfileStatusVariant(doc) && statusProfileDelivery(doc) === "async";
257
+ }
258
+ function isReviewStatusProfileStatusVariant(doc) {
259
+ return isStatusProfileStatusVariant(doc) && statusProfileDelivery(doc) === "review";
260
+ }
227
261
  function statusProfileSnapshot(doc, format) {
228
262
  if (!isStatusProfileStatusVariant(doc)) {
229
263
  return null;
@@ -865,7 +899,9 @@ class UiActionPickerComponent {
865
899
  const selectedDoc = this.#currentEntry().doc;
866
900
  const selectedActions = this.#currentActions();
867
901
  const renderLines = [];
868
- const innerPadSegment = horizontalPadding > 0 ? this.#theme.bg("customMessageBg", " ".repeat(horizontalPadding)) : "";
902
+ const panelBg = (text) => this.#theme.bg("customMessageBg", text);
903
+ const borderCell = (tone, text) => panelBg(this.#theme.fg(tone, text));
904
+ const innerPadSegment = horizontalPadding > 0 ? panelBg(" ".repeat(horizontalPadding)) : "";
869
905
  const contentRowText = (line, bg) => {
870
906
  const core = this.#theme.bg(bg, fitStyledLine(line, contentWidth));
871
907
  return `${innerPadSegment}${core}${innerPadSegment}`;
@@ -956,16 +992,16 @@ class UiActionPickerComponent {
956
992
  const titleWidth = Math.min(innerWidth, visibleWidth(title));
957
993
  const leftRule = "─".repeat(Math.max(0, Math.floor((innerWidth - titleWidth) / 2)));
958
994
  const rightRule = "─".repeat(Math.max(0, innerWidth - titleWidth - leftRule.length));
959
- frame.push(`${leftPad}${this.#theme.fg("borderAccent", `╭${leftRule}`)}${this.#theme.fg("accent", title)}${this.#theme.fg("borderAccent", `${rightRule}╮`)}`);
995
+ frame.push(`${leftPad}${panelBg(`${this.#theme.fg("borderAccent", `╭${leftRule}`)}${this.#theme.fg("accent", title)}${this.#theme.fg("borderAccent", `${rightRule}╮`)}`)}`);
960
996
  this.#mouseTargets = [];
961
- const blankInnerRow = `${leftPad}${this.#theme.fg("border", "│")}${this.#theme.bg("customMessageBg", " ".repeat(innerWidth))}${this.#theme.fg("border", "│")}`;
997
+ const blankInnerRow = `${leftPad}${borderCell("border", "│")}${panelBg(" ".repeat(innerWidth))}${borderCell("border", "│")}`;
962
998
  for (let row = 0; row < verticalPadding; row += 1) {
963
999
  frame.push(blankInnerRow);
964
1000
  }
965
1001
  const contentStartRow = frame.length + 1;
966
1002
  for (let idx = 0; idx < renderLines.length; idx += 1) {
967
1003
  const line = renderLines[idx];
968
- frame.push(`${leftPad}${this.#theme.fg("border", "│")}${line.text}${this.#theme.fg("border", "│")}`);
1004
+ frame.push(`${leftPad}${borderCell("border", "│")}${line.text}${borderCell("border", "│")}`);
969
1005
  const row = contentStartRow + idx;
970
1006
  if (line.docTarget) {
971
1007
  this.#mouseTargets.push({
@@ -989,7 +1025,7 @@ class UiActionPickerComponent {
989
1025
  for (let row = 0; row < verticalPadding; row += 1) {
990
1026
  frame.push(blankInnerRow);
991
1027
  }
992
- frame.push(`${leftPad}${this.#theme.fg("borderAccent", `╰${"─".repeat(innerWidth)}╯`)}`);
1028
+ frame.push(`${leftPad}${borderCell("borderAccent", `╰${"─".repeat(innerWidth)}╯`)}`);
993
1029
  for (let row = 0; row < bottomMarginRows; row += 1) {
994
1030
  frame.push("");
995
1031
  }
@@ -1135,6 +1171,40 @@ function buildToolResult(opts) {
1135
1171
  };
1136
1172
  return result;
1137
1173
  }
1174
+ function asyncStatusWidgetLines(ctx, docs) {
1175
+ if (!ctx.hasUI) {
1176
+ return null;
1177
+ }
1178
+ const asyncDocs = docs
1179
+ .filter((doc) => isAsyncStatusProfileStatusVariant(doc))
1180
+ .sort((left, right) => {
1181
+ if (left.updated_at_ms !== right.updated_at_ms) {
1182
+ return right.updated_at_ms - left.updated_at_ms;
1183
+ }
1184
+ return left.ui_id.localeCompare(right.ui_id);
1185
+ });
1186
+ if (asyncDocs.length === 0) {
1187
+ return null;
1188
+ }
1189
+ const visible = asyncDocs.slice(0, UI_ASYNC_WIDGET_DOCS_MAX);
1190
+ const lines = [
1191
+ ctx.ui.theme.fg("dim", `ui async status · ${asyncDocs.length} ${pluralize(asyncDocs.length, "doc")}`),
1192
+ ];
1193
+ for (const doc of visible) {
1194
+ const profileId = statusProfileId(doc) ?? doc.ui_id;
1195
+ const snapshot = statusProfileSnapshot(doc, "compact") ?? doc.summary ?? `${doc.title} (${doc.revision.version})`;
1196
+ lines.push([
1197
+ ctx.ui.theme.fg("muted", " •"),
1198
+ ctx.ui.theme.fg("text", short(profileId, 24)),
1199
+ ctx.ui.theme.fg("muted", "·"),
1200
+ ctx.ui.theme.fg("dim", short(snapshot, UI_ASYNC_WIDGET_SNAPSHOT_MAX)),
1201
+ ].join(" "));
1202
+ }
1203
+ if (asyncDocs.length > visible.length) {
1204
+ lines.push(ctx.ui.theme.fg("muted", ` ... (+${asyncDocs.length - visible.length} more)`));
1205
+ }
1206
+ return lines;
1207
+ }
1138
1208
  function refreshUi(ctx) {
1139
1209
  const key = sessionKey(ctx);
1140
1210
  const state = ensureState(key);
@@ -1149,22 +1219,32 @@ function refreshUi(ctx) {
1149
1219
  return;
1150
1220
  }
1151
1221
  const awaiting = awaitingDocs(state, docs);
1222
+ const asyncStatusDocs = docs.filter((doc) => isAsyncStatusProfileStatusVariant(doc));
1152
1223
  const labels = docs.map((doc) => doc.ui_id).join(", ");
1153
1224
  const readiness = state.interactionDepth > 0
1154
1225
  ? ctx.ui.theme.fg("accent", "prompting")
1155
1226
  : awaiting.length > 0
1156
1227
  ? ctx.ui.theme.fg("accent", `awaiting ${awaiting.length}`)
1157
1228
  : ctx.ui.theme.fg("dim", "ready");
1158
- ctx.ui.setStatus("mu-ui", [
1229
+ const statusParts = [
1159
1230
  ctx.ui.theme.fg("dim", "ui"),
1160
1231
  ctx.ui.theme.fg("muted", "·"),
1161
1232
  ctx.ui.theme.fg("accent", `${docs.length}`),
1162
1233
  ctx.ui.theme.fg("muted", "·"),
1163
1234
  readiness,
1164
- ctx.ui.theme.fg("muted", "·"),
1165
- ctx.ui.theme.fg("text", labels),
1166
- ].join(" "));
1167
- ctx.ui.setWidget("mu-ui", undefined);
1235
+ ];
1236
+ if (asyncStatusDocs.length > 0) {
1237
+ statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("dim", `async ${asyncStatusDocs.length}`));
1238
+ }
1239
+ statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("text", labels));
1240
+ ctx.ui.setStatus("mu-ui", statusParts.join(" "));
1241
+ const widgetLines = asyncStatusWidgetLines(ctx, docs);
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
+ }
1168
1248
  }
1169
1249
  export function uiExtension(pi) {
1170
1250
  const commandUsage = "/mu ui status|snapshot [compact|multiline]|interact [ui_id [action_id]]";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@femtomc/mu-agent",
3
- "version": "26.2.115",
3
+ "version": "26.2.117",
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.115",
27
+ "@femtomc/mu-core": "26.2.117",
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",