@austinthesing/magic-shell 0.2.7 → 0.2.9

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.
Files changed (3) hide show
  1. package/dist/cli.js +622 -59
  2. package/dist/tui.js +622 -59
  3. package/package.json +1 -1
package/dist/tui.js CHANGED
@@ -20475,6 +20475,523 @@ class EditBufferRenderable extends Renderable {
20475
20475
  }
20476
20476
  }
20477
20477
  }
20478
+ var defaultTextareaKeybindings = [
20479
+ { name: "left", action: "move-left" },
20480
+ { name: "right", action: "move-right" },
20481
+ { name: "up", action: "move-up" },
20482
+ { name: "down", action: "move-down" },
20483
+ { name: "left", shift: true, action: "select-left" },
20484
+ { name: "right", shift: true, action: "select-right" },
20485
+ { name: "up", shift: true, action: "select-up" },
20486
+ { name: "down", shift: true, action: "select-down" },
20487
+ { name: "home", action: "buffer-home" },
20488
+ { name: "end", action: "buffer-end" },
20489
+ { name: "home", shift: true, action: "select-buffer-home" },
20490
+ { name: "end", shift: true, action: "select-buffer-end" },
20491
+ { name: "a", ctrl: true, action: "line-home" },
20492
+ { name: "e", ctrl: true, action: "line-end" },
20493
+ { name: "a", ctrl: true, shift: true, action: "select-line-home" },
20494
+ { name: "e", ctrl: true, shift: true, action: "select-line-end" },
20495
+ { name: "a", meta: true, action: "visual-line-home" },
20496
+ { name: "e", meta: true, action: "visual-line-end" },
20497
+ { name: "a", meta: true, shift: true, action: "select-visual-line-home" },
20498
+ { name: "e", meta: true, shift: true, action: "select-visual-line-end" },
20499
+ { name: "f", ctrl: true, action: "move-right" },
20500
+ { name: "b", ctrl: true, action: "move-left" },
20501
+ { name: "w", ctrl: true, action: "delete-word-backward" },
20502
+ { name: "backspace", ctrl: true, action: "delete-word-backward" },
20503
+ { name: "d", meta: true, action: "delete-word-forward" },
20504
+ { name: "delete", meta: true, action: "delete-word-forward" },
20505
+ { name: "delete", ctrl: true, action: "delete-word-forward" },
20506
+ { name: "d", ctrl: true, shift: true, action: "delete-line" },
20507
+ { name: "k", ctrl: true, action: "delete-to-line-end" },
20508
+ { name: "u", ctrl: true, action: "delete-to-line-start" },
20509
+ { name: "backspace", action: "backspace" },
20510
+ { name: "backspace", shift: true, action: "backspace" },
20511
+ { name: "d", ctrl: true, action: "delete" },
20512
+ { name: "delete", action: "delete" },
20513
+ { name: "delete", shift: true, action: "delete" },
20514
+ { name: "return", action: "newline" },
20515
+ { name: "linefeed", action: "newline" },
20516
+ { name: "return", meta: true, action: "submit" },
20517
+ { name: "-", ctrl: true, action: "undo" },
20518
+ { name: ".", ctrl: true, action: "redo" },
20519
+ { name: "z", super: true, action: "undo" },
20520
+ { name: "z", super: true, shift: true, action: "redo" },
20521
+ { name: "f", meta: true, action: "word-forward" },
20522
+ { name: "b", meta: true, action: "word-backward" },
20523
+ { name: "right", meta: true, action: "word-forward" },
20524
+ { name: "left", meta: true, action: "word-backward" },
20525
+ { name: "right", ctrl: true, action: "word-forward" },
20526
+ { name: "left", ctrl: true, action: "word-backward" },
20527
+ { name: "f", meta: true, shift: true, action: "select-word-forward" },
20528
+ { name: "b", meta: true, shift: true, action: "select-word-backward" },
20529
+ { name: "right", meta: true, shift: true, action: "select-word-forward" },
20530
+ { name: "left", meta: true, shift: true, action: "select-word-backward" },
20531
+ { name: "backspace", meta: true, action: "delete-word-backward" },
20532
+ { name: "left", super: true, action: "visual-line-home" },
20533
+ { name: "right", super: true, action: "visual-line-end" },
20534
+ { name: "up", super: true, action: "buffer-home" },
20535
+ { name: "down", super: true, action: "buffer-end" },
20536
+ { name: "left", super: true, shift: true, action: "select-visual-line-home" },
20537
+ { name: "right", super: true, shift: true, action: "select-visual-line-end" },
20538
+ { name: "up", super: true, shift: true, action: "select-buffer-home" },
20539
+ { name: "down", super: true, shift: true, action: "select-buffer-end" }
20540
+ ];
20541
+
20542
+ class TextareaRenderable extends EditBufferRenderable {
20543
+ _placeholder;
20544
+ _unfocusedBackgroundColor;
20545
+ _unfocusedTextColor;
20546
+ _focusedBackgroundColor;
20547
+ _focusedTextColor;
20548
+ _keyBindingsMap;
20549
+ _keyAliasMap;
20550
+ _keyBindings;
20551
+ _actionHandlers;
20552
+ _initialValueSet = false;
20553
+ _submitListener = undefined;
20554
+ static defaults = {
20555
+ backgroundColor: "transparent",
20556
+ textColor: "#FFFFFF",
20557
+ focusedBackgroundColor: "transparent",
20558
+ focusedTextColor: "#FFFFFF",
20559
+ placeholder: null
20560
+ };
20561
+ constructor(ctx, options) {
20562
+ const defaults = TextareaRenderable.defaults;
20563
+ const baseOptions = {
20564
+ ...options,
20565
+ backgroundColor: options.backgroundColor || defaults.backgroundColor,
20566
+ textColor: options.textColor || defaults.textColor
20567
+ };
20568
+ super(ctx, baseOptions);
20569
+ this._unfocusedBackgroundColor = parseColor(options.backgroundColor || defaults.backgroundColor);
20570
+ this._unfocusedTextColor = parseColor(options.textColor || defaults.textColor);
20571
+ this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || defaults.focusedBackgroundColor);
20572
+ this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || defaults.focusedTextColor);
20573
+ this._placeholder = options.placeholder ?? defaults.placeholder;
20574
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, options.keyAliasMap || {});
20575
+ this._keyBindings = options.keyBindings || [];
20576
+ const mergedBindings = mergeKeyBindings(defaultTextareaKeybindings, this._keyBindings);
20577
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap);
20578
+ this._actionHandlers = this.buildActionHandlers();
20579
+ this._submitListener = options.onSubmit;
20580
+ if (options.initialValue) {
20581
+ this.setText(options.initialValue);
20582
+ this._initialValueSet = true;
20583
+ }
20584
+ this.updateColors();
20585
+ this.applyPlaceholder(this._placeholder);
20586
+ }
20587
+ applyPlaceholder(placeholder) {
20588
+ if (placeholder === null) {
20589
+ this.editorView.setPlaceholderStyledText([]);
20590
+ return;
20591
+ }
20592
+ if (typeof placeholder === "string") {
20593
+ const defaultGray = fg("#666666");
20594
+ const chunks = [defaultGray(placeholder)];
20595
+ this.editorView.setPlaceholderStyledText(chunks);
20596
+ } else {
20597
+ this.editorView.setPlaceholderStyledText(placeholder.chunks);
20598
+ }
20599
+ }
20600
+ buildActionHandlers() {
20601
+ return new Map([
20602
+ ["move-left", () => this.moveCursorLeft()],
20603
+ ["move-right", () => this.moveCursorRight()],
20604
+ ["move-up", () => this.moveCursorUp()],
20605
+ ["move-down", () => this.moveCursorDown()],
20606
+ ["select-left", () => this.moveCursorLeft({ select: true })],
20607
+ ["select-right", () => this.moveCursorRight({ select: true })],
20608
+ ["select-up", () => this.moveCursorUp({ select: true })],
20609
+ ["select-down", () => this.moveCursorDown({ select: true })],
20610
+ ["line-home", () => this.gotoLineHome()],
20611
+ ["line-end", () => this.gotoLineEnd()],
20612
+ ["select-line-home", () => this.gotoLineHome({ select: true })],
20613
+ ["select-line-end", () => this.gotoLineEnd({ select: true })],
20614
+ ["visual-line-home", () => this.gotoVisualLineHome()],
20615
+ ["visual-line-end", () => this.gotoVisualLineEnd()],
20616
+ ["select-visual-line-home", () => this.gotoVisualLineHome({ select: true })],
20617
+ ["select-visual-line-end", () => this.gotoVisualLineEnd({ select: true })],
20618
+ ["select-buffer-home", () => this.gotoBufferHome({ select: true })],
20619
+ ["select-buffer-end", () => this.gotoBufferEnd({ select: true })],
20620
+ ["buffer-home", () => this.gotoBufferHome()],
20621
+ ["buffer-end", () => this.gotoBufferEnd()],
20622
+ ["delete-line", () => this.deleteLine()],
20623
+ ["delete-to-line-end", () => this.deleteToLineEnd()],
20624
+ ["delete-to-line-start", () => this.deleteToLineStart()],
20625
+ ["backspace", () => this.deleteCharBackward()],
20626
+ ["delete", () => this.deleteChar()],
20627
+ ["newline", () => this.newLine()],
20628
+ ["undo", () => this.undo()],
20629
+ ["redo", () => this.redo()],
20630
+ ["word-forward", () => this.moveWordForward()],
20631
+ ["word-backward", () => this.moveWordBackward()],
20632
+ ["select-word-forward", () => this.moveWordForward({ select: true })],
20633
+ ["select-word-backward", () => this.moveWordBackward({ select: true })],
20634
+ ["delete-word-forward", () => this.deleteWordForward()],
20635
+ ["delete-word-backward", () => this.deleteWordBackward()],
20636
+ ["submit", () => this.submit()]
20637
+ ]);
20638
+ }
20639
+ handlePaste(event) {
20640
+ this.insertText(event.text);
20641
+ }
20642
+ handleKeyPress(key) {
20643
+ const bindingKey = getKeyBindingKey({
20644
+ name: key.name,
20645
+ ctrl: key.ctrl,
20646
+ shift: key.shift,
20647
+ meta: key.meta,
20648
+ super: key.super,
20649
+ action: "move-left"
20650
+ });
20651
+ const action = this._keyBindingsMap.get(bindingKey);
20652
+ if (action) {
20653
+ const handler = this._actionHandlers.get(action);
20654
+ if (handler) {
20655
+ return handler();
20656
+ }
20657
+ }
20658
+ if (!key.ctrl && !key.meta && !key.super && !key.hyper) {
20659
+ if (key.name === "space") {
20660
+ this.insertText(" ");
20661
+ return true;
20662
+ }
20663
+ if (key.sequence) {
20664
+ const firstCharCode = key.sequence.charCodeAt(0);
20665
+ if (firstCharCode < 32) {
20666
+ return false;
20667
+ }
20668
+ if (firstCharCode === 127) {
20669
+ return false;
20670
+ }
20671
+ this.insertText(key.sequence);
20672
+ return true;
20673
+ }
20674
+ }
20675
+ return false;
20676
+ }
20677
+ updateColors() {
20678
+ const effectiveBg = this._focused ? this._focusedBackgroundColor : this._unfocusedBackgroundColor;
20679
+ const effectiveFg = this._focused ? this._focusedTextColor : this._unfocusedTextColor;
20680
+ super.backgroundColor = effectiveBg;
20681
+ super.textColor = effectiveFg;
20682
+ }
20683
+ insertChar(char) {
20684
+ if (this.hasSelection()) {
20685
+ this.deleteSelectedText();
20686
+ }
20687
+ this.editBuffer.insertChar(char);
20688
+ this.requestRender();
20689
+ }
20690
+ insertText(text) {
20691
+ if (this.hasSelection()) {
20692
+ this.deleteSelectedText();
20693
+ }
20694
+ this.editBuffer.insertText(text);
20695
+ this.requestRender();
20696
+ }
20697
+ deleteChar() {
20698
+ if (this.hasSelection()) {
20699
+ this.deleteSelectedText();
20700
+ return true;
20701
+ }
20702
+ this._ctx.clearSelection();
20703
+ this.editBuffer.deleteChar();
20704
+ this.requestRender();
20705
+ return true;
20706
+ }
20707
+ deleteCharBackward() {
20708
+ if (this.hasSelection()) {
20709
+ this.deleteSelectedText();
20710
+ return true;
20711
+ }
20712
+ this._ctx.clearSelection();
20713
+ this.editBuffer.deleteCharBackward();
20714
+ this.requestRender();
20715
+ return true;
20716
+ }
20717
+ deleteSelectedText() {
20718
+ this.editorView.deleteSelectedText();
20719
+ this._ctx.clearSelection();
20720
+ this.requestRender();
20721
+ }
20722
+ newLine() {
20723
+ this._ctx.clearSelection();
20724
+ this.editBuffer.newLine();
20725
+ this.requestRender();
20726
+ return true;
20727
+ }
20728
+ deleteLine() {
20729
+ this._ctx.clearSelection();
20730
+ this.editBuffer.deleteLine();
20731
+ this.requestRender();
20732
+ return true;
20733
+ }
20734
+ moveCursorLeft(options) {
20735
+ const select = options?.select ?? false;
20736
+ this.updateSelectionForMovement(select, true);
20737
+ this.editBuffer.moveCursorLeft();
20738
+ this.updateSelectionForMovement(select, false);
20739
+ this.requestRender();
20740
+ return true;
20741
+ }
20742
+ moveCursorRight(options) {
20743
+ const select = options?.select ?? false;
20744
+ this.updateSelectionForMovement(select, true);
20745
+ this.editBuffer.moveCursorRight();
20746
+ this.updateSelectionForMovement(select, false);
20747
+ this.requestRender();
20748
+ return true;
20749
+ }
20750
+ moveCursorUp(options) {
20751
+ const select = options?.select ?? false;
20752
+ this.updateSelectionForMovement(select, true);
20753
+ this.editorView.moveUpVisual();
20754
+ this.updateSelectionForMovement(select, false);
20755
+ this.requestRender();
20756
+ return true;
20757
+ }
20758
+ moveCursorDown(options) {
20759
+ const select = options?.select ?? false;
20760
+ this.updateSelectionForMovement(select, true);
20761
+ this.editorView.moveDownVisual();
20762
+ this.updateSelectionForMovement(select, false);
20763
+ this.requestRender();
20764
+ return true;
20765
+ }
20766
+ gotoLine(line) {
20767
+ this.editBuffer.gotoLine(line);
20768
+ this.requestRender();
20769
+ }
20770
+ gotoLineHome(options) {
20771
+ const select = options?.select ?? false;
20772
+ this.updateSelectionForMovement(select, true);
20773
+ const cursor = this.editorView.getCursor();
20774
+ if (cursor.col === 0 && cursor.row > 0) {
20775
+ this.editBuffer.setCursor(cursor.row - 1, 0);
20776
+ const prevLineEol = this.editBuffer.getEOL();
20777
+ this.editBuffer.setCursor(prevLineEol.row, prevLineEol.col);
20778
+ } else {
20779
+ this.editBuffer.setCursor(cursor.row, 0);
20780
+ }
20781
+ this.updateSelectionForMovement(select, false);
20782
+ this.requestRender();
20783
+ return true;
20784
+ }
20785
+ gotoLineEnd(options) {
20786
+ const select = options?.select ?? false;
20787
+ this.updateSelectionForMovement(select, true);
20788
+ const cursor = this.editorView.getCursor();
20789
+ const eol = this.editBuffer.getEOL();
20790
+ const lineCount = this.editBuffer.getLineCount();
20791
+ if (cursor.col === eol.col && cursor.row < lineCount - 1) {
20792
+ this.editBuffer.setCursor(cursor.row + 1, 0);
20793
+ } else {
20794
+ this.editBuffer.setCursor(eol.row, eol.col);
20795
+ }
20796
+ this.updateSelectionForMovement(select, false);
20797
+ this.requestRender();
20798
+ return true;
20799
+ }
20800
+ gotoVisualLineHome(options) {
20801
+ const select = options?.select ?? false;
20802
+ this.updateSelectionForMovement(select, true);
20803
+ const sol = this.editorView.getVisualSOL();
20804
+ this.editBuffer.setCursor(sol.logicalRow, sol.logicalCol);
20805
+ this.updateSelectionForMovement(select, false);
20806
+ this.requestRender();
20807
+ return true;
20808
+ }
20809
+ gotoVisualLineEnd(options) {
20810
+ const select = options?.select ?? false;
20811
+ this.updateSelectionForMovement(select, true);
20812
+ const eol = this.editorView.getVisualEOL();
20813
+ this.editBuffer.setCursor(eol.logicalRow, eol.logicalCol);
20814
+ this.updateSelectionForMovement(select, false);
20815
+ this.requestRender();
20816
+ return true;
20817
+ }
20818
+ gotoBufferHome(options) {
20819
+ const select = options?.select ?? false;
20820
+ this.updateSelectionForMovement(select, true);
20821
+ this.editBuffer.setCursor(0, 0);
20822
+ this.updateSelectionForMovement(select, false);
20823
+ this.requestRender();
20824
+ return true;
20825
+ }
20826
+ gotoBufferEnd(options) {
20827
+ const select = options?.select ?? false;
20828
+ this.updateSelectionForMovement(select, true);
20829
+ this.editBuffer.gotoLine(999999);
20830
+ this.updateSelectionForMovement(select, false);
20831
+ this.requestRender();
20832
+ return true;
20833
+ }
20834
+ deleteToLineEnd() {
20835
+ const cursor = this.editorView.getCursor();
20836
+ const eol = this.editBuffer.getEOL();
20837
+ if (eol.col > cursor.col) {
20838
+ this.editBuffer.deleteRange(cursor.row, cursor.col, eol.row, eol.col);
20839
+ }
20840
+ this.requestRender();
20841
+ return true;
20842
+ }
20843
+ deleteToLineStart() {
20844
+ const cursor = this.editorView.getCursor();
20845
+ if (cursor.col > 0) {
20846
+ this.editBuffer.deleteRange(cursor.row, 0, cursor.row, cursor.col);
20847
+ }
20848
+ this.requestRender();
20849
+ return true;
20850
+ }
20851
+ undo() {
20852
+ this._ctx.clearSelection();
20853
+ this.editBuffer.undo();
20854
+ this.requestRender();
20855
+ return true;
20856
+ }
20857
+ redo() {
20858
+ this._ctx.clearSelection();
20859
+ this.editBuffer.redo();
20860
+ this.requestRender();
20861
+ return true;
20862
+ }
20863
+ moveWordForward(options) {
20864
+ const select = options?.select ?? false;
20865
+ this.updateSelectionForMovement(select, true);
20866
+ const nextWord = this.editBuffer.getNextWordBoundary();
20867
+ this.editBuffer.setCursorByOffset(nextWord.offset);
20868
+ this.updateSelectionForMovement(select, false);
20869
+ this.requestRender();
20870
+ return true;
20871
+ }
20872
+ moveWordBackward(options) {
20873
+ const select = options?.select ?? false;
20874
+ this.updateSelectionForMovement(select, true);
20875
+ const prevWord = this.editBuffer.getPrevWordBoundary();
20876
+ this.editBuffer.setCursorByOffset(prevWord.offset);
20877
+ this.updateSelectionForMovement(select, false);
20878
+ this.requestRender();
20879
+ return true;
20880
+ }
20881
+ deleteWordForward() {
20882
+ if (this.hasSelection()) {
20883
+ this.deleteSelectedText();
20884
+ return true;
20885
+ }
20886
+ const currentCursor = this.editBuffer.getCursorPosition();
20887
+ const nextWord = this.editBuffer.getNextWordBoundary();
20888
+ if (nextWord.offset > currentCursor.offset) {
20889
+ this.editBuffer.deleteRange(currentCursor.row, currentCursor.col, nextWord.row, nextWord.col);
20890
+ }
20891
+ this._ctx.clearSelection();
20892
+ this.requestRender();
20893
+ return true;
20894
+ }
20895
+ deleteWordBackward() {
20896
+ if (this.hasSelection()) {
20897
+ this.deleteSelectedText();
20898
+ return true;
20899
+ }
20900
+ const currentCursor = this.editBuffer.getCursorPosition();
20901
+ const prevWord = this.editBuffer.getPrevWordBoundary();
20902
+ if (prevWord.offset < currentCursor.offset) {
20903
+ this.editBuffer.deleteRange(prevWord.row, prevWord.col, currentCursor.row, currentCursor.col);
20904
+ }
20905
+ this._ctx.clearSelection();
20906
+ this.requestRender();
20907
+ return true;
20908
+ }
20909
+ focus() {
20910
+ super.focus();
20911
+ this.updateColors();
20912
+ }
20913
+ blur() {
20914
+ super.blur();
20915
+ if (!this.isDestroyed) {
20916
+ this.updateColors();
20917
+ }
20918
+ }
20919
+ get placeholder() {
20920
+ return this._placeholder;
20921
+ }
20922
+ set placeholder(value) {
20923
+ if (this._placeholder !== value) {
20924
+ this._placeholder = value;
20925
+ this.applyPlaceholder(value);
20926
+ this.requestRender();
20927
+ }
20928
+ }
20929
+ get backgroundColor() {
20930
+ return this._unfocusedBackgroundColor;
20931
+ }
20932
+ set backgroundColor(value) {
20933
+ const newColor = parseColor(value ?? TextareaRenderable.defaults.backgroundColor);
20934
+ if (this._unfocusedBackgroundColor !== newColor) {
20935
+ this._unfocusedBackgroundColor = newColor;
20936
+ this.updateColors();
20937
+ }
20938
+ }
20939
+ get textColor() {
20940
+ return this._unfocusedTextColor;
20941
+ }
20942
+ set textColor(value) {
20943
+ const newColor = parseColor(value ?? TextareaRenderable.defaults.textColor);
20944
+ if (this._unfocusedTextColor !== newColor) {
20945
+ this._unfocusedTextColor = newColor;
20946
+ this.updateColors();
20947
+ }
20948
+ }
20949
+ set focusedBackgroundColor(value) {
20950
+ const newColor = parseColor(value ?? TextareaRenderable.defaults.focusedBackgroundColor);
20951
+ if (this._focusedBackgroundColor !== newColor) {
20952
+ this._focusedBackgroundColor = newColor;
20953
+ this.updateColors();
20954
+ }
20955
+ }
20956
+ set focusedTextColor(value) {
20957
+ const newColor = parseColor(value ?? TextareaRenderable.defaults.focusedTextColor);
20958
+ if (this._focusedTextColor !== newColor) {
20959
+ this._focusedTextColor = newColor;
20960
+ this.updateColors();
20961
+ }
20962
+ }
20963
+ set initialValue(value) {
20964
+ if (!this._initialValueSet) {
20965
+ this.setText(value);
20966
+ this._initialValueSet = true;
20967
+ }
20968
+ }
20969
+ submit() {
20970
+ if (this._submitListener) {
20971
+ this._submitListener({});
20972
+ }
20973
+ return true;
20974
+ }
20975
+ set onSubmit(handler) {
20976
+ this._submitListener = handler;
20977
+ }
20978
+ get onSubmit() {
20979
+ return this._submitListener;
20980
+ }
20981
+ set keyBindings(bindings) {
20982
+ this._keyBindings = bindings;
20983
+ const mergedBindings = mergeKeyBindings(defaultTextareaKeybindings, bindings);
20984
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap);
20985
+ }
20986
+ set keyAliasMap(aliases) {
20987
+ this._keyAliasMap = mergeKeyAliases(defaultKeyAliases, aliases);
20988
+ const mergedBindings = mergeKeyBindings(defaultTextareaKeybindings, this._keyBindings);
20989
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings, this._keyAliasMap);
20990
+ }
20991
+ get extmarks() {
20992
+ return this.editorView.extmarks;
20993
+ }
20994
+ }
20478
20995
 
