feat: add web search, file edit, MCP management, file refs, and /stop to CLI/TUI (#348)
This commit was merged in pull request #348.
This commit is contained in:
@@ -15,6 +15,7 @@ import { useConversations } from './hooks/use-conversations.js';
|
||||
import { useSearch } from './hooks/use-search.js';
|
||||
import { executeHelp, executeStatus, executeHistory, commandRegistry } from './commands/index.js';
|
||||
import { fetchConversationMessages } from './gateway-api.js';
|
||||
import { expandFileRefs, hasFileRefs, handleAttachCommand } from './file-ref.js';
|
||||
|
||||
export interface TuiAppProps {
|
||||
gatewayUrl: string;
|
||||
@@ -85,6 +86,36 @@ export function TuiApp({
|
||||
// combo is handled by the top-level useInput handler (e.g. Ctrl+T → 't').
|
||||
const ctrlJustFired = useRef(false);
|
||||
|
||||
// Wrap sendMessage to expand @file references before sending
|
||||
const sendMessageWithFileRefs = useCallback(
|
||||
(content: string) => {
|
||||
if (!hasFileRefs(content)) {
|
||||
socket.sendMessage(content);
|
||||
return;
|
||||
}
|
||||
void expandFileRefs(content)
|
||||
.then(({ expandedMessage, filesAttached, errors }) => {
|
||||
for (const err of errors) {
|
||||
socket.addSystemMessage(err);
|
||||
}
|
||||
if (filesAttached.length > 0) {
|
||||
socket.addSystemMessage(
|
||||
`📎 Attached ${filesAttached.length} file(s): ${filesAttached.join(', ')}`,
|
||||
);
|
||||
}
|
||||
socket.sendMessage(expandedMessage);
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
socket.addSystemMessage(
|
||||
`File expansion failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
// Send original message without expansion
|
||||
socket.sendMessage(content);
|
||||
});
|
||||
},
|
||||
[socket],
|
||||
);
|
||||
|
||||
const handleLocalCommand = useCallback(
|
||||
(parsed: ParsedCommand) => {
|
||||
switch (parsed.command) {
|
||||
@@ -123,9 +154,36 @@ export function TuiApp({
|
||||
socket.addSystemMessage('Failed to create new conversation.');
|
||||
});
|
||||
break;
|
||||
case 'attach': {
|
||||
if (!parsed.args) {
|
||||
socket.addSystemMessage('Usage: /attach <file-path>');
|
||||
break;
|
||||
}
|
||||
void handleAttachCommand(parsed.args)
|
||||
.then(({ content, error }) => {
|
||||
if (error) {
|
||||
socket.addSystemMessage(`Attach error: ${error}`);
|
||||
} else if (content) {
|
||||
// Send the file content as a user message
|
||||
socket.sendMessage(content);
|
||||
}
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
socket.addSystemMessage(
|
||||
`Attach failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'stop':
|
||||
// Currently no stop mechanism exposed — show feedback
|
||||
socket.addSystemMessage('Stop is not available for the current session.');
|
||||
if (socket.isStreaming && socket.socketRef.current?.connected && socket.conversationId) {
|
||||
socket.socketRef.current.emit('abort', {
|
||||
conversationId: socket.conversationId,
|
||||
});
|
||||
socket.addSystemMessage('Abort signal sent.');
|
||||
} else {
|
||||
socket.addSystemMessage('No active stream to stop.');
|
||||
}
|
||||
break;
|
||||
case 'cost': {
|
||||
const u = socket.tokenUsage;
|
||||
@@ -348,7 +406,7 @@ export function TuiApp({
|
||||
}
|
||||
setTuiInput(val);
|
||||
}}
|
||||
onSubmit={socket.sendMessage}
|
||||
onSubmit={sendMessageWithFileRefs}
|
||||
onSystemMessage={socket.addSystemMessage}
|
||||
onLocalCommand={handleLocalCommand}
|
||||
onGatewayCommand={handleGatewayCommand}
|
||||
|
||||
Reference in New Issue
Block a user