refactor(mobile): drop the five adapter methods with no live caller

- HostSessionNativeChatOperations sendMessage, respond and attachImage. Every
  shipped send path calls sendMobileNativeChatMessageWithOutcome or
  typeMobileNativeChatCommandWithOutcome directly, as on main.
- HostWorkspaceCreationOperations createBlankWorkspace and
  createWorkspaceFromSource. use-new-workspace-create-submit imports
  createBlankWorkspace from the source module instead.

With those two gone the native creation factory only spread the RPC
operations and RpcWorkspaceCreationOperations only excluded them, so both
collapse. The arg and result types that existed solely for the five methods go
with them, as does the dead SessionTabsResult re-export.

Each name was grepped against non-test, non-adapter callers before and after.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
Jinwoo-H
2026-09-09 03:12:13 -04:00
parent b1f1ff78d1
commit 5cbbadfb2b
7 changed files with 7 additions and 110 deletions
@@ -4,7 +4,6 @@ import type {
} from '../../../src/shared/native-chat-types'
import type { MobileNativeChatSendOutcome } from './mobile-native-chat-send'
import type { MobileNativeChatStreamFrame } from './mobile-native-chat-stream-frame'
import type { MobileImageSource } from './mobile-image-source-picker'
export type HostSessionNativeChatTarget = {
workspaceId: string
@@ -29,10 +28,6 @@ export type HostSessionNativeChatImageAttachment = {
previewUri: string
}
export type HostSessionNativeChatImageAttachResult =
| { status: 'accepted'; attachment: HostSessionNativeChatImageAttachment }
| { status: 'cancelled' | 'permission-denied' | 'too-large' }
export type HostSessionNativeChatOperations = {
/** Whether the serving host can read this workspace's agent transcripts. */
readability(workspaceId: string): Promise<boolean>
@@ -48,25 +43,7 @@ export type HostSessionNativeChatOperations = {
limit: number,
beforeOffset?: number
): Promise<HostSessionNativeChatReadResult>
sendMessage(
target: HostSessionNativeChatTarget,
text: string,
deadline?: number,
clearInputFirst?: boolean,
resolvedLaunchDraft?: { text: string; createdAt: number },
typeCommand?: boolean
): Promise<MobileNativeChatSendOutcome>
respond(
target: HostSessionNativeChatTarget,
text: string,
enter: boolean,
deadline?: number
): Promise<MobileNativeChatSendOutcome>
stop(target: HostSessionNativeChatTarget, deadline?: number): Promise<MobileNativeChatSendOutcome>
attachImage?(
target: HostSessionNativeChatTarget,
source: MobileImageSource
): Promise<HostSessionNativeChatImageAttachResult>
pasteImages?(
target: HostSessionNativeChatTarget,
references: readonly string[],
@@ -1,5 +1,3 @@
import type { SessionTabsResult } from './mobile-session-route-types'
export type HostSessionTabCloseResult =
| { outcome: 'closed' }
| { outcome: 'refused'; reason: string | null }
@@ -8,5 +6,3 @@ export type HostSessionTabOperations = {
createBrowser(workspaceId: string, url: string): Promise<{ browserPageId?: string }>
close(workspaceId: string, tabId: string): Promise<HostSessionTabCloseResult>
}
export type { SessionTabsResult }
@@ -79,7 +79,7 @@ const HEAD_TIMER_CREATION_SHA256 =
'1a31b625e2174c3db77272249843196d2b6b06ab1e654a96d8f7858e3082e66b'
const HEAD_TIMER_CLEANUP_SHA256 = 'c73f1d1c2cc89642f3d727d6f3b6b81860a9d6f34234541a2065ec3d1a8cd116'
const HEAD_RUNTIME_STRING_SHA256 =
'390b26467725abc0514fdbbee2cba3ded2586d471438cea0b113182465484d5b'
'f7ab0549d15dfa0b830bf916844816fa317581a129ace4e99917ddf9cfb3771e'
const HEAD_HOST_JSX_SHA256 = '390405926b1695fa3a33686f0bc192b432f5468d8576499d7cafbb4922defbb5'
const HEAD_LEAF_JSX_SHA256 = 'd5f1ef0db57c63eb3e4ee7c98e8483bc21882a151ce0ca24e42c7d1234e1dace'
const HEAD_STYLE_REFERENCE_SHA256 =
@@ -517,7 +517,7 @@ describe('mobile session route extraction parity', () => {
it('preserves runtime strings, styles, and the expanded JSX tree', () => {
const strings = readRuntimeStrings()
expect(strings).toHaveLength(593)
expect(strings).toHaveLength(592)
expect(hash(strings)).toBe(HEAD_RUNTIME_STRING_SHA256)
const jsx = readJsxFacts(readDefinitions())
expect(jsx.host).toHaveLength(124)
@@ -4,7 +4,6 @@ import { isFloatingWorkspaceWorktreeId } from './floating-workspace'
import { isMobileNativeChatTranscriptReadable } from './mobile-native-chat-eligibility'
import {
sendMobileNativeChatMessageWithOutcome,
typeMobileNativeChatCommandWithOutcome,
type MobileNativeChatSendOutcome
} from './mobile-native-chat-send'
import { rankSuggestions } from './mobile-native-chat-autocomplete'
@@ -63,24 +62,6 @@ export function nativeHostSessionNativeChatOperations(
return { error: 'Transcript read failed' }
}
},
sendMessage(target, text, deadline, clearInputFirst, resolvedLaunchDraft, typeCommand) {
if (typeCommand && target.terminalId) {
return typeMobileNativeChatCommandWithOutcome({
client,
terminal: target.terminalId,
command: text,
resolvedLaunchDraft,
deadline,
...(target.clientId
? { mobileClient: { id: target.clientId, type: 'mobile' as const } }
: {})
})
}
return sendNative(target, text, true, client, deadline, clearInputFirst, resolvedLaunchDraft)
},
respond(target, text, enter, deadline) {
return sendNative(target, text, enter, client, deadline)
},
stop(target, deadline) {
// Escape must not carry Return: the extra newline submits whatever the agent
// had parked on its input line.
@@ -8,20 +8,13 @@ import type { SparsePreset } from '../../../src/shared/worktree/create-types'
import type { GitHubPrStartPoint } from '../../../src/shared/worktree/types'
import type { RepoSlug } from '../../../src/shared/new-workspace/github-links'
import type { SshConnectionState } from '../../../src/shared/ssh-types'
import type { WorktreeCreateResult } from '../tasks/worktree-create-retry'
import type { WorktreeCreateIdempotencyProbe } from '../tasks/worktree-create-idempotency-policy'
import type { NewWorktreeRuntimeCapabilities } from '../tasks/worktree-create-capability'
import type {
MrStateFilter,
MobileComposerCreateSelection
} from '../tasks/mobile-composer-source-types'
import type { MrStateFilter } from '../tasks/mobile-composer-source-types'
import type {
ComposerHostedBase,
ResolveComposerMrBaseArgs,
ResolveComposerPrBaseArgs
} from '../tasks/composer-source-base-resolve'
import type { WorkspaceAgentChoice } from '../tasks/workspace-agent-selection'
import type { WorkspaceCreateSetupDecision } from '../tasks/workspace-create-params'
import type { SetupHookTrust } from '../tasks/setup-hook-trust'
import type { ExecutionHostId } from '../../../src/shared/execution-host'
import type { GitRemoteIdentity } from '../../../src/shared/git-remote-identity'
@@ -56,28 +49,6 @@ export type NewWorkspaceRepoHooks = {
setupTrust?: SetupHookTrust
}
export type CreateBlankWorkspaceOperationArgs = {
repoId: string
baseName: string
agentChoice: WorkspaceAgentChoice
nameWasGenerated: boolean
comment: string | undefined
setupDecision: WorkspaceCreateSetupDecision
worktreeCreateIdempotency: WorktreeCreateIdempotencyProbe
}
export type CreateWorkspaceFromSourceOperationArgs = {
selection: MobileComposerCreateSelection
targetRepoId: string
setupDecision: WorkspaceCreateSetupDecision
agentChoice: WorkspaceAgentChoice
workspaceName: string | undefined
note: string | undefined
sparseCheckout?: { directories: string[]; presetId?: string }
nameIsAutoManaged?: boolean
worktreeCreateIdempotency: WorktreeCreateIdempotencyProbe
}
export type HostWorkspaceCreationOperations = {
listRepositories(): Promise<NewWorkspaceRepository[]>
readRetiredWorktreeNames(repoId: string): Promise<RetiredNameRegistry>
@@ -129,8 +100,4 @@ export type HostWorkspaceCreationOperations = {
}): Promise<GitLabWorkItem | null>
resolvePrBase(args: Omit<ResolveComposerPrBaseArgs, 'client'>): Promise<GitHubPrStartPoint>
resolveMrBase(args: Omit<ResolveComposerMrBaseArgs, 'client'>): Promise<ComposerHostedBase>
createBlankWorkspace(args: CreateBlankWorkspaceOperationArgs): Promise<WorktreeCreateResult>
createWorkspaceFromSource(
args: CreateWorkspaceFromSourceOperationArgs
): Promise<WorktreeCreateResult>
}
@@ -1,27 +1,9 @@
import type { RpcClient } from '../transport/rpc-client'
import { createBlankWorkspace } from '../tasks/blank-workspace-create'
import { createWorkspaceFromComposerSource } from '../tasks/source-workspace-create'
import type { HostWorkspaceCreationOperations } from './host-workspace-creation-operations'
import { rpcWorkspaceCreationOperations } from './rpc-workspace-creation-operations'
export function nativeHostWorkspaceCreationOperations(
client: RpcClient
): HostWorkspaceCreationOperations {
return {
...rpcWorkspaceCreationOperations(client),
async createBlankWorkspace(args) {
return createBlankWorkspace({
client,
...args,
createdWithAgentId: args.agentChoice === 'blank' ? undefined : args.agentChoice
})
},
async createWorkspaceFromSource(args) {
return createWorkspaceFromComposerSource({
client,
...args,
agent: { choice: args.agentChoice }
})
}
}
return rpcWorkspaceCreationOperations(client)
}
@@ -4,17 +4,11 @@ import type { HostWorkspaceCreationOperations } from './host-workspace-creation-
import { nativeHostWorkspaceCreationReadOperations } from './native-host-workspace-creation-read-operations'
import { nativeHostWorkspaceCreationSourceOperations } from './native-host-workspace-creation-source-operations'
export type RpcWorkspaceCreationOperations = Omit<
HostWorkspaceCreationOperations,
'createBlankWorkspace' | 'createWorkspaceFromSource'
>
/** Every workspace-creation call that is a plain desktop request, written against a bare request
* sender so any non-socket provider can supply one without a second copy. Creation itself is
* excluded: it needs connection state for its retry, which a sender cannot report. */
/** Every workspace-creation call the screens make, written against a bare request sender so any
* non-socket provider can supply one without a second copy. */
export function rpcWorkspaceCreationOperations(
client: RpcRequestSender
): RpcWorkspaceCreationOperations {
): HostWorkspaceCreationOperations {
return {
...nativeHostWorkspaceCreationReadOperations(client),
...nativeHostWorkspaceCreationSourceOperations(client),