@femtomc/mu-agent 26.2.118 → 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.
@@ -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;AAwEpF,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,QAoOjD;AAED,eAAe,iBAAiB,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
- if (!ctx.hasUI || !enabled)
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(4_000);
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
- void refreshStatus(activeCtx);
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
- async function initialize(ctx) {
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
- await refreshStatus(ctx);
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", async (_event, ctx) => {
217
- await initialize(ctx);
237
+ pi.on("session_start", (_event, ctx) => {
238
+ initialize(ctx);
218
239
  });
219
- pi.on("session_switch", async (_event, ctx) => {
220
- await initialize(ctx);
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
- await refreshStatus(ctx);
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;AAi+CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QA+N3C;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;AAq/CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QAkO3C;AAED,eAAe,WAAW,CAAC"}
@@ -44,6 +44,8 @@ function createState() {
44
44
  promptedRevisionKeys: new Set(),
45
45
  awaitingUiIds: new Set(),
46
46
  interactionDepth: 0,
47
+ lastStatusText: null,
48
+ lastWidgetSignature: null,
47
49
  };
48
50
  }
49
51
  function pruneStaleStates(nowMs) {
@@ -1214,11 +1216,30 @@ function refreshUi(ctx) {
1214
1216
  if (!ctx.hasUI) {
1215
1217
  return;
1216
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
+ };
1217
1238
  retainAwaitingUiIdsForActiveDocs(state);
1218
1239
  const docs = activeDocs(state);
1219
1240
  if (docs.length === 0) {
1220
- ctx.ui.setStatus("mu-ui", undefined);
1221
- ctx.ui.setWidget("mu-ui", undefined);
1241
+ commitStatus(null);
1242
+ commitWidget(null);
1222
1243
  return;
1223
1244
  }
1224
1245
  const awaiting = awaitingDocs(state, docs);
@@ -1240,14 +1261,8 @@ function refreshUi(ctx) {
1240
1261
  statusParts.push(ctx.ui.theme.fg("muted", "·"), ctx.ui.theme.fg("dim", `async ${asyncStatusDocs.length}`));
1241
1262
  }
1242
1263
  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
- }
1264
+ commitStatus(statusParts.join(" "));
1265
+ commitWidget(asyncStatusWidgetLines(ctx, docs));
1251
1266
  }
1252
1267
  export function uiExtension(pi) {
1253
1268
  const commandUsage = "/mu ui status|snapshot [compact|multiline]|interact [ui_id [action_id]]";
@@ -1447,6 +1462,9 @@ export function uiExtension(pi) {
1447
1462
  pi.on("session_shutdown", (_event, ctx) => {
1448
1463
  const key = sessionKey(ctx);
1449
1464
  touchState(key);
1465
+ const state = ensureState(key);
1466
+ state.lastStatusText = null;
1467
+ state.lastWidgetSignature = null;
1450
1468
  if (!ctx.hasUI) {
1451
1469
  return;
1452
1470
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@femtomc/mu-agent",
3
- "version": "26.2.118",
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.118",
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",