From cdba9a77034afac1fccf67c1a42ff92b3ce52e5c Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Fri, 23 Oct 2026 17:33:42 -0700 Subject: [PATCH] refactor(dashboard): remove unreachable popout spawn/sleep IPC (#32954) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- .../ipc/dashboard-agent-launch-validation.ts | 13 +---- .../ipc/dashboard-payload-validation.test.ts | 7 +-- src/main/ipc/dashboard-payload-validation.ts | 11 ----- src/main/ipc/dashboard-popout.test.ts | 25 ---------- src/main/ipc/dashboard-popout.ts | 28 +---------- src/preload/api/dashboard-api.ts | 11 +---- src/preload/api/dashboard-bridge.ts | 25 +--------- .../dashboard/launch-dashboard-agent.test.ts | 49 ------------------- .../dashboard/launch-dashboard-agent.ts | 25 ---------- .../dashboard/useDashboardPopoutBridge.ts | 20 -------- .../launch-parity-window-tab.test.ts | 5 -- ...ent-launch-caller-profiles-test-harness.ts | 5 -- src/shared/dashboard-snapshot.ts | 11 ----- .../launch-parity-plus-cases.test-fixture.ts | 4 +- ...unch-parity-window-request.test-fixture.ts | 5 +- 15 files changed, 10 insertions(+), 234 deletions(-) delete mode 100644 src/renderer/src/components/dashboard/launch-dashboard-agent.test.ts delete mode 100644 src/renderer/src/components/dashboard/launch-dashboard-agent.ts diff --git a/src/main/ipc/dashboard-agent-launch-validation.ts b/src/main/ipc/dashboard-agent-launch-validation.ts index c50e72f6ec3..3c36b9857e0 100644 --- a/src/main/ipc/dashboard-agent-launch-validation.ts +++ b/src/main/ipc/dashboard-agent-launch-validation.ts @@ -1,7 +1,4 @@ -import { - DASHBOARD_MAX_LAUNCH_WORKTREES, - type DashboardSpawnAgentArgs -} from '../../shared/dashboard-snapshot' +import { DASHBOARD_MAX_LAUNCH_WORKTREES } from '../../shared/dashboard-snapshot' import { isTuiAgent } from '../../shared/tui-agent-config' const MAX_ID_LENGTH = 4_096 @@ -11,14 +8,6 @@ function isBoundedId(value: unknown): value is string { return typeof value === 'string' && value.length > 0 && value.length <= MAX_ID_LENGTH } -export function isDashboardSpawnAgentArgs(value: unknown): value is DashboardSpawnAgentArgs { - if (!value || typeof value !== 'object' || Array.isArray(value)) { - return false - } - const args = value as Record - return isBoundedId(args.worktreeId) && isTuiAgent(args.agent) -} - export function isDashboardLaunchOptions(value: unknown): boolean { if (value === undefined) { return true diff --git a/src/main/ipc/dashboard-payload-validation.test.ts b/src/main/ipc/dashboard-payload-validation.test.ts index 63dd1076a4b..695f8e0504f 100644 --- a/src/main/ipc/dashboard-payload-validation.test.ts +++ b/src/main/ipc/dashboard-payload-validation.test.ts @@ -18,7 +18,6 @@ vi.mock('../../shared/repo-icon', async (importOriginal) => { import { admitDashboardSnapshot, isDashboardRevealAgentArgs, - isDashboardSpawnAgentArgs, isDashboardSnapshot } from './dashboard-payload-validation' @@ -276,7 +275,7 @@ describe('dashboard payload validation', () => { ).toBe(false) }) - it('validates bounded launch choices and spawn requests', () => { + it('validates bounded launch choices', () => { expect( isDashboardSnapshot({ ...SNAPSHOT, @@ -290,10 +289,6 @@ describe('dashboard payload validation', () => { }) ).toBe(false) expect(isDashboardSnapshot({ ...SNAPSHOT, launchableAgentsByWorktreeId: [] })).toBe(false) - - expect(isDashboardSpawnAgentArgs({ worktreeId: 'worktree-1', agent: 'codex' })).toBe(true) - expect(isDashboardSpawnAgentArgs({ worktreeId: '', agent: 'codex' })).toBe(false) - expect(isDashboardSpawnAgentArgs({ worktreeId: 'worktree-1', agent: 'unknown' })).toBe(false) }) it('bounds the conversation name', () => { diff --git a/src/main/ipc/dashboard-payload-validation.ts b/src/main/ipc/dashboard-payload-validation.ts index 4199d7d99bd..c507d724a1f 100644 --- a/src/main/ipc/dashboard-payload-validation.ts +++ b/src/main/ipc/dashboard-payload-validation.ts @@ -1,7 +1,6 @@ import { DASHBOARD_MAX_LABEL_LENGTH, type DashboardRevealAgentArgs, - type DashboardSleepWorkspaceArgs, type DashboardSnapshot } from '../../shared/dashboard-snapshot' import { BoundedMap } from '../../shared/bounded-map' @@ -19,7 +18,6 @@ import { isDashboardWorkspaceList } from './dashboard-workspace-payload-validation' import { isDashboardFilterOptions } from './dashboard-filter-payload-validation' -export { isDashboardSpawnAgentArgs } from './dashboard-agent-launch-validation' const MAX_DASHBOARD_CARDS = 1_000 const MAX_DASHBOARD_REPO_ICONS = 500 @@ -85,15 +83,6 @@ export function isDashboardPaneKey(value: unknown): value is string { return isBoundedString(value, MAX_ID_LENGTH) } -export function isDashboardSleepWorkspaceArgs( - value: unknown -): value is DashboardSleepWorkspaceArgs { - if (!value || typeof value !== 'object' || Array.isArray(value)) { - return false - } - return isBoundedString((value as Record).worktreeId, MAX_ID_LENGTH) -} - export function isDashboardSnapshot(value: unknown): value is DashboardSnapshot { if (!value || typeof value !== 'object' || Array.isArray(value)) { return false diff --git a/src/main/ipc/dashboard-popout.test.ts b/src/main/ipc/dashboard-popout.test.ts index d197794f3bf..69df99aebe2 100644 --- a/src/main/ipc/dashboard-popout.test.ts +++ b/src/main/ipc/dashboard-popout.test.ts @@ -253,31 +253,6 @@ describe('registerDashboardPopoutHandlers', () => { ]) }) - it('relays only valid agent launches from the popout', () => { - const args = { worktreeId: 'worktree-1', agent: 'codex' } - handlers.get('dashboardPopout:spawnAgent')!({ sender: untrustedSender } as never, args) - handlers.get('dashboardPopout:spawnAgent')!({ sender: popoutSender } as never, { - ...args, - agent: 'unknown' - }) - expect(sendToTrustedMock).not.toHaveBeenCalled() - - handlers.get('dashboardPopout:spawnAgent')!({ sender: popoutSender } as never, args) - expect(sendToTrustedMock).toHaveBeenCalledWith('ui:spawnDashboardAgent', args) - }) - - it('relays only valid sleep requests from the popout', () => { - const args = { worktreeId: 'worktree-1' } - handlers.get('dashboardPopout:sleepWorkspace')!({ sender: untrustedSender } as never, args) - handlers.get('dashboardPopout:sleepWorkspace')!({ sender: popoutSender } as never, { - worktreeId: '' - }) - expect(sendToTrustedMock).not.toHaveBeenCalled() - - handlers.get('dashboardPopout:sleepWorkspace')!({ sender: popoutSender } as never, args) - expect(sendToTrustedMock).toHaveBeenCalledWith('ui:sleepDashboardWorkspace', args) - }) - it('reveals an agent in only the trusted main window', () => { const main = makeWindow(mainSender) getTrustedWindowMock.mockReturnValue(main) diff --git a/src/main/ipc/dashboard-popout.ts b/src/main/ipc/dashboard-popout.ts index f8ae77df799..a77cc518b44 100644 --- a/src/main/ipc/dashboard-popout.ts +++ b/src/main/ipc/dashboard-popout.ts @@ -15,9 +15,7 @@ import { getTrustedUIRendererWindow, isTrustedUIRenderer, sendToTrustedUIRendere import { admitDashboardSnapshot, isDashboardPaneKey, - isDashboardRevealAgentArgs, - isDashboardSleepWorkspaceArgs, - isDashboardSpawnAgentArgs + isDashboardRevealAgentArgs } from './dashboard-payload-validation' // Replay immediately on mount; clear on close to avoid showing a previous session. @@ -37,8 +35,6 @@ export function registerDashboardPopoutHandlers( ipcMain.removeHandler('dashboard:getPopoutOpen') ipcMain.removeHandler('dashboardPopout:revealAgent') ipcMain.removeHandler('dashboardPopout:ackAgent') - ipcMain.removeHandler('dashboardPopout:spawnAgent') - ipcMain.removeHandler('dashboardPopout:sleepWorkspace') onDashboardPopoutOpenChanged((open) => { if (!open) { @@ -141,26 +137,4 @@ export function registerDashboardPopoutHandlers( } } }) - - ipcMain.handle('dashboardPopout:spawnAgent', (event, args: unknown): void => { - if ( - !isDashboardPopoutRenderer(event.sender) || - !isDashboardEnabled(store) || - !isDashboardSpawnAgentArgs(args) - ) { - return - } - sendToTrustedUIRenderer('ui:spawnDashboardAgent', args) - }) - - ipcMain.handle('dashboardPopout:sleepWorkspace', (event, args: unknown): void => { - if ( - !isDashboardPopoutRenderer(event.sender) || - !isDashboardEnabled(store) || - !isDashboardSleepWorkspaceArgs(args) - ) { - return - } - sendToTrustedUIRenderer('ui:sleepDashboardWorkspace', args) - }) } diff --git a/src/preload/api/dashboard-api.ts b/src/preload/api/dashboard-api.ts index 2db2598a7ba..813f4ec3318 100644 --- a/src/preload/api/dashboard-api.ts +++ b/src/preload/api/dashboard-api.ts @@ -1,9 +1,4 @@ -import type { - DashboardRevealAgentArgs, - DashboardSleepWorkspaceArgs, - DashboardSnapshot, - DashboardSpawnAgentArgs -} from '../../shared/dashboard-snapshot' +import type { DashboardRevealAgentArgs, DashboardSnapshot } from '../../shared/dashboard-snapshot' import type { TerminalPreviewConnectResult, TerminalPreviewDataPayload @@ -18,14 +13,10 @@ export type DashboardApi = { onRevealAgent: (callback: (args: DashboardRevealAgentArgs) => void) => () => void /** `explicit` only for a click on the card; watching an open dialog is a view. */ onAckAgent: (callback: (paneKey: string, intent: 'view' | 'explicit') => void) => () => void - onSpawnAgent: (callback: (args: DashboardSpawnAgentArgs) => void) => () => void - onSleepWorkspace: (callback: (args: DashboardSleepWorkspaceArgs) => void) => () => void requestSnapshot: () => Promise onSnapshot: (callback: (snapshot: DashboardSnapshot) => void) => () => void revealAgent: (args: DashboardRevealAgentArgs) => Promise ackAgent: (paneKey: string, intent: 'view' | 'explicit') => Promise - spawnAgent: (args: DashboardSpawnAgentArgs) => Promise - sleepWorkspace: (args: DashboardSleepWorkspaceArgs) => Promise } export type TerminalPreviewApi = { diff --git a/src/preload/api/dashboard-bridge.ts b/src/preload/api/dashboard-bridge.ts index c4f015e8495..4663b87459e 100644 --- a/src/preload/api/dashboard-bridge.ts +++ b/src/preload/api/dashboard-bridge.ts @@ -1,10 +1,5 @@ import { ipcRenderer } from 'electron' -import type { - DashboardRevealAgentArgs, - DashboardSleepWorkspaceArgs, - DashboardSnapshot, - DashboardSpawnAgentArgs -} from '../../shared/dashboard-snapshot' +import type { DashboardRevealAgentArgs, DashboardSnapshot } from '../../shared/dashboard-snapshot' import type { PreloadApi } from '../api-types' export const dashboardApi = { @@ -37,18 +32,6 @@ export const dashboardApi = { ipcRenderer.on('ui:ackDashboardAgent', listener) return () => ipcRenderer.removeListener('ui:ackDashboardAgent', listener) }, - onSpawnAgent: (callback: (args: DashboardSpawnAgentArgs) => void): (() => void) => { - const listener = (_event: Electron.IpcRendererEvent, args: DashboardSpawnAgentArgs): void => - callback(args) - ipcRenderer.on('ui:spawnDashboardAgent', listener) - return () => ipcRenderer.removeListener('ui:spawnDashboardAgent', listener) - }, - onSleepWorkspace: (callback: (args: DashboardSleepWorkspaceArgs) => void): (() => void) => { - const listener = (_event: Electron.IpcRendererEvent, args: DashboardSleepWorkspaceArgs): void => - callback(args) - ipcRenderer.on('ui:sleepDashboardWorkspace', listener) - return () => ipcRenderer.removeListener('ui:sleepDashboardWorkspace', listener) - }, requestSnapshot: (): Promise => ipcRenderer.invoke('dashboard:requestSnapshot'), onSnapshot: (callback: (snapshot: DashboardSnapshot) => void): (() => void) => { @@ -60,9 +43,5 @@ export const dashboardApi = { revealAgent: (args: DashboardRevealAgentArgs): Promise => ipcRenderer.invoke('dashboardPopout:revealAgent', args), ackAgent: (paneKey: string, intent: 'view' | 'explicit'): Promise => - ipcRenderer.invoke('dashboardPopout:ackAgent', { paneKey, intent }), - spawnAgent: (args: DashboardSpawnAgentArgs): Promise => - ipcRenderer.invoke('dashboardPopout:spawnAgent', args), - sleepWorkspace: (args: DashboardSleepWorkspaceArgs): Promise => - ipcRenderer.invoke('dashboardPopout:sleepWorkspace', args) + ipcRenderer.invoke('dashboardPopout:ackAgent', { paneKey, intent }) } satisfies PreloadApi['dashboard'] diff --git a/src/renderer/src/components/dashboard/launch-dashboard-agent.test.ts b/src/renderer/src/components/dashboard/launch-dashboard-agent.test.ts deleted file mode 100644 index f72a249b9c7..00000000000 --- a/src/renderer/src/components/dashboard/launch-dashboard-agent.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const mocks = vi.hoisted(() => ({ - getKnownWorktreeById: vi.fn(), - setActiveWorktree: vi.fn(), - launchAgentInNewTab: vi.fn(), - getExecutionHostIdForWorktree: vi.fn() -})) - -vi.mock('@/store', () => ({ - useAppStore: { - getState: () => ({ - settings: null, - getKnownWorktreeById: mocks.getKnownWorktreeById, - setActiveWorktree: mocks.setActiveWorktree - }) - } -})) -vi.mock('@/lib/launch-agent-in-new-tab', () => ({ - launchAgentInNewTab: mocks.launchAgentInNewTab -})) -vi.mock('@/lib/worktree-runtime-owner', () => ({ - getExecutionHostIdForWorktree: mocks.getExecutionHostIdForWorktree -})) - -import { launchDashboardAgent } from './launch-dashboard-agent' - -describe('launchDashboardAgent', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.getExecutionHostIdForWorktree.mockReturnValue('ssh:docs') - mocks.getKnownWorktreeById.mockReturnValue({ id: 'folder:docs' }) - mocks.launchAgentInNewTab.mockReturnValue({ - surface: { kind: 'local-terminal', tabId: 'tab-1' } - }) - }) - - it('activates a folder or git workspace on its execution host before launching', () => { - expect(launchDashboardAgent({ worktreeId: 'folder:docs', agent: 'codex' })).toBe(true) - expect(mocks.getKnownWorktreeById).toHaveBeenCalledWith('folder:docs', 'ssh:docs') - expect(mocks.setActiveWorktree).toHaveBeenCalledWith('folder:docs', 'ssh:docs') - expect(mocks.launchAgentInNewTab).toHaveBeenCalledWith({ - requestId: expect.any(String), - agent: 'codex', - worktreeId: 'folder:docs', - launchSource: 'unknown' - }) - }) -}) diff --git a/src/renderer/src/components/dashboard/launch-dashboard-agent.ts b/src/renderer/src/components/dashboard/launch-dashboard-agent.ts deleted file mode 100644 index 43ff278bd7c..00000000000 --- a/src/renderer/src/components/dashboard/launch-dashboard-agent.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { launchAgentInNewTab } from '@/lib/launch-agent-in-new-tab' -import { newAgentLaunchRequestId } from '@/lib/agent-launch-request-id' -import { useAppStore } from '@/store' -import { getExecutionHostIdForWorktree } from '@/lib/worktree-runtime-owner' -import type { DashboardSpawnAgentArgs } from '../../../../shared/dashboard-snapshot' -import { isTuiAgentEnabled } from '../../../../shared/tui-agent-selection' - -/** Starts the requested agent through the same host-aware tab path as Quick Launch. */ -export function launchDashboardAgent({ worktreeId, agent }: DashboardSpawnAgentArgs): boolean { - const state = useAppStore.getState() - const executionHostId = getExecutionHostIdForWorktree(state, worktreeId) - const worktree = state.getKnownWorktreeById(worktreeId, executionHostId) - if (!worktree || !isTuiAgentEnabled(agent, state.settings?.disabledTuiAgents)) { - return false - } - state.setActiveWorktree(worktreeId, executionHostId) - return ( - launchAgentInNewTab({ - requestId: newAgentLaunchRequestId(), - agent, - worktreeId, - launchSource: 'unknown' - }) !== null - ) -} diff --git a/src/renderer/src/components/dashboard/useDashboardPopoutBridge.ts b/src/renderer/src/components/dashboard/useDashboardPopoutBridge.ts index 14ce45b462b..f9c641b7a63 100644 --- a/src/renderer/src/components/dashboard/useDashboardPopoutBridge.ts +++ b/src/renderer/src/components/dashboard/useDashboardPopoutBridge.ts @@ -8,11 +8,9 @@ import { selectAgentLaunchRouteView } from '@/lib/agent-launch-route-input' import { revealDashboardAgent } from './reveal-dashboard-agent' -import { runSleepWorktree } from '../sidebar/sleep-worktree-flow' import type { RepoIcon } from '../../../../shared/repo-icon' import { buildDashboardSnapshot, type DashboardSnapshotState } from './build-dashboard-snapshot' import { createWorktreeAgentRowsCache } from './worktree-agent-rows-cache' -import { launchDashboardAgent } from './launch-dashboard-agent' import { selectWorktreesByRepo } from '@/store/workspace-record-selectors' // Why: cap snapshot rebuilds during bursts of agent-status pings. The board is a @@ -127,24 +125,6 @@ export function watchSnapshotInputs(onChanged: () => void): () => void { * the agent's worktree and focus its pane in this (main) window. */ export function useDashboardPopoutBridge(enabled: boolean): void { - useEffect(() => { - if (!enabled) { - return - } - return window.api.dashboard.onSpawnAgent?.(launchDashboardAgent) - }, [enabled]) - - // Sleeping from the popout runs the shared teardown here, where the store and - // the live terminal panes are — the popout only names the workspace. - useEffect(() => { - if (!enabled) { - return - } - return window.api.dashboard.onSleepWorkspace?.(({ worktreeId }) => { - void runSleepWorktree(worktreeId) - }) - }, [enabled]) - useEffect(() => { if (!enabled) { return diff --git a/src/renderer/src/components/terminal-pane/launch-parity-window-tab.test.ts b/src/renderer/src/components/terminal-pane/launch-parity-window-tab.test.ts index 9c4dc519574..5ae2070cd99 100644 --- a/src/renderer/src/components/terminal-pane/launch-parity-window-tab.test.ts +++ b/src/renderer/src/components/terminal-pane/launch-parity-window-tab.test.ts @@ -74,7 +74,6 @@ const load = perClientLoader(async () => ({ quick: await import('@/lib/run-quick-command-in-new-tab'), vault: await import('@/lib/launch-ai-vault-session'), resume: await import('@/lib/ai-vault-resume-command'), - dashboard: await import('@/components/dashboard/launch-dashboard-agent'), pane: await import('./pty-connection'), paneOptions: await import('./terminal-pane-manager-options'), defaults: await import('@/lib/pane-manager/pane-terminal-options'), @@ -112,10 +111,6 @@ async function openTab(c: WindowLaunchCase) { launchSource: 'terminal_context_menu', initialCwd: producer.initialCwd }) - } else if (producer.kind === 'plus' && producer.via === 'dashboard') { - // Its workspace activation asks for a PR refresh, which this harness has no bridge for. - Object.assign(window.api, { gh: {} }) - modules.dashboard.launchDashboardAgent({ worktreeId, agent: producer.agent }) } else if (producer.kind === 'plus') { // Hand-built copies of what the "+" menu and the new-agent shortcut pass. modules.launch.launchAgentInNewTab({ diff --git a/src/renderer/src/lib/agent-launch-caller-profiles-test-harness.ts b/src/renderer/src/lib/agent-launch-caller-profiles-test-harness.ts index 37a39fc35de..97684add82b 100644 --- a/src/renderer/src/lib/agent-launch-caller-profiles-test-harness.ts +++ b/src/renderer/src/lib/agent-launch-caller-profiles-test-harness.ts @@ -30,11 +30,6 @@ export type AgentLaunchCallerProfile = { const PROMPT = 'Explain the failing check and propose a fix.' export const AGENT_LAUNCH_CALLER_PROFILES: readonly AgentLaunchCallerProfile[] = [ - { - id: 'dashboard-spawn', - caller: 'src/renderer/src/components/dashboard/launch-dashboard-agent.ts', - args: { agent: 'codex', worktreeId: 'wt-1', launchSource: 'unknown' } - }, { id: 'empty-workspace-default-chat', caller: 'src/renderer/src/lib/empty-workspace-default-agent-chat.ts', diff --git a/src/shared/dashboard-snapshot.ts b/src/shared/dashboard-snapshot.ts index bfd41984f81..6abbc221347 100644 --- a/src/shared/dashboard-snapshot.ts +++ b/src/shared/dashboard-snapshot.ts @@ -223,14 +223,3 @@ export type DashboardRevealAgentArgs = { tabId: string leafId: string | null } - -export type DashboardSpawnAgentArgs = { - worktreeId: string - agent: TuiAgent -} - -/** Puts a workspace to sleep from the dashboard: the main renderer owns the - * teardown sequence, so the pop-out only names the target. */ -export type DashboardSleepWorkspaceArgs = { - worktreeId: string -} diff --git a/src/shared/launch-parity-plus-cases.test-fixture.ts b/src/shared/launch-parity-plus-cases.test-fixture.ts index f35e0a00750..549d0fae64f 100644 --- a/src/shared/launch-parity-plus-cases.test-fixture.ts +++ b/src/shared/launch-parity-plus-cases.test-fixture.ts @@ -1,5 +1,5 @@ // Test-only (never imported by production code): the window-lane launch parity table for row 1, the -// "+" launches C2 moves onto the pane trigger. One row per "+" entry point; local hosts only. +// "+" launches C2 moves onto the pane trigger. Covers each "+" entry point; local hosts only. import { POSIX_PATH, WIN_PATH } from './launch-parity-window-cases.test-fixture' import type { LaunchClient, @@ -55,5 +55,5 @@ export const PLUS_LAUNCH_CASES: WindowLaunchCase[] = [ }, { shellOverride: 'powershell.exe', terminalWindowsWslDistro: null } ), - plus('dashboard', 'Linux repo', 'linux', { kind: 'repo', path: POSIX_PATH }, quoted(posix), ZSH) + plus('menu', 'Linux repo', 'linux', { kind: 'repo', path: POSIX_PATH }, quoted(posix), ZSH) ] diff --git a/src/shared/launch-parity-window-request.test-fixture.ts b/src/shared/launch-parity-window-request.test-fixture.ts index f1f1c922ba9..49d6896e501 100644 --- a/src/shared/launch-parity-window-request.test-fixture.ts +++ b/src/shared/launch-parity-window-request.test-fixture.ts @@ -44,7 +44,7 @@ export type WindowLaunchProducer = | { kind: 'folder-composer'; agent: 'claude' | 'codex'; note: string } /** "+" entry points. Quick Launch items omit launchSource and get `menu`'s source by default. */ -export type PlusEntry = 'menu' | 'shortcut' | 'dashboard' +export type PlusEntry = 'menu' | 'shortcut' const PRODUCER_LAUNCH_SOURCE = { 'quick-command': 'quick_command', continuation: 'terminal_context_menu', @@ -53,8 +53,7 @@ const PRODUCER_LAUNCH_SOURCE = { } as const const PLUS_LAUNCH_SOURCE: Record = { menu: 'tab_bar_quick_launch', - shortcut: 'shortcut', - dashboard: 'unknown' + shortcut: 'shortcut' } type ProjectRuntimeSent =