Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/ipc/devDebug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ipcMain } from 'electron'

export type DevDebugConfig = {
enabled: boolean
}

function envFlag(name: string): boolean {
const value = process.env[name]
return value === '1' || value === 'true' || value === 'yes'
}

export function registerDevDebugIpc(): void {
ipcMain.handle('dev-debug:get-config', (): DevDebugConfig => {
return {
// WHY this flag lives in main instead of import.meta.env:
// dev-debug modules are allowed to be noisy, temporary, and
// sometimes performance-hostile. Gating them from the same
// project-root `.env` loader as performance telemetry gives us a
// runtime switch that works in Electron dev without requiring a
// Vite-prefixed renderer variable or rebuild-time config.
enabled: envFlag('AGENT_CODE_DEV_DEBUG'),
}
})
}
2 changes: 2 additions & 0 deletions src/main/ipc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { registerSetupIpc } from '@main/ipc/setup.js'
import { registerWorktreeActivityIpc } from '@main/ipc/worktreeActivity.js'
import { registerDictationIpc } from '@main/ipc/dictation.js'
import { registerPasteDebugIpc } from '@main/ipc/pasteDebug.js'
import { registerDevDebugIpc } from '@main/ipc/devDebug.js'
import { installPerformanceIpcInstrumentation } from '@main/performance/instrumentIpc.js'
import type { WorktreeActivityIndex } from '@main/worktreeActivity/WorktreeActivityIndex.js'

Expand Down Expand Up @@ -55,4 +56,5 @@ export function registerAllIpc(deps: IpcDeps): void {
registerSetupIpc()
registerDictationIpc({ dictationDebugJournals: deps.dictationDebugJournals })
registerPasteDebugIpc({ pasteDebugJournals: deps.pasteDebugJournals })
registerDevDebugIpc()
}
8 changes: 8 additions & 0 deletions src/preload/api/devDebug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ipcRenderer } from 'electron'

import type { DevDebugConfig } from '@preload/api/types.js'

export const devDebugApi = {
getDevDebugConfig: (): Promise<DevDebugConfig> =>
ipcRenderer.invoke('dev-debug:get-config'),
}
2 changes: 2 additions & 0 deletions src/preload/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { setupApi } from '@preload/api/setup.js'
import { dictationApi } from '@preload/api/dictation.js'
import { dictationDebugApi } from '@preload/api/dictationDebug.js'
import { pasteDebugApi } from '@preload/api/pasteDebug.js'
import { devDebugApi } from '@preload/api/devDebug.js'

// Composed preload API surface.
//
Expand Down Expand Up @@ -45,6 +46,7 @@ export const api = {
...dictationApi,
...dictationDebugApi,
...pasteDebugApi,
...devDebugApi,
}

export type Api = typeof api
4 changes: 4 additions & 0 deletions src/preload/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export type { ProviderConditionSnapshot } from '@shared/types/providerConditions

export type Unsub = () => void

export type DevDebugConfig = {
enabled: boolean
}

export type DictationProvider = 'deepgram' | 'assemblyai' | 'openai' | 'gladia' | 'elevenlabs'

