feat: turn Explore into a full /explore command

Promote the last plain-prompt draft chip into a proper /explore command so
all draft welcome presets are now commands. Its hidden prompt investigates
the repository and gives a structured orientation — big picture, main
modules, how they connect, conventions, and where to start — instead of a
file-by-file dump.

Follows the established pattern: visible + hidden magic prompts wired into
command autocomplete, the submit handler, the draft chip, and the Magic
Prompts settings page, with i18n across all locales. Drops the now-unused
explore prompt string.
This commit is contained in:
Bohdan Triapitsyn
2026-05-30 02:04:32 +03:00
parent 4bc75cc749
commit 6cd71bdfe5
21 changed files with 110 additions and 10 deletions
+24 -2
View File
@@ -99,7 +99,7 @@ type DraftPreset = {
command?: string;
};
const DRAFT_PRESETS: readonly DraftPreset[] = [
{ id: 'explore', icon: 'compass-3', labelKey: 'chat.draftPresets.explore.label', promptKey: 'chat.draftPresets.explore.prompt' },
{ id: 'explore', icon: 'compass-3', labelKey: 'chat.draftPresets.explore.label', command: '/explore' },
{ id: 'catchup', icon: 'history', labelKey: 'chat.draftPresets.catchup.label', command: '/catch-up' },
{ id: 'weigh', icon: 'scales-3', labelKey: 'chat.draftPresets.weigh.label', command: '/weigh' },
{ id: 'plan', icon: 'survey', labelKey: 'chat.draftPresets.plan.label', command: '/plan-feature' },
@@ -1124,7 +1124,7 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
const availableSkills = useSkillsStore((s) => s.skills);
const knownSlashNames = React.useMemo(() => {
const names = new Set<string>([
'init', 'review', 'undo', 'redo', 'timeline', 'compact', 'summary', 'workspace-review', 'plan-feature', 'catch-up', 'debug', 'weigh',
'init', 'review', 'undo', 'redo', 'timeline', 'compact', 'summary', 'workspace-review', 'plan-feature', 'catch-up', 'debug', 'weigh', 'explore',
]);
for (const command of availableCommands) names.add(command.name.toLowerCase());
for (const skill of availableSkills) names.add(skill.name.toLowerCase());
@@ -2040,6 +2040,28 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
}
return;
}
else if (commandName === 'explore' && (currentSessionId || newSessionDraftOpen)) {
try {
await sessionActions.waitForConnectionOrThrow();
const visibleText = await renderMagicPrompt('session.explore.visible');
const instructionsText = await renderMagicPrompt('session.explore.instructions');
await sendMessage(
visibleText,
providerIdToSend,
modelIdToSend,
agentNameToSend,
[],
agentMentionName,
[{ text: instructionsText, synthetic: true }],
variantToSend,
inputMode,
);
scrollToBottom?.();
} catch (error) {
toast.error(error instanceof Error ? error.message : t('chat.chatInput.toast.exploreFailed'));
}
return;
}
}
const currentSessionDirectory = currentSessionId
@@ -168,6 +168,10 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
? [{ id: 'openchamber:weigh', name: 'weigh', source: 'openchamber' as const, description: t('chat.commandAutocomplete.command.weighDescription'), isOpenChamber: true }]
: []
),
...(canStartSessionCommand
? [{ id: 'openchamber:explore', name: 'explore', source: 'openchamber' as const, description: t('chat.commandAutocomplete.command.exploreDescription'), isOpenChamber: true }]
: []
),
];
const allCommands = [...builtInCommands, ...customCommands, ...skillCommands];
@@ -229,6 +233,10 @@ export const CommandAutocomplete = React.forwardRef<CommandAutocompleteHandle, C
? [{ id: 'openchamber:weigh', name: 'weigh', source: 'openchamber' as const, description: t('chat.commandAutocomplete.command.weighDescription'), isOpenChamber: true }]
: []
),
...(canStartSessionCommand
? [{ id: 'openchamber:explore', name: 'explore', source: 'openchamber' as const, description: t('chat.commandAutocomplete.command.exploreDescription'), isOpenChamber: true }]
: []
),
];
const filtered = (searchQuery