fix: pass draft starter text as command arguments
This commit is contained in:
@@ -516,7 +516,7 @@ const DraftWelcome: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
</h1>
|
</h1>
|
||||||
<DraftPresetChips
|
<DraftPresetChips
|
||||||
onSubmit={(text) => useInputStore.getState().requestPresetSubmit(text)}
|
onSubmit={(starter) => useInputStore.getState().requestPresetSubmit(starter.submitText, starter.ref.type)}
|
||||||
className="oc-draft-starters mt-8 max-w-md"
|
className="oc-draft-starters mt-8 max-w-md"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1271,12 +1271,14 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
|
|||||||
}, [inputMode, getCurrentInputSnapshot, currentSessionId, sessionPhase, autoReviewRunning, followUpBehavior, handleQueueMessage]);
|
}, [inputMode, getCurrentInputSnapshot, currentSessionId, sessionPhase, autoReviewRunning, followUpBehavior, handleQueueMessage]);
|
||||||
|
|
||||||
// Draft welcome presets: submit immediately.
|
// Draft welcome presets: submit immediately.
|
||||||
const submitPresetPrompt = React.useCallback((text: string) => {
|
const submitPresetPrompt = React.useCallback((text: string, type: 'command' | 'skill') => {
|
||||||
// The text goes straight into the submit (see SubmitOptions.presetText)
|
// The text goes straight into the submit (see SubmitOptions.presetText)
|
||||||
// instead of through the composer input — the collapsed mobile pill has
|
// instead of through the composer input — the collapsed mobile pill has
|
||||||
// no mounted textarea to stage it in.
|
// no mounted textarea to stage it in.
|
||||||
const draft = (composerRef.current?.getValue() ?? messageRef.current).trim();
|
const draft = (composerRef.current?.getValue() ?? messageRef.current).trim();
|
||||||
const presetText = draft ? `${text}\n${draft}` : text;
|
// OpenCode recognizes slash commands only when their arguments follow
|
||||||
|
// the command on the same line. Skills retain the multiline prompt form.
|
||||||
|
const presetText = draft ? `${text}${type === 'command' ? ' ' : '\n'}${draft}` : text;
|
||||||
void handleSubmitRef.current({ presetText });
|
void handleSubmitRef.current({ presetText });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -1308,7 +1310,7 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (pendingPresetSubmit == null) return;
|
if (pendingPresetSubmit == null) return;
|
||||||
const text = useInputStore.getState().consumePendingPresetSubmit();
|
const text = useInputStore.getState().consumePendingPresetSubmit();
|
||||||
if (text) submitPresetPrompt(text);
|
if (text) submitPresetPrompt(text.text, text.type);
|
||||||
}, [pendingPresetSubmit, submitPresetPrompt]);
|
}, [pendingPresetSubmit, submitPresetPrompt]);
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
@@ -2718,7 +2720,10 @@ const ChatInputComponent: React.FC<ChatInputProps> = ({ onOpenSettings, scrollTo
|
|||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{newSessionDraftOpen && !isDesktopExpanded && !isMobile && !isVSCode && !isMiniChatSurface ? (
|
{newSessionDraftOpen && !isDesktopExpanded && !isMobile && !isVSCode && !isMiniChatSurface ? (
|
||||||
<DraftPresetChips onSubmit={submitPresetPrompt} className="chat-input-column mt-4" />
|
<DraftPresetChips
|
||||||
|
onSubmit={(starter) => submitPresetPrompt(starter.submitText, starter.ref.type)}
|
||||||
|
className="chat-input-column mt-4"
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ import {
|
|||||||
} from './useDraftStarters';
|
} from './useDraftStarters';
|
||||||
|
|
||||||
type DraftPresetChipsProps = {
|
type DraftPresetChipsProps = {
|
||||||
/** Called with the resolved text (command or skill invocation) when a chip is clicked. */
|
/** Called with the resolved starter invocation when a chip is clicked. */
|
||||||
onSubmit: (text: string) => void;
|
onSubmit: (starter: ResolvedStarter) => void;
|
||||||
/** Extra classes for the wrapper (e.g. width/spacing per surface). */
|
/** Extra classes for the wrapper (e.g. width/spacing per surface). */
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
@@ -66,7 +66,7 @@ const PICKER_SECTIONS: { key: PinnableSection; headingKey: 'chat.draftStarters.s
|
|||||||
|
|
||||||
const SortableChip: React.FC<{
|
const SortableChip: React.FC<{
|
||||||
item: ResolvedStarter;
|
item: ResolvedStarter;
|
||||||
onSubmit: (text: string) => void;
|
onSubmit: (starter: ResolvedStarter) => void;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
/** Hide the per-chip hover "x" (mobile uses the trash drop-zone instead). */
|
/** Hide the per-chip hover "x" (mobile uses the trash drop-zone instead). */
|
||||||
hideRemove?: boolean;
|
hideRemove?: boolean;
|
||||||
@@ -91,7 +91,7 @@ const SortableChip: React.FC<{
|
|||||||
type="button"
|
type="button"
|
||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
onClick={() => onSubmit(item.submitText)}
|
onClick={() => onSubmit(item)}
|
||||||
className="group inline-flex touch-none select-none items-center gap-1.5 rounded-full border px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-[var(--interactive-hover)] hover:text-foreground"
|
className="group inline-flex touch-none select-none items-center gap-1.5 rounded-full border px-3 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-[var(--interactive-hover)] hover:text-foreground"
|
||||||
style={chipStyle}
|
style={chipStyle}
|
||||||
>
|
>
|
||||||
@@ -116,7 +116,7 @@ const SortableChip: React.FC<{
|
|||||||
|
|
||||||
const StarterGroup: React.FC<{
|
const StarterGroup: React.FC<{
|
||||||
items: ResolvedStarter[];
|
items: ResolvedStarter[];
|
||||||
onSubmit: (text: string) => void;
|
onSubmit: (starter: ResolvedStarter) => void;
|
||||||
onRemove: (item: ResolvedStarter) => void;
|
onRemove: (item: ResolvedStarter) => void;
|
||||||
hideRemove?: boolean;
|
hideRemove?: boolean;
|
||||||
}> = ({ items, onSubmit, onRemove, hideRemove }) => (
|
}> = ({ items, onSubmit, onRemove, hideRemove }) => (
|
||||||
|
|||||||
@@ -105,14 +105,14 @@ export type InputState = {
|
|||||||
* render the chips outside ChatInput (e.g. under the welcome message on
|
* render the chips outside ChatInput (e.g. under the welcome message on
|
||||||
* narrow layouts); consumed by ChatInput, which owns the command-aware submit.
|
* narrow layouts); consumed by ChatInput, which owns the command-aware submit.
|
||||||
*/
|
*/
|
||||||
pendingPresetSubmit: string | null
|
pendingPresetSubmit: { text: string; type: "command" | "skill" } | null
|
||||||
attachedFiles: AttachedFile[]
|
attachedFiles: AttachedFile[]
|
||||||
activeEditorFile: VSCodeActiveEditorFile | null
|
activeEditorFile: VSCodeActiveEditorFile | null
|
||||||
|
|
||||||
setPendingInputText: (text: string | null, mode?: "replace" | "append" | "append-inline") => void
|
setPendingInputText: (text: string | null, mode?: "replace" | "append" | "append-inline") => void
|
||||||
consumePendingInputText: () => { text: string; mode: "replace" | "append" | "append-inline" } | null
|
consumePendingInputText: () => { text: string; mode: "replace" | "append" | "append-inline" } | null
|
||||||
requestPresetSubmit: (text: string) => void
|
requestPresetSubmit: (text: string, type: "command" | "skill") => void
|
||||||
consumePendingPresetSubmit: () => string | null
|
consumePendingPresetSubmit: () => { text: string; type: "command" | "skill" } | null
|
||||||
setPendingSyntheticParts: (parts: SyntheticContextPart[] | null) => void
|
setPendingSyntheticParts: (parts: SyntheticContextPart[] | null) => void
|
||||||
consumePendingSyntheticParts: () => SyntheticContextPart[] | null
|
consumePendingSyntheticParts: () => SyntheticContextPart[] | null
|
||||||
addAttachedFile: (file: File) => Promise<boolean>
|
addAttachedFile: (file: File) => Promise<boolean>
|
||||||
@@ -144,7 +144,7 @@ export const useInputStore = create<InputState>()((set, get) => ({
|
|||||||
return { text: pendingInputText, mode: pendingInputMode }
|
return { text: pendingInputText, mode: pendingInputMode }
|
||||||
},
|
},
|
||||||
|
|
||||||
requestPresetSubmit: (text) => set({ pendingPresetSubmit: text }),
|
requestPresetSubmit: (text, type) => set({ pendingPresetSubmit: { text, type } }),
|
||||||
|
|
||||||
consumePendingPresetSubmit: () => {
|
consumePendingPresetSubmit: () => {
|
||||||
const { pendingPresetSubmit } = get()
|
const { pendingPresetSubmit } = get()
|
||||||
|
|||||||
Reference in New Issue
Block a user