@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.
- package/assets/mu-tui-logo.png +0 -0
- package/dist/extensions/ui.d.ts.map +1 -1
- package/dist/extensions/ui.js +344 -51
- package/package.json +2 -2
package/assets/mu-tui-logo.png
CHANGED
|
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;
|
|
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"}
|
package/dist/extensions/ui.js
CHANGED
|
@@ -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
|
|
637
|
-
const
|
|
638
|
-
|
|
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
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
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
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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
|
-
|
|
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((
|
|
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.
|
|
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.
|
|
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",
|