import type { Page } from '@stablyai/playwright-test' export type LineageScenario = { parentId: string childId: string } export async function seedLineageScenario(page: Page): Promise { return page.evaluate(() => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } const state = store.getState() state.setActiveView('terminal') state.setSidebarOpen(true) state.setGroupBy('none') state.setSortBy('recent') // Why: these specs assert lineage structure, not the user's persisted // sidebar filters. Make the seeded child render even when it has no live PTY. state.setShowActiveOnly(false) state.setShowSleepingWorkspaces(true) state.setHideDefaultBranchWorkspace(false) state.setFilterRepoIds([]) const worktrees = Object.values(state.worktreesByRepo) .flat() .filter((worktree) => !worktree.isArchived) if (worktrees.length < 2) { throw new Error('Worktree lineage E2E needs at least two worktrees') } const [parent, child] = worktrees if (!parent.instanceId || !child.instanceId) { throw new Error('Worktree lineage E2E needs instance-stamped worktrees') } store.setState((current) => ({ worktreesByRepo: Object.fromEntries( Object.entries(current.worktreesByRepo).map(([repoId, repoWorktrees]) => [ repoId, repoWorktrees.map((worktree) => { if (worktree.id === parent.id) { return { ...worktree, displayName: 'E2E lineage parent', sortOrder: 0 } } if (worktree.id === child.id) { return { ...worktree, displayName: 'E2E lineage child', sortOrder: 1 } } return worktree }) ]) ), worktreeLineageById: { ...current.worktreeLineageById, [child.id]: { worktreeId: child.id, worktreeInstanceId: child.instanceId, parentWorktreeId: parent.id, parentWorktreeInstanceId: parent.instanceId, origin: 'manual', capture: { source: 'manual-action', confidence: 'explicit' }, createdAt: Date.now() } } })) store.getState().setActiveWorktree(parent.id) return { parentId: parent.id, childId: child.id } }) } export async function seedWorkspaceAgentStatus( page: Page, worktreeId: string, label: string ): Promise { return page.evaluate( ({ worktreeId, label }) => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } const state = store.getState() if (!state.worktreeCardProperties.includes('inline-agents')) { state.toggleWorktreeCardProperty('inline-agents') } if ((state.tabsByWorktree[worktreeId] ?? []).length === 0) { state.createTab(worktreeId) } const next = store.getState() const tab = next.tabsByWorktree[worktreeId]?.[0] if (!tab) { throw new Error(`Worktree lineage E2E failed to create a ${label} workspace tab`) } const prompt = `LINEAGE_${label}_AGENT_${Date.now()}` const leafId = crypto.randomUUID() const now = Date.now() next.setAgentStatus( `${tab.id}:${leafId}`, { state: 'working', prompt, agentType: 'codex' }, 'codex', { updatedAt: now, stateStartedAt: now } ) return prompt }, { worktreeId, label } ) } export async function seedWorkspaceLiveTerminal(page: Page, worktreeId: string): Promise { return page.evaluate((worktreeId) => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } const state = store.getState() if ((state.tabsByWorktree[worktreeId] ?? []).length === 0) { state.createTab(worktreeId) } const next = store.getState() const tab = next.tabsByWorktree[worktreeId]?.[0] if (!tab) { throw new Error('Worktree lineage E2E failed to create a live terminal tab') } next.dropAgentStatusByWorktree(worktreeId) store.setState((current) => ({ ptyIdsByTabId: { ...current.ptyIdsByTabId, [tab.id]: [`e2e-live-pty-${Date.now()}`] }, browserTabsByWorktree: { ...current.browserTabsByWorktree, [worktreeId]: [] } })) return tab.id }, worktreeId) } export async function markWorkspaceTerminalSlept( page: Page, args: { worktreeId: string; tabId: string } ): Promise { await page.evaluate(({ worktreeId, tabId }) => { const store = window.__store if (!store) { throw new Error('window.__store is not available') } store.getState().dropAgentStatusByWorktree(worktreeId) store.setState((current) => ({ ptyIdsByTabId: { ...current.ptyIdsByTabId, [tabId]: [] }, browserTabsByWorktree: { ...current.browserTabsByWorktree, [worktreeId]: [] } })) }, args) }