Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
ba0681b
fix(native-chat): a refused queued message still blocks the queue whe…
brennanb2025 Oct 18, 2026
e42b90d
refactor(native-chat): keep each queued message in the chat's journal…
brennanb2025 Oct 19, 2026
4daf94e
test(native-chat): adapt the queue tests to cards kept in the journal
brennanb2025 Oct 19, 2026
62a0bcf
test(native-chat): a refused card holds the queue through rewind, a n…
brennanb2025 Oct 19, 2026
4db1581
test(native-chat): an earlier build's queued cards move into the jour…
brennanb2025 Oct 19, 2026
6d22d29
test(native-chat): adapt typechecked tests to cards kept in the journal
brennanb2025 Oct 19, 2026
a89bca3
refactor(native-chat): drop the journal row writer's unused transacti…
brennanb2025 Oct 19, 2026
627e8a3
test(native-chat): downgrade probes write rows at the version older b…
brennanb2025 Oct 19, 2026
9e535d9
test(native-chat): unit tests follow the queue row's version 4
brennanb2025 Oct 19, 2026
db68669
fix(native-chat): one batch echoing two refused queued messages spend…
brennanb2025 Oct 19, 2026
0d31aca
fix(native-chat): a rewind moves an earlier build's cards into the jo…
brennanb2025 Oct 19, 2026
e096d5f
fix(native-chat): keep an earlier build's card whose hand-off is stil…
brennanb2025 Oct 19, 2026
6b66b65
Merge remote-tracking branch 'origin/main' into brennanb2025/send-lif…
brennanb2025 Oct 19, 2026
88c44a9
fix(native-chat): one delivery echo withdraws at most one queued card
brennanb2025 Oct 19, 2026
f4f9442
fix(native-chat): a queued message handed to the agent is sent again …
brennanb2025 Oct 19, 2026
8f84e49
fix(native-chat): Claude's report that it removed a queued message un…
brennanb2025 Oct 19, 2026
41a28fd
fix(native-chat): an earlier build's card stopped after hand-over fol…
brennanb2025 Oct 19, 2026
14c1a02
fix(native-chat): read a queued row's hand-off before the lookup that…
brennanb2025 Oct 19, 2026
ff11457
test(native-chat): a card steered into a turn a Stop ends stays sent …
brennanb2025 Oct 19, 2026
6b91762
Merge remote-tracking branch 'origin/main' into brennanb2025/send-lif…
brennanb2025 Oct 19, 2026
fb72fc8
fix(native-chat): a queued message stopped before Orca handed it to t…
brennanb2025 Oct 19, 2026
e19bd95
fix(native-chat): a queued message stopped while the agent prepares i…
brennanb2025 Oct 19, 2026
f60d1b3
Merge remote-tracking branch 'origin/main' into brennanb2025/send-lif…
brennanb2025 Oct 20, 2026
7f25a0d
test(native-chat): the usage-limit Continue backlog case writes its c…
brennanb2025 Oct 20, 2026
e9513f8
test(claude): the real-CLI queued Stop expects the unrun mark Claude'…
brennanb2025 Oct 20, 2026
e370d76
feat(mobile): edit a queued message's images on the phone: remove or …
brennanb2025 Oct 19, 2026
cff6f14
fix(mobile): gate queued image edits on the host reader verdict
brennanb2025 Oct 20, 2026
39174be
test(mobile): declare the upload fixture chat mode
brennanb2025 Oct 20, 2026
aeeec4b
Merge origin/main into the journal queue branch
brennanb2025 Oct 20, 2026
0512fff
Merge origin/main for the daemon backpressure test fix
brennanb2025 Oct 21, 2026
e9bfdaf
fix(native-chat): retain spent legacy messages when import fails
brennanb2025 Oct 21, 2026
730f28c
fix(mobile): reveal the full queued image editor on open
brennanb2025 Oct 21, 2026
7416b2d
fix(mobile): invalidate queued editor geometry without a render ref w…
brennanb2025 Oct 21, 2026
e14c1ec
refactor(chat): prepare composer drafts and measured queue dragging
brennanb2025 Oct 21, 2026
293bb82
Merge origin/main into queued message journal branch
brennanb2025 Oct 21, 2026
114433c
Merge remote-tracking branch 'origin/main' into brennanb2025/queued-e…
brennanb2025 Oct 22, 2026
a042724
Merge commit '293bb82544967f097081040cb21d7d55ce17636c' into brennanb…
brennanb2025 Oct 22, 2026
352724b
feat(native-chat): add conditional queue removal and authoritative re…
brennanb2025 Oct 22, 2026
925c441
feat(native-chat): move queued edits into the normal composer on desk…
brennanb2025 Oct 22, 2026
ef47118
Merge origin/main before landing
brennanb2025 Oct 22, 2026
d22d814
fix(native-chat): own complete phone drafts before authoring
brennanb2025 Oct 22, 2026
23fd859
fix: preserve submitted composer drafts across storage replacement
brennanb2025 Oct 22, 2026
a98a99d
fix composer validation and mobile CI diagnostics
brennanb2025 Oct 22, 2026
b0b6dc5
fix mobile composer test contracts and diagnostic output
brennanb2025 Oct 22, 2026
30e042e
Capture mobile test compiler diagnostics in CI
brennanb2025 Oct 22, 2026
d7e548a
Fix queued message contract typing and English strings
brennanb2025 Oct 22, 2026
0b530d6
test: complete queued extraction transport fixtures
brennanb2025 Oct 22, 2026
fc0feca
refactor: separate composer skill binding from send mutations
brennanb2025 Oct 22, 2026
b33ec92
Merge queued message journal dependency into composer branch
brennanb2025 Oct 22, 2026
d0abf28
Merge main and retain selected skills in checked phone sends
brennanb2025 Oct 22, 2026
a3ba0a9
fix(mobile): grant draft storage within route limits
brennanb2025 Oct 22, 2026
2f7d4f2
fix(native-chat): settle each draft save on its own and publish compl…
brennanb2025 Oct 23, 2026
7266024
Merge remote-tracking branch 'origin/main' into brennanb2025/queued-e…
brennanb2025 Oct 23, 2026
b979c86
fix(native-chat): import the draft type once in the draft cache
brennanb2025 Oct 23, 2026
042989f
test(mobile): type the held-write state without an assertion
brennanb2025 Oct 23, 2026
c691a01
test(native-chat): assert the handed-back file on Send without readin…
brennanb2025 Oct 23, 2026
a6a2657
test(mobile): pass main's agent-confirmed flag to the submitted-files…
brennanb2025 Oct 23, 2026
9a1a1f7
fix: reveal queued reorder grip on touch screens
brennanb2025 Oct 23, 2026
8af0fd8
fix: save reopened phone drafts and batch reorder measurements
brennanb2025 Oct 23, 2026
5bea4d5
Merge origin/main to integrate composer input updates
brennanb2025 Oct 23, 2026
4d2d8cb
test: use an explicit React module type
brennanb2025 Oct 23, 2026
09bc572
Preserve queued message sortable identities on unchanged renders
brennanb2025 Oct 23, 2026
caed289
Prevent stale queued drag completion after unmount
brennanb2025 Oct 23, 2026
5958f31
Merge main into queued composer editing
brennanb2025 Oct 24, 2026
9d5195b
fix(mobile): hand off navigation across session workspaces
brennanb2025 Oct 24, 2026
f31e786
Merge main into phone queued edit in place
brennanb2025 Oct 24, 2026
deef3cf
test(mobile): use resolved session identity in dictation fixture
brennanb2025 Oct 24, 2026
2131665
Merge main and relocate command result delegation
brennanb2025 Oct 24, 2026
ab3db4c
Merge main and replace the superseded queued edit implementation
brennanb2025 Oct 26, 2026
5b3f4a6
feat: edit queued messages inline with the chat composer
brennanb2025 Oct 26, 2026
48663e8
fix: normalize queued edit skill ownership
brennanb2025 Oct 26, 2026
5f06abd
fix: retire phone skill selections with the sent draft
brennanb2025 Oct 26, 2026
fd44faf
Merge main and resolve chat menu integration
brennanb2025 Oct 26, 2026
81f1549
fix: consolidate queued edit module imports
brennanb2025 Oct 26, 2026
b6ba975
fix: separate edit save action and stabilize image callbacks
brennanb2025 Oct 26, 2026
730e5a7
fix: complete phone inline composer integration
brennanb2025 Oct 26, 2026
824c6f8
fix: retain same-name queued skill selections
brennanb2025 Oct 26, 2026
970d114
fix: complete desktop queued composer integration
brennanb2025 Oct 26, 2026
354514a
test: use typed phone composer host lookups
brennanb2025 Oct 26, 2026
f0837de
fix: include queued edit localization keys
brennanb2025 Oct 26, 2026
dab24dd
Preserve inline edit input across save and attachment completion
brennanb2025 Oct 26, 2026
08ffe99
Preserve complete queued edits across delayed saves
brennanb2025 Oct 27, 2026
34abb5a
Preserve queued edit input across delayed completion
brennanb2025 Oct 27, 2026
f3279f8
Complete queued edit lease loss and pending cancellation
brennanb2025 Oct 27, 2026
c44799c
Merge main into queued message editing
brennanb2025 Oct 27, 2026
c27fde4
Use recognized queued edit test fixtures
brennanb2025 Oct 27, 2026
2d88e9c
Consolidate queued edit imports and type host test spy
brennanb2025 Oct 27, 2026
c38069b
Print mobile test compiler diagnostics on ratchet failure
brennanb2025 Oct 27, 2026
c988cb8
Correct queued edit integration fixture types
brennanb2025 Oct 27, 2026
14ff5f7
fix: keep queued edit placeholder independent of readiness
brennanb2025 Oct 27, 2026
bb3e425
Merge main after queued message reorder integration
brennanb2025 Oct 27, 2026
d1f36d9
Fix queued edit compiler fixture boundaries
brennanb2025 Oct 27, 2026
81f22e8
Align upload completion test with ordinary insertion
brennanb2025 Oct 27, 2026
4029b8a
Merge main into queued edit branch
brennanb2025 Oct 27, 2026
8fd1749
Combine mobile composer draft imports
brennanb2025 Oct 27, 2026
a5c0af0
Merge main into queued edit branch
brennanb2025 Oct 27, 2026
67ce690
Load queued edit host fixture during test collection
brennanb2025 Oct 27, 2026
003afa5
Size inline phone queue editor to available space
brennanb2025 Oct 27, 2026
48aaf58
Use typed scroll components in phone presentation contract
brennanb2025 Oct 27, 2026
b81ed9a
Merge main and retain moved phone image preview import
brennanb2025 Oct 27, 2026
a7dacd9
Merge main into queued message editor branch
brennanb2025 Oct 27, 2026
744e661
Save typed text in a queued edit as written
brennanb2025 Oct 28, 2026
b084a55
Merge main into queued message editor branch
brennanb2025 Oct 28, 2026
10916fa
Keep ordinary sends on the main composer contract
brennanb2025 Oct 28, 2026
a6a2210
Fix mobile composer imports and fixture loading
brennanb2025 Oct 28, 2026
6e4a8f1
Consolidate queued edit imports and duplicate regression
brennanb2025 Oct 28, 2026
637d966
Restore ordinary send catalog short circuit and repair test boundaries
brennanb2025 Oct 28, 2026
1770732
Preserve returned rich drafts through send acceptance
brennanb2025 Oct 28, 2026
a070389
Merge main into queued edit branch
brennanb2025 Oct 28, 2026
d262af5
Remove obsolete queued editor strings from new locales
brennanb2025 Oct 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions mobile/scripts/check-tests-typecheck-incremental-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ it.each([
const source = "import type { Shape } from './model'; const shape: Shape = { value: 1 }"
writeFileSync(test, source)
const clean = collectTypecheckPass(root)
expect(clean).toEqual({ failing: [], programTestFiles: ['value.test.ts'] })
expect(clean).toEqual({ failing: [], diagnostics: [], programTestFiles: ['value.test.ts'] })
if (buildInfo) {
expect(existsSync(buildInfo)).toBe(true)
}
Expand All @@ -54,6 +54,9 @@ it.each([
writeFileSync(join(root, 'model.ts'), 'export interface Shape { value: string }')
const failed = collectTypecheckPass(root)
expect(failed.failing).toEqual(['value.test.ts'])
expect(failed.diagnostics).toEqual([
expect.stringMatching(/^value\.test\.ts\(1,\d+\): error TS2322:/)
])
expect(collectTypecheckPass(root)).toEqual(failed)

writeFileSync(join(root, 'new.test.ts'), 'export const value: number = 1')
Expand All @@ -64,7 +67,11 @@ it.each([
expect(findTsNocheckFiles(root, nocheck.programTestFiles)).toEqual(['value.test.ts'])

unlinkSync(test)
expect(collectTypecheckPass(root)).toEqual({ failing: [], programTestFiles: ['new.test.ts'] })
expect(collectTypecheckPass(root)).toEqual({
failing: [],
diagnostics: [],
programTestFiles: ['new.test.ts']
})
} finally {
vi.unstubAllEnvs()
removeTreeSync(root)
Expand Down
4 changes: 4 additions & 0 deletions mobile/scripts/check-tests-typecheck-ratchet.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export function collectTypecheckPass(root = process.cwd()) {
const output = `${result.stdout ?? ''}${result.stderr ?? ''}`
return {
failing: parseFailingFiles(output),
diagnostics: output.split('\n').filter((line) => ERROR_LINE.test(line)),
programTestFiles: parseProgramTestFiles(output, fs.realpathSync(root))
}
}
Expand Down Expand Up @@ -277,6 +278,9 @@ export function main(root = process.cwd()) {

if (added.length > 0) {
printAddedFailure(added)
for (const diagnostic of pass.diagnostics) {
console.error(diagnostic)
}
if (stale.length > 0) {
printStaleFailure(stale)
}
Expand Down
82 changes: 80 additions & 2 deletions mobile/scripts/check-tests-typecheck-ratchet.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,95 @@
import { runProcessSync } from '@orca/process-host'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { describe, expect, it } from 'vitest'
// Only the pure functions are under test; the tsc spawn is proven end to end by CI.
import { describe, expect, it, vi } from 'vitest'
import { removeTreeSync } from '../../src/shared/windows-transient-lock-removal'
import {
diffBaseline,
diffCensus,
hasTsNocheckDirective,
main,
parseBaseline,
parseFailingFiles,
parseProgramTestFiles,
TESTS_OUTSIDE_PROGRAM
} from './check-tests-typecheck-ratchet.mjs'

vi.mock('@orca/process-host', () => ({ runProcessSync: vi.fn() }))
vi.mock('./mobile-typecheck-compiler.mjs', () => ({
resolveMobileTypecheckCommand: (project: string, cwd: string) => ({
program: 'compiler',
args: ['--project', project],
cwd
})
}))

describe('ratchet failure diagnostics', () => {
it.each([
{ name: 'new failure', baseline: '', failed: true, exit: 1, printsDiagnostics: true },
{ name: 'clean pass', baseline: '', failed: false, exit: 0, printsDiagnostics: false },
{
name: 'grandfathered failure',
baseline: 'src/value.test.ts\n',
failed: true,
exit: 0,
printsDiagnostics: false
},
{
name: 'stale baseline',
baseline: 'src/value.test.ts\n',
failed: false,
exit: 1,
printsDiagnostics: false
}
])('preserves $name outcome and baseline', ({ baseline, failed, exit, printsDiagnostics }) => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'orca-pr31180-ratchet-'))
const diagnostic = 'src/value.test.ts(1,2): error TS2322: Type number is not assignable.'
const stderrDiagnostic = 'src/value.test.ts(2,3): error TS2345: Argument type mismatch.'
const detail = ' Type number is not assignable to type string.'
const errors = vi.spyOn(console, 'error').mockImplementation(() => {})
const logs = vi.spyOn(console, 'log').mockImplementation(() => {})
try {
for (const file of [...TESTS_OUTSIDE_PROGRAM.keys(), 'src/value.test.ts']) {
fs.mkdirSync(path.dirname(path.join(root, file)), { recursive: true })
fs.writeFileSync(path.join(root, file), 'export {}\n')
}
const baselineFile = path.join(root, 'tests-typecheck-baseline.txt')
fs.writeFileSync(baselineFile, baseline)
const programFile = path.join(fs.realpathSync(root), 'src/value.test.ts')
vi.mocked(runProcessSync).mockReturnValue({
code: failed ? 2 : 0,
signal: null,
timedOut: false,
stdout: `${programFile}\n${failed ? `${diagnostic}\n${detail}\n` : ''}`,
stderr: failed ? `${stderrDiagnostic}\n` : ''
})

expect(main(root)).toBe(exit)
expect(runProcessSync).toHaveBeenCalledExactlyOnceWith({
program: 'compiler',
args: ['--project', 'tsconfig.test.json', '--listFiles'],
cwd: root,
timeoutMs: null,
maxOutputBytes: 64 * 1024 * 1024
})
expect(errors.mock.calls.some(([message]) => message === diagnostic)).toBe(printsDiagnostics)
expect(errors.mock.calls.some(([message]) => message === stderrDiagnostic)).toBe(
printsDiagnostics
)
expect(
errors.mock.calls.some(([message]) => message === detail || message === programFile)
).toBe(false)
expect(fs.readFileSync(baselineFile, 'utf8')).toBe(baseline)
} finally {
vi.mocked(runProcessSync).mockReset()
errors.mockRestore()
logs.mockRestore()
removeTreeSync(root)
}
})
})

describe('the failing-file parser', () => {
it('names each file once however many errors it carries', () => {
const output = [
Expand Down
210 changes: 122 additions & 88 deletions mobile/src/session/MobileNativeChatOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MobileQueuedMessageComposerContext } from './mobile-queued-message-composer-context'
import { useCallback, useLayoutEffect, useMemo } from 'react'
import { StyleSheet, View } from 'react-native'
import { MobileNativeChatView, type MobileNativeChatInputLockReason } from './MobileNativeChatView'
Expand Down Expand Up @@ -121,6 +122,36 @@ export function MobileNativeChatOverlay({
: null,
[itemSource, fullContent.detail, load]
)
const queuedComposerContext = useMemo(
() => ({
agent,
structured: structuredComposer ?? null,
skillDiscovery: controller.nativeChatSkills,
onNeedSkills: controller.loadNativeChatSkills,
filePaths: controller.nativeChatFilePaths,
onNeedFiles: controller.loadNativeChatFiles,
onError: (message: string) => controller.reportQueuedEditError?.(message),
onMicPress,
micActive,
dictationMode,
onMicPressIn,
onMicPressOut
}),
[
agent,
structuredComposer,
controller.nativeChatSkills,
controller.loadNativeChatSkills,
controller.nativeChatFilePaths,
controller.loadNativeChatFiles,
controller.reportQueuedEditError,
onMicPress,
micActive,
dictationMode,
onMicPressIn,
onMicPressOut
]
)
const noticeNames = useMemo(
() => ({ hostName, ...(agent ? { agentName: tuiAgentDisplayName(agent) ?? agent } : {}) }),
[hostName, agent]
Expand All @@ -133,94 +164,97 @@ export function MobileNativeChatOverlay({
conversation={{ surfaceId: sendSurfaceId, sessionId }}
imageClient={controller.nativeChatVisualSource?.client}
>
<View style={styles.overlay}>
<MobileNativeChatVisualContext.Provider value={visuals}>
<MobileNativeChatRootItemSourceContext.Provider value={detailSource}>
<MobileNativeChatReplyRevealsContext.Provider value={replyReveals}>
<MobileNativeChatNoticeContext.Provider value={noticeNames}>
<MobileNativeChatView
messages={session.messages}
folded={folded}
status={session.status}
error={session.error}
readFailedFinally={session.readFailedFinally === true}
agent={controller.nativeChatAgent}
agentWorking={controller.nativeChatTurnActive}
awaitingInput={controller.nativeChatAwaitingInput}
canStop={controller.nativeChatCanStop}
structuredActivityUi={controller.nativeChatStructured}
turnIndicator={controller.nativeChatTurnIndicator}
workingStartedAt={controller.nativeChatWorkingStartedAt}
settledTurns={controller.nativeChatSettledTurns}
turnJournal={controller.nativeChatTurnJournal}
receipts={controller.nativeChatReceipts}
actionablePromptIds={controller.nativeChatActionablePromptIds}
streaming={streaming}
onStop={controller.handleNativeChatStop}
ask={controller.nativeChatAsk}
askKey={controller.nativeChatAskKey}
promptKey={controller.nativeChatPromptKey}
onDismissAsk={controller.dismissNativeChatAsk}
onAnswerAsk={controller.handleNativeChatAnswerAsk}
askRequiresTerminal={
!controller.nativeChatStructured && nativeChatAskRequiresTerminal(agent)
}
onAnswerInTerminal={
activeSessionTabId
? () => controller.setTabView(activeSessionTabId, 'terminal')
: undefined
}
onCancelAsk={controller.handleNativeChatCancelAsk}
onCancelPrompt={controller.handleNativeChatCancelPrompt}
onCollapseAsk={controller.collapseNativeChatAsk}
onCollapsePrompt={controller.collapseNativeChatPrompt}
collapsedPrompt={controller.nativeChatCollapsedPrompt}
question={controller.nativeChatQuestion}
onAnswerQuestion={controller.handleNativeChatQuestionAnswer}
permission={controller.nativeChatPermission}
onRespondPermission={controller.handleNativeChatRespondPermission}
composerTray={composerTray}
onOpenFile={onOpenFile}
hasMore={session.hasMore}
olderPages={session.olderPages}
onLoadEarlier={session.loadEarlier}
onSend={images.sendNativeChat}
sendSurfaceId={sendSurfaceId}
getSendCompletionGeneration={getSendCompletionGeneration}
getComposerEditGeneration={controller.getChatComposerEditGeneration}
pending={controller.chatPending}
imagePreviewsByMessageId={controller.chatImagePreviewsByMessageId}
draftKey={controller.chatDraftKey}
onComposerTextChange={controller.setChatComposerText}
onAttachImage={
controller.nativeChatAcceptsImages
? () => void images.attachImage('library')
: undefined
}
attachments={images.attachments}
onRemoveAttachment={images.removeAttachment}
isAttaching={images.isAttaching}
onMicPress={onMicPress}
micActive={micActive}
dictationMode={dictationMode}
onMicPressIn={onMicPressIn}
onMicPressOut={onMicPressOut}
inputLockReason={inputLockReason}
sendErrorMessage={sendErrorMessage}
onClearSendError={onClearSendError}
filePaths={controller.nativeChatFilePaths}
onNeedFiles={controller.loadNativeChatFiles}
skillDiscovery={controller.nativeChatSkills}
onNeedSkills={controller.loadNativeChatSkills}
sessionOptions={controller.nativeChatSessionOptions}
structuredComposer={structuredComposer}
keyboardInset={keyboardInset}
/>
</MobileNativeChatNoticeContext.Provider>
</MobileNativeChatReplyRevealsContext.Provider>
</MobileNativeChatRootItemSourceContext.Provider>
</MobileNativeChatVisualContext.Provider>
</View>
<MobileQueuedMessageComposerContext.Provider value={queuedComposerContext}>
<View style={styles.overlay}>
<MobileNativeChatVisualContext.Provider value={visuals}>
<MobileNativeChatRootItemSourceContext.Provider value={detailSource}>
<MobileNativeChatReplyRevealsContext.Provider value={replyReveals}>
<MobileNativeChatNoticeContext.Provider value={noticeNames}>
<MobileNativeChatView
messages={session.messages}
folded={folded}
status={session.status}
error={session.error}
readFailedFinally={session.readFailedFinally === true}
agent={controller.nativeChatAgent}
agentWorking={controller.nativeChatTurnActive}
awaitingInput={controller.nativeChatAwaitingInput}
canStop={controller.nativeChatCanStop}
structuredActivityUi={controller.nativeChatStructured}
turnIndicator={controller.nativeChatTurnIndicator}
workingStartedAt={controller.nativeChatWorkingStartedAt}
settledTurns={controller.nativeChatSettledTurns}
turnJournal={controller.nativeChatTurnJournal}
receipts={controller.nativeChatReceipts}
actionablePromptIds={controller.nativeChatActionablePromptIds}
streaming={streaming}
onStop={controller.handleNativeChatStop}
ask={controller.nativeChatAsk}
askKey={controller.nativeChatAskKey}
promptKey={controller.nativeChatPromptKey}
onDismissAsk={controller.dismissNativeChatAsk}
onAnswerAsk={controller.handleNativeChatAnswerAsk}
askRequiresTerminal={
!controller.nativeChatStructured && nativeChatAskRequiresTerminal(agent)
}
onAnswerInTerminal={
activeSessionTabId
? () => controller.setTabView(activeSessionTabId, 'terminal')
: undefined
}
onCancelAsk={controller.handleNativeChatCancelAsk}
onCancelPrompt={controller.handleNativeChatCancelPrompt}
onCollapseAsk={controller.collapseNativeChatAsk}
onCollapsePrompt={controller.collapseNativeChatPrompt}
collapsedPrompt={controller.nativeChatCollapsedPrompt}
question={controller.nativeChatQuestion}
onAnswerQuestion={controller.handleNativeChatQuestionAnswer}
permission={controller.nativeChatPermission}
onRespondPermission={controller.handleNativeChatRespondPermission}
composerTray={composerTray}
onOpenFile={onOpenFile}
hasMore={session.hasMore}
olderPages={session.olderPages}
onLoadEarlier={session.loadEarlier}
onSend={images.sendNativeChat}
sendSurfaceId={sendSurfaceId}
getSendCompletionGeneration={getSendCompletionGeneration}
getComposerEditGeneration={controller.getChatComposerEditGeneration}
pending={controller.chatPending}
imagePreviewsByMessageId={controller.chatImagePreviewsByMessageId}
composerScopeKey={controller.chatComposerScopeKey}
draftKey={controller.chatDraftKey}
onComposerTextChange={controller.setChatComposerText}
onAttachImage={
controller.nativeChatAcceptsImages
? () => void images.attachImage('library')
: undefined
}
attachments={images.attachments}
onRemoveAttachment={images.removeAttachment}
isAttaching={images.isAttaching}
onMicPress={onMicPress}
micActive={micActive}
dictationMode={dictationMode}
onMicPressIn={onMicPressIn}
onMicPressOut={onMicPressOut}
inputLockReason={inputLockReason}
sendErrorMessage={sendErrorMessage}
onClearSendError={onClearSendError}
filePaths={controller.nativeChatFilePaths}
onNeedFiles={controller.loadNativeChatFiles}
skillDiscovery={controller.nativeChatSkills}
onNeedSkills={controller.loadNativeChatSkills}
sessionOptions={controller.nativeChatSessionOptions}
structuredComposer={structuredComposer}
keyboardInset={keyboardInset}
/>
</MobileNativeChatNoticeContext.Provider>
</MobileNativeChatReplyRevealsContext.Provider>
</MobileNativeChatRootItemSourceContext.Provider>
</MobileNativeChatVisualContext.Provider>
</View>
</MobileQueuedMessageComposerContext.Provider>
</MobileNativeChatRowOverlaysHost>
)
}
Expand Down
4 changes: 4 additions & 0 deletions mobile/src/session/MobileNativeChatView.composer-lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,7 @@ describe('MobileNativeChatView: composer lock and prompt cards', () => {
})
})
})

vi.mock('./MobileQueuedMessageComposer', () => ({
MobileQueuedMessageComposer: 'QueuedMessageComposer'
}))
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,7 @@ describe('MobileNativeChatView: send and read failure banners', () => {
expect(onClearSendError).toHaveBeenCalledOnce()
})
})

vi.mock('./MobileQueuedMessageComposer', () => ({
MobileQueuedMessageComposer: 'QueuedMessageComposer'
}))
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,7 @@ describe('MobileNativeChatView: history paging and anchoring', () => {
})
})
})

vi.mock('./MobileQueuedMessageComposer', () => ({
MobileQueuedMessageComposer: 'QueuedMessageComposer'
}))
Loading
Loading