Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7a8b2cb
refactor(native-chat): keep the provider resume handle opaque to shar…
brennanb2025 Oct 3, 2026
d8b831e
fix(native-chat): derive journal-row provider handles from the journa…
brennanb2025 Oct 3, 2026
a00a327
fix(native-chat): refuse a stored provider handle written in both forms
brennanb2025 Oct 3, 2026
2667173
refactor(native-chat): route structured agents through registered def…
brennanb2025 Oct 3, 2026
63508a5
refactor(native-chat): name the structured agent list once in host types
brennanb2025 Oct 3, 2026
96028ca
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-a2-a…
brennanb2025 Oct 3, 2026
88a09c4
fix(native-chat): narrow the record before reading its agent's option…
brennanb2025 Oct 4, 2026
38ac910
refactor(native-chat): make the router's registrations the only agent…
brennanb2025 Oct 4, 2026
92861a7
Merge origin/main into ACP opaque handle foundation
brennanb2025 Oct 4, 2026
3717fc4
test(native-chat): use opaque handle in queued rejection fixture
brennanb2025 Oct 5, 2026
aa85dd1
Merge refreshed ACP opaque handle foundation into agent registry
brennanb2025 Oct 5, 2026
a84ac5c
Merge origin/main into ACP agent registry
brennanb2025 Oct 5, 2026
3b68163
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-a1-o…
brennanb2025 Oct 5, 2026
01f9206
test(native-chat): share one Codex journal identity in the integratio…
brennanb2025 Oct 5, 2026
4178e5a
refactor(agent-session): name the handle's adapter state resumeCursor
brennanb2025 Oct 5, 2026
d23e5c0
Merge remote-tracking branch 'origin/brennanb2025/acp-a1-opaque-handl…
brennanb2025 Oct 5, 2026
9ddbafd
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-a2-a…
brennanb2025 Oct 5, 2026
19c8cb5
refactor(agent-session): one required agent registry; declarations ad…
brennanb2025 Oct 5, 2026
c5aaee8
refactor(agent-session): the router applies the declared rewind itself
brennanb2025 Oct 5, 2026
7591167
chore(agent-session): the registry is the one lookup; drop the test-o…
brennanb2025 Oct 5, 2026
288f72c
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-a2-a…
brennanb2025 Oct 5, 2026
374e740
Merge origin/main into acp-a1-opaque-handle
brennanb2025 Oct 5, 2026
22d3d85
Merge acp-a1-opaque-handle (with origin/main) into acp-a2-agent-registry
brennanb2025 Oct 5, 2026
3b0c7ab
Merge origin/main into acp-a2-agent-registry (main #24862)
brennanb2025 Oct 5, 2026
fc120f7
Merge origin/main into acp-a2-agent-registry (main squash of A1 #2499…
brennanb2025 Oct 5, 2026
fb8bcb8
test(native-chat): build the Stop-opened-turn test's identity and tur…
brennanb2025 Oct 5, 2026
e35bf18
test(ratchet): require src/main/provider-process now that it has landed
brennanb2025 Oct 5, 2026
0bb3919
Merge origin/main into acp-a2-agent-registry (main #25706, #25073)
brennanb2025 Oct 5, 2026
5f8deca
Merge brennanb2025/ratchet-provider-process-required (#25710) into ac…
brennanb2025 Oct 5, 2026
5b75928
test(native-chat): keep main's opaque-handle import in the Stop-opene…
brennanb2025 Oct 5, 2026
9dbd818
Merge origin/main into acp-a2-agent-registry (main's submission-posit…
brennanb2025 Oct 5, 2026
6312c30
Merge origin/main into acp-a2-agent-registry (main's duplicate-import…
brennanb2025 Oct 6, 2026
5e84b09
Merge current main into agent registry branch
brennanb2025 Oct 6, 2026
db71a89
Merge 08a970a3f117 into acp-a2-agent-registry
brennanb2025 Oct 6, 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
2 changes: 2 additions & 0 deletions src/main/claude/claude-api-retry-idle-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { createClaudeJournalTranslator } from './claude-structured-journal-trans
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'
import { codexProviderHandle } from '../../shared/agent-session-provider-handle-encoding'
import { NO_STRUCTURED_AGENTS } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'

const SWEEP_MS = 5
const RETRY_GAP_MS = 10 * 60_000
Expand Down Expand Up @@ -79,6 +80,7 @@ beforeEach(async () => {
setOption: async () => undefined
}
host = new StructuredAgentSessionHost({
agents: NO_STRUCTURED_AGENTS,
logger: createStructuredAgentSessionLogger(),
store,
adapter,
Expand Down
23 changes: 12 additions & 11 deletions src/main/claude/claude-context-usage-unloaded-turn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
import type { AgentSessionJournal } from '../native-chat/agent-session-journal/journal-store'
import { createTrackedJournalOpener } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { readAgentSessionHistory } from '../native-chat/agent-session-wire/agent-session-history-page'
import type { StructuredAgentSessionAdapter } from '../native-chat/agent-session-wire/structured-agent-session-adapter'
import { createDeferredStructuredAgentSessionEventSink } from '../native-chat/agent-session-wire/structured-agent-session-event-sink'
import type { StructuredAgentSessionMutationContext } from '../native-chat/agent-session-wire/structured-agent-session-host-mutations'
import { readStructuredAgentSessionOptions } from '../native-chat/agent-session-wire/structured-agent-session-options-read'
Expand All @@ -29,6 +28,11 @@ import {
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'
import { claudeProviderHandle } from '../../shared/agent-session-provider-handle-encoding'
import {
claudeAndCodexAgents,
NO_STRUCTURED_AGENTS
} from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'
import type { StructuredAgentRegistry } from '../native-chat/agent-session-wire/structured-agent-registry'

const SESSION = 'orca-session'
const journals = createTrackedJournalOpener()
Expand Down Expand Up @@ -81,10 +85,7 @@ function runTurn(
})
}

function readOptions(
journal: AgentSessionJournal,
adapter: Partial<StructuredAgentSessionAdapter>
) {
function readOptions(journal: AgentSessionJournal, agents: StructuredAgentRegistry) {
const running = {
journal,
child: { fence: 1, generation: 'generation-1' },
Expand All @@ -94,9 +95,9 @@ function readOptions(
const context = {
deps: {
adapter: {
readOptions: async () => ({ models: [], current: { model: 'opus' } }),
...adapter
readOptions: async () => ({ models: [], current: { model: 'opus' } })
},
agents,
store: { getRecord: () => undefined }
},
serialize: (_sessionId: string, task: () => Promise<unknown>) => task(),
Expand Down Expand Up @@ -171,7 +172,7 @@ describe('context usage for a turn row outside the loaded page', () => {
const state = attachTail(journal, 3)
expect(state.hasOlder).toBe(true)
expect(hasTurnRow(state)).toBe(false)
const options = await readOptions(journal, { recordsContextUsage: () => true })
const options = await readOptions(journal, claudeAndCodexAgents())

expect(options.contextUsage?.current).toEqual(
latestStructuredAgentContextFacts(journal.snapshot().items)
Expand All @@ -190,7 +191,7 @@ describe('context usage for a turn row outside the loaded page', () => {
runTurn(translator, 'turn-a', 1_000, [120_000, 130_000, 140_000])
await settle()

const options = await readOptions(journal, {})
const options = await readOptions(journal, NO_STRUCTURED_AGENTS)
expect(options).not.toHaveProperty('contextUsage')
// An older host answers the same way, so the ring reads only the loaded page, as before.
expect(selectStructuredAgentContextUsage(attachTail(journal, 2).items)).toBeNull()
Expand All @@ -213,7 +214,7 @@ describe('context usage for a turn row outside the loaded page', () => {

expect(hasTurnRow(live)).toBe(false)
expect(live.unloadedTurnRevisions).toBe(1)
const options = await readOptions(journal, { recordsContextUsage: () => true })
const options = await readOptions(journal, claudeAndCodexAgents())
expect(
selectStructuredAgentContextUsage(live.items, options.contextUsage?.current)
).toMatchObject({ usedTokens: 250_000, windowTokens: 1_000_000 })
Expand All @@ -227,7 +228,7 @@ describe('context usage for a turn row outside the loaded page', () => {
runTurn(translator, 'turn-b', 3_000, [])
await settle()
const hostAnswer = async () =>
(await readOptions(journal, { recordsContextUsage: () => true })).contextUsage?.current
(await readOptions(journal, claudeAndCodexAgents())).contextUsage?.current
// The client reads the host once per turn, and again whenever its window loses a turn row.
let state = attachTail(journal, 200)
let host = await hostAnswer()
Expand Down
24 changes: 24 additions & 0 deletions src/main/claude/claude-structured-agent-definition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { StructuredAgentDefinition } from '../native-chat/agent-session-wire/structured-agent-definition'
import { isClaudeStructuredOptionKey } from './claude-structured-options'
import { claudeFallbackModelOptions } from './claude-structured-session-options'

export const CLAUDE_STRUCTURED_AGENT: StructuredAgentDefinition = {
agent: 'claude',
capabilities: {
// Orca's marker-based rewind proof can never pass on the real binary; rewind returns via a fork.
rewind: false,
compact: true,
threadGoal: false,
// A session at rest still reports the usage its journal recorded.
contextUsage: true,
imagePrompts: true,
steering: 'inject',
// The permission mode is a launch flag the CLI enforces.
approvalEnforcement: 'provider'
},
restingOptions: {
acceptsKey: isClaudeStructuredOptionKey,
fallbackModels: claudeFallbackModelOptions,
effortDefaultsToModel: true
}
}
14 changes: 12 additions & 2 deletions src/main/claude/claude-structured-effort-default-at-rest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { agentModelCatalogFingerprintForRecord } from '../native-chat/agent-mode
import { AgentModelCatalogStore } from '../native-chat/agent-model-catalog/agent-model-catalog-store'
import type { StructuredAgentSessionMutationContext } from '../native-chat/agent-session-wire/structured-agent-session-host-mutations'
import { readStructuredAgentSessionOptions } from '../native-chat/agent-session-wire/structured-agent-session-options-read'
import { claudeAndCodexAgents } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'
import { composeCodexSessionOptionCatalog } from '../codex/codex-structured-model-catalog'
import { nativeSessionOptionsFromReport } from '../native-chat/agent-session-wire/structured-agent-session-option-restoration'
import {
Expand Down Expand Up @@ -145,10 +146,19 @@ function readAtRest(store: AgentModelCatalogStore, record: AgentSessionRecord) {
getRecord: () => record,
resolveAccountHome: async () => ({ variable: 'CLAUDE_CONFIG_DIR', path: ACCOUNT_HOME })
})
const resting = { child: null, params: { provider: 'claude' } }
const resting = {
child: null,
params: { provider: 'claude' },
journal: { threadGoal: () => null, contextUsage: () => null }
}
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the resting read touches only these members.
const context = {
deps: { adapter: {}, store: { getRecord: () => record }, modelCatalog },
deps: {
adapter: {},
agents: claudeAndCodexAgents(),
store: { getRecord: () => record },
modelCatalog
},
serialize: (_sessionId: string, task: () => Promise<unknown>) => task(),
openConversation: async () => resting,
conversation: async () => resting
Expand Down
6 changes: 4 additions & 2 deletions src/main/claude/claude-structured-launch-resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { resolveClaudeCommand } from '../codex-cli/command'
import { resolveSessionFilePath } from '../native-chat/session-file-resolver'
import { withoutInheritedClaudeConfigDir } from './claude-config-dir-pin'
import type { AgentSessionRecordStore } from '../runtime/agent-session-record-store'
import { agentConfigDirectoryVariable } from '../../shared/agent-session-account-home'

export const CLAUDE_DEFAULT_SETTING_SOURCES = ['user', 'project', 'local'] as const
export const CLAUDE_SESSION_STATE_EVENTS_ENV = 'CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS'
Expand Down Expand Up @@ -250,8 +251,9 @@ export function createClaudeStructuredLaunchResolver(
`claude structured sessions run on the local host, not ${record.location.executionHostId}`
)
}
if (record.accountHome.variable !== 'CLAUDE_CONFIG_DIR') {
throw new Error(`claude sessions pin CLAUDE_CONFIG_DIR, not ${record.accountHome.variable}`)
const pinned = agentConfigDirectoryVariable('claude')
if (record.accountHome.variable !== pinned) {
throw new Error(`claude sessions pin ${pinned}, not ${record.accountHome.variable}`)
}
// Every acquisition, not just the first: the account state can change under a live session, and
// a reacquire after an unexpected exit would otherwise spawn under whatever it has become.
Expand Down
9 changes: 0 additions & 9 deletions src/main/claude/claude-structured-session-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,6 @@ export class ClaudeStructuredSessionAdapter implements StructuredAgentSessionAda

supportsLocation = supportsClaudeStructuredLocation

// Orca's marker-based rewind proof can never pass on the real binary; rewind returns via a fork.
rewindSupport: NonNullable<StructuredAgentSessionAdapter['rewindSupport']> = () => ({
supported: false,
reason: 'unsupported'
})

acquire = (input: StructuredAgentSessionAcquireInput): Promise<AgentSessionAcquisition> => {
this.settledExitErrors.delete(input.identity.sessionId)
return acquireClaudeSession({
Expand Down Expand Up @@ -267,9 +261,6 @@ export class ClaudeStructuredSessionAdapter implements StructuredAgentSessionAda
)
readOptions = (input: { sessionId: string; fence: number }) =>
readClaudeStructuredSessionOptions(this.session(input.sessionId), this.deps.requestTimeoutMs)
// Provider-level: a session at rest still reports the usage its journal recorded.
recordsContextUsage = (): boolean => true

readOptionRestoreFailures = (sessionId: string): readonly string[] => [
...(this.sessions.get(sessionId)?.restoreSkippedOptions ?? [])
]
Expand Down
10 changes: 10 additions & 0 deletions src/main/claude/claude-structured-session-test-support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,13 @@ export function recordingJournalSink(): StructuredAgentSessionEventSink {
export function tick(): Promise<void> {
return new Promise((resolve) => setImmediate(resolve))
}

/** Delivers one frame from Claude on `connection`, under the provider session it runs. */
export function claudeFrame(connection: FakeConnection, message: Record<string, unknown>): void {
connection.handlers.onMessage?.({ session_id: PROVIDER_SESSION_ID, ...message })
}

/** Whether anything sent to Claude on `connection` carries `text`. */
export function claudeWasSent(connection: FakeConnection, text: string): boolean {
return connection.sent.some((message) => JSON.stringify(message).includes(text))
}
2 changes: 2 additions & 0 deletions src/main/codex/codex-provider-retry-idle-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { createCodexJournalTranslator } from './codex-structured-journal-transla
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'
import { codexProviderHandle } from '../../shared/agent-session-provider-handle-encoding'
import { NO_STRUCTURED_AGENTS } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'

const SWEEP_MS = 5
const RETRY_GAP_MS = 10 * 60_000
Expand Down Expand Up @@ -77,6 +78,7 @@ beforeEach(async () => {
setOption: async () => undefined
}
host = new StructuredAgentSessionHost({
agents: NO_STRUCTURED_AGENTS,
logger: createStructuredAgentSessionLogger(),
store,
adapter,
Expand Down
25 changes: 25 additions & 0 deletions src/main/codex/codex-structured-agent-definition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { StructuredAgentDefinition } from '../native-chat/agent-session-wire/structured-agent-definition'
import { isCodexTurnOptionKey } from './codex-structured-turn-start'

export const CODEX_STRUCTURED_AGENT: StructuredAgentDefinition = {
agent: 'codex',
capabilities: {
// A thread with legacy, unpaginated history narrows this to unsupported once it runs.
rewind: true,
compact: true,
// A goal change at rest starts the agent first.
threadGoal: true,
contextUsage: false,
imagePrompts: true,
steering: 'inject',
// Approval and sandbox policy ride on the thread; the app-server enforces them.
approvalEnforcement: 'provider'
},
restingOptions: {
acceptsKey: isCodexTurnOptionKey,
// No built-in list: the client fills the current model from its own unknown-model defaults.
fallbackModels: () => null,
// A running child answers only the effort its thread reported, never the model's default.
effortDefaultsToModel: false
}
}
6 changes: 4 additions & 2 deletions src/main/codex/codex-structured-launch-resolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type { CodexStructuredLaunch } from './codex-structured-session-adapter'
import type { CodexStructuredPermissionPolicy } from './codex-structured-permission-policy'
import { resolvePinnedCodexRolloutProof } from './codex-pinned-rollout-proof'
import { isWindowsProcessStartTimeAvailable } from '../windows/windows-process-table'
import { agentConfigDirectoryVariable } from '../../shared/agent-session-account-home'

export type CodexStructuredLaunchResolverDeps = {
store: AgentSessionRecordStore
Expand Down Expand Up @@ -85,8 +86,9 @@ export function createCodexStructuredLaunchResolver(
) {
throw new Error('codex structured sessions require Windows process creation-time proof')
}
if (accountHome.variable !== 'CODEX_HOME') {
throw new Error(`codex sessions pin CODEX_HOME, not ${accountHome.variable}`)
const pinned = agentConfigDirectoryVariable('codex')
if (accountHome.variable !== pinned) {
throw new Error(`codex sessions pin ${pinned}, not ${accountHome.variable}`)
}
const { command, environment } = await resolveCodexStructuredInvocation(deps)
// `record.launchArgs` is deliberately not read: the configured CLI arguments are a terminal
Expand Down
2 changes: 2 additions & 0 deletions src/main/codex/codex-structured-question-order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'
import { codexProviderHandle } from '../../shared/agent-session-provider-handle-encoding'
import { NO_STRUCTURED_AGENTS } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'

const CALLER = { callerKey: 'client-1' }

Expand Down Expand Up @@ -95,6 +96,7 @@ beforeEach(async () => {
}
store = await openTestAgentSessionRecordStore(root)
host = new StructuredAgentSessionHost({
agents: NO_STRUCTURED_AGENTS,
logger: createStructuredAgentSessionLogger(),
store,
adapter,
Expand Down
3 changes: 0 additions & 3 deletions src/main/codex/codex-structured-session-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,6 @@ export class CodexStructuredSessionAdapter implements StructuredAgentSessionAdap
this.deps.requestTimeoutMs
)

// Provider-level: a goal change at rest starts the agent first.
supportsThreadGoal = (): boolean => true

answerPrompt: StructuredAgentSessionAdapter['answerPrompt'] = (request) =>
answerCodexStructuredPrompt({ request, sessions: this.sessions })

Expand Down
4 changes: 2 additions & 2 deletions src/main/codex/codex-structured-session-close.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { CodexBackgroundTaskTracker } from './codex-background-task-tracker'
import { CodexPromptRegistry } from './codex-structured-prompt-replies'
import type { CodexSession } from './codex-structured-session-state'
import type { StructuredAgentSessionAdapter } from '../native-chat/agent-session-wire/structured-agent-session-adapter'
import { StructuredAgentSessionAdapterRouter } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router'
import { claudeAndCodexRouter } from '../native-chat/agent-session-wire/structured-agent-session-adapter-router-test-support'
import { codexProviderHandle } from '../../shared/agent-session-provider-handle-encoding'

const THREAD = 'thread-1'
Expand Down Expand Up @@ -211,7 +211,7 @@ describe('Codex structured session close lifecycle', () => {

it('routes Codex sink-failure recovery through force-close and preserves unexpected-exit settlement', async () => {
const { adapter, connections, events } = adapterFixture()
const router = new StructuredAgentSessionAdapterRouter(
const router = claudeAndCodexRouter(
{ claude: claudeAdapterStub(), codex: adapter },
async () => {}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type {
AgentModelCatalogSessionAccess,
AgentModelCatalogStore
} from './agent-model-catalog-store'
import { agentConfigDirectoryVariable } from '../../../shared/agent-session-account-home'
import type { AgentSessionHandleProvider } from '../../../shared/agent-session-provider-handle'

/**
* Everything that changes which models a listing can answer with: the agent,
Expand Down Expand Up @@ -55,7 +57,7 @@ export function agentModelCatalogFingerprintForRecord(
* Native only: both structured adapters refuse non-native locations at launch. */
export function agentModelCatalogSessionAccess(
store: AgentModelCatalogStore | undefined,
agent: 'claude' | 'codex',
agent: AgentSessionHandleProvider,
accountHomePath: string | null
): AgentModelCatalogSessionAccess | undefined {
if (!store || !accountHomePath) {
Expand All @@ -65,7 +67,7 @@ export function agentModelCatalogSessionAccess(
store,
fingerprint: agentModelCatalogFingerprint({
agent,
accountHomeVariable: agent === 'claude' ? 'CLAUDE_CONFIG_DIR' : 'CODEX_HOME',
accountHomeVariable: agentConfigDirectoryVariable(agent),
accountHomePath,
wslDistro: null
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { AgentSessionModelCatalogResult } from '../../../shared/agent-session-wire'
import type { AgentSessionRecord } from '../../../shared/agent-session-record'
import type {
AgentSessionAccountHome,
AgentSessionRecord
} from '../../../shared/agent-session-record'
import type { AgentSessionHandleProvider } from '../../../shared/agent-session-provider-handle'
import {
agentModelCatalogFingerprint,
agentModelCatalogFingerprintForRecord
Expand All @@ -16,9 +20,7 @@ export type AgentModelCatalogServiceDeps = {
/** The account home a structured launch for this agent would pin right now —
* the SAME resolver the create path fills `record.accountHome` with, so a
* record-less read can never answer from another account's listing. */
resolveAccountHome: (
agent: 'claude' | 'codex'
) => Promise<{ variable: 'CLAUDE_CONFIG_DIR' | 'CODEX_HOME'; path: string }>
resolveAccountHome: (agent: AgentSessionHandleProvider) => Promise<AgentSessionAccountHome>
/** Session-less listers, one per agent that has one on this host. */
probes?: Partial<Record<'claude' | 'codex', AgentModelCatalogProbe>>
/** Whether the workspace's own config could pick a model other than the listed default. */
Expand Down Expand Up @@ -99,7 +101,7 @@ export function createAgentModelCatalogService(
// Probes spawn natively; a WSL-pinned record has no host-side lister.
accountHomePath = scoped.location.wslDistro === null ? scoped.accountHome.path : null
} else {
let resolved: { variable: 'CLAUDE_CONFIG_DIR' | 'CODEX_HOME'; path: string }
let resolved: AgentSessionAccountHome
try {
resolved = await deps.resolveAccountHome(params.agent)
} catch {
Expand Down
Loading
Loading