@femtomc/mu-agent 26.2.110 → 26.2.112

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.
Binary file
@@ -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;AAs/BpF,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;AA82CpF,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,QA6N3C;AAED,eAAe,WAAW,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { normalizeUiDocs, parseUiDoc, resolveUiStatusProfileName, uiStatusProfileWarnings, } from "@femtomc/mu-core";
2
- import { matchesKey } from "@mariozechner/pi-tui";
2
+ import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
3
3
  import { registerMuSubcommand } from "./mu-command-dispatcher.js";
4
4
  const UI_DISPLAY_DOCS_MAX = 16;
5
5
  const UI_PICKER_COMPONENTS_MAX = 8;
@@ -8,6 +8,18 @@ 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
10
  const UI_INTERACT_SHORTCUT = "ctrl+shift+u";
11
+ const UI_PICKER_PANEL_MIN_WIDTH = 56;
12
+ const UI_PICKER_PANEL_MAX_WIDTH = 118;
13
+ const UI_PICKER_PANEL_WIDTH_RATIO = 0.9;
14
+ const UI_PICKER_PANEL_TOP_MARGIN = 1;
15
+ const UI_PICKER_PANEL_BOTTOM_MARGIN = 1;
16
+ const UI_PICKER_TWO_PANE_MIN_WIDTH = 92;
17
+ const UI_PICKER_TWO_PANE_LEFT_MIN = 24;
18
+ const UI_PICKER_TWO_PANE_RIGHT_MIN = 32;
19
+ const UI_PICKER_TWO_PANE_SEPARATOR_WIDTH = 3;
20
+ const UI_PICKER_INTERACTION_HINT = "↑/↓ move · tab switch pane · enter select/submit · esc cancel · click rows";
21
+ const UI_ENABLE_MOUSE_TRACKING = "\x1b[?1000h\x1b[?1006h";
22
+ const UI_DISABLE_MOUSE_TRACKING = "\x1b[?1000l\x1b[?1006l";
11
23
  const UI_INTERACT_OVERLAY_OPTIONS = {
12
24
  anchor: "top-left",
13
25
  row: 0,
@@ -487,6 +499,45 @@ function boundedIndex(index, length) {
487
499
  }
488
500
  return index;
489
501
  }
502
+ function parseSgrMouseEvent(data) {
503
+ const match = /^\x1b\[<(\d+);(\d+);(\d+)([Mm])$/.exec(data);
504
+ if (!match) {
505
+ return null;
506
+ }
507
+ const buttonCode = Number.parseInt(match[1] ?? "", 10);
508
+ const col = Number.parseInt(match[2] ?? "", 10);
509
+ const row = Number.parseInt(match[3] ?? "", 10);
510
+ if (!Number.isInteger(buttonCode) || !Number.isInteger(col) || !Number.isInteger(row)) {
511
+ return null;
512
+ }
513
+ return {
514
+ buttonCode,
515
+ col,
516
+ row,
517
+ release: match[4] === "m",
518
+ };
519
+ }
520
+ function isPrimaryMouseRelease(event) {
521
+ if (!event.release) {
522
+ return false;
523
+ }
524
+ if (event.buttonCode >= 64) {
525
+ return false;
526
+ }
527
+ const primaryButton = event.buttonCode & 0b11;
528
+ return primaryButton === 0;
529
+ }
530
+ function fitStyledLine(text, width) {
531
+ const trimmed = truncateToWidth(text, width, "…", true);
532
+ const missing = width - visibleWidth(trimmed);
533
+ if (missing <= 0) {
534
+ return trimmed;
535
+ }
536
+ return `${trimmed}${" ".repeat(missing)}`;
537
+ }
538
+ function pluralize(count, singular, plural = `${singular}s`) {
539
+ return count === 1 ? singular : plural;
540
+ }
490
541
  function pickerComponentLines(component) {
491
542
  switch (component.kind) {
492
543
  case "text":
@@ -525,13 +576,21 @@ function pickerComponentLines(component) {
525
576
  }
526
577
  }
527
578
  class UiActionPickerComponent {
579
+ #tui;
528
580
  #entries;
529
581
  #theme;
530
582
  #done;
531
583
  #mode = "doc";
532
584
  #docIndex = 0;
533
585
  #actionIndex = 0;
586
+ #mouseEnabled = false;
587
+ #panelRowStart = 1;
588
+ #panelRowEnd = 1;
589
+ #panelColStart = 1;
590
+ #panelColEnd = 1;
591
+ #mouseTargets = [];
534
592
  constructor(opts) {
593
+ this.#tui = opts.tui;
535
594
  this.#entries = opts.entries;
536
595
  this.#theme = opts.theme;
537
596
  this.#done = opts.done;
@@ -549,6 +608,21 @@ class UiActionPickerComponent {
549
608
  this.#mode = "action";
550
609
  }
551
610
  }
611
+ this.#enableMouseTracking();
612
+ }
613
+ #enableMouseTracking() {
614
+ if (this.#mouseEnabled) {
615
+ return;
616
+ }
617
+ this.#tui.terminal.write(UI_ENABLE_MOUSE_TRACKING);
618
+ this.#mouseEnabled = true;
619
+ }
620
+ #disableMouseTracking() {
621
+ if (!this.#mouseEnabled) {
622
+ return;
623
+ }
624
+ this.#tui.terminal.write(UI_DISABLE_MOUSE_TRACKING);
625
+ this.#mouseEnabled = false;
552
626
  }
