fix(app): source composer cwd from agent state, not draft hook

The GitHub picker showed "No results found." for any running agent after
the first message was sent. useAgentInputDraft owned a local cwd state
that clear("sent") wiped to "", so the composer read cwd: "" even though
the agent's real cwd was correct on the wire.

Drop cwd ownership from the hook. Composer takes cwd as a prop sourced
by the parent — agentState.cwd for running agents, composerState.workingDir
for drafts, sourceDirectory for setup flows. The hook now persists only
{text, attachments}. Legacy persisted drafts with a cwd field still
hydrate; tagged COMPAT(draft-cwd) for removal after 2026-11-09.

Also moves attachment pills back inside the composer's bordered surface
via a new attachmentSlot prop on MessageInput, and shrinks pill height
from 48 to 32 — the subagents-track tuck previously had attachments
floating between it and the input.

Adds one Playwright spec asserting the draft-create-agent path submits
the workspace cwd.
This commit is contained in:
Mohamed Boudra
2026-05-09 18:32:43 +07:00
parent d241c24776
commit d1bda25a0b
14 changed files with 145 additions and 310 deletions
+6 -6
View File
@@ -1541,7 +1541,6 @@ export function Composer({
<View style={styles.messageInputContainer}>
{autocompletePopover}
{attachmentPreviewList}
{/* MessageInput handles everything: text, dictation, attachments, all buttons */}
<StableMessageInput
@@ -1581,6 +1580,7 @@ export function Composer({
onFocusChange={handleFocusChange}
onHeightChange={onComposerHeightChange}
inputWrapperStyle={inputWrapperStyle}
attachmentSlot={attachmentPreviewList}
/>
<Combobox
options={githubSearchOptions}
@@ -1685,16 +1685,16 @@ const styles = StyleSheet.create((theme: Theme) => ({
flexWrap: "wrap",
},
imageThumbnail: {
width: 48,
height: 48,
width: 32,
height: 32,
},
imageThumbnailPlaceholder: {
width: 48,
height: 48,
width: 32,
height: 32,
backgroundColor: theme.colors.surface2,
},
githubPillBody: {
minHeight: 48,
minHeight: 32,
maxWidth: 260,
flexDirection: "row",
alignItems: "center",
@@ -125,6 +125,8 @@ export interface MessageInputProps {
onHeightChange?: (height: number) => void;
/** Extra styles merged onto the input wrapper (e.g. elevated background). */
inputWrapperStyle?: import("react-native").ViewStyle;
/** Content rendered inside the bordered input surface, above the text input (e.g. attachment pills). */
attachmentSlot?: React.ReactNode;
}
export interface MessageInputRef {
@@ -1094,6 +1096,7 @@ interface ResolvedMessageInputProps {
onFocusChange: ((focused: boolean) => void) | undefined;
onHeightChange: ((height: number) => void) | undefined;
inputWrapperStyle: import("react-native").ViewStyle | undefined;
attachmentSlot: React.ReactNode;
}
function resolveMessageInputProps(props: MessageInputProps): ResolvedMessageInputProps {
@@ -1133,6 +1136,7 @@ function resolveMessageInputProps(props: MessageInputProps): ResolvedMessageInpu
onFocusChange: props.onFocusChange,
onHeightChange: props.onHeightChange,
inputWrapperStyle: props.inputWrapperStyle,
attachmentSlot: props.attachmentSlot,
};
}
@@ -1180,6 +1184,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
onFocusChange,
onHeightChange,
inputWrapperStyle,
attachmentSlot,
} = resolveMessageInputProps(props);
const buttonIconSize = isWeb ? ICON_SIZE.md : ICON_SIZE.lg;
const toast = useToast();
@@ -1697,6 +1702,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
<View ref={rootRef} style={styles.container} testID="message-input-root">
{/* Regular input */}
<Animated.View ref={inputWrapperRef} style={inputWrapperCombinedStyle}>
{attachmentSlot}
{/* Text input */}
<View style={styles.textInputScrollWrapper}>
<ThemedTextInput
@@ -151,7 +151,6 @@ export function WorkspaceSetupDialog() {
const isConnected = useHostRuntimeIsConnected(serverId);
const chatDraft = useAgentInputDraft({
draftKey: `workspace-setup:${serverId}:${sourceDirectory}`,
initialCwd: sourceDirectory,
composer: buildChatDraftComposerArgs({
serverId,
isConnected,
@@ -393,7 +392,7 @@ export function WorkspaceSetupDialog() {
onChangeText={chatDraft.setText}
attachments={chatDraft.attachments}
onChangeAttachments={chatDraft.setAttachments}
cwd={chatDraft.cwd}
cwd={sourceDirectory}
clearDraft={chatDraft.clear}
autoFocus
commandDraftConfig={composerState?.commandDraftConfig}