@zhongqian97-code/ecode 0.2.4 → 0.2.5
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/dist/index.js +199 -32
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -597,19 +597,45 @@ import { Box as Box3, Text as Text3, useInput } from "ink";
|
|
|
597
597
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
598
598
|
var CURSOR_CHAR = "\u258C";
|
|
599
599
|
var BLINK_INTERVAL_MS = 530;
|
|
600
|
+
function wordBackward(s, pos) {
|
|
601
|
+
let i = pos;
|
|
602
|
+
while (i > 0 && s[i - 1] === " ") {
|
|
603
|
+
i--;
|
|
604
|
+
}
|
|
605
|
+
while (i > 0 && s[i - 1] !== " ") {
|
|
606
|
+
i--;
|
|
607
|
+
}
|
|
608
|
+
return i;
|
|
609
|
+
}
|
|
610
|
+
function wordForward(s, pos) {
|
|
611
|
+
let i = pos;
|
|
612
|
+
const len = s.length;
|
|
613
|
+
while (i < len && s[i] !== " ") {
|
|
614
|
+
i++;
|
|
615
|
+
}
|
|
616
|
+
while (i < len && s[i] === " ") {
|
|
617
|
+
i++;
|
|
618
|
+
}
|
|
619
|
+
return i;
|
|
620
|
+
}
|
|
600
621
|
var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placeholder }, ref) {
|
|
601
|
-
const [
|
|
622
|
+
const [value, setValue] = useState2("");
|
|
623
|
+
const [cursorPos, setCursorPos] = useState2(0);
|
|
602
624
|
const [cursorVisible, setCursorVisible] = useState2(true);
|
|
603
|
-
const
|
|
604
|
-
|
|
625
|
+
const valueRef = useRef(value);
|
|
626
|
+
valueRef.current = value;
|
|
627
|
+
const cursorPosRef = useRef(cursorPos);
|
|
628
|
+
cursorPosRef.current = cursorPos;
|
|
605
629
|
const onChangeRef = useRef(onChange);
|
|
606
630
|
onChangeRef.current = onChange;
|
|
607
631
|
const onSubmitRef = useRef(onSubmit);
|
|
608
632
|
onSubmitRef.current = onSubmit;
|
|
609
633
|
useImperativeHandle(ref, () => ({
|
|
610
634
|
fill(text) {
|
|
611
|
-
|
|
612
|
-
|
|
635
|
+
valueRef.current = text;
|
|
636
|
+
cursorPosRef.current = text.length;
|
|
637
|
+
setValue(text);
|
|
638
|
+
setCursorPos(text.length);
|
|
613
639
|
onChangeRef.current?.(text);
|
|
614
640
|
}
|
|
615
641
|
}));
|
|
@@ -625,49 +651,124 @@ var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placehold
|
|
|
625
651
|
clearInterval(timer);
|
|
626
652
|
};
|
|
627
653
|
}, [isActive]);
|
|
654
|
+
function setValueSync(newValue) {
|
|
655
|
+
valueRef.current = newValue;
|
|
656
|
+
setValue(newValue);
|
|
657
|
+
}
|
|
658
|
+
function setCursorPosSync(newPos) {
|
|
659
|
+
cursorPosRef.current = newPos;
|
|
660
|
+
setCursorPos(newPos);
|
|
661
|
+
}
|
|
628
662
|
useInput(
|
|
629
663
|
(input, key) => {
|
|
630
|
-
const
|
|
664
|
+
const v = valueRef.current;
|
|
665
|
+
const pos = cursorPosRef.current;
|
|
631
666
|
if (key.return && key.shift) {
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
667
|
+
const newValue = v.slice(0, pos) + "\n" + v.slice(pos);
|
|
668
|
+
setValueSync(newValue);
|
|
669
|
+
setCursorPosSync(pos + 1);
|
|
670
|
+
onChangeRef.current?.(newValue);
|
|
635
671
|
return;
|
|
636
672
|
}
|
|
637
673
|
if (key.return) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
674
|
+
onSubmitRef.current(v);
|
|
675
|
+
setValueSync("");
|
|
676
|
+
setCursorPosSync(0);
|
|
641
677
|
onChangeRef.current?.("");
|
|
642
678
|
return;
|
|
643
679
|
}
|
|
644
680
|
if (key.backspace || key.delete) {
|
|
645
|
-
|
|
646
|
-
const
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
681
|
+
if (pos === 0) return;
|
|
682
|
+
const newValue = v.slice(0, pos - 1) + v.slice(pos);
|
|
683
|
+
setValueSync(newValue);
|
|
684
|
+
setCursorPosSync(pos - 1);
|
|
685
|
+
onChangeRef.current?.(newValue);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
if (key.ctrl) {
|
|
689
|
+
switch (input) {
|
|
690
|
+
case "a": {
|
|
691
|
+
setCursorPosSync(0);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
case "e": {
|
|
695
|
+
setCursorPosSync(v.length);
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
case "b": {
|
|
699
|
+
setCursorPosSync(Math.max(0, pos - 1));
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
case "f": {
|
|
703
|
+
setCursorPosSync(Math.min(v.length, pos + 1));
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
case "k": {
|
|
707
|
+
const nextNl = v.indexOf("\n", pos);
|
|
708
|
+
const lineEnd = nextNl === -1 ? v.length : nextNl;
|
|
709
|
+
const newValue = v.slice(0, pos) + v.slice(lineEnd);
|
|
710
|
+
setValueSync(newValue);
|
|
711
|
+
onChangeRef.current?.(newValue);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
case "u": {
|
|
715
|
+
const newValue = v.slice(pos);
|
|
716
|
+
setValueSync(newValue);
|
|
717
|
+
setCursorPosSync(0);
|
|
718
|
+
onChangeRef.current?.(newValue);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
case "w": {
|
|
722
|
+
const newPos = wordBackward(v, pos);
|
|
723
|
+
const newValue = v.slice(0, newPos) + v.slice(pos);
|
|
724
|
+
setValueSync(newValue);
|
|
725
|
+
setCursorPosSync(newPos);
|
|
726
|
+
onChangeRef.current?.(newValue);
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
case "d": {
|
|
730
|
+
if (pos >= v.length) return;
|
|
731
|
+
const newValue = v.slice(0, pos) + v.slice(pos + 1);
|
|
732
|
+
setValueSync(newValue);
|
|
733
|
+
onChangeRef.current?.(newValue);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
default:
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
if (key.meta) {
|
|
741
|
+
if (input === "b") {
|
|
742
|
+
setCursorPosSync(wordBackward(v, pos));
|
|
653
743
|
return;
|
|
654
744
|
}
|
|
655
|
-
|
|
656
|
-
|
|
745
|
+
if (input === "f") {
|
|
746
|
+
setCursorPosSync(wordForward(v, pos));
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (key.leftArrow) {
|
|
752
|
+
setCursorPosSync(Math.max(0, pos - 1));
|
|
657
753
|
return;
|
|
658
754
|
}
|
|
659
|
-
if (key.
|
|
755
|
+
if (key.rightArrow) {
|
|
756
|
+
setCursorPosSync(Math.min(v.length, pos + 1));
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
if (key.escape || key.upArrow || key.downArrow || key.tab || key.pageUp || key.pageDown) {
|
|
660
760
|
return;
|
|
661
761
|
}
|
|
662
762
|
if (input.length > 0) {
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
|
|
763
|
+
const newValue = v.slice(0, pos) + input + v.slice(pos);
|
|
764
|
+
setValueSync(newValue);
|
|
765
|
+
setCursorPosSync(pos + input.length);
|
|
766
|
+
onChangeRef.current?.(newValue);
|
|
666
767
|
}
|
|
667
768
|
},
|
|
668
769
|
{ isActive }
|
|
669
770
|
);
|
|
670
|
-
const isEmpty =
|
|
771
|
+
const isEmpty = value === "";
|
|
671
772
|
const renderLines = () => {
|
|
672
773
|
if (isEmpty && placeholder) {
|
|
673
774
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
@@ -676,19 +777,41 @@ var Input = forwardRef(function Input2({ isActive, onSubmit, onChange, placehold
|
|
|
676
777
|
isActive && cursorVisible && /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: CURSOR_CHAR })
|
|
677
778
|
] });
|
|
678
779
|
}
|
|
780
|
+
const lines = value.split("\n");
|
|
781
|
+
let remaining = cursorPos;
|
|
782
|
+
let cursorLine = 0;
|
|
783
|
+
let cursorCol = 0;
|
|
784
|
+
for (let i = 0; i < lines.length; i++) {
|
|
785
|
+
const lineLen = lines[i].length;
|
|
786
|
+
if (remaining <= lineLen) {
|
|
787
|
+
cursorLine = i;
|
|
788
|
+
cursorCol = remaining;
|
|
789
|
+
break;
|
|
790
|
+
}
|
|
791
|
+
remaining -= lineLen + 1;
|
|
792
|
+
}
|
|
679
793
|
return /* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: lines.map((line, idx) => {
|
|
680
|
-
const isLastLine = idx === lines.length - 1;
|
|
681
794
|
const prefix = idx === 0 ? "> " : " ";
|
|
795
|
+
const showCursor = isActive && cursorVisible && idx === cursorLine;
|
|
796
|
+
if (!showCursor) {
|
|
797
|
+
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
798
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: prefix }),
|
|
799
|
+
/* @__PURE__ */ jsx3(Text3, { children: line })
|
|
800
|
+
] }, idx);
|
|
801
|
+
}
|
|
802
|
+
const before = line.slice(0, cursorCol);
|
|
803
|
+
const after = line.slice(cursorCol);
|
|
682
804
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
683
805
|
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: prefix }),
|
|
684
|
-
/* @__PURE__ */ jsx3(Text3, { children:
|
|
685
|
-
|
|
806
|
+
/* @__PURE__ */ jsx3(Text3, { children: before }),
|
|
807
|
+
/* @__PURE__ */ jsx3(Text3, { color: "cyan", children: CURSOR_CHAR }),
|
|
808
|
+
/* @__PURE__ */ jsx3(Text3, { children: after })
|
|
686
809
|
] }, idx);
|
|
687
810
|
}) });
|
|
688
811
|
};
|
|
689
812
|
return /* @__PURE__ */ jsx3(Box3, { children: isActive ? renderLines() : /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
690
813
|
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "> " }),
|
|
691
|
-
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: isEmpty ? placeholder ?? "" :
|
|
814
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: isEmpty ? placeholder ?? "" : value })
|
|
692
815
|
] }) });
|
|
693
816
|
});
|
|
694
817
|
var Input_default = Input;
|
|
@@ -764,6 +887,11 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
764
887
|
const [confirmPrompt, setConfirmPrompt] = useState3(void 0);
|
|
765
888
|
const [expandTools, setExpandTools] = useState3(false);
|
|
766
889
|
const [scrollOffset, setScrollOffset] = useState3(0);
|
|
890
|
+
const [inputHistory, setInputHistory] = useState3([]);
|
|
891
|
+
const inputHistoryRef = useRef2([]);
|
|
892
|
+
inputHistoryRef.current = inputHistory;
|
|
893
|
+
const historyIndexRef = useRef2(-1);
|
|
894
|
+
const isNavigatingHistoryRef = useRef2(false);
|
|
767
895
|
const totalLines = useMemo(() => {
|
|
768
896
|
const visible = messages.filter((m) => m.role !== "system");
|
|
769
897
|
return visible.reduce(
|
|
@@ -799,7 +927,7 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
799
927
|
}
|
|
800
928
|
loggedCountRef.current = messages.length;
|
|
801
929
|
}, [messages]);
|
|
802
|
-
useInput2((
|
|
930
|
+
useInput2((input, key) => {
|
|
803
931
|
const skillList = registry2?.list() ?? [];
|
|
804
932
|
const suggestions = computeSuggestions(skillList, acState);
|
|
805
933
|
const open = isOpen(acState, suggestions);
|
|
@@ -837,6 +965,38 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
837
965
|
setScrollOffset((prev) => Math.max(0, prev - scrollStep));
|
|
838
966
|
return;
|
|
839
967
|
}
|
|
968
|
+
if (key.ctrl && input === "v") {
|
|
969
|
+
setScrollOffset((prev) => Math.max(0, prev - scrollStep));
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
if (key.meta && input === "v") {
|
|
973
|
+
setScrollOffset((prev) => Math.min(prev + scrollStep, Math.max(0, totalLines - 1)));
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
if (key.ctrl && input === "p") {
|
|
977
|
+
const history = inputHistoryRef.current;
|
|
978
|
+
const newIndex = Math.min(historyIndexRef.current + 1, history.length - 1);
|
|
979
|
+
if (newIndex >= 0 && newIndex < history.length) {
|
|
980
|
+
historyIndexRef.current = newIndex;
|
|
981
|
+
isNavigatingHistoryRef.current = true;
|
|
982
|
+
inputRef.current?.fill(history[newIndex]);
|
|
983
|
+
}
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
if (key.ctrl && input === "n") {
|
|
987
|
+
const history = inputHistoryRef.current;
|
|
988
|
+
if (historyIndexRef.current > 0) {
|
|
989
|
+
const newIndex = historyIndexRef.current - 1;
|
|
990
|
+
historyIndexRef.current = newIndex;
|
|
991
|
+
isNavigatingHistoryRef.current = true;
|
|
992
|
+
inputRef.current?.fill(history[newIndex]);
|
|
993
|
+
} else if (historyIndexRef.current === 0) {
|
|
994
|
+
historyIndexRef.current = -1;
|
|
995
|
+
isNavigatingHistoryRef.current = true;
|
|
996
|
+
inputRef.current?.fill("");
|
|
997
|
+
}
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
840
1000
|
});
|
|
841
1001
|
const confirm = useCallback((prompt) => {
|
|
842
1002
|
return new Promise((resolve2) => {
|
|
@@ -980,6 +1140,8 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
980
1140
|
return;
|
|
981
1141
|
}
|
|
982
1142
|
if (!trimmed) return;
|
|
1143
|
+
setInputHistory((prev) => [trimmed, ...prev.slice(0, 99)]);
|
|
1144
|
+
historyIndexRef.current = -1;
|
|
983
1145
|
setScrollOffset(0);
|
|
984
1146
|
if (registry2) {
|
|
985
1147
|
const skillResult = handleSkillInput(trimmed, registry2);
|
|
@@ -1021,6 +1183,11 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
|
|
|
1021
1183
|
);
|
|
1022
1184
|
const isInputActive = status === "idle" || status === "awaiting_confirm";
|
|
1023
1185
|
const handleInputTextChange = useCallback((text) => {
|
|
1186
|
+
if (isNavigatingHistoryRef.current) {
|
|
1187
|
+
isNavigatingHistoryRef.current = false;
|
|
1188
|
+
} else {
|
|
1189
|
+
historyIndexRef.current = -1;
|
|
1190
|
+
}
|
|
1024
1191
|
if (status !== "awaiting_confirm") {
|
|
1025
1192
|
setAcState((prev) => handleInputChange(prev, text));
|
|
1026
1193
|
}
|