553
627
  #currentEntry() {
554
628
  return this.#entries[this.#docIndex];
@@ -583,7 +657,152 @@ class UiActionPickerComponent {
583
657
  action,
584
658
  });
585
659
  }
660
+ #kindChip(action) {
661
+ switch (action.kind) {
662
+ case "primary":
663
+ return this.#theme.fg("success", "[primary]");
664
+ case "danger":
665
+ return this.#theme.fg("error", "[danger]");
666
+ case "link":
667
+ return this.#theme.fg("accent", "[link]");
668
+ case "secondary":
669
+ default:
670
+ return this.#theme.fg("muted", "[secondary]");
671
+ }
672
+ }
673
+ #buildDocsLines() {
674
+ const lines = [];
675
+ lines.push({
676
+ text: this.#theme.fg(this.#mode === "doc" ? "accent" : "dim", `Documents (${this.#entries.length})`),
677
+ });
678
+ for (let idx = 0; idx < this.#entries.length; idx += 1) {
679
+ const entry = this.#entries[idx];
680
+ const active = idx === this.#docIndex;
681
+ const marker = active ? (this.#mode === "doc" ? "▶" : "▸") : " ";
682
+ const actionCount = entry.actions.length;
683
+ const actionLabel = actionCount > 0
684
+ ? `${actionCount} ${pluralize(actionCount, "action")}`
685
+ : "status";
686
+ const title = this.#theme.fg(active ? "text" : "muted", `${marker} ${entry.doc.title}`);
687
+ const meta = this.#theme.fg("dim", `${entry.doc.ui_id} · ${actionLabel}`);
688
+ lines.push({
689
+ text: `${title} ${meta}`,
690
+ selected: active,
691
+ docIndex: idx,
692
+ });
693
+ }
694
+ return lines;
695
+ }
696
+ #buildDetailLines() {
697
+ const lines = [];
698
+ const selectedDoc = this.#currentEntry().doc;
699
+ const selectedActions = this.#currentActions();
700
+ lines.push({ text: this.#theme.fg("accent", selectedDoc.title) });
701
+ lines.push({
702
+ text: this.#theme.fg("dim", `${selectedDoc.ui_id} · revision ${selectedDoc.revision.version}`),
703
+ });
704
+ if (selectedDoc.summary) {
705
+ lines.push({ text: this.#theme.fg("dim", `Summary: ${selectedDoc.summary}`) });
706
+ }
707
+ lines.push({ text: "" });
708
+ lines.push({
709
+ text: this.#theme.fg("dim", `Components (${selectedDoc.components.length})`),
710
+ });
711
+ const visibleComponents = selectedDoc.components.slice(0, UI_PICKER_COMPONENTS_MAX);
712
+ for (const component of visibleComponents) {
713
+ const componentLines = pickerComponentLines(component);
714
+ for (let idx = 0; idx < componentLines.length; idx += 1) {
715
+ const line = componentLines[idx];
716
+ const prefix = idx === 0 ? " " : " ";
717
+ lines.push({ text: this.#theme.fg("text", `${prefix}${line}`) });
718
+ }
719
+ }
720
+ if (selectedDoc.components.length > visibleComponents.length) {
721
+ lines.push({
722
+ text: this.#theme.fg("muted", ` ... (+${selectedDoc.components.length - visibleComponents.length} more components)`),
723
+ });
724
+ }
725
+ lines.push({ text: "" });
726
+ lines.push({
727
+ text: this.#theme.fg(this.#mode === "action" ? "accent" : "dim", `Actions (${selectedActions.length})`),
728
+ });
729
+ for (let idx = 0; idx < selectedActions.length; idx += 1) {
730
+ const action = selectedActions[idx];
731
+ const active = idx === this.#actionIndex;
732
+ const marker = active ? (this.#mode === "action" ? "▶" : "▸") : " ";
733
+ const label = this.#theme.fg(active ? "text" : "muted", `${marker} ${action.label}`);
734
+ const chip = this.#kindChip(action);
735
+ const idLabel = this.#theme.fg("dim", `#${action.id}`);
736
+ lines.push({
737
+ text: `${label} ${chip} ${idLabel}`,
738
+ selected: active,
739
+ actionIndex: idx,
740
+ });
741
+ }
742
+ const action = this.#currentAction();
743
+ if (action?.description) {
744
+ lines.push({ text: "" });
745
+ lines.push({ text: this.#theme.fg("dim", `Ask: ${action.description}`) });
746
+ }
747
+ if (action?.component_id) {
748
+ lines.push({
749
+ text: this.#theme.fg("dim", `Targets component: ${action.component_id}`),
750
+ });
751
+ }
752
+ const commandText = action ? actionCommandText(action) : null;
753
+ if (commandText) {
754
+ lines.push({ text: "" });
755
+ lines.push({ text: this.#theme.fg("dim", `Prompt template: ${commandText}`) });
756
+ }
757
+ return lines;
758
+ }
759
+ #singleColumnLines() {
760
+ const lines = [];
761
+ const docs = this.#buildDocsLines();
762
+ const detail = this.#buildDetailLines();
763
+ for (const line of docs) {
764
+ lines.push(line);
765
+ }
766
+ lines.push({ text: "" });
767
+ for (const line of detail) {
768
+ lines.push(line);
769
+ }
770
+ return lines;
771
+ }
772
+ #handleMouseEvent(event) {
773
+ if (!isPrimaryMouseRelease(event)) {
774
+ return;
775
+ }
776
+ if (event.row < this.#panelRowStart ||
777
+ event.row > this.#panelRowEnd ||
778
+ event.col < this.#panelColStart ||
779
+ event.col > this.#panelColEnd) {
780
+ return;
781
+ }
782
+ const target = this.#mouseTargets.find((candidate) => {
783
+ return (candidate.row === event.row &&
784
+ event.col >= candidate.colStart &&
785
+ event.col <= candidate.colEnd);
786
+ });
787
+ if (!target) {
788
+ return;
789
+ }
790
+ if (target.kind === "doc") {
791
+ this.#docIndex = boundedIndex(target.index, this.#entries.length);
792
+ this.#actionIndex = boundedIndex(this.#actionIndex, this.#currentActions().length);
793
+ this.#mode = "doc";
794
+ return;
795
+ }
796
+ this.#mode = "action";
797
+ this.#actionIndex = boundedIndex(target.index, this.#currentActions().length);
798
+ this.#submit();
799
+ }
586
800
  handleInput(data) {
801
+ const mouse = parseSgrMouseEvent(data);
802
+ if (mouse) {
803
+ this.#handleMouseEvent(mouse);
804
+ return;
805
+ }
587
806
  if (matchesKey(data, "escape")) {
588
807
  this.#done(null);
589
808
  return;
@@ -632,67 +851,141 @@ class UiActionPickerComponent {
632
851
  invalidate() {
633
852
  // No cached state.
634
853
  }
854
+ dispose() {
855
+ this.#disableMouseTracking();
856
+ }
635
857
  render(width) {
636
- const maxWidth = Math.max(24, width - 2);
637
- const lines = [];
638
- lines.push(this.#theme.fg("accent", short("Programmable UI", maxWidth)));
639
- lines.push(this.#theme.fg("dim", short("↑/↓ move · tab switch · enter select/submit · esc cancel", maxWidth)));
640
- lines.push("");
641
- lines.push(this.#theme.fg(this.#mode === "doc" ? "accent" : "dim", short(`Documents (${this.#entries.length})`, maxWidth)));
642
- for (let idx = 0; idx < this.#entries.length; idx += 1) {
643
- const entry = this.#entries[idx];
644
- const active = idx === this.#docIndex;
645
- const marker = active ? (this.#mode === "doc" ? "▶" : "▸") : " ";
646
- const label = `${marker} ${entry.doc.ui_id} · ${entry.doc.title}`;
647
- lines.push(this.#theme.fg(active ? "accent" : "muted", short(label, maxWidth)));
648
- }
858
+ const panelTargetWidth = Math.max(UI_PICKER_PANEL_MIN_WIDTH, Math.min(UI_PICKER_PANEL_MAX_WIDTH, Math.floor(width * UI_PICKER_PANEL_WIDTH_RATIO)));
859
+ const panelWidth = Math.max(4, Math.min(width, panelTargetWidth));
860
+ const innerWidth = Math.max(1, panelWidth - 2);
649
861
  const selectedDoc = this.#currentEntry().doc;
650
- if (selectedDoc.summary) {
651
- lines.push("");
652
- lines.push(this.#theme.fg("dim", short(`Summary: ${selectedDoc.summary}`, maxWidth)));
653
- }
654
- lines.push("");
655
- lines.push(this.#theme.fg("dim", short(`Components (${selectedDoc.components.length})`, maxWidth)));
656
- const visibleComponents = selectedDoc.components.slice(0, UI_PICKER_COMPONENTS_MAX);
657
- for (const component of visibleComponents) {
658
- const componentLines = pickerComponentLines(component);
659
- for (let idx = 0; idx < componentLines.length; idx += 1) {
660
- const line = componentLines[idx];
661
- const prefix = idx === 0 ? " " : " ";
662
- lines.push(this.#theme.fg("text", short(`${prefix}${line}`, maxWidth)));
862
+ const selectedActions = this.#currentActions();
863
+ const renderLines = [];
864
+ const pushFullLine = (line) => {
865
+ renderLines.push({
866
+ text: this.#theme.bg("customMessageBg", fitStyledLine(line, innerWidth)),
867
+ });
868
+ };
869
+ const modeLabel = this.#mode === "action" ? "action focus" : "document focus";
870
+ pushFullLine(`${this.#theme.fg("accent", "mu_ui")}${this.#theme.fg("dim", ` · ${this.#entries.length} ${pluralize(this.#entries.length, "doc")} · ${modeLabel}`)}`);
871
+ pushFullLine(this.#theme.fg("dim", short(UI_PICKER_INTERACTION_HINT, Math.max(8, innerWidth))));
872
+ pushFullLine(this.#theme.fg("borderMuted", "─".repeat(innerWidth)));
873
+ const minTwoPaneWidth = UI_PICKER_TWO_PANE_LEFT_MIN + UI_PICKER_TWO_PANE_RIGHT_MIN + UI_PICKER_TWO_PANE_SEPARATOR_WIDTH;
874
+ const useTwoPane = innerWidth >= UI_PICKER_TWO_PANE_MIN_WIDTH && innerWidth >= minTwoPaneWidth;
875
+ if (useTwoPane) {
876
+ let leftWidth = Math.max(UI_PICKER_TWO_PANE_LEFT_MIN, Math.floor(innerWidth * 0.34));
877
+ let rightWidth = innerWidth - leftWidth - UI_PICKER_TWO_PANE_SEPARATOR_WIDTH;
878
+ if (rightWidth < UI_PICKER_TWO_PANE_RIGHT_MIN) {
879
+ leftWidth = Math.max(UI_PICKER_TWO_PANE_LEFT_MIN, innerWidth - UI_PICKER_TWO_PANE_RIGHT_MIN - UI_PICKER_TWO_PANE_SEPARATOR_WIDTH);
880
+ rightWidth = innerWidth - leftWidth - UI_PICKER_TWO_PANE_SEPARATOR_WIDTH;
881
+ }
882
+ const leftLines = this.#buildDocsLines();
883
+ const rightLines = this.#buildDetailLines();
884
+ const rowCount = Math.max(leftLines.length, rightLines.length);
885
+ for (let idx = 0; idx < rowCount; idx += 1) {
886
+ const left = leftLines[idx];
887
+ const right = rightLines[idx];
888
+ const leftCell = this.#theme.bg(left?.selected ? "selectedBg" : "customMessageBg", fitStyledLine(left?.text ?? "", leftWidth));
889
+ const separator = this.#theme.bg("customMessageBg", this.#theme.fg("borderMuted", " │ "));
890
+ const rightCell = this.#theme.bg(right?.selected ? "selectedBg" : "customMessageBg", fitStyledLine(right?.text ?? "", rightWidth));
891
+ const row = {
892
+ text: `${leftCell}${separator}${rightCell}`,
893
+ };
894
+ if (left?.docIndex !== undefined) {
895
+ row.docTarget = {
896
+ index: left.docIndex,
897
+ colStart: 1,
898
+ colEnd: leftWidth,
899
+ };
900
+ }
901
+ if (right?.actionIndex !== undefined) {
902
+ row.actionTarget = {
903
+ index: right.actionIndex,
904
+ colStart: leftWidth + UI_PICKER_TWO_PANE_SEPARATOR_WIDTH + 1,
905
+ colEnd: leftWidth + UI_PICKER_TWO_PANE_SEPARATOR_WIDTH + rightWidth,
906
+ };
907
+ }
908
+ renderLines.push(row);
663
909
  }
664
910
  }
665
- if (selectedDoc.components.length > visibleComponents.length) {
666
- lines.push(this.#theme.fg("muted", short(` ... (+${selectedDoc.components.length - visibleComponents.length} more components)`, maxWidth)));
667
- }
668
- const actions = this.#currentActions();
669
- lines.push("");
670
- lines.push(this.#theme.fg(this.#mode === "action" ? "accent" : "dim", short(`Actions (${actions.length})`, maxWidth)));
671
- for (let idx = 0; idx < actions.length; idx += 1) {
672
- const action = actions[idx];
673
- const active = idx === this.#actionIndex;
674
- const marker = active ? (this.#mode === "action" ? "▶" : "▸") : " ";
675
- const label = `${marker} ${action.id} · ${action.label}`;
676
- lines.push(this.#theme.fg(active ? "accent" : "text", short(label, maxWidth)));
911
+ else {
912
+ const singleColumn = this.#singleColumnLines();
913
+ for (const line of singleColumn) {
914
+ const row = {
915
+ text: this.#theme.bg(line.selected ? "selectedBg" : "customMessageBg", fitStyledLine(line.text, innerWidth)),
916
+ };
917
+ if (line.docIndex !== undefined) {
918
+ row.docTarget = {
919
+ index: line.docIndex,
920
+ colStart: 1,
921
+ colEnd: innerWidth,
922
+ };
923
+ }
924
+ if (line.actionIndex !== undefined) {
925
+ row.actionTarget = {
926
+ index: line.actionIndex,
927
+ colStart: 1,
928
+ colEnd: innerWidth,
929
+ };
930
+ }
931
+ renderLines.push(row);
932
+ }
677
933
  }
678
- const action = this.#currentAction();
679
- if (action?.description) {
680
- lines.push("");
681
- lines.push(this.#theme.fg("dim", short(`Ask: ${action.description}`, maxWidth)));
934
+ pushFullLine(this.#theme.fg("borderMuted", "─".repeat(innerWidth)));
935
+ pushFullLine(this.#theme.fg("dim", short(`selected ${selectedDoc.ui_id} · revision ${selectedDoc.revision.version} · ${selectedActions.length} ${pluralize(selectedActions.length, "action")}`, Math.max(8, innerWidth))));
936
+ const topMarginRows = Math.max(0, UI_PICKER_PANEL_TOP_MARGIN);
937
+ const bottomMarginRows = Math.max(0, UI_PICKER_PANEL_BOTTOM_MARGIN);
938
+ const leftPadWidth = Math.max(0, Math.floor((width - panelWidth) / 2));
939
+ const leftPad = " ".repeat(leftPadWidth);
940
+ const panelColStart = leftPadWidth + 1;
941
+ const frame = [];
942
+ for (let row = 0; row < topMarginRows; row += 1) {
943
+ frame.push("");
682
944
  }
683
- if (action?.component_id) {
684
- lines.push(this.#theme.fg("dim", short(`Targets component: ${action.component_id}`, maxWidth)));
945
+ const title = " mu_ui ";
946
+ const titleWidth = Math.min(innerWidth, visibleWidth(title));
947
+ const leftRule = "─".repeat(Math.max(0, Math.floor((innerWidth - titleWidth) / 2)));
948
+ const rightRule = "─".repeat(Math.max(0, innerWidth - titleWidth - leftRule.length));
949
+ frame.push(`${leftPad}${this.#theme.fg("borderAccent", `╭${leftRule}`)}${this.#theme.fg("accent", title)}${this.#theme.fg("borderAccent", `${rightRule}╮`)}`);
950
+ this.#mouseTargets = [];
951
+ const contentStartRow = frame.length + 1;
952
+ for (let idx = 0; idx < renderLines.length; idx += 1) {
953
+ const line = renderLines[idx];
954
+ frame.push(`${leftPad}${this.#theme.fg("border", "│")}${line.text}${this.#theme.fg("border", "│")}`);
955
+ const row = contentStartRow + idx;
956
+ if (line.docTarget) {
957
+ this.#mouseTargets.push({
958
+ kind: "doc",
959
+ index: line.docTarget.index,
960
+ row,
961
+ colStart: panelColStart + line.docTarget.colStart,
962
+ colEnd: panelColStart + line.docTarget.colEnd,
963
+ });
964
+ }
965
+ if (line.actionTarget) {
966
+ this.#mouseTargets.push({
967
+ kind: "action",
968
+ index: line.actionTarget.index,
969
+ row,
970
+ colStart: panelColStart + line.actionTarget.colStart,
971
+ colEnd: panelColStart + line.actionTarget.colEnd,
972
+ });
973
+ }
685
974
  }
686
- const commandText = action ? actionCommandText(action) : null;
687
- if (commandText) {
688
- lines.push("");
689
- lines.push(this.#theme.fg("dim", short(`Prompt template: ${commandText}`, maxWidth)));
975
+ frame.push(`${leftPad}${this.#theme.fg("borderAccent", `╰${"─".repeat(innerWidth)}╯`)}`);
976
+ for (let row = 0; row < bottomMarginRows; row += 1) {
977
+ frame.push("");
690
978
  }
691
- return lines;
979
+ this.#panelRowStart = topMarginRows + 1;
980
+ this.#panelRowEnd = this.#panelRowStart + renderLines.length + 1;
981
+ this.#panelColStart = panelColStart;
982
+ this.#panelColEnd = leftPadWidth + panelWidth;
983
+ return frame;
692
984
  }
693
985
  }
694
986
  async function pickUiActionInteractively(opts) {
695
- const selected = await opts.ctx.ui.custom((_tui, theme, _keybindings, done) => new UiActionPickerComponent({
987
+ const selected = await opts.ctx.ui.custom((tui, theme, _keybindings, done) => new UiActionPickerComponent({
988
+ tui,
696
989
  entries: opts.entries,
697
990
  theme: theme,
698
991
  done,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@femtomc/mu-agent",
3
- "version": "26.2.110",
3
+ "version": "26.2.112",
4
4
  "description": "Shared operator runtime for mu assistant sessions and serve extensions.",
5
5
  "keywords": [
6
6
  "mu",
@@ -25,7 +25,7 @@
25
25
  "themes/**"
26
26
  ],
27
27
  "dependencies": {
28
- "@femtomc/mu-core": "26.2.110",
28
+ "@femtomc/mu-core": "26.2.112",
29
29
  "@mariozechner/pi-agent-core": "^0.54.2",
30
30
  "@mariozechner/pi-ai": "^0.54.2",
31
31
  "@mariozechner/pi-coding-agent": "^0.54.2",