mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +00:00
refactor(terminal): publish new tabs together with their startup command (#28848)
Seven call sites created a terminal tab and then queued its startup command in a second store write. Pass the command through createTab's existing pendingStartup option instead, so the tab and its command land in one write. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a93a236577
commit
c8f080764b
@@ -62,7 +62,28 @@ export function registerTerminalRequestIpcBridge(unsubs: (() => void)[]): void {
|
||||
recordInteraction: false,
|
||||
...(data.cwd ? { startupCwd: data.cwd } : {})
|
||||
}
|
||||
const tab = store.createTab(worktreeId, data.targetGroupId, data.shellOverride, tabOptions)
|
||||
const pendingStartup = data.command
|
||||
? {
|
||||
command: data.command,
|
||||
...(data.env ? { env: data.env } : {}),
|
||||
...(data.envToDelete ? { envToDelete: data.envToDelete } : {}),
|
||||
...(data.launchConfig ? { launchConfig: data.launchConfig } : {}),
|
||||
...(data.resumeProviderSession
|
||||
? { resumeProviderSession: data.resumeProviderSession }
|
||||
: {}),
|
||||
...(data.launchToken ? { launchToken: data.launchToken } : {}),
|
||||
...(data.launchAgent ? { launchAgent: data.launchAgent } : {}),
|
||||
...(data.startupCommandDelivery
|
||||
? { startupCommandDelivery: data.startupCommandDelivery }
|
||||
: {})
|
||||
}
|
||||
: undefined
|
||||
const tab = store.createTab(
|
||||
worktreeId,
|
||||
data.targetGroupId,
|
||||
data.shellOverride,
|
||||
pendingStartup ? { ...tabOptions, pendingStartup } : tabOptions
|
||||
)
|
||||
if (!shouldActivate) {
|
||||
// Why: renderer-backed Codex startup must mount its new TerminalPane without switching UI or connecting every saved tab.
|
||||
requestBackgroundTerminalWorktreeMount({ worktreeId, tabIds: [tab.id] })
|
||||
@@ -89,22 +110,6 @@ export function registerTerminalRequestIpcBridge(unsubs: (() => void)[]): void {
|
||||
if (data.title) {
|
||||
store.setTabCustomTitle(tab.id, data.title, { recordInteraction: false })
|
||||
}
|
||||
if (data.command) {
|
||||
store.queueTabStartupCommand(tab.id, {
|
||||
command: data.command,
|
||||
...(data.env ? { env: data.env } : {}),
|
||||
...(data.envToDelete ? { envToDelete: data.envToDelete } : {}),
|
||||
...(data.launchConfig ? { launchConfig: data.launchConfig } : {}),
|
||||
...(data.resumeProviderSession
|
||||
? { resumeProviderSession: data.resumeProviderSession }
|
||||
: {}),
|
||||
...(data.launchToken ? { launchToken: data.launchToken } : {}),
|
||||
...(data.launchAgent ? { launchAgent: data.launchAgent } : {}),
|
||||
...(data.startupCommandDelivery
|
||||
? { startupCommandDelivery: data.startupCommandDelivery }
|
||||
: {})
|
||||
})
|
||||
}
|
||||
window.api.ui.replyTerminalCreate({
|
||||
requestId: data.requestId,
|
||||
tabId: tab.id,
|
||||
|
||||
@@ -231,7 +231,15 @@ describe('useIpcEvents updater integration', () => {
|
||||
activate: false,
|
||||
recordInteraction: false,
|
||||
launchAgent: 'codex',
|
||||
startupCwd: '/repo/packages/app'
|
||||
startupCwd: '/repo/packages/app',
|
||||
pendingStartup: {
|
||||
command: 'codex',
|
||||
launchConfig: {
|
||||
agentArgs: '--model gpt-5',
|
||||
agentEnv: { CODEX_PROFILE: 'request' }
|
||||
},
|
||||
launchAgent: 'codex'
|
||||
}
|
||||
})
|
||||
expect(setActiveView).not.toHaveBeenCalled()
|
||||
expect(setActiveWorktree).not.toHaveBeenCalled()
|
||||
@@ -251,14 +259,7 @@ describe('useIpcEvents updater integration', () => {
|
||||
expect(setTabCustomTitle).toHaveBeenCalledWith('tab-new', 'Codex', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(queueTabStartupCommand).toHaveBeenCalledWith('tab-new', {
|
||||
command: 'codex',
|
||||
launchConfig: {
|
||||
agentArgs: '--model gpt-5',
|
||||
agentEnv: { CODEX_PROFILE: 'request' }
|
||||
},
|
||||
launchAgent: 'codex'
|
||||
})
|
||||
expect(queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(replyTerminalCreate).toHaveBeenCalledWith({
|
||||
requestId: 'req-renderer-backed',
|
||||
tabId: 'tab-new',
|
||||
@@ -282,7 +283,8 @@ describe('useIpcEvents updater integration', () => {
|
||||
|
||||
expect(createTab).toHaveBeenCalledWith('wt-2', 'group-left', undefined, {
|
||||
launchAgent: 'codex',
|
||||
viewMode: 'terminal'
|
||||
viewMode: 'terminal',
|
||||
pendingStartup: { command: 'codex', launchAgent: 'codex' }
|
||||
})
|
||||
expect(replyTerminalCreate).toHaveBeenCalledWith({
|
||||
requestId: 'req-runtime-session',
|
||||
@@ -444,7 +446,8 @@ describe('useIpcEvents updater integration', () => {
|
||||
|
||||
expect(createTab).toHaveBeenCalledWith('wt-2', undefined, undefined, {
|
||||
activate: false,
|
||||
recordInteraction: false
|
||||
recordInteraction: false,
|
||||
pendingStartup: { command: 'codex' }
|
||||
})
|
||||
expect(setActiveView).not.toHaveBeenCalled()
|
||||
expect(setActiveWorktree).not.toHaveBeenCalled()
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
createdTabOptions,
|
||||
createLaunchFunnelStore,
|
||||
hostLaunchRequest,
|
||||
queuedStartupCommand,
|
||||
queuedStartupPayload,
|
||||
resetLaunchFunnelStore
|
||||
} from './agent-launch-funnel-test-harness'
|
||||
@@ -143,10 +144,6 @@ describe('agent launch caller placement and telemetry', () => {
|
||||
'tab-1',
|
||||
profile.args.initialCwd
|
||||
)
|
||||
// Ordering matters: the pane snapshots the queued cwd on first render.
|
||||
expect(store.queueTabInitialCwd.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
store.queueTabStartupCommand.mock.invocationCallOrder[0] ?? Number.MAX_SAFE_INTEGER
|
||||
)
|
||||
return
|
||||
}
|
||||
expect(store.queueTabInitialCwd).not.toHaveBeenCalled()
|
||||
@@ -173,16 +170,15 @@ describe('agent launch caller placement and telemetry', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('creates the tab before queueing its startup command', async () => {
|
||||
it('publishes the tab together with its startup command', async () => {
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
launchAgentInNewTab({ requestId: 'request-2', agent: 'codex', worktreeId: 'wt-1' })
|
||||
|
||||
// Why: the terminal pane snapshots pending startup in useState on first render, so a startup
|
||||
// queued after mount is never seen.
|
||||
expect(store.createTab.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
store.queueTabStartupCommand.mock.invocationCallOrder[0] ?? 0
|
||||
)
|
||||
// Why: the terminal pane snapshots pending startup in useState on first render, so the tab
|
||||
// must never exist without its startup command.
|
||||
expect(store.createTab).toHaveBeenCalledTimes(1)
|
||||
expect(queuedStartupCommand(store)).toEqual(expect.any(String))
|
||||
})
|
||||
|
||||
it('seeds working status for a Command Code prompt that rides argv', async () => {
|
||||
|
||||
@@ -11,7 +11,11 @@ import {
|
||||
callerProfileCases,
|
||||
type AgentLaunchCallerProfile
|
||||
} from './agent-launch-caller-profiles-test-harness'
|
||||
import { createLaunchFunnelStore, resetLaunchFunnelStore } from './agent-launch-funnel-test-harness'
|
||||
import {
|
||||
createLaunchFunnelStore,
|
||||
queuedStartupCommand,
|
||||
resetLaunchFunnelStore
|
||||
} from './agent-launch-funnel-test-harness'
|
||||
|
||||
import type * as LaunchAdmissionModule from './structured-agent-session-launch-admission'
|
||||
const store = createLaunchFunnelStore()
|
||||
@@ -270,10 +274,7 @@ describe('agent launch caller routing', () => {
|
||||
await expect(result?.structuredSettlement).resolves.toEqual({ kind: 'terminal' })
|
||||
expect(store.createTab).toHaveBeenCalledOnce()
|
||||
expect(store.createTab.mock.calls[0]?.slice(0, 2)).toEqual(['wt-1', 'group-1'])
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledOnce()
|
||||
expect(store.queueTabStartupCommand.mock.calls[0]?.[1]?.command).toBe(
|
||||
"claude '--model' 'sonnet'"
|
||||
)
|
||||
expect(queuedStartupCommand(store)).toBe("claude '--model' 'sonnet'")
|
||||
// The typed prompt goes to that terminal once, and the caller hears it arrived.
|
||||
await expect(result?.promptDeliveryResult).resolves.toEqual({
|
||||
delivered: true,
|
||||
@@ -339,7 +340,6 @@ describe('agent launch caller routing', () => {
|
||||
expect(result).toBeNull()
|
||||
expect(beforeSurfaceOpen).toHaveBeenCalledExactlyOnceWith({ kind: 'local-terminal' })
|
||||
expect(store.createTab).not.toHaveBeenCalled()
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('aborts a host-published open when beforeSurfaceOpen refuses', async () => {
|
||||
|
||||
@@ -45,7 +45,6 @@ export function createLaunchFunnelStore(): {
|
||||
tabBarOrderByWorktree: Record<string, string[]>
|
||||
createTab: ReturnType<typeof vi.fn>
|
||||
queueTabInitialCwd: ReturnType<typeof vi.fn>
|
||||
queueTabStartupCommand: ReturnType<typeof vi.fn>
|
||||
setActiveTabType: ReturnType<typeof vi.fn>
|
||||
setTabBarOrder: ReturnType<typeof vi.fn>
|
||||
setAgentStatus: ReturnType<typeof vi.fn>
|
||||
@@ -65,7 +64,6 @@ export function createLaunchFunnelStore(): {
|
||||
tabBarOrderByWorktree: {},
|
||||
createTab: vi.fn(),
|
||||
queueTabInitialCwd: vi.fn(),
|
||||
queueTabStartupCommand: vi.fn(),
|
||||
setActiveTabType: vi.fn(),
|
||||
setTabBarOrder: vi.fn(),
|
||||
setAgentStatus: vi.fn(),
|
||||
@@ -117,16 +115,18 @@ export function resetLaunchFunnelStore(
|
||||
store.createTab.mockImplementation(createTabInto(store))
|
||||
}
|
||||
|
||||
/** The startup command `queueTabStartupCommand` received, or undefined when no tab was queued. */
|
||||
/** The startup command the window planned for the new tab, or undefined when the host plans it. */
|
||||
export function queuedStartupCommand(store: LaunchFunnelStore): string | undefined {
|
||||
return store.queueTabStartupCommand.mock.calls[0]?.[1]?.command
|
||||
return queuedStartupPayload(store)?.command
|
||||
}
|
||||
|
||||
/** The whole startup-command payload, for callers that assert more than the command string. */
|
||||
/** The whole window-planned startup payload, for callers that assert more than the command string. */
|
||||
export function queuedStartupPayload(
|
||||
store: LaunchFunnelStore
|
||||
): Record<string, unknown> | undefined {
|
||||
return store.queueTabStartupCommand.mock.calls[0]?.[1]
|
||||
): { command?: string; [key: string]: unknown } | undefined {
|
||||
const options: { pendingStartup?: { command?: string; agentLaunch?: unknown } } =
|
||||
store.createTab.mock.calls[0]?.[3] ?? {}
|
||||
return options.pendingStartup?.agentLaunch ? undefined : options.pendingStartup
|
||||
}
|
||||
|
||||
/** The tab-creation options object (`createTab`'s 4th argument). */
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mockCreateTab = vi.fn()
|
||||
const mockQueueTabStartupCommand = vi.fn()
|
||||
/** Startup commands published with the created tabs, in creation order. */
|
||||
function queuedStartups() {
|
||||
return mockCreateTab.mock.calls.flatMap((call) => call[3]?.pendingStartup ?? [])
|
||||
}
|
||||
|
||||
type StoreRepo = {
|
||||
id: string
|
||||
@@ -57,7 +60,6 @@ const store = {
|
||||
ptyIdsByTabId: {} as Record<string, string[]>,
|
||||
createTab: mockCreateTab,
|
||||
closeTab: vi.fn(),
|
||||
queueTabStartupCommand: mockQueueTabStartupCommand,
|
||||
setActiveTabType: vi.fn(),
|
||||
setTabBarOrder: vi.fn(),
|
||||
setAgentStatus: vi.fn(),
|
||||
@@ -112,7 +114,7 @@ async function launchOnLinux(): Promise<void> {
|
||||
}
|
||||
|
||||
function queuedCommand(): string {
|
||||
return mockQueueTabStartupCommand.mock.calls[0]?.[1]?.command
|
||||
return queuedStartups()[0]?.command
|
||||
}
|
||||
|
||||
describe('launchAgentInNewTab execution host resolution', () => {
|
||||
|
||||
@@ -6,7 +6,10 @@ import { setLocalRuntimeCapabilitiesForTests } from '@/runtime/local-runtime-cap
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../shared/constants'
|
||||
|
||||
const mockCreateTab = vi.fn()
|
||||
const mockQueueTabStartupCommand = vi.fn()
|
||||
/** Startup commands published with the created tabs, in creation order. */
|
||||
function queuedStartups() {
|
||||
return mockCreateTab.mock.calls.flatMap((call) => call[3]?.pendingStartup ?? [])
|
||||
}
|
||||
const mockSetActiveTabType = vi.fn()
|
||||
const mockSeedNativeChatAppliedSessionOptions = vi.fn()
|
||||
|
||||
@@ -42,7 +45,6 @@ const store = {
|
||||
tabBarOrderByWorktree: {},
|
||||
createTab: mockCreateTab,
|
||||
queueTabInitialCwd: vi.fn(),
|
||||
queueTabStartupCommand: mockQueueTabStartupCommand,
|
||||
setActiveTabType: mockSetActiveTabType,
|
||||
setTabBarOrder: vi.fn()
|
||||
}
|
||||
@@ -130,7 +132,8 @@ describe('launchAgentInNewTab terminal tab activation', () => {
|
||||
undefined,
|
||||
{
|
||||
launchAgent: 'codex',
|
||||
quickCommandLabel: undefined
|
||||
quickCommandLabel: undefined,
|
||||
pendingStartup: expect.anything()
|
||||
}
|
||||
)
|
||||
expect(mockSetActiveTabType).toHaveBeenCalledExactlyOnceWith(
|
||||
@@ -138,6 +141,6 @@ describe('launchAgentInNewTab terminal tab activation', () => {
|
||||
FLOATING_TERMINAL_WORKTREE_ID
|
||||
)
|
||||
// Chat UI model preferences belong to structured chats, not a terminal fallback.
|
||||
expect(mockQueueTabStartupCommand.mock.calls[0]?.[1]).not.toHaveProperty('sessionOptions')
|
||||
expect(queuedStartups()[0]).not.toHaveProperty('sessionOptions')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,7 +7,10 @@ const mockIsWebRuntimeSessionActive = vi.fn(() => false)
|
||||
const mockCreateWebRuntimeAgentSessionTerminal = vi.fn()
|
||||
const mockCreateWebRuntimeAgentSessionTerminalWithLaunchDraft = vi.fn()
|
||||
const mockCreateTab = vi.fn()
|
||||
const mockQueueTabStartupCommand = vi.fn()
|
||||
/** Startup commands published with the created tabs, in creation order. */
|
||||
function queuedStartups() {
|
||||
return mockCreateTab.mock.calls.flatMap((call) => call[3]?.pendingStartup ?? [])
|
||||
}
|
||||
const mockPasteDraftWhenAgentReady = vi.fn()
|
||||
|
||||
const store = {
|
||||
@@ -67,7 +70,6 @@ const store = {
|
||||
ptyIdsByTabId: {} as Record<string, string[]>,
|
||||
createTab: mockCreateTab,
|
||||
closeTab: vi.fn(),
|
||||
queueTabStartupCommand: mockQueueTabStartupCommand,
|
||||
setActiveTabType: vi.fn(),
|
||||
setTabBarOrder: vi.fn(),
|
||||
setAgentStatus: vi.fn(),
|
||||
@@ -202,8 +204,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
launchPlatform: 'win32'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "claude '--dangerously-skip-permissions' --prefill 'review Bob''s change'"
|
||||
})
|
||||
@@ -221,8 +222,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
launchPlatform: 'win32'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: 'claude "--dangerously-skip-permissions"'
|
||||
})
|
||||
@@ -240,8 +240,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
launchPlatform: 'win32'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "claude '--dangerously-skip-permissions'"
|
||||
})
|
||||
@@ -261,8 +260,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
launchPlatform: 'win32'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: 'codex "--model" "gpt-5" "fix the spinner"',
|
||||
agentArgsOverride: '--model gpt-5'
|
||||
@@ -283,8 +281,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
launchPlatform: 'win32'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: `claude '--dangerously-skip-permissions' --prefill 'review Bob'"'"'s change'`
|
||||
})
|
||||
@@ -301,8 +298,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
|
||||
launchAgentInNewTab({ requestId: 'request-7', agent: 'claude', worktreeId: 'wt-1' })
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "claude '--dangerously-skip-permissions'"
|
||||
})
|
||||
@@ -339,8 +335,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
promptDelivery: 'draft'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: `claude '--dangerously-skip-permissions' --prefill 'review Bob'"'"'s change'`
|
||||
})
|
||||
@@ -374,7 +369,7 @@ describe('launchAgentInNewTab Windows shell quoting', () => {
|
||||
|
||||
launchAgentInNewTab({ requestId: 'request-9', agent: 'codex', worktreeId: 'wt-1' })
|
||||
|
||||
const queued = mockQueueTabStartupCommand.mock.calls.at(-1)?.[1] as { command: string }
|
||||
const queued = queuedStartups().at(-1)
|
||||
expect(queued.command).toContain(`'don'"'"'t'`)
|
||||
expect(queued.command).not.toContain("'don''t'")
|
||||
})
|
||||
|
||||
@@ -4,7 +4,10 @@ import { toAppSshPtyId } from '../../../shared/ssh-pty-id'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../shared/constants'
|
||||
|
||||
const mockCreateTab = vi.fn()
|
||||
const mockQueueTabStartupCommand = vi.fn()
|
||||
/** Startup commands published with the created tabs, in creation order. */
|
||||
function queuedStartups() {
|
||||
return mockCreateTab.mock.calls.flatMap((call) => call[3]?.pendingStartup ?? [])
|
||||
}
|
||||
const mockSetActiveTabType = vi.fn()
|
||||
const mockSetTabViewMode = vi.fn()
|
||||
const mockSetTabBarOrder = vi.fn()
|
||||
@@ -84,7 +87,6 @@ const store = {
|
||||
ptyIdsByTabId: {} as Record<string, string[]>,
|
||||
createTab: mockCreateTab,
|
||||
closeTab: vi.fn(),
|
||||
queueTabStartupCommand: mockQueueTabStartupCommand,
|
||||
setActiveTabType: mockSetActiveTabType,
|
||||
setTabViewMode: mockSetTabViewMode,
|
||||
setTabBarOrder: mockSetTabBarOrder,
|
||||
@@ -215,7 +217,8 @@ describe('launchAgentInNewTab', () => {
|
||||
launchAgentInNewTab({ requestId: 'request-1', agent: 'codex', worktreeId: 'wt-1' })
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
launchAgent: 'codex'
|
||||
launchAgent: 'codex',
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
})
|
||||
it('keeps Floating Workspace authority on native Windows beside an active WSL project', async () => {
|
||||
@@ -241,7 +244,7 @@ describe('launchAgentInNewTab', () => {
|
||||
FLOATING_TERMINAL_WORKTREE_ID,
|
||||
undefined,
|
||||
undefined,
|
||||
{ launchAgent: 'codex' }
|
||||
{ launchAgent: 'codex', pendingStartup: expect.anything() }
|
||||
)
|
||||
})
|
||||
|
||||
@@ -265,10 +268,10 @@ describe('launchAgentInNewTab', () => {
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
launchAgent: 'codex',
|
||||
quickCommandLabel: undefined
|
||||
quickCommandLabel: undefined,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.not.stringContaining('large generated prompt')
|
||||
})
|
||||
@@ -302,7 +305,8 @@ describe('launchAgentInNewTab', () => {
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
launchAgent: 'grok',
|
||||
quickCommandLabel: undefined
|
||||
quickCommandLabel: undefined,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(mockSeedNativeChatLaunchPrompt).toHaveBeenCalledWith({
|
||||
tabId: 'tab-1',
|
||||
@@ -327,7 +331,8 @@ describe('launchAgentInNewTab', () => {
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
launchAgent: 'grok',
|
||||
quickCommandLabel: undefined
|
||||
quickCommandLabel: undefined,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -398,7 +403,8 @@ describe('launchAgentInNewTab', () => {
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
launchAgent: 'codex',
|
||||
quickCommandLabel: 'Review'
|
||||
quickCommandLabel: 'Review',
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -427,7 +433,7 @@ describe('launchAgentInNewTab', () => {
|
||||
quickCommandLabel: 'Review'
|
||||
})
|
||||
|
||||
const launch = mockQueueTabStartupCommand.mock.calls[0]?.[1]
|
||||
const launch = queuedStartups()[0]
|
||||
expect(launch.command).toContain("'--profile' 'team'")
|
||||
expect(launch.command).not.toContain("'-m'")
|
||||
expect(launch.command).not.toContain('model_reasoning_effort=')
|
||||
@@ -459,7 +465,7 @@ describe('launchAgentInNewTab', () => {
|
||||
quickCommandLabel: 'Review'
|
||||
})
|
||||
|
||||
const launch = mockQueueTabStartupCommand.mock.calls[0]?.[1]
|
||||
const launch = queuedStartups()[0]
|
||||
expect(launch.command).not.toContain("'-m'")
|
||||
expect(launch.command).not.toContain('model_reasoning_effort=')
|
||||
expect(launch.sessionOptions).toBeUndefined()
|
||||
@@ -597,8 +603,7 @@ describe('launchAgentInNewTab', () => {
|
||||
prompt: 'fix the spinner'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "command-code --trust '--yolo' 'fix the spinner'",
|
||||
initialAgentStatus: {
|
||||
@@ -637,8 +642,7 @@ describe('launchAgentInNewTab', () => {
|
||||
})
|
||||
|
||||
expect(result).not.toHaveProperty('promptDeliveryResult')
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "claude '--dangerously-skip-permissions'"
|
||||
})
|
||||
@@ -704,8 +708,7 @@ describe('launchAgentInNewTab', () => {
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "command-code --trust '--yolo'"
|
||||
})
|
||||
@@ -885,8 +888,7 @@ describe('launchAgentInNewTab', () => {
|
||||
promptDelivery: 'submit-after-ready'
|
||||
})
|
||||
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(queuedStartups()).toContainEqual(
|
||||
expect.objectContaining({
|
||||
command: "codex '--model' 'gpt-5.5'"
|
||||
})
|
||||
|
||||
@@ -265,35 +265,34 @@ function launchAgentInNewTabInternal(args: LaunchAgentInNewTabArgs): LaunchAgent
|
||||
promptDeliveryResult: launched.promptDeliveryResult
|
||||
}
|
||||
}
|
||||
// Why: queue startup BEFORE TerminalPane mounts — it snapshots pendingStartupByTabId in useState on first render.
|
||||
const tab = store.createTab(worktreeId, groupId, undefined, {
|
||||
launchAgent: agent,
|
||||
quickCommandLabel,
|
||||
...(pendingActivationSpawn ? { pendingActivationSpawn: true } : {}),
|
||||
...(activate === false ? { activate: false } : {})
|
||||
...(activate === false ? { activate: false } : {}),
|
||||
pendingStartup: {
|
||||
command: startupPlan.launchCommand,
|
||||
...(startupPlan.env ? { env: startupPlan.env } : {}),
|
||||
launchConfig: startupPlan.launchConfig,
|
||||
launchAgent: agent,
|
||||
...(agentArgs !== undefined ? { agentArgsOverride: agentArgs } : {}),
|
||||
...(startupPlan.startupCommandDelivery
|
||||
? { startupCommandDelivery: startupPlan.startupCommandDelivery }
|
||||
: {}),
|
||||
...(agent === 'command-code' && hasPrompt && promptDelivery === 'auto-submit'
|
||||
? { initialAgentStatus: { agent, prompt: trimmedPrompt } }
|
||||
: {}),
|
||||
telemetry: {
|
||||
agent_kind: tuiAgentToAgentKind(agent),
|
||||
launch_source: launchSource ?? 'tab_bar_quick_launch',
|
||||
request_kind: 'new'
|
||||
}
|
||||
}
|
||||
})
|
||||
if (initialCwd?.trim()) {
|
||||
// Why: queue before mount so local, WSL, and SSH continuations preserve their subdirectory.
|
||||
store.queueTabInitialCwd(tab.id, initialCwd)
|
||||
}
|
||||
store.queueTabStartupCommand(tab.id, {
|
||||
command: startupPlan.launchCommand,
|
||||
...(startupPlan.env ? { env: startupPlan.env } : {}),
|
||||
launchConfig: startupPlan.launchConfig,
|
||||
launchAgent: agent,
|
||||
...(agentArgs !== undefined ? { agentArgsOverride: agentArgs } : {}),
|
||||
...(startupPlan.startupCommandDelivery
|
||||
? { startupCommandDelivery: startupPlan.startupCommandDelivery }
|
||||
: {}),
|
||||
...(agent === 'command-code' && hasPrompt && promptDelivery === 'auto-submit'
|
||||
? { initialAgentStatus: { agent, prompt: trimmedPrompt } }
|
||||
: {}),
|
||||
telemetry: {
|
||||
agent_kind: tuiAgentToAgentKind(agent),
|
||||
launch_source: launchSource ?? 'tab_bar_quick_launch',
|
||||
request_kind: 'new'
|
||||
}
|
||||
})
|
||||
// Why: fire-and-forget the paste-after-ready delivery so callers keep the synchronous { tabId, startupPlan } signature.
|
||||
// Why: safe to call unconditionally — the helper short-circuits (no paste) for native-prefill agents already holding the draft.
|
||||
if (hasPrompt && promptDelivery === 'draft' && pasteDraftAfterLaunch === null) {
|
||||
|
||||
@@ -3,7 +3,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
const mockCreateTab = vi.fn()
|
||||
const mockCreateEmptySplitGroup = vi.fn()
|
||||
const mockCloseEmptyGroup = vi.fn()
|
||||
const mockQueueTabStartupCommand = vi.fn()
|
||||
/** Startup commands published with the created tabs, in creation order. */
|
||||
function queuedStartups() {
|
||||
return mockCreateTab.mock.calls.flatMap((call) => call[3]?.pendingStartup ?? [])
|
||||
}
|
||||
const mockSetActiveTabType = vi.fn()
|
||||
const mockSetTabBarOrder = vi.fn()
|
||||
const runtimeMocks = vi.hoisted(() => ({
|
||||
@@ -16,7 +19,6 @@ const mockState = {
|
||||
createTab: mockCreateTab,
|
||||
createEmptySplitGroup: mockCreateEmptySplitGroup,
|
||||
closeEmptyGroup: mockCloseEmptyGroup,
|
||||
queueTabStartupCommand: mockQueueTabStartupCommand,
|
||||
setActiveTabType: mockSetActiveTabType,
|
||||
setTabBarOrder: mockSetTabBarOrder,
|
||||
tabsByWorktree: {} as Record<string, { id: string }[]>,
|
||||
@@ -83,8 +85,10 @@ describe('launchAiVaultSessionInNewTab', () => {
|
||||
command: 'claude --resume session-1'
|
||||
})
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', 'group-1')
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', 'group-1', undefined, {
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(queuedStartups()).toContainEqual({
|
||||
command: 'claude --resume session-1',
|
||||
telemetry: {
|
||||
agent_kind: 'claude',
|
||||
@@ -115,9 +119,10 @@ describe('launchAiVaultSessionInNewTab', () => {
|
||||
})
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
startupCwd: 'C:\\Users\\alice\\repo'
|
||||
startupCwd: 'C:\\Users\\alice\\repo',
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(mockQueueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(queuedStartups()).toContainEqual({
|
||||
command: "claude '--dangerously-skip-permissions' '--effort' 'max' '--resume' 'session-1'",
|
||||
env: { ANTHROPIC_BASE_URL: 'https://claude.example.test' },
|
||||
envToDelete: ['CODEX_HOME'],
|
||||
@@ -146,7 +151,9 @@ describe('launchAiVaultSessionInNewTab', () => {
|
||||
})
|
||||
|
||||
expect(mockCreateEmptySplitGroup).toHaveBeenCalledWith('wt-1', 'group-1', 'right')
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', 'group-new')
|
||||
expect(mockCreateTab).toHaveBeenCalledWith('wt-1', 'group-new', undefined, {
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
})
|
||||
|
||||
it('creates runtime-hosted resume terminals through the paired host', async () => {
|
||||
@@ -188,7 +195,7 @@ describe('launchAiVaultSessionInNewTab', () => {
|
||||
activate: true
|
||||
})
|
||||
expect(mockCreateTab).not.toHaveBeenCalled()
|
||||
expect(mockQueueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(queuedStartups()).toEqual([])
|
||||
|
||||
if (result.tabId === null) {
|
||||
await expect(result.runtimeLaunch).resolves.toEqual({ status: 'created' })
|
||||
|
||||
@@ -69,19 +69,19 @@ export function launchAiVaultSessionInNewTab(args: {
|
||||
}
|
||||
}
|
||||
|
||||
const tab = args.cwd
|
||||
? store.createTab(args.worktreeId, targetGroupId, undefined, { startupCwd: args.cwd })
|
||||
: store.createTab(args.worktreeId, targetGroupId)
|
||||
store.queueTabStartupCommand(tab.id, {
|
||||
command: args.command,
|
||||
...(args.env ? { env: args.env } : {}),
|
||||
...(args.envToDelete ? { envToDelete: args.envToDelete } : {}),
|
||||
...(args.launchConfig ? { launchConfig: args.launchConfig, launchAgent: args.agent } : {}),
|
||||
...(args.providerSession ? { resumeProviderSession: args.providerSession } : {}),
|
||||
telemetry: {
|
||||
agent_kind: tuiAgentToAgentKind(args.agent),
|
||||
launch_source: 'sidebar',
|
||||
request_kind: 'resume'
|
||||
const tab = store.createTab(args.worktreeId, targetGroupId, undefined, {
|
||||
...(args.cwd ? { startupCwd: args.cwd } : {}),
|
||||
pendingStartup: {
|
||||
command: args.command,
|
||||
...(args.env ? { env: args.env } : {}),
|
||||
...(args.envToDelete ? { envToDelete: args.envToDelete } : {}),
|
||||
...(args.launchConfig ? { launchConfig: args.launchConfig, launchAgent: args.agent } : {}),
|
||||
...(args.providerSession ? { resumeProviderSession: args.providerSession } : {}),
|
||||
telemetry: {
|
||||
agent_kind: tuiAgentToAgentKind(args.agent),
|
||||
launch_source: 'sidebar',
|
||||
request_kind: 'resume'
|
||||
}
|
||||
}
|
||||
})
|
||||
store.setActiveTabType('terminal', args.worktreeId)
|
||||
|
||||
@@ -3,7 +3,6 @@ import { runQuickCommandInNewTab } from './run-quick-command-in-new-tab'
|
||||
|
||||
type MockStoreState = {
|
||||
createTab: ReturnType<typeof vi.fn>
|
||||
queueTabStartupCommand: ReturnType<typeof vi.fn>
|
||||
setActiveTabType: ReturnType<typeof vi.fn>
|
||||
setTabBarOrder: ReturnType<typeof vi.fn>
|
||||
setRecentQuickCommandForGroup: ReturnType<typeof vi.fn>
|
||||
@@ -37,7 +36,6 @@ vi.mock('@/lib/launch-agent-in-new-tab', () => ({
|
||||
function createStoreState(): MockStoreState {
|
||||
return {
|
||||
createTab: vi.fn(() => ({ id: 'tab-new' })),
|
||||
queueTabStartupCommand: vi.fn(),
|
||||
setActiveTabType: vi.fn(),
|
||||
setTabBarOrder: vi.fn(),
|
||||
setRecentQuickCommandForGroup: vi.fn(),
|
||||
@@ -73,10 +71,8 @@ describe('runQuickCommandInNewTab', () => {
|
||||
|
||||
expect(result).toEqual({ tabId: 'tab-new' })
|
||||
expect(mockState.createTab).toHaveBeenCalledWith('wt-1', 'group-1', undefined, {
|
||||
quickCommandLabel: 'Build'
|
||||
})
|
||||
expect(mockState.queueTabStartupCommand).toHaveBeenCalledWith('tab-new', {
|
||||
command: 'cd packages; bun run build; cd ..'
|
||||
quickCommandLabel: 'Build',
|
||||
pendingStartup: { command: 'cd packages; bun run build; cd ..' }
|
||||
})
|
||||
expect(mockState.setRecentQuickCommandForGroup).toHaveBeenCalledWith('group-1', 'build')
|
||||
})
|
||||
@@ -139,8 +135,9 @@ describe('runQuickCommandInNewTab', () => {
|
||||
groupId: 'group-1'
|
||||
})
|
||||
|
||||
expect(mockState.queueTabStartupCommand).toHaveBeenCalledWith('tab-new', {
|
||||
command: 'git status'
|
||||
expect(mockState.createTab).toHaveBeenCalledWith('wt-1', 'group-1', undefined, {
|
||||
quickCommandLabel: 'Status',
|
||||
pendingStartup: { command: 'git status' }
|
||||
})
|
||||
})
|
||||
|
||||
@@ -174,7 +171,7 @@ describe('runQuickCommandInNewTab', () => {
|
||||
launchSource: 'quick_command',
|
||||
quickCommandLabel: 'Review'
|
||||
})
|
||||
expect(mockState.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(mockState.createTab).not.toHaveBeenCalled()
|
||||
expect(mockState.setRecentQuickCommandForGroup).toHaveBeenCalledWith('group-1', 'agent-review')
|
||||
})
|
||||
|
||||
@@ -330,6 +327,6 @@ describe('runQuickCommandInNewTab', () => {
|
||||
|
||||
expect(result).toBeNull()
|
||||
expect(mocks.launchAgentInNewTab).not.toHaveBeenCalled()
|
||||
expect(mockState.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(mockState.createTab).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -103,11 +103,8 @@ export function runQuickCommandInNewTab({
|
||||
}
|
||||
const store = useAppStore.getState()
|
||||
const tab = store.createTab(worktreeId, targetGroupId, undefined, {
|
||||
quickCommandLabel: command.label
|
||||
})
|
||||
|
||||
store.queueTabStartupCommand(tab.id, {
|
||||
command: flattenTerminalQuickCommand(command).command
|
||||
quickCommandLabel: command.label,
|
||||
pendingStartup: { command: flattenTerminalQuickCommand(command).command }
|
||||
})
|
||||
|
||||
// Why: match `+` button's createNewTerminalTab — without this, a worktree
|
||||
|
||||
@@ -2,7 +2,8 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-seeding'
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset
|
||||
registerWorktreeActivationReset,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
|
||||
registerWorktreeActivationReset()
|
||||
@@ -20,10 +21,11 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true
|
||||
})
|
||||
expect(store.setActiveTab).toHaveBeenCalledWith('tab-1')
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'claude "Fix this bug"'
|
||||
})
|
||||
expect(store.queueTabSetupSplit).not.toHaveBeenCalled()
|
||||
@@ -49,10 +51,11 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
launchAgent: 'claude'
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'claude',
|
||||
launchAgent: 'claude'
|
||||
})
|
||||
@@ -82,6 +85,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
launchAgent: 'claude',
|
||||
...expectedViewMode
|
||||
@@ -114,6 +118,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
launchAgent: 'claude',
|
||||
...expectedViewMode
|
||||
@@ -141,6 +146,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(createTab).toHaveBeenNthCalledWith(1, 'wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
launchAgent: 'claude'
|
||||
@@ -173,6 +179,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(createTab).toHaveBeenNthCalledWith(1, 'wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
launchAgent: 'claude',
|
||||
@@ -200,10 +207,11 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
launchAgent: 'claude'
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'claude',
|
||||
telemetry: {
|
||||
agent_kind: 'claude-code',
|
||||
@@ -228,10 +236,11 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
)
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingStartup: expect.anything(),
|
||||
pendingActivationSpawn: true,
|
||||
launchAgent: 'codex'
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'codex',
|
||||
launchAgent: 'codex'
|
||||
})
|
||||
|
||||
@@ -2,7 +2,8 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-seeding'
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset
|
||||
registerWorktreeActivationReset,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
|
||||
registerWorktreeActivationReset()
|
||||
@@ -17,7 +18,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
pendingActivationSpawn: true
|
||||
})
|
||||
expect(store.setActiveTab).toHaveBeenCalledWith('tab-1')
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(createdTabStartups(store)).toEqual({})
|
||||
expect(store.queueTabSetupSplit).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -39,9 +40,10 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
ensureWorktreeHasInitialTerminal(store, 'wt-1', { command: 'claude "Fix this bug"' })
|
||||
|
||||
expect(store.createTab).toHaveBeenCalledWith('wt-1', undefined, undefined, {
|
||||
pendingActivationSpawn: true
|
||||
pendingActivationSpawn: true,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'claude "Fix this bug"'
|
||||
})
|
||||
})
|
||||
@@ -71,7 +73,8 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(createTab).toHaveBeenCalledTimes(2)
|
||||
expect(createTab).toHaveBeenNthCalledWith(1, 'wt-1', undefined, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false
|
||||
recordInteraction: false,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-1', 'Claude', {
|
||||
recordInteraction: false
|
||||
@@ -81,8 +84,8 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
})
|
||||
expect(store.setTabColor).toHaveBeenCalledWith('tab-1', '#f97316')
|
||||
expect(store.setTabColor).toHaveBeenCalledWith('tab-2', '#9ca3af')
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', { command: 'claude' })
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', { command: 'pnpm dev' })
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({ command: 'claude' })
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({ command: 'pnpm dev' })
|
||||
expect(store.setActiveTab).toHaveBeenLastCalledWith('tab-1')
|
||||
})
|
||||
|
||||
@@ -111,18 +114,20 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(createTab).toHaveBeenNthCalledWith(1, 'wt-1', undefined, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
activate: false
|
||||
activate: false,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(createTab).toHaveBeenNthCalledWith(2, 'wt-1', undefined, undefined, {
|
||||
recordInteraction: false,
|
||||
activate: false
|
||||
activate: false,
|
||||
pendingStartup: expect.anything()
|
||||
})
|
||||
expect(store.setActiveTab).not.toHaveBeenCalled()
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-2', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', { command: 'pnpm dev' })
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({ command: 'pnpm dev' })
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: { ORCA_WORKTREE_PATH: '/tmp/worktrees/wt-1' }
|
||||
})
|
||||
@@ -136,7 +141,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
tabs: [{ title: 'Server', command: 'pnpm dev' }]
|
||||
})
|
||||
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(createdTabStartups(store)).toEqual({})
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-1', 'Server', {
|
||||
recordInteraction: false
|
||||
})
|
||||
@@ -159,7 +164,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(store.setTabCustomTitle).not.toHaveBeenCalledWith('tab-1', 'Claude', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).not.toEqual({
|
||||
command: 'claude'
|
||||
})
|
||||
})
|
||||
@@ -176,7 +181,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
|
||||
expect(store.createTab).not.toHaveBeenCalled()
|
||||
expect(store.setActiveTab).not.toHaveBeenCalled()
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(createdTabStartups(store)).toEqual({})
|
||||
expect(store.queueTabSetupSplit).not.toHaveBeenCalled()
|
||||
expect(store.queueTabIssueCommandSplit).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
@@ -3,7 +3,8 @@ import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-se
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset,
|
||||
setSetupScriptLaunchMode
|
||||
setSetupScriptLaunchMode,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
|
||||
registerWorktreeActivationReset()
|
||||
@@ -67,7 +68,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(createdTabStartups(store)).toEqual({})
|
||||
expect(store.queueTabSetupSplit).toHaveBeenCalledWith('tab-1', {
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: { ORCA_ROOT_PATH: '/tmp/repo' },
|
||||
@@ -84,7 +85,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
|
||||
ensureWorktreeHasInitialTerminal(store, 'wt-1')
|
||||
|
||||
expect(store.queueTabStartupCommand).not.toHaveBeenCalled()
|
||||
expect(createdTabStartups(store)).toEqual({})
|
||||
expect(store.queueTabIssueCommandSplit).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -64,7 +64,6 @@ describe('activateAndRevealWorktree', () => {
|
||||
setTabCustomTitle: vi.fn(),
|
||||
setTabColor: vi.fn(),
|
||||
markDefaultTerminalTabsApplied: vi.fn(),
|
||||
queueTabStartupCommand: vi.fn(),
|
||||
queueTabInitialCwd,
|
||||
queueTabSetupSplit: vi.fn(),
|
||||
queueTabIssueCommandSplit: vi.fn(),
|
||||
@@ -134,7 +133,6 @@ describe('activateAndRevealWorktree', () => {
|
||||
setTabCustomTitle: vi.fn(),
|
||||
setTabColor: vi.fn(),
|
||||
markDefaultTerminalTabsApplied: vi.fn(),
|
||||
queueTabStartupCommand: vi.fn(),
|
||||
queueTabInitialCwd: vi.fn(),
|
||||
queueTabSetupSplit: vi.fn(),
|
||||
queueTabIssueCommandSplit: vi.fn(),
|
||||
|
||||
@@ -4,7 +4,8 @@ import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-se
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset,
|
||||
setSetupScriptLaunchMode
|
||||
setSetupScriptLaunchMode,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
|
||||
registerWorktreeActivationReset()
|
||||
@@ -29,7 +30,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-2', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: {
|
||||
ORCA_ROOT_PATH: '/tmp/repo',
|
||||
@@ -53,7 +54,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
})
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /c/repo/.git/orca/setup-runner.sh',
|
||||
env: {
|
||||
ORCA_ROOT_PATH: 'C:\\repo',
|
||||
@@ -83,7 +84,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-2', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash -lc wrapped-setup',
|
||||
env: { ORCA_ROOT_PATH: '/tmp/repo' }
|
||||
})
|
||||
@@ -112,14 +113,12 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
|
||||
expect(result).toBe('tab-1')
|
||||
expect(createTab).toHaveBeenCalledTimes(1)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('bash /tmp/repo/.git/orca/setup-runner.sh')
|
||||
})
|
||||
)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('printf')
|
||||
})
|
||||
@@ -141,7 +140,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
})
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /mnt/c/repo/.git/orca/setup-runner.sh',
|
||||
env: {
|
||||
ORCA_ROOT_PATH: 'C:\\repo',
|
||||
@@ -167,8 +166,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual(
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
[SETUP_AGENT_SEQUENCE_STARTUP_SCRIPT_ENV]: expect.stringContaining(
|
||||
@@ -177,22 +175,19 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
})
|
||||
})
|
||||
)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual(
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
[SETUP_AGENT_SEQUENCE_STARTUP_SCRIPT_ENV]: expect.stringContaining('exec claude')
|
||||
})
|
||||
})
|
||||
)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('printf')
|
||||
})
|
||||
)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('bash /tmp/repo/.git/orca/setup-runner.sh')
|
||||
})
|
||||
@@ -216,10 +211,10 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'claude'
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: { ORCA_ROOT_PATH: '/tmp/repo' }
|
||||
})
|
||||
@@ -240,8 +235,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual(
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
[SETUP_AGENT_SEQUENCE_STARTUP_SCRIPT_ENV]: expect.stringContaining('exec claude')
|
||||
@@ -276,8 +270,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-1',
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual(
|
||||
expect.objectContaining({
|
||||
env: expect.objectContaining({
|
||||
[SETUP_AGENT_SEQUENCE_STARTUP_SCRIPT_ENV]: expect.stringContaining(
|
||||
@@ -344,7 +337,7 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-2', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-2', {
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual({
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: { ORCA_ROOT_PATH: '/tmp/repo' }
|
||||
})
|
||||
|
||||
@@ -24,6 +24,18 @@ export type WorktreeActivationStore = Partial<WorktreeRuntimeOwnerState> & {
|
||||
recordInteraction?: boolean
|
||||
viewMode?: Tab['viewMode']
|
||||
activate?: boolean
|
||||
pendingStartup?: {
|
||||
command: string
|
||||
env?: Record<string, string>
|
||||
launchConfig?: SleepingAgentLaunchConfig
|
||||
resumeProviderSession?: AgentProviderSessionMetadata
|
||||
launchToken?: string
|
||||
launchAgent?: TuiAgent
|
||||
draftPrompt?: string
|
||||
initialAgentStatus?: { agent: TuiAgent; prompt: string }
|
||||
showSessionRestoredBanner?: boolean
|
||||
telemetry?: AgentStartedTelemetry
|
||||
}
|
||||
}
|
||||
) => { id: string }
|
||||
setActiveTab: (tabId: string) => void
|
||||
@@ -35,21 +47,6 @@ export type WorktreeActivationStore = Partial<WorktreeRuntimeOwnerState> & {
|
||||
setTabColor: (tabId: string, color: string | null) => void
|
||||
markDefaultTerminalTabsApplied: (worktreeId: string) => void
|
||||
reconcileWorktreeTabModel: (worktreeId: string) => { renderableTabCount: number }
|
||||
queueTabStartupCommand: (
|
||||
tabId: string,
|
||||
startup: {
|
||||
command: string
|
||||
env?: Record<string, string>
|
||||
launchConfig?: SleepingAgentLaunchConfig
|
||||
resumeProviderSession?: AgentProviderSessionMetadata
|
||||
launchToken?: string
|
||||
launchAgent?: TuiAgent
|
||||
draftPrompt?: string
|
||||
initialAgentStatus?: { agent: TuiAgent; prompt: string }
|
||||
showSessionRestoredBanner?: boolean
|
||||
telemetry?: AgentStartedTelemetry
|
||||
}
|
||||
) => void
|
||||
queueTabSetupSplit: (
|
||||
tabId: string,
|
||||
startup: { command: string; env?: Record<string, string>; direction: SetupSplitDirection }
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset,
|
||||
setSetupScriptLaunchMode
|
||||
setSetupScriptLaunchMode,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
|
||||
const initialAppStoreState = useAppStore.getState()
|
||||
@@ -49,7 +50,7 @@ describe('seeding beside a caller-provided chat surface', () => {
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-1', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith('tab-1', {
|
||||
expect(createdTabStartups(store)['tab-1']).toEqual({
|
||||
command: 'bash /tmp/repo/.git/orca/setup-runner.sh',
|
||||
env: setup.envVars
|
||||
})
|
||||
|
||||
@@ -46,13 +46,12 @@ export function registerWorktreeActivationReset(): void {
|
||||
export type MockActivationStore = {
|
||||
tabsByWorktree: Record<string, { id: string }[]>
|
||||
defaultTerminalTabsAppliedByWorktreeId: Record<string, true>
|
||||
createTab: Mock<() => { id: string }>
|
||||
createTab: Mock<(...args: unknown[]) => { id: string }>
|
||||
setActiveTab: Mock<() => void>
|
||||
setTabCustomTitle: Mock<() => void>
|
||||
setTabColor: Mock<() => void>
|
||||
markDefaultTerminalTabsApplied: Mock<() => void>
|
||||
reconcileWorktreeTabModel: Mock<() => { renderableTabCount: number }>
|
||||
queueTabStartupCommand: Mock<() => void>
|
||||
queueTabInitialCwd: Mock<() => void>
|
||||
queueTabSetupSplit: Mock<() => void>
|
||||
queueTabIssueCommandSplit: Mock<() => void>
|
||||
@@ -68,10 +67,27 @@ export function createMockStore(overrides: Record<string, unknown> = {}): MockAc
|
||||
setTabColor: vi.fn(),
|
||||
markDefaultTerminalTabsApplied: vi.fn(),
|
||||
reconcileWorktreeTabModel: vi.fn(() => ({ renderableTabCount: 0 })),
|
||||
queueTabStartupCommand: vi.fn(),
|
||||
queueTabInitialCwd: vi.fn(),
|
||||
queueTabSetupSplit: vi.fn(),
|
||||
queueTabIssueCommandSplit: vi.fn(),
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
/** The startup command each created tab was published with, keyed by the created tab's id. */
|
||||
export function createdTabStartups(store: MockActivationStore): Record<string, unknown> {
|
||||
const startups: Record<string, unknown> = {}
|
||||
store.createTab.mock.calls.forEach((call, index) => {
|
||||
const result = store.createTab.mock.results[index]
|
||||
const options = call[3]
|
||||
if (
|
||||
result?.type === 'return' &&
|
||||
options &&
|
||||
typeof options === 'object' &&
|
||||
'pendingStartup' in options
|
||||
) {
|
||||
startups[result.value.id] = options.pendingStartup
|
||||
}
|
||||
})
|
||||
return startups
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import { ensureWorktreeHasInitialTerminal } from './worktree-initial-terminal-se
|
||||
import type { AppStoreState } from './worktree-activation-test-harness'
|
||||
import {
|
||||
createMockStore,
|
||||
registerWorktreeActivationReset
|
||||
registerWorktreeActivationReset,
|
||||
createdTabStartups
|
||||
} from './worktree-activation-test-harness'
|
||||
import { useAppStore } from '@/store'
|
||||
import {
|
||||
@@ -299,14 +300,12 @@ describe('ensureWorktreeHasInitialTerminal', () => {
|
||||
expect(store.setTabCustomTitle).toHaveBeenCalledWith('tab-2', 'Setup', {
|
||||
recordInteraction: false
|
||||
})
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('bash /tmp/repo/.git/orca/setup-runner.sh')
|
||||
})
|
||||
)
|
||||
expect(store.queueTabStartupCommand).toHaveBeenCalledWith(
|
||||
'tab-2',
|
||||
expect(createdTabStartups(store)['tab-2']).toEqual(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('printf')
|
||||
})
|
||||
|
||||
@@ -41,25 +41,31 @@ export function applyDefaultTerminalTabs(
|
||||
: isStartupTab && startup?.telemetry
|
||||
? (agentKindToTuiAgent(startup.telemetry.agent_kind) ?? undefined)
|
||||
: undefined
|
||||
const templateCommand = template.command?.trim()
|
||||
const pendingStartup = isStartupTab
|
||||
? startup
|
||||
: templateCommand && defaultTabs.runCommands
|
||||
? { command: templateCommand }
|
||||
: undefined
|
||||
const tab = store.createTab(worktreeId, undefined, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
recordInteraction: false,
|
||||
...(launchAgent ? { launchAgent } : {}),
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {})
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {}),
|
||||
...(pendingStartup ? { pendingStartup } : {})
|
||||
})
|
||||
if (index === 0) {
|
||||
firstTabId = tab.id
|
||||
}
|
||||
if (isStartupTab && launchAgent) {
|
||||
seedNativeChatAppliedSessionOptions(tab.id, launchAgent, startup.sessionOptions)
|
||||
}
|
||||
if (template.title) {
|
||||
store.setTabCustomTitle(tab.id, template.title, { recordInteraction: false })
|
||||
}
|
||||
if (template.color) {
|
||||
store.setTabColor(tab.id, template.color)
|
||||
}
|
||||
const templateCommand = template.command?.trim()
|
||||
if (templateCommand && defaultTabs.runCommands && !(index === 0 && startup)) {
|
||||
store.queueTabStartupCommand(tab.id, { command: templateCommand })
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstTabId) {
|
||||
@@ -68,17 +74,6 @@ export function applyDefaultTerminalTabs(
|
||||
if (opts?.activateCreatedTabs !== false) {
|
||||
store.setActiveTab(firstTabId)
|
||||
}
|
||||
if (startup) {
|
||||
const startupAgent =
|
||||
startup.launchAgent ??
|
||||
(startup.telemetry
|
||||
? (agentKindToTuiAgent(startup.telemetry.agent_kind) ?? undefined)
|
||||
: undefined)
|
||||
if (startupAgent) {
|
||||
seedNativeChatAppliedSessionOptions(firstTabId, startupAgent, startup.sessionOptions)
|
||||
}
|
||||
store.queueTabStartupCommand(firstTabId, startup)
|
||||
}
|
||||
queueSetupAndIssueCommands(
|
||||
store,
|
||||
worktreeId,
|
||||
|
||||
@@ -281,22 +281,19 @@ export function ensureWorktreeHasInitialTerminal(
|
||||
const terminalTab = store.createTab(worktreeId, undefined, undefined, {
|
||||
pendingActivationSpawn: true,
|
||||
...(launchAgent ? { launchAgent } : {}),
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {})
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {}),
|
||||
// Why: the initial pane begins in the requested agent session instead of an idle shell.
|
||||
...(sequencedStartup ? { pendingStartup: sequencedStartup } : {})
|
||||
})
|
||||
if (opts?.activateCreatedTabs !== false) {
|
||||
store.setActiveTab(terminalTab.id)
|
||||
}
|
||||
|
||||
// Why: queue the seeded startup on the initial pane so the terminal begins in the requested agent session instead of an idle shell.
|
||||
if (sequencedStartup) {
|
||||
if (launchAgent) {
|
||||
seedNativeChatAppliedSessionOptions(
|
||||
terminalTab.id,
|
||||
launchAgent,
|
||||
sequencedStartup.sessionOptions
|
||||
)
|
||||
}
|
||||
store.queueTabStartupCommand(terminalTab.id, sequencedStartup)
|
||||
if (sequencedStartup && launchAgent) {
|
||||
seedNativeChatAppliedSessionOptions(
|
||||
terminalTab.id,
|
||||
launchAgent,
|
||||
sequencedStartup.sessionOptions
|
||||
)
|
||||
}
|
||||
queueSetupAndIssueCommands(
|
||||
store,
|
||||
|
||||
@@ -34,7 +34,8 @@ export function queueSetupAndIssueCommands(
|
||||
if (mode === 'new-tab') {
|
||||
const setupTab = store.createTab(worktreeId, undefined, undefined, {
|
||||
recordInteraction: false,
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {})
|
||||
...(opts?.activateCreatedTabs === false ? { activate: false } : {}),
|
||||
pendingStartup: setupCommand
|
||||
})
|
||||
// Why: createTab auto-activates the new tab; revert so focus stays on the primary terminal while Setup runs in the background.
|
||||
if (opts?.activateCreatedTabs !== false && terminalTabId) {
|
||||
@@ -42,7 +43,6 @@ export function queueSetupAndIssueCommands(
|
||||
}
|
||||
// Why: customTitle overrides the auto "Terminal N" label everywhere the tab renders, so it's the authoritative label source.
|
||||
store.setTabCustomTitle(setupTab.id, 'Setup', { recordInteraction: false })
|
||||
store.queueTabStartupCommand(setupTab.id, setupCommand)
|
||||
} else if (terminalTabId) {
|
||||
store.queueTabSetupSplit(terminalTabId, {
|
||||
...setupCommand,
|
||||
|
||||
Reference in New Issue
Block a user