20479
20996
  // src/cli.ts
20480
20997
  import { spawn } from "child_process";
@@ -22106,6 +22623,8 @@ var headerText;
22106
22623
  var statusBarText;
22107
22624
  var chatScrollBox;
22108
22625
  var inputField;
22626
+ var inputContainer;
22627
+ var inputHintText;
22109
22628
  var helpBarText;
22110
22629
  var modelSelector = null;
22111
22630
  var providerSelector = null;
@@ -22333,43 +22852,53 @@ function createMainUI() {
22333
22852
  });
22334
22853
  mainContainer.add(chatScrollBox);
22335
22854
  addSystemMessage(getWelcomeMessage());
22336
- const inputRow = new BoxRenderable(renderer, {
22337
- id: "input-row",
22338
- flexDirection: "row",
22855
+ inputContainer = new BoxRenderable(renderer, {
22856
+ id: "input-container",
22857
+ flexDirection: "column",
22339
22858
  width: "100%",
22340
22859
  marginTop: 1,
22341
- alignItems: "center"
22342
- });
22343
- mainContainer.add(inputRow);
22344
- const promptText = new TextRenderable(renderer, {
22345
- id: "prompt-text",
22346
- content: t`${fg(theme.colors.primary)("~>")} `,
22347
- width: 3,
22348
- height: 1
22860
+ border: true,
22861
+ borderColor: theme.colors.primary,
22862
+ borderStyle: "rounded",
22863
+ paddingLeft: 1,
22864
+ paddingRight: 1,
22865
+ paddingTop: 0,
22866
+ paddingBottom: 0,
22867
+ backgroundColor: theme.colors.backgroundPanel
22349
22868
  });
22350
- inputRow.add(promptText);
22351
- inputField = new InputRenderable(renderer, {
22869
+ mainContainer.add(inputContainer);
22870
+ inputField = new TextareaRenderable(renderer, {
22352
22871
  id: "input-field",
22353
- flexGrow: 1,
22354
- height: 1,
22355
- placeholder: "describe what you want to do...",
22872
+ width: "100%",
22873
+ height: 3,
22874
+ placeholder: t`${fg(theme.colors.textMuted)("Describe what you want to do...")}`,
22356
22875
  backgroundColor: "transparent",
22357
- focusedBackgroundColor: theme.colors.backgroundPanel,
22876
+ focusedBackgroundColor: "transparent",
22358
22877
  textColor: theme.colors.text,
22359
- placeholderColor: theme.colors.textMuted,
22360
- cursorColor: theme.colors.primary,
22361
- onPaste: (event) => {
22362
- inputField.insertText(event.text);
22878
+ keyBindings: [
22879
+ { name: "return", action: "submit" },
22880
+ { name: "linefeed", action: "submit" },
22881
+ { name: "return", shift: true, action: "newline" },
22882
+ { name: "linefeed", shift: true, action: "newline" },
22883
+ { name: "return", meta: true, action: "submit" }
22884
+ ],
22885
+ onSubmit: () => {
22886
+ const value = inputField.editBuffer.getText();
22887
+ handleInput(value);
22363
22888
  }
22364
22889
  });
22365
- inputRow.add(inputField);
22890
+ inputContainer.add(inputField);
22891
+ inputHintText = new TextRenderable(renderer, {
22892
+ id: "input-hint",
22893
+ content: getInputHintContent()
22894
+ });
22895
+ inputContainer.add(inputHintText);
22366
22896
  helpBarText = new TextRenderable(renderer, {
22367
22897
  id: "help-bar-text",
22368
22898
  content: getHelpBarContent(),
22369
22899
  marginTop: 1
22370
22900
  });
22371
22901
  mainContainer.add(helpBarText);
22372
- inputField.on(InputRenderableEvents.ENTER, handleInput);
22373
22902
  renderer.keyInput.on("keypress", handleKeypress);
22374
22903
  inputField.focus();
22375
22904
  }
@@ -22385,10 +22914,14 @@ function getStatusBarContent() {
22385
22914
  function getHelpBarContent() {
22386
22915
  const theme = getTheme();
22387
22916
  if (awaitingConfirmation) {
22388
- return t`${fg(theme.colors.warning)(">>> Press Enter to execute command <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22917
+ return t`${fg(theme.colors.warning)(">>> Cmd+Enter or Enter to execute <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22389
22918
  }
22390
22919
  return t`${fg(theme.colors.primary)("Ctrl+X P")}${fg(theme.colors.textMuted)(" Commands")} ${fg(theme.colors.primary)("Ctrl+Y")}${fg(theme.colors.textMuted)(" Safety")} ${fg(theme.colors.primary)("Ctrl+Z")}${fg(theme.colors.textMuted)(" Exit")}`;
22391
22920
  }
22921
+ function getInputHintContent() {
22922
+ const theme = getTheme();
22923
+ return t`${fg(theme.colors.textMuted)("Enter")}${fg(theme.colors.border)(" send")} ${fg(theme.colors.textMuted)("Shift+Enter")}${fg(theme.colors.border)(" newline")}`;
22924
+ }
22392
22925
  function getWelcomeMessage() {
22393
22926
  const providerName = config.provider === "opencode-zen" ? "OpenCode Zen" : "OpenRouter";
22394
22927
  const freeNote = config.provider === "opencode-zen" ? `
@@ -22432,13 +22965,15 @@ function addAssistantMessage(content, command, safety) {
22432
22965
  renderMessage(msg);
22433
22966
  return msg;
22434
22967
  }
22435
- function addResultMessage(content, exitCode) {
22968
+ function addResultMessage(content, exitCode, executionKind, parentMessageId) {
22436
22969
  const msg = {
22437
22970
  id: generateMessageId(),
22438
22971
  type: "result",
22439
22972
  content,
22440
22973
  timestamp: Date.now(),
22441
- exitCode
22974
+ exitCode,
22975
+ executionKind,
22976
+ parentMessageId
22442
22977
  };
22443
22978
  chatMessages.push(msg);
22444
22979
  renderMessage(msg);
@@ -22483,7 +23018,7 @@ function createAssistantMessageRenderable(msg, theme) {
22483
23018
  width: "100%",
22484
23019
  border: true,
22485
23020
  borderColor: isSelected ? theme.colors.primary : theme.colors.border,
22486
- borderStyle: "single",
23021
+ borderStyle: "rounded",
22487
23022
  paddingLeft: 1,
22488
23023
  paddingRight: 1,
22489
23024
  paddingTop: 0,
@@ -22492,34 +23027,32 @@ function createAssistantMessageRenderable(msg, theme) {
22492
23027
  });
22493
23028
  const commandText = new TextRenderable(renderer, {
22494
23029
  id: `msg-${msg.id}-cmd`,
22495
- content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.text)(msg.command || "")}`
23030
+ content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.secondary)(msg.command || "")}`
22496
23031
  });
22497
23032
  card.add(commandText);
22498
23033
  if (msg.safety) {
22499
23034
  const severityColor = getSeverityColor(msg.safety.severity);
22500
- const severityText = msg.safety.isDangerous ? `${msg.safety.severity.toUpperCase()} risk${msg.safety.reason ? ` - ${msg.safety.reason}` : ""}` : "Low risk";
23035
+ const severityLabel = msg.safety.severity === "low" ? "Low risk" : `${msg.safety.severity[0].toUpperCase()}${msg.safety.severity.slice(1)} risk`;
22501
23036
  const safetyText = new TextRenderable(renderer, {
22502
23037
  id: `msg-${msg.id}-safety`,
22503
- content: t`${fg(severityColor)("●")} ${fg(theme.colors.textMuted)(severityText)}`
23038
+ content: t`${fg(severityColor)(severityLabel)}`
22504
23039
  });
22505
23040
  card.add(safetyText);
23041
+ if (msg.safety.isDangerous && msg.safety.reason) {
23042
+ const reasonText = new TextRenderable(renderer, {
23043
+ id: `msg-${msg.id}-safety-reason`,
23044
+ content: t`${fg(theme.colors.textMuted)(msg.safety.reason)}`
23045
+ });
23046
+ card.add(reasonText);
23047
+ }
22506
23048
  }
22507
23049
  if (isSelected && !msg.executed) {
22508
23050
  const actionsText = new TextRenderable(renderer, {
22509
23051
  id: `msg-${msg.id}-actions`,
22510
- content: t`${fg(theme.colors.warning)("Press Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
23052
+ content: t`${fg(theme.colors.warning)("Cmd+Enter or Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
22511
23053
  });
22512
23054
  card.add(actionsText);
22513
23055
  }
22514
- if (msg.executed) {
22515
- const wasAutoRun = !msg.safety?.isDangerous;
22516
- const execLabel = wasAutoRun ? "Auto-executed (safe)" : "Executed";
22517
- const execText = new TextRenderable(renderer, {
22518
- id: `msg-${msg.id}-exec`,
22519
- content: t`${fg(theme.colors.success)("✓")} ${fg(theme.colors.success)(execLabel)}`
22520
- });
22521
- card.add(execText);
22522
- }
22523
23056
  return card;
22524
23057
  }
22525
23058
  function createResultMessageRenderable(msg, theme) {
@@ -22530,28 +23063,30 @@ function createResultMessageRenderable(msg, theme) {
22530
23063
  `) : [];
22531
23064
  const isLongOutput = outputLines.length > 5;
22532
23065
  const PREVIEW_LINES = 3;
23066
+ const executionKind = msg.executionKind || "manual";
22533
23067
  const card = new BoxRenderable(renderer, {
22534
23068
  id: `msg-${msg.id}`,
22535
23069
  flexDirection: "column",
22536
23070
  width: "100%",
22537
23071
  border: true,
22538
- borderColor: isSuccess ? theme.colors.success : theme.colors.error,
22539
- borderStyle: "single",
23072
+ borderColor: theme.colors.border,
23073
+ borderStyle: "rounded",
22540
23074
  paddingLeft: 1,
22541
23075
  paddingRight: 1,
23076
+ paddingTop: 0,
23077
+ paddingBottom: 0,
22542
23078
  backgroundColor: theme.colors.backgroundPanel,
22543
23079
  onMouseDown: isLongOutput ? () => {
22544
23080
  toggleResultExpand(msg.id);
22545
23081
  } : undefined
22546
23082
  });
22547
- const statusIcon = isSuccess ? "✓" : "✗";
22548
23083
  const statusColor = isSuccess ? theme.colors.success : theme.colors.error;
22549
- const statusLabel = isSuccess ? "Executed successfully" : `Exit code: ${msg.exitCode}`;
23084
+ const statusLabel = isSuccess ? executionKind === "auto" ? "Auto-executed (safe command)" : executionKind === "dry-run" ? "Dry run (not executed)" : "Executed (confirmed)" : `Command failed (exit code: ${msg.exitCode})`;
22550
23085
  const expandIcon = isLongOutput ? isExpanded ? "▼" : "▶" : "";
22551
23086
  const lineCount = isLongOutput ? ` (${outputLines.length} lines)` : "";
22552
23087
  const statusText = new TextRenderable(renderer, {
22553
23088
  id: `msg-${msg.id}-status`,
22554
- content: t`${fg(statusColor)(statusIcon)} ${fg(theme.colors.text)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
23089
+ content: t`${fg(statusColor)(">")} ${fg(statusColor)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
22555
23090
  });
22556
23091
  card.add(statusText);
22557
23092
  if (hasOutput) {
@@ -22564,11 +23099,26 @@ function createResultMessageRenderable(msg, theme) {
22564
23099
  `) + `
22565
23100
  ... ${outputLines.length - PREVIEW_LINES} more lines`;
22566
23101
  }
23102
+ const outputBox = new BoxRenderable(renderer, {
23103
+ id: `msg-${msg.id}-output-box`,
23104
+ flexDirection: "column",
23105
+ width: "100%",
23106
+ border: true,
23107
+ borderColor: theme.colors.borderSubtle,
23108
+ borderStyle: "single",
23109
+ paddingLeft: 1,
23110
+ paddingRight: 1,
23111
+ paddingTop: 0,
23112
+ paddingBottom: 0,
23113
+ backgroundColor: theme.colors.backgroundElement,
23114
+ marginTop: 1
23115
+ });
22567
23116
  const outputText = new TextRenderable(renderer, {
22568
23117
  id: `msg-${msg.id}-output`,
22569
23118
  content: t`${fg(theme.colors.textMuted)(displayContent)}`
22570
23119
  });
22571
- card.add(outputText);
23120
+ outputBox.add(outputText);
23121
+ card.add(outputBox);
22572
23122
  if (isLongOutput) {
22573
23123
  const hintText = new TextRenderable(renderer, {
22574
23124
  id: `msg-${msg.id}-hint`,
@@ -22649,17 +23199,23 @@ function refreshThemeColors() {
22649
23199
  };
22650
23200
  }
22651
23201
  if (inputField) {
22652
- inputField.focusedBackgroundColor = theme.colors.backgroundPanel;
23202
+ inputField.focusedBackgroundColor = "transparent";
22653
23203
  inputField.textColor = theme.colors.text;
22654
- inputField.placeholderColor = theme.colors.textMuted;
22655
- inputField.cursorColor = theme.colors.primary;
23204
+ inputField.placeholder = t`${fg(theme.colors.textMuted)("Describe what you want to do...")}`;
23205
+ }
23206
+ if (inputContainer) {
23207
+ inputContainer.borderColor = theme.colors.primary;
23208
+ inputContainer.backgroundColor = theme.colors.backgroundPanel;
23209
+ }
23210
+ if (inputHintText) {
23211
+ inputHintText.content = getInputHintContent();
22656
23212
  }
22657
23213
  }
22658
23214
  async function handleInput(value) {
22659
23215
  const input = value.trim();
22660
23216
  if (!input)
22661
23217
  return;
22662
- inputField.value = "";
23218
+ inputField.setText("");
22663
23219
  if (input.startsWith("!")) {
22664
23220
  await handleSpecialCommand(input);
22665
23221
  return;
@@ -22736,6 +23292,8 @@ async function processDirectCommand(input, command) {
22736
23292
  }
22737
23293
  }
22738
23294
  async function executeAndShowResult(input, command, assistantMsgId) {
23295
+ const executionKind = getExecutionKind(assistantMsgId, dryRunMode);
23296
+ updateAssistantMessage(assistantMsgId, { executed: true });
22739
23297
  if (command.startsWith("cd ")) {
22740
23298
  const path2 = command.slice(3).trim().replace(/^["']|["']$/g, "");
22741
23299
  try {
@@ -22743,7 +23301,7 @@ async function executeAndShowResult(input, command, assistantMsgId) {
22743
23301
  process.chdir(expandedPath);
22744
23302
  currentCwd = getCwd();
22745
23303
  statusBarText.content = getStatusBarContent();
22746
- addResultMessage(`Changed directory to ${currentCwd}`, 0);
23304
+ addResultMessage(`Changed directory to ${currentCwd}`, 0, executionKind, assistantMsgId);
22747
23305
  addToHistory({
22748
23306
  input,
22749
23307
  command,
@@ -22751,22 +23309,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
22751
23309
  timestamp: Date.now()
22752
23310
  });
22753
23311
  history = loadHistory();
22754
- updateAssistantMessage(assistantMsgId, { executed: true });
22755
23312
  } catch (err) {
22756
- addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1);
23313
+ addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1, executionKind, assistantMsgId);
22757
23314
  }
22758
23315
  clearCommandState();
22759
23316
  return;
22760
23317
  }
22761
23318
  if (dryRunMode) {
22762
- addResultMessage(`[DRY RUN] Would execute: ${command}`, 0);
22763
- updateAssistantMessage(assistantMsgId, { executed: true });
23319
+ addResultMessage(`[DRY RUN] Would execute: ${command}`, 0, executionKind, assistantMsgId);
22764
23320
  clearCommandState();
22765
23321
  return;
22766
23322
  }
22767
23323
  try {
22768
23324
  const { output, exitCode } = await executeCommandWithCode(command);
22769
- addResultMessage(output || "Command completed successfully", exitCode);
23325
+ addResultMessage(output || "Command completed successfully", exitCode, executionKind, assistantMsgId);
22770
23326
  addToHistory({
22771
23327
  input,
22772
23328
  command,
@@ -22774,13 +23330,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
22774
23330
  timestamp: Date.now()
22775
23331
  });
22776
23332
  history = loadHistory();
22777
- updateAssistantMessage(assistantMsgId, { executed: true });
22778
23333
  } catch (error) {
22779
23334
  const message = error instanceof Error ? error.message : String(error);
22780
- addResultMessage(`Error: ${message}`, 1);
23335
+ addResultMessage(`Error: ${message}`, 1, executionKind, assistantMsgId);
22781
23336
  }
22782
23337
  clearCommandState();
22783
23338
  }
23339
+ function getExecutionKind(assistantMsgId, isDryRun) {
23340
+ if (isDryRun)
23341
+ return "dry-run";
23342
+ const assistantMsg = chatMessages.find((msg) => msg.id === assistantMsgId);
23343
+ if (!assistantMsg || assistantMsg.type !== "assistant")
23344
+ return "manual";
23345
+ return assistantMsg.safety?.isDangerous ? "manual" : "auto";
23346
+ }
22784
23347
  function executeCommandWithCode(command) {
22785
23348
  return new Promise((resolve3, reject) => {
22786
23349
  const child = spawn(command, {
@@ -23404,7 +23967,7 @@ function handleKeypress(key) {
23404
23967
  if (key.name === "e" && awaitingConfirmation && pendingMessageId) {
23405
23968
  const msg = chatMessages.find((m) => m.id === pendingMessageId);
23406
23969
  if (msg && msg.command) {
23407
- inputField.value = msg.command;
23970
+ inputField.setText(msg.command);
23408
23971
  clearCommandState();
23409
23972
  inputField.focus();
23410
23973
  }