@rawwee/interactive-mcp 1.5.2 → 1.5.3

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.
@@ -11,8 +11,8 @@ const IGNORED_DIRECTORIES = new Set([
11
11
  '.vscode',
12
12
  '.DS_Store',
13
13
  ]);
14
- const MAX_REPOSITORY_FILES = 6000;
15
- const MAX_SUGGESTIONS = 6;
14
+ const MAX_REPOSITORY_ENTRIES = 50000;
15
+ const MAX_SUGGESTIONS_WITH_EMPTY_QUERY = 24;
16
16
  const toPosixPath = (value) => value.replaceAll(path.sep, '/');
17
17
  const getFuzzyScore = (candidate, query) => {
18
18
  const candidateLower = candidate.toLowerCase();
@@ -76,7 +76,7 @@ export const getAutocompleteTarget = (value, caret) => {
76
76
  };
77
77
  export const rankFileSuggestions = (files, query) => {
78
78
  if (query.length === 0) {
79
- return files.slice(0, MAX_SUGGESTIONS);
79
+ return files.slice(0, MAX_SUGGESTIONS_WITH_EMPTY_QUERY);
80
80
  }
81
81
  return files
82
82
  .map((filePath) => ({
@@ -85,16 +85,15 @@ export const rankFileSuggestions = (files, query) => {
85
85
  }))
86
86
  .filter((entry) => typeof entry.score === 'number')
87
87
  .sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath))
88
- .slice(0, MAX_SUGGESTIONS)
89
88
  .map((entry) => entry.filePath);
90
89
  };
91
90
  export const readRepositoryFiles = async (repoRoot) => {
92
91
  const discoveredFiles = [];
93
92
  const visitDirectory = async (directoryPath) => {
94
- if (discoveredFiles.length >= MAX_REPOSITORY_FILES) {
93
+ if (discoveredFiles.length >= MAX_REPOSITORY_ENTRIES) {
95
94
  return;
96
95
  }
97
- let entries = [];
96
+ let entries;
98
97
  try {
99
98
  entries = await fs.readdir(directoryPath, { withFileTypes: true });
100
99
  }
@@ -102,22 +101,23 @@ export const readRepositoryFiles = async (repoRoot) => {
102
101
  return;
103
102
  }
104
103
  for (const entry of entries) {
105
- if (discoveredFiles.length >= MAX_REPOSITORY_FILES) {
104
+ if (discoveredFiles.length >= MAX_REPOSITORY_ENTRIES) {
106
105
  return;
107
106
  }
108
107
  if (IGNORED_DIRECTORIES.has(entry.name)) {
109
108
  continue;
110
109
  }
111
110
  const entryAbsolutePath = path.join(directoryPath, entry.name);
111
+ const relativePath = path.relative(repoRoot, entryAbsolutePath);
112
+ if (!relativePath || relativePath.startsWith('..')) {
113
+ continue;
114
+ }
112
115
  if (entry.isDirectory()) {
116
+ discoveredFiles.push(`${toPosixPath(relativePath)}/`);
113
117
  await visitDirectory(entryAbsolutePath);
114
118
  continue;
115
119
  }
116
120
  if (entry.isFile()) {
117
- const relativePath = path.relative(repoRoot, entryAbsolutePath);
118
- if (!relativePath || relativePath.startsWith('..')) {
119
- continue;
120
- }
121
121
  discoveredFiles.push(toPosixPath(relativePath));
122
122
  }
123
123
  }
@@ -12,8 +12,8 @@ export const OptionList = ({ mode, options, selectedIndex, onSelectOption, onAct
12
12
  };
13
13
  export const InputEditor = ({ questionId, textareaRenderVersion, textareaRef, textareaContainerHeight, textareaRows, hasSuggestions, keyBindings, onFocusRequest, onContentSync, onSubmitFromTextarea, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", children: [_jsx("text", { fg: "gray", children: "Input" }), _jsx("box", { border: true, borderStyle: "single", borderColor: hasSuggestions ? 'cyan' : 'gray', backgroundColor: "#1f1f1f", height: textareaContainerHeight, paddingLeft: 1, paddingRight: 1, onClick: onFocusRequest, children: _jsx("textarea", { ref: textareaRef, focused: true, height: textareaRows, wrapMode: "word", backgroundColor: "#1f1f1f", focusedBackgroundColor: "#1f1f1f", textColor: "white", focusedTextColor: "white", placeholderColor: "gray", placeholder: "Type your answer...", keyBindings: keyBindings, onContentChange: onContentSync, onCursorChange: onContentSync, onSubmit: onSubmitFromTextarea }, `textarea-${questionId}-${textareaRenderVersion}`) })] }));
14
14
  export const SuggestionsPanel = ({ hasOptions, isIndexingFiles, fileSuggestions, selectedSuggestionIndex, selectedSuggestionVscodeLink, hasSearchRoot, }) => (_jsxs("box", { flexDirection: "column", marginBottom: 0, width: "100%", gap: 0, children: [_jsx("text", { fg: "gray", children: hasOptions
15
- ? 'File suggestions • ↑/↓ or Ctrl+N/P navigate • Enter apply'
16
- : 'File suggestions • ↑/↓ or Ctrl+N/P navigate • Enter/Tab apply' }), isIndexingFiles ? (_jsx("text", { fg: "gray", children: "Indexing files..." })) : fileSuggestions.length > 0 ? (_jsxs("box", { flexDirection: "column", width: "100%", children: [fileSuggestions.map((suggestion, index) => (_jsx("box", { paddingLeft: 0, paddingRight: 1, gap: 0, children: _jsxs("text", { fg: index === selectedSuggestionIndex ? 'cyan' : 'gray', wrapMode: "char", children: [index === selectedSuggestionIndex ? '› ' : ' ', suggestion] }) }, suggestion))), selectedSuggestionVscodeLink && (_jsxs("box", { flexDirection: "column", width: "100%", children: [_jsx("text", { fg: "gray", wrapMode: "word", children: "open file with:" }), _jsx("text", { fg: "cyan", wrapMode: "word", onMouseUp: () => {
15
+ ? 'Path suggestions (files + folders) • ↑/↓ or Ctrl+N/P navigate • Enter apply'
16
+ : 'Path suggestions (files + folders) • ↑/↓ or Ctrl+N/P navigate • Enter/Tab apply' }), isIndexingFiles ? (_jsx("text", { fg: "gray", children: "Indexing files..." })) : fileSuggestions.length > 0 ? (_jsxs("box", { flexDirection: "column", width: "100%", children: [fileSuggestions.map((suggestion, index) => (_jsx("box", { paddingLeft: 0, paddingRight: 1, gap: 0, children: _jsxs("text", { fg: index === selectedSuggestionIndex ? 'cyan' : 'gray', wrapMode: "char", children: [index === selectedSuggestionIndex ? '› ' : ' ', suggestion] }) }, suggestion))), selectedSuggestionVscodeLink && (_jsxs("box", { flexDirection: "column", width: "100%", children: [_jsx("text", { fg: "gray", wrapMode: "word", children: "open file with:" }), _jsx("text", { fg: "cyan", wrapMode: "word", onMouseUp: () => {
17
17
  void openExternalLink(selectedSuggestionVscodeLink, 'vscode');
18
18
  }, children: "\u2022 VS Code" }), _jsx("text", { fg: "cyan", wrapMode: "word", onMouseUp: () => {
19
19
  void openExternalLink(selectedSuggestionVscodeLink, 'vscode-insiders');
@@ -25,7 +25,7 @@ export const SearchStatus = ({ isIndexingFiles, repositoryFiles, searchRoot, has
25
25
  ? `#search root: ${searchRoot}`
26
26
  : '#search root: no search root' }), _jsx("text", { fg: "gray", children: isIndexingFiles
27
27
  ? '#search index: indexing...'
28
- : `#search index: ${repositoryFiles.length} files indexed` })] }));
28
+ : `#search index: ${repositoryFiles.length} paths indexed` })] }));
29
29
  export const InputStatus = ({ mode, isNarrow, inputValue, queuedAttachments, }) => (_jsxs("box", { flexDirection: isNarrow ? 'column' : 'row', justifyContent: "space-between", marginBottom: 0, gap: isNarrow ? 0 : undefined, children: [_jsx("text", { fg: "gray", children: mode === 'input' ? 'Custom input' : 'Option selection' }), _jsx("text", { fg: "gray", children: mode === 'input' && queuedAttachments.length > 0
30
30
  ? `${inputValue.length} chars + ${queuedAttachments.length} queued`
31
31
  : `${inputValue.length} chars` })] }));
@@ -33,5 +33,5 @@ export const ClipboardStatus = ({ status }) => (_jsx("text", { fg: status.starts
33
33
  export const AttachmentsDisplay = ({ queuedAttachments, }) => (_jsxs("box", { flexDirection: "column", width: "100%", gap: 0, children: [_jsxs("text", { fg: "yellow", children: [_jsx("strong", { children: "QUEUED ATTACHMENTS" }), " (Delete placeholder text to remove)"] }), queuedAttachments.map((attachment, index) => (_jsxs("text", { fg: "gray", wrapMode: "word", children: ["[File ", index + 1, "] ", attachment.label] }, attachment.id)))] }));
34
34
  export const SendButton = () => (_jsx("box", { backgroundColor: "cyan", paddingLeft: 1, paddingRight: 1, alignSelf: "flex-start", marginBottom: 0, children: _jsxs("text", { fg: "black", children: [_jsx("strong", { children: "Send" }), " \u2303S"] }) }));
35
35
  export const HelpText = ({ hasOptions }) => (_jsx("text", { fg: "gray", wrapMode: "word", children: hasOptions
36
- ? 'Enter/Ctrl+J newline (or #search apply) • #search nav: ↑/↓ or Ctrl+N/P • Tab mode switch • #path for repo file autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo'
37
- : 'Enter/Ctrl+J newline • #search nav: ↑/↓ or Ctrl+N/P • Enter/Tab #search apply • #path for repo file autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo' }));
36
+ ? 'Enter/Ctrl+J newline (or #search apply) • #search nav: ↑/↓ or Ctrl+N/P • Tab mode switch • #path for repo file/folder autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo'
37
+ : 'Enter/Ctrl+J newline • #search nav: ↑/↓ or Ctrl+N/P • Enter/Tab #search apply • #path for repo file/folder autocomplete • Cmd/Ctrl+C copy input • Cmd/Ctrl+V paste/attach • Cmd/Ctrl+Z undo • Cmd/Ctrl+Shift+Z redo' }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawwee/interactive-mcp",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "bin": {