diff --git a/config/flaky-test-pattern-baseline.txt b/config/flaky-test-pattern-baseline.txt index e604c236e9a..78125b397ce 100644 --- a/config/flaky-test-pattern-baseline.txt +++ b/config/flaky-test-pattern-baseline.txt @@ -695,7 +695,7 @@ 1 test-no-wall-clock:mobile/src/components/pr-sidebar/pr-comment-card-web-avatar.test.tsx 1 test-no-wall-clock:mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts 1 test-no-wall-clock:mobile/src/session/mobile-structured-send-new-action.test.ts -2 test-no-wall-clock:mobile/src/session/use-mobile-native-chat-message-send-draft-lifetime.test.ts +2 test-no-wall-clock:mobile/src/session/native-chat/composer/use-mobile-native-chat-message-send-draft-lifetime.test.ts 1 test-no-wall-clock:mobile/src/session/use-mobile-native-chat-message-send.test.ts 1 test-no-wall-clock:mobile/src/source-control/MobileGitHistoryList.test.tsx 1 test-no-wall-clock:mobile/src/tasks/worktree-create-launch-operation.test.ts diff --git a/config/scripts/mobile-file-ranking-benchmark.mjs b/config/scripts/mobile-file-ranking-benchmark.mjs index 7ca18cbc998..7c791593a7d 100644 --- a/config/scripts/mobile-file-ranking-benchmark.mjs +++ b/config/scripts/mobile-file-ranking-benchmark.mjs @@ -14,7 +14,7 @@ if (!baseline) { 'Usage: node config/scripts/mobile-file-ranking-benchmark.mjs ' ) } -// git show :mobile/src/session/mobile-native-chat-autocomplete.ts | node config/scripts/mobile-file-ranking-benchmark.mjs --autocomplete-stdin +// git show :mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.ts | node config/scripts/mobile-file-ranking-benchmark.mjs --autocomplete-stdin const autocompleteSource = baseline === '--autocomplete-stdin' ? readFileSync(0, 'utf8') : null const root = path.resolve(import.meta.dirname, '../..') function git(args) { @@ -116,7 +116,7 @@ const results = [] let differentialCases = 0 for (const [file, name] of [ ['src/main/runtime/files/search/mobile-path-search.ts', 'rankRuntimeMobileFilePaths'], - ['mobile/src/session/mobile-native-chat-autocomplete.ts', 'rankSuggestions'] + ['mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.ts', 'rankSuggestions'] ]) { if (autocompleteSource !== null && name === 'rankRuntimeMobileFilePaths') { continue diff --git a/config/scripts/mobile-web-app/mobile-web-app-held-press-render.test.mjs b/config/scripts/mobile-web-app/mobile-web-app-held-press-render.test.mjs index 9e9a37a98e2..d8fdbcc007d 100644 --- a/config/scripts/mobile-web-app/mobile-web-app-held-press-render.test.mjs +++ b/config/scripts/mobile-web-app/mobile-web-app-held-press-render.test.mjs @@ -65,7 +65,7 @@ beforeAll(async () => { join(routeDir, 'hold-dictation-probe.tsx'), holdDictationProbeRouteSource({ terminalActionsModule: join(sessionDir, 'MobileTerminalInputActions'), - chatComposerModule: join(sessionDir, 'MobileNativeChatComposer') + chatComposerModule: join(sessionDir, 'native-chat', 'composer', 'MobileNativeChatComposer') }) ) await writeFile( diff --git a/mobile/src/session/MobileNativeChatOverlay.tsx b/mobile/src/session/MobileNativeChatOverlay.tsx index aa865c0b0c6..c7947c0c83f 100644 --- a/mobile/src/session/MobileNativeChatOverlay.tsx +++ b/mobile/src/session/MobileNativeChatOverlay.tsx @@ -4,9 +4,9 @@ import { MobileNativeChatView, type MobileNativeChatInputLockReason } from './Mo import { foldMobileNativeChatMessages } from './mobile-native-chat-render-data' import type { MobileNativeChatImageAttachments } from './native-chat/composer/use-mobile-native-chat-image-attachments' import type { MobileNativeChatController } from './use-mobile-native-chat-controller' -import type { MobileNativeChatStructuredComposer } from './MobileNativeChatComposer' +import type { MobileNativeChatStructuredComposer } from './native-chat/composer/MobileNativeChatComposer' import { useMobileNativeChatStreamingBubble } from './native-chat/use-mobile-native-chat-streaming-bubble' -import { useMobileNativeChatComposerTray } from './use-mobile-native-chat-composer-tray' +import { useMobileNativeChatComposerTray } from './native-chat/composer/use-mobile-native-chat-composer-tray' import { useMobileNativeChatVisualRenderer } from './MobileNativeChatVisual' import { MobileNativeChatVisualContext } from './mobile-native-chat-visual-context' import { MobileNativeChatRootItemSourceContext } from './mobile-native-chat-item-read' diff --git a/mobile/src/session/MobileNativeChatQuestion.tsx b/mobile/src/session/MobileNativeChatQuestion.tsx index 3f7ce2f0a68..d9554293bda 100644 --- a/mobile/src/session/MobileNativeChatQuestion.tsx +++ b/mobile/src/session/MobileNativeChatQuestion.tsx @@ -3,7 +3,7 @@ import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' import { ArrowUp, Check, CircleHelp } from 'lucide-react-native' import { MobileNativeChatCardHeaderAction } from './MobileNativeChatCardHeaderAction' import { colors, radii, spacing, typography } from '../theme/mobile-theme' -import { mobileNativeChatInputStyles } from './mobile-native-chat-input-styles' +import { mobileNativeChatInputStyles } from './native-chat/composer/mobile-native-chat-input-styles' import { formatQuestionAnswerByIndexes, formatQuestionAnswerWithOtherByIndexes, diff --git a/mobile/src/session/MobileNativeChatQueuedMessageEditor.tsx b/mobile/src/session/MobileNativeChatQueuedMessageEditor.tsx index dd06284975e..12b0e67d2e2 100644 --- a/mobile/src/session/MobileNativeChatQueuedMessageEditor.tsx +++ b/mobile/src/session/MobileNativeChatQueuedMessageEditor.tsx @@ -11,7 +11,7 @@ import { } from 'react-native' import { Check, X } from 'lucide-react-native' import { colors, radii, spacing, typography } from '../theme/mobile-theme' -import { mobileNativeChatInputStyles } from './mobile-native-chat-input-styles' +import { mobileNativeChatInputStyles } from './native-chat/composer/mobile-native-chat-input-styles' import type { MobileQueuedMessageInlineEditor } from './use-mobile-structured-queued-edit' import { useTextInputContentHeight } from '../platform/text-input-content-height' diff --git a/mobile/src/session/MobileNativeChatStopButton.tsx b/mobile/src/session/MobileNativeChatStopButton.tsx index 31cdeb1b30d..965bb244546 100644 --- a/mobile/src/session/MobileNativeChatStopButton.tsx +++ b/mobile/src/session/MobileNativeChatStopButton.tsx @@ -2,7 +2,7 @@ import { ActivityIndicator, Pressable } from 'react-native' import { Square } from 'lucide-react-native' import { NATIVE_CHAT_TURN_STATUS_COPY } from '../../../src/shared/native-chat-turn-status' import { colors } from '../theme/mobile-theme' -import { mobileNativeChatComposerStyles as styles } from './mobile-native-chat-composer-styles' +import { mobileNativeChatComposerStyles as styles } from './native-chat/composer/mobile-native-chat-composer-styles' // held tracks this phone’s in-flight Stop request, not the host’s stopping status. export function MobileNativeChatStopButton({ diff --git a/mobile/src/session/MobileNativeChatView.composer-lock.test.ts b/mobile/src/session/MobileNativeChatView.composer-lock.test.ts index fbfa4dcf2ec..d479e2868d1 100644 --- a/mobile/src/session/MobileNativeChatView.composer-lock.test.ts +++ b/mobile/src/session/MobileNativeChatView.composer-lock.test.ts @@ -32,7 +32,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.failure-banner.test.ts b/mobile/src/session/MobileNativeChatView.failure-banner.test.ts index 69cb502780d..d362405498b 100644 --- a/mobile/src/session/MobileNativeChatView.failure-banner.test.ts +++ b/mobile/src/session/MobileNativeChatView.failure-banner.test.ts @@ -35,7 +35,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.history-paging.test.ts b/mobile/src/session/MobileNativeChatView.history-paging.test.ts index 9574f0fa53f..49323412f88 100644 --- a/mobile/src/session/MobileNativeChatView.history-paging.test.ts +++ b/mobile/src/session/MobileNativeChatView.history-paging.test.ts @@ -38,7 +38,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts b/mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts index 5b8dd042545..7d75141f72a 100644 --- a/mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts +++ b/mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts @@ -67,7 +67,7 @@ vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQu vi.mock('./MobileNativeChatSessionOptionPickers', () => ({ MobileNativeChatSessionOptionPickers: 'SessionOptions' })) -vi.mock('./MobileNativeChatComposerMenu', () => ({ +vi.mock('./native-chat/composer/MobileNativeChatComposerMenu', () => ({ MobileNativeChatComposerMenu: 'Suggestions', composerMenuInsertText: () => '' })) diff --git a/mobile/src/session/MobileNativeChatView.rows.test.ts b/mobile/src/session/MobileNativeChatView.rows.test.ts index e881b319fec..63d8837b86d 100644 --- a/mobile/src/session/MobileNativeChatView.rows.test.ts +++ b/mobile/src/session/MobileNativeChatView.rows.test.ts @@ -31,7 +31,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.stop.test.ts b/mobile/src/session/MobileNativeChatView.stop.test.ts index 82ea9ab7860..e9273ec1da4 100644 --- a/mobile/src/session/MobileNativeChatView.stop.test.ts +++ b/mobile/src/session/MobileNativeChatView.stop.test.ts @@ -30,7 +30,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.streaming-rows.test.ts b/mobile/src/session/MobileNativeChatView.streaming-rows.test.ts index 01561088c2f..ad08391c28b 100644 --- a/mobile/src/session/MobileNativeChatView.streaming-rows.test.ts +++ b/mobile/src/session/MobileNativeChatView.streaming-rows.test.ts @@ -174,7 +174,9 @@ vi.mock('./MobileNativeChatImageViewer', () => ({ MobileNativeChatImageViewer: ' vi.mock('./MobileNativeChatMessageActionsSheet', () => ({ MobileNativeChatMessageActionsSheet: 'ActionsSheet' })) -vi.mock('./MobileNativeChatComposer', () => ({ MobileNativeChatComposer: 'Composer' })) +vi.mock('./native-chat/composer/MobileNativeChatComposer', () => ({ + MobileNativeChatComposer: 'Composer' +})) const stable = { onSend: async () => true, diff --git a/mobile/src/session/MobileNativeChatView.tail-follow.test.ts b/mobile/src/session/MobileNativeChatView.tail-follow.test.ts index 77f6b9f9721..dbe46c36145 100644 --- a/mobile/src/session/MobileNativeChatView.tail-follow.test.ts +++ b/mobile/src/session/MobileNativeChatView.tail-follow.test.ts @@ -36,7 +36,7 @@ vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'ChatPermission' })) vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const { composerStub } = await import('./MobileNativeChatView.render-stubs.test-fixture') return composerStub() }) diff --git a/mobile/src/session/MobileNativeChatView.tsx b/mobile/src/session/MobileNativeChatView.tsx index 8dd34002906..3102e039b6c 100644 --- a/mobile/src/session/MobileNativeChatView.tsx +++ b/mobile/src/session/MobileNativeChatView.tsx @@ -44,9 +44,12 @@ import type { PendingNativeChatImage } from './native-chat/composer/mobile-nativ import { MobileNativeChatComposer, type MobileNativeChatStructuredComposer -} from './MobileNativeChatComposer' +} from './native-chat/composer/MobileNativeChatComposer' import { MobileNativeChatPromptCard } from './MobileNativeChatPromptCard' -import { NO_COMPOSER_TRAY, type ComposerTrayProps } from './use-mobile-native-chat-composer-tray' +import { + NO_COMPOSER_TRAY, + type ComposerTrayProps +} from './native-chat/composer/use-mobile-native-chat-composer-tray' import type { MobileChatPermission } from './mobile-native-chat-permission' import type { MobileChatQuestion } from './mobile-native-chat-question' import type { MobileNativeChatSessionOptionPickersProps } from './MobileNativeChatSessionOptionPickers' diff --git a/mobile/src/session/MobileNativeChatView.turn-status.test.ts b/mobile/src/session/MobileNativeChatView.turn-status.test.ts index 859cf6977b4..a2d35bd9d87 100644 --- a/mobile/src/session/MobileNativeChatView.turn-status.test.ts +++ b/mobile/src/session/MobileNativeChatView.turn-status.test.ts @@ -69,7 +69,7 @@ vi.mock('./MobileNativeChatPermission', () => ({ MobileNativeChatPermission: 'Ch vi.mock('./MobileNativeChatQuestion', () => ({ MobileNativeChatQuestion: 'ChatQuestion' })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('./MobileNativeChatComposer', async () => { +vi.mock('./native-chat/composer/MobileNativeChatComposer', async () => { const React = await import('react') const { MobileNativeChatStopButton } = await import('./MobileNativeChatStopButton') return { diff --git a/mobile/src/session/MobileNativeChatView.waiting-rows.test.ts b/mobile/src/session/MobileNativeChatView.waiting-rows.test.ts index 443b0e0a259..11e42cbb629 100644 --- a/mobile/src/session/MobileNativeChatView.waiting-rows.test.ts +++ b/mobile/src/session/MobileNativeChatView.waiting-rows.test.ts @@ -39,7 +39,9 @@ vi.mock('lucide-react-native', () => ({ })) vi.mock('./MobileNativeChatMessage', () => ({ MobileNativeChatMessage: 'ChatMessage' })) vi.mock('./MobileNativeChatLiveLine', () => ({ MobileNativeChatLiveLine: 'LiveStatus' })) -vi.mock('./MobileNativeChatComposer', () => ({ MobileNativeChatComposer: 'Composer' })) +vi.mock('./native-chat/composer/MobileNativeChatComposer', () => ({ + MobileNativeChatComposer: 'Composer' +})) // The queue's action sheet pulls in the animation runtime, which this react-native mock can't host. vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) vi.mock('./MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) diff --git a/mobile/src/session/__mocks__/mobile-prompt-controller.ts b/mobile/src/session/__mocks__/mobile-prompt-controller.ts index 3fbaa311018..20fb46add65 100644 --- a/mobile/src/session/__mocks__/mobile-prompt-controller.ts +++ b/mobile/src/session/__mocks__/mobile-prompt-controller.ts @@ -75,7 +75,7 @@ vi.mock('../MobileNativeChatAsk', () => ({ MobileNativeChatAsk: 'ChatAsk' })) vi.mock('../MobileNativeChatSessionOptionPickers', () => ({ MobileNativeChatSessionOptionPickers: 'SessionOptions' })) -vi.mock('../MobileNativeChatComposerMenu', () => ({ +vi.mock('../native-chat/composer/MobileNativeChatComposerMenu', () => ({ MobileNativeChatComposerMenu: 'Suggestions', composerMenuInsertText: () => '' })) @@ -113,7 +113,7 @@ vi.mock('../use-mobile-session-view-mode', () => ({ vi.mock('../use-mobile-native-chat-session-lane', () => ({ useMobileNativeChatSessionLane: () => ({ session, structuredSession: structured }) })) -vi.mock('../use-mobile-native-chat-drafts', () => ({ +vi.mock('../native-chat/composer/use-mobile-native-chat-drafts', () => ({ useMobileNativeChatDrafts: () => ({ composerText: 'ordinary message', setComposerText: vi.fn(), @@ -139,7 +139,7 @@ vi.mock('../use-mobile-native-chat-session-option-controller', () => ({ vi.mock('../native-chat/composer/use-mobile-native-chat-file-search', () => ({ useMobileNativeChatFileSearch: () => ({ nativeChatFilePaths: [], loadNativeChatFiles: vi.fn() }) })) -vi.mock('../use-mobile-native-chat-composer-tray', () => ({ +vi.mock('../native-chat/composer/use-mobile-native-chat-composer-tray', () => ({ NO_COMPOSER_TRAY: {}, useMobileNativeChatComposerTray: () => ({}) })) diff --git a/mobile/src/session/mobile-file-search-owner-cleanup.test.tsx b/mobile/src/session/mobile-file-search-owner-cleanup.test.tsx index b49c0d22a54..3b840e8b50c 100644 --- a/mobile/src/session/mobile-file-search-owner-cleanup.test.tsx +++ b/mobile/src/session/mobile-file-search-owner-cleanup.test.tsx @@ -2,7 +2,7 @@ import { createElement, StrictMode, type ReactNode } from 'react' import { act, create } from 'react-test-renderer' import { afterEach, beforeEach, expect, it, vi } from 'vitest' import type { RpcClient } from '../transport/rpc-client' -import { MobileNativeChatComposer } from './MobileNativeChatComposer' +import { MobileNativeChatComposer } from './native-chat/composer/MobileNativeChatComposer' import { useMobileNativeChatFileSearch } from './native-chat/composer/use-mobile-native-chat-file-search' import { stubRpcClient } from '../transport/rpc-client-test-stub' diff --git a/mobile/src/session/mobile-native-chat-controller-contract.ts b/mobile/src/session/mobile-native-chat-controller-contract.ts index 294a1b7ab51..4bbcc47e646 100644 --- a/mobile/src/session/mobile-native-chat-controller-contract.ts +++ b/mobile/src/session/mobile-native-chat-controller-contract.ts @@ -18,7 +18,7 @@ import type { MobileNativeChatSendOutcome } from './native-chat/mobile-native-ch import type { MobileNativeChatCommandRefusalCauses } from './native-chat/use-mobile-native-chat-send-error' import type { MobileStructuredQueuedMessageControls } from './use-mobile-structured-queued-message-controls' import type { MobileStructuredBackgroundTasks } from './use-mobile-structured-background-tasks' -import type { MobileNativeChatPendingMessage } from './use-mobile-native-chat-drafts' +import type { MobileNativeChatPendingMessage } from './native-chat/mobile-native-chat-pending-echo' import type { useMobileNativeChatSession } from './use-mobile-native-chat-session' import type { MobileNativeChatSessionOptionPickersProps } from './MobileNativeChatSessionOptionPickers' import type { MobileNativeChatVisualSource } from './mobile-native-chat-visual-read' diff --git a/mobile/src/session/mobile-native-chat-merged-snapshot-parity-hooks.test.tsx b/mobile/src/session/mobile-native-chat-merged-snapshot-parity-hooks.test.tsx index 956e2ba5bbc..be5be3418a5 100644 --- a/mobile/src/session/mobile-native-chat-merged-snapshot-parity-hooks.test.tsx +++ b/mobile/src/session/mobile-native-chat-merged-snapshot-parity-hooks.test.tsx @@ -19,7 +19,7 @@ import { STOP_JOURNAL_SESSION, stopJournal } from './mobile-native-chat-stop-journal.test-fixture' -import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' +import { useMobileNativeChatDrafts } from './native-chat/composer/use-mobile-native-chat-drafts' import type { MobileNativeChatController } from './use-mobile-native-chat-controller' import { useMobileStructuredAgentSession } from './use-mobile-structured-agent-session' @@ -64,7 +64,9 @@ vi.mock('./MobileNativeChatMessageActionsSheet', () => ({ MobileNativeChatMessageActionsSheet: 'MessageActionsSheet' })) vi.mock('./MobileNativeChatLiveLine', () => ({ MobileNativeChatLiveLine: 'LiveStatus' })) -vi.mock('./MobileNativeChatComposer', () => ({ MobileNativeChatComposer: 'Composer' })) +vi.mock('./native-chat/composer/MobileNativeChatComposer', () => ({ + MobileNativeChatComposer: 'Composer' +})) vi.mock('./MobileNativeChatQueuedMessages', () => ({ MobileNativeChatQueuedMessages: 'Queued' })) vi.mock('./MobileNativeChatVisual', () => ({ useMobileNativeChatVisualRenderer: () => null })) vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) diff --git a/mobile/src/session/mobile-native-chat-queued-message-styles.ts b/mobile/src/session/mobile-native-chat-queued-message-styles.ts index bb04d8c4ba2..9e3a3a510ed 100644 --- a/mobile/src/session/mobile-native-chat-queued-message-styles.ts +++ b/mobile/src/session/mobile-native-chat-queued-message-styles.ts @@ -1,6 +1,6 @@ import { StyleSheet } from 'react-native' import { colors, radii, spacing, typography } from '../theme/mobile-theme' -import { COMPOSER_INSET_TOP } from './mobile-native-chat-composer-styles' +import { COMPOSER_INSET_TOP } from './native-chat/composer/mobile-native-chat-composer-styles' // Keep 44pt targets inside the parent row because Android drops outside touches. const MIN_TOUCH_TARGET = 44 diff --git a/mobile/src/session/MobileNativeChatComposer.structured.test.ts b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.structured.test.ts similarity index 97% rename from mobile/src/session/MobileNativeChatComposer.structured.test.ts rename to mobile/src/session/native-chat/composer/MobileNativeChatComposer.structured.test.ts index cdfddeef0ac..d8a5604d9ab 100644 --- a/mobile/src/session/MobileNativeChatComposer.structured.test.ts +++ b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.structured.test.ts @@ -52,8 +52,10 @@ vi.mock('lucide-react-native', () => ({ X: 'X' })) -vi.mock('../components/mounted-bottom-drawer', () => ({ MountedBottomDrawer: 'BottomDrawer' })) -vi.mock('../components/bottom-drawer-modal-host-scope', () => ({ +vi.mock('../../../components/mounted-bottom-drawer', () => ({ + MountedBottomDrawer: 'BottomDrawer' +})) +vi.mock('../../../components/bottom-drawer-modal-host-scope', () => ({ useBottomDrawerModalHost: () => null })) diff --git a/mobile/src/session/MobileNativeChatComposer.test.ts b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.test.ts similarity index 98% rename from mobile/src/session/MobileNativeChatComposer.test.ts rename to mobile/src/session/native-chat/composer/MobileNativeChatComposer.test.ts index 79b1b37f85d..18ca064ec59 100644 --- a/mobile/src/session/MobileNativeChatComposer.test.ts +++ b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.test.ts @@ -2,9 +2,12 @@ import { createElement, createRef, StrictMode, type ComponentProps, type ReactNo import { act, create, type ReactTestInstance, type ReactTestRenderer } from 'react-test-renderer' import { Keyboard, type TextInput } from 'react-native' import { afterEach, describe, expect, it, vi } from 'vitest' -import { radii, spacing } from '../theme/mobile-theme' +import { radii, spacing } from '../../../theme/mobile-theme' import { MobileNativeChatComposer as NativeChatComposer } from './MobileNativeChatComposer' -import { findAllByHostType, findByHostType } from '../test-support/react-test-renderer-host-nodes' +import { + findAllByHostType, + findByHostType +} from '../../../test-support/react-test-renderer-host-nodes' const getNoComposerEditGeneration = () => 0 @@ -54,8 +57,10 @@ vi.mock('lucide-react-native', () => ({ X: 'X' })) -vi.mock('../components/mounted-bottom-drawer', () => ({ MountedBottomDrawer: 'BottomDrawer' })) -vi.mock('../components/bottom-drawer-modal-host-scope', () => ({ +vi.mock('../../../components/mounted-bottom-drawer', () => ({ + MountedBottomDrawer: 'BottomDrawer' +})) +vi.mock('../../../components/bottom-drawer-modal-host-scope', () => ({ useBottomDrawerModalHost: () => null })) diff --git a/mobile/src/session/MobileNativeChatComposer.tsx b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.tsx similarity index 93% rename from mobile/src/session/MobileNativeChatComposer.tsx rename to mobile/src/session/native-chat/composer/MobileNativeChatComposer.tsx index 17dc08211db..7da7fb78f82 100644 --- a/mobile/src/session/MobileNativeChatComposer.tsx +++ b/mobile/src/session/native-chat/composer/MobileNativeChatComposer.tsx @@ -1,25 +1,25 @@ import { useEffect, useLayoutEffect, useRef, useState } from 'react' import { ActivityIndicator, Keyboard, Pressable, type TextInput, View } from 'react-native' import { ArrowUp, Mic, Plus, Square } from 'lucide-react-native' -import { colors } from '../theme/mobile-theme' -import { NATIVE_CHAT_COMPOSER_PLACEHOLDER } from '../../../src/shared/native-chat-turn-status' +import { colors } from '../../../theme/mobile-theme' +import { NATIVE_CHAT_COMPOSER_PLACEHOLDER } from '../../../../../src/shared/native-chat-turn-status' import { MobileNativeChatComposerMenu } from './MobileNativeChatComposerMenu' import { MobileNativeChatComposerField } from './MobileNativeChatComposerField' -import { MobileNativeChatComposerAttachments } from './native-chat/composer/MobileNativeChatComposerAttachments' -import type { PendingNativeChatFile } from './native-chat/composer/mobile-native-chat-file-attachment' -import { ActionSheetModal } from '../components/ActionSheetModal' -import { mobileNativeChatAttachActions } from './mobile-native-chat-attach-actions' +import { MobileNativeChatComposerAttachments } from './MobileNativeChatComposerAttachments' +import type { PendingNativeChatFile } from './mobile-native-chat-file-attachment' +import { ActionSheetModal } from '../../../components/ActionSheetModal' +import { mobileNativeChatAttachActions } from '../../mobile-native-chat-attach-actions' import { MobileNativeChatSessionOptionPickers, type MobileNativeChatPickerPresentation, type MobileNativeChatSessionOptionPickersProps -} from './MobileNativeChatSessionOptionPickers' -import type { PendingNativeChatImage } from './native-chat/composer/mobile-native-chat-image-attachment' +} from '../../MobileNativeChatSessionOptionPickers' +import type { PendingNativeChatImage } from './mobile-native-chat-image-attachment' import type { MobileComposerStructuredCatalog } from './mobile-native-chat-composer-menu' import { useMobileNativeChatComposerMenu } from './use-mobile-native-chat-composer-menu' -import { keepHeldPressThroughLongPress } from './held-press-long-press' +import { keepHeldPressThroughLongPress } from '../../held-press-long-press' import { mobileNativeChatComposerShowsStop } from './mobile-native-chat-composer-layout' -import { MobileNativeChatStopButton } from './MobileNativeChatStopButton' +import { MobileNativeChatStopButton } from '../../MobileNativeChatStopButton' import { mobileNativeChatComposerStyles as styles } from './mobile-native-chat-composer-styles' const NO_FILE_PATHS: string[] = [] diff --git a/mobile/src/session/MobileNativeChatComposerField.tsx b/mobile/src/session/native-chat/composer/MobileNativeChatComposerField.tsx similarity index 100% rename from mobile/src/session/MobileNativeChatComposerField.tsx rename to mobile/src/session/native-chat/composer/MobileNativeChatComposerField.tsx diff --git a/mobile/src/session/MobileNativeChatComposerField.web.tsx b/mobile/src/session/native-chat/composer/MobileNativeChatComposerField.web.tsx similarity index 97% rename from mobile/src/session/MobileNativeChatComposerField.web.tsx rename to mobile/src/session/native-chat/composer/MobileNativeChatComposerField.web.tsx index f83ae1f80bb..640a1db4260 100644 --- a/mobile/src/session/MobileNativeChatComposerField.web.tsx +++ b/mobile/src/session/native-chat/composer/MobileNativeChatComposerField.web.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' import { StyleSheet, Text, TextInput, View } from 'react-native' -import { colors } from '../theme/mobile-theme' +import { colors } from '../../../theme/mobile-theme' import { mobileNativeChatInputStyles as inputStyles } from './mobile-native-chat-input-styles' import { mobileNativeChatComposerSkillStyles as skillStyles, diff --git a/mobile/src/session/MobileNativeChatComposerMenu.tsx b/mobile/src/session/native-chat/composer/MobileNativeChatComposerMenu.tsx similarity index 95% rename from mobile/src/session/MobileNativeChatComposerMenu.tsx rename to mobile/src/session/native-chat/composer/MobileNativeChatComposerMenu.tsx index 8a1092f5adb..81123d29ed0 100644 --- a/mobile/src/session/MobileNativeChatComposerMenu.tsx +++ b/mobile/src/session/native-chat/composer/MobileNativeChatComposerMenu.tsx @@ -1,7 +1,7 @@ import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' import { FileText, Package, Terminal } from 'lucide-react-native' -import type { NativeChatPickerItem } from '../../../src/shared/native-chat-picker-items' -import { colors, spacing, typography } from '../theme/mobile-theme' +import type { NativeChatPickerItem } from '../../../../../src/shared/native-chat-picker-items' +import { colors, spacing, typography } from '../../../theme/mobile-theme' export type ComposerMenuRow = NativeChatPickerItem | { kind: 'file'; id: string; path: string } diff --git a/mobile/src/session/mobile-native-chat-autocomplete.test.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.test.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-autocomplete.test.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.test.ts diff --git a/mobile/src/session/mobile-native-chat-autocomplete.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-autocomplete.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-autocomplete.ts diff --git a/mobile/src/session/mobile-native-chat-composer-field-skill.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-field-skill.ts similarity index 91% rename from mobile/src/session/mobile-native-chat-composer-field-skill.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-composer-field-skill.ts index 4a0e97a9917..2cf98f9a2c0 100644 --- a/mobile/src/session/mobile-native-chat-composer-field-skill.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-field-skill.ts @@ -1,5 +1,5 @@ import { StyleSheet, type TextInput, type TextInputProps } from 'react-native' -import { colors } from '../theme/mobile-theme' +import { colors } from '../../../theme/mobile-theme' export type MobileNativeChatComposerFieldProps = Omit< TextInputProps, diff --git a/mobile/src/session/mobile-native-chat-composer-layout.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-layout.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-composer-layout.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-composer-layout.ts diff --git a/mobile/src/session/mobile-native-chat-composer-menu.test.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-menu.test.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-composer-menu.test.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-composer-menu.test.ts diff --git a/mobile/src/session/mobile-native-chat-composer-menu.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-menu.ts similarity index 79% rename from mobile/src/session/mobile-native-chat-composer-menu.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-composer-menu.ts index b26e0d1f65c..c54089e7a7f 100644 --- a/mobile/src/session/mobile-native-chat-composer-menu.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-menu.ts @@ -1,13 +1,13 @@ -import type { AgentSessionConversationCommand } from '../../../src/shared/agent-session/agent-session-conversation-command' -import type { AgentSessionSlashCommand } from '../../../src/shared/agent-session-wire' -import { getNativeChatAgentProfile } from '../../../src/shared/native-chat-agent-profiles' +import type { AgentSessionConversationCommand } from '../../../../../src/shared/agent-session/agent-session-conversation-command' +import type { AgentSessionSlashCommand } from '../../../../../src/shared/agent-session-wire' +import { getNativeChatAgentProfile } from '../../../../../src/shared/native-chat-agent-profiles' import { buildNativeChatPickerItems, type NativeChatPickerItem -} from '../../../src/shared/native-chat-picker-items' -import { sessionReportedSkills } from '../../../src/shared/native-chat-slash-commands' -import { structuredSessionSlashCommands } from '../../../src/shared/structured-agent-session-composer' -import { getMobileNativeChatCommands } from './native-chat/mobile-native-chat-send-classification' +} from '../../../../../src/shared/native-chat-picker-items' +import { sessionReportedSkills } from '../../../../../src/shared/native-chat-slash-commands' +import { structuredSessionSlashCommands } from '../../../../../src/shared/structured-agent-session-composer' +import { getMobileNativeChatCommands } from '../mobile-native-chat-send-classification' // Why: the menu is a plain ScrollView right above a streaming transcript, so it mounts a bounded // number of rows; typing narrows the rest. diff --git a/mobile/src/session/mobile-native-chat-composer-styles.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-styles.ts similarity index 95% rename from mobile/src/session/mobile-native-chat-composer-styles.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-composer-styles.ts index e95bebaa83c..3d1621a6bf3 100644 --- a/mobile/src/session/mobile-native-chat-composer-styles.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-composer-styles.ts @@ -1,5 +1,5 @@ import { StyleSheet } from 'react-native' -import { colors, radii, spacing } from '../theme/mobile-theme' +import { colors, radii, spacing } from '../../../theme/mobile-theme' /** Round controls on the action row: the attach button, the mic and Send/Stop. */ const COMPOSER_CONTROL_SIZE = 38 diff --git a/mobile/src/session/mobile-native-chat-draft-reconcile.test.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.test.ts similarity index 98% rename from mobile/src/session/mobile-native-chat-draft-reconcile.test.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.test.ts index eeaba0f280e..c36c23940e4 100644 --- a/mobile/src/session/mobile-native-chat-draft-reconcile.test.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' import { findLandedImagePreviewEchoes, findLandedUnconfirmedSends, diff --git a/mobile/src/session/mobile-native-chat-draft-reconcile.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.ts similarity index 97% rename from mobile/src/session/mobile-native-chat-draft-reconcile.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.ts index 9b034b0b034..c673f239919 100644 --- a/mobile/src/session/mobile-native-chat-draft-reconcile.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.ts @@ -1,11 +1,14 @@ -import { isImageRefBlock, type NativeChatMessage } from '../../../src/shared/native-chat-types' +import { + isImageRefBlock, + type NativeChatMessage +} from '../../../../../src/shared/native-chat-types' import { hasImagePromptMarker, isImageSourceUserTurn, normalizeImageTranscriptMessages, normalizeNativeChatUserText, normalizedNativeChatUserMessageText -} from '../../../src/shared/native-chat-image-transcript-markers' +} from '../../../../../src/shared/native-chat-image-transcript-markers' export type UnconfirmedSend = { draftKey: string diff --git a/mobile/src/session/mobile-native-chat-draft-store.test.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-store.test.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-draft-store.test.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-draft-store.test.ts diff --git a/mobile/src/session/mobile-native-chat-draft-store.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-draft-store.ts similarity index 100% rename from mobile/src/session/mobile-native-chat-draft-store.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-draft-store.ts diff --git a/mobile/src/session/mobile-native-chat-input-base-styles.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-input-base-styles.ts similarity index 90% rename from mobile/src/session/mobile-native-chat-input-base-styles.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-input-base-styles.ts index d40252b2590..2861529d272 100644 --- a/mobile/src/session/mobile-native-chat-input-base-styles.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-input-base-styles.ts @@ -1,4 +1,4 @@ -import { colors, radii, spacing } from '../theme/mobile-theme' +import { colors, radii, spacing } from '../../../theme/mobile-theme' // Keep platform-neutral styles separate because a web sibling cannot import the file it shadows. const chatInputSurface = { diff --git a/mobile/src/session/mobile-native-chat-input-styles.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.ts similarity index 90% rename from mobile/src/session/mobile-native-chat-input-styles.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.ts index 8eed012e537..9e047d9f70f 100644 --- a/mobile/src/session/mobile-native-chat-input-styles.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.ts @@ -1,5 +1,5 @@ import { StyleSheet } from 'react-native' -import { typography } from '../theme/mobile-theme' +import { typography } from '../../../theme/mobile-theme' import { mobileNativeChatInputBase } from './mobile-native-chat-input-base-styles' // Native sizes need no zoom guard; the web sibling applies the iOS focus-zoom floor. diff --git a/mobile/src/session/mobile-native-chat-input-styles.web.ts b/mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.web.ts similarity index 85% rename from mobile/src/session/mobile-native-chat-input-styles.web.ts rename to mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.web.ts index 5fe06ddbb6b..89e84549037 100644 --- a/mobile/src/session/mobile-native-chat-input-styles.web.ts +++ b/mobile/src/session/native-chat/composer/mobile-native-chat-input-styles.web.ts @@ -1,5 +1,5 @@ import { StyleSheet } from 'react-native' -import { TEXT_INPUT_FONT_SIZE } from '../platform/text-input-font-size' +import { TEXT_INPUT_FONT_SIZE } from '../../../platform/text-input-font-size' import { mobileNativeChatInputBase } from './mobile-native-chat-input-base-styles' // Keep inputs at the focus-zoom floor: iOS zoom would make keyboard geometry return zero for the rest of typing. diff --git a/mobile/src/session/use-mobile-native-chat-composer-menu.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-menu.ts similarity index 100% rename from mobile/src/session/use-mobile-native-chat-composer-menu.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-menu.ts diff --git a/mobile/src/session/use-mobile-native-chat-composer-tray.test.tsx b/mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.test.tsx similarity index 88% rename from mobile/src/session/use-mobile-native-chat-composer-tray.test.tsx rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.test.tsx index 57d7c7ed3bf..50ef795866d 100644 --- a/mobile/src/session/use-mobile-native-chat-composer-tray.test.tsx +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.test.tsx @@ -3,12 +3,12 @@ import { createElement } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, describe, expect, it, vi } from 'vitest' -import type { AgentChildWorkView } from '../../../src/shared/agent-status-child-work-view' -import type { AgentSessionBackgroundTaskState } from '../../../src/shared/agent-session-wire' -import { agentChildRowContextForSessionStream } from '../../../src/shared/agent-child-row-stream-context' -import { structuredSessionBackgroundTasksView } from '../../../src/shared/structured-session-background-tasks-view' +import type { AgentChildWorkView } from '../../../../../src/shared/agent-status-child-work-view' +import type { AgentSessionBackgroundTaskState } from '../../../../../src/shared/agent-session-wire' +import { agentChildRowContextForSessionStream } from '../../../../../src/shared/agent-child-row-stream-context' +import { structuredSessionBackgroundTasksView } from '../../../../../src/shared/structured-session-background-tasks-view' import { useMobileNativeChatComposerTray } from './use-mobile-native-chat-composer-tray' -import type { MobileStructuredBackgroundTasks } from './use-mobile-structured-background-tasks' +import type { MobileStructuredBackgroundTasks } from '../../use-mobile-structured-background-tasks' vi.mock('react-native', () => ({ Dimensions: { get: () => ({ width: 430, height: 900 }) }, @@ -38,12 +38,12 @@ vi.mock('lucide-react-native', () => ({ Trash2: 'Trash2' })) -vi.mock('../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) -vi.mock('../components/AgentStateDot', () => ({ +vi.mock('../../../components/ActionSheetModal', () => ({ ActionSheetModal: 'ActionSheetModal' })) +vi.mock('../../../components/AgentStateDot', () => ({ AGENT_WORKING_COLOR: '#eab308', AgentStateDot: 'AgentStateDot' })) -vi.mock('../hooks/use-now', () => ({ useNow: () => 100_000 })) +vi.mock('../../../hooks/use-now', () => ({ useNow: () => 100_000 })) const CARD = { messageId: 'waiting-1', diff --git a/mobile/src/session/use-mobile-native-chat-composer-tray.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.ts similarity index 86% rename from mobile/src/session/use-mobile-native-chat-composer-tray.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.ts index ef972566c5f..a3541ecb55b 100644 --- a/mobile/src/session/use-mobile-native-chat-composer-tray.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-composer-tray.ts @@ -1,12 +1,12 @@ import { createElement, Fragment, useMemo, type ReactNode, type RefObject } from 'react' import type { TextInput } from 'react-native' -import { MobileNativeChatBackgroundTasks } from './MobileNativeChatBackgroundTasks' +import { MobileNativeChatBackgroundTasks } from '../../MobileNativeChatBackgroundTasks' import { MobileNativeChatQueuedMessages, type MobileNativeChatQueuedMessagesProps -} from './MobileNativeChatQueuedMessages' -import type { MobileStructuredBackgroundTasks } from './use-mobile-structured-background-tasks' -import { useMobileNativeChatQueuedEditFocus } from './use-mobile-native-chat-queued-edit-focus' +} from '../../MobileNativeChatQueuedMessages' +import type { MobileStructuredBackgroundTasks } from '../../use-mobile-structured-background-tasks' +import { useMobileNativeChatQueuedEditFocus } from '../../use-mobile-native-chat-queued-edit-focus' export type MobileNativeChatComposerTray = { content?: ReactNode diff --git a/mobile/src/session/use-mobile-native-chat-drafts-glued-pending.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-glued-pending.test.ts similarity index 98% rename from mobile/src/session/use-mobile-native-chat-drafts-glued-pending.test.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-glued-pending.test.ts index 3bdbb5a91cd..55211d654da 100644 --- a/mobile/src/session/use-mobile-native-chat-drafts-glued-pending.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-glued-pending.test.ts @@ -1,8 +1,8 @@ import { createElement } from 'react' import { act, create } from 'react-test-renderer' import { afterEach, describe, expect, it } from 'vitest' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' -import { buildMobileNativeChatTransientData } from './mobile-native-chat-render-data' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' +import { buildMobileNativeChatTransientData } from '../../mobile-native-chat-render-data' import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' import { resetMobileNativeChatDraftStoreForTests } from './mobile-native-chat-draft-store' diff --git a/mobile/src/session/use-mobile-native-chat-drafts-launch-draft.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-launch-draft.test.ts similarity index 98% rename from mobile/src/session/use-mobile-native-chat-drafts-launch-draft.test.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-launch-draft.test.ts index 094da928f69..262ffa44855 100644 --- a/mobile/src/session/use-mobile-native-chat-drafts-launch-draft.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-launch-draft.test.ts @@ -1,8 +1,8 @@ import { createElement } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, describe, expect, it } from 'vitest' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' -import { projectStructuredAgentSessionMessages } from '../../../src/shared/structured-agent-session-message-projection' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' +import { projectStructuredAgentSessionMessages } from '../../../../../src/shared/structured-agent-session-message-projection' import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' import { resetMobileNativeChatDraftStoreForTests } from './mobile-native-chat-draft-store' diff --git a/mobile/src/session/use-mobile-native-chat-drafts-queued-hold.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-queued-hold.test.ts similarity index 100% rename from mobile/src/session/use-mobile-native-chat-drafts-queued-hold.test.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-queued-hold.test.ts diff --git a/mobile/src/session/use-mobile-native-chat-drafts.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.test.ts similarity index 99% rename from mobile/src/session/use-mobile-native-chat-drafts.test.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.test.ts index 3b3546adabc..7eb687ecdb1 100644 --- a/mobile/src/session/use-mobile-native-chat-drafts.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.test.ts @@ -1,7 +1,7 @@ import { createElement } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, describe, expect, it, vi } from 'vitest' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' import { resetMobileNativeChatDraftStoreForTests } from './mobile-native-chat-draft-store' diff --git a/mobile/src/session/use-mobile-native-chat-drafts.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts similarity index 92% rename from mobile/src/session/use-mobile-native-chat-drafts.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts index 1201fd12fd2..b81f513506c 100644 --- a/mobile/src/session/use-mobile-native-chat-drafts.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts @@ -1,16 +1,16 @@ import { useCallback, useEffect, useRef, useState, type Dispatch, type SetStateAction } from 'react' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' -import { appendReturnedDraftText } from '../../../src/shared/returned-draft-text' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' +import { appendReturnedDraftText } from '../../../../../src/shared/returned-draft-text' import { countUserTextOccurrences, findLandedImagePreviewEchoes, mergeSentImagePreviews, migrateImagePreviewMessageIds } from './mobile-native-chat-draft-reconcile' -import { normalizeNativeChatUserText as normalizeReconcileText } from '../../../src/shared/native-chat-image-transcript-markers' -import { useMobileNativeChatUnconfirmedSends } from './native-chat/use-mobile-native-chat-unconfirmed-sends' -import { rebaseMobileNativeChatPendingBaselines } from './mobile-native-chat-pending-baseline' -import { retireLandedMobileNativeChatPending } from './native-chat/mobile-native-chat-pending-retirement' +import { normalizeNativeChatUserText as normalizeReconcileText } from '../../../../../src/shared/native-chat-image-transcript-markers' +import { useMobileNativeChatUnconfirmedSends } from '../use-mobile-native-chat-unconfirmed-sends' +import { rebaseMobileNativeChatPendingBaselines } from '../../mobile-native-chat-pending-baseline' +import { retireLandedMobileNativeChatPending } from '../mobile-native-chat-pending-retirement' import { appendMobileNativeChatPending, combineMobileNativeChatPending, @@ -18,8 +18,8 @@ import { removeWaitingSessionPending, type MobileNativeChatPendingMessage, type MobileNativeChatSendOrigin -} from './native-chat/mobile-native-chat-pending-echo' -import { mobileNativeChatScopeKey } from './native-chat/mobile-native-chat-scope-key' +} from '../mobile-native-chat-pending-echo' +import { mobileNativeChatScopeKey } from '../mobile-native-chat-scope-key' import { useMobileNativeChatLaunchDraftSeed } from './use-mobile-native-chat-launch-draft-seed' import type { MobileNativeChatLaunchDraftSeed } from './use-mobile-native-chat-launch-draft-seed' import { @@ -30,8 +30,6 @@ import { useMobileNativeChatDraft } from './mobile-native-chat-draft-store' -export type { MobileNativeChatPendingMessage, MobileNativeChatSendOrigin } - const NO_PENDING_MESSAGES: MobileNativeChatPendingMessage[] = [] const NO_IMAGE_PREVIEWS: Record = {} diff --git a/mobile/src/session/native-chat/composer/use-mobile-native-chat-file-search.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-file-search.ts index 5c6565c1263..72188514d22 100644 --- a/mobile/src/session/native-chat/composer/use-mobile-native-chat-file-search.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-file-search.ts @@ -8,7 +8,7 @@ import { nativeChatFileInventoryRead, nativeChatFileSearchRead } from '../../mobile-session-read-operations' -import { rankSuggestions } from '../../mobile-native-chat-autocomplete' +import { rankSuggestions } from './mobile-native-chat-autocomplete' const FILE_SEARCH_DEBOUNCE_MS = 120 const FILE_SEARCH_RESULT_LIMIT = 16 diff --git a/mobile/src/session/use-mobile-native-chat-launch-draft-seed.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-launch-draft-seed.ts similarity index 97% rename from mobile/src/session/use-mobile-native-chat-launch-draft-seed.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-launch-draft-seed.ts index 0b8bcd8a58a..4151e1f7f50 100644 --- a/mobile/src/session/use-mobile-native-chat-launch-draft-seed.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-launch-draft-seed.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, type SetStateAction } from 'react' -import type { NativeChatMessage } from '../../../src/shared/native-chat-types' +import type { NativeChatMessage } from '../../../../../src/shared/native-chat-types' import { normalizedUserText } from './mobile-native-chat-draft-reconcile' import { mobileNativeChatLaunchDraftSeeds } from './mobile-native-chat-draft-store' diff --git a/mobile/src/session/use-mobile-native-chat-message-send-draft-lifetime.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-message-send-draft-lifetime.test.ts similarity index 96% rename from mobile/src/session/use-mobile-native-chat-message-send-draft-lifetime.test.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-message-send-draft-lifetime.test.ts index 6fa32dab062..eb115667c91 100644 --- a/mobile/src/session/use-mobile-native-chat-message-send-draft-lifetime.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-message-send-draft-lifetime.test.ts @@ -1,7 +1,7 @@ import { createElement } from 'react' import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, describe, expect, it, vi } from 'vitest' -import type { RpcClient } from '../transport/rpc-client' +import type { RpcClient } from '../../../transport/rpc-client' const transport = vi.hoisted(() => ({ heal: vi.fn<() => Promise>(), @@ -11,10 +11,10 @@ const transport = vi.hoisted(() => ({ error: vi.fn() })) -vi.mock('./native-chat/mobile-native-chat-stale-input', () => ({ +vi.mock('../mobile-native-chat-stale-input', () => ({ healMobileNativeChatStaleInput: transport.heal })) -vi.mock('./native-chat/mobile-native-chat-send', () => ({ +vi.mock('../mobile-native-chat-send', () => ({ healMobileNativeChatStaleInput: transport.heal, clearMobileNativeChatInput: transport.clearInput, sendMobileNativeChatMessageWithOutcome: transport.send, @@ -25,7 +25,7 @@ vi.mock('./native-chat/mobile-native-chat-send', () => ({ })) import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' -import { useMobileNativeChatMessageSend } from './use-mobile-native-chat-message-send' +import { useMobileNativeChatMessageSend } from '../../use-mobile-native-chat-message-send' import { resetMobileNativeChatDraftStoreForTests } from './mobile-native-chat-draft-store' function deferred() { diff --git a/mobile/src/session/use-mobile-native-chat-structured-composer.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-structured-composer.ts similarity index 80% rename from mobile/src/session/use-mobile-native-chat-structured-composer.ts rename to mobile/src/session/native-chat/composer/use-mobile-native-chat-structured-composer.ts index 52238c2aba8..89b71d40c80 100644 --- a/mobile/src/session/use-mobile-native-chat-structured-composer.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-structured-composer.ts @@ -1,9 +1,9 @@ import { useMemo } from 'react' -import type { AgentSessionConversationCommand } from '../../../src/shared/agent-session/agent-session-conversation-command' -import type { RpcClient } from '../transport/rpc-client' +import type { AgentSessionConversationCommand } from '../../../../../src/shared/agent-session/agent-session-conversation-command' +import type { RpcClient } from '../../../transport/rpc-client' import type { MobileNativeChatStructuredComposer } from './MobileNativeChatComposer' -import type { MobileNativeChatFileAttachments } from './native-chat/composer/use-mobile-native-chat-file-attachments' -import { useMobileStructuredSessionCommands } from './use-mobile-structured-session-commands' +import type { MobileNativeChatFileAttachments } from './use-mobile-native-chat-file-attachments' +import { useMobileStructuredSessionCommands } from '../../use-mobile-structured-session-commands' const NO_COMMANDS: readonly AgentSessionConversationCommand[] = [] diff --git a/mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts b/mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts index 37af5c96337..5b4c931af2d 100644 --- a/mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts +++ b/mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import type { NativeChatMessage } from '../../../../src/shared/native-chat-types' -import { countUserTextOccurrences } from '../mobile-native-chat-draft-reconcile' +import { countUserTextOccurrences } from './composer/mobile-native-chat-draft-reconcile' import { normalizeNativeChatUserText as normalizeReconcileText } from '../../../../src/shared/native-chat-image-transcript-markers' import { appendMobileNativeChatPending, diff --git a/mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts b/mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts index 88b3e242496..a34b1b039e7 100644 --- a/mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts +++ b/mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts @@ -3,7 +3,7 @@ import type { NativeChatMessage } from '../../../../src/shared/native-chat-types import { countImageSourceTurnsAfter, normalizedUserText -} from '../mobile-native-chat-draft-reconcile' +} from './composer/mobile-native-chat-draft-reconcile' import { normalizeNativeChatUserText as normalizeReconcileText } from '../../../../src/shared/native-chat-image-transcript-markers' import type { MobileNativeChatPendingMessage } from './mobile-native-chat-pending-echo' diff --git a/mobile/src/session/native-chat/use-mobile-native-chat-unconfirmed-sends.ts b/mobile/src/session/native-chat/use-mobile-native-chat-unconfirmed-sends.ts index fbe878e3073..81782596159 100644 --- a/mobile/src/session/native-chat/use-mobile-native-chat-unconfirmed-sends.ts +++ b/mobile/src/session/native-chat/use-mobile-native-chat-unconfirmed-sends.ts @@ -5,7 +5,7 @@ import type { NativeChatMessage } from '../../../../src/shared/native-chat-types import { findLandedUnconfirmedSends, type UnconfirmedSend -} from '../mobile-native-chat-draft-reconcile' +} from './composer/mobile-native-chat-draft-reconcile' import type { MobileNativeChatSendOrigin } from './mobile-native-chat-pending-echo' export const UNCONFIRMED_SEND_DEADLINE_MS = 20_000 diff --git a/mobile/src/session/use-mobile-native-chat-controller.test.ts b/mobile/src/session/use-mobile-native-chat-controller.test.ts index e98921c7dd9..5473ebc672f 100644 --- a/mobile/src/session/use-mobile-native-chat-controller.test.ts +++ b/mobile/src/session/use-mobile-native-chat-controller.test.ts @@ -104,7 +104,7 @@ vi.mock('./use-mobile-structured-agent-session', () => ({ invokeStructuredOption: structuredInvokeOption }) })) -vi.mock('./use-mobile-native-chat-drafts', () => ({ +vi.mock('./native-chat/composer/use-mobile-native-chat-drafts', () => ({ useMobileNativeChatDrafts: () => { return { composerText: '', diff --git a/mobile/src/session/use-mobile-native-chat-controller.ts b/mobile/src/session/use-mobile-native-chat-controller.ts index fd99a2fb3af..158ec1a0e6b 100644 --- a/mobile/src/session/use-mobile-native-chat-controller.ts +++ b/mobile/src/session/use-mobile-native-chat-controller.ts @@ -4,7 +4,7 @@ import type { ConnectionState } from '../transport/types' import type { MobileNativeChatTab } from './native-chat/mobile-native-chat-eligibility' import type { StructuredAgentSessionHostSupport } from './mobile-structured-agent-session-host-support' import { useMobileNativeChatAskDismiss } from './use-mobile-native-chat-ask-dismiss' -import { useMobileNativeChatDrafts } from './use-mobile-native-chat-drafts' +import { useMobileNativeChatDrafts } from './native-chat/composer/use-mobile-native-chat-drafts' import { useMobileNativeChatFileSearch } from './native-chat/composer/use-mobile-native-chat-file-search' import { useMobileNativeChatMessageSend } from './use-mobile-native-chat-message-send' import { mobileNativeChatStreamPreview } from './native-chat/mobile-native-chat-streaming-gate' diff --git a/mobile/src/session/use-mobile-native-chat-message-send.ts b/mobile/src/session/use-mobile-native-chat-message-send.ts index 71b1f641497..eea13a11580 100644 --- a/mobile/src/session/use-mobile-native-chat-message-send.ts +++ b/mobile/src/session/use-mobile-native-chat-message-send.ts @@ -15,9 +15,9 @@ import { acquireMobileNativeChatTerminalWrite, releaseMobileNativeChatTerminalWrite } from './native-chat/mobile-native-chat-terminal-write-lock' -import type { MobileNativeChatSendOrigin } from './use-mobile-native-chat-drafts' +import type { MobileNativeChatSendOrigin } from './native-chat/mobile-native-chat-pending-echo' import { UNCONFIRMED_SEND_MESSAGE } from './native-chat/use-mobile-native-chat-unconfirmed-sends' -import type { MobileNativeChatLaunchDraftSeed } from './use-mobile-native-chat-launch-draft-seed' +import type { MobileNativeChatLaunchDraftSeed } from './native-chat/composer/use-mobile-native-chat-launch-draft-seed' import { AGENT_TUI_CLEAR_INPUT_LINE, buildAgentTuiClearInputForText diff --git a/mobile/src/session/use-mobile-session-attachments.ts b/mobile/src/session/use-mobile-session-attachments.ts index 7d6aef9a00a..2e5bb595243 100644 --- a/mobile/src/session/use-mobile-session-attachments.ts +++ b/mobile/src/session/use-mobile-session-attachments.ts @@ -5,7 +5,7 @@ import { triggerSelection, triggerError } from '../platform/haptics' import { resolveMobileImageAttachmentAgent } from './mobile-image-paste-agent' import { useMobileNewTabAgentOptions } from './use-mobile-new-tab-agent-options' import { useMobileSessionImageAttachments } from './use-mobile-session-image-attachments' -import { useMobileNativeChatStructuredComposer } from './use-mobile-native-chat-structured-composer' +import { useMobileNativeChatStructuredComposer } from './native-chat/composer/use-mobile-native-chat-structured-composer' import { isMobileNativeChatAgentConfirmed, resolveMobileNativeChatSessionId diff --git a/mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts b/mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts index b143a0dcc0c..9308c823375 100644 --- a/mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts +++ b/mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts @@ -3,7 +3,7 @@ import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { StructuredAgentId } from '../../../src/shared/agent-session-provider-handle' import type { MobileNativeChatSendOutcome } from './native-chat/mobile-native-chat-send' -import type { MobileNativeChatSendOrigin } from './use-mobile-native-chat-drafts' +import type { MobileNativeChatSendOrigin } from './native-chat/mobile-native-chat-pending-echo' import { useMobileStructuredNativeChatSendBridge } from './use-mobile-structured-native-chat-send-bridge' const ORIGIN: MobileNativeChatSendOrigin = { diff --git a/mobile/src/session/use-mobile-structured-native-chat-send-bridge.ts b/mobile/src/session/use-mobile-structured-native-chat-send-bridge.ts index 81a3b9dd162..6609fdfa9af 100644 --- a/mobile/src/session/use-mobile-structured-native-chat-send-bridge.ts +++ b/mobile/src/session/use-mobile-structured-native-chat-send-bridge.ts @@ -2,7 +2,7 @@ import { useCallback } from 'react' import type { StructuredAgentId } from '../../../src/shared/agent-session-provider-handle' import { isStructuredAgentSessionComposerCommand } from '../../../src/shared/structured-agent-session-composer' import type { MobileNativeChatSendOutcome } from './native-chat/mobile-native-chat-send' -import type { MobileNativeChatSendOrigin } from './use-mobile-native-chat-drafts' +import type { MobileNativeChatSendOrigin } from './native-chat/mobile-native-chat-pending-echo' import type { StructuredMobileSendAttachment } from './use-mobile-structured-send-with-outcome' export function useMobileStructuredNativeChatSendBridge(args: { diff --git a/mobile/src/session/use-mobile-structured-sends.ts b/mobile/src/session/use-mobile-structured-sends.ts index f2d4ec9e31b..fa0e7877c6c 100644 --- a/mobile/src/session/use-mobile-structured-sends.ts +++ b/mobile/src/session/use-mobile-structured-sends.ts @@ -11,7 +11,7 @@ import { structuredAgentSessionReadCoversSend, structuredAgentSessionSettledSends } from '../../../src/shared/structured-agent-session-send-settlement' -import { mergeSentImagePreviews } from './mobile-native-chat-draft-reconcile' +import { mergeSentImagePreviews } from './native-chat/composer/mobile-native-chat-draft-reconcile' import type { MobileQueuedMessageFeed } from './mobile-structured-queued-message-feed' import type { MobileNativeChatSendErrorReporter } from './native-chat/use-mobile-native-chat-send-error' import { diff --git a/mobile/web-entry/web-overrides.json b/mobile/web-entry/web-overrides.json index 21131bb3567..5a1cf6dce39 100644 --- a/mobile/web-entry/web-overrides.json +++ b/mobile/web-entry/web-overrides.json @@ -118,11 +118,11 @@ "reason": "Not an RN Web API gap but a transport one that exists only in the page. A terminal's first frame is its scrollback snapshot, which the desktop trims to 512 KiB of raw terminal text while the bridge measures the serialized event against BRIDGE_MAX_MESSAGE_BYTES. An ANSI snapshot is mostly ESC bytes and JSON spends six on each, so a colour-dense 80-column screen comes back at 669,268 bytes against a 655,360-byte cap and the stream ends with overflow before a live byte is painted. This file derives the budget the page sends in terminal.subscribe from the cap less the event envelope; the native sibling sends nothing, because a socket frame has no ceiling above it and a budget there would shrink a phone's scrollback for a limit that does not exist." }, { - "file": "src/session/MobileNativeChatComposerField.web.tsx", + "file": "src/session/native-chat/composer/MobileNativeChatComposerField.web.tsx", "reason": "A picked skill leads the composer's draft and is drawn highlighted in place. Natively that is a styled span of the TextInput's own text, but react-native-web renders TextInput as a textarea, which cannot style part of its text and ignores Text children. This one draws a copy of the draft behind the field with the skill highlighted, clears the field's own text while keeping its caret, and moves the copy with the field's scroll." }, { - "file": "src/session/mobile-native-chat-input-styles.web.ts", + "file": "src/session/native-chat/composer/mobile-native-chat-input-styles.web.ts", "reason": "The chat's composer and its question field render one point above the app's body size, which is 15 and under the floor below which iOS zooms the page on focus. keyboard-occlusion.web.ts reads a scale other than 1 as 'no keyboard' and answers 0, and on this screen that lift is the terminal's only feedback that its hidden input has focus, so one focus of the composer would cost the rest of the session. This file puts both fields on TEXT_INPUT_FONT_SIZE; the native sibling keeps the question field at 15 and the composer at 16." }, {