export type DictationStartResult =
Expand Down
1 change: 1 addition & 0 deletions src/preload/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type { Api }
// preload bundle.
export type {
FeedDebugPersistEntry,
DevDebugConfig,
JsonlEntry,
LspDiagnostic,
LspDiagnosticsEvent,
Expand Down
1 change: 1 addition & 0 deletions src/renderer/src/app-state/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type UiShellSlice = UiShellState & {
toggleFeedDebugPanel: () => void
toggleProxyDebugPanel: () => void
toggleHtmlDebugPanel: () => void
toggleDevDebugPanel: () => void
togglePerformancePanel: () => void
openPromptSearch: () => void
closePromptSearch: () => void
Expand Down
7 changes: 7 additions & 0 deletions src/renderer/src/app-state/uiShell/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const createUiShellSlice: StateCreator<
feedDebugPanelOpen: false,
proxyDebugPanelOpen: false,
htmlDebugPanelOpen: false,
devDebugPanelOpen: false,
performancePanelOpen: false,
promptSearchOpen: false,
agentActivityOpen: false,
Expand Down Expand Up @@ -119,6 +120,12 @@ export const createUiShellSlice: StateCreator<
false,
'uiShell/toggleHtmlDebugPanel',
),
toggleDevDebugPanel: () =>
set(
state => ({ devDebugPanelOpen: !state.devDebugPanelOpen }),
false,
'uiShell/toggleDevDebugPanel',
),
togglePerformancePanel: () =>
set(
state => ({ performancePanelOpen: !state.performancePanelOpen }),
Expand Down
6 changes: 6 additions & 0 deletions src/renderer/src/app-state/uiShell/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ export type UiShellState = {
* Lives on the uiShell slice alongside the other three debug panels
* and follows the same toggle pattern. */
htmlDebugPanelOpen: boolean
/** When true, the .env-gated Dev Debug Panel is mounted. Unlike the
* stable debug panels above, this is a temporary module host for
* one-off investigations. Its modules are intentionally freeform:
* they may poll, render custom UI, or call IPC while a bug is being
* understood, and then disappear after the fix lands. */
devDebugPanelOpen: boolean
performancePanelOpen: boolean
/** When true, the Search Conversation Prompts modal is open. Lives
* on the uiShell slice (not the workspace slice) because it's
Expand Down
33 changes: 32 additions & 1 deletion src/renderer/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useCallback, useEffect, useMemo, useRef } from 'react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import { CommandPalette } from '@renderer/features/command-palette/ui/CommandPalette'
import { PinAgentsModal, type PinAgentsModalRow } from '@renderer/features/dispatch-pin/PinAgentsModal'
import { DebugPanel } from '@renderer/features/debug/ui/DebugPanel'
import { FeedDebugPanel } from '@renderer/features/debug/ui/FeedDebugPanel'
import { HtmlDebugPanel } from '@renderer/features/debug/ui/HtmlDebugPanel'
import { ProxyDebugPanel } from '@renderer/features/debug/ui/ProxyDebugPanel'
import { DevDebugPanel } from '@renderer/features/debug/ui/DevDebugPanel'
import { SettingsPage } from '@renderer/features/settings/ui/SettingsPage'
import { SetupGate } from '@renderer/features/setup/ui/SetupGate'
import { SpotlightView } from '@renderer/features/spotlight/ui/SpotlightView'
Expand Down Expand Up @@ -78,6 +79,7 @@ export default function App() {
const feedDebugPanelOpen = useAppStore(state => state.feedDebugPanelOpen)
const proxyDebugPanelOpen = useAppStore(state => state.proxyDebugPanelOpen)
const htmlDebugPanelOpen = useAppStore(state => state.htmlDebugPanelOpen)
const devDebugPanelOpen = useAppStore(state => state.devDebugPanelOpen)
const performancePanelOpen = useAppStore(state => state.performancePanelOpen)
const dangerousAgentsEnabled = settings.dangerousAgentsEnabled
const aggressiveDebugPersistenceEnabled = settings.aggressiveDebugPersistence
Expand Down Expand Up @@ -117,6 +119,7 @@ export default function App() {
const toggleFeedDebugPanel = useAppStore(state => state.toggleFeedDebugPanel)
const toggleProxyDebugPanel = useAppStore(state => state.toggleProxyDebugPanel)
const toggleHtmlDebugPanel = useAppStore(state => state.toggleHtmlDebugPanel)
const toggleDevDebugPanel = useAppStore(state => state.toggleDevDebugPanel)
const togglePerformancePanel = useAppStore(state => state.togglePerformancePanel)
const promptSearchOpen = useAppStore(state => state.promptSearchOpen)
const openPromptSearch = useAppStore(state => state.openPromptSearch)
Expand All @@ -127,11 +130,26 @@ export default function App() {
const rewindPromptSessionId = useAppStore(state => state.rewindPromptSessionId)
const openRewindPrompt = useAppStore(state => state.openRewindPrompt)
const closeRewindPrompt = useAppStore(state => state.closeRewindPrompt)
const [devDebugEnabled, setDevDebugEnabled] = useState(false)

useEffect(() => {
applyTheme(settings)
}, [settings])

useEffect(() => {
let cancelled = false
void window.api.getDevDebugConfig()
.then(config => {
if (!cancelled) setDevDebugEnabled(config.enabled)
})
.catch(() => {
if (!cancelled) setDevDebugEnabled(false)
})
return () => {
cancelled = true
}
}, [])

useEffect(() => {
// The default dictation trigger is bare Fn, which Chromium does not expose
// reliably to renderer keydown. Settings live in the renderer, but the
Expand Down Expand Up @@ -529,6 +547,16 @@ export default function App() {
onClose={toggleHtmlDebugPanel}
/>
)}

{devDebugEnabled && devDebugPanelOpen && commandTargetId && (
<DevDebugPanel
sessionId={commandTargetId}
runtime={workspace.getRuntime(commandTargetId)}
kind={workspace.state.sessions[commandTargetId]?.kind ?? 'claude'}
workspace={workspace}
onClose={toggleDevDebugPanel}
/>
)}
</div>

<CommandPalette
Expand All @@ -543,6 +571,7 @@ export default function App() {
toggleFeedDebugPanel={toggleFeedDebugPanel}
toggleProxyDebugPanel={toggleProxyDebugPanel}
toggleHtmlDebugPanel={toggleHtmlDebugPanel}
toggleDevDebugPanel={toggleDevDebugPanel}
togglePerformancePanel={togglePerformancePanel}
enterDispatchMode={workspace.enterDispatchMode}
enterGlobalDispatch={() =>
Expand Down Expand Up @@ -574,6 +603,8 @@ export default function App() {
feedDebugPanelOpen={feedDebugPanelOpen}
proxyDebugPanelOpen={proxyDebugPanelOpen}
htmlDebugPanelOpen={htmlDebugPanelOpen}
devDebugEnabled={devDebugEnabled}
devDebugPanelOpen={devDebugPanelOpen}
performancePanelOpen={performancePanelOpen}
dispatchModeEnabled={workspace.dispatchMode !== null}
globalDispatchEnabled={workspace.dispatchMode?.scope === 'global'}
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/src/features/command-palette/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export type CommandContext = {
toggleFeedDebugPanel: () => void
toggleProxyDebugPanel: () => void
toggleHtmlDebugPanel: () => void
toggleDevDebugPanel: () => void
togglePerformancePanel: () => void
enterDispatchMode: () => Promise<void> | void
enterGlobalDispatch: () => Promise<void> | void
Expand Down Expand Up @@ -60,6 +61,8 @@ export type CommandContext = {
feedDebugPanelOpen: boolean
proxyDebugPanelOpen: boolean
htmlDebugPanelOpen: boolean
devDebugEnabled: boolean
devDebugPanelOpen: boolean
performancePanelOpen: boolean
dispatchModeEnabled: boolean
globalDispatchEnabled: boolean
Expand Down
12 changes: 12 additions & 0 deletions src/renderer/src/features/command-palette/ui/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ type Props = {
toggleFeedDebugPanel: () => void
toggleProxyDebugPanel: () => void
toggleHtmlDebugPanel: () => void
toggleDevDebugPanel: () => void
togglePerformancePanel: () => void
enterDispatchMode: () => Promise<void> | void
enterGlobalDispatch: () => Promise<void> | void
Expand All @@ -93,6 +94,8 @@ type Props = {
feedDebugPanelOpen: boolean
proxyDebugPanelOpen: boolean
htmlDebugPanelOpen: boolean
devDebugEnabled: boolean
devDebugPanelOpen: boolean
performancePanelOpen: boolean
dispatchModeEnabled: boolean
globalDispatchEnabled: boolean
Expand Down Expand Up @@ -129,6 +132,7 @@ export function CommandPalette({
toggleFeedDebugPanel,
toggleProxyDebugPanel,
toggleHtmlDebugPanel,
toggleDevDebugPanel,
togglePerformancePanel,
enterDispatchMode,
enterGlobalDispatch,
Expand All @@ -149,6 +153,8 @@ export function CommandPalette({
feedDebugPanelOpen,
proxyDebugPanelOpen,
htmlDebugPanelOpen,
devDebugEnabled,
devDebugPanelOpen,
performancePanelOpen,
dispatchModeEnabled,
globalDispatchEnabled,
Expand Down Expand Up @@ -289,6 +295,7 @@ export function CommandPalette({
toggleFeedDebugPanel,
toggleProxyDebugPanel,
toggleHtmlDebugPanel,
toggleDevDebugPanel,
togglePerformancePanel,
enterDispatchMode,
enterGlobalDispatch,
Expand Down Expand Up @@ -319,6 +326,8 @@ export function CommandPalette({
feedDebugPanelOpen,
proxyDebugPanelOpen,
htmlDebugPanelOpen,
devDebugEnabled,
devDebugPanelOpen,
performancePanelOpen,
dispatchModeEnabled,
globalDispatchEnabled,
Expand All @@ -341,6 +350,7 @@ export function CommandPalette({
toggleFeedDebugPanel,
toggleProxyDebugPanel,
toggleHtmlDebugPanel,
toggleDevDebugPanel,
togglePerformancePanel,
enterDispatchMode,
enterGlobalDispatch,
Expand Down Expand Up @@ -369,6 +379,8 @@ export function CommandPalette({
feedDebugPanelOpen,
proxyDebugPanelOpen,
htmlDebugPanelOpen,
devDebugEnabled,
devDebugPanelOpen,
performancePanelOpen,
dispatchModeEnabled,
globalDispatchEnabled,
Expand Down
Loading