diff --git a/src/renderer/src/app-shell/platform/client-platform.ts b/src/renderer/src/app-shell/platform/client-platform.ts new file mode 100644 index 00000000000..af66c999d0e --- /dev/null +++ b/src/renderer/src/app-shell/platform/client-platform.ts @@ -0,0 +1,5 @@ +export const CLIENT_PLATFORM: NodeJS.Platform = navigator.userAgent.includes('Windows') + ? 'win32' + : navigator.userAgent.includes('Mac') + ? 'darwin' + : 'linux' diff --git a/src/renderer/src/components/terminal-pane/account-restart/detached/codex-detached-pane-restart.ts b/src/renderer/src/components/terminal-pane/account-restart/detached/codex-detached-pane-restart.ts index 8b2031ecea3..342d92f6f0a 100644 --- a/src/renderer/src/components/terminal-pane/account-restart/detached/codex-detached-pane-restart.ts +++ b/src/renderer/src/components/terminal-pane/account-restart/detached/codex-detached-pane-restart.ts @@ -158,7 +158,7 @@ async function executeDetachedCodexPaneRestart( return } const { worktreeId, tab, leafId } = located - const startup = buildPaneAccountRestartStartup(agent, { + const startup = buildPaneAccountRestartStartup(state, agent, { worktreeId, tabId: tab.id, leafId, diff --git a/src/renderer/src/components/terminal-pane/account-restart/use-pane-account-restart-startup.ts b/src/renderer/src/components/terminal-pane/account-restart/use-pane-account-restart-startup.ts index 4a3cbe4bafb..1728e5021a8 100644 --- a/src/renderer/src/components/terminal-pane/account-restart/use-pane-account-restart-startup.ts +++ b/src/renderer/src/components/terminal-pane/account-restart/use-pane-account-restart-startup.ts @@ -9,15 +9,16 @@ export function usePaneAccountRestartStartup({ worktreeId }: Pick) { const buildAccountRestartStartup = useCallback( - (agent: AccountRestartAgent, leafId: string) => - buildPaneAccountRestartStartup(agent, { + (agent: AccountRestartAgent, leafId: string) => { + const state = useAppStore.getState() + return buildPaneAccountRestartStartup(state, agent, { tabId, worktreeId, leafId, - shellOverride: useAppStore - .getState() - .tabsByWorktree[worktreeId]?.find((tab) => tab.id === tabId)?.shellOverride - }), + shellOverride: state.tabsByWorktree[worktreeId]?.find((tab) => tab.id === tabId) + ?.shellOverride + }) + }, [tabId, worktreeId] ) return { buildAccountRestartStartup } diff --git a/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.test.ts b/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.test.ts index 23d318ac27a..e1393b490a5 100644 --- a/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.test.ts +++ b/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.test.ts @@ -49,7 +49,7 @@ function seedAgentStatus(entry: Partial | null): void { } function build(): AgentAccountRestartStartup { - const startup = buildPaneAccountRestartStartup('codex', { + const startup = buildPaneAccountRestartStartup(useAppStore.getState(), 'codex', { tabId: TAB_ID, leafId: LEAF_ID, worktreeId: WORKTREE_ID @@ -127,7 +127,7 @@ describe('buildPaneAccountRestartStartup for Claude', () => { } }) - expect(buildPaneAccountRestartStartup('claude', pane)).toBeNull() + expect(buildPaneAccountRestartStartup(useAppStore.getState(), 'claude', pane)).toBeNull() }) it.each([ @@ -170,7 +170,7 @@ describe('buildPaneAccountRestartStartup for Claude', () => { } }) - expect(buildPaneAccountRestartStartup('claude', pane)?.command).toBe( + expect(buildPaneAccountRestartStartup(useAppStore.getState(), 'claude', pane)?.command).toBe( `${prefix}claude '--resume' '${SESSION_ID}'` ) } finally { diff --git a/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.ts b/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.ts index e009e0593b0..119a626616b 100644 --- a/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.ts +++ b/src/renderer/src/lib/agent-session/accounts/agent-account-restart-startup.ts @@ -1,5 +1,4 @@ import { getConnectionIdFromState } from '@/lib/workspace/ownership/connection-owner-resolution' -import { useAppStore } from '@/store/index' import { buildAgentResumeStartupPlan } from '../../../../../shared/agent-launch/startup/tui-agent-resume-startup' import { resolveRuntimeHostReportedPlatform, @@ -50,10 +49,10 @@ export type AgentAccountRestartResumeInput = { } | null export function captureAgentAccountRestartResumeInput( + state: AppState, agent: AccountRestartAgent, args: AccountRestartPane ): AgentAccountRestartResumeInput { - const state = useAppStore.getState() const paneKey = makePaneKey(args.tabId, args.leafId) const entry = state.agentStatusByPaneKey[paneKey] const sleeping = state.sleepingAgentSessionsByPaneKey[paneKey] @@ -76,12 +75,13 @@ export function captureAgentAccountRestartResumeInput( /** Capture before teardown; retry a build error using the same conversation inputs. */ export function resolveAgentAccountRestartResumeStartup( + state: AppState, agent: AccountRestartAgent, args: AccountRestartPane, input?: AgentAccountRestartResumeInput ): AgentAccountRestartStartup | null { - const state = useAppStore.getState() - const captured = input === undefined ? captureAgentAccountRestartResumeInput(agent, args) : input + const captured = + input === undefined ? captureAgentAccountRestartResumeInput(state, agent, args) : input if (!captured) { return null } @@ -131,11 +131,12 @@ export function resolveAgentAccountRestartResumeStartup( /** Account-switch startup: Codex can relaunch fresh; Claude requires its recorded conversation. */ export function buildPaneAccountRestartStartup( + state: AppState, agent: AccountRestartAgent, args: AccountRestartPane, input?: AgentAccountRestartResumeInput ): AgentAccountRestartStartup | null { - const resume = resolveAgentAccountRestartResumeStartup(agent, args, input) + const resume = resolveAgentAccountRestartResumeStartup(state, agent, args, input) if (input && !resume) { throw new Error('terminal_account_restart_resume_unavailable') } @@ -144,21 +145,17 @@ export function buildPaneAccountRestartStartup( if ( agent === 'claude' && sessionId && - isSessionHeldByAnotherPane( - useAppStore.getState(), - makePaneKey(args.tabId, args.leafId), - sessionId - ) + isSessionHeldByAnotherPane(state, makePaneKey(args.tabId, args.leafId), sessionId) ) { return null } - return resume ?? (agent === 'codex' ? buildCodexAccountRestartStartup(args) : null) + return resume ?? (agent === 'codex' ? buildCodexAccountRestartStartup(state, args) : null) } export function buildCodexAccountRestartStartup( + state: AppState, args: AccountRestartTarget ): AgentAccountRestartStartup { - const state = useAppStore.getState() const target = resolveAccountRestartLaunchTarget( state, args, diff --git a/src/renderer/src/lib/agent-session/accounts/claude/claude-session-account-move.ts b/src/renderer/src/lib/agent-session/accounts/claude/claude-session-account-move.ts index ccf1b448bdb..94065a90ef8 100644 --- a/src/renderer/src/lib/agent-session/accounts/claude/claude-session-account-move.ts +++ b/src/renderer/src/lib/agent-session/accounts/claude/claude-session-account-move.ts @@ -214,7 +214,7 @@ function scanPane( if (isClaudePaneOnAccount(folder, args.toAccountId, args.host)) { return null } - const resumable = resolveAgentAccountRestartResumeStartup('claude', { + const resumable = resolveAgentAccountRestartResumeStartup(useAppStore.getState(), 'claude', { tabId: pane.tabId, leafId: pane.leafId, worktreeId: pane.worktreeId, diff --git a/src/renderer/src/lib/agent-session/resume/agent-resume-launch-target.ts b/src/renderer/src/lib/agent-session/resume/agent-resume-launch-target.ts index 95a2a9f1191..d1a7de5ff31 100644 --- a/src/renderer/src/lib/agent-session/resume/agent-resume-launch-target.ts +++ b/src/renderer/src/lib/agent-session/resume/agent-resume-launch-target.ts @@ -1,4 +1,4 @@ -import { CLIENT_PLATFORM } from '@/lib/workspace/creation/new-workspace' +import { CLIENT_PLATFORM } from '@/app-shell/platform/client-platform' import { REMOTE_RUNTIME_PTY_HONOURS_TAB_SHELL_OVERRIDE } from '@/components/terminal-pane/pty-transport/remote-runtime/remote-runtime-pty-shell' import { parseExecutionHostId } from '../../../../../shared/execution-host' import { lastVerifiedRuntimeStatus } from '../../../../../shared/remote-runtime/host-status/runtime-host-status' diff --git a/src/renderer/src/lib/workspace/creation/new-workspace.ts b/src/renderer/src/lib/workspace/creation/new-workspace.ts index 9bf9a6c0a91..688eef0d885 100644 --- a/src/renderer/src/lib/workspace/creation/new-workspace.ts +++ b/src/renderer/src/lib/workspace/creation/new-workspace.ts @@ -14,11 +14,7 @@ import type { WorkspaceLinkedItem as FolderWorkspaceLinkedTask } from '../../../ import { slugifyForWorkspaceName } from '../../../../../shared/workspace-name' import { createNonSecureContextUuid as createBrowserUuid } from '../../../../../shared/non-secure-context-uuid' -export const CLIENT_PLATFORM: NodeJS.Platform = navigator.userAgent.includes('Windows') - ? 'win32' - : navigator.userAgent.includes('Mac') - ? 'darwin' - : 'linux' +export { CLIENT_PLATFORM } from '../../../app-shell/platform/client-platform' export type LinkedWorkItemSummary = Omit & { provider?: FolderWorkspaceLinkedTask['provider'] diff --git a/src/renderer/src/store/terminals/codex-account-restart-actions.ts b/src/renderer/src/store/terminals/codex-account-restart-actions.ts index d02f1a96b46..183eddbcdaf 100644 --- a/src/renderer/src/store/terminals/codex-account-restart-actions.ts +++ b/src/renderer/src/store/terminals/codex-account-restart-actions.ts @@ -50,12 +50,13 @@ export function createCodexAccountRestartActions( let error: string | undefined try { if (pane.leafId) { - startupInput = captureAgentAccountRestartResumeInput('codex', { + startupInput = captureAgentAccountRestartResumeInput(s, 'codex', { ...pane, leafId: pane.leafId }) startup = structuredClone( buildPaneAccountRestartStartup( + s, 'codex', { ...pane, leafId: pane.leafId }, startupInput @@ -221,9 +222,9 @@ export function createCodexAccountRestartActions( } const input = request.leafId ? request.startupInput - : captureAgentAccountRestartResumeInput('codex', { ...pane, leafId: pane.leafId }) + : captureAgentAccountRestartResumeInput(s, 'codex', { ...pane, leafId: pane.leafId }) const startup = structuredClone( - buildPaneAccountRestartStartup('codex', { ...pane, leafId: pane.leafId }, input) + buildPaneAccountRestartStartup(s, 'codex', { ...pane, leafId: pane.leafId }, input) ) if (!startup) { return s