Support completion of checkpoint names in /resume (#1063)
This commit is contained in:
parent
6d772a30c0
commit
b67806ae9a
|
@ -109,11 +109,20 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||||
const selectedSuggestion = completionSuggestions[indexToUse];
|
const selectedSuggestion = completionSuggestions[indexToUse];
|
||||||
|
|
||||||
if (query.trimStart().startsWith('/')) {
|
if (query.trimStart().startsWith('/')) {
|
||||||
|
const parts = query.trimStart().substring(1).split(' ');
|
||||||
|
const commandName = parts[0];
|
||||||
const slashIndex = query.indexOf('/');
|
const slashIndex = query.indexOf('/');
|
||||||
const base = query.substring(0, slashIndex + 1);
|
const base = query.substring(0, slashIndex + 1);
|
||||||
const newValue = base + selectedSuggestion.value;
|
|
||||||
buffer.setText(newValue);
|
const command = slashCommands.find((cmd) => cmd.name === commandName);
|
||||||
handleSubmitAndClear(newValue);
|
if (command && command.completion) {
|
||||||
|
const newValue = `${base}${commandName} ${selectedSuggestion.value}`;
|
||||||
|
buffer.setText(newValue);
|
||||||
|
} else {
|
||||||
|
const newValue = base + selectedSuggestion.value;
|
||||||
|
buffer.setText(newValue);
|
||||||
|
handleSubmitAndClear(newValue);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const atIndex = query.lastIndexOf('@');
|
const atIndex = query.lastIndexOf('@');
|
||||||
if (atIndex === -1) return;
|
if (atIndex === -1) return;
|
||||||
|
@ -131,7 +140,13 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
|
||||||
}
|
}
|
||||||
resetCompletionState();
|
resetCompletionState();
|
||||||
},
|
},
|
||||||
[resetCompletionState, handleSubmitAndClear, buffer, completionSuggestions],
|
[
|
||||||
|
resetCompletionState,
|
||||||
|
handleSubmitAndClear,
|
||||||
|
buffer,
|
||||||
|
completionSuggestions,
|
||||||
|
slashCommands,
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
useInput(
|
useInput(
|
||||||
|
|
|
@ -44,6 +44,7 @@ export interface SlashCommand {
|
||||||
name: string;
|
name: string;
|
||||||
altName?: string;
|
altName?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
completion?: () => Promise<string[]>;
|
||||||
action: (
|
action: (
|
||||||
mainCommand: string,
|
mainCommand: string,
|
||||||
subCommand?: string,
|
subCommand?: string,
|
||||||
|
@ -643,6 +644,25 @@ Add any other context about the problem here.
|
||||||
name: 'resume',
|
name: 'resume',
|
||||||
description:
|
description:
|
||||||
'resume from conversation checkpoint. Usage: /resume [tag]',
|
'resume from conversation checkpoint. Usage: /resume [tag]',
|
||||||
|
completion: async () => {
|
||||||
|
const geminiDir = config?.getGeminiDir();
|
||||||
|
if (!geminiDir) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const files = await fs.readdir(geminiDir);
|
||||||
|
return files
|
||||||
|
.filter(
|
||||||
|
(file) =>
|
||||||
|
file.startsWith('checkpoint-') && file.endsWith('.json'),
|
||||||
|
)
|
||||||
|
.map((file) =>
|
||||||
|
file.replace('checkpoint-', '').replace('.json', ''),
|
||||||
|
);
|
||||||
|
} catch (_err) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
action: async (_mainCommand, subCommand, _args) => {
|
action: async (_mainCommand, subCommand, _args) => {
|
||||||
const tag = (subCommand || '').trim();
|
const tag = (subCommand || '').trim();
|
||||||
const logger = new Logger(config?.getSessionId() || '');
|
const logger = new Logger(config?.getSessionId() || '');
|
||||||
|
|
|
@ -127,6 +127,34 @@ export function useCompletion(
|
||||||
|
|
||||||
// --- Handle Slash Command Completion ---
|
// --- Handle Slash Command Completion ---
|
||||||
if (trimmedQuery.startsWith('/')) {
|
if (trimmedQuery.startsWith('/')) {
|
||||||
|
const parts = trimmedQuery.substring(1).split(' ');
|
||||||
|
const commandName = parts[0];
|
||||||
|
const subCommand = parts.slice(1).join(' ');
|
||||||
|
|
||||||
|
const command = slashCommands.find(
|
||||||
|
(cmd) => cmd.name === commandName || cmd.altName === commandName,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (command && command.completion) {
|
||||||
|
const fetchAndSetSuggestions = async () => {
|
||||||
|
setIsLoadingSuggestions(true);
|
||||||
|
if (command.completion) {
|
||||||
|
const results = await command.completion();
|
||||||
|
const filtered = results.filter((r) => r.startsWith(subCommand));
|
||||||
|
const newSuggestions = filtered.map((s) => ({
|
||||||
|
label: s,
|
||||||
|
value: s,
|
||||||
|
}));
|
||||||
|
setSuggestions(newSuggestions);
|
||||||
|
setShowSuggestions(newSuggestions.length > 0);
|
||||||
|
setActiveSuggestionIndex(newSuggestions.length > 0 ? 0 : -1);
|
||||||
|
}
|
||||||
|
setIsLoadingSuggestions(false);
|
||||||
|
};
|
||||||
|
fetchAndSetSuggestions();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const partialCommand = trimmedQuery.substring(1);
|
const partialCommand = trimmedQuery.substring(1);
|
||||||
const filteredSuggestions = slashCommands
|
const filteredSuggestions = slashCommands
|
||||||
.filter(
|
.filter(
|
||||||
|
|
Loading…
Reference in New Issue