centaurus-cli 2.8.1 → 2.8.2
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/tools/reproduce_issue.d.ts +2 -0
- package/dist/tools/reproduce_issue.d.ts.map +1 -0
- package/dist/tools/reproduce_issue.js +166 -0
- package/dist/tools/reproduce_issue.js.map +1 -0
- package/dist/tools/validation.d.ts.map +1 -1
- package/dist/tools/validation.js +4 -3
- package/dist/tools/validation.js.map +1 -1
- package/dist/ui/components/App.d.ts +1 -1
- package/dist/ui/components/App.d.ts.map +1 -1
- package/dist/ui/components/App.js +23 -10
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/DiffViewer.d.ts.map +1 -1
- package/dist/ui/components/DiffViewer.js +69 -58
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.d.ts +11 -0
- package/dist/ui/components/FileTagAutocomplete.d.ts.map +1 -0
- package/dist/ui/components/FileTagAutocomplete.js +27 -0
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -0
- package/dist/ui/components/InputBox.d.ts.map +1 -1
- package/dist/ui/components/InputBox.js +185 -2
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.d.ts.map +1 -1
- package/dist/ui/components/InteractiveShell.js +177 -13
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
- package/dist/ui/components/ToolExecutionMessage.js +44 -14
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,91 +2,95 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import { wrapText } from '../../utils/markdown-parser.js';
|
|
4
4
|
// Maximum number of lines to show before truncating in diff view
|
|
5
|
-
//
|
|
6
|
-
const MAX_PREVIEW_LINES =
|
|
5
|
+
// Using 10 lines to match FileCreationPreview
|
|
6
|
+
const MAX_PREVIEW_LINES = 10;
|
|
7
7
|
// Maximum number of lines to show in full view before truncating
|
|
8
8
|
const MAX_FULL_VIEW_LINES = 1000;
|
|
9
9
|
export const DiffViewer = ({ diff, filePath, fullDiff }) => {
|
|
10
10
|
const [showFull, setShowFull] = useState(false);
|
|
11
11
|
useInput((input, key) => {
|
|
12
|
-
if (
|
|
12
|
+
if (input === 'o' && key.ctrl) {
|
|
13
13
|
setShowFull(prev => !prev);
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
|
|
16
|
+
// Process content into displayable lines (wrapped and styled)
|
|
17
|
+
const renderDiffContent = (content, maxLines) => {
|
|
18
|
+
const lines = content.split('\n');
|
|
19
|
+
const processedLines = [];
|
|
20
|
+
// Parse diff logic
|
|
21
|
+
let currentLineNum = 1;
|
|
22
|
+
// Calculate max content width
|
|
23
|
+
// Terminal width - borders (2) - padding (2) - line number (5 with space)
|
|
24
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
25
|
+
const maxContentWidth = Math.max(40, terminalWidth - 11);
|
|
22
26
|
for (const line of lines) {
|
|
23
27
|
const trimmed = line.trim();
|
|
24
|
-
// Handle diff headers
|
|
28
|
+
// Handle diff headers and hunk headers
|
|
25
29
|
if (line.startsWith('@@')) {
|
|
26
|
-
// Parse @@ -old,count +new,count @@
|
|
27
30
|
const match = line.match(/@@ \-\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
28
31
|
if (match && match[1]) {
|
|
29
32
|
currentLineNum = parseInt(match[1], 10);
|
|
30
33
|
}
|
|
31
|
-
|
|
34
|
+
// In full view or if this is relevant context, we generally want to show it
|
|
35
|
+
// But for compactness in preview, sometimes hunks are skipped if we implemented smart slicing
|
|
36
|
+
// Here we just render everything linearly
|
|
32
37
|
}
|
|
33
|
-
// Skip
|
|
38
|
+
// Skip generic diff metadata if it's not useful code context
|
|
34
39
|
if (line.startsWith('---') || line.startsWith('+++'))
|
|
35
40
|
continue;
|
|
36
41
|
if (line.startsWith('Index:'))
|
|
37
42
|
continue;
|
|
38
43
|
if (trimmed.startsWith('==='))
|
|
39
44
|
continue;
|
|
40
|
-
|
|
45
|
+
let type = 'context';
|
|
46
|
+
let lineNum = undefined;
|
|
41
47
|
if (line.startsWith('+')) {
|
|
42
|
-
|
|
48
|
+
type = 'added';
|
|
49
|
+
lineNum = currentLineNum++;
|
|
43
50
|
}
|
|
44
51
|
else if (line.startsWith('-')) {
|
|
45
|
-
|
|
46
|
-
//
|
|
52
|
+
type = 'deleted';
|
|
53
|
+
// No line num increment for deleted lines in new file version
|
|
47
54
|
}
|
|
48
55
|
else {
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
type = 'context';
|
|
57
|
+
lineNum = currentLineNum++;
|
|
51
58
|
}
|
|
59
|
+
// Determine style
|
|
60
|
+
let style = { color: 'white', backgroundColor: undefined };
|
|
61
|
+
if (type === 'added')
|
|
62
|
+
style = { backgroundColor: undefined, color: 'green' }; // Clean look: colored text
|
|
63
|
+
if (type === 'deleted')
|
|
64
|
+
style = { backgroundColor: undefined, color: 'red' };
|
|
65
|
+
// Format line number
|
|
66
|
+
const lineNumStr = lineNum ? lineNum.toString().padStart(4, ' ') : ' ';
|
|
67
|
+
const cleanText = (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) ? line.slice(1) : line;
|
|
68
|
+
// Wrap text
|
|
69
|
+
const wrapped = wrapText(cleanText || ' ', maxContentWidth, 0);
|
|
70
|
+
wrapped.forEach((wLine, idx) => {
|
|
71
|
+
processedLines.push({
|
|
72
|
+
text: wLine,
|
|
73
|
+
...style,
|
|
74
|
+
lineNumStr: idx === 0 ? lineNumStr : ' '
|
|
75
|
+
});
|
|
76
|
+
});
|
|
52
77
|
}
|
|
53
|
-
//
|
|
54
|
-
const
|
|
55
|
-
const deletedCount = contentLines.filter(l => l.type === 'deleted').length;
|
|
56
|
-
// Determine if we need to truncate
|
|
57
|
-
const totalLines = contentLines.length;
|
|
78
|
+
// Determine truncation
|
|
79
|
+
const totalLines = processedLines.length;
|
|
58
80
|
const shouldTruncate = totalLines > maxLines;
|
|
59
|
-
const displayLines = shouldTruncate ?
|
|
81
|
+
const displayLines = shouldTruncate ? processedLines.slice(0, maxLines) : processedLines;
|
|
60
82
|
const hiddenLines = shouldTruncate ? totalLines - maxLines : 0;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (type === 'deleted')
|
|
65
|
-
return { backgroundColor: 'red', color: 'black' };
|
|
66
|
-
return { color: 'white' };
|
|
67
|
-
};
|
|
68
|
-
// Generate summary text
|
|
83
|
+
// Stats for summary
|
|
84
|
+
const addedCount = (content.match(/^\+/gm) || []).length;
|
|
85
|
+
const deletedCount = (content.match(/^\-/gm) || []).length;
|
|
69
86
|
const addedText = addedCount === 1 ? '1 line added' : `${addedCount} lines added`;
|
|
70
87
|
const deletedText = deletedCount === 1 ? '1 line deleted' : `${deletedCount} lines deleted`;
|
|
71
|
-
// Calculate available width for content
|
|
72
|
-
// Terminal width - borders (2) - padding (2) - line number (5 with space)
|
|
73
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
74
|
-
const maxContentWidth = Math.max(40, terminalWidth - 11);
|
|
75
88
|
return (React.createElement(React.Fragment, null,
|
|
76
|
-
displayLines.map((line, idx) => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const text = line.text || ' ';
|
|
82
|
-
const wrappedLines = wrapText(text, maxContentWidth, 0);
|
|
83
|
-
return wrappedLines.map((wrappedLine, lineIdx) => (React.createElement(Box, { key: `${idx}-${lineIdx}`, flexDirection: "column" },
|
|
84
|
-
React.createElement(Box, { flexDirection: "row" },
|
|
85
|
-
React.createElement(Text, { color: "gray" },
|
|
86
|
-
lineIdx === 0 ? lineNumStr : ' ',
|
|
87
|
-
' '),
|
|
88
|
-
React.createElement(Text, { ...style }, wrappedLine)))));
|
|
89
|
-
}).flat(),
|
|
89
|
+
displayLines.map((line, idx) => (React.createElement(Box, { key: idx, flexDirection: "row" },
|
|
90
|
+
React.createElement(Text, { color: "gray" },
|
|
91
|
+
line.lineNumStr,
|
|
92
|
+
" "),
|
|
93
|
+
React.createElement(Text, { color: line.color, backgroundColor: line.backgroundColor }, line.text)))),
|
|
90
94
|
shouldTruncate && (React.createElement(Box, { marginTop: 1 },
|
|
91
95
|
React.createElement(Text, { color: "#ffaa00", dimColor: true },
|
|
92
96
|
"... ",
|
|
@@ -95,20 +99,27 @@ export const DiffViewer = ({ diff, filePath, fullDiff }) => {
|
|
|
95
99
|
hiddenLines === 1 ? 'line' : 'lines',
|
|
96
100
|
" not shown ..."))),
|
|
97
101
|
React.createElement(Box, { marginTop: 1, marginBottom: 1 },
|
|
98
|
-
React.createElement(Text, { color: "#666666" }, '─'.repeat(
|
|
102
|
+
React.createElement(Text, { color: "#666666" }, '─'.repeat(terminalWidth - 4))),
|
|
99
103
|
React.createElement(Box, null,
|
|
100
104
|
React.createElement(Text, { color: "green" }, addedText),
|
|
101
105
|
React.createElement(Text, { color: "#666666" }, ", "),
|
|
102
106
|
React.createElement(Text, { color: "red" }, deletedText))));
|
|
103
107
|
};
|
|
108
|
+
// Determine which content to show
|
|
109
|
+
// If showFull is true AND fullDiff is available, show fullDiff
|
|
110
|
+
// If showFull is true but no fullDiff, show expanded regular diff
|
|
111
|
+
// Otherwise show limited regular diff
|
|
112
|
+
const contentToShow = (showFull && fullDiff) ? fullDiff : diff;
|
|
113
|
+
const limit = showFull ? MAX_FULL_VIEW_LINES : MAX_PREVIEW_LINES;
|
|
104
114
|
return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#ffaa00", paddingX: 1 },
|
|
105
115
|
React.createElement(Box, { justifyContent: "space-between" },
|
|
106
|
-
React.createElement(Text, { color: "#ffffff", bold: true },
|
|
107
|
-
|
|
116
|
+
React.createElement(Text, { color: "#ffffff", bold: true },
|
|
117
|
+
"Diff Preview: ",
|
|
118
|
+
filePath || 'Untitled'),
|
|
119
|
+
React.createElement(Box, null,
|
|
120
|
+
React.createElement(Text, { color: "#666666", dimColor: true }, showFull ? 'Ctrl+O: Collapse' : 'Ctrl+O: Full File'))),
|
|
108
121
|
React.createElement(Box, { marginTop: 1, marginBottom: 1 },
|
|
109
|
-
React.createElement(Text, { color: "#666666" }, '─'.repeat(80))),
|
|
110
|
-
|
|
111
|
-
? renderDiffContent(fullDiff, MAX_FULL_VIEW_LINES)
|
|
112
|
-
: renderDiffContent(diff, MAX_PREVIEW_LINES)));
|
|
122
|
+
React.createElement(Text, { color: "#666666" }, '─'.repeat((process.stdout.columns || 80) - 4))),
|
|
123
|
+
renderDiffContent(contentToShow, limit)));
|
|
113
124
|
};
|
|
114
125
|
//# sourceMappingURL=DiffViewer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffViewer.js","sourceRoot":"","sources":["../../../src/ui/components/DiffViewer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAQ1D,iEAAiE;AACjE,
|
|
1
|
+
{"version":3,"file":"DiffViewer.js","sourceRoot":"","sources":["../../../src/ui/components/DiffViewer.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface FileTagAutocompleteProps {
|
|
3
|
+
files: Array<{
|
|
4
|
+
name: string;
|
|
5
|
+
isDirectory: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
selectedIndex: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const FileTagAutocomplete: React.FC<FileTagAutocompleteProps>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=FileTagAutocomplete.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileTagAutocomplete.d.ts","sourceRoot":"","sources":["../../../src/ui/components/FileTagAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,UAAU,wBAAwB;IAC9B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACrD,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA+ClE,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export const FileTagAutocomplete = ({ files, selectedIndex }) => {
|
|
4
|
+
if (files.length === 0)
|
|
5
|
+
return null;
|
|
6
|
+
// Limit to 6 suggestions
|
|
7
|
+
const displayFiles = files.slice(0, 6);
|
|
8
|
+
return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: "#00ccff", paddingX: 1, marginLeft: 1, marginTop: 0 },
|
|
9
|
+
React.createElement(Box, { marginBottom: 0 },
|
|
10
|
+
React.createElement(Text, { color: "#666666", dimColor: true }, "Files matching @...")),
|
|
11
|
+
displayFiles.map((file, index) => {
|
|
12
|
+
const isSelected = index === selectedIndex;
|
|
13
|
+
const icon = file.isDirectory ? '📁' : '📄';
|
|
14
|
+
return (React.createElement(Box, { key: file.name, paddingX: 1 },
|
|
15
|
+
React.createElement(Text, { color: isSelected ? '#00ccff' : '#aaaaaa', bold: isSelected, inverse: isSelected },
|
|
16
|
+
icon,
|
|
17
|
+
" ",
|
|
18
|
+
file.name,
|
|
19
|
+
file.isDirectory ? '/' : '')));
|
|
20
|
+
}),
|
|
21
|
+
files.length > 6 && (React.createElement(Box, { marginTop: 0 },
|
|
22
|
+
React.createElement(Text, { color: "#666666", dimColor: true },
|
|
23
|
+
"...and ",
|
|
24
|
+
files.length - 6,
|
|
25
|
+
" more")))));
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=FileTagAutocomplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileTagAutocomplete.js","sourceRoot":"","sources":["../../../src/ui/components/FileTagAutocomplete.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAOhC,MAAM,CAAC,MAAM,mBAAmB,GAAuC,CAAC,EACpE,KAAK,EACL,aAAa,EAChB,EAAE,EAAE;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,yBAAyB;IACzB,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvC,OAAO,CACH,oBAAC,GAAG,IACA,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAC,SAAS,EACrB,QAAQ,EAAE,CAAC,EACX,UAAU,EAAE,CAAC,EACb,SAAS,EAAE,CAAC;QAEZ,oBAAC,GAAG,IAAC,YAAY,EAAE,CAAC;YAChB,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,QAAQ,gCAA2B,CACvD;QACL,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC9B,MAAM,UAAU,GAAG,KAAK,KAAK,aAAa,CAAC;YAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAE5C,OAAO,CACH,oBAAC,GAAG,IACA,GAAG,EAAE,IAAI,CAAC,IAAI,EACd,QAAQ,EAAE,CAAC;gBAEX,oBAAC,IAAI,IACD,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACzC,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,UAAU;oBAElB,IAAI;;oBAAG,IAAI,CAAC,IAAI;oBAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAC3C,CACL,CACT,CAAC;QACN,CAAC,CAAC;QACD,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CACjB,oBAAC,GAAG,IAAC,SAAS,EAAE,CAAC;YACb,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,QAAQ;;gBAAS,KAAK,CAAC,MAAM,GAAG,CAAC;wBAAa,CAClE,CACT,CACC,CACT,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../../src/ui/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../../src/ui/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+C,MAAM,OAAO,CAAC;AAIpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAWzD,UAAU,aAAa;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+CD,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAgoC3C,CAAC"}
|
|
@@ -7,6 +7,7 @@ import { ContextWindowIndicator } from './ContextWindowIndicator.js';
|
|
|
7
7
|
import { detectIntent } from '../../utils/input-classifier.js';
|
|
8
8
|
import { CommandHistoryManager } from '../../utils/command-history.js';
|
|
9
9
|
import { SlashCommandAutocomplete } from './SlashCommandAutocomplete.js';
|
|
10
|
+
import { FileTagAutocomplete } from './FileTagAutocomplete.js';
|
|
10
11
|
import { filterCommands } from '../../config/slash-commands.js';
|
|
11
12
|
const getVisualLines = (text, width) => {
|
|
12
13
|
const logicalLines = text.split('\n');
|
|
@@ -67,6 +68,12 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
67
68
|
const [slashAutocompleteVisible, setSlashAutocompleteVisible] = useState(false);
|
|
68
69
|
const [slashAutocompleteCommands, setSlashAutocompleteCommands] = useState([]);
|
|
69
70
|
const [slashAutocompleteSelectedIndex, setSlashAutocompleteSelectedIndex] = useState(0);
|
|
71
|
+
// File Tag Autocomplete State (@ symbol)
|
|
72
|
+
const [fileTagAutocompleteVisible, setFileTagAutocompleteVisible] = useState(false);
|
|
73
|
+
const [fileTagSuggestions, setFileTagSuggestions] = useState([]);
|
|
74
|
+
const [fileTagSelectedIndex, setFileTagSelectedIndex] = useState(0);
|
|
75
|
+
const [activeFileTagStart, setActiveFileTagStart] = useState(null);
|
|
76
|
+
const [confirmedFileTags, setConfirmedFileTags] = useState([]);
|
|
70
77
|
// Configuration for scrolling
|
|
71
78
|
const MAX_VISIBLE_LINES = 9;
|
|
72
79
|
// Load history on mount
|
|
@@ -139,6 +146,82 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
139
146
|
onToggleCommandMode();
|
|
140
147
|
}
|
|
141
148
|
}, [value, commandMode, onToggleCommandMode, isAutoMode]);
|
|
149
|
+
// Helper function to get files matching a query from the current directory
|
|
150
|
+
const getMatchingFiles = (query) => {
|
|
151
|
+
try {
|
|
152
|
+
const cwd = currentWorkingDirectory || process.cwd();
|
|
153
|
+
if (!fs.existsSync(cwd))
|
|
154
|
+
return [];
|
|
155
|
+
const entries = fs.readdirSync(cwd, { withFileTypes: true });
|
|
156
|
+
const lowerQuery = query.toLowerCase();
|
|
157
|
+
return entries
|
|
158
|
+
.filter(entry => {
|
|
159
|
+
// Exclude hidden files (starting with .)
|
|
160
|
+
if (entry.name.startsWith('.'))
|
|
161
|
+
return false;
|
|
162
|
+
// Match case-insensitive
|
|
163
|
+
return entry.name.toLowerCase().includes(lowerQuery);
|
|
164
|
+
})
|
|
165
|
+
.map(entry => ({
|
|
166
|
+
name: entry.name,
|
|
167
|
+
isDirectory: entry.isDirectory()
|
|
168
|
+
}))
|
|
169
|
+
.sort((a, b) => {
|
|
170
|
+
// Prioritize files that start with the query
|
|
171
|
+
const aStarts = a.name.toLowerCase().startsWith(lowerQuery);
|
|
172
|
+
const bStarts = b.name.toLowerCase().startsWith(lowerQuery);
|
|
173
|
+
if (aStarts && !bStarts)
|
|
174
|
+
return -1;
|
|
175
|
+
if (!aStarts && bStarts)
|
|
176
|
+
return 1;
|
|
177
|
+
return a.name.localeCompare(b.name);
|
|
178
|
+
})
|
|
179
|
+
.slice(0, 10); // Get more than 6 initially, UI will limit display
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
// File tag (@) detection effect
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
// Don't show file tag autocomplete in command mode
|
|
188
|
+
if (commandMode) {
|
|
189
|
+
setFileTagAutocompleteVisible(false);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// Find if cursor is within a potential file tag
|
|
193
|
+
// Look backwards from cursor to find @
|
|
194
|
+
let atPosition = -1;
|
|
195
|
+
for (let i = cursorOffset - 1; i >= 0; i--) {
|
|
196
|
+
const char = value[i];
|
|
197
|
+
// Stop if we hit whitespace or another special char
|
|
198
|
+
if (/[\s\n]/.test(char))
|
|
199
|
+
break;
|
|
200
|
+
if (char === '@') {
|
|
201
|
+
atPosition = i;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (atPosition === -1) {
|
|
206
|
+
setFileTagAutocompleteVisible(false);
|
|
207
|
+
setActiveFileTagStart(null);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Extract the query after @
|
|
211
|
+
const query = value.slice(atPosition + 1, cursorOffset);
|
|
212
|
+
// Get matching files
|
|
213
|
+
const matches = getMatchingFiles(query);
|
|
214
|
+
if (matches.length > 0) {
|
|
215
|
+
setFileTagSuggestions(matches);
|
|
216
|
+
setFileTagAutocompleteVisible(true);
|
|
217
|
+
setActiveFileTagStart(atPosition);
|
|
218
|
+
setFileTagSelectedIndex(0);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
setFileTagAutocompleteVisible(false);
|
|
222
|
+
setActiveFileTagStart(null);
|
|
223
|
+
}
|
|
224
|
+
}, [value, cursorOffset, commandMode, currentWorkingDirectory]);
|
|
142
225
|
const pushToUndoStack = () => {
|
|
143
226
|
setUndoStack(prev => [...prev, { value, cursorOffset }]);
|
|
144
227
|
setRedoStack([]); // Clear redo stack on new action
|
|
@@ -209,6 +292,79 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
209
292
|
return;
|
|
210
293
|
}
|
|
211
294
|
}
|
|
295
|
+
// Handle file tag (@) autocomplete navigation
|
|
296
|
+
if (fileTagAutocompleteVisible) {
|
|
297
|
+
if (key.downArrow) {
|
|
298
|
+
setFileTagSelectedIndex(prev => Math.min(prev + 1, Math.min(fileTagSuggestions.length - 1, 5)));
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (key.upArrow) {
|
|
302
|
+
setFileTagSelectedIndex(prev => Math.max(prev - 1, 0));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (key.return && input.length <= 1 && !key.shift && !key.ctrl) {
|
|
306
|
+
// Select the highlighted file
|
|
307
|
+
const selected = fileTagSuggestions[fileTagSelectedIndex];
|
|
308
|
+
if (selected && activeFileTagStart !== null) {
|
|
309
|
+
pushToUndoStack();
|
|
310
|
+
// Replace @query with @filename
|
|
311
|
+
const beforeTag = value.slice(0, activeFileTagStart);
|
|
312
|
+
const afterCursor = value.slice(cursorOffset);
|
|
313
|
+
const fileName = selected.name + (selected.isDirectory ? '/' : '');
|
|
314
|
+
const newValue = beforeTag + '@' + fileName + ' ' + afterCursor;
|
|
315
|
+
const newCursorPos = activeFileTagStart + 1 + fileName.length + 1;
|
|
316
|
+
setValue(newValue);
|
|
317
|
+
setCursorOffset(newCursorPos);
|
|
318
|
+
// Add to confirmed file tags
|
|
319
|
+
setConfirmedFileTags(prev => [
|
|
320
|
+
...prev.filter(tag =>
|
|
321
|
+
// Remove any overlapping tags
|
|
322
|
+
!(tag.start >= activeFileTagStart && tag.start <= cursorOffset)),
|
|
323
|
+
{
|
|
324
|
+
start: activeFileTagStart,
|
|
325
|
+
end: activeFileTagStart + 1 + fileName.length,
|
|
326
|
+
fileName: selected.name
|
|
327
|
+
}
|
|
328
|
+
]);
|
|
329
|
+
setFileTagAutocompleteVisible(false);
|
|
330
|
+
setActiveFileTagStart(null);
|
|
331
|
+
}
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (key.escape) {
|
|
335
|
+
setFileTagAutocompleteVisible(false);
|
|
336
|
+
setActiveFileTagStart(null);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
// If Tab is pressed, also select the current file
|
|
340
|
+
if (key.tab && !key.shift) {
|
|
341
|
+
const selected = fileTagSuggestions[fileTagSelectedIndex];
|
|
342
|
+
if (selected && activeFileTagStart !== null) {
|
|
343
|
+
pushToUndoStack();
|
|
344
|
+
const beforeTag = value.slice(0, activeFileTagStart);
|
|
345
|
+
const afterCursor = value.slice(cursorOffset);
|
|
346
|
+
const fileName = selected.name + (selected.isDirectory ? '/' : '');
|
|
347
|
+
const newValue = beforeTag + '@' + fileName + afterCursor;
|
|
348
|
+
const newCursorPos = activeFileTagStart + 1 + fileName.length;
|
|
349
|
+
setValue(newValue);
|
|
350
|
+
setCursorOffset(newCursorPos);
|
|
351
|
+
// If it's a directory, keep dropdown open for subdirectory navigation
|
|
352
|
+
if (!selected.isDirectory) {
|
|
353
|
+
setConfirmedFileTags(prev => [
|
|
354
|
+
...prev.filter(tag => !(tag.start >= activeFileTagStart && tag.start <= cursorOffset)),
|
|
355
|
+
{
|
|
356
|
+
start: activeFileTagStart,
|
|
357
|
+
end: activeFileTagStart + 1 + fileName.length,
|
|
358
|
+
fileName: selected.name
|
|
359
|
+
}
|
|
360
|
+
]);
|
|
361
|
+
setFileTagAutocompleteVisible(false);
|
|
362
|
+
setActiveFileTagStart(null);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
212
368
|
// DELETE WORD BACKWARDS - Check this FIRST before standard backspace/delete
|
|
213
369
|
// Triggers on any of these conditions:
|
|
214
370
|
// 1. Ctrl+W (char code 23) - Standard Unix terminal shortcut
|
|
@@ -728,7 +884,22 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
728
884
|
if (commandMode) {
|
|
729
885
|
CommandHistoryManager.getInstance().addCommand(trimmedValue, currentDir);
|
|
730
886
|
}
|
|
731
|
-
|
|
887
|
+
// Resolve file tags (@filename -> absolute path)
|
|
888
|
+
let resolvedValue = trimmedValue;
|
|
889
|
+
if (!commandMode) {
|
|
890
|
+
const cwd = currentWorkingDirectory || process.cwd();
|
|
891
|
+
// Find all @filename patterns (@ followed by non-whitespace)
|
|
892
|
+
resolvedValue = trimmedValue.replace(/@([^\s@]+)/g, (match, fileName) => {
|
|
893
|
+
// Check if file exists
|
|
894
|
+
const filePath = path.resolve(cwd, fileName);
|
|
895
|
+
if (fs.existsSync(filePath)) {
|
|
896
|
+
return filePath;
|
|
897
|
+
}
|
|
898
|
+
// If file doesn't exist, keep original
|
|
899
|
+
return match;
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
onSubmit(resolvedValue);
|
|
732
903
|
setValue('');
|
|
733
904
|
setCursorOffset(0);
|
|
734
905
|
setCompletions([]);
|
|
@@ -739,6 +910,7 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
739
910
|
setRedoStack([]);
|
|
740
911
|
setSelection(null);
|
|
741
912
|
setAutocompleteSuggestion(null);
|
|
913
|
+
setConfirmedFileTags([]); // Clear confirmed tags on submit
|
|
742
914
|
}
|
|
743
915
|
};
|
|
744
916
|
// Rendering Logic with Scrolling
|
|
@@ -800,6 +972,12 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
800
972
|
const isSelected = selection &&
|
|
801
973
|
absPos >= Math.min(selection.start, selection.end) &&
|
|
802
974
|
absPos < Math.max(selection.start, selection.end);
|
|
975
|
+
// Check if this character is part of an active file tag (being typed after @)
|
|
976
|
+
const isInActiveFileTag = activeFileTagStart !== null &&
|
|
977
|
+
absPos >= activeFileTagStart &&
|
|
978
|
+
absPos < cursorOffset;
|
|
979
|
+
// Check if this character is part of a confirmed file tag
|
|
980
|
+
const isInConfirmedFileTag = confirmedFileTags.some(tag => absPos >= tag.start && absPos < tag.end);
|
|
803
981
|
const isCursor = isCursorLine && charIdx === cursorCol;
|
|
804
982
|
if (isCursor) {
|
|
805
983
|
return React.createElement(Text, { key: charIdx, inverse: true, color: isSelected ? "yellow" : undefined }, char);
|
|
@@ -807,6 +985,10 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
807
985
|
if (isSelected) {
|
|
808
986
|
return React.createElement(Text, { key: charIdx, backgroundColor: "white", color: "black" }, char);
|
|
809
987
|
}
|
|
988
|
+
// Highlight file tags with cyan color
|
|
989
|
+
if (isInConfirmedFileTag || isInActiveFileTag) {
|
|
990
|
+
return React.createElement(Text, { key: charIdx, color: "#00ccff", bold: true }, char);
|
|
991
|
+
}
|
|
810
992
|
return React.createElement(Text, { key: charIdx }, char);
|
|
811
993
|
});
|
|
812
994
|
// Handle cursor at end of line
|
|
@@ -854,6 +1036,7 @@ export const InputBox = React.memo(({ onSubmit, placeholder = 'Ask anything...',
|
|
|
854
1036
|
!commandMode && autoAcceptMode ? (React.createElement(Text, { color: "#00cc66", bold: true }, "[AUTO-ACCEPT: ON]")) : !commandMode ? (React.createElement(Text, { color: "#666666", dimColor: true }, "[AUTO-ACCEPT: OFF]")) : null,
|
|
855
1037
|
!commandMode && (React.createElement(Box, { marginLeft: 1 },
|
|
856
1038
|
React.createElement(ContextWindowIndicator, { currentTokens: currentTokens, maxTokens: maxTokens }))))),
|
|
857
|
-
slashAutocompleteVisible && (React.createElement(SlashCommandAutocomplete, { commands: slashAutocompleteCommands, selectedIndex: slashAutocompleteSelectedIndex }))
|
|
1039
|
+
slashAutocompleteVisible && (React.createElement(SlashCommandAutocomplete, { commands: slashAutocompleteCommands, selectedIndex: slashAutocompleteSelectedIndex })),
|
|
1040
|
+
fileTagAutocompleteVisible && (React.createElement(FileTagAutocomplete, { files: fileTagSuggestions, selectedIndex: fileTagSelectedIndex }))));
|
|
858
1041
|
});
|
|
859
1042
|
//# sourceMappingURL=InputBox.js.map
|