mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
refactor(mobile): colocate native chat composer and drafts (#33922)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -14,7 +14,7 @@ if (!baseline) {
|
||||
'Usage: node config/scripts/mobile-file-ranking-benchmark.mjs <baseline-ref|--autocomplete-stdin>'
|
||||
)
|
||||
}
|
||||
// git show <ref>:mobile/src/session/mobile-native-chat-autocomplete.ts | node config/scripts/mobile-file-ranking-benchmark.mjs --autocomplete-stdin
|
||||
// git show <ref>: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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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: () => ''
|
||||
}))
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
})
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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' }))
|
||||
|
||||
@@ -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: () => ({})
|
||||
}))
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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' }))
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-2
@@ -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
|
||||
}))
|
||||
|
||||
+9
-4
@@ -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
|
||||
}))
|
||||
|
||||
+10
-10
@@ -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[] = []
|
||||
+1
-1
@@ -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,
|
||||
+2
-2
@@ -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 }
|
||||
|
||||
+1
-1
@@ -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,
|
||||
+7
-7
@@ -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.
|
||||
+1
-1
@@ -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
|
||||
+1
-1
@@ -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,
|
||||
+5
-2
@@ -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
|
||||
+1
-1
@@ -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 = {
|
||||
+1
-1
@@ -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.
|
||||
+1
-1
@@ -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.
|
||||
+8
-8
@@ -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',
|
||||
+4
-4
@@ -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
|
||||
+2
-2
@@ -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'
|
||||
|
||||
+2
-2
@@ -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'
|
||||
|
||||
+1
-1
@@ -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'
|
||||
|
||||
+8
-10
@@ -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<string, string[]> = {}
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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'
|
||||
|
||||
+4
-4
@@ -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<boolean>>(),
|
||||
@@ -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<T>() {
|
||||
+4
-4
@@ -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[] = []
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: '',
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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."
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user