Files
orca/src/main/runtime/structured-claude-runtime-adapter.ts
T
Merge Sim 73fb77a7e7 Match the Claude structured launch to the terminal path's managed-account auth rules
The SDK path stripped ambient Anthropic auth unconditionally, let an explicit
agentDefaultEnv override beat a pinned managed account, and had no account-switch
guard. Reuse the terminal preflight's own predicate and messages so both transports
strip, refuse, and report identically, and cover the CLI transcript location that
mobile native chat depends on.
2026-09-03 12:04:30 -07:00

95 lines
4.0 KiB
TypeScript

import type { AgentSessionRecord } from '../../shared/agent-session-record'
import { join } from 'node:path'
import { resolveClaudeCommand } from '../codex-cli/command'
import {
createClaudeStructuredLaunchResolver,
type ClaudeStructuredAuthPolicy
} from '../claude/claude-structured-launch-resolution'
import {
ClaudeStructuredSessionAdapter,
type ClaudeStructuredSessionAdapterDeps
} from '../claude/claude-structured-session-adapter'
import { claudeProviderHandleLink } from '../claude/claude-structured-owner-identity'
import type { StructuredAgentSessionLifecycleEvent } from '../native-chat/agent-session-wire/structured-agent-session-adapter'
import {
readClaudeTranscriptLeafUuid,
resolveSessionFilePath
} from '../native-chat/session-file-resolver'
import { recordAgentSessionProviderHandle } from './agent-session-provider-handle-transition'
import type { AgentSessionRecordStore } from './agent-session-record-store'
export type StructuredClaudeRuntimeAdapterDeps = {
store: AgentSessionRecordStore
resolveWorkspacePath: (workspaceId: string) => Promise<string>
resolveClaudeCommand?: () => string
resolveClaudeLaunchEnv?: () => Promise<Record<string, string>> | Record<string, string>
/** Managed-account auth state for a Claude launch, mirroring the terminal preflight. */
resolveClaudeAuthPolicy?: () => Promise<ClaudeStructuredAuthPolicy> | ClaudeStructuredAuthPolicy
openClaudeConnection?: ClaudeStructuredSessionAdapterDeps['openConnection']
readProcessStartTime?: ClaudeStructuredSessionAdapterDeps['readProcessStartTime']
onUnexpectedExit: (event: StructuredAgentSessionLifecycleEvent) => void
}
export function createStructuredClaudeRuntimeAdapter(
deps: StructuredClaudeRuntimeAdapterDeps
): ClaudeStructuredSessionAdapter {
const { store } = deps
return new ClaudeStructuredSessionAdapter({
resolveLaunch: createClaudeStructuredLaunchResolver({
store,
resolveWorkspacePath: deps.resolveWorkspacePath,
resolveCommand: deps.resolveClaudeCommand ?? resolveClaudeCommand,
...(deps.resolveClaudeLaunchEnv ? { resolveEnv: deps.resolveClaudeLaunchEnv } : {}),
...(deps.resolveClaudeAuthPolicy ? { resolveAuthPolicy: deps.resolveClaudeAuthPolicy } : {})
}),
persistHandle: async ({ sessionId, providerSessionId, leafUuid, fence }) => {
const currentFence = store.getRecord(sessionId)?.lease.runtimeFence ?? fence
const observedAt = Date.now()
await store.transitionHandoff(sessionId, (record: AgentSessionRecord) =>
recordAgentSessionProviderHandle({
record,
fence: currentFence,
link: claudeProviderHandleLink({
sessionId: providerSessionId,
leafUuid,
resumed: true,
fence: currentFence,
observedAt
}),
now: observedAt
})
)
},
readTranscriptLeaf: async ({ providerSessionId, previousLeafUuid, claudeConfigDir }) => {
const transcriptPath = await resolveSessionFilePath('claude', providerSessionId, {
claudeProjectsDir: join(claudeConfigDir, 'projects')
})
return transcriptPath
? await readClaudeTranscriptLeafUuid(transcriptPath, providerSessionId, previousLeafUuid)
: null
},
onEvent: (event) => {
if (
event.type === 'ended' &&
event.cause === 'unexpected-exit' &&
event.fence !== undefined &&
event.acquisitionGeneration
) {
deps.onUnexpectedExit({
type: 'ended',
sessionId: event.sessionId,
reason: event.reason,
cause: event.cause,
fence: event.fence,
acquisitionGeneration: event.acquisitionGeneration,
...(event.settlementRetryRequired
? { settlementRetryRequired: event.settlementRetryRequired }
: {})
})
}
},
...(deps.openClaudeConnection ? { openConnection: deps.openClaudeConnection } : {}),
...(deps.readProcessStartTime ? { readProcessStartTime: deps.readProcessStartTime } : {})
})
}