@testany/hephos 0.3.9 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ReplModeInk.d.ts","sourceRoot":"","sources":["../../src/repl/ReplModeInk.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAgoFH,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,QAMjF"}
1
+ {"version":3,"file":"ReplModeInk.d.ts","sourceRoot":"","sources":["../../src/repl/ReplModeInk.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAy1FH,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,QAMjF"}
@@ -25,6 +25,8 @@ import { SessionStorageService } from '@testany/agent-chatter-core';
25
25
  import { RestorePrompt } from './components/RestorePrompt.js';
26
26
  import { QueueDisplay } from './components/QueueDisplay.js';
27
27
  import { TipsBar } from './components/TipsBar.js';
28
+ import { HistoryOverlay } from './components/HistoryOverlay.js';
29
+ import { useHistory } from './hooks/useHistory.js';
28
30
  // Read version from package.json
29
31
  const __filename = fileURLToPath(import.meta.url);
30
32
  const __dirname = path.dirname(__filename);
@@ -230,6 +232,8 @@ function App({ registryPath, debug = false, proxyUrl }) {
230
232
  const [isExiting, setIsExiting] = useState(false);
231
233
  const [queueState, setQueueState] = useState(null);
232
234
  const [showTips, setShowTips] = useState(true); // Tips bar visibility (default: on)
235
+ // Command history management
236
+ const history = useHistory();
233
237
  // Track previous queue size to detect DROP-triggered clears
234
238
  const prevQueueSizeRef = useRef(0);
235
239
  // Streaming event handling
@@ -560,7 +564,30 @@ function App({ registryPath, debug = false, proxyUrl }) {
560
564
  };
561
565
  // Handle input submission (Enter key)
562
566
  const handleInputSubmit = (value) => {
563
- const trimmed = value.trim();
567
+ let submittedValue = value;
568
+ // Exit search mode if active (user submitted with Enter while in search mode)
569
+ // Use the selected history entry as the submitted value for consistency
570
+ if (history.searchMode) {
571
+ const selectedEntry = history.acceptSearch();
572
+ if (selectedEntry !== null) {
573
+ submittedValue = selectedEntry;
574
+ setInput(selectedEntry); // Sync input state
575
+ }
576
+ }
577
+ // Exit history mode if active (user submitted with Enter while browsing history)
578
+ // Use the selected history entry as the submitted value for consistency
579
+ else if (history.isActive) {
580
+ const selectedEntry = history.acceptHistory();
581
+ if (selectedEntry !== null) {
582
+ submittedValue = selectedEntry;
583
+ setInput(selectedEntry); // Sync input state
584
+ }
585
+ }
586
+ const trimmed = submittedValue.trim();
587
+ // Add to history (filtering handled by hook)
588
+ if (trimmed) {
589
+ history.addEntry(trimmed);
590
+ }
564
591
  // Handle / commands
565
592
  if (trimmed.startsWith('/')) {
566
593
  const cmd = trimmed.split(' ')[0].toLowerCase();
@@ -645,8 +672,21 @@ function App({ registryPath, debug = false, proxyUrl }) {
645
672
  }
646
673
  return;
647
674
  }
648
- // ESC key - Cancel agent execution in conversation mode
675
+ // ESC key - Exit search/history mode or cancel agent execution
649
676
  if (key.escape) {
677
+ // First, check if we're in search mode
678
+ if (history.searchMode) {
679
+ const savedInput = history.exitSearchMode();
680
+ setInput(savedInput);
681
+ return;
682
+ }
683
+ // Then check if we're in history browsing mode
684
+ if (history.isActive) {
685
+ const savedInput = history.exitHistory();
686
+ setInput(savedInput);
687
+ return;
688
+ }
689
+ // Cancel agent execution in conversation mode
650
690
  if (mode === 'conversation' && activeCoordinator && executingAgent) {
651
691
  // Check if ESC cancellation is allowed (LLD-05: use uiPrefs)
652
692
  if (uiPrefs.allowEscCancel) {
@@ -660,8 +700,80 @@ function App({ registryPath, debug = false, proxyUrl }) {
660
700
  }
661
701
  }
662
702
  }
703
+ // Ctrl+R - Enter search mode or search backward
704
+ if (key.ctrl && inputChar === 'r') {
705
+ if (mode === 'normal' || mode === 'conversation') {
706
+ if (history.searchMode) {
707
+ // Already in search mode - search backward
708
+ const result = history.searchBackward();
709
+ if (result !== null) {
710
+ setInput(result);
711
+ }
712
+ }
713
+ else {
714
+ // Enter search mode
715
+ history.enterSearchMode(input);
716
+ }
717
+ return;
718
+ }
719
+ }
720
+ // Ctrl+S - Search forward (only in search mode)
721
+ if (key.ctrl && inputChar === 's') {
722
+ if (history.searchMode) {
723
+ const result = history.searchForward();
724
+ if (result !== null) {
725
+ setInput(result);
726
+ }
727
+ return;
728
+ }
729
+ }
730
+ // Ctrl+P - Navigate to previous (older) history entry (same as ↑)
731
+ if (key.ctrl && inputChar === 'p') {
732
+ if (mode === 'normal' || mode === 'conversation') {
733
+ // In search mode, navigate search results
734
+ if (history.searchMode) {
735
+ const result = history.searchBackward();
736
+ if (result !== null) {
737
+ setInput(result);
738
+ }
739
+ return;
740
+ }
741
+ // Regular history navigation
742
+ const historyEntry = history.navigateUp(input);
743
+ if (historyEntry !== null) {
744
+ setInput(historyEntry);
745
+ }
746
+ return;
747
+ }
748
+ }
749
+ // Ctrl+N - Navigate to next (newer) history entry (same as ↓)
750
+ if (key.ctrl && inputChar === 'n') {
751
+ if (mode === 'normal' || mode === 'conversation') {
752
+ // In search mode, navigate search results
753
+ if (history.searchMode) {
754
+ const result = history.searchForward();
755
+ if (result !== null) {
756
+ setInput(result);
757
+ }
758
+ return;
759
+ }
760
+ // Regular history navigation
761
+ const historyEntry = history.navigateDown();
762
+ if (historyEntry !== null) {
763
+ setInput(historyEntry);
764
+ }
765
+ return;
766
+ }
767
+ }
663
768
  // Ctrl+C 退出或取消
664
769
  if (key.ctrl && inputChar === 'c') {
770
+ // First, clean up any search/history state
771
+ if (history.searchMode) {
772
+ history.exitSearchMode();
773
+ }
774
+ else if (history.isActive) {
775
+ history.exitHistory();
776
+ }
665
777
  if (mode === 'conversation' && activeCoordinator) {
666
778
  // 退出对话模式
667
779
  // stop() is async, fire-and-forget for UI responsiveness
@@ -741,14 +853,60 @@ function App({ registryPath, debug = false, proxyUrl }) {
741
853
  // normal/conversation/wizard/form 由 TextInput 的 onSubmit 处理
742
854
  return;
743
855
  }
856
+ // Alt+↑ - Large jump backward (skip 5 entries)
857
+ // Cross-platform: key.meta captures Option key on macOS, Alt key on Windows/Linux
858
+ // in most modern terminal emulators (Windows Terminal, iTerm2, etc.)
859
+ if (key.meta && key.upArrow) {
860
+ if ((mode === 'normal' || mode === 'conversation') && !history.searchMode) {
861
+ const historyEntry = history.jumpUp(input);
862
+ if (historyEntry !== null) {
863
+ setInput(historyEntry);
864
+ }
865
+ return;
866
+ }
867
+ }
868
+ // Alt+↓ - Large jump forward (skip 5 entries)
869
+ // Cross-platform: key.meta captures Option key on macOS, Alt key on Windows/Linux
870
+ if (key.meta && key.downArrow) {
871
+ if ((mode === 'normal' || mode === 'conversation') && !history.searchMode && history.isActive) {
872
+ const historyEntry = history.jumpDown();
873
+ if (historyEntry !== null) {
874
+ setInput(historyEntry);
875
+ }
876
+ return;
877
+ }
878
+ }
744
879
  // 处理不同模式下的上下键导航
745
880
  if (key.upArrow) {
881
+ // Search mode takes priority - navigate search results
882
+ if (history.searchMode) {
883
+ const result = history.searchBackward();
884
+ if (result !== null) {
885
+ setInput(result);
886
+ }
887
+ return;
888
+ }
746
889
  if (mode === 'normal') {
747
890
  const matches = getMatches();
748
891
  if (matches.length > 0) {
892
+ // Command hint navigation has priority
749
893
  setSelectedIndex(prev => (prev > 0 ? prev - 1 : matches.length - 1));
750
894
  return;
751
895
  }
896
+ // No command hints - use regular history navigation
897
+ const historyEntry = history.navigateUp(input);
898
+ if (historyEntry !== null) {
899
+ setInput(historyEntry);
900
+ }
901
+ return;
902
+ }
903
+ else if (mode === 'conversation') {
904
+ // Regular history navigation in conversation mode
905
+ const historyEntry = history.navigateUp(input);
906
+ if (historyEntry !== null) {
907
+ setInput(historyEntry);
908
+ }
909
+ return;
752
910
  }
753
911
  else if (mode === 'menu' && menuItems.length > 0) {
754
912
  setSelectedIndex(prev => (prev > 0 ? prev - 1 : menuItems.length - 1));
@@ -760,12 +918,35 @@ function App({ registryPath, debug = false, proxyUrl }) {
760
918
  }
761
919
  }
762
920
  if (key.downArrow) {
921
+ // Search mode takes priority - navigate search results
922
+ if (history.searchMode) {
923
+ const result = history.searchForward();
924
+ if (result !== null) {
925
+ setInput(result);
926
+ }
927
+ return;
928
+ }
763
929
  if (mode === 'normal') {
764
930
  const matches = getMatches();
765
931
  if (matches.length > 0) {
932
+ // Command hint navigation has priority
766
933
  setSelectedIndex(prev => (prev < matches.length - 1 ? prev + 1 : 0));
767
934
  return;
768
935
  }
936
+ // No command hints - use regular history navigation
937
+ const historyEntry = history.navigateDown();
938
+ if (historyEntry !== null) {
939
+ setInput(historyEntry);
940
+ }
941
+ return;
942
+ }
943
+ else if (mode === 'conversation') {
944
+ // Regular history navigation in conversation mode
945
+ const historyEntry = history.navigateDown();
946
+ if (historyEntry !== null) {
947
+ setInput(historyEntry);
948
+ }
949
+ return;
769
950
  }
770
951
  else if (mode === 'menu' && menuItems.length > 0) {
771
952
  setSelectedIndex(prev => (prev < menuItems.length - 1 ? prev + 1 : 0));
@@ -1620,6 +1801,13 @@ function App({ registryPath, debug = false, proxyUrl }) {
1620
1801
  }
1621
1802
  }
1622
1803
  }
1804
+ // Show search/history mode indicator in conversation mode
1805
+ if (history.searchMode) {
1806
+ return _jsxs(Text, { color: "yellow", children: ["[search:", teamName, "] ", history.searchQuery ? `"${history.searchQuery}"` : '', "> "] });
1807
+ }
1808
+ if (history.isActive) {
1809
+ return _jsxs(Text, { color: "green", bold: true, children: ["[history:", teamName, "] ", memberPrompt, "> "] });
1810
+ }
1623
1811
  return _jsxs(Text, { color: "green", bold: true, children: ["[conversation:", teamName, "] ", memberPrompt, "> "] });
1624
1812
  }
1625
1813
  case 'wizard':
@@ -1627,10 +1815,16 @@ function App({ registryPath, debug = false, proxyUrl }) {
1627
1815
  case 'form':
1628
1816
  return _jsx(Text, { color: "cyan", bold: true, children: "[form] input> " });
1629
1817
  default:
1630
- // 'normal' mode
1818
+ // 'normal' mode - show search/history mode indicator
1819
+ if (history.searchMode) {
1820
+ return _jsxs(Text, { color: "yellow", children: ["[search] ", history.searchQuery ? `"${history.searchQuery}"` : '', "> "] });
1821
+ }
1822
+ if (history.isActive) {
1823
+ return _jsx(Text, { color: "cyan", children: "[history] hephos> " });
1824
+ }
1631
1825
  return _jsx(Text, { color: "cyan", children: "[normal] hephos> " });
1632
1826
  }
1633
- })(), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleInputSubmit, placeholder: " " })] }), _jsx(Text, { color: mode === 'conversation' ? 'green' : 'cyan', dimColor: true, children: '─'.repeat(terminalWidth - 4) })] })), !isExiting && mode === 'normal' && _jsx(CommandHints, { input: input, selectedIndex: selectedIndex }), !isExiting && mode === 'conversation' && (_jsx(TipsBar, { visible: showTips, terminalWidth: terminalWidth }))] }));
1827
+ })(), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleInputSubmit, placeholder: " " })] }), _jsx(Text, { color: mode === 'conversation' ? 'green' : 'cyan', dimColor: true, children: '─'.repeat(terminalWidth - 4) })] })), !isExiting && (mode === 'normal' || mode === 'conversation') && (history.isActive || history.searchMode) && (_jsx(HistoryOverlay, { visible: true, entries: history.entries, currentIndex: history.currentIndex, searchMode: history.searchMode, searchQuery: history.searchQuery, terminalWidth: terminalWidth })), !isExiting && mode === 'normal' && !history.isActive && !history.searchMode && _jsx(CommandHints, { input: input, selectedIndex: selectedIndex }), !isExiting && mode === 'conversation' && !history.isActive && !history.searchMode && (_jsx(TipsBar, { visible: showTips, terminalWidth: terminalWidth }))] }));
1634
1828
  }
1635
1829
  export function startReplInk(registryPath, options = {}) {
1636
1830
  render(_jsx(App, { registryPath: registryPath, debug: options.debug, proxyUrl: options.proxyUrl